diff --git a/.prettierignore b/.prettierignore index 5b29e158..047e5087 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,3 @@ -**/*.d.ts +*.d.ts +test/data/ +/example diff --git a/.prettierrc.js b/.prettierrc.js index 52988ff8..46207e36 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -8,6 +8,8 @@ module.exports = { files: "*.md", options: { printWidth: 60, + // Don't reformat code examples in README + embeddedLanguageFormatting: "off", }, }, ], diff --git a/README.md b/README.md index 87b430cb..d55db99f 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,12 @@ 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 @@ -19,10 +18,10 @@ From GitHub: 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); @@ -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); @@ -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"; @@ -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]; @@ -89,11 +91,15 @@ 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 + @@ -101,26 +107,32 @@ var add = function(b, a) { 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. @@ -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. @@ -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. diff --git a/lib/fast-path.ts b/lib/fast-path.ts index d6fa4e7b..cadf01cb 100644 --- a/lib/fast-path.ts +++ b/lib/fast-path.ts @@ -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; diff --git a/lib/lines.ts b/lib/lines.ts index 75c87cfb..3eaddab7 100644 --- a/lib/lines.ts +++ b/lib/lines.ts @@ -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 = []; @@ -750,7 +746,8 @@ export function countSpaces(spaces: any, tabWidth?: number) { const leadingSpaceExp = /^\s*/; // As specified here: http://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. diff --git a/lib/parser.ts b/lib/parser.ts index 60e36776..ca48b56b 100644 --- a/lib/parser.ts +++ b/lib/parser.ts @@ -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, @@ -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; diff --git a/lib/patcher.ts b/lib/patcher.ts index 3a19befd..733b48e8 100644 --- a/lib/patcher.ts +++ b/lib/patcher.ts @@ -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); @@ -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; diff --git a/lib/printer.ts b/lib/printer.ts index 8c3ab5d1..3452f75b 100644 --- a/lib/printer.ts +++ b/lib/printer.ts @@ -20,7 +20,7 @@ interface PrintResultConstructor { new (code: any, sourceMap?: any): PrintResultType; } -const PrintResult = (function PrintResult( +const PrintResult = function PrintResult( this: PrintResultType, code: any, sourceMap?: any, @@ -34,7 +34,7 @@ const PrintResult = (function PrintResult( isObject.assert(sourceMap); this.map = sourceMap; } -} as any) as PrintResultConstructor; +} as any as PrintResultConstructor; const PRp: PrintResultType = PrintResult.prototype; let warnedAboutToString = false; @@ -64,7 +64,7 @@ interface PrinterConstructor { new (config?: any): PrinterType; } -const Printer = (function Printer(this: PrinterType, config?: any) { +const Printer = function Printer(this: PrinterType, config?: any) { assert.ok(this instanceof Printer); const explicitTabWidth = config && config.tabWidth; @@ -181,7 +181,7 @@ const Printer = (function Printer(this: PrinterType, config?: any) { config.reuseWhitespace = oldReuseWhitespace; return pr; }; -} as any) as PrinterConstructor; +} as any as PrinterConstructor; export { Printer }; @@ -619,15 +619,11 @@ function genericPrintNoParens(path: any, options: any, print: any) { } case "ImportAttribute": - return concat([ - path.call(print, "key"), - ": ", - path.call(print, "value"), - ]); + return concat([path.call(print, "key"), ": ", path.call(print, "value")]); case "StaticBlock": parts.push("static "); - // Intentionally fall through to BlockStatement below. + // Intentionally fall through to BlockStatement below. case "BlockStatement": { const naked = path.call( @@ -705,7 +701,7 @@ function genericPrintNoParens(path: any, options: any, print: any) { case "RecordExpression": parts.push("#"); - // Intentionally fall through to printing the object literal... + // Intentionally fall through to printing the object literal... case "ObjectExpression": case "ObjectPattern": case "ObjectTypeAnnotation": { @@ -846,7 +842,7 @@ function genericPrintNoParens(path: any, options: any, print: any) { case "TupleExpression": parts.push("#"); - // Intentionally fall through to printing the tuple elements... + // Intentionally fall through to printing the tuple elements... case "ArrayExpression": case "ArrayPattern": { const elems: any[] = n.elements; @@ -924,31 +920,20 @@ function genericPrintNoParens(path: any, options: any, print: any) { ); case "BigIntLiteral": // Babel 7 Literal split - return fromString( - getPossibleRaw(n) || (n.value + "n"), - options, - ); + return fromString(getPossibleRaw(n) || n.value + "n", options); case "NumericLiteral": // Babel 6 Literal Split - return fromString( - getPossibleRaw(n) || n.value, - options, - ); + return fromString(getPossibleRaw(n) || n.value, options); case "DecimalLiteral": - return fromString( - getPossibleRaw(n) || (n.value + "m"), - options, - ); + return fromString(getPossibleRaw(n) || n.value + "m", options); case "BooleanLiteral": // Babel 6 Literal split case "StringLiteral": // Babel 6 Literal split case "Literal": return fromString( - getPossibleRaw(n) || ( - typeof n.value === "string" - ? nodeStr(n.value, options) - : n.value), + getPossibleRaw(n) || + (typeof n.value === "string" ? nodeStr(n.value, options) : n.value), options, ); @@ -2898,7 +2883,7 @@ function maybePrintImportAssertions( "\n}", ); } else { - parts.push(" ", flat, " }") + parts.push(" ", flat, " }"); } return concat(parts); } @@ -2982,7 +2967,8 @@ function printExportDeclaration(path: any, options: any, print: any) { if (decl.source) { parts.push( - " from ", path.call(print, "source"), + " from ", + path.call(print, "source"), maybePrintImportAssertions(path, options, print), ); } @@ -3062,22 +3048,19 @@ function swapQuotes(str: string) { return str.replace(/['"]/g, (m) => (m === '"' ? "'" : '"')); } -function getPossibleRaw(node: - | types.namedTypes.Literal - | types.namedTypes.NumericLiteral - | types.namedTypes.StringLiteral - | types.namedTypes.RegExpLiteral - | types.namedTypes.BigIntLiteral - | types.namedTypes.DecimalLiteral +function getPossibleRaw( + node: + | types.namedTypes.Literal + | types.namedTypes.NumericLiteral + | types.namedTypes.StringLiteral + | types.namedTypes.RegExpLiteral + | types.namedTypes.BigIntLiteral + | types.namedTypes.DecimalLiteral, ): string | void { const value = types.getFieldValue(node, "value"); const extra = types.getFieldValue(node, "extra"); - if ( - extra && - typeof extra.raw === "string" && - value == extra.rawValue - ) { + if (extra && typeof extra.raw === "string" && value == extra.rawValue) { return extra.raw; } diff --git a/main.ts b/main.ts index aab2e650..4d4f7e92 100644 --- a/main.ts +++ b/main.ts @@ -10,7 +10,6 @@ export { * arbitrary modification and reprinting. */ parse, - /** * Convenient shorthand for the ast-types package. */ @@ -68,7 +67,7 @@ export interface RunOptions extends Options { } function runFile(path: any, transformer: Transformer, options?: RunOptions) { - fs.readFile(path, "utf-8", function(err, code) { + fs.readFile(path, "utf-8", function (err, code) { if (err) { console.error(err); return; @@ -82,9 +81,13 @@ function defaultWriteback(output: string) { process.stdout.write(output); } -function runString(code: string, transformer: Transformer, options?: RunOptions) { - const writeback = options && options.writeback || defaultWriteback; - transformer(parse(code, options), function(node: any) { +function runString( + code: string, + transformer: Transformer, + options?: RunOptions, +) { + const writeback = (options && options.writeback) || defaultWriteback; + transformer(parse(code, options), function (node: any) { writeback(print(node, options).code); }); } diff --git a/package-lock.json b/package-lock.json index 591508c2..3c1beaa2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,7 @@ "glob": "7.2.0", "lint-staged": "^12.4.1", "mocha": "9.0.2", - "prettier": "^2.0.5", + "prettier": "^2.6.2", "reify": "0.20.12", "ts-emit-clean": "1.0.0", "typescript": "^4.3.5" @@ -4605,15 +4605,18 @@ } }, "node_modules/prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", "dev": true, "bin": { "prettier": "bin-prettier.js" }, "engines": { "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/progress": { @@ -8883,9 +8886,9 @@ "dev": true }, "prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", "dev": true }, "progress": { diff --git a/package.json b/package.json index b6c7617b..3a3c305b 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "test": "npm run lint && npm run build && npm run mocha", "build": "npm run clean && tsc", "lint": "eslint --ext .ts .", - "format": "prettier --write '{lib,test}/**.ts' '*rc.js'", + "format": "prettier --write .", "clean": "ts-emit-clean", "prepack": "npm run build", "postpack": "npm run clean" @@ -62,7 +62,7 @@ "glob": "7.2.0", "lint-staged": "^12.4.1", "mocha": "9.0.2", - "prettier": "^2.0.5", + "prettier": "^2.6.2", "reify": "0.20.12", "ts-emit-clean": "1.0.0", "typescript": "^4.3.5" diff --git a/parsers/_babel_options.ts b/parsers/_babel_options.ts index 3af8cbc3..60d50ac5 100644 --- a/parsers/_babel_options.ts +++ b/parsers/_babel_options.ts @@ -6,7 +6,9 @@ export type Overrides = Partial<{ strictMode: ParserOptions["strictMode"]; }>; -export default function getBabelOptions(options?: Overrides): ParserOptions & { plugins: ParserPlugin[] } { +export default function getBabelOptions( + options?: Overrides, +): ParserOptions & { plugins: ParserPlugin[] } { // The goal here is to tolerate as much syntax as possible, since Recast // is not in the business of forbidding anything. If you want your // parser to be more restrictive for some reason, you can always pass @@ -41,15 +43,21 @@ export default function getBabelOptions(options?: Overrides): ParserOptions & { "objectRestSpread", "optionalCatchBinding", "optionalChaining", - ["pipelineOperator", { - proposal: "minimal", - }] as any as ParserPlugin, - ["recordAndTuple", { - syntaxType: "hash", - }], + [ + "pipelineOperator", + { + proposal: "minimal", + }, + ] as any as ParserPlugin, + [ + "recordAndTuple", + { + syntaxType: "hash", + }, + ], "throwExpressions", "topLevelAwait", "v8intrinsic", - ] + ], }; -}; +} diff --git a/parsers/acorn.ts b/parsers/acorn.ts index beb2dae7..ad23bb35 100644 --- a/parsers/acorn.ts +++ b/parsers/acorn.ts @@ -21,13 +21,13 @@ export function parse(source: string, options?: any) { onToken: tokens, }); - if (! ast.comments) { + if (!ast.comments) { ast.comments = comments; } - if (! ast.tokens) { + if (!ast.tokens) { ast.tokens = tokens; } return ast; -}; +} diff --git a/parsers/babel.ts b/parsers/babel.ts index edf86dec..25b134ea 100644 --- a/parsers/babel.ts +++ b/parsers/babel.ts @@ -5,13 +5,13 @@ type BabelParser = { parse: typeof babelParse }; // Prefer the new @babel/parser package, but fall back to babylon if // that's what's available. -export const parser = function (): BabelParser { +export const parser = (function (): BabelParser { try { return require("@babel/parser"); } catch (e) { return require("babylon"); } -}(); +})(); // This module is suitable for passing as options.parser when calling // recast.parse to process JavaScript code with Babel: @@ -24,4 +24,4 @@ export function parse(source: string, options?: Overrides) { const babelOptions = getBabelOptions(options); babelOptions.plugins.push("jsx", "flow"); return parser.parse(source, babelOptions); -}; +} diff --git a/parsers/esprima.ts b/parsers/esprima.ts index 09913c5c..f2486c2e 100644 --- a/parsers/esprima.ts +++ b/parsers/esprima.ts @@ -19,7 +19,7 @@ export function parse(source: string, options?: any) { range: getOption(options, "range", false), tolerant: getOption(options, "tolerant", true), tokens: true, - jsx: getOption(options, "jsx", false) + jsx: getOption(options, "jsx", false), }); if (!Array.isArray(ast.comments)) { @@ -27,4 +27,4 @@ export function parse(source: string, options?: any) { } return ast; -}; +} diff --git a/parsers/flow.ts b/parsers/flow.ts index 49592c60..771c6ced 100644 --- a/parsers/flow.ts +++ b/parsers/flow.ts @@ -12,4 +12,4 @@ export function parse(source: string, options?: Overrides) { const babelOptions = getBabelOptions(options); babelOptions.plugins.push("jsx", "flow"); return parser.parse(source, babelOptions); -}; +} diff --git a/parsers/typescript.ts b/parsers/typescript.ts index 1c8e93ad..c258ce93 100644 --- a/parsers/typescript.ts +++ b/parsers/typescript.ts @@ -12,4 +12,4 @@ export function parse(source: string, options?: Overrides) { const babelOptions = getBabelOptions(options); babelOptions.plugins.push("typescript"); return parser.parse(source, babelOptions); -}; +} diff --git a/test/babel.ts b/test/babel.ts index 39cea3a4..72be5c87 100644 --- a/test/babel.ts +++ b/test/babel.ts @@ -150,14 +150,11 @@ describe("Babel", function () { " 3.1415926535897932m,", " 100.000m,", " 123456.789m", - ");" + ");", ]); // V8IntrinsicIdentifier - check([ - "%DebugPrint('hello');", - "%DebugPrint(%StringParseInt('42', 10));", - ]); + check(["%DebugPrint('hello');", "%DebugPrint(%StringParseInt('42', 10));"]); }); it("babel 6: should not wrap IIFE when reusing nodes", function () { diff --git a/test/comments.ts b/test/comments.ts index 75aeb9ea..4029c036 100644 --- a/test/comments.ts +++ b/test/comments.ts @@ -177,13 +177,15 @@ function runTestsForParser(parserId: any) { }, }; - const info = ({ - acorn: esprimaInfo, - babel: babelInfo, - esprima: esprimaInfo, - flow: babelInfo, - typescript: babelInfo, - } as any)[parserName]; + const info = ( + { + acorn: esprimaInfo, + babel: babelInfo, + esprima: esprimaInfo, + flow: babelInfo, + typescript: babelInfo, + } as any + )[parserName]; const props = assign.right.properties; info.Property.arrayOf().assert(props); diff --git a/test/printer.ts b/test/printer.ts index 0278a06c..03ebb307 100644 --- a/test/printer.ts +++ b/test/printer.ts @@ -663,17 +663,11 @@ describe("printer", function () { it("pretty-prints U+2028 and U+2029 as Unicode escapes", function () { const ast = parse('"\\u2028";'); const printer = new Printer(); - assert.strictEqual( - printer.printGenerically(ast).code, - '"\\u2028";', - ); + assert.strictEqual(printer.printGenerically(ast).code, '"\\u2028";'); const ast2 = parse('"\\u2029";'); const printer2 = new Printer(); - assert.strictEqual( - printer2.printGenerically(ast2).code, - '"\\u2029";', - ); + assert.strictEqual(printer2.printGenerically(ast2).code, '"\\u2029";'); }); it("should print block comments at head of class once", function () { @@ -1714,12 +1708,8 @@ describe("printer", function () { it("prints chained expression elements", function () { const node = b.chainExpression( - b.memberExpression( - b.identifier("foo"), - b.identifier("bar"), - false - ), - ) + b.memberExpression(b.identifier("foo"), b.identifier("bar"), false), + ); assert.strictEqual(recast.print(node).code, "foo.bar"); }); @@ -1730,9 +1720,9 @@ describe("printer", function () { b.identifier("foo"), b.identifier("bar"), false, - true + true, ), - ) + ); assert.strictEqual(recast.print(node).code, "foo?.bar"); }); @@ -2235,23 +2225,29 @@ describe("printer", function () { }); const emptyBlockReprinted = printer.print(ast).code; - assert.strictEqual(emptyBlockReprinted, [ - "class A {", - " static a = 1;", - " static #b = 2;", - "", // Empty line preserved because of conservative printer.print reprinting. - " static {}", - "}", - ].join(eol)); + assert.strictEqual( + emptyBlockReprinted, + [ + "class A {", + " static a = 1;", + " static #b = 2;", + "", // Empty line preserved because of conservative printer.print reprinting. + " static {}", + "}", + ].join(eol), + ); const emptyBlockPrettyPrinted = printer.printGenerically(ast).code; - assert.strictEqual(emptyBlockPrettyPrinted, [ - "class A {", - " static a = 1;", - " static #b = 2;", - " static {}", - "}", - ].join(eol)); + assert.strictEqual( + emptyBlockPrettyPrinted, + [ + "class A {", + " static a = 1;", + " static #b = 2;", + " static {}", + "}", + ].join(eol), + ); }); it("can pretty-print ImportAttribute syntax", function () { @@ -2266,10 +2262,10 @@ describe("printer", function () { 'import * as noAssertions from "./module";', 'import * as emptyAssert from "./module";', 'import json from "./module" assert { type: "json" };', - '', + "", 'import * as ns from "./module" assert {', ' type: "reallyLongStringLiteralThatShouldTriggerReflowOntoMultipleLines"', - '};', + "};", ].join(eol); const printer = new Printer({ @@ -2297,12 +2293,15 @@ describe("printer", function () { }); const reprinted = printer.print(ast).code; - assert.strictEqual(reprinted, [ - 'import * as noAssertions from "./module";', - 'import * as emptyAssert from "./module" assert {};', - 'import json from "./module" assert { type: "json" };', - 'import * as ns from "./module" assert { type: "shorter" }', - ].join(eol)); + assert.strictEqual( + reprinted, + [ + 'import * as noAssertions from "./module";', + 'import * as emptyAssert from "./module" assert {};', + 'import json from "./module" assert { type: "json" };', + 'import * as ns from "./module" assert { type: "shorter" }', + ].join(eol), + ); }); it("can pretty-print RecordExpression syntax", function () { @@ -2359,8 +2358,8 @@ describe("printer", function () { it("can pretty-print ModuleExpression syntax", function () { const code = [ 'import { log } from "logger";', - 'export const url = import.meta.url;', - 'log(url);', + "export const url = import.meta.url;", + "log(url);", ].join(eol); const ast = parse(code, { @@ -2375,13 +2374,12 @@ describe("printer", function () { const pretty = printer.printGenerically(ast).code; assert.strictEqual(pretty, code); - const reprinted = printer.print( - b.moduleExpression(ast.program) - ).code; - assert.strictEqual(reprinted, [ - "module {", - ...code.split(eol).map(line => " " + line), - "}", - ].join(eol)); + const reprinted = printer.print(b.moduleExpression(ast.program)).code; + assert.strictEqual( + reprinted, + ["module {", ...code.split(eol).map((line) => " " + line), "}"].join( + eol, + ), + ); }); }); diff --git a/test/typescript.ts b/test/typescript.ts index a776d7aa..65dc82c4 100644 --- a/test/typescript.ts +++ b/test/typescript.ts @@ -310,26 +310,22 @@ const nodeMajorVersion = parseInt(process.versions.node, 10); it("InterfaceBody: duplicate semicolon", function () { const code = [ - "interface Hello {", - " 'hello': any;", - " 'hello': string;", - "}", + "interface Hello {", + " 'hello': any;", + " 'hello': string;", + "}", ].join(eol); - + const ast = recast.parse(code, { parser }); - + ast.program.body[0].body.body.pop(); assert.strictEqual( recast.print(ast).code, - [ - "interface Hello {", - " 'hello': any;", - "}", - ].join(eol), + ["interface Hello {", " 'hello': any;", "}"].join(eol), ); }); - + it("InterfaceBody: duplicate semicolon: a lot of properties", function () { const code = [ "interface LabelledContainer {", @@ -346,9 +342,9 @@ const nodeMajorVersion = parseInt(process.versions.node, 10); " a(c: (this: void, e: E) => void): void;", "}", ].join(eol); - + const ast = recast.parse(code, { parser }); - + ast.program.body[0].body.body.shift(); assert.strictEqual(