diff --git a/lib/javascript/JavascriptParser.js b/lib/javascript/JavascriptParser.js index 2c9874a3e..f6741b03b 100644 --- a/lib/javascript/JavascriptParser.js +++ b/lib/javascript/JavascriptParser.js @@ -1955,6 +1955,32 @@ class JavascriptParser extends Parser { } } + /** + * Module pre walking iterates the scope for import entries + * @param {(Statement | ModuleDeclaration)[]} statements statements + */ + modulePreWalkStatements(statements) { + for (let index = 0, len = statements.length; index < len; index++) { + const statement = statements[index]; + /** @type {StatementPath} */ + (this.statementPath).push(statement); + switch (statement.type) { + case "ImportDeclaration": + this.modulePreWalkImportDeclaration(statement); + break; + case "ExportAllDeclaration": + this.modulePreWalkExportAllDeclaration(statement); + break; + case "ExportNamedDeclaration": + this.modulePreWalkExportNamedDeclaration(statement); + break; + } + this.prevStatement = + /** @type {StatementPath} */ + (this.statementPath).pop(); + } + } + /** * Pre walking iterates the scope for variable declarations * @param {(Statement | ModuleDeclaration)[]} statements statements @@ -2075,12 +2101,6 @@ class JavascriptParser extends Parser { return; } switch (statement.type) { - case "ImportDeclaration": - this.blockPreWalkImportDeclaration(statement); - break; - case "ExportAllDeclaration": - this.blockPreWalkExportAllDeclaration(statement); - break; case "ExportDefaultDeclaration": this.blockPreWalkExportDefaultDeclaration(statement); break; @@ -2620,7 +2640,7 @@ class JavascriptParser extends Parser { /** * @param {ImportDeclaration} statement statement */ - blockPreWalkImportDeclaration(statement) { + modulePreWalkImportDeclaration(statement) { const source = /** @type {ImportSource} */ (statement.source.value); this.hooks.import.call(statement, source); for (const specifier of statement.specifiers) { @@ -2690,14 +2710,49 @@ class JavascriptParser extends Parser { /** * @param {ExportNamedDeclaration} statement statement */ - blockPreWalkExportNamedDeclaration(statement) { - let source; - if (statement.source) { - source = /** @type {ImportSource} */ (statement.source.value); - this.hooks.exportImport.call(statement, source); - } else { - this.hooks.export.call(statement); + modulePreWalkExportNamedDeclaration(statement) { + if (!statement.source) return; + const source = /** @type {ImportSource} */ (statement.source.value); + this.hooks.exportImport.call(statement, source); + if (statement.specifiers) { + for ( + let specifierIndex = 0; + specifierIndex < statement.specifiers.length; + specifierIndex++ + ) { + const specifier = statement.specifiers[specifierIndex]; + switch (specifier.type) { + case "ExportSpecifier": { + const localName = + /** @type {Identifier} */ (specifier.local).name || + /** @type {string} */ ( + /** @type {Literal} */ (specifier.local).value + ); + const name = + /** @type {Identifier} */ + (specifier.exported).name || + /** @type {string} */ + (/** @type {Literal} */ (specifier.exported).value); + this.hooks.exportImportSpecifier.call( + statement, + source, + localName, + name, + specifierIndex + ); + break; + } + } + } } + } + + /** + * @param {ExportNamedDeclaration} statement statement + */ + blockPreWalkExportNamedDeclaration(statement) { + if (statement.source) return; + this.hooks.export.call(statement); if ( statement.declaration && !this.hooks.exportDeclaration.call(statement, statement.declaration) @@ -2730,22 +2785,12 @@ class JavascriptParser extends Parser { (specifier.exported).name || /** @type {string} */ (/** @type {Literal} */ (specifier.exported).value); - if (source) { - this.hooks.exportImportSpecifier.call( - statement, - source, - localName, - name, - specifierIndex - ); - } else { - this.hooks.exportSpecifier.call( - statement, - localName, - name, - specifierIndex - ); - } + this.hooks.exportSpecifier.call( + statement, + localName, + name, + specifierIndex + ); break; } } @@ -2837,7 +2882,7 @@ class JavascriptParser extends Parser { /** * @param {ExportAllDeclaration} statement statement */ - blockPreWalkExportAllDeclaration(statement) { + modulePreWalkExportAllDeclaration(statement) { const source = /** @type {ImportSource} */ (statement.source.value); const name = statement.exported ? /** @type {Identifier} */ @@ -4568,6 +4613,7 @@ class JavascriptParser extends Parser { if (this.hooks.program.call(ast, comments) === undefined) { this.destructuringAssignmentProperties = new WeakMap(); this.detectMode(ast.body); + this.modulePreWalkStatements(ast.body); this.preWalkStatements(ast.body); this.prevStatement = undefined; this.blockPreWalkStatements(ast.body); diff --git a/test/configCases/require/module-require/index.js b/test/configCases/require/module-require/index.js index dfbe396eb..342ade913 100644 --- a/test/configCases/require/module-require/index.js +++ b/test/configCases/require/module-require/index.js @@ -1,6 +1,10 @@ import { createRequire as _createRequire } from "module"; import { createRequire as __createRequire, builtinModules } from "module"; -import { createRequire as ___createRequire} from "node:module"; +import { createRequire as ___createRequire } from "node:module"; + +let topLetRequire = _createRequireForVar(import.meta.url); +var topVarRequire = _createRequireForVar(import.meta.url); +import { createRequire as _createRequireForVar } from "node:module"; it("should evaluate require/createRequire", () => { expect( @@ -73,3 +77,10 @@ it("should add warning on using require.main", () => { it("should import Node.js module", () => { expect(Array.isArray(builtinModules)).toBe(true); }); + +var varRequire = _createRequireForVar(import.meta.url); +it("should works with top-level var declarations", () => { + expect(varRequire("./a")).toBe(1); + expect(topVarRequire("./b")).toBe(2); + expect(topLetRequire("./c")).toBe(3); +}); diff --git a/types.d.ts b/types.d.ts index 411c17741..b92f44951 100644 --- a/types.d.ts +++ b/types.d.ts @@ -7056,6 +7056,40 @@ declare class JavascriptParser extends ParserClass { classy: ClassExpression | ClassDeclaration | MaybeNamedClassDeclaration ): void; + /** + * Module pre walking iterates the scope for import entries + */ + modulePreWalkStatements( + statements: ( + | ImportDeclarationJavascriptParser + | ExportNamedDeclarationJavascriptParser + | ExportAllDeclarationJavascriptParser + | FunctionDeclaration + | VariableDeclaration + | ClassDeclaration + | ExpressionStatement + | BlockStatement + | StaticBlock + | EmptyStatement + | DebuggerStatement + | WithStatement + | ReturnStatement + | LabeledStatement + | BreakStatement + | ContinueStatement + | IfStatement + | SwitchStatement + | ThrowStatement + | TryStatement + | WhileStatement + | DoWhileStatement + | ForStatement + | ForInStatement + | ForOfStatement + | ExportDefaultDeclaration + )[] + ): void; + /** * Pre walking iterates the scope for variable declarations */ @@ -7295,13 +7329,16 @@ declare class JavascriptParser extends ParserClass { ): void; blockPreWalkExpressionStatement(statement: ExpressionStatement): void; preWalkAssignmentExpression(expression: AssignmentExpression): void; - blockPreWalkImportDeclaration( + modulePreWalkImportDeclaration( statement: ImportDeclarationJavascriptParser ): void; enterDeclaration( declaration: Declaration, onIdent: (ident: string, identifier: Identifier) => void ): void; + modulePreWalkExportNamedDeclaration( + statement: ExportNamedDeclarationJavascriptParser + ): void; blockPreWalkExportNamedDeclaration( statement: ExportNamedDeclarationJavascriptParser ): void; @@ -7312,7 +7349,7 @@ declare class JavascriptParser extends ParserClass { statement: ExportDefaultDeclaration ): void; walkExportDefaultDeclaration(statement: ExportDefaultDeclaration): void; - blockPreWalkExportAllDeclaration( + modulePreWalkExportAllDeclaration( statement: ExportAllDeclarationJavascriptParser ): void; preWalkVariableDeclaration(statement: VariableDeclaration): void;