From 65bd2ad8190ef11f5454158c10ad101728323fe6 Mon Sep 17 00:00:00 2001 From: TyrealHu Date: Tue, 21 Feb 2023 23:31:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=9A=80add=20outer=20kind=20variab?= =?UTF-8?q?le=20to=20help=20parse=20import=20or=20export?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __test__/__snapshot__/export/type.ts | 170 +++++++++++++++++++++++++ __test__/__snapshot__/import/normal.ts | 113 ++++++++++++++++ __test__/export/type.test.ts | 11 ++ __test__/import/normal.test.ts | 8 ++ src/index.ts | 39 ++++-- 5 files changed, 327 insertions(+), 14 deletions(-) diff --git a/__test__/__snapshot__/export/type.ts b/__test__/__snapshot__/export/type.ts index 0952f52..b9b5b03 100644 --- a/__test__/__snapshot__/export/type.ts +++ b/__test__/__snapshot__/export/type.ts @@ -1484,6 +1484,176 @@ const ExportTypeSnapshot = { } ], 'sourceType': 'module' + }, + ExportTypeAsAsWithName: { + 'type': 'Program', + 'start': 0, + 'end': 50, + 'loc': { + 'start': { + 'line': 1, + 'column': 0, + 'index': 0 + }, + 'end': { + 'line': 4, + 'column': 1, + 'index': 50 + } + }, + 'body': [ + { + 'type': 'VariableDeclaration', + 'start': 0, + 'end': 17, + 'loc': { + 'start': { + 'line': 1, + 'column': 0, + 'index': 0 + }, + 'end': { + 'line': 1, + 'column': 17, + 'index': 17 + } + }, + 'declarations': [ + { + 'type': 'VariableDeclarator', + 'start': 6, + 'end': 17, + 'loc': { + 'start': { + 'line': 1, + 'column': 6, + 'index': 6 + }, + 'end': { + 'line': 1, + 'column': 17, + 'index': 17 + } + }, + 'id': { + 'type': 'Identifier', + 'start': 6, + 'end': 8, + 'loc': { + 'start': { + 'line': 1, + 'column': 6, + 'index': 6 + }, + 'end': { + 'line': 1, + 'column': 8, + 'index': 8 + } + }, + 'name': 'as' + }, + 'init': { + 'type': 'Literal', + 'start': 11, + 'end': 17, + 'loc': { + 'start': { + 'line': 1, + 'column': 11, + 'index': 11 + }, + 'end': { + 'line': 1, + 'column': 17, + 'index': 17 + } + }, + 'value': 'test', + 'raw': '\'test\'' + } + } + ], + 'kind': 'const' + }, + { + 'type': 'ExportNamedDeclaration', + 'start': 18, + 'end': 50, + 'loc': { + 'start': { + 'line': 2, + 'column': 0, + 'index': 18 + }, + 'end': { + 'line': 4, + 'column': 1, + 'index': 50 + } + }, + 'exportKind': 'value', + 'declaration': null, + 'specifiers': [ + { + 'type': 'ExportSpecifier', + 'start': 29, + 'end': 48, + 'loc': { + 'start': { + 'line': 3, + 'column': 2, + 'index': 29 + }, + 'end': { + 'line': 3, + 'column': 21, + 'index': 48 + } + }, + 'local': { + 'type': 'Identifier', + 'start': 34, + 'end': 36, + 'loc': { + 'start': { + 'line': 3, + 'column': 7, + 'index': 34 + }, + 'end': { + 'line': 3, + 'column': 9, + 'index': 36 + } + }, + 'name': 'as' + }, + 'exported': { + 'type': 'Identifier', + 'start': 40, + 'end': 48, + 'loc': { + 'start': { + 'line': 3, + 'column': 13, + 'index': 40 + }, + 'end': { + 'line': 3, + 'column': 21, + 'index': 48 + } + }, + 'name': 'someName' + }, + 'exportKind': 'type' + } + ], + 'source': null + } + ], + 'sourceType': 'module' } } diff --git a/__test__/__snapshot__/import/normal.ts b/__test__/__snapshot__/import/normal.ts index eb28142..db8f1de 100644 --- a/__test__/__snapshot__/import/normal.ts +++ b/__test__/__snapshot__/import/normal.ts @@ -1700,6 +1700,119 @@ const NormalImportSnapshot = { } ], 'sourceType': 'module' + }, + ImportTypeSpecifierWithAsAsSomethings: { + 'type': 'Program', + 'start': 0, + 'end': 50, + 'loc': { + 'start': { + 'line': 1, + 'column': 0, + 'index': 0 + }, + 'end': { + 'line': 1, + 'column': 50, + 'index': 50 + } + }, + 'body': [ + { + 'type': 'ImportDeclaration', + 'start': 0, + 'end': 50, + 'loc': { + 'start': { + 'line': 1, + 'column': 0, + 'index': 0 + }, + 'end': { + 'line': 1, + 'column': 50, + 'index': 50 + } + }, + 'importKind': 'value', + 'specifiers': [ + { + 'type': 'ImportSpecifier', + 'start': 9, + 'end': 30, + 'loc': { + 'start': { + 'line': 1, + 'column': 9, + 'index': 9 + }, + 'end': { + 'line': 1, + 'column': 30, + 'index': 30 + } + }, + 'imported': { + 'type': 'Identifier', + 'start': 14, + 'end': 16, + 'loc': { + 'start': { + 'line': 1, + 'column': 14, + 'index': 14 + }, + 'end': { + 'line': 1, + 'column': 16, + 'index': 16 + } + }, + 'name': 'as' + }, + 'local': { + 'type': 'Identifier', + 'start': 20, + 'end': 30, + 'loc': { + 'start': { + 'line': 1, + 'column': 20, + 'index': 20 + }, + 'end': { + 'line': 1, + 'column': 30, + 'index': 30 + } + }, + 'name': 'somethings' + }, + 'importKind': 'type' + } + ], + 'source': { + 'type': 'Literal', + 'start': 38, + 'end': 50, + 'loc': { + 'start': { + 'line': 1, + 'column': 38, + 'index': 38 + }, + 'end': { + 'line': 1, + 'column': 50, + 'index': 50 + } + }, + 'value': './index.js', + 'raw': '\'./index.js\'' + } + } + ], + 'sourceType': 'module' } } diff --git a/__test__/export/type.test.ts b/__test__/export/type.test.ts index 71e76ae..5258a24 100644 --- a/__test__/export/type.test.ts +++ b/__test__/export/type.test.ts @@ -74,4 +74,15 @@ describe('export type', () => { equalNode(node, ExportTypeSnapshot.ExportTypeTypeWithAsAs) }) + + it('export type as as with name', () => { + const node = parseSource(generateSource([ + `const as = 'test'`, + `export {`, + ` type as as someName`, + `}` + ])) + + equalNode(node, ExportTypeSnapshot.ExportTypeAsAsWithName) + }) }) diff --git a/__test__/import/normal.test.ts b/__test__/import/normal.test.ts index 633780e..0d3a4bb 100644 --- a/__test__/import/normal.test.ts +++ b/__test__/import/normal.test.ts @@ -83,4 +83,12 @@ describe('normal syntax', () => { equalNode(node, NormalImportSnapshot.ImportTypeSpecifierWithAsAs) }) + + it('import type specifier with as as', function() { + const node = parseSource(generateSource([ + `import { type as as somethings } from './index.js'`, + ])) + + equalNode(node, NormalImportSnapshot.ImportTypeSpecifierWithAsAsSomethings) + }) }) diff --git a/src/index.ts b/src/index.ts index e5e50af..fed1d12 100644 --- a/src/index.ts +++ b/src/index.ts @@ -233,6 +233,11 @@ export default function tsPlugin(options?: { inDisallowConditionalTypesContext: boolean = false maybeInArrowParameters: boolean = false canStartJSXElement: boolean = false + /** + * we will only parse one import node or export node at same time. + * default kind is undefined + * */ + importOrExportOuterKind: string | undefined = undefined constructor(options: Options, input: string, startPos?: number) { super(options, input, startPos) @@ -2717,7 +2722,7 @@ export default function tsPlugin(options?: { } tsParseImportEqualsDeclaration( - node, + node: any, isExport?: boolean ): Node { node.isExport = isExport || false @@ -2985,6 +2990,7 @@ export default function tsPlugin(options?: { ) { let enterHead = this.lookahead() node.importKind = 'value' + this.importOrExportOuterKind = 'value' if ( tokenIsIdentifier(enterHead.type) || this.match(tokTypes.star) || @@ -3000,6 +3006,7 @@ export default function tsPlugin(options?: { ahead.type !== tokTypes.eq && this.ts_eatContextualWithState('type', 1, enterHead) ) { + this.importOrExportOuterKind = 'type' node.importKind = 'type' enterHead = this.lookahead() ahead = this.lookahead(2) @@ -3007,12 +3014,15 @@ export default function tsPlugin(options?: { if (tokenIsIdentifier(enterHead.type) && ahead.type === tokTypes.eq) { this.next() - return this.tsParseImportEqualsDeclaration(node) + const importNode = this.tsParseImportEqualsDeclaration(node) + this.importOrExportOuterKind = 'value' + return importNode } } const importNode = super.parseImport(node) + this.importOrExportOuterKind = 'value' /*:: invariant(importNode.type !== "TSImportEqualsDeclaration") */ // `import type` can only be used on imports with named imports or with a @@ -3036,21 +3046,24 @@ export default function tsPlugin(options?: { this.lookaheadCharCode() !== charCodes.equalsTo ) { node.importKind = 'type' + this.importOrExportOuterKind = 'type' this.next() // eat "type" } else { node.importKind = 'value' + this.importOrExportOuterKind = 'value' } - return this.tsParseImportEqualsDeclaration( + const exportEqualsNode = this.tsParseImportEqualsDeclaration( node, /* isExport */ true ) + this.importOrExportOuterKind = undefined + return exportEqualsNode } else if (this.ts_eatWithState(tokTypes.eq, 2, enterHead)) { // `export = x;` const assign = node - assign.expression = this.parseExpression() - this.semicolon() + this.importOrExportOuterKind = undefined return this.finishNode(assign, 'TSExportAssignment') } else if (this.ts_eatContextualWithState('as', 2, enterHead)) { // `export as namespace A;` @@ -3059,6 +3072,7 @@ export default function tsPlugin(options?: { this.expectContextual('namespace') decl.id = this.parseIdent() this.semicolon() + this.importOrExportOuterKind = undefined return this.finishNode(decl, 'TSNamespaceExportDeclaration') } else { if ( @@ -3066,8 +3080,10 @@ export default function tsPlugin(options?: { this.lookahead(2).type === tokTypes.braceL ) { this.next() + this.importOrExportOuterKind = 'type' node.exportKind = 'type' } else { + this.importOrExportOuterKind = 'value' node.exportKind = 'value' } @@ -3132,8 +3148,7 @@ export default function tsPlugin(options?: { node.source = null } else { // export { x, y as z } [from '...'] node.declaration = null - const isTypeExport = node.exportKind === 'type' - node.specifiers = this.parseExportSpecifiers(exports, isTypeExport) + node.specifiers = this.parseExportSpecifiers(exports) if (this.eatContextual('from')) { if (this.type !== tokTypes.string) this.unexpected() node.source = this.parseExprAtom() @@ -5154,9 +5169,7 @@ export default function tsPlugin(options?: { super.expect(tokTypes.braceL) while (!this.eat(tokTypes.braceR)) { if (!first) { - this.expect(tokTypes.comma) - if (this.afterTrailingComma(tokTypes.braceR)) { break } @@ -5172,7 +5185,7 @@ export default function tsPlugin(options?: { this.parseTypeOnlyImportExportSpecifier( node, /* isImport */ true, - node.importKind === 'type' + this.importOrExportOuterKind === 'type' ) nodes.push(this.finishNode(node, 'ImportSpecifier')) @@ -5194,7 +5207,7 @@ export default function tsPlugin(options?: { return nodes } - parseExportSpecifiers(exports, isInTypeExport = false) { + parseExportSpecifiers(exports) { let nodes = [], first = true // export { x, y as z } [from '...'] this.expect(tokTypes.braceL) @@ -5220,7 +5233,7 @@ export default function tsPlugin(options?: { this.parseTypeOnlyImportExportSpecifier( node, /* isImport */ false, - isInTypeExport + this.importOrExportOuterKind === 'type' ) this.finishNode(node, 'ExportSpecifier') } else { @@ -5304,14 +5317,12 @@ export default function tsPlugin(options?: { // { type something ...? } hasTypeSpecifier = true if (isImport) { - leftOfAs = super.parseIdent(true) if (!this.ts_isContextual(tsTokenType.as)) { this.checkUnreserved(leftOfAs) } } else { - leftOfAs = this.parseModuleExportName() } }