From 91a27a90800e37a41a650ba71be6b891128e9f83 Mon Sep 17 00:00:00 2001 From: TyrealHu Date: Mon, 9 Oct 2023 10:28:14 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=F0=9F=90=9B=20parse=20import=20specifie?= =?UTF-8?q?r=20with=20keyword?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __test__/__snapshot__/import/normal.ts | 94 ++++++++++++++++++++++++++ __test__/import/normal.test.ts | 8 +++ src/index.ts | 60 ++++++++++------ src/middleware.ts | 4 ++ 4 files changed, 147 insertions(+), 19 deletions(-) diff --git a/__test__/__snapshot__/import/normal.ts b/__test__/__snapshot__/import/normal.ts index db8f1de..62ef4f5 100644 --- a/__test__/__snapshot__/import/normal.ts +++ b/__test__/__snapshot__/import/normal.ts @@ -1813,6 +1813,100 @@ const NormalImportSnapshot = { } ], 'sourceType': 'module' + }, + Issue45: { + 'type': 'Program', + 'start': 0, + 'end': 31, + 'loc': { + 'start': { + 'line': 1, + 'column': 0, + 'index': 0 + }, + 'end': { + 'line': 1, + 'column': 31, + 'index': 31 + } + }, + 'body': [ + { + 'type': 'ImportDeclaration', + 'start': 0, + 'end': 31, + 'loc': { + 'start': { + 'line': 1, + 'column': 0, + 'index': 0 + }, + 'end': { + 'line': 1, + 'column': 31, + 'index': 31 + } + }, + 'importKind': 'value', + 'specifiers': [ + { + 'type': 'ImportDefaultSpecifier', + 'start': 7, + 'end': 13, + 'loc': { + 'start': { + 'line': 1, + 'column': 7, + 'index': 7 + }, + 'end': { + 'line': 1, + 'column': 13, + 'index': 13 + } + }, + 'local': { + 'type': 'Identifier', + 'start': 7, + 'end': 13, + 'loc': { + 'start': { + 'line': 1, + 'column': 7, + 'index': 7 + }, + 'end': { + 'line': 1, + 'column': 13, + 'index': 13 + } + }, + 'name': 'assert' + } + } + ], + 'source': { + 'type': 'Literal', + 'start': 19, + 'end': 31, + 'loc': { + 'start': { + 'line': 1, + 'column': 19, + 'index': 19 + }, + 'end': { + 'line': 1, + 'column': 31, + 'index': 31 + } + }, + 'value': './index.js', + 'raw': '\'./index.js\'' + } + } + ], + 'sourceType': 'module' } } diff --git a/__test__/import/normal.test.ts b/__test__/import/normal.test.ts index 0d3a4bb..344f1fc 100644 --- a/__test__/import/normal.test.ts +++ b/__test__/import/normal.test.ts @@ -91,4 +91,12 @@ describe('normal syntax', () => { equalNode(node, NormalImportSnapshot.ImportTypeSpecifierWithAsAsSomethings) }) + + it('issue 45', function() { + const node = parseSource(generateSource([ + `import assert from './index.js'`, + ])) + + equalNode(node, NormalImportSnapshot.Issue45) + }) }) diff --git a/src/index.ts b/src/index.ts index f461e22..5c3fe6b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3049,6 +3049,28 @@ function tsPlugin(options?: { return super.parseExprOp(left, leftStartPos, leftStartLoc, minPrec, forInit) } + parseImportSpecifiers() { + let nodes = [], first = true + if (acornTypeScript.tokenIsIdentifier(this.type)) { + nodes.push(this.parseImportDefaultSpecifier()) + if (!this.eat(tt.comma)) return nodes + } + if (this.type === tt.star) { + nodes.push(this.parseImportNamespaceSpecifier()) + return nodes + } + this.expect(tt.braceL) + while (!this.eat(tt.braceR)) { + if (!first) { + this.expect(tt.comma) + if (this.afterTrailingComma(tt.braceR)) break + } else first = false + + nodes.push(this.parseImportSpecifier()) + } + return nodes + } + /** * @param {Node} node this may be ImportDeclaration | * TsImportEqualsDeclaration @@ -3144,45 +3166,45 @@ function tsPlugin(options?: { parseExportAllDeclaration(node, exports) { if (this.options.ecmaVersion >= 11) { - if (this.eatContextual("as")) { + if (this.eatContextual('as')) { node.exported = this.parseModuleExportName() this.checkExport(exports, node.exported, this.lastTokStart) } else { node.exported = null } } - this.expectContextual("from") + this.expectContextual('from') if (this.type !== tt.string) this.unexpected() node.source = this.parseExprAtom() this.parseMaybeImportAttributes(node) this.semicolon() - return this.finishNode(node, "ExportAllDeclaration") + return this.finishNode(node, 'ExportAllDeclaration') } parseDynamicImport(node) { - this.next(); // skip `(` + this.next() // skip `(` // Parse node.source. - node.source = this.parseMaybeAssign(); + node.source = this.parseMaybeAssign() if (this.eat(tt.comma)) { - const expr = this.parseExpression(); - node.arguments = [expr]; + const expr = this.parseExpression() + node.arguments = [expr] } // Verify ending. if (!this.eat(tt.parenR)) { - const errorPos = this.start; + const errorPos = this.start if (this.eat(tt.comma) && this.eat(tt.parenR)) { - this.raiseRecoverable(errorPos, "Trailing comma is not allowed in import()"); + this.raiseRecoverable(errorPos, 'Trailing comma is not allowed in import()') } else { - this.unexpected(errorPos); + this.unexpected(errorPos) } } - return this.finishNode(node, "ImportExpression") + return this.finishNode(node, 'ImportExpression') } parseExport(node: any, exports: any): any { @@ -3241,14 +3263,14 @@ function tsPlugin(options?: { return this.parseExportAllDeclaration(node, exports) } if (this.eat(tt._default)) { // export default ... - this.checkExport(exports, "default", this.lastTokStart) + this.checkExport(exports, 'default', this.lastTokStart) node.declaration = this.parseExportDefaultDeclaration() - return this.finishNode(node, "ExportDefaultDeclaration") + return this.finishNode(node, 'ExportDefaultDeclaration') } // export var|const|let|function|class ... if (this.shouldParseExportStatement()) { node.declaration = this.parseExportDeclaration(node) - if (node.declaration.type === "VariableDeclaration") + if (node.declaration.type === 'VariableDeclaration') this.checkVariableExport(exports, node.declaration.declarations) else this.checkExport(exports, node.declaration.id, node.declaration.id.start) @@ -3257,7 +3279,7 @@ function tsPlugin(options?: { } else { // export { x, y as z } [from '...'] node.declaration = null node.specifiers = this.parseExportSpecifiers(exports) - if (this.eatContextual("from")) { + if (this.eatContextual('from')) { if (this.type !== tt.string) this.unexpected() node.source = this.parseExprAtom() @@ -3269,8 +3291,8 @@ function tsPlugin(options?: { // check if export is defined this.checkLocalExport(spec.local) - if (spec.local.type === "Literal") { - this.raise(spec.local.start, "A string literal cannot be used as an exported binding without `from`.") + if (spec.local.type === 'Literal') { + this.raise(spec.local.start, 'A string literal cannot be used as an exported binding without `from`.') } } @@ -3278,7 +3300,7 @@ function tsPlugin(options?: { } this.semicolon() } - return this.finishNode(node, "ExportNamedDeclaration") + return this.finishNode(node, 'ExportNamedDeclaration') // end } } @@ -4394,7 +4416,7 @@ function tsPlugin(options?: { } return super.toAssignable(node, isBinding, refDestructuringErrors) case 'TSTypeCastExpression': { - return this.typeCastToParameter(node); + return this.typeCastToParameter(node) } default: return super.toAssignable(node, isBinding, refDestructuringErrors) diff --git a/src/middleware.ts b/src/middleware.ts index 87ed69f..8933b32 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -262,6 +262,10 @@ export declare class AcornParseClass extends Parser { parseImportSpecifiers(): any + parseImportDefaultSpecifier(): any + + parseImportNamespaceSpecifier(): any + parseImportAttributes(): any parseMaybeImportAttributes(node: any): any