From 9ac36b136adcfa1940cdcc60399cb4079fb67361 Mon Sep 17 00:00:00 2001 From: Bogdan Savluk Date: Wed, 27 Jan 2021 19:21:07 +0100 Subject: [PATCH] convert `@babel/generator` to TypeScript (#12487) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nicolò Ribaudo --- lib/babel-packages.js.flow | 5 + packages/babel-generator/package.json | 5 +- .../src/{buffer.js => buffer.ts} | 60 +++-- .../src/generators/{base.js => base.ts} | 22 +- .../src/generators/{classes.js => classes.ts} | 24 +- .../{expressions.js => expressions.ts} | 79 ++++-- .../src/generators/{flow.js => flow.ts} | 224 +++++++++++----- .../src/generators/{index.js => index.ts} | 0 .../src/generators/{jsx.js => jsx.ts} | 43 +-- .../src/generators/{methods.js => methods.ts} | 20 +- .../src/generators/{modules.js => modules.ts} | 50 +++- .../{statements.js => statements.ts} | 46 ++-- ...plate-literals.js => template-literals.ts} | 16 +- .../src/generators/{types.js => types.ts} | 46 ++-- .../{typescript.js => typescript.ts} | 191 +++++++++----- packages/babel-generator/src/index.js | 119 --------- packages/babel-generator/src/index.ts | 246 ++++++++++++++++++ .../src/node/{index.js => index.ts} | 4 +- .../node/{parentheses.js => parentheses.ts} | 75 +++--- .../src/node/{whitespace.js => whitespace.ts} | 94 ++++--- .../src/{printer.js => printer.ts} | 90 ++++--- .../src/{source-map.js => source-map.ts} | 11 +- yarn.lock | 25 +- 23 files changed, 982 insertions(+), 513 deletions(-) rename packages/babel-generator/src/{buffer.js => buffer.ts} (90%) rename packages/babel-generator/src/generators/{base.js => base.ts} (77%) rename packages/babel-generator/src/generators/{classes.js => classes.ts} (82%) rename packages/babel-generator/src/generators/{expressions.js => expressions.ts} (69%) rename packages/babel-generator/src/generators/{flow.js => flow.ts} (65%) rename packages/babel-generator/src/generators/{index.js => index.ts} (100%) rename packages/babel-generator/src/generators/{jsx.js => jsx.ts} (56%) rename packages/babel-generator/src/generators/{methods.js => methods.ts} (83%) rename packages/babel-generator/src/generators/{modules.js => modules.ts} (75%) rename packages/babel-generator/src/generators/{statements.js => statements.ts} (79%) rename packages/babel-generator/src/generators/{template-literals.js => template-literals.ts} (60%) rename packages/babel-generator/src/generators/{types.js => types.ts} (76%) rename packages/babel-generator/src/generators/{typescript.js => typescript.ts} (64%) delete mode 100644 packages/babel-generator/src/index.js create mode 100644 packages/babel-generator/src/index.ts rename packages/babel-generator/src/node/{index.js => index.ts} (95%) rename packages/babel-generator/src/node/{parentheses.js => parentheses.ts} (80%) rename packages/babel-generator/src/node/{whitespace.js => whitespace.ts} (68%) rename packages/babel-generator/src/{printer.js => printer.ts} (90%) rename packages/babel-generator/src/{source-map.js => source-map.ts} (89%) diff --git a/lib/babel-packages.js.flow b/lib/babel-packages.js.flow index 22d1926abb..4a91be1750 100644 --- a/lib/babel-packages.js.flow +++ b/lib/babel-packages.js.flow @@ -172,3 +172,8 @@ declare module "@babel/helper-split-export-declaration" { declare module "@babel/traverse" { declare module.exports: any; } + +declare module "@babel/generator" { + declare module.exports: any; +} + diff --git a/packages/babel-generator/package.json b/packages/babel-generator/package.json index f938349f6c..8de1fa1916 100644 --- a/packages/babel-generator/package.json +++ b/packages/babel-generator/package.json @@ -25,6 +25,9 @@ }, "devDependencies": { "@babel/helper-fixtures": "workspace:*", - "@babel/parser": "workspace:*" + "@babel/parser": "workspace:*", + "@types/jsesc": "^2.5.0", + "@types/lodash": "^4.14.150", + "@types/source-map": "^0.5.0" } } diff --git a/packages/babel-generator/src/buffer.js b/packages/babel-generator/src/buffer.ts similarity index 90% rename from packages/babel-generator/src/buffer.js rename to packages/babel-generator/src/buffer.ts index 2714bf3fcf..f94a4d8225 100644 --- a/packages/babel-generator/src/buffer.js +++ b/packages/babel-generator/src/buffer.ts @@ -1,4 +1,5 @@ import type SourceMap from "./source-map"; +import type * as t from "@babel/types"; const SPACES_RE = /^[ \t]+$/; @@ -10,32 +11,41 @@ const SPACES_RE = /^[ \t]+$/; */ export default class Buffer { - constructor(map: ?SourceMap) { + constructor(map?: SourceMap | null) { this._map = map; } _map: SourceMap = null; - _buf: Array = []; + _buf: Array = []; _last: string = ""; - _queue: Array = []; + _queue: Array< + [ + str: string, + line: number, + column: number, + identifierName: string | null, + filename: string | null | undefined, + force: boolean | undefined, + ] + > = []; - _position: Object = { + _position: any = { line: 1, column: 0, }; - _sourcePosition: Object = { + _sourcePosition: any = { identifierName: null, line: null, column: null, filename: null, }; - _disallowedPop: Object | null = null; + _disallowedPop: any | null = null; /** * Get the final string output from the buffer, along with the sourcemap if one exists. */ - get(): Object { + get(): any { this._flush(); const map = this._map; @@ -104,16 +114,25 @@ export default class Buffer { } _flush(): void { - let item; - while ((item = this._queue.pop())) this._append(...item); + let item: [ + string, + number, + number, + string | null | undefined, + string | null | undefined, + boolean | undefined, + ]; + while ((item = this._queue.pop())) { + this._append(...item); + } } _append( str: string, line: number, column: number, - identifierName: ?string, - filename: ?string, + identifierName?: string | null, + filename?: string | null, force?: boolean, ): void { this._buf.push(str); @@ -151,8 +170,8 @@ export default class Buffer { _mark( line: number, column: number, - identifierName: ?string, - filename: ?string, + identifierName?: string | null, + filename?: string | null, force?: boolean, ): void { this._map?.mark( @@ -230,7 +249,7 @@ export default class Buffer { * With this line, there will be one mapping range over "mod" and another * over "();", where previously it would have been a single mapping. */ - exactSource(loc: Object, cb: () => void) { + exactSource(loc: any, cb: () => void) { // In cases where parent expressions start at the same locations as the // identifier itself, the current active location could already be the // start of this range. We use 'force' here to explicitly start a new @@ -255,7 +274,7 @@ export default class Buffer { * will be given this position in the sourcemap. */ - source(prop: string, loc: Location, force?: boolean): void { + source(prop: string, loc: t.SourceLocation, force?: boolean): void { if (prop && !loc) return; // Since this is called extremely often, we re-use the same _sourcePosition @@ -267,7 +286,7 @@ export default class Buffer { * Call a callback with a specific source location and restore on completion. */ - withSource(prop: string, loc: Location, cb: () => void): void { + withSource(prop: string, loc: t.SourceLocation, cb: () => void): void { if (!this._map) return cb(); // Use the call stack to manage a stack of "source location" data because @@ -309,18 +328,13 @@ export default class Buffer { * sourcemap output, so that certain printers can be sure that the * "end" location that they set is actually treated as the end position. */ - _disallowPop(prop: string, loc: Location) { + _disallowPop(prop: string, loc: t.SourceLocation) { if (prop && !loc) return; this._disallowedPop = this._normalizePosition(prop, loc); } - _normalizePosition( - prop: string, - loc: Object, - targetObj: Object, - force?: boolean, - ) { + _normalizePosition(prop: string, loc: any, targetObj?: any, force?: boolean) { const pos = loc ? loc[prop] : null; if (targetObj === undefined) { diff --git a/packages/babel-generator/src/generators/base.js b/packages/babel-generator/src/generators/base.ts similarity index 77% rename from packages/babel-generator/src/generators/base.js rename to packages/babel-generator/src/generators/base.ts index 0f3c8f2895..3d87606250 100644 --- a/packages/babel-generator/src/generators/base.js +++ b/packages/babel-generator/src/generators/base.ts @@ -1,4 +1,7 @@ -export function File(node: Object) { +import type Printer from "../printer"; +import * as t from "@babel/types"; + +export function File(this: Printer, node: t.File) { if (node.program) { // Print this here to ensure that Program node 'leadingComments' still // get printed after the hashbang. @@ -8,7 +11,7 @@ export function File(node: Object) { this.print(node.program, node); } -export function Program(node: Object) { +export function Program(this: Printer, node: t.Program) { this.printInnerComments(node, false); this.printSequence(node.directives, node); @@ -17,7 +20,7 @@ export function Program(node: Object) { this.printSequence(node.body, node); } -export function BlockStatement(node: Object) { +export function BlockStatement(this: Printer, node: t.BlockStatement) { this.token("{"); this.printInnerComments(node); @@ -43,9 +46,9 @@ export function BlockStatement(node: Object) { } } -export function Noop() {} +export function Noop(this: Printer) {} -export function Directive(node: Object) { +export function Directive(this: Printer, node: t.Directive) { this.print(node.value, node); this.semicolon(); } @@ -54,7 +57,7 @@ export function Directive(node: Object) { const unescapedSingleQuoteRE = /(?:^|[^\\])(?:\\\\)*'/; const unescapedDoubleQuoteRE = /(?:^|[^\\])(?:\\\\)*"/; -export function DirectiveLiteral(node: Object) { +export function DirectiveLiteral(this: Printer, node: t.DirectiveLiteral) { const raw = this.getPossibleRaw(node); if (raw != null) { this.token(raw); @@ -79,11 +82,14 @@ export function DirectiveLiteral(node: Object) { } } -export function InterpreterDirective(node: Object) { +export function InterpreterDirective( + this: Printer, + node: t.InterpreterDirective, +) { this.token(`#!${node.value}\n`); } -export function Placeholder(node: Object) { +export function Placeholder(this: Printer, node: t.Placeholder) { this.token("%%"); this.print(node.name); this.token("%%"); diff --git a/packages/babel-generator/src/generators/classes.js b/packages/babel-generator/src/generators/classes.ts similarity index 82% rename from packages/babel-generator/src/generators/classes.js rename to packages/babel-generator/src/generators/classes.ts index e08fc35ef5..2c32f3164f 100644 --- a/packages/babel-generator/src/generators/classes.js +++ b/packages/babel-generator/src/generators/classes.ts @@ -1,6 +1,11 @@ +import type Printer from "../printer"; import * as t from "@babel/types"; -export function ClassDeclaration(node: Object, parent: Object) { +export function ClassDeclaration( + this: Printer, + node: t.ClassDeclaration, + parent: any, +) { if ( !this.format.decoratorsBeforeExport || (!t.isExportDefaultDeclaration(parent) && @@ -51,7 +56,7 @@ export function ClassDeclaration(node: Object, parent: Object) { export { ClassDeclaration as ClassExpression }; -export function ClassBody(node: Object) { +export function ClassBody(this: Printer, node: t.ClassBody) { this.token("{"); this.printInnerComments(node); if (node.body.length === 0) { @@ -69,7 +74,7 @@ export function ClassBody(node: Object) { } } -export function ClassProperty(node: Object) { +export function ClassProperty(this: Printer, node: t.ClassProperty) { this.printJoin(node.decorators, node); // catch up to property key, avoid line break @@ -105,7 +110,10 @@ export function ClassProperty(node: Object) { this.semicolon(); } -export function ClassPrivateProperty(node: Object) { +export function ClassPrivateProperty( + this: Printer, + node: t.ClassPrivateProperty, +) { this.printJoin(node.decorators, node); if (node.static) { this.word("static"); @@ -122,19 +130,19 @@ export function ClassPrivateProperty(node: Object) { this.semicolon(); } -export function ClassMethod(node: Object) { +export function ClassMethod(this: Printer, node: t.ClassMethod) { this._classMethodHead(node); this.space(); this.print(node.body, node); } -export function ClassPrivateMethod(node: Object) { +export function ClassPrivateMethod(this: Printer, node: t.ClassPrivateMethod) { this._classMethodHead(node); this.space(); this.print(node.body, node); } -export function _classMethodHead(node) { +export function _classMethodHead(this: Printer, node) { this.printJoin(node.decorators, node); // catch up to method key, avoid line break // between member modifiers/method heads and the method key. @@ -143,7 +151,7 @@ export function _classMethodHead(node) { this._methodHead(node); } -export function StaticBlock(node) { +export function StaticBlock(node: t.StaticBlock) { this.word("static"); this.space(); this.token("{"); diff --git a/packages/babel-generator/src/generators/expressions.js b/packages/babel-generator/src/generators/expressions.ts similarity index 69% rename from packages/babel-generator/src/generators/expressions.js rename to packages/babel-generator/src/generators/expressions.ts index 902789ffa5..0ee7f1ead7 100644 --- a/packages/babel-generator/src/generators/expressions.js +++ b/packages/babel-generator/src/generators/expressions.ts @@ -1,7 +1,8 @@ +import type Printer from "../printer"; import * as t from "@babel/types"; import * as n from "../node"; -export function UnaryExpression(node: Object) { +export function UnaryExpression(this: Printer, node: t.UnaryExpression) { if ( node.operator === "void" || node.operator === "delete" || @@ -18,19 +19,22 @@ export function UnaryExpression(node: Object) { this.print(node.argument, node); } -export function DoExpression(node: Object) { +export function DoExpression(this: Printer, node: t.DoExpression) { this.word("do"); this.space(); this.print(node.body, node); } -export function ParenthesizedExpression(node: Object) { +export function ParenthesizedExpression( + this: Printer, + node: t.ParenthesizedExpression, +) { this.token("("); this.print(node.expression, node); this.token(")"); } -export function UpdateExpression(node: Object) { +export function UpdateExpression(this: Printer, node: t.UpdateExpression) { if (node.prefix) { this.token(node.operator); this.print(node.argument, node); @@ -42,7 +46,10 @@ export function UpdateExpression(node: Object) { } } -export function ConditionalExpression(node: Object) { +export function ConditionalExpression( + this: Printer, + node: t.ConditionalExpression, +) { this.print(node.test, node); this.space(); this.token("?"); @@ -54,7 +61,11 @@ export function ConditionalExpression(node: Object) { this.print(node.alternate, node); } -export function NewExpression(node: Object, parent: Object) { +export function NewExpression( + this: Printer, + node: t.NewExpression, + parent: any, +) { this.word("new"); this.space(); this.print(node.callee, node); @@ -80,25 +91,28 @@ export function NewExpression(node: Object, parent: Object) { this.token(")"); } -export function SequenceExpression(node: Object) { +export function SequenceExpression(this: Printer, node: t.SequenceExpression) { this.printList(node.expressions, node); } -export function ThisExpression() { +export function ThisExpression(this: Printer) { this.word("this"); } -export function Super() { +export function Super(this: Printer) { this.word("super"); } -export function Decorator(node: Object) { +export function Decorator(this: Printer, node: t.Decorator) { this.token("@"); this.print(node.expression, node); this.newline(); } -export function OptionalMemberExpression(node: Object) { +export function OptionalMemberExpression( + this: Printer, + node: t.OptionalMemberExpression, +) { this.print(node.object, node); if (!node.computed && t.isMemberExpression(node.property)) { @@ -106,6 +120,7 @@ export function OptionalMemberExpression(node: Object) { } let computed = node.computed; + // @ts-expect-error todo(flow->ts) maybe instead of typeof check specific literal types? if (t.isLiteral(node.property) && typeof node.property.value === "number") { computed = true; } @@ -125,7 +140,10 @@ export function OptionalMemberExpression(node: Object) { } } -export function OptionalCallExpression(node: Object) { +export function OptionalCallExpression( + this: Printer, + node: t.OptionalCallExpression, +) { this.print(node.callee, node); this.print(node.typeArguments, node); // Flow @@ -139,7 +157,7 @@ export function OptionalCallExpression(node: Object) { this.token(")"); } -export function CallExpression(node: Object) { +export function CallExpression(this: Printer, node: t.CallExpression) { this.print(node.callee, node); this.print(node.typeArguments, node); // Flow @@ -149,12 +167,12 @@ export function CallExpression(node: Object) { this.token(")"); } -export function Import() { +export function Import(this: Printer) { this.word("import"); } function buildYieldAwait(keyword: string) { - return function (node: Object) { + return function (node: any) { this.word(keyword); if (node.delegate) { @@ -173,18 +191,23 @@ function buildYieldAwait(keyword: string) { export const YieldExpression = buildYieldAwait("yield"); export const AwaitExpression = buildYieldAwait("await"); -export function EmptyStatement() { +export function EmptyStatement(this: Printer) { this.semicolon(true /* force */); } -export function ExpressionStatement(node: Object) { +export function ExpressionStatement( + this: Printer, + node: t.ExpressionStatement, +) { this.print(node.expression, node); this.semicolon(); } -export function AssignmentPattern(node: Object) { +export function AssignmentPattern(this: Printer, node: t.AssignmentPattern) { this.print(node.left, node); + // @ts-expect-error todo(flow->ts) property present on some of the types in union but not all if (node.left.optional) this.token("?"); + // @ts-expect-error todo(flow->ts) property present on some of the types in union but not all this.print(node.left.typeAnnotation, node); this.space(); this.token("="); @@ -192,7 +215,11 @@ export function AssignmentPattern(node: Object) { this.print(node.right, node); } -export function AssignmentExpression(node: Object, parent: Object) { +export function AssignmentExpression( + this: Printer, + node: t.AssignmentExpression, + parent: any, +) { // Somewhere inside a for statement `init` node but doesn't usually // needs a paren except for `in` expressions: `for (a in b ? a : b;;)` const parens = @@ -221,7 +248,7 @@ export function AssignmentExpression(node: Object, parent: Object) { } } -export function BindExpression(node: Object) { +export function BindExpression(this: Printer, node: t.BindExpression) { this.print(node.object, node); this.token("::"); this.print(node.callee, node); @@ -232,7 +259,7 @@ export { AssignmentExpression as LogicalExpression, }; -export function MemberExpression(node: Object) { +export function MemberExpression(this: Printer, node: t.MemberExpression) { this.print(node.object, node); if (!node.computed && t.isMemberExpression(node.property)) { @@ -240,6 +267,7 @@ export function MemberExpression(node: Object) { } let computed = node.computed; + // @ts-expect-error todo(flow->ts) maybe use specific literal types if (t.isLiteral(node.property) && typeof node.property.value === "number") { computed = true; } @@ -254,18 +282,21 @@ export function MemberExpression(node: Object) { } } -export function MetaProperty(node: Object) { +export function MetaProperty(this: Printer, node: t.MetaProperty) { this.print(node.meta, node); this.token("."); this.print(node.property, node); } -export function PrivateName(node: Object) { +export function PrivateName(this: Printer, node: t.PrivateName) { this.token("#"); this.print(node.id, node); } -export function V8IntrinsicIdentifier(node: Object) { +export function V8IntrinsicIdentifier( + this: Printer, + node: t.V8IntrinsicIdentifier, +) { this.token("%"); this.word(node.name); } diff --git a/packages/babel-generator/src/generators/flow.js b/packages/babel-generator/src/generators/flow.ts similarity index 65% rename from packages/babel-generator/src/generators/flow.js rename to packages/babel-generator/src/generators/flow.ts index b599c48eb7..587d3fcb85 100644 --- a/packages/babel-generator/src/generators/flow.js +++ b/packages/babel-generator/src/generators/flow.ts @@ -1,29 +1,40 @@ +import type Printer from "../printer"; import * as t from "@babel/types"; import { ExportAllDeclaration } from "./modules"; -export function AnyTypeAnnotation() { +export function AnyTypeAnnotation(this: Printer) { this.word("any"); } -export function ArrayTypeAnnotation(node: Object) { +export function ArrayTypeAnnotation( + this: Printer, + node: t.ArrayTypeAnnotation, +) { this.print(node.elementType, node); this.token("["); this.token("]"); } -export function BooleanTypeAnnotation() { +export function BooleanTypeAnnotation(this: Printer) { this.word("boolean"); } -export function BooleanLiteralTypeAnnotation(node: Object) { +export function BooleanLiteralTypeAnnotation( + this: Printer, + node: t.BooleanLiteralTypeAnnotation, +) { this.word(node.value ? "true" : "false"); } -export function NullLiteralTypeAnnotation() { +export function NullLiteralTypeAnnotation(this: Printer) { this.word("null"); } -export function DeclareClass(node: Object, parent: Object) { +export function DeclareClass( + this: Printer, + node: t.DeclareClass, + parent: t.Node, +) { if (!t.isDeclareExportDeclaration(parent)) { this.word("declare"); this.space(); @@ -33,7 +44,11 @@ export function DeclareClass(node: Object, parent: Object) { this._interfaceish(node); } -export function DeclareFunction(node: Object, parent: Object) { +export function DeclareFunction( + this: Printer, + node: t.DeclareFunction, + parent: any, +) { if (!t.isDeclareExportDeclaration(parent)) { this.word("declare"); this.space(); @@ -41,6 +56,7 @@ export function DeclareFunction(node: Object, parent: Object) { this.word("function"); this.space(); this.print(node.id, node); + // @ts-expect-error todo(flow->ts) typeAnnotation does not exist on Noop this.print(node.id.typeAnnotation.typeAnnotation, node); if (node.predicate) { @@ -56,7 +72,7 @@ export function InferredPredicate(/*node: Object*/) { this.word("checks"); } -export function DeclaredPredicate(node: Object) { +export function DeclaredPredicate(this: Printer, node: t.DeclaredPredicate) { this.token("%"); this.word("checks"); this.token("("); @@ -64,13 +80,13 @@ export function DeclaredPredicate(node: Object) { this.token(")"); } -export function DeclareInterface(node: Object) { +export function DeclareInterface(this: Printer, node: t.DeclareInterface) { this.word("declare"); this.space(); this.InterfaceDeclaration(node); } -export function DeclareModule(node: Object) { +export function DeclareModule(this: Printer, node: t.DeclareModule) { this.word("declare"); this.space(); this.word("module"); @@ -80,7 +96,10 @@ export function DeclareModule(node: Object) { this.print(node.body, node); } -export function DeclareModuleExports(node: Object) { +export function DeclareModuleExports( + this: Printer, + node: t.DeclareModuleExports, +) { this.word("declare"); this.space(); this.word("module"); @@ -89,13 +108,17 @@ export function DeclareModuleExports(node: Object) { this.print(node.typeAnnotation, node); } -export function DeclareTypeAlias(node: Object) { +export function DeclareTypeAlias(this: Printer, node: t.DeclareTypeAlias) { this.word("declare"); this.space(); this.TypeAlias(node); } -export function DeclareOpaqueType(node: Object, parent: Object) { +export function DeclareOpaqueType( + this: Printer, + node: t.DeclareOpaqueType, + parent: any, +) { if (!t.isDeclareExportDeclaration(parent)) { this.word("declare"); this.space(); @@ -103,7 +126,11 @@ export function DeclareOpaqueType(node: Object, parent: Object) { this.OpaqueType(node); } -export function DeclareVariable(node: Object, parent: Object) { +export function DeclareVariable( + this: Printer, + node: t.DeclareVariable, + parent: any, +) { if (!t.isDeclareExportDeclaration(parent)) { this.word("declare"); this.space(); @@ -115,7 +142,10 @@ export function DeclareVariable(node: Object, parent: Object) { this.semicolon(); } -export function DeclareExportDeclaration(node: Object) { +export function DeclareExportDeclaration( + this: Printer, + node: t.DeclareExportDeclaration, +) { this.word("declare"); this.space(); this.word("export"); @@ -134,7 +164,7 @@ export function DeclareExportAllDeclaration(/*node: Object*/) { ExportAllDeclaration.apply(this, arguments); } -export function EnumDeclaration(node: Object) { +export function EnumDeclaration(this: Printer, node: t.EnumDeclaration) { const { id, body } = node; this.word("enum"); this.space(); @@ -143,7 +173,7 @@ export function EnumDeclaration(node: Object) { } function enumExplicitType( - context: Object, + context: any, name: string, hasExplicitType: boolean, ) { @@ -156,7 +186,7 @@ function enumExplicitType( context.space(); } -function enumBody(context: Object, node: Object) { +function enumBody(context: any, node: any) { const { members } = node; context.token("{"); context.indent(); @@ -169,36 +199,39 @@ function enumBody(context: Object, node: Object) { context.token("}"); } -export function EnumBooleanBody(node: Object) { +export function EnumBooleanBody(this: Printer, node: t.EnumBooleanBody) { const { explicitType } = node; enumExplicitType(this, "boolean", explicitType); enumBody(this, node); } -export function EnumNumberBody(node: Object) { +export function EnumNumberBody(this: Printer, node: t.EnumNumberBody) { const { explicitType } = node; enumExplicitType(this, "number", explicitType); enumBody(this, node); } -export function EnumStringBody(node: Object) { +export function EnumStringBody(this: Printer, node: t.EnumStringBody) { const { explicitType } = node; enumExplicitType(this, "string", explicitType); enumBody(this, node); } -export function EnumSymbolBody(node: Object) { +export function EnumSymbolBody(this: Printer, node: t.EnumSymbolBody) { enumExplicitType(this, "symbol", true); enumBody(this, node); } -export function EnumDefaultedMember(node: Object) { +export function EnumDefaultedMember( + this: Printer, + node: t.EnumDefaultedMember, +) { const { id } = node; this.print(id, node); this.token(","); } -function enumInitializedMember(context: Object, node: Object) { +function enumInitializedMember(context: any, node: any) { const { id, init } = node; context.print(id, node); context.space(); @@ -208,19 +241,19 @@ function enumInitializedMember(context: Object, node: Object) { context.token(","); } -export function EnumBooleanMember(node: Object) { +export function EnumBooleanMember(this: Printer, node: t.EnumBooleanMember) { enumInitializedMember(this, node); } -export function EnumNumberMember(node: Object) { +export function EnumNumberMember(this: Printer, node: t.EnumNumberMember) { enumInitializedMember(this, node); } -export function EnumStringMember(node: Object) { +export function EnumStringMember(this: Printer, node: t.EnumStringMember) { enumInitializedMember(this, node); } -function FlowExportDeclaration(node: Object) { +function FlowExportDeclaration(node: any) { if (node.declaration) { const declar = node.declaration; this.print(declar, node); @@ -245,11 +278,15 @@ function FlowExportDeclaration(node: Object) { } } -export function ExistsTypeAnnotation() { +export function ExistsTypeAnnotation(this: Printer) { this.token("*"); } -export function FunctionTypeAnnotation(node: Object, parent: Object) { +export function FunctionTypeAnnotation( + this: Printer, + node: t.FunctionTypeAnnotation, + parent: any, +) { this.print(node.typeParameters, node); this.token("("); this.printList(node.params, node); @@ -281,7 +318,7 @@ export function FunctionTypeAnnotation(node: Object, parent: Object) { this.print(node.returnType, node); } -export function FunctionTypeParam(node: Object) { +export function FunctionTypeParam(this: Printer, node: t.FunctionTypeParam) { this.print(node.name, node); if (node.optional) this.token("?"); if (node.name) { @@ -291,7 +328,7 @@ export function FunctionTypeParam(node: Object) { this.print(node.typeAnnotation, node); } -export function InterfaceExtends(node: Object) { +export function InterfaceExtends(this: Printer, node: t.InterfaceExtends) { this.print(node.id, node); this.print(node.typeParameters, node); } @@ -301,7 +338,10 @@ export { InterfaceExtends as GenericTypeAnnotation, }; -export function _interfaceish(node: Object) { +export function _interfaceish( + this: Printer, + node: t.InterfaceDeclaration | t.DeclareInterface | t.DeclareClass, +) { this.print(node.id, node); this.print(node.typeParameters, node); if (node.extends.length) { @@ -326,7 +366,7 @@ export function _interfaceish(node: Object) { this.print(node.body, node); } -export function _variance(node) { +export function _variance(this: Printer, node) { if (node.variance) { if (node.variance.kind === "plus") { this.token("+"); @@ -336,7 +376,10 @@ export function _variance(node) { } } -export function InterfaceDeclaration(node: Object) { +export function InterfaceDeclaration( + this: Printer, + node: t.InterfaceDeclaration | t.DeclareInterface, +) { this.word("interface"); this.space(); this._interfaceish(node); @@ -348,7 +391,10 @@ function andSeparator() { this.space(); } -export function InterfaceTypeAnnotation(node: Object) { +export function InterfaceTypeAnnotation( + this: Printer, + node: t.InterfaceTypeAnnotation, +) { this.word("interface"); if (node.extends && node.extends.length) { this.space(); @@ -360,19 +406,25 @@ export function InterfaceTypeAnnotation(node: Object) { this.print(node.body, node); } -export function IntersectionTypeAnnotation(node: Object) { +export function IntersectionTypeAnnotation( + this: Printer, + node: t.IntersectionTypeAnnotation, +) { this.printJoin(node.types, node, { separator: andSeparator }); } -export function MixedTypeAnnotation() { +export function MixedTypeAnnotation(this: Printer) { this.word("mixed"); } -export function EmptyTypeAnnotation() { +export function EmptyTypeAnnotation(this: Printer) { this.word("empty"); } -export function NullableTypeAnnotation(node: Object) { +export function NullableTypeAnnotation( + this: Printer, + node: t.NullableTypeAnnotation, +) { this.token("?"); this.print(node.typeAnnotation, node); } @@ -382,31 +434,40 @@ export { StringLiteral as StringLiteralTypeAnnotation, } from "./types"; -export function NumberTypeAnnotation() { +export function NumberTypeAnnotation(this: Printer) { this.word("number"); } -export function StringTypeAnnotation() { +export function StringTypeAnnotation(this: Printer) { this.word("string"); } -export function ThisTypeAnnotation() { +export function ThisTypeAnnotation(this: Printer) { this.word("this"); } -export function TupleTypeAnnotation(node: Object) { +export function TupleTypeAnnotation( + this: Printer, + node: t.TupleTypeAnnotation, +) { this.token("["); this.printList(node.types, node); this.token("]"); } -export function TypeofTypeAnnotation(node: Object) { +export function TypeofTypeAnnotation( + this: Printer, + node: t.TypeofTypeAnnotation, +) { this.word("typeof"); this.space(); this.print(node.argument, node); } -export function TypeAlias(node: Object) { +export function TypeAlias( + this: Printer, + node: t.TypeAlias | t.DeclareTypeAlias, +) { this.word("type"); this.space(); this.print(node.id, node); @@ -418,14 +479,18 @@ export function TypeAlias(node: Object) { this.semicolon(); } -export function TypeAnnotation(node) { +export function TypeAnnotation(this: Printer, node: t.TypeAnnotation) { this.token(":"); this.space(); + // @ts-expect-error todo(flow->ts) can this be removed? `.optional` looks to be not existing property if (node.optional) this.token("?"); this.print(node.typeAnnotation, node); } -export function TypeParameterInstantiation(node): void { +export function TypeParameterInstantiation( + this: Printer, + node: t.TypeParameterInstantiation, +): void { this.token("<"); this.printList(node.params, node, {}); this.token(">"); @@ -433,7 +498,7 @@ export function TypeParameterInstantiation(node): void { export { TypeParameterInstantiation as TypeParameterDeclaration }; -export function TypeParameter(node) { +export function TypeParameter(this: Printer, node: t.TypeParameter) { this._variance(node); this.word(node.name); @@ -450,7 +515,10 @@ export function TypeParameter(node) { } } -export function OpaqueType(node: Object) { +export function OpaqueType( + this: Printer, + node: t.OpaqueType | t.DeclareOpaqueType, +) { this.word("opaque"); this.space(); this.word("type"); @@ -462,16 +530,22 @@ export function OpaqueType(node: Object) { this.space(); this.print(node.supertype, node); } + + // @ts-expect-error todo(flow->ts) `.impltype` does not exist on t.DeclareOpaqueType if (node.impltype) { this.space(); this.token("="); this.space(); + // @ts-expect-error todo(flow->ts) `.impltype` does not exist on t.DeclareOpaqueType this.print(node.impltype, node); } this.semicolon(); } -export function ObjectTypeAnnotation(node: Object) { +export function ObjectTypeAnnotation( + this: Printer, + node: t.ObjectTypeAnnotation, +) { if (node.exact) { this.token("{|"); } else { @@ -479,11 +553,12 @@ export function ObjectTypeAnnotation(node: Object) { } // TODO: remove the array fallbacks and instead enforce the types to require an array - const props = node.properties.concat( - node.callProperties || [], - node.indexers || [], - node.internalSlots || [], - ); + const props = [ + ...node.properties, + ...(node.callProperties || []), + ...(node.indexers || []), + ...(node.internalSlots || []), + ]; if (props.length) { this.space(); @@ -521,7 +596,10 @@ export function ObjectTypeAnnotation(node: Object) { } } -export function ObjectTypeInternalSlot(node: Object) { +export function ObjectTypeInternalSlot( + this: Printer, + node: t.ObjectTypeInternalSlot, +) { if (node.static) { this.word("static"); this.space(); @@ -539,7 +617,10 @@ export function ObjectTypeInternalSlot(node: Object) { this.print(node.value, node); } -export function ObjectTypeCallProperty(node: Object) { +export function ObjectTypeCallProperty( + this: Printer, + node: t.ObjectTypeCallProperty, +) { if (node.static) { this.word("static"); this.space(); @@ -547,7 +628,7 @@ export function ObjectTypeCallProperty(node: Object) { this.print(node.value, node); } -export function ObjectTypeIndexer(node: Object) { +export function ObjectTypeIndexer(this: Printer, node: t.ObjectTypeIndexer) { if (node.static) { this.word("static"); this.space(); @@ -566,7 +647,7 @@ export function ObjectTypeIndexer(node: Object) { this.print(node.value, node); } -export function ObjectTypeProperty(node: Object) { +export function ObjectTypeProperty(this: Printer, node: t.ObjectTypeProperty) { if (node.proto) { this.word("proto"); this.space(); @@ -589,18 +670,24 @@ export function ObjectTypeProperty(node: Object) { this.print(node.value, node); } -export function ObjectTypeSpreadProperty(node: Object) { +export function ObjectTypeSpreadProperty( + this: Printer, + node: t.ObjectTypeSpreadProperty, +) { this.token("..."); this.print(node.argument, node); } -export function QualifiedTypeIdentifier(node: Object) { +export function QualifiedTypeIdentifier( + this: Printer, + node: t.QualifiedTypeIdentifier, +) { this.print(node.qualification, node); this.token("."); this.print(node.id, node); } -export function SymbolTypeAnnotation() { +export function SymbolTypeAnnotation(this: Printer) { this.word("symbol"); } @@ -610,18 +697,21 @@ function orSeparator() { this.space(); } -export function UnionTypeAnnotation(node: Object) { +export function UnionTypeAnnotation( + this: Printer, + node: t.UnionTypeAnnotation, +) { this.printJoin(node.types, node, { separator: orSeparator }); } -export function TypeCastExpression(node: Object) { +export function TypeCastExpression(this: Printer, node: t.TypeCastExpression) { this.token("("); this.print(node.expression, node); this.print(node.typeAnnotation, node); this.token(")"); } -export function Variance(node: Object) { +export function Variance(this: Printer, node: t.Variance) { if (node.kind === "plus") { this.token("+"); } else { @@ -629,6 +719,6 @@ export function Variance(node: Object) { } } -export function VoidTypeAnnotation() { +export function VoidTypeAnnotation(this: Printer) { this.word("void"); } diff --git a/packages/babel-generator/src/generators/index.js b/packages/babel-generator/src/generators/index.ts similarity index 100% rename from packages/babel-generator/src/generators/index.js rename to packages/babel-generator/src/generators/index.ts diff --git a/packages/babel-generator/src/generators/jsx.js b/packages/babel-generator/src/generators/jsx.ts similarity index 56% rename from packages/babel-generator/src/generators/jsx.js rename to packages/babel-generator/src/generators/jsx.ts index 89312add92..d59eeed87f 100644 --- a/packages/babel-generator/src/generators/jsx.js +++ b/packages/babel-generator/src/generators/jsx.ts @@ -1,4 +1,7 @@ -export function JSXAttribute(node: Object) { +import type Printer from "../printer"; +import * as t from "@babel/types"; + +export function JSXAttribute(this: Printer, node: t.JSXAttribute) { this.print(node.name, node); if (node.value) { this.token("="); @@ -6,43 +9,49 @@ export function JSXAttribute(node: Object) { } } -export function JSXIdentifier(node: Object) { +export function JSXIdentifier(this: Printer, node: t.JSXIdentifier) { this.word(node.name); } -export function JSXNamespacedName(node: Object) { +export function JSXNamespacedName(this: Printer, node: t.JSXNamespacedName) { this.print(node.namespace, node); this.token(":"); this.print(node.name, node); } -export function JSXMemberExpression(node: Object) { +export function JSXMemberExpression( + this: Printer, + node: t.JSXMemberExpression, +) { this.print(node.object, node); this.token("."); this.print(node.property, node); } -export function JSXSpreadAttribute(node: Object) { +export function JSXSpreadAttribute(this: Printer, node: t.JSXSpreadAttribute) { this.token("{"); this.token("..."); this.print(node.argument, node); this.token("}"); } -export function JSXExpressionContainer(node: Object) { +export function JSXExpressionContainer( + this: Printer, + node: t.JSXExpressionContainer, +) { this.token("{"); this.print(node.expression, node); this.token("}"); } -export function JSXSpreadChild(node: Object) { +export function JSXSpreadChild(this: Printer, node: t.JSXSpreadChild) { this.token("{"); this.token("..."); this.print(node.expression, node); this.token("}"); } -export function JSXText(node: Object) { +export function JSXText(this: Printer, node: t.JSXText) { const raw = this.getPossibleRaw(node); if (raw != null) { @@ -52,13 +61,13 @@ export function JSXText(node: Object) { } } -export function JSXElement(node: Object) { +export function JSXElement(this: Printer, node: t.JSXElement) { const open = node.openingElement; this.print(open, node); if (open.selfClosing) return; this.indent(); - for (const child of (node.children: Array)) { + for (const child of node.children as Array) { this.print(child, node); } this.dedent(); @@ -70,7 +79,7 @@ function spaceSeparator() { this.space(); } -export function JSXOpeningElement(node: Object) { +export function JSXOpeningElement(this: Printer, node: t.JSXOpeningElement) { this.token("<"); this.print(node.name, node); this.print(node.typeParameters, node); // TS @@ -86,21 +95,21 @@ export function JSXOpeningElement(node: Object) { } } -export function JSXClosingElement(node: Object) { +export function JSXClosingElement(this: Printer, node: t.JSXClosingElement) { this.token(""); } -export function JSXEmptyExpression(node: Object) { +export function JSXEmptyExpression(this: Printer, node: t.JSXEmptyExpression) { this.printInnerComments(node); } -export function JSXFragment(node: Object) { +export function JSXFragment(this: Printer, node: t.JSXFragment) { this.print(node.openingFragment, node); this.indent(); - for (const child of (node.children: Array)) { + for (const child of node.children as Array) { this.print(child, node); } this.dedent(); @@ -108,12 +117,12 @@ export function JSXFragment(node: Object) { this.print(node.closingFragment, node); } -export function JSXOpeningFragment() { +export function JSXOpeningFragment(this: Printer) { this.token("<"); this.token(">"); } -export function JSXClosingFragment() { +export function JSXClosingFragment(this: Printer) { this.token(""); } diff --git a/packages/babel-generator/src/generators/methods.js b/packages/babel-generator/src/generators/methods.ts similarity index 83% rename from packages/babel-generator/src/generators/methods.js rename to packages/babel-generator/src/generators/methods.ts index ea656b8b0c..607aba9049 100644 --- a/packages/babel-generator/src/generators/methods.js +++ b/packages/babel-generator/src/generators/methods.ts @@ -1,6 +1,7 @@ +import type Printer from "../printer"; import * as t from "@babel/types"; -export function _params(node: Object) { +export function _params(this: Printer, node: any) { this.print(node.typeParameters, node); this.token("("); this._parameters(node.params, node); @@ -9,7 +10,7 @@ export function _params(node: Object) { this.print(node.returnType, node); } -export function _parameters(parameters, parent) { +export function _parameters(this: Printer, parameters, parent) { for (let i = 0; i < parameters.length; i++) { this._param(parameters[i], parent); @@ -20,14 +21,14 @@ export function _parameters(parameters, parent) { } } -export function _param(parameter, parent) { +export function _param(this: Printer, parameter, parent?) { this.printJoin(parameter.decorators, parameter); this.print(parameter, parent); if (parameter.optional) this.token("?"); // TS / flow this.print(parameter.typeAnnotation, parameter); // TS / flow } -export function _methodHead(node: Object) { +export function _methodHead(this: Printer, node: any) { const kind = node.kind; const key = node.key; @@ -65,7 +66,7 @@ export function _methodHead(node: Object) { this._params(node); } -export function _predicate(node: Object) { +export function _predicate(this: Printer, node: any) { if (node.predicate) { if (!node.returnType) { this.token(":"); @@ -75,7 +76,7 @@ export function _predicate(node: Object) { } } -export function _functionHead(node: Object) { +export function _functionHead(this: Printer, node: any) { if (node.async) { this.word("async"); this.space(); @@ -92,7 +93,7 @@ export function _functionHead(node: Object) { this._predicate(node); } -export function FunctionExpression(node: Object) { +export function FunctionExpression(this: Printer, node: t.FunctionExpression) { this._functionHead(node); this.space(); this.print(node.body, node); @@ -100,7 +101,10 @@ export function FunctionExpression(node: Object) { export { FunctionExpression as FunctionDeclaration }; -export function ArrowFunctionExpression(node: Object) { +export function ArrowFunctionExpression( + this: Printer, + node: t.ArrowFunctionExpression, +) { if (node.async) { this.word("async"); this.space(); diff --git a/packages/babel-generator/src/generators/modules.js b/packages/babel-generator/src/generators/modules.ts similarity index 75% rename from packages/babel-generator/src/generators/modules.js rename to packages/babel-generator/src/generators/modules.ts index 0906f6829f..40dd668043 100644 --- a/packages/babel-generator/src/generators/modules.js +++ b/packages/babel-generator/src/generators/modules.ts @@ -1,12 +1,14 @@ +import type Printer from "../printer"; import * as t from "@babel/types"; -export function ImportSpecifier(node: Object) { +export function ImportSpecifier(this: Printer, node: t.ImportSpecifier) { if (node.importKind === "type" || node.importKind === "typeof") { this.word(node.importKind); this.space(); } this.print(node.imported, node); + // @ts-expect-error todo(flow-ts) maybe check node type instead of relying on name to be undefined on t.StringLiteral if (node.local && node.local.name !== node.imported.name) { this.space(); this.word("as"); @@ -15,16 +17,23 @@ export function ImportSpecifier(node: Object) { } } -export function ImportDefaultSpecifier(node: Object) { +export function ImportDefaultSpecifier( + this: Printer, + node: t.ImportDefaultSpecifier, +) { this.print(node.local, node); } -export function ExportDefaultSpecifier(node: Object) { +export function ExportDefaultSpecifier( + this: Printer, + node: t.ExportDefaultSpecifier, +) { this.print(node.exported, node); } -export function ExportSpecifier(node: Object) { +export function ExportSpecifier(this: Printer, node: t.ExportSpecifier) { this.print(node.local, node); + // @ts-expect-error todo(flow-ts) maybe check node type instead of relying on name to be undefined on t.StringLiteral if (node.exported && node.local.name !== node.exported.name) { this.space(); this.word("as"); @@ -33,7 +42,10 @@ export function ExportSpecifier(node: Object) { } } -export function ExportNamespaceSpecifier(node: Object) { +export function ExportNamespaceSpecifier( + this: Printer, + node: t.ExportNamespaceSpecifier, +) { this.token("*"); this.space(); this.word("as"); @@ -41,7 +53,10 @@ export function ExportNamespaceSpecifier(node: Object) { this.print(node.exported, node); } -export function ExportAllDeclaration(node: Object) { +export function ExportAllDeclaration( + this: Printer, + node: t.ExportAllDeclaration, +) { this.word("export"); this.space(); if (node.exportKind === "type") { @@ -57,7 +72,10 @@ export function ExportAllDeclaration(node: Object) { this.semicolon(); } -export function ExportNamedDeclaration(node: Object) { +export function ExportNamedDeclaration( + this: Printer, + node: t.ExportNamedDeclaration, +) { if ( this.format.decoratorsBeforeExport && t.isClassDeclaration(node.declaration) @@ -70,7 +88,10 @@ export function ExportNamedDeclaration(node: Object) { ExportDeclaration.apply(this, arguments); } -export function ExportDefaultDeclaration(node: Object) { +export function ExportDefaultDeclaration( + this: Printer, + node: t.ExportDefaultDeclaration, +) { if ( this.format.decoratorsBeforeExport && t.isClassDeclaration(node.declaration) @@ -85,7 +106,7 @@ export function ExportDefaultDeclaration(node: Object) { ExportDeclaration.apply(this, arguments); } -function ExportDeclaration(node: Object) { +function ExportDeclaration(node: any) { if (node.declaration) { const declar = node.declaration; this.print(declar, node); @@ -139,7 +160,7 @@ function ExportDeclaration(node: Object) { } } -export function ImportDeclaration(node: Object) { +export function ImportDeclaration(this: Printer, node: t.ImportDeclaration) { this.word("import"); this.space(); @@ -185,24 +206,29 @@ export function ImportDeclaration(node: Object) { this.printAssertions(node); // todo(Babel 8): remove this if branch // `module-attributes` support is discontinued, use `import-assertions` instead. + // @ts-expect-error if (node.attributes?.length) { this.space(); this.word("with"); this.space(); + // @ts-expect-error this.printList(node.attributes, node); } this.semicolon(); } -export function ImportAttribute(node: Object) { +export function ImportAttribute(this: Printer, node: t.ImportAttribute) { this.print(node.key); this.token(":"); this.space(); this.print(node.value); } -export function ImportNamespaceSpecifier(node: Object) { +export function ImportNamespaceSpecifier( + this: Printer, + node: t.ImportNamespaceSpecifier, +) { this.token("*"); this.space(); this.word("as"); diff --git a/packages/babel-generator/src/generators/statements.js b/packages/babel-generator/src/generators/statements.ts similarity index 79% rename from packages/babel-generator/src/generators/statements.js rename to packages/babel-generator/src/generators/statements.ts index dbeb45bf32..24ca879d96 100644 --- a/packages/babel-generator/src/generators/statements.js +++ b/packages/babel-generator/src/generators/statements.ts @@ -1,6 +1,7 @@ +import type Printer from "../printer"; import * as t from "@babel/types"; -export function WithStatement(node: Object) { +export function WithStatement(this: Printer, node: t.WithStatement) { this.word("with"); this.space(); this.token("("); @@ -9,7 +10,7 @@ export function WithStatement(node: Object) { this.printBlock(node); } -export function IfStatement(node: Object) { +export function IfStatement(this: Printer, node: t.IfStatement) { this.word("if"); this.space(); this.token("("); @@ -47,7 +48,7 @@ function getLastStatement(statement) { return getLastStatement(statement.body); } -export function ForStatement(node: Object) { +export function ForStatement(this: Printer, node: t.ForStatement) { this.word("for"); this.space(); this.token("("); @@ -72,7 +73,7 @@ export function ForStatement(node: Object) { this.printBlock(node); } -export function WhileStatement(node: Object) { +export function WhileStatement(this: Printer, node: t.WhileStatement) { this.word("while"); this.space(); this.token("("); @@ -82,7 +83,7 @@ export function WhileStatement(node: Object) { } const buildForXStatement = function (op) { - return function (node: Object) { + return function (node: any) { this.word("for"); this.space(); if (op === "of" && node.await) { @@ -103,7 +104,7 @@ const buildForXStatement = function (op) { export const ForInStatement = buildForXStatement("in"); export const ForOfStatement = buildForXStatement("of"); -export function DoWhileStatement(node: Object) { +export function DoWhileStatement(this: Printer, node: t.DoWhileStatement) { this.word("do"); this.space(); this.print(node.body, node); @@ -117,7 +118,7 @@ export function DoWhileStatement(node: Object) { } function buildLabelStatement(prefix, key = "label") { - return function (node: Object) { + return function (node: any) { this.word(prefix); const label = node[key]; @@ -138,14 +139,14 @@ export const ReturnStatement = buildLabelStatement("return", "argument"); export const BreakStatement = buildLabelStatement("break"); export const ThrowStatement = buildLabelStatement("throw", "argument"); -export function LabeledStatement(node: Object) { +export function LabeledStatement(this: Printer, node: t.LabeledStatement) { this.print(node.label, node); this.token(":"); this.space(); this.print(node.body, node); } -export function TryStatement(node: Object) { +export function TryStatement(this: Printer, node: t.TryStatement) { this.word("try"); this.space(); this.print(node.block, node); @@ -154,7 +155,9 @@ export function TryStatement(node: Object) { // Esprima bug puts the catch clause in a `handlers` array. // see https://code.google.com/p/esprima/issues/detail?id=433 // We run into this from regenerator generated ast. + // @ts-expect-error todo(flow->ts) should ast node type be updated to support this? if (node.handlers) { + // @ts-expect-error todo(flow->ts) should ast node type be updated to support this? this.print(node.handlers[0], node); } else { this.print(node.handler, node); @@ -168,7 +171,7 @@ export function TryStatement(node: Object) { } } -export function CatchClause(node: Object) { +export function CatchClause(this: Printer, node: t.CatchClause) { this.word("catch"); this.space(); if (node.param) { @@ -181,7 +184,7 @@ export function CatchClause(node: Object) { this.print(node.body, node); } -export function SwitchStatement(node: Object) { +export function SwitchStatement(this: Printer, node: t.SwitchStatement) { this.word("switch"); this.space(); this.token("("); @@ -200,7 +203,7 @@ export function SwitchStatement(node: Object) { this.token("}"); } -export function SwitchCase(node: Object) { +export function SwitchCase(this: Printer, node: t.SwitchCase) { if (node.test) { this.word("case"); this.space(); @@ -217,7 +220,7 @@ export function SwitchCase(node: Object) { } } -export function DebuggerStatement() { +export function DebuggerStatement(this: Printer) { this.word("debugger"); this.semicolon(); } @@ -236,7 +239,11 @@ function constDeclarationIndent() { if (this.endsWith("\n")) for (let i = 0; i < 6; i++) this.space(true); } -export function VariableDeclaration(node: Object, parent: Object) { +export function VariableDeclaration( + this: Printer, + node: t.VariableDeclaration, + parent: t.Node, +) { if (node.declare) { // TS this.word("declare"); @@ -249,7 +256,7 @@ export function VariableDeclaration(node: Object, parent: Object) { let hasInits = false; // don't add whitespace to loop heads if (!t.isFor(parent)) { - for (const declar of (node.declarations: Array)) { + for (const declar of node.declarations as Array) { if (declar.init) { // has an init so let's split it up over multiple lines hasInits = true; @@ -283,15 +290,20 @@ export function VariableDeclaration(node: Object, parent: Object) { if (t.isFor(parent)) { // don't give semicolons to these nodes since they'll be inserted in the parent generator - if (parent.left === node || parent.init === node) return; + if (t.isForStatement(parent)) { + if (parent.init === node) return; + } else { + if (parent.left === node) return; + } } this.semicolon(); } -export function VariableDeclarator(node: Object) { +export function VariableDeclarator(this: Printer, node: t.VariableDeclarator) { this.print(node.id, node); if (node.definite) this.token("!"); // TS + // @ts-expect-error todo(flow-ts) Property 'typeAnnotation' does not exist on type 'MemberExpression'. this.print(node.id.typeAnnotation, node); if (node.init) { this.space(); diff --git a/packages/babel-generator/src/generators/template-literals.js b/packages/babel-generator/src/generators/template-literals.ts similarity index 60% rename from packages/babel-generator/src/generators/template-literals.js rename to packages/babel-generator/src/generators/template-literals.ts index c9a9f9c820..adecaa2e94 100644 --- a/packages/babel-generator/src/generators/template-literals.js +++ b/packages/babel-generator/src/generators/template-literals.ts @@ -1,10 +1,20 @@ -export function TaggedTemplateExpression(node: Object) { +import type Printer from "../printer"; +import * as t from "@babel/types"; + +export function TaggedTemplateExpression( + this: Printer, + node: t.TaggedTemplateExpression, +) { this.print(node.tag, node); this.print(node.typeParameters, node); // TS this.print(node.quasi, node); } -export function TemplateElement(node: Object, parent: Object) { +export function TemplateElement( + this: Printer, + node: t.TemplateElement, + parent: any, +) { const isFirst = parent.quasis[0] === node; const isLast = parent.quasis[parent.quasis.length - 1] === node; @@ -13,7 +23,7 @@ export function TemplateElement(node: Object, parent: Object) { this.token(value); } -export function TemplateLiteral(node: Object) { +export function TemplateLiteral(this: Printer, node: t.TemplateLiteral) { const quasis = node.quasis; for (let i = 0; i < quasis.length; i++) { diff --git a/packages/babel-generator/src/generators/types.js b/packages/babel-generator/src/generators/types.ts similarity index 76% rename from packages/babel-generator/src/generators/types.js rename to packages/babel-generator/src/generators/types.ts index 3a074b7598..45b38179b5 100644 --- a/packages/babel-generator/src/generators/types.js +++ b/packages/babel-generator/src/generators/types.ts @@ -1,24 +1,25 @@ +import type Printer from "../printer"; import * as t from "@babel/types"; import jsesc from "jsesc"; -export function Identifier(node: Object) { +export function Identifier(this: Printer, node: t.Identifier) { this.exactSource(node.loc, () => { this.word(node.name); }); } -export function ArgumentPlaceholder() { +export function ArgumentPlaceholder(this: Printer) { this.token("?"); } -export function RestElement(node: Object) { +export function RestElement(this: Printer, node: t.RestElement) { this.token("..."); this.print(node.argument, node); } export { RestElement as SpreadElement }; -export function ObjectExpression(node: Object) { +export function ObjectExpression(this: Printer, node: t.ObjectExpression) { const props = node.properties; this.token("{"); @@ -35,14 +36,14 @@ export function ObjectExpression(node: Object) { export { ObjectExpression as ObjectPattern }; -export function ObjectMethod(node: Object) { +export function ObjectMethod(this: Printer, node: t.ObjectMethod) { this.printJoin(node.decorators, node); this._methodHead(node); this.space(); this.print(node.body, node); } -export function ObjectProperty(node: Object) { +export function ObjectProperty(this: Printer, node: t.ObjectProperty) { this.printJoin(node.decorators, node); if (node.computed) { @@ -54,6 +55,7 @@ export function ObjectProperty(node: Object) { if ( t.isAssignmentPattern(node.value) && t.isIdentifier(node.key) && + // @ts-expect-error todo(flow->ts) `.name` does not exist on some types in union node.key.name === node.value.left.name ) { this.print(node.value, node); @@ -78,7 +80,7 @@ export function ObjectProperty(node: Object) { this.print(node.value, node); } -export function ArrayExpression(node: Object) { +export function ArrayExpression(this: Printer, node: t.ArrayExpression) { const elems = node.elements; const len = elems.length; @@ -106,7 +108,7 @@ export function ArrayExpression(node: Object) { export { ArrayExpression as ArrayPattern }; -export function RecordExpression(node: Object) { +export function RecordExpression(this: Printer, node: t.RecordExpression) { const props = node.properties; let startToken; @@ -136,7 +138,7 @@ export function RecordExpression(node: Object) { this.token(endToken); } -export function TupleExpression(node: Object) { +export function TupleExpression(this: Printer, node: t.TupleExpression) { const elems = node.elements; const len = elems.length; @@ -169,19 +171,19 @@ export function TupleExpression(node: Object) { this.token(endToken); } -export function RegExpLiteral(node: Object) { +export function RegExpLiteral(this: Printer, node: t.RegExpLiteral) { this.word(`/${node.pattern}/${node.flags}`); } -export function BooleanLiteral(node: Object) { +export function BooleanLiteral(this: Printer, node: t.BooleanLiteral) { this.word(node.value ? "true" : "false"); } -export function NullLiteral() { +export function NullLiteral(this: Printer) { this.word("null"); } -export function NumericLiteral(node: Object) { +export function NumericLiteral(this: Printer, node: t.NumericLiteral) { const raw = this.getPossibleRaw(node); const opts = this.format.jsescOption; const value = node.value + ""; @@ -196,7 +198,7 @@ export function NumericLiteral(node: Object) { } } -export function StringLiteral(node: Object) { +export function StringLiteral(this: Printer, node: t.StringLiteral) { const raw = this.getPossibleRaw(node); if (!this.format.minified && raw != null) { this.token(raw); @@ -216,7 +218,7 @@ export function StringLiteral(node: Object) { return this.token(val); } -export function BigIntLiteral(node: Object) { +export function BigIntLiteral(this: Printer, node: t.BigIntLiteral) { const raw = this.getPossibleRaw(node); if (!this.format.minified && raw != null) { this.word(raw); @@ -225,7 +227,7 @@ export function BigIntLiteral(node: Object) { this.word(node.value + "n"); } -export function DecimalLiteral(node: Object) { +export function DecimalLiteral(this: Printer, node: t.DecimalLiteral) { const raw = this.getPossibleRaw(node); if (!this.format.minified && raw != null) { this.word(raw); @@ -234,14 +236,20 @@ export function DecimalLiteral(node: Object) { this.word(node.value + "m"); } -export function PipelineTopicExpression(node: Object) { +export function PipelineTopicExpression( + this: Printer, + node: t.PipelineTopicExpression, +) { this.print(node.expression, node); } -export function PipelineBareFunction(node: Object) { +export function PipelineBareFunction( + this: Printer, + node: t.PipelineBareFunction, +) { this.print(node.callee, node); } -export function PipelinePrimaryTopicReference() { +export function PipelinePrimaryTopicReference(this: Printer) { this.token("#"); } diff --git a/packages/babel-generator/src/generators/typescript.js b/packages/babel-generator/src/generators/typescript.ts similarity index 64% rename from packages/babel-generator/src/generators/typescript.js rename to packages/babel-generator/src/generators/typescript.ts index 02e36a1810..9c18ab0a0b 100644 --- a/packages/babel-generator/src/generators/typescript.js +++ b/packages/babel-generator/src/generators/typescript.ts @@ -1,11 +1,18 @@ -export function TSTypeAnnotation(node) { +import type Printer from "../printer"; +import * as t from "@babel/types"; + +export function TSTypeAnnotation(this: Printer, node: t.TSTypeAnnotation) { this.token(":"); this.space(); + // @ts-expect-error todo(flow->ts) can this be removed? `.optional` looks to be not existing property if (node.optional) this.token("?"); this.print(node.typeAnnotation, node); } -export function TSTypeParameterInstantiation(node): void { +export function TSTypeParameterInstantiation( + this: Printer, + node: t.TSTypeParameterInstantiation, +): void { this.token("<"); this.printList(node.params, node, {}); this.token(">"); @@ -13,7 +20,7 @@ export function TSTypeParameterInstantiation(node): void { export { TSTypeParameterInstantiation as TSTypeParameterDeclaration }; -export function TSTypeParameter(node) { +export function TSTypeParameter(this: Printer, node: t.TSTypeParameter) { this.word(node.name); if (node.constraint) { @@ -31,7 +38,10 @@ export function TSTypeParameter(node) { } } -export function TSParameterProperty(node) { +export function TSParameterProperty( + this: Printer, + node: t.TSParameterProperty, +) { if (node.accessibility) { this.word(node.accessibility); this.space(); @@ -45,7 +55,7 @@ export function TSParameterProperty(node) { this._param(node.parameter); } -export function TSDeclareFunction(node) { +export function TSDeclareFunction(this: Printer, node: t.TSDeclareFunction) { if (node.declare) { this.word("declare"); this.space(); @@ -54,30 +64,39 @@ export function TSDeclareFunction(node) { this.token(";"); } -export function TSDeclareMethod(node) { +export function TSDeclareMethod(this: Printer, node: t.TSDeclareMethod) { this._classMethodHead(node); this.token(";"); } -export function TSQualifiedName(node) { +export function TSQualifiedName(this: Printer, node: t.TSQualifiedName) { this.print(node.left, node); this.token("."); this.print(node.right, node); } -export function TSCallSignatureDeclaration(node) { +export function TSCallSignatureDeclaration( + this: Printer, + node: t.TSCallSignatureDeclaration, +) { this.tsPrintSignatureDeclarationBase(node); this.token(";"); } -export function TSConstructSignatureDeclaration(node) { +export function TSConstructSignatureDeclaration( + this: Printer, + node: t.TSConstructSignatureDeclaration, +) { this.word("new"); this.space(); this.tsPrintSignatureDeclarationBase(node); this.token(";"); } -export function TSPropertySignature(node) { +export function TSPropertySignature( + this: Printer, + node: t.TSPropertySignature, +) { const { readonly, initializer } = node; if (readonly) { this.word("readonly"); @@ -94,7 +113,7 @@ export function TSPropertySignature(node) { this.token(";"); } -export function tsPrintPropertyOrMethodName(node) { +export function tsPrintPropertyOrMethodName(this: Printer, node) { if (node.computed) { this.token("["); } @@ -107,13 +126,13 @@ export function tsPrintPropertyOrMethodName(node) { } } -export function TSMethodSignature(node) { +export function TSMethodSignature(this: Printer, node: t.TSMethodSignature) { this.tsPrintPropertyOrMethodName(node); this.tsPrintSignatureDeclarationBase(node); this.token(";"); } -export function TSIndexSignature(node) { +export function TSIndexSignature(this: Printer, node: t.TSIndexSignature) { const { readonly } = node; if (readonly) { this.word("readonly"); @@ -126,62 +145,64 @@ export function TSIndexSignature(node) { this.token(";"); } -export function TSAnyKeyword() { +export function TSAnyKeyword(this: Printer) { this.word("any"); } -export function TSBigIntKeyword() { +export function TSBigIntKeyword(this: Printer) { this.word("bigint"); } -export function TSUnknownKeyword() { +export function TSUnknownKeyword(this: Printer) { this.word("unknown"); } -export function TSNumberKeyword() { +export function TSNumberKeyword(this: Printer) { this.word("number"); } -export function TSObjectKeyword() { +export function TSObjectKeyword(this: Printer) { this.word("object"); } -export function TSBooleanKeyword() { +export function TSBooleanKeyword(this: Printer) { this.word("boolean"); } -export function TSStringKeyword() { +export function TSStringKeyword(this: Printer) { this.word("string"); } -export function TSSymbolKeyword() { +export function TSSymbolKeyword(this: Printer) { this.word("symbol"); } -export function TSVoidKeyword() { +export function TSVoidKeyword(this: Printer) { this.word("void"); } -export function TSUndefinedKeyword() { +export function TSUndefinedKeyword(this: Printer) { this.word("undefined"); } -export function TSNullKeyword() { +export function TSNullKeyword(this: Printer) { this.word("null"); } -export function TSNeverKeyword() { +export function TSNeverKeyword(this: Printer) { this.word("never"); } export function TSIntrinsicKeyword() { this.word("intrinsic"); } -export function TSThisType() { +export function TSThisType(this: Printer) { this.word("this"); } -export function TSFunctionType(node) { +export function TSFunctionType(this: Printer, node: t.TSFunctionType) { this.tsPrintFunctionOrConstructorType(node); } -export function TSConstructorType(node) { +export function TSConstructorType(this: Printer, node: t.TSConstructorType) { this.word("new"); this.space(); this.tsPrintFunctionOrConstructorType(node); } export function tsPrintFunctionOrConstructorType( - node: FunctionOrConstructorType, + this: Printer, + // todo: missing type FunctionOrConstructorType + node: any, ) { const { typeParameters, parameters } = node; this.print(typeParameters, node); @@ -194,12 +215,12 @@ export function tsPrintFunctionOrConstructorType( this.print(node.typeAnnotation.typeAnnotation, node); } -export function TSTypeReference(node) { +export function TSTypeReference(this: Printer, node: t.TSTypeReference) { this.print(node.typeName, node); this.print(node.typeParameters, node); } -export function TSTypePredicate(node) { +export function TSTypePredicate(this: Printer, node: t.TSTypePredicate) { if (node.asserts) { this.word("asserts"); this.space(); @@ -213,21 +234,25 @@ export function TSTypePredicate(node) { } } -export function TSTypeQuery(node) { +export function TSTypeQuery(this: Printer, node: t.TSTypeQuery) { this.word("typeof"); this.space(); this.print(node.exprName); } -export function TSTypeLiteral(node) { +export function TSTypeLiteral(this: Printer, node: t.TSTypeLiteral) { this.tsPrintTypeLiteralOrInterfaceBody(node.members, node); } -export function tsPrintTypeLiteralOrInterfaceBody(members, node) { +export function tsPrintTypeLiteralOrInterfaceBody( + this: Printer, + members, + node, +) { this.tsPrintBraced(members, node); } -export function tsPrintBraced(members, node) { +export function tsPrintBraced(this: Printer, members, node) { this.token("{"); if (members.length) { this.indent(); @@ -244,28 +269,28 @@ export function tsPrintBraced(members, node) { } } -export function TSArrayType(node) { +export function TSArrayType(this: Printer, node: t.TSArrayType) { this.print(node.elementType, node); this.token("[]"); } -export function TSTupleType(node) { +export function TSTupleType(this: Printer, node: t.TSTupleType) { this.token("["); this.printList(node.elementTypes, node); this.token("]"); } -export function TSOptionalType(node) { +export function TSOptionalType(this: Printer, node: t.TSOptionalType) { this.print(node.typeAnnotation, node); this.token("?"); } -export function TSRestType(node) { +export function TSRestType(this: Printer, node: t.TSRestType) { this.token("..."); this.print(node.typeAnnotation, node); } -export function TSNamedTupleMember(node) { +export function TSNamedTupleMember(this: Printer, node: t.TSNamedTupleMember) { this.print(node.label, node); if (node.optional) this.token("?"); this.token(":"); @@ -273,15 +298,15 @@ export function TSNamedTupleMember(node) { this.print(node.elementType, node); } -export function TSUnionType(node) { +export function TSUnionType(this: Printer, node: t.TSUnionType) { this.tsPrintUnionOrIntersectionType(node, "|"); } -export function TSIntersectionType(node) { +export function TSIntersectionType(this: Printer, node: t.TSIntersectionType) { this.tsPrintUnionOrIntersectionType(node, "&"); } -export function tsPrintUnionOrIntersectionType(node, sep) { +export function tsPrintUnionOrIntersectionType(this: Printer, node: any, sep) { this.printJoin(node.types, node, { separator() { this.space(); @@ -291,7 +316,7 @@ export function tsPrintUnionOrIntersectionType(node, sep) { }); } -export function TSConditionalType(node) { +export function TSConditionalType(this: Printer, node: t.TSConditionalType) { this.print(node.checkType); this.space(); this.word("extends"); @@ -307,32 +332,38 @@ export function TSConditionalType(node) { this.print(node.falseType); } -export function TSInferType(node) { +export function TSInferType(this: Printer, node: t.TSInferType) { this.token("infer"); this.space(); this.print(node.typeParameter); } -export function TSParenthesizedType(node) { +export function TSParenthesizedType( + this: Printer, + node: t.TSParenthesizedType, +) { this.token("("); this.print(node.typeAnnotation, node); this.token(")"); } -export function TSTypeOperator(node) { +export function TSTypeOperator(this: Printer, node: t.TSTypeOperator) { this.word(node.operator); this.space(); this.print(node.typeAnnotation, node); } -export function TSIndexedAccessType(node) { +export function TSIndexedAccessType( + this: Printer, + node: t.TSIndexedAccessType, +) { this.print(node.objectType, node); this.token("["); this.print(node.indexType, node); this.token("]"); } -export function TSMappedType(node) { +export function TSMappedType(this: Printer, node: t.TSMappedType) { const { nameType, optional, readonly, typeParameter } = node; this.token("{"); this.space(); @@ -375,16 +406,22 @@ function tokenIfPlusMinus(self, tok) { } } -export function TSLiteralType(node) { +export function TSLiteralType(this: Printer, node: t.TSLiteralType) { this.print(node.literal, node); } -export function TSExpressionWithTypeArguments(node) { +export function TSExpressionWithTypeArguments( + this: Printer, + node: t.TSExpressionWithTypeArguments, +) { this.print(node.expression, node); this.print(node.typeParameters, node); } -export function TSInterfaceDeclaration(node) { +export function TSInterfaceDeclaration( + this: Printer, + node: t.TSInterfaceDeclaration, +) { const { declare, id, typeParameters, extends: extendz, body } = node; if (declare) { this.word("declare"); @@ -404,11 +441,14 @@ export function TSInterfaceDeclaration(node) { this.print(body, node); } -export function TSInterfaceBody(node) { +export function TSInterfaceBody(this: Printer, node: t.TSInterfaceBody) { this.tsPrintTypeLiteralOrInterfaceBody(node.body, node); } -export function TSTypeAliasDeclaration(node) { +export function TSTypeAliasDeclaration( + this: Printer, + node: t.TSTypeAliasDeclaration, +) { const { declare, id, typeParameters, typeAnnotation } = node; if (declare) { this.word("declare"); @@ -425,7 +465,7 @@ export function TSTypeAliasDeclaration(node) { this.token(";"); } -export function TSAsExpression(node) { +export function TSAsExpression(this: Printer, node: t.TSAsExpression) { const { expression, typeAnnotation } = node; this.print(expression, node); this.space(); @@ -434,7 +474,7 @@ export function TSAsExpression(node) { this.print(typeAnnotation, node); } -export function TSTypeAssertion(node) { +export function TSTypeAssertion(this: Printer, node: t.TSTypeAssertion) { const { typeAnnotation, expression } = node; this.token("<"); this.print(typeAnnotation, node); @@ -443,7 +483,7 @@ export function TSTypeAssertion(node) { this.print(expression, node); } -export function TSEnumDeclaration(node) { +export function TSEnumDeclaration(this: Printer, node: t.TSEnumDeclaration) { const { declare, const: isConst, id, members } = node; if (declare) { this.word("declare"); @@ -460,7 +500,7 @@ export function TSEnumDeclaration(node) { this.tsPrintBraced(members, node); } -export function TSEnumMember(node) { +export function TSEnumMember(this: Printer, node: t.TSEnumMember) { const { id, initializer } = node; this.print(id, node); if (initializer) { @@ -472,7 +512,10 @@ export function TSEnumMember(node) { this.token(","); } -export function TSModuleDeclaration(node) { +export function TSModuleDeclaration( + this: Printer, + node: t.TSModuleDeclaration, +) { const { declare, id } = node; if (declare) { @@ -502,11 +545,11 @@ export function TSModuleDeclaration(node) { this.print(body, node); } -export function TSModuleBlock(node) { +export function TSModuleBlock(this: Printer, node: t.TSModuleBlock) { this.tsPrintBraced(node.body, node); } -export function TSImportType(node) { +export function TSImportType(this: Printer, node: t.TSImportType) { const { argument, qualifier, typeParameters } = node; this.word("import"); this.token("("); @@ -521,7 +564,10 @@ export function TSImportType(node) { } } -export function TSImportEqualsDeclaration(node) { +export function TSImportEqualsDeclaration( + this: Printer, + node: t.TSImportEqualsDeclaration, +) { const { isExport, id, moduleReference } = node; if (isExport) { this.word("export"); @@ -537,18 +583,24 @@ export function TSImportEqualsDeclaration(node) { this.token(";"); } -export function TSExternalModuleReference(node) { +export function TSExternalModuleReference( + this: Printer, + node: t.TSExternalModuleReference, +) { this.token("require("); this.print(node.expression, node); this.token(")"); } -export function TSNonNullExpression(node) { +export function TSNonNullExpression( + this: Printer, + node: t.TSNonNullExpression, +) { this.print(node.expression, node); this.token("!"); } -export function TSExportAssignment(node) { +export function TSExportAssignment(this: Printer, node: t.TSExportAssignment) { this.word("export"); this.space(); this.token("="); @@ -557,7 +609,10 @@ export function TSExportAssignment(node) { this.token(";"); } -export function TSNamespaceExportDeclaration(node) { +export function TSNamespaceExportDeclaration( + this: Printer, + node: t.TSNamespaceExportDeclaration, +) { this.word("export"); this.space(); this.word("as"); @@ -567,7 +622,7 @@ export function TSNamespaceExportDeclaration(node) { this.print(node.id, node); } -export function tsPrintSignatureDeclarationBase(node) { +export function tsPrintSignatureDeclarationBase(this: Printer, node: any) { const { typeParameters, parameters } = node; this.print(typeParameters, node); this.token("("); @@ -576,7 +631,7 @@ export function tsPrintSignatureDeclarationBase(node) { this.print(node.typeAnnotation, node); } -export function tsPrintClassMemberModifiers(node, isField) { +export function tsPrintClassMemberModifiers(this: Printer, node: any, isField) { if (isField && node.declare) { this.word("declare"); this.space(); diff --git a/packages/babel-generator/src/index.js b/packages/babel-generator/src/index.js deleted file mode 100644 index 588208acca..0000000000 --- a/packages/babel-generator/src/index.js +++ /dev/null @@ -1,119 +0,0 @@ -import SourceMap from "./source-map"; -import Printer, { type Format } from "./printer"; - -/** - * Babel's code generator, turns an ast into code, maintaining sourcemaps, - * user preferences, and valid output. - */ - -class Generator extends Printer { - constructor(ast, opts = {}, code) { - const format = normalizeOptions(code, opts); - const map = opts.sourceMaps ? new SourceMap(opts, code) : null; - super(format, map); - - this.ast = ast; - } - - ast: Object; - - /** - * Generate code and sourcemap from ast. - * - * Appends comments that weren't attached to any node to the end of the generated output. - */ - - generate() { - return super.generate(this.ast); - } -} - -/** - * Normalize generator options, setting defaults. - * - * - Detects code indentation. - * - If `opts.compact = "auto"` and the code is over 500KB, `compact` will be set to `true`. - */ - -function normalizeOptions(code, opts): Format { - const format = { - auxiliaryCommentBefore: opts.auxiliaryCommentBefore, - auxiliaryCommentAfter: opts.auxiliaryCommentAfter, - shouldPrintComment: opts.shouldPrintComment, - retainLines: opts.retainLines, - retainFunctionParens: opts.retainFunctionParens, - comments: opts.comments == null || opts.comments, - compact: opts.compact, - minified: opts.minified, - concise: opts.concise, - indent: { - adjustMultilineComment: true, - style: " ", - base: 0, - }, - decoratorsBeforeExport: !!opts.decoratorsBeforeExport, - jsescOption: { - quotes: "double", - wrap: true, - minimal: true, - ...opts.jsescOption, - }, - recordAndTupleSyntaxType: opts.recordAndTupleSyntaxType, - }; - - if (!process.env.BABEL_8_BREAKING) { - format.jsonCompatibleStrings = opts.jsonCompatibleStrings; - delete format.jsescOption.minimal; - } - - if (format.minified) { - format.compact = true; - - format.shouldPrintComment = - format.shouldPrintComment || (() => format.comments); - } else { - format.shouldPrintComment = - format.shouldPrintComment || - (value => - format.comments || - value.indexOf("@license") >= 0 || - value.indexOf("@preserve") >= 0); - } - - if (format.compact === "auto") { - format.compact = code.length > 500_000; // 500KB - - if (format.compact) { - console.error( - "[BABEL] Note: The code generator has deoptimised the styling of " + - `${opts.filename} as it exceeds the max of ${"500KB"}.`, - ); - } - } - - if (format.compact) { - format.indent.adjustMultilineComment = false; - } - - return format; -} - -/** - * We originally exported the Generator class above, but to make it extra clear that it is a private API, - * we have moved that to an internal class instance and simplified the interface to the two public methods - * that we wish to support. - */ - -export class CodeGenerator { - constructor(ast, opts, code) { - this._generator = new Generator(ast, opts, code); - } - generate() { - return this._generator.generate(); - } -} - -export default function (ast: Object, opts: Object, code: string): Object { - const gen = new Generator(ast, opts, code); - return gen.generate(); -} diff --git a/packages/babel-generator/src/index.ts b/packages/babel-generator/src/index.ts new file mode 100644 index 0000000000..6bc9cc138d --- /dev/null +++ b/packages/babel-generator/src/index.ts @@ -0,0 +1,246 @@ +import SourceMap from "./source-map"; +import Printer from "./printer"; +import type * as t from "@babel/types"; + +import type { Format } from "./printer"; + +/** + * Babel's code generator, turns an ast into code, maintaining sourcemaps, + * user preferences, and valid output. + */ + +class Generator extends Printer { + constructor(ast: t.Node, opts: { sourceMaps?: boolean } = {}, code) { + const format = normalizeOptions(code, opts); + const map = opts.sourceMaps ? new SourceMap(opts, code) : null; + super(format, map); + + this.ast = ast; + } + + ast: t.Node; + + /** + * Generate code and sourcemap from ast. + * + * Appends comments that weren't attached to any node to the end of the generated output. + */ + + generate() { + return super.generate(this.ast); + } +} + +/** + * Normalize generator options, setting defaults. + * + * - Detects code indentation. + * - If `opts.compact = "auto"` and the code is over 500KB, `compact` will be set to `true`. + */ + +function normalizeOptions(code, opts): Format { + const format: Format = { + auxiliaryCommentBefore: opts.auxiliaryCommentBefore, + auxiliaryCommentAfter: opts.auxiliaryCommentAfter, + shouldPrintComment: opts.shouldPrintComment, + retainLines: opts.retainLines, + retainFunctionParens: opts.retainFunctionParens, + comments: opts.comments == null || opts.comments, + compact: opts.compact, + minified: opts.minified, + concise: opts.concise, + indent: { + adjustMultilineComment: true, + style: " ", + base: 0, + }, + decoratorsBeforeExport: !!opts.decoratorsBeforeExport, + jsescOption: { + quotes: "double", + wrap: true, + minimal: true, + ...opts.jsescOption, + }, + recordAndTupleSyntaxType: opts.recordAndTupleSyntaxType, + }; + + if (!process.env.BABEL_8_BREAKING) { + format.jsonCompatibleStrings = opts.jsonCompatibleStrings; + delete format.jsescOption.minimal; + } + + if (format.minified) { + format.compact = true; + + format.shouldPrintComment = + format.shouldPrintComment || (() => format.comments); + } else { + format.shouldPrintComment = + format.shouldPrintComment || + (value => + format.comments || + value.indexOf("@license") >= 0 || + value.indexOf("@preserve") >= 0); + } + + if (format.compact === "auto") { + format.compact = code.length > 500_000; // 500KB + + if (format.compact) { + console.error( + "[BABEL] Note: The code generator has deoptimised the styling of " + + `${opts.filename} as it exceeds the max of ${"500KB"}.`, + ); + } + } + + if (format.compact) { + format.indent.adjustMultilineComment = false; + } + + return format; +} + +export interface GeneratorOptions { + /** + * Optional string to add as a block comment at the start of the output file. + */ + auxiliaryCommentBefore?: string; + + /** + * Optional string to add as a block comment at the end of the output file. + */ + auxiliaryCommentAfter?: string; + + /** + * Function that takes a comment (as a string) and returns true if the comment should be included in the output. + * By default, comments are included if `opts.comments` is `true` or if `opts.minifed` is `false` and the comment + * contains `@preserve` or `@license`. + */ + shouldPrintComment?(comment: string): boolean; + + /** + * Attempt to use the same line numbers in the output code as in the source code (helps preserve stack traces). + * Defaults to `false`. + */ + retainLines?: boolean; + + /** + * Retain parens around function expressions (could be used to change engine parsing behavior) + * Defaults to `false`. + */ + retainFunctionParens?: boolean; + + /** + * Should comments be included in output? Defaults to `true`. + */ + comments?: boolean; + + /** + * Set to true to avoid adding whitespace for formatting. Defaults to the value of `opts.minified`. + */ + compact?: boolean | "auto"; + + /** + * Should the output be minified. Defaults to `false`. + */ + minified?: boolean; + + /** + * Set to true to reduce whitespace (but not as much as opts.compact). Defaults to `false`. + */ + concise?: boolean; + + /** + * Used in warning messages + */ + filename?: string; + + /** + * Enable generating source maps. Defaults to `false`. + */ + sourceMaps?: boolean; + + /** + * A root for all relative URLs in the source map. + */ + sourceRoot?: string; + + /** + * The filename for the source code (i.e. the code in the `code` argument). + * This will only be used if `code` is a string. + */ + sourceFileName?: string; + + /** + * Set to true to run jsesc with "json": true to print "\u00A9" vs. "©"; + */ + jsonCompatibleStrings?: boolean; + + /** + * Set to true to enable support for experimental decorators syntax before module exports. + * Defaults to `false`. + */ + decoratorsBeforeExport?: boolean; + + /** + * Options for outputting jsesc representation. + */ + jsescOption?: { + /** + * The type of quote to use in the output. If omitted, autodetects based on `ast.tokens`. + */ + quotes?: "single" | "double"; + + /** + * When enabled, the output is a valid JavaScript string literal wrapped in quotes. The type of quotes can be specified through the quotes setting. + * Defaults to `true`. + */ + wrap?: boolean; + }; +} + +export interface GeneratorResult { + code: string; + map: { + version: number; + sources: string[]; + names: string[]; + sourceRoot?: string; + sourcesContent?: string[]; + mappings: string; + file: string; + } | null; +} + +/** + * We originally exported the Generator class above, but to make it extra clear that it is a private API, + * we have moved that to an internal class instance and simplified the interface to the two public methods + * that we wish to support. + */ + +export class CodeGenerator { + private _generator: Generator; + constructor(ast: t.Node, opts?: GeneratorOptions, code?: string) { + this._generator = new Generator(ast, opts, code); + } + generate(): GeneratorResult { + return this._generator.generate(); + } +} + +/** + * Turns an AST into code, maintaining sourcemaps, user preferences, and valid output. + * @param ast - the abstract syntax tree from which to generate output code. + * @param opts - used for specifying options for code generation. + * @param code - the original source code, used for source maps. + * @returns - an object containing the output code and source map. + */ +export default function generate( + ast: t.Node, + opts?: GeneratorOptions, + code?: string | { [filename: string]: string }, +): any { + const gen = new Generator(ast, opts, code); + return gen.generate(); +} diff --git a/packages/babel-generator/src/node/index.js b/packages/babel-generator/src/node/index.ts similarity index 95% rename from packages/babel-generator/src/node/index.js rename to packages/babel-generator/src/node/index.ts index c91910f75f..78d40c1d9f 100644 --- a/packages/babel-generator/src/node/index.js +++ b/packages/babel-generator/src/node/index.ts @@ -36,7 +36,7 @@ const expandedParens = expandAliases(parens); const expandedWhitespaceNodes = expandAliases(whitespace.nodes); const expandedWhitespaceList = expandAliases(whitespace.list); -function find(obj, node, parent, printStack) { +function find(obj, node, parent, printStack?) { const fn = obj[node.type]; return fn ? fn(node, parent, printStack) : null; } @@ -83,7 +83,7 @@ export function needsWhitespaceAfter(node, parent) { return needsWhitespace(node, parent, "after"); } -export function needsParens(node, parent, printStack) { +export function needsParens(node, parent, printStack?) { if (!parent) return false; if (t.isNewExpression(parent) && parent.callee === node) { diff --git a/packages/babel-generator/src/node/parentheses.js b/packages/babel-generator/src/node/parentheses.ts similarity index 80% rename from packages/babel-generator/src/node/parentheses.js rename to packages/babel-generator/src/node/parentheses.ts index 56ae5d6018..26789bf13d 100644 --- a/packages/babel-generator/src/node/parentheses.js +++ b/packages/babel-generator/src/node/parentheses.ts @@ -28,11 +28,11 @@ const PRECEDENCE = { "**": 10, }; -const isClassExtendsClause = (node: Object, parent: Object): boolean => +const isClassExtendsClause = (node: any, parent: any): boolean => (t.isClassDeclaration(parent) || t.isClassExpression(parent)) && parent.superClass === node; -const hasPostfixPart = (node: Object, parent: Object) => +const hasPostfixPart = (node: any, parent: any) => ((t.isMemberExpression(parent) || t.isOptionalMemberExpression(parent)) && parent.object === node) || ((t.isCallExpression(parent) || @@ -42,14 +42,14 @@ const hasPostfixPart = (node: Object, parent: Object) => (t.isTaggedTemplateExpression(parent) && parent.tag === node) || t.isTSNonNullExpression(parent); -export function NullableTypeAnnotation(node: Object, parent: Object): boolean { +export function NullableTypeAnnotation(node: any, parent: any): boolean { return t.isArrayTypeAnnotation(parent); } export function FunctionTypeAnnotation( - node: Object, - parent: Object, - printStack: Array, + node: any, + parent: any, + printStack: Array, ): boolean { return ( // (() => A) | (() => B) @@ -65,27 +65,27 @@ export function FunctionTypeAnnotation( ); } -export function UpdateExpression(node: Object, parent: Object): boolean { +export function UpdateExpression(node: any, parent: any): boolean { return hasPostfixPart(node, parent) || isClassExtendsClause(node, parent); } export function ObjectExpression( - node: Object, - parent: Object, - printStack: Array, + node: any, + parent: any, + printStack: Array, ): boolean { return isFirstInStatement(printStack, { considerArrow: true }); } export function DoExpression( - node: Object, - parent: Object, - printStack: Array, + node: any, + parent: any, + printStack: Array, ): boolean { return isFirstInStatement(printStack); } -export function Binary(node: Object, parent: Object): boolean { +export function Binary(node: any, parent: any): boolean { if ( node.operator === "**" && t.isBinaryExpression(parent, { operator: "**" }) @@ -124,7 +124,7 @@ export function Binary(node: Object, parent: Object): boolean { } } -export function UnionTypeAnnotation(node: Object, parent: Object): boolean { +export function UnionTypeAnnotation(node: any, parent: any): boolean { return ( t.isArrayTypeAnnotation(parent) || t.isNullableTypeAnnotation(parent) || @@ -143,7 +143,7 @@ export function TSTypeAssertion() { return true; } -export function TSUnionType(node: Object, parent: Object): boolean { +export function TSUnionType(node: any, parent: any): boolean { return ( t.isTSArrayType(parent) || t.isTSOptionalType(parent) || @@ -155,11 +155,11 @@ export function TSUnionType(node: Object, parent: Object): boolean { export { TSUnionType as TSIntersectionType }; -export function TSInferType(node: Object, parent: Object): boolean { +export function TSInferType(node: any, parent: any): boolean { return t.isTSArrayType(parent) || t.isTSOptionalType(parent); } -export function BinaryExpression(node: Object, parent: Object): boolean { +export function BinaryExpression(node: any, parent: any): boolean { // let i = (1 in []); // for ((1 in []);;); return ( @@ -168,7 +168,7 @@ export function BinaryExpression(node: Object, parent: Object): boolean { ); } -export function SequenceExpression(node: Object, parent: Object): boolean { +export function SequenceExpression(node: any, parent: any): boolean { if ( // Although parentheses wouldn"t hurt around sequence // expressions in the head of for loops, traditional style @@ -191,7 +191,7 @@ export function SequenceExpression(node: Object, parent: Object): boolean { return true; } -export function YieldExpression(node: Object, parent: Object): boolean { +export function YieldExpression(node: any, parent: any): boolean { return ( t.isBinary(parent) || t.isUnaryLike(parent) || @@ -205,14 +205,14 @@ export function YieldExpression(node: Object, parent: Object): boolean { export { YieldExpression as AwaitExpression }; export function ClassExpression( - node: Object, - parent: Object, - printStack: Array, + node: any, + parent: any, + printStack: Array, ): boolean { return isFirstInStatement(printStack, { considerDefaultExports: true }); } -export function UnaryLike(node: Object, parent: Object): boolean { +export function UnaryLike(node: any, parent: any): boolean { return ( hasPostfixPart(node, parent) || t.isBinaryExpression(parent, { operator: "**", left: node }) || @@ -221,18 +221,18 @@ export function UnaryLike(node: Object, parent: Object): boolean { } export function FunctionExpression( - node: Object, - parent: Object, - printStack: Array, + node: any, + parent: any, + printStack: Array, ): boolean { return isFirstInStatement(printStack, { considerDefaultExports: true }); } -export function ArrowFunctionExpression(node: Object, parent: Object): boolean { +export function ArrowFunctionExpression(node: any, parent: any): boolean { return t.isExportDeclaration(parent) || ConditionalExpression(node, parent); } -export function ConditionalExpression(node: Object, parent: Object): boolean { +export function ConditionalExpression(node: any, parent?): boolean { if ( t.isUnaryLike(parent) || t.isBinary(parent) || @@ -247,10 +247,7 @@ export function ConditionalExpression(node: Object, parent: Object): boolean { return UnaryLike(node, parent); } -export function OptionalMemberExpression( - node: Object, - parent: Object, -): boolean { +export function OptionalMemberExpression(node: any, parent: any): boolean { return ( t.isCallExpression(parent, { callee: node }) || t.isMemberExpression(parent, { object: node }) @@ -259,19 +256,15 @@ export function OptionalMemberExpression( export { OptionalMemberExpression as OptionalCallExpression }; -export function AssignmentExpression( - node: Object, - parent: Object, - printStack: Array, -): boolean { +export function AssignmentExpression(node: any, parent: any): boolean { if (t.isObjectPattern(node.left)) { return true; } else { - return ConditionalExpression(node, parent, printStack); + return ConditionalExpression(node, parent); } } -export function LogicalExpression(node: Object, parent: Object): boolean { +export function LogicalExpression(node: any, parent: any): boolean { switch (node.operator) { case "||": if (!t.isLogicalExpression(parent)) return false; @@ -286,7 +279,7 @@ export function LogicalExpression(node: Object, parent: Object): boolean { // Walk up the print stack to determine if our node can come first // in statement. function isFirstInStatement( - printStack: Array, + printStack: Array, { considerArrow = false, considerDefaultExports = false } = {}, ): boolean { let i = printStack.length - 1; diff --git a/packages/babel-generator/src/node/whitespace.js b/packages/babel-generator/src/node/whitespace.ts similarity index 68% rename from packages/babel-generator/src/node/whitespace.js rename to packages/babel-generator/src/node/whitespace.ts index 67194e5b7b..b5de18f3f4 100644 --- a/packages/babel-generator/src/node/whitespace.js +++ b/packages/babel-generator/src/node/whitespace.ts @@ -1,8 +1,8 @@ import * as t from "@babel/types"; type WhitespaceObject = { - before?: boolean, - after?: boolean, + before?: boolean; + after?: boolean; }; /** @@ -13,7 +13,10 @@ type WhitespaceObject = { * // { hasCall: false, hasFunction: true, hasHelper: false } */ -function crawl(node, state = {}) { +function crawl( + node: t.Node, + state: { hasCall?: boolean; hasFunction?: boolean; hasHelper?: boolean } = {}, +) { if (t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) { crawl(node.object, state); if (node.computed) crawl(node.property, state); @@ -26,6 +29,7 @@ function crawl(node, state = {}) { } else if (t.isFunction(node)) { state.hasFunction = true; } else if (t.isIdentifier(node)) { + // @ts-expect-error todo(flow->ts): node.callee is not really expected here… state.hasHelper = state.hasHelper || isHelper(node.callee); } @@ -36,7 +40,7 @@ function crawl(node, state = {}) { * Test if a node is or has a helper. */ -function isHelper(node) { +function isHelper(node: t.Node): boolean { if (t.isMemberExpression(node)) { return isHelper(node.object) || isHelper(node.property); } else if (t.isIdentifier(node)) { @@ -66,12 +70,23 @@ function isType(node) { * Tests for node types that need whitespace. */ -export const nodes = { +export const nodes: { + [K in string]?: ( + node: K extends t.Node["type"] ? Extract : t.Node, + // todo: + // node: K extends keyof typeof t + // ? Extract + // : t.Node, + parent: t.Node, + ) => void; +} = { /** * Test if AssignmentExpression needs whitespace. */ - AssignmentExpression(node: Object): ?WhitespaceObject { + AssignmentExpression( + node: t.AssignmentExpression, + ): WhitespaceObject | undefined | null { const state = crawl(node.right); if ((state.hasCall && state.hasHelper) || state.hasFunction) { return { @@ -85,9 +100,9 @@ export const nodes = { * Test if SwitchCase needs whitespace. */ - SwitchCase(node: Object, parent: Object): WhitespaceObject { + SwitchCase(node: t.SwitchCase, parent: t.SwitchStatement): WhitespaceObject { return { - before: node.consequent.length || parent.cases[0] === node, + before: !!node.consequent.length || parent.cases[0] === node, after: !node.consequent.length && parent.cases[parent.cases.length - 1] === node, @@ -98,7 +113,7 @@ export const nodes = { * Test if LogicalExpression needs whitespace. */ - LogicalExpression(node: Object): ?WhitespaceObject { + LogicalExpression(node: t.LogicalExpression): WhitespaceObject | undefined { if (t.isFunction(node.left) || t.isFunction(node.right)) { return { after: true, @@ -110,8 +125,8 @@ export const nodes = { * Test if Literal needs whitespace. */ - Literal(node: Object): ?WhitespaceObject { - if (node.value === "use strict") { + Literal(node: t.Literal): WhitespaceObject | undefined | null { + if (t.isStringLiteral(node) && node.value === "use strict") { return { after: true, }; @@ -122,7 +137,7 @@ export const nodes = { * Test if CallExpressionish needs whitespace. */ - CallExpression(node: Object): ?WhitespaceObject { + CallExpression(node: t.CallExpression): WhitespaceObject | undefined | null { if (t.isFunction(node.callee) || isHelper(node)) { return { before: true, @@ -131,7 +146,9 @@ export const nodes = { } }, - OptionalCallExpression(node: Object): ?WhitespaceObject { + OptionalCallExpression( + node: t.OptionalCallExpression, + ): WhitespaceObject | undefined | null { if (t.isFunction(node.callee)) { return { before: true, @@ -144,7 +161,9 @@ export const nodes = { * Test if VariableDeclaration needs whitespace. */ - VariableDeclaration(node: Object): ?WhitespaceObject { + VariableDeclaration( + node: t.VariableDeclaration, + ): WhitespaceObject | undefined | null { for (let i = 0; i < node.declarations.length; i++) { const declar = node.declarations[i]; @@ -167,7 +186,7 @@ export const nodes = { * Test if IfStatement needs whitespace. */ - IfStatement(node: Object): ?WhitespaceObject { + IfStatement(node: t.IfStatement): WhitespaceObject | undefined | null { if (t.isBlockStatement(node.consequent)) { return { before: true, @@ -182,9 +201,9 @@ export const nodes = { */ nodes.ObjectProperty = nodes.ObjectTypeProperty = nodes.ObjectMethod = function ( - node: Object, - parent, -): ?WhitespaceObject { + node: t.ObjectProperty | t.ObjectTypeProperty | t.ObjectMethod, + parent: any, +): WhitespaceObject | undefined | null { if (parent.properties[0] === node) { return { before: true, @@ -193,9 +212,9 @@ nodes.ObjectProperty = nodes.ObjectTypeProperty = nodes.ObjectMethod = function }; nodes.ObjectTypeCallProperty = function ( - node: Object, - parent, -): ?WhitespaceObject { + node: t.ObjectTypeCallProperty, + parent: any, +): WhitespaceObject | undefined | null { if (parent.callProperties[0] === node && !parent.properties?.length) { return { before: true, @@ -203,7 +222,10 @@ nodes.ObjectTypeCallProperty = function ( } }; -nodes.ObjectTypeIndexer = function (node: Object, parent): ?WhitespaceObject { +nodes.ObjectTypeIndexer = function ( + node: t.ObjectTypeIndexer, + parent: any, +): WhitespaceObject | undefined | null { if ( parent.indexers[0] === node && !parent.properties?.length && @@ -216,9 +238,9 @@ nodes.ObjectTypeIndexer = function (node: Object, parent): ?WhitespaceObject { }; nodes.ObjectTypeInternalSlot = function ( - node: Object, - parent, -): ?WhitespaceObject { + node: t.ObjectTypeInternalSlot, + parent: any, +): WhitespaceObject | undefined | null { if ( parent.internalSlots[0] === node && !parent.properties?.length && @@ -240,7 +262,7 @@ export const list = { * Return VariableDeclaration declarations init properties. */ - VariableDeclaration(node: Object): Array { + VariableDeclaration(node: t.VariableDeclaration) { return node.declarations.map(decl => decl.init); }, @@ -248,7 +270,7 @@ export const list = { * Return VariableDeclaration elements. */ - ArrayExpression(node: Object): Array { + ArrayExpression(node: t.ArrayExpression) { return node.elements; }, @@ -256,7 +278,7 @@ export const list = { * Return VariableDeclaration properties. */ - ObjectExpression(node: Object): Array { + ObjectExpression(node: t.ObjectExpression) { return node.properties; }, }; @@ -265,20 +287,22 @@ export const list = { * Add whitespace tests for nodes and their aliases. */ -[ +([ ["Function", true], ["Class", true], ["Loop", true], ["LabeledStatement", true], ["SwitchStatement", true], ["TryStatement", true], -].forEach(function ([type, amounts]) { +] as Array<[string, any]>).forEach(function ([type, amounts]) { if (typeof amounts === "boolean") { amounts = { after: amounts, before: amounts }; } - [type].concat(t.FLIPPED_ALIAS_KEYS[type] || []).forEach(function (type) { - nodes[type] = function () { - return amounts; - }; - }); + [type as string] + .concat(t.FLIPPED_ALIAS_KEYS[type] || []) + .forEach(function (type) { + nodes[type] = function () { + return amounts; + }; + }); }); diff --git a/packages/babel-generator/src/printer.js b/packages/babel-generator/src/printer.ts similarity index 90% rename from packages/babel-generator/src/printer.js rename to packages/babel-generator/src/printer.ts index 854119a2c3..f25a88e453 100644 --- a/packages/babel-generator/src/printer.js +++ b/packages/babel-generator/src/printer.ts @@ -3,6 +3,7 @@ import * as n from "./node"; import * as t from "@babel/types"; import * as generatorFunctions from "./generators"; +import type SourceMap from "./source-map"; const SCIENTIFIC_NOTATION = /e/i; const ZERO_DECIMAL_INTEGER = /\.0+$/; @@ -10,26 +11,29 @@ const NON_DECIMAL_LITERAL = /^0[box]/; const PURE_ANNOTATION_RE = /^\s*[@#]__PURE__\s*$/; export type Format = { - shouldPrintComment: (comment: string) => boolean, - retainLines: boolean, - retainFunctionParens: boolean, - comments: boolean, - auxiliaryCommentBefore: string, - auxiliaryCommentAfter: string, - compact: boolean | "auto", - minified: boolean, - concise: boolean, + shouldPrintComment: (comment: string) => boolean; + retainLines: boolean; + retainFunctionParens: boolean; + comments: boolean; + auxiliaryCommentBefore: string; + auxiliaryCommentAfter: string; + compact: boolean | "auto"; + minified: boolean; + concise: boolean; indent: { - adjustMultilineComment: boolean, - style: string, - base: number, - }, - decoratorsBeforeExport: boolean, + adjustMultilineComment: boolean; + style: string; + base: number; + }; + decoratorsBeforeExport: boolean; + recordAndTupleSyntaxType: "bar" | "hash"; + jsescOption; + jsonCompatibleStrings?; }; -export default class Printer { - constructor(format, map) { - this.format = format || {}; +class Printer { + constructor(format: Format, map: SourceMap) { + this.format = format; this._buf = new Buffer(map); } @@ -37,14 +41,14 @@ export default class Printer { inForStatementInitCounter: number = 0; declare _buf: Buffer; - _printStack: Array = []; + _printStack: Array = []; _indent: number = 0; _insideAux: boolean = false; - _printedCommentStarts: Object = {}; - _parenPushNewlineState: ?Object = null; + _printedCommentStarts: any = {}; + _parenPushNewlineState: any = null; _noLineTerminator: boolean = false; _printAuxAfterOnNextUserNode: boolean = false; - _printedComments: WeakSet = new WeakSet(); + _printedComments: WeakSet = new WeakSet(); _endsWithInteger = false; _endsWithWord = false; @@ -199,19 +203,19 @@ export default class Printer { this._buf.removeTrailingNewline(); } - exactSource(loc: Object, cb: () => void) { + exactSource(loc: any, cb: () => void) { this._catchUp("start", loc); this._buf.exactSource(loc, cb); } - source(prop: string, loc: Object): void { + source(prop: string, loc: any): void { this._catchUp(prop, loc); this._buf.source(prop, loc); } - withSource(prop: string, loc: Object, cb: () => void): void { + withSource(prop: string, loc: any, cb: () => void): void { this._catchUp(prop, loc); this._buf.withSource(prop, loc, cb); @@ -303,7 +307,7 @@ export default class Printer { parenPushNewlineState.printed = true; } - _catchUp(prop: string, loc: Object) { + _catchUp(prop: string, loc: any) { if (!this.format.retainLines) return; // catch up to this nodes newline if we're behind @@ -341,7 +345,7 @@ export default class Printer { * `undefined` will be returned and not `foo` due to the terminator. */ - startTerminatorless(isLabel: boolean = false): Object { + startTerminatorless(isLabel: boolean = false): any { if (isLabel) { this._noLineTerminator = true; return null; @@ -356,7 +360,7 @@ export default class Printer { * Print an ending parentheses if a starting one has been printed. */ - endTerminatorless(state: Object) { + endTerminatorless(state?: any) { this._noLineTerminator = false; if (state?.printed) { this.dedent(); @@ -365,7 +369,7 @@ export default class Printer { } } - print(node, parent) { + print(node, parent?) { if (!node) return; const oldConcise = this.format.concise; @@ -417,7 +421,7 @@ export default class Printer { this._insideAux = oldInAux; } - _maybeAddAuxComment(enteredPositionlessNode) { + _maybeAddAuxComment(enteredPositionlessNode?) { if (enteredPositionlessNode) this._printAuxBeforeComment(); if (!this._insideAux) this._printAuxAfterComment(); } @@ -460,7 +464,7 @@ export default class Printer { } } - printJoin(nodes: ?Array, parent: Object, opts = {}) { + printJoin(nodes: Array | undefined | null, parent: any, opts: any = {}) { if (!nodes?.length) return; if (opts.indent) this.indent(); @@ -527,12 +531,24 @@ export default class Printer { if (indent) this.dedent(); } - printSequence(nodes, parent, opts = {}) { + printSequence( + nodes, + parent, + opts: { + statement?: boolean; + indent?: boolean; + addNewlines?: Function; + } = {}, + ) { opts.statement = true; return this.printJoin(nodes, parent, opts); } - printList(items, parent, opts = {}) { + printList( + items, + parent, + opts: { separator?: Function; indent?: boolean; statement?: boolean } = {}, + ) { if (opts.separator == null) { opts.separator = commaSeparator; } @@ -627,7 +643,7 @@ export default class Printer { if (printNewLines) this.newline(1); } - _printComments(comments?: Array, inlinePureAnnotation?: boolean) { + _printComments(comments?: Array, inlinePureAnnotation?: boolean) { if (!comments?.length) return; if ( @@ -646,8 +662,8 @@ export default class Printer { } } } - - printAssertions(node: Node) { + // todo(flow->ts): was Node + printAssertions(node) { if (node.assertions?.length) { this.space(); this.word("assert"); @@ -664,6 +680,10 @@ export default class Printer { // Expose the node type functions and helpers on the prototype for easy usage. Object.assign(Printer.prototype, generatorFunctions); +type GeneratorFunctions = typeof generatorFunctions; +interface Printer extends GeneratorFunctions {} +export default Printer; + function commaSeparator() { this.token(","); this.space(); diff --git a/packages/babel-generator/src/source-map.js b/packages/babel-generator/src/source-map.ts similarity index 89% rename from packages/babel-generator/src/source-map.js rename to packages/babel-generator/src/source-map.ts index 9c58d8b8c6..402c68a6f6 100644 --- a/packages/babel-generator/src/source-map.js +++ b/packages/babel-generator/src/source-map.ts @@ -5,6 +5,13 @@ import sourceMap from "source-map"; */ export default class SourceMap { + private _cachedMap: sourceMap.SourceMapGenerator | null; + private _code: any; + private _opts: any; + private _rawMappings: any[]; + private _lastGenLine: number; + private _lastSourceLine: number; + private _lastSourceColumn: number; constructor(opts, code) { this._cachedMap = null; this._code = code; @@ -57,8 +64,8 @@ export default class SourceMap { generatedColumn: number, line: number, column: number, - identifierName: ?string, - filename: ?string, + identifierName?: string | null, + filename?: string | null, force?: boolean, ) { // Adding an empty mapping at the start of a generated line just clutters the map. diff --git a/yarn.lock b/yarn.lock index fd81c0ff99..812778b4e4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -251,6 +251,9 @@ __metadata: "@babel/helper-fixtures": "workspace:*" "@babel/parser": "workspace:*" "@babel/types": "workspace:^7.12.11" + "@types/jsesc": ^2.5.0 + "@types/lodash": ^4.14.150 + "@types/source-map": ^0.5.0 jsesc: "condition: BABEL_8_BREAKING ? ^3.0.2 : ^2.5.1" source-map: ^0.5.0 languageName: unknown @@ -3906,6 +3909,13 @@ __metadata: languageName: node linkType: hard +"@types/jsesc@npm:^2.5.0": + version: 2.5.1 + resolution: "@types/jsesc@npm:2.5.1" + checksum: c4df356ce6b1f2af847f9b059075b879c15a7834ce4387c8d5e5cebc24d1173abae5d19c07160d24f74c6e7413ee312a66ce3ce965d0544278d2c16b218306e1 + languageName: node + linkType: hard + "@types/json-schema@npm:^7.0.3": version: 7.0.4 resolution: "@types/json-schema@npm:7.0.4" @@ -3920,10 +3930,10 @@ __metadata: languageName: node linkType: hard -"@types/lodash@npm:^4.14.162": - version: 4.14.165 - resolution: "@types/lodash@npm:4.14.165" - checksum: 525bfc34b0b591cc957125a961c70e63e5ad8b23cbd89b7594a5ea74823285b6d96993a7eec506e26b379ee52dc9dcd3a894ff210be4c97bccb536e62361dbc8 +"@types/lodash@npm:^4.14.150, @types/lodash@npm:^4.14.162": + version: 4.14.168 + resolution: "@types/lodash@npm:4.14.168" + checksum: 9a4e25f89fc035b9f0388f1f7be85e5eff49f9e6db0d93432c9a89fce0916f8a89db4e8290415f7ea02de6b00d3573826378dcb655b7b2d20530a6e8d6dd6fd0 languageName: node linkType: hard @@ -3964,6 +3974,13 @@ __metadata: languageName: node linkType: hard +"@types/source-map@npm:^0.5.0": + version: 0.5.2 + resolution: "@types/source-map@npm:0.5.2" + checksum: 228e1ef7c7f9c126cf38afdef2c3ccfb1224523c3692da6148abb9bb81095269645495773e94477e8512e1f652419b471cc8c30997f6bd222185e931f6d97acc + languageName: node + linkType: hard + "@types/stack-utils@npm:^2.0.0": version: 2.0.0 resolution: "@types/stack-utils@npm:2.0.0"