From 6ac07a16472a47073fa24e2c650b092f6288f685 Mon Sep 17 00:00:00 2001 From: Bogdan Savluk Date: Sat, 27 Mar 2021 01:40:32 +0100 Subject: [PATCH] convert `@babel/helper-module-transforms` to typescript (#12928) 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 | 4 + ...{get-module-name.js => get-module-name.ts} | 8 +- .../src/{index.js => index.ts} | 29 ++++-- ...data.js => normalize-and-load-metadata.ts} | 91 ++++++++++--------- ...ferences.js => rewrite-live-references.ts} | 59 +++++++++--- .../src/{rewrite-this.js => rewrite-this.ts} | 5 +- 6 files changed, 124 insertions(+), 72 deletions(-) rename packages/babel-helper-module-transforms/src/{get-module-name.js => get-module-name.ts} (94%) rename packages/babel-helper-module-transforms/src/{index.js => index.ts} (95%) rename packages/babel-helper-module-transforms/src/{normalize-and-load-metadata.js => normalize-and-load-metadata.ts} (89%) rename packages/babel-helper-module-transforms/src/{rewrite-live-references.js => rewrite-live-references.ts} (84%) rename packages/babel-helper-module-transforms/src/{rewrite-this.js => rewrite-this.ts} (76%) diff --git a/lib/babel-packages.js.flow b/lib/babel-packages.js.flow index 48f2bdc5ee..100ebd9f0f 100644 --- a/lib/babel-packages.js.flow +++ b/lib/babel-packages.js.flow @@ -208,3 +208,7 @@ declare module "@babel/highlight" { declare module "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" { declare module.exports: any; } + +declare module "@babel/helper-module-transforms" { + declare module.exports: any; +} diff --git a/packages/babel-helper-module-transforms/src/get-module-name.js b/packages/babel-helper-module-transforms/src/get-module-name.ts similarity index 94% rename from packages/babel-helper-module-transforms/src/get-module-name.js rename to packages/babel-helper-module-transforms/src/get-module-name.ts index 0e4e81ad3e..428da27d16 100644 --- a/packages/babel-helper-module-transforms/src/get-module-name.js +++ b/packages/babel-helper-module-transforms/src/get-module-name.ts @@ -1,9 +1,7 @@ -// @flow - export default function getModuleName( - rootOpts: Object, - pluginOpts: Object, -): ?string { + rootOpts: any, + pluginOpts: any, +): string | undefined | null { const { filename, filenameRelative = filename, diff --git a/packages/babel-helper-module-transforms/src/index.js b/packages/babel-helper-module-transforms/src/index.ts similarity index 95% rename from packages/babel-helper-module-transforms/src/index.js rename to packages/babel-helper-module-transforms/src/index.ts index 558913a703..a22364b35a 100644 --- a/packages/babel-helper-module-transforms/src/index.js +++ b/packages/babel-helper-module-transforms/src/index.ts @@ -9,9 +9,13 @@ import rewriteLiveReferences from "./rewrite-live-references"; import normalizeAndLoadModuleMetadata, { hasExports, isSideEffectImport, - type ModuleMetadata, - type SourceModuleMetadata, } from "./normalize-and-load-metadata"; +import type { + InteropType, + ModuleMetadata, + SourceModuleMetadata, +} from "./normalize-and-load-metadata"; +import type { NodePath } from "@babel/traverse"; export { default as getModuleName } from "./get-module-name"; @@ -24,7 +28,7 @@ export { hasExports, isSideEffectImport, isModule, rewriteThis }; * and returns a list of statements for use when initializing the module. */ export function rewriteModuleStatementsAndPrepareHeader( - path: NodePath, + path: NodePath, { // TODO(Babel 8): Remove this loose, @@ -39,6 +43,17 @@ export function rewriteModuleStatementsAndPrepareHeader( constantReexports = loose, enumerableModuleMeta = loose, + }: { + exportName?; + strict; + allowTopLevelThis?; + strictMode; + loose?; + noInterop?; + lazy?; + esNamespaceOnly?; + constantReexports?; + enumerableModuleMeta?; }, ) { assert(isModule(path), "Cannot process module statements in a script"); @@ -106,9 +121,9 @@ export function ensureStatementsHoisted(statements) { */ export function wrapInterop( programPath: NodePath, - expr: Node, + expr: t.Expression, type: InteropType, -): Node { +): t.CallExpression { if (type === "none") { return null; } @@ -138,7 +153,7 @@ export function buildNamespaceInitStatements( ) { const statements = []; - let srcNamespace = t.identifier(sourceMetadata.name); + let srcNamespace: t.Node = t.identifier(sourceMetadata.name); if (sourceMetadata.lazy) srcNamespace = t.callExpression(srcNamespace, []); for (const localName of sourceMetadata.importsNamespace) { @@ -329,7 +344,7 @@ function buildExportNameListDeclaration( exportedVars[exportName] = true; } - hasReexport = hasReexport || data.reexportAll; + hasReexport = hasReexport || !!data.reexportAll; } if (!hasReexport || Object.keys(exportedVars).length === 0) return null; diff --git a/packages/babel-helper-module-transforms/src/normalize-and-load-metadata.js b/packages/babel-helper-module-transforms/src/normalize-and-load-metadata.ts similarity index 89% rename from packages/babel-helper-module-transforms/src/normalize-and-load-metadata.js rename to packages/babel-helper-module-transforms/src/normalize-and-load-metadata.ts index 84bac99f3c..1c1c7b2cd8 100644 --- a/packages/babel-helper-module-transforms/src/normalize-and-load-metadata.js +++ b/packages/babel-helper-module-transforms/src/normalize-and-load-metadata.ts @@ -1,61 +1,52 @@ import { basename, extname } from "path"; +import type * as t from "@babel/types"; import { isIdentifierName } from "@babel/helper-validator-identifier"; import splitExportDeclaration from "@babel/helper-split-export-declaration"; +import type { NodePath } from "@babel/traverse"; -export type ModuleMetadata = { - exportName: string, - +export interface ModuleMetadata { + exportName: string; // The name of the variable that will reference an object containing export names. - exportNameListName: null | string, - - hasExports: boolean, - + exportNameListName: null | string; + hasExports: boolean; // Lookup from local binding to export information. - local: Map, - + local: Map; // Lookup of source file to source file metadata. - source: Map, - + source: Map; // List of names that should only be printed as string literals. // i.e. `import { "any unicode" as foo } from "some-module"` // `stringSpecifiers` is Set(1) ["any unicode"] // In most cases `stringSpecifiers` is an empty Set - stringSpecifiers: Set, -}; + stringSpecifiers: Set; +} export type InteropType = "default" | "namespace" | "none"; -export type SourceModuleMetadata = { +export interface SourceModuleMetadata { // A unique variable name to use for this namespace object. Centralized for simplicity. - name: string, - - loc: ?BabelNodeSourceLocation, - - interop: InteropType, - + name: string; + loc: t.SourceLocation | undefined | null; + interop: InteropType; // Local binding to reference from this source namespace. Key: Local name, value: Import name - imports: Map, - + imports: Map; // Local names that reference namespace object. - importsNamespace: Set, - + importsNamespace: Set; // Reexports to create for namespace. Key: Export name, value: Import name - reexports: Map, - + reexports: Map; // List of names to re-export namespace as. - reexportNamespace: Set, - + reexportNamespace: Set; // Tracks if the source should be re-exported. reexportAll: null | { - loc: ?BabelNodeSourceLocation, - }, -}; + loc: t.SourceLocation | undefined | null; + }; + lazy?; +} -export type LocalExportMetadata = { - name: Array, // names of exports - kind: "import" | "hoisted" | "block" | "var", -}; +export interface LocalExportMetadata { + names: Array; // names of exports, + kind: "import" | "hoisted" | "block" | "var"; +} /** * Check if the module has any exports that need handling. @@ -82,7 +73,7 @@ export function isSideEffectImport(source: SourceModuleMetadata) { * needed to reconstruct the module's behavior. */ export default function normalizeModuleAndLoadMetadata( - programPath: NodePath, + programPath: NodePath, exportName?: string, { noInterop = false, @@ -94,7 +85,7 @@ export default function normalizeModuleAndLoadMetadata( if (!exportName) { exportName = programPath.scope.generateUidIdentifier("exports").name; } - const stringSpecifiers = new Set(); + const stringSpecifiers = new Set(); nameAnonymousExports(programPath); @@ -166,11 +157,15 @@ function getExportSpecifierName( * Get metadata about the imports and exports present in this module. */ function getModuleMetadata( - programPath: NodePath, + programPath: NodePath, { lazy, initializeReexports, - }: { lazy: boolean, initializeReexports: boolean }, + }: { + // todo(flow-ts) changed from boolean, to match expected usage inside the function + lazy: boolean | string[] | Function; + initializeReexports: boolean; + }, stringSpecifiers: Set, ) { const localData = getLocalExportMetadata( @@ -289,7 +284,9 @@ function getModuleMetadata( data.reexports.set(exportName, importName); if (exportName === "__esModule") { - throw exportName.buildCodeFrameError('Illegal export "__esModule".'); + throw spec + .get("exported") + .buildCodeFrameError('Illegal export "__esModule".'); } }); } else if ( @@ -360,13 +357,13 @@ function getModuleMetadata( * Get metadata about local variables that are exported. */ function getLocalExportMetadata( - programPath: NodePath, + programPath: NodePath, initializeReexports: boolean, stringSpecifiers: Set, ): Map { const bindingKindLookup = new Map(); - programPath.get("body").forEach(child => { + programPath.get("body").forEach((child: any) => { let kind; if (child.isImportDeclaration()) { kind = "import"; @@ -434,7 +431,8 @@ function getLocalExportMetadata( (initializeReexports || !child.node.source) ) { if (child.node.declaration) { - const declaration = child.get("declaration"); + // todo: flow->ts babel-types node field types + const declaration = child.get("declaration") as NodePath; const ids = declaration.getOuterBindingIdentifierPaths(); Object.keys(ids).forEach(name => { if (name === "__esModule") { @@ -463,6 +461,7 @@ function getLocalExportMetadata( declaration.isFunctionDeclaration() || declaration.isClassDeclaration() ) { + // @ts-expect-error todo(flow->ts): improve babel-types getLocalMetadata(declaration.get("id")).names.push("default"); } else { // These should have been removed by the nameAnonymousExports() call. @@ -478,7 +477,7 @@ function getLocalExportMetadata( /** * Ensure that all exported values have local binding names. */ -function nameAnonymousExports(programPath: NodePath) { +function nameAnonymousExports(programPath: NodePath) { // Name anonymous exported locals. programPath.get("body").forEach(child => { if (!child.isExportDefaultDeclaration()) return; @@ -486,12 +485,13 @@ function nameAnonymousExports(programPath: NodePath) { }); } -function removeModuleDeclarations(programPath: NodePath) { +function removeModuleDeclarations(programPath: NodePath) { programPath.get("body").forEach(child => { if (child.isImportDeclaration()) { child.remove(); } else if (child.isExportNamedDeclaration()) { if (child.node.declaration) { + // @ts-expect-error todo(flow->ts): avoid mutations child.node.declaration._blockHoist = child.node._blockHoist; child.replaceWith(child.node.declaration); } else { @@ -504,6 +504,7 @@ function removeModuleDeclarations(programPath: NodePath) { declaration.isFunctionDeclaration() || declaration.isClassDeclaration() ) { + // @ts-expect-error todo(flow->ts): avoid mutations declaration._blockHoist = child.node._blockHoist; child.replaceWith(declaration); } else { diff --git a/packages/babel-helper-module-transforms/src/rewrite-live-references.js b/packages/babel-helper-module-transforms/src/rewrite-live-references.ts similarity index 84% rename from packages/babel-helper-module-transforms/src/rewrite-live-references.js rename to packages/babel-helper-module-transforms/src/rewrite-live-references.ts index a5de3a2492..0d80521d9c 100644 --- a/packages/babel-helper-module-transforms/src/rewrite-live-references.js +++ b/packages/babel-helper-module-transforms/src/rewrite-live-references.ts @@ -1,12 +1,33 @@ import assert from "assert"; import * as t from "@babel/types"; import template from "@babel/template"; +import type { NodePath, Visitor, Scope } from "@babel/traverse"; import simplifyAccess from "@babel/helper-simple-access"; import type { ModuleMetadata } from "./normalize-and-load-metadata"; +interface RewriteReferencesVisitorState { + exported: Map; + metadata: ModuleMetadata; + requeueInParent: (path) => void; + scope: Scope; + imported: Map; + buildImportReference: ( + [source, importName, localName]: readonly [any, any, any], + identNode, + ) => any; + seen: WeakSet; +} + +interface RewriteBindingInitVisitorState { + exported: Map; + metadata: ModuleMetadata; + requeueInParent: (path) => void; + scope: Scope; +} + export default function rewriteLiveReferences( - programPath: NodePath, + programPath: NodePath, metadata: ModuleMetadata, ) { const imported = new Map(); @@ -39,12 +60,16 @@ export default function rewriteLiveReferences( } // Rewrite initialization of bindings to update exports. - programPath.traverse(rewriteBindingInitVisitor, { + const rewriteBindingInitVisitorState: RewriteBindingInitVisitorState = { metadata, requeueInParent, scope: programPath.scope, exported, // local name => exported name list - }); + }; + programPath.traverse( + rewriteBindingInitVisitor, + rewriteBindingInitVisitorState, + ); simplifyAccess( programPath, @@ -53,7 +78,7 @@ export default function rewriteLiveReferences( ); // Rewrite reads/writes from imports and exports to have the correct behavior. - programPath.traverse(rewriteReferencesVisitor, { + const rewriteReferencesVisitorState: RewriteReferencesVisitorState = { seen: new WeakSet(), metadata, requeueInParent, @@ -68,7 +93,7 @@ export default function rewriteLiveReferences( return identNode; } - let namespace = t.identifier(meta.name); + let namespace: t.Expression = t.identifier(meta.name); if (meta.lazy) namespace = t.callExpression(namespace, []); const computed = metadata.stringSpecifiers.has(importName); @@ -79,13 +104,14 @@ export default function rewriteLiveReferences( computed, ); }, - }); + }; + programPath.traverse(rewriteReferencesVisitor, rewriteReferencesVisitorState); } /** * A visitor to inject export update statements during binding initialization. */ -const rewriteBindingInitVisitor = { +const rewriteBindingInitVisitor: Visitor = { Scope(path) { path.skip(); }, @@ -105,6 +131,7 @@ const rewriteBindingInitVisitor = { t.identifier(localName), ), ); + // @ts-expect-error todo(flow->ts): avoid mutations statement._blockHoist = path.node._blockHoist; requeueInParent(path.insertAfter(statement)[0]); @@ -124,6 +151,7 @@ const rewriteBindingInitVisitor = { t.identifier(localName), ), ); + // @ts-expect-error todo(flow->ts): avoid mutations statement._blockHoist = path.node._blockHoist; requeueInParent(path.insertAfter(statement)[0]); @@ -163,7 +191,7 @@ const buildImportThrow = localName => { `; }; -const rewriteReferencesVisitor = { +const rewriteReferencesVisitor: Visitor = { ReferencedIdentifier(path) { const { seen, @@ -200,9 +228,11 @@ const rewriteReferencesVisitor = { } else if (path.isJSXIdentifier() && t.isMemberExpression(ref)) { const { object, property } = ref; path.replaceWith( - t.JSXMemberExpression( - t.JSXIdentifier(object.name), - t.JSXIdentifier(property.name), + t.jsxMemberExpression( + // @ts-expect-error todo(flow->ts): possible bug `object` might not have a name + t.jsxIdentifier(object.name), + // @ts-expect-error todo(flow->ts): possible bug `property` might not have a name + t.jsxIdentifier(property.name), ), ); } else { @@ -303,9 +333,10 @@ const rewriteReferencesVisitor = { }); if (items.length > 0) { - let node = t.sequenceExpression(items); + let node: t.Node = t.sequenceExpression(items); if (path.parentPath.isExpressionStatement()) { node = t.expressionStatement(node); + // @ts-expect-error todo(flow->ts): avoid mutations node._blockHoist = path.parentPath.node._blockHoist; } @@ -315,7 +346,9 @@ const rewriteReferencesVisitor = { } }, }, - "ForOfStatement|ForInStatement"(path) { + "ForOfStatement|ForInStatement"( + path: NodePath, + ) { const { scope, node } = path; const { left } = node; const { exported, scope: programScope } = this; diff --git a/packages/babel-helper-module-transforms/src/rewrite-this.js b/packages/babel-helper-module-transforms/src/rewrite-this.ts similarity index 76% rename from packages/babel-helper-module-transforms/src/rewrite-this.js rename to packages/babel-helper-module-transforms/src/rewrite-this.ts index 02d96f930e..4e564cc33a 100644 --- a/packages/babel-helper-module-transforms/src/rewrite-this.js +++ b/packages/babel-helper-module-transforms/src/rewrite-this.ts @@ -2,6 +2,7 @@ import { environmentVisitor } from "@babel/helper-replace-supers"; import traverse from "@babel/traverse"; import * as t from "@babel/types"; +import type { NodePath, Visitor } from "@babel/traverse"; export default function rewriteThis(programPath: NodePath) { // Rewrite "this" to be "undefined". traverse(programPath.node, { ...rewriteThisVisitor, noScope: true }); @@ -11,10 +12,10 @@ export default function rewriteThis(programPath: NodePath) { * A visitor to walk the tree, rewriting all `this` references in the top-level scope to be * `void 0` (undefined). */ -const rewriteThisVisitor = traverse.visitors.merge([ +const rewriteThisVisitor: Visitor = traverse.visitors.merge([ environmentVisitor, { - ThisExpression(path) { + ThisExpression(path: NodePath) { path.replaceWith(t.unaryExpression("void", t.numericLiteral(0), true)); }, },