Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refine Prettier configuration (redux) #1094

Merged
merged 2 commits into from
Apr 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
**/*.d.ts
*.d.ts
test/data/
/example
2 changes: 2 additions & 0 deletions .prettierrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ module.exports = {
files: "*.md",
options: {
printWidth: 60,
// Don't reformat code examples in README
embeddedLanguageFormatting: "off",
},
},
],
Expand Down
45 changes: 28 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,23 @@
1. to remodel or reconstruct (a literary work, document, sentence, etc.).
1. to supply (a theater or opera work) with a new cast.

Installation
---
## Installation

From npm:

npm install recast

From GitHub:

cd path/to/node_modules
git clone git:https://github.com/benjamn/recast.git
cd recast
npm install .

Import style
---
## Import style

Recast is designed to be imported using **named** imports:

```js
import { parse, print } from "recast";
console.log(print(parse(source)).code);
Expand All @@ -32,6 +31,7 @@ console.log(recast.print(recast.parse(source)).code);
```

If you're using CommonJS:

```js
const { parse, print } = require("recast");
console.log(print(parse(source)).code);
Expand All @@ -40,12 +40,12 @@ const recast = require("recast");
console.log(recast.print(recast.parse(source)).code);
```

Usage
---
## Usage

Recast exposes two essential interfaces, one for parsing JavaScript code (`require("recast").parse`) and the other for reprinting modified syntax trees (`require("recast").print`).

Here's a simple but non-trivial example of how you might use `.parse` and `.print`:

```js
import * as recast from "recast";

Expand All @@ -61,9 +61,11 @@ const code = [
// Parse the code using an interface similar to require("esprima").parse.
const ast = recast.parse(code);
```
Now do *whatever* you want to `ast`. Really, anything at all!

Now do _whatever_ you want to `ast`. Really, anything at all!

See [ast-types](https://github.com/benjamn/ast-types) (especially the [def/core.ts](https://github.com/benjamn/ast-types/blob/master/def/core.ts)) module for a thorough overview of the `ast` API.

```js
// Grab a reference to the function declaration we just parsed.
const add = ast.program.body[0];
Expand All @@ -89,38 +91,48 @@ ast.program.body[0] = b.variableDeclaration("var", [
// Just for fun, because addition is commutative:
add.params.push(add.params.shift());
```

When you finish manipulating the AST, let `recast.print` work its magic:

```js
const output = recast.print(ast).code;
```

The `output` string now looks exactly like this, weird formatting and all:

```js
var add = function(b, a) {
return a +
// Weird formatting, huh?
b;
}
```

The magic of Recast is that it reprints only those parts of the syntax tree that you modify. In other words, the following identity is guaranteed:

```js
recast.print(recast.parse(source)).code === source
```

Whenever Recast cannot reprint a modified node using the original source code, it falls back to using a generic pretty printer. So the worst that can happen is that your changes trigger some harmless reformatting of your code.

If you really don't care about preserving the original formatting, you can access the pretty printer directly:

```js
var output = recast.prettyPrint(ast, { tabWidth: 2 }).code;
```

And here's the exact `output`:

```js
var add = function(b, a) {
return a + b;
}
```

Note that the weird formatting was discarded, yet the behavior and abstract structure of the code remain the same.

Using a different parser
---
## Using a different parser

By default, Recast uses the [Esprima JavaScript parser](https://www.npmjs.com/package/esprima) when you call `recast.parse(code)`. While Esprima supports almost all modern ECMAScript syntax, you may want to use a different parser to enable TypeScript or Flow syntax, or just because you want to match other compilation tools you might be using.

Expand Down Expand Up @@ -160,21 +172,21 @@ const tsAst = recast.parse(source, {

After calling `recast.parse`, if you're going to transform the AST, make sure that the `.original` property is preserved. With Babel, for instance, if you call `transformFromAST`, you must pass `cloneInputAst: false` in its options. ([More detail](https://github.com/babel/babel/issues/12882).

Source maps
---
## Source maps

One of the coolest consequences of tracking and reusing original source code during reprinting is that it's pretty easy to generate a high-resolution mapping between the original code and the generated code—completely automatically!

With every `slice`, `join`, and re-`indent`-ation, the reprinting process maintains exact knowledge of which character sequences are original, and where in the original source they came from.

All you have to think about is how to manipulate the syntax tree, and Recast will give you a [source map](https://github.com/mozilla/source-map) in exchange for specifying the names of your source file(s) and the desired name of the map:

```js
var result = recast.print(transform(recast.parse(source, {
sourceFileName: "source.js"
})), {
sourceMapName: "map.json"
});

console.log(result.code); // Resulting string of code.
console.log(result.map); // JSON source map.

Expand All @@ -193,13 +205,12 @@ Note that you are free to mix and match syntax trees parsed from different sourc

Note also that the source maps generated by Recast are character-by-character maps, so meaningful identifier names are not recorded at this time. This approach leads to higher-resolution debugging in modern browsers, at the expense of somewhat larger map sizes. Striking the perfect balance here is an area for future exploration, but such improvements will not require any breaking changes to the interface demonstrated above.

Options
---
## Options

All Recast API functions take second parameter with configuration options, documented in
[options.ts](https://github.com/benjamn/recast/blob/master/lib/options.ts)

Motivation
---
## Motivation

The more code you have, the harder it becomes to make big, sweeping changes quickly and confidently. Even if you trust yourself not to make too many mistakes, and no matter how proficient you are with your text editor, changing tens of thousands of lines of code takes precious, non-refundable time.

Expand Down
4 changes: 2 additions & 2 deletions lib/fast-path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ interface FastPathConstructor {
from(obj: any): any;
}

const FastPath = (function FastPath(this: FastPathType, value: any) {
const FastPath = function FastPath(this: FastPathType, value: any) {
assert.ok(this instanceof FastPath);
this.stack = [value];
} as any) as FastPathConstructor;
} as any as FastPathConstructor;

const FPp: FastPathType = FastPath.prototype;

Expand Down
11 changes: 4 additions & 7 deletions lib/lines.ts
Original file line number Diff line number Diff line change
Expand Up @@ -555,12 +555,8 @@ export class Lines {
end: Pos = this.lastPos(),
options?: Options,
) {
const {
tabWidth,
useTabs,
reuseWhitespace,
lineTerminator,
} = normalizeOptions(options);
const { tabWidth, useTabs, reuseWhitespace, lineTerminator } =
normalizeOptions(options);

const parts = [];

Expand Down Expand Up @@ -750,7 +746,8 @@ export function countSpaces(spaces: any, tabWidth?: number) {
const leadingSpaceExp = /^\s*/;

// As specified here: http:https://www.ecma-international.org/ecma-262/6.0/#sec-line-terminators
const lineTerminatorSeqExp = /\u000D\u000A|\u000D(?!\u000A)|\u000A|\u2028|\u2029/;
const lineTerminatorSeqExp =
/\u000D\u000A|\u000D(?!\u000A)|\u000A|\u2028|\u2029/;

/**
* @param {Object} options - Options object that configures printing.
Expand Down
4 changes: 2 additions & 2 deletions lib/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ interface TreeCopierConstructor {
new (lines: any, tokens: any): TreeCopierType;
}

const TreeCopier = (function TreeCopier(
const TreeCopier = function TreeCopier(
this: TreeCopierType,
lines: any,
tokens: any,
Expand All @@ -150,7 +150,7 @@ const TreeCopier = (function TreeCopier(
this.endTokenIndex = tokens.length;
this.indent = 0;
this.seen = new Map();
} as any) as TreeCopierConstructor;
} as any as TreeCopierConstructor;

const TCp: TreeCopierType = TreeCopier.prototype;

Expand Down
4 changes: 2 additions & 2 deletions lib/patcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ interface PatcherConstructor {
new (lines: any): PatcherType;
}

const Patcher = (function Patcher(this: PatcherType, lines: any) {
const Patcher = function Patcher(this: PatcherType, lines: any) {
assert.ok(this instanceof Patcher);
assert.ok(lines instanceof linesModule.Lines);

Expand Down Expand Up @@ -71,7 +71,7 @@ const Patcher = (function Patcher(this: PatcherType, lines: any) {

return linesModule.concat(toConcat);
};
} as any) as PatcherConstructor;
} as any as PatcherConstructor;
export { Patcher };

const Pp: PatcherType = Patcher.prototype;
Expand Down
Loading