Support TypeScript 4.5 type-only import/export specifiers (#13802)

This commit is contained in:
Sosuke Suzuki 2021-10-29 08:23:23 +09:00 committed by GitHub
parent 872086a9a0
commit d5ba355867
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
90 changed files with 1342 additions and 57 deletions

View File

@ -40,6 +40,11 @@ export function ExportDefaultSpecifier(
} }
export function ExportSpecifier(this: Printer, node: t.ExportSpecifier) { export function ExportSpecifier(this: Printer, node: t.ExportSpecifier) {
if (node.exportKind === "type") {
this.word("type");
this.space();
}
this.print(node.local, node); 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 // @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) { if (node.exported && node.local.name !== node.exported.name) {

View File

@ -0,0 +1 @@
export { type foo } from "foo";

View File

@ -0,0 +1 @@
export { type foo } from "foo";

View File

@ -0,0 +1 @@
import { type foo } from "foo";

View File

@ -0,0 +1 @@
import { type foo } from "foo";

View File

@ -1878,7 +1878,8 @@ export default class StatementParser extends ExpressionParser {
maybeParseExportNamedSpecifiers(node: N.Node): boolean { maybeParseExportNamedSpecifiers(node: N.Node): boolean {
if (this.match(tt.braceL)) { if (this.match(tt.braceL)) {
if (!node.specifiers) node.specifiers = []; if (!node.specifiers) node.specifiers = [];
node.specifiers.push(...this.parseExportSpecifiers()); const isTypeExport = node.exportKind === "type";
node.specifiers.push(...this.parseExportSpecifiers(isTypeExport));
node.source = null; node.source = null;
node.declaration = null; node.declaration = null;
@ -2158,7 +2159,7 @@ export default class StatementParser extends ExpressionParser {
// Parses a comma-separated list of module exports. // Parses a comma-separated list of module exports.
parseExportSpecifiers(): Array<N.ExportSpecifier> { parseExportSpecifiers(isInTypeExport: boolean): Array<N.ExportSpecifier> {
const nodes = []; const nodes = [];
let first = true; let first = true;
@ -2172,24 +2173,41 @@ export default class StatementParser extends ExpressionParser {
this.expect(tt.comma); this.expect(tt.comma);
if (this.eat(tt.braceR)) break; if (this.eat(tt.braceR)) break;
} }
const isMaybeTypeOnly = this.isContextual(tt._type);
const node = this.startNode();
const isString = this.match(tt.string); const isString = this.match(tt.string);
const local = this.parseModuleExportName(); const node = this.startNode();
node.local = local; node.local = this.parseModuleExportName();
if (this.eatContextual(tt._as)) { nodes.push(
node.exported = this.parseModuleExportName(); this.parseExportSpecifier(
} else if (isString) { node,
node.exported = cloneStringLiteral(local); isString,
} else { isInTypeExport,
node.exported = cloneIdentifier(local); isMaybeTypeOnly,
} ),
nodes.push(this.finishNode(node, "ExportSpecifier")); );
} }
return nodes; return nodes;
} }
parseExportSpecifier(
node: any,
isString: boolean,
/* eslint-disable no-unused-vars -- used in TypeScript parser */
isInTypeExport: boolean,
isMaybeTypeOnly: boolean,
/* eslint-enable no-unused-vars */
): N.ExportSpecifier {
if (this.eatContextual(tt._as)) {
node.exported = this.parseModuleExportName();
} else if (isString) {
node.exported = cloneStringLiteral(node.local);
} else if (!node.exported) {
node.exported = cloneIdentifier(node.local);
}
return this.finishNode<N.ExportSpecifier>(node, "ExportSpecifier");
}
// https://tc39.es/ecma262/#prod-ModuleExportName // https://tc39.es/ecma262/#prod-ModuleExportName
parseModuleExportName(): N.StringLiteral | N.Identifier { parseModuleExportName(): N.StringLiteral | N.Identifier {
if (this.match(tt.string)) { if (this.match(tt.string)) {
@ -2438,15 +2456,29 @@ export default class StatementParser extends ExpressionParser {
if (this.eat(tt.braceR)) break; if (this.eat(tt.braceR)) break;
} }
this.parseImportSpecifier(node); const specifier = this.startNode();
const importedIsString = this.match(tt.string);
const isMaybeTypeOnly = this.isContextual(tt._type);
specifier.imported = this.parseModuleExportName();
const importSpecifier = this.parseImportSpecifier(
specifier,
importedIsString,
node.importKind === "type" || node.importKind === "typeof",
isMaybeTypeOnly,
);
node.specifiers.push(importSpecifier);
} }
} }
// https://tc39.es/ecma262/#prod-ImportSpecifier // https://tc39.es/ecma262/#prod-ImportSpecifier
parseImportSpecifier(node: N.ImportDeclaration): void { parseImportSpecifier(
const specifier = this.startNode(); specifier: any,
const importedIsString = this.match(tt.string); importedIsString: boolean,
specifier.imported = this.parseModuleExportName(); /* eslint-disable no-unused-vars -- used in TypeScript and Flow parser */
isInTypeOnlyImport: boolean,
isMaybeTypeOnly: boolean,
/* eslint-enable no-unused-vars */
): N.ImportSpecifier {
if (this.eatContextual(tt._as)) { if (this.eatContextual(tt._as)) {
specifier.local = this.parseIdentifier(); specifier.local = this.parseIdentifier();
} else { } else {
@ -2459,10 +2491,12 @@ export default class StatementParser extends ExpressionParser {
); );
} }
this.checkReservedWord(imported.name, specifier.start, true, true); this.checkReservedWord(imported.name, specifier.start, true, true);
specifier.local = cloneIdentifier(imported); if (!specifier.local) {
specifier.local = cloneIdentifier(imported);
}
} }
this.checkLVal(specifier.local, "import specifier", BIND_LEXICAL); this.checkLVal(specifier.local, "import specifier", BIND_LEXICAL);
node.specifiers.push(this.finishNode(specifier, "ImportSpecifier")); return this.finishNode(specifier, "ImportSpecifier");
} }
// This is used in flow and typescript plugin // This is used in flow and typescript plugin

View File

@ -2123,7 +2123,9 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (this.match(tt.braceL)) { if (this.match(tt.braceL)) {
// export type { foo, bar }; // export type { foo, bar };
node.specifiers = this.parseExportSpecifiers(); node.specifiers = this.parseExportSpecifiers(
/* isInTypeExport */ true,
);
this.parseExportFrom(node); this.parseExportFrom(node);
return null; return null;
} else { } else {
@ -2629,10 +2631,14 @@ export default (superClass: Class<Parser>): Class<Parser> =>
} }
// parse import-type/typeof shorthand // parse import-type/typeof shorthand
parseImportSpecifier(node: N.ImportDeclaration): void { parseImportSpecifier(
const specifier = this.startNode(); specifier: any,
const firstIdentIsString = this.match(tt.string); importedIsString: boolean,
const firstIdent = this.parseModuleExportName(); isInTypeOnlyImport: boolean,
// eslint-disable-next-line no-unused-vars
isMaybeTypeOnly: boolean,
): N.ImportSpecifier {
const firstIdent = specifier.imported;
let specifierTypeKind = null; let specifierTypeKind = null;
if (firstIdent.type === "Identifier") { if (firstIdent.type === "Identifier") {
@ -2669,7 +2675,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
specifier.imported = this.parseIdentifier(true); specifier.imported = this.parseIdentifier(true);
specifier.importKind = specifierTypeKind; specifier.importKind = specifierTypeKind;
} else { } else {
if (firstIdentIsString) { if (importedIsString) {
/*:: invariant(firstIdent instanceof N.StringLiteral) */ /*:: invariant(firstIdent instanceof N.StringLiteral) */
throw this.raise( throw this.raise(
specifier.start, specifier.start,
@ -2690,17 +2696,16 @@ export default (superClass: Class<Parser>): Class<Parser> =>
} }
} }
const nodeIsTypeImport = hasTypeImportKind(node);
const specifierIsTypeImport = hasTypeImportKind(specifier); const specifierIsTypeImport = hasTypeImportKind(specifier);
if (nodeIsTypeImport && specifierIsTypeImport) { if (isInTypeOnlyImport && specifierIsTypeImport) {
this.raise( this.raise(
specifier.start, specifier.start,
FlowErrors.ImportTypeShorthandOnlyInPureImport, FlowErrors.ImportTypeShorthandOnlyInPureImport,
); );
} }
if (nodeIsTypeImport || specifierIsTypeImport) { if (isInTypeOnlyImport || specifierIsTypeImport) {
this.checkReservedType( this.checkReservedType(
specifier.local.name, specifier.local.name,
specifier.local.start, specifier.local.start,
@ -2708,7 +2713,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
); );
} }
if (isBinding && !nodeIsTypeImport && !specifierIsTypeImport) { if (isBinding && !isInTypeOnlyImport && !specifierIsTypeImport) {
this.checkReservedWord( this.checkReservedWord(
specifier.local.name, specifier.local.name,
specifier.start, specifier.start,
@ -2718,7 +2723,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
} }
this.checkLVal(specifier.local, "import specifier", BIND_LEXICAL); this.checkLVal(specifier.local, "import specifier", BIND_LEXICAL);
node.specifiers.push(this.finishNode(specifier, "ImportSpecifier")); return this.finishNode(specifier, "ImportSpecifier");
} }
parseBindingAtom(): N.Pattern { parseBindingAtom(): N.Pattern {

View File

@ -11,6 +11,7 @@ import {
tokenIsTSDeclarationStart, tokenIsTSDeclarationStart,
tokenIsTSTypeOperator, tokenIsTSTypeOperator,
tokenOperatorPrecedence, tokenOperatorPrecedence,
tokenIsKeywordOrIdentifier,
tt, tt,
type TokenType, type TokenType,
} from "../../tokenizer/types"; } from "../../tokenizer/types";
@ -41,6 +42,7 @@ import {
type ErrorTemplate, type ErrorTemplate,
ErrorCodes, ErrorCodes,
} from "../../parser/error"; } from "../../parser/error";
import { cloneIdentifier } from "../../parser/node";
type TsModifier = type TsModifier =
| "readonly" | "readonly"
@ -151,6 +153,10 @@ const TSErrors = makeErrorTemplates(
"Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`.", "Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`.",
TypeImportCannotSpecifyDefaultAndNamed: TypeImportCannotSpecifyDefaultAndNamed:
"A type-only import can specify a default import or named bindings, but not both.", "A type-only import can specify a default import or named bindings, but not both.",
TypeModifierIsUsedInTypeExports:
"The 'type' modifier cannot be used on a named export when 'export type' is used on its export statement.",
TypeModifierIsUsedInTypeImports:
"The 'type' modifier cannot be used on a named import when 'import type' is used on its import statement.",
UnexpectedParameterModifier: UnexpectedParameterModifier:
"A parameter property is only allowed in a constructor implementation.", "A parameter property is only allowed in a constructor implementation.",
UnexpectedReadonly: UnexpectedReadonly:
@ -3368,4 +3374,130 @@ export default (superClass: Class<Parser>): Class<Parser> =>
} }
return super.getExpression(); return super.getExpression();
} }
parseExportSpecifier(
node: any,
isString: boolean,
isInTypeExport: boolean,
isMaybeTypeOnly: boolean,
) {
if (!isString && isMaybeTypeOnly) {
this.parseTypeOnlyImportExportSpecifier(
node,
/* isImport */ false,
isInTypeExport,
);
return this.finishNode<N.ExportSpecifier>(node, "ExportSpecifier");
}
node.exportKind = "value";
return super.parseExportSpecifier(
node,
isString,
isInTypeExport,
isMaybeTypeOnly,
);
}
parseImportSpecifier(
specifier: any,
importedIsString: boolean,
isInTypeOnlyImport: boolean,
isMaybeTypeOnly: boolean,
): N.ImportSpecifier {
if (!importedIsString && isMaybeTypeOnly) {
this.parseTypeOnlyImportExportSpecifier(
specifier,
/* isImport */ true,
isInTypeOnlyImport,
);
return this.finishNode<N.ImportSpecifier>(specifier, "ImportSpecifier");
}
specifier.importKind = "value";
return super.parseImportSpecifier(
specifier,
importedIsString,
isInTypeOnlyImport,
isMaybeTypeOnly,
);
}
parseTypeOnlyImportExportSpecifier(
node: any,
isImport: boolean,
isInTypeOnlyImportExport: boolean,
): void {
const leftOfAsKey = isImport ? "imported" : "local";
const rightOfAsKey = isImport ? "local" : "exported";
let leftOfAs = node[leftOfAsKey];
let rightOfAs;
let hasTypeSpecifier = false;
let canParseAsKeyword = true;
const pos = leftOfAs.start;
// https://github.com/microsoft/TypeScript/blob/fc4f9d83d5939047aa6bb2a43965c6e9bbfbc35b/src/compiler/parser.ts#L7411-L7456
// import { type } from "mod"; - hasTypeSpecifier: false, leftOfAs: type
// import { type as } from "mod"; - hasTypeSpecifier: true, leftOfAs: as
// import { type as as } from "mod"; - hasTypeSpecifier: false, leftOfAs: type, rightOfAs: as
// import { type as as as } from "mod"; - hasTypeSpecifier: true, leftOfAs: as, rightOfAs: as
if (this.isContextual(tt._as)) {
// { type as ...? }
const firstAs = this.parseIdentifier();
if (this.isContextual(tt._as)) {
// { type as as ...? }
const secondAs = this.parseIdentifier();
if (tokenIsKeywordOrIdentifier(this.state.type)) {
// { type as as something }
hasTypeSpecifier = true;
leftOfAs = firstAs;
rightOfAs = this.parseIdentifier();
canParseAsKeyword = false;
} else {
// { type as as }
rightOfAs = secondAs;
canParseAsKeyword = false;
}
} else if (tokenIsKeywordOrIdentifier(this.state.type)) {
// { type as something }
canParseAsKeyword = false;
rightOfAs = this.parseIdentifier();
} else {
// { type as }
hasTypeSpecifier = true;
leftOfAs = firstAs;
}
} else if (tokenIsKeywordOrIdentifier(this.state.type)) {
// { type something ...? }
hasTypeSpecifier = true;
leftOfAs = this.parseIdentifier();
}
if (hasTypeSpecifier && isInTypeOnlyImportExport) {
this.raise(
pos,
isImport
? TSErrors.TypeModifierIsUsedInTypeImports
: TSErrors.TypeModifierIsUsedInTypeExports,
);
}
node[leftOfAsKey] = leftOfAs;
node[rightOfAsKey] = rightOfAs;
const kindKey = isImport ? "importKind" : "exportKind";
node[kindKey] = hasTypeSpecifier ? "type" : "value";
if (canParseAsKeyword && this.eatContextual(tt._as)) {
node[rightOfAsKey] = isImport
? this.parseIdentifier()
: this.parseModuleExportName();
}
if (!node[rightOfAsKey]) {
node[rightOfAsKey] = cloneIdentifier(node[leftOfAsKey]);
}
if (isImport) {
this.checkLVal(node[rightOfAsKey], "import specifier", BIND_LEXICAL);
}
}
}; };

View File

@ -903,6 +903,7 @@ export type ImportDeclaration = NodeBase & {
export type ImportSpecifier = ModuleSpecifier & { export type ImportSpecifier = ModuleSpecifier & {
type: "ImportSpecifier", type: "ImportSpecifier",
imported: Identifier | StringLiteral, imported: Identifier | StringLiteral,
importKind?: "type" | "value",
}; };
export type ImportDefaultSpecifier = ModuleSpecifier & { export type ImportDefaultSpecifier = ModuleSpecifier & {
@ -930,6 +931,7 @@ export type ExportSpecifier = NodeBase & {
type: "ExportSpecifier", type: "ExportSpecifier",
exported: Identifier | StringLiteral, exported: Identifier | StringLiteral,
local: Identifier, local: Identifier,
exportKind?: "type" | "value",
}; };
export type ExportDefaultSpecifier = NodeBase & { export type ExportDefaultSpecifier = NodeBase & {

View File

@ -20,6 +20,7 @@
"start":14,"end":15,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":15},"identifierName":"T"}, "start":14,"end":15,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":15},"identifierName":"T"},
"name": "T" "name": "T"
}, },
"exportKind": "value",
"exported": { "exported": {
"type": "Identifier", "type": "Identifier",
"start":14,"end":15,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":15},"identifierName":"T"}, "start":14,"end":15,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":15},"identifierName":"T"},

View File

@ -42,6 +42,7 @@
"start":26,"end":27,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":15},"identifierName":"A"}, "start":26,"end":27,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":15},"identifierName":"A"},
"name": "A" "name": "A"
}, },
"exportKind": "value",
"exported": { "exported": {
"type": "Identifier", "type": "Identifier",
"start":26,"end":27,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":15},"identifierName":"A"}, "start":26,"end":27,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":15},"identifierName":"A"},

View File

@ -20,6 +20,7 @@
"start":27,"end":28,"loc":{"start":{"line":1,"column":27},"end":{"line":1,"column":28},"identifierName":"A"}, "start":27,"end":28,"loc":{"start":{"line":1,"column":27},"end":{"line":1,"column":28},"identifierName":"A"},
"name": "A" "name": "A"
}, },
"exportKind": "value",
"exported": { "exported": {
"type": "Identifier", "type": "Identifier",
"start":27,"end":28,"loc":{"start":{"line":1,"column":27},"end":{"line":1,"column":28},"identifierName":"A"}, "start":27,"end":28,"loc":{"start":{"line":1,"column":27},"end":{"line":1,"column":28},"identifierName":"A"},
@ -55,6 +56,7 @@
} }
] ]
}, },
"exportKind": "value",
"exported": { "exported": {
"type": "Identifier", "type": "Identifier",
"start":59,"end":60,"loc":{"start":{"line":1,"column":59},"end":{"line":1,"column":60},"identifierName":"C"}, "start":59,"end":60,"loc":{"start":{"line":1,"column":59},"end":{"line":1,"column":60},"identifierName":"C"},

View File

@ -44,6 +44,7 @@
"start":34,"end":35,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":10},"identifierName":"a"}, "start":34,"end":35,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":10},"identifierName":"a"},
"name": "a" "name": "a"
}, },
"exportKind": "value",
"exported": { "exported": {
"type": "Identifier", "type": "Identifier",
"start":34,"end":35,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":10},"identifierName":"a"}, "start":34,"end":35,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":10},"identifierName":"a"},

View File

@ -29,6 +29,7 @@
"start":15,"end":18,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":18},"identifierName":"bar"}, "start":15,"end":18,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":18},"identifierName":"bar"},
"name": "bar" "name": "bar"
}, },
"importKind": "value",
"local": { "local": {
"type": "Identifier", "type": "Identifier",
"start":15,"end":18,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":18},"identifierName":"bar"}, "start":15,"end":18,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":18},"identifierName":"bar"},

View File

@ -20,6 +20,7 @@
"start":9,"end":12,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":12},"identifierName":"foo"}, "start":9,"end":12,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":12},"identifierName":"foo"},
"name": "foo" "name": "foo"
}, },
"importKind": "value",
"local": { "local": {
"type": "Identifier", "type": "Identifier",
"start":9,"end":12,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":12},"identifierName":"foo"}, "start":9,"end":12,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":12},"identifierName":"foo"},

View File

@ -43,6 +43,7 @@
"start":42,"end":43,"loc":{"start":{"line":1,"column":42},"end":{"line":1,"column":43},"identifierName":"A"}, "start":42,"end":43,"loc":{"start":{"line":1,"column":42},"end":{"line":1,"column":43},"identifierName":"A"},
"name": "A" "name": "A"
}, },
"importKind": "value",
"local": { "local": {
"type": "Identifier", "type": "Identifier",
"start":42,"end":43,"loc":{"start":{"line":1,"column":42},"end":{"line":1,"column":43},"identifierName":"A"}, "start":42,"end":43,"loc":{"start":{"line":1,"column":42},"end":{"line":1,"column":43},"identifierName":"A"},
@ -78,6 +79,7 @@
} }
] ]
}, },
"importKind": "value",
"local": { "local": {
"type": "Identifier", "type": "Identifier",
"start":74,"end":75,"loc":{"start":{"line":1,"column":74},"end":{"line":1,"column":75},"identifierName":"C"}, "start":74,"end":75,"loc":{"start":{"line":1,"column":74},"end":{"line":1,"column":75},"identifierName":"C"},

View File

@ -41,6 +41,7 @@
"start":40,"end":43,"loc":{"start":{"line":3,"column":9},"end":{"line":3,"column":12},"identifierName":"foo"}, "start":40,"end":43,"loc":{"start":{"line":3,"column":9},"end":{"line":3,"column":12},"identifierName":"foo"},
"name": "foo" "name": "foo"
}, },
"exportKind": "value",
"exported": { "exported": {
"type": "Identifier", "type": "Identifier",
"start":40,"end":43,"loc":{"start":{"line":3,"column":9},"end":{"line":3,"column":12},"identifierName":"foo"}, "start":40,"end":43,"loc":{"start":{"line":3,"column":9},"end":{"line":3,"column":12},"identifierName":"foo"},

View File

@ -20,6 +20,7 @@
"start":9,"end":12,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":12},"identifierName":"foo"}, "start":9,"end":12,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":12},"identifierName":"foo"},
"name": "foo" "name": "foo"
}, },
"exportKind": "value",
"exported": { "exported": {
"type": "Identifier", "type": "Identifier",
"start":9,"end":12,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":12},"identifierName":"foo"}, "start":9,"end":12,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":12},"identifierName":"foo"},

View File

@ -37,6 +37,7 @@
"start":70,"end":74,"loc":{"start":{"line":5,"column":9},"end":{"line":5,"column":13},"identifierName":"Test"}, "start":70,"end":74,"loc":{"start":{"line":5,"column":9},"end":{"line":5,"column":13},"identifierName":"Test"},
"name": "Test" "name": "Test"
}, },
"exportKind": "value",
"exported": { "exported": {
"type": "Identifier", "type": "Identifier",
"start":78,"end":85,"loc":{"start":{"line":5,"column":17},"end":{"line":5,"column":24},"identifierName":"default"}, "start":78,"end":85,"loc":{"start":{"line":5,"column":17},"end":{"line":5,"column":24},"identifierName":"default"},

View File

@ -20,6 +20,7 @@
"start":9,"end":13,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":13},"identifierName":"Test"}, "start":9,"end":13,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":13},"identifierName":"Test"},
"name": "Test" "name": "Test"
}, },
"exportKind": "value",
"exported": { "exported": {
"type": "Identifier", "type": "Identifier",
"start":17,"end":24,"loc":{"start":{"line":1,"column":17},"end":{"line":1,"column":24},"identifierName":"default"}, "start":17,"end":24,"loc":{"start":{"line":1,"column":17},"end":{"line":1,"column":24},"identifierName":"default"},

View File

@ -34,6 +34,7 @@
"start":24,"end":25,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":10},"identifierName":"A"}, "start":24,"end":25,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":10},"identifierName":"A"},
"name": "A" "name": "A"
}, },
"exportKind": "value",
"exported": { "exported": {
"type": "Identifier", "type": "Identifier",
"start":24,"end":25,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":10},"identifierName":"A"}, "start":24,"end":25,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":10},"identifierName":"A"},

View File

@ -20,6 +20,7 @@
"start":9,"end":10,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":10},"identifierName":"A"}, "start":9,"end":10,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":10},"identifierName":"A"},
"name": "A" "name": "A"
}, },
"exportKind": "value",
"exported": { "exported": {
"type": "Identifier", "type": "Identifier",
"start":9,"end":10,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":10},"identifierName":"A"}, "start":9,"end":10,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":10},"identifierName":"A"},

View File

@ -34,6 +34,7 @@
"start":25,"end":26,"loc":{"start":{"line":3,"column":9},"end":{"line":3,"column":10},"identifierName":"N"}, "start":25,"end":26,"loc":{"start":{"line":3,"column":9},"end":{"line":3,"column":10},"identifierName":"N"},
"name": "N" "name": "N"
}, },
"exportKind": "value",
"exported": { "exported": {
"type": "Identifier", "type": "Identifier",
"start":25,"end":26,"loc":{"start":{"line":3,"column":9},"end":{"line":3,"column":10},"identifierName":"N"}, "start":25,"end":26,"loc":{"start":{"line":3,"column":9},"end":{"line":3,"column":10},"identifierName":"N"},

View File

@ -33,6 +33,7 @@
"start":26,"end":27,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":10},"identifierName":"A"}, "start":26,"end":27,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":10},"identifierName":"A"},
"name": "A" "name": "A"
}, },
"exportKind": "value",
"exported": { "exported": {
"type": "Identifier", "type": "Identifier",
"start":26,"end":27,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":10},"identifierName":"A"}, "start":26,"end":27,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":10},"identifierName":"A"},

View File

@ -20,6 +20,7 @@
"start":9,"end":10,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":10},"identifierName":"A"}, "start":9,"end":10,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":10},"identifierName":"A"},
"name": "A" "name": "A"
}, },
"exportKind": "value",
"exported": { "exported": {
"type": "Identifier", "type": "Identifier",
"start":9,"end":10,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":10},"identifierName":"A"}, "start":9,"end":10,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":10},"identifierName":"A"},

View File

@ -58,6 +58,7 @@
"start":46,"end":47,"loc":{"start":{"line":4,"column":9},"end":{"line":4,"column":10},"identifierName":"f"}, "start":46,"end":47,"loc":{"start":{"line":4,"column":9},"end":{"line":4,"column":10},"identifierName":"f"},
"name": "f" "name": "f"
}, },
"exportKind": "value",
"exported": { "exported": {
"type": "Identifier", "type": "Identifier",
"start":46,"end":47,"loc":{"start":{"line":4,"column":9},"end":{"line":4,"column":10},"identifierName":"f"}, "start":46,"end":47,"loc":{"start":{"line":4,"column":9},"end":{"line":4,"column":10},"identifierName":"f"},

View File

@ -0,0 +1 @@
export { type A, type B, type C } from "foo";

View File

@ -0,0 +1,75 @@
{
"type": "File",
"start":0,"end":45,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":45}},
"program": {
"type": "Program",
"start":0,"end":45,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":45}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ExportNamedDeclaration",
"start":0,"end":45,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":45}},
"exportKind": "value",
"specifiers": [
{
"type": "ExportSpecifier",
"start":9,"end":15,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":15}},
"local": {
"type": "Identifier",
"start":14,"end":15,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":15},"identifierName":"A"},
"name": "A"
},
"exportKind": "type",
"exported": {
"type": "Identifier",
"start":14,"end":15,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":15},"identifierName":"A"},
"name": "A"
}
},
{
"type": "ExportSpecifier",
"start":17,"end":23,"loc":{"start":{"line":1,"column":17},"end":{"line":1,"column":23}},
"local": {
"type": "Identifier",
"start":22,"end":23,"loc":{"start":{"line":1,"column":22},"end":{"line":1,"column":23},"identifierName":"B"},
"name": "B"
},
"exportKind": "type",
"exported": {
"type": "Identifier",
"start":22,"end":23,"loc":{"start":{"line":1,"column":22},"end":{"line":1,"column":23},"identifierName":"B"},
"name": "B"
}
},
{
"type": "ExportSpecifier",
"start":25,"end":31,"loc":{"start":{"line":1,"column":25},"end":{"line":1,"column":31}},
"local": {
"type": "Identifier",
"start":30,"end":31,"loc":{"start":{"line":1,"column":30},"end":{"line":1,"column":31},"identifierName":"C"},
"name": "C"
},
"exportKind": "type",
"exported": {
"type": "Identifier",
"start":30,"end":31,"loc":{"start":{"line":1,"column":30},"end":{"line":1,"column":31},"identifierName":"C"},
"name": "C"
}
}
],
"source": {
"type": "StringLiteral",
"start":39,"end":44,"loc":{"start":{"line":1,"column":39},"end":{"line":1,"column":44}},
"extra": {
"rawValue": "foo",
"raw": "\"foo\""
},
"value": "foo"
},
"declaration": null
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
export type { type foo } from "foo";

View File

@ -0,0 +1,48 @@
{
"type": "File",
"start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}},
"errors": [
"SyntaxError: The 'type' modifier cannot be used on a named export when 'export type' is used on its export statement. (1:14)"
],
"program": {
"type": "Program",
"start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ExportNamedDeclaration",
"start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}},
"exportKind": "type",
"specifiers": [
{
"type": "ExportSpecifier",
"start":14,"end":22,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":22}},
"local": {
"type": "Identifier",
"start":19,"end":22,"loc":{"start":{"line":1,"column":19},"end":{"line":1,"column":22},"identifierName":"foo"},
"name": "foo"
},
"exported": {
"type": "Identifier",
"start":19,"end":22,"loc":{"start":{"line":1,"column":19},"end":{"line":1,"column":22},"identifierName":"foo"},
"name": "foo"
},
"exportKind": "type"
}
],
"source": {
"type": "StringLiteral",
"start":30,"end":35,"loc":{"start":{"line":1,"column":30},"end":{"line":1,"column":35}},
"extra": {
"rawValue": "foo",
"raw": "\"foo\""
},
"value": "foo"
},
"declaration": null
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
export { Component, type ComponentProps } from "./exports.js";

View File

@ -0,0 +1,60 @@
{
"type": "File",
"start":0,"end":62,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":62}},
"program": {
"type": "Program",
"start":0,"end":62,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":62}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ExportNamedDeclaration",
"start":0,"end":62,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":62}},
"exportKind": "value",
"specifiers": [
{
"type": "ExportSpecifier",
"start":9,"end":18,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":18}},
"local": {
"type": "Identifier",
"start":9,"end":18,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":18},"identifierName":"Component"},
"name": "Component"
},
"exported": {
"type": "Identifier",
"start":9,"end":18,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":18},"identifierName":"Component"},
"name": "Component"
},
"exportKind": "value"
},
{
"type": "ExportSpecifier",
"start":20,"end":39,"loc":{"start":{"line":1,"column":20},"end":{"line":1,"column":39}},
"local": {
"type": "Identifier",
"start":25,"end":39,"loc":{"start":{"line":1,"column":25},"end":{"line":1,"column":39},"identifierName":"ComponentProps"},
"name": "ComponentProps"
},
"exported": {
"type": "Identifier",
"start":25,"end":39,"loc":{"start":{"line":1,"column":25},"end":{"line":1,"column":39},"identifierName":"ComponentProps"},
"name": "ComponentProps"
},
"exportKind": "type"
}
],
"source": {
"type": "StringLiteral",
"start":47,"end":61,"loc":{"start":{"line":1,"column":47},"end":{"line":1,"column":61}},
"extra": {
"rawValue": "./exports.js",
"raw": "\"./exports.js\""
},
"value": "./exports.js"
},
"declaration": null
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
export { type as as } from "./mod.js";

View File

@ -0,0 +1,45 @@
{
"type": "File",
"start":0,"end":38,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":38}},
"program": {
"type": "Program",
"start":0,"end":38,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":38}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ExportNamedDeclaration",
"start":0,"end":38,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":38}},
"exportKind": "value",
"specifiers": [
{
"type": "ExportSpecifier",
"start":9,"end":19,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":19}},
"local": {
"type": "Identifier",
"start":9,"end":13,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":13},"identifierName":"type"},
"name": "type"
},
"exported": {
"type": "Identifier",
"start":17,"end":19,"loc":{"start":{"line":1,"column":17},"end":{"line":1,"column":19},"identifierName":"as"},
"name": "as"
},
"exportKind": "value"
}
],
"source": {
"type": "StringLiteral",
"start":27,"end":37,"loc":{"start":{"line":1,"column":27},"end":{"line":1,"column":37}},
"extra": {
"rawValue": "./mod.js",
"raw": "\"./mod.js\""
},
"value": "./mod.js"
},
"declaration": null
}
],
"directives": []
}
}

View File

@ -0,0 +1,2 @@
const type = {};
export { type as if };

View File

@ -0,0 +1,58 @@
{
"type": "File",
"start":0,"end":39,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":22}},
"program": {
"type": "Program",
"start":0,"end":39,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":22}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "VariableDeclaration",
"start":0,"end":16,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":16}},
"declarations": [
{
"type": "VariableDeclarator",
"start":6,"end":15,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":15}},
"id": {
"type": "Identifier",
"start":6,"end":10,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":10},"identifierName":"type"},
"name": "type"
},
"init": {
"type": "ObjectExpression",
"start":13,"end":15,"loc":{"start":{"line":1,"column":13},"end":{"line":1,"column":15}},
"properties": []
}
}
],
"kind": "const"
},
{
"type": "ExportNamedDeclaration",
"start":17,"end":39,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":22}},
"exportKind": "value",
"specifiers": [
{
"type": "ExportSpecifier",
"start":26,"end":36,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":19}},
"local": {
"type": "Identifier",
"start":26,"end":30,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":13},"identifierName":"type"},
"name": "type"
},
"exported": {
"type": "Identifier",
"start":34,"end":36,"loc":{"start":{"line":2,"column":17},"end":{"line":2,"column":19},"identifierName":"if"},
"name": "if"
},
"exportKind": "value"
}
],
"source": null,
"declaration": null
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
export { type } from "./mod.js";

View File

@ -0,0 +1,45 @@
{
"type": "File",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":32}},
"program": {
"type": "Program",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":32}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ExportNamedDeclaration",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":32}},
"exportKind": "value",
"specifiers": [
{
"type": "ExportSpecifier",
"start":9,"end":13,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":13}},
"local": {
"type": "Identifier",
"start":9,"end":13,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":13},"identifierName":"type"},
"name": "type"
},
"exportKind": "value",
"exported": {
"type": "Identifier",
"start":9,"end":13,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":13},"identifierName":"type"},
"name": "type"
}
}
],
"source": {
"type": "StringLiteral",
"start":21,"end":31,"loc":{"start":{"line":1,"column":21},"end":{"line":1,"column":31}},
"extra": {
"rawValue": "./mod.js",
"raw": "\"./mod.js\""
},
"value": "./mod.js"
},
"declaration": null
}
],
"directives": []
}
}

View File

@ -0,0 +1,2 @@
const as = {};
export { type as as if };

View File

@ -0,0 +1,58 @@
{
"type": "File",
"start":0,"end":40,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":25}},
"program": {
"type": "Program",
"start":0,"end":40,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":25}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "VariableDeclaration",
"start":0,"end":14,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":14}},
"declarations": [
{
"type": "VariableDeclarator",
"start":6,"end":13,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":13}},
"id": {
"type": "Identifier",
"start":6,"end":8,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":8},"identifierName":"as"},
"name": "as"
},
"init": {
"type": "ObjectExpression",
"start":11,"end":13,"loc":{"start":{"line":1,"column":11},"end":{"line":1,"column":13}},
"properties": []
}
}
],
"kind": "const"
},
{
"type": "ExportNamedDeclaration",
"start":15,"end":40,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":25}},
"exportKind": "value",
"specifiers": [
{
"type": "ExportSpecifier",
"start":24,"end":37,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":22}},
"local": {
"type": "Identifier",
"start":29,"end":31,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":16},"identifierName":"as"},
"name": "as"
},
"exported": {
"type": "Identifier",
"start":35,"end":37,"loc":{"start":{"line":2,"column":20},"end":{"line":2,"column":22},"identifierName":"if"},
"name": "if"
},
"exportKind": "type"
}
],
"source": null,
"declaration": null
}
],
"directives": []
}
}

View File

@ -0,0 +1,2 @@
const if = {};
export { type if };

View File

@ -0,0 +1,58 @@
{
"type": "File",
"start":0,"end":34,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":19}},
"program": {
"type": "Program",
"start":0,"end":34,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":19}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "VariableDeclaration",
"start":0,"end":14,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":14}},
"declarations": [
{
"type": "VariableDeclarator",
"start":6,"end":13,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":13}},
"id": {
"type": "Identifier",
"start":6,"end":8,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":8},"identifierName":"if"},
"name": "if"
},
"init": {
"type": "ObjectExpression",
"start":11,"end":13,"loc":{"start":{"line":1,"column":11},"end":{"line":1,"column":13}},
"properties": []
}
}
],
"kind": "const"
},
{
"type": "ExportNamedDeclaration",
"start":15,"end":34,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":19}},
"exportKind": "value",
"specifiers": [
{
"type": "ExportSpecifier",
"start":24,"end":31,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":16}},
"local": {
"type": "Identifier",
"start":29,"end":31,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":16},"identifierName":"if"},
"name": "if"
},
"exported": {
"type": "Identifier",
"start":29,"end":31,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":16},"identifierName":"if"},
"name": "if"
},
"exportKind": "type"
}
],
"source": null,
"declaration": null
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
export { type as } from "./mod.js";

View File

@ -0,0 +1,45 @@
{
"type": "File",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}},
"program": {
"type": "Program",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ExportNamedDeclaration",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}},
"exportKind": "value",
"specifiers": [
{
"type": "ExportSpecifier",
"start":9,"end":16,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":16}},
"local": {
"type": "Identifier",
"start":14,"end":16,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":16},"identifierName":"as"},
"name": "as"
},
"exportKind": "type",
"exported": {
"type": "Identifier",
"start":14,"end":16,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":16},"identifierName":"as"},
"name": "as"
}
}
],
"source": {
"type": "StringLiteral",
"start":24,"end":34,"loc":{"start":{"line":1,"column":24},"end":{"line":1,"column":34}},
"extra": {
"rawValue": "./mod.js",
"raw": "\"./mod.js\""
},
"value": "./mod.js"
},
"declaration": null
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
export { typ\u0065 as } from "x";

View File

@ -0,0 +1,7 @@
{
"sourceType": "module",
"plugins": [
"typescript"
],
"throws": "Unexpected token (1:22)"
}

View File

@ -0,0 +1 @@
import { type A, type B, type C } from "foo";

View File

@ -0,0 +1,74 @@
{
"type": "File",
"start":0,"end":45,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":45}},
"program": {
"type": "Program",
"start":0,"end":45,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":45}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ImportDeclaration",
"start":0,"end":45,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":45}},
"importKind": "value",
"specifiers": [
{
"type": "ImportSpecifier",
"start":9,"end":15,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":15}},
"imported": {
"type": "Identifier",
"start":14,"end":15,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":15},"identifierName":"A"},
"name": "A"
},
"importKind": "type",
"local": {
"type": "Identifier",
"start":14,"end":15,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":15},"identifierName":"A"},
"name": "A"
}
},
{
"type": "ImportSpecifier",
"start":17,"end":23,"loc":{"start":{"line":1,"column":17},"end":{"line":1,"column":23}},
"imported": {
"type": "Identifier",
"start":22,"end":23,"loc":{"start":{"line":1,"column":22},"end":{"line":1,"column":23},"identifierName":"B"},
"name": "B"
},
"importKind": "type",
"local": {
"type": "Identifier",
"start":22,"end":23,"loc":{"start":{"line":1,"column":22},"end":{"line":1,"column":23},"identifierName":"B"},
"name": "B"
}
},
{
"type": "ImportSpecifier",
"start":25,"end":31,"loc":{"start":{"line":1,"column":25},"end":{"line":1,"column":31}},
"imported": {
"type": "Identifier",
"start":30,"end":31,"loc":{"start":{"line":1,"column":30},"end":{"line":1,"column":31},"identifierName":"C"},
"name": "C"
},
"importKind": "type",
"local": {
"type": "Identifier",
"start":30,"end":31,"loc":{"start":{"line":1,"column":30},"end":{"line":1,"column":31},"identifierName":"C"},
"name": "C"
}
}
],
"source": {
"type": "StringLiteral",
"start":39,"end":44,"loc":{"start":{"line":1,"column":39},"end":{"line":1,"column":44}},
"extra": {
"rawValue": "foo",
"raw": "\"foo\""
},
"value": "foo"
}
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
import { typ\u0065 as } from "x";

View File

@ -0,0 +1,7 @@
{
"sourceType": "module",
"plugins": [
"typescript"
],
"throws": "Unexpected token (1:22)"
}

View File

@ -0,0 +1,44 @@
{
"type": "File",
"start":0,"end":33,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":33}},
"program": {
"type": "Program",
"start":0,"end":33,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":33}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ImportDeclaration",
"start":0,"end":33,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":33}},
"importKind": "value",
"specifiers": [
{
"type": "ImportSpecifier",
"start":9,"end":19,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":19}},
"imported": {
"type": "Identifier",
"start":9,"end":13,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":13},"identifierName":"type"},
"name": "type"
},
"local": {
"type": "Identifier",
"start":17,"end":19,"loc":{"start":{"line":1,"column":17},"end":{"line":1,"column":19},"identifierName":"if"},
"name": "if"
},
"importKind": "value"
}
],
"source": {
"type": "StringLiteral",
"start":27,"end":32,"loc":{"start":{"line":1,"column":27},"end":{"line":1,"column":32}},
"extra": {
"rawValue": "mod",
"raw": "\"mod\""
},
"value": "mod"
}
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
import type { type foo } from "foo";

View File

@ -0,0 +1,47 @@
{
"type": "File",
"start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}},
"errors": [
"SyntaxError: The 'type' modifier cannot be used on a named import when 'import type' is used on its import statement. (1:14)"
],
"program": {
"type": "Program",
"start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ImportDeclaration",
"start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}},
"importKind": "type",
"specifiers": [
{
"type": "ImportSpecifier",
"start":14,"end":22,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":22}},
"imported": {
"type": "Identifier",
"start":19,"end":22,"loc":{"start":{"line":1,"column":19},"end":{"line":1,"column":22},"identifierName":"foo"},
"name": "foo"
},
"local": {
"type": "Identifier",
"start":19,"end":22,"loc":{"start":{"line":1,"column":19},"end":{"line":1,"column":22},"identifierName":"foo"},
"name": "foo"
},
"importKind": "type"
}
],
"source": {
"type": "StringLiteral",
"start":30,"end":35,"loc":{"start":{"line":1,"column":30},"end":{"line":1,"column":35}},
"extra": {
"rawValue": "foo",
"raw": "\"foo\""
},
"value": "foo"
}
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
import { type as as if } from "mod";

View File

@ -0,0 +1,44 @@
{
"type": "File",
"start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}},
"program": {
"type": "Program",
"start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ImportDeclaration",
"start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}},
"importKind": "value",
"specifiers": [
{
"type": "ImportSpecifier",
"start":9,"end":22,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":22}},
"imported": {
"type": "Identifier",
"start":14,"end":16,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":16},"identifierName":"as"},
"name": "as"
},
"local": {
"type": "Identifier",
"start":20,"end":22,"loc":{"start":{"line":1,"column":20},"end":{"line":1,"column":22},"identifierName":"if"},
"name": "if"
},
"importKind": "type"
}
],
"source": {
"type": "StringLiteral",
"start":30,"end":35,"loc":{"start":{"line":1,"column":30},"end":{"line":1,"column":35}},
"extra": {
"rawValue": "mod",
"raw": "\"mod\""
},
"value": "mod"
}
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
import { type foo as "bar" } from "mod";

View File

@ -0,0 +1,7 @@
{
"sourceType": "module",
"plugins": [
"typescript"
],
"throws": "Unexpected token (1:21)"
}

View File

@ -0,0 +1 @@
import { Component, type ComponentProps } from "./exports.js";

View File

@ -0,0 +1,59 @@
{
"type": "File",
"start":0,"end":62,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":62}},
"program": {
"type": "Program",
"start":0,"end":62,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":62}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ImportDeclaration",
"start":0,"end":62,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":62}},
"importKind": "value",
"specifiers": [
{
"type": "ImportSpecifier",
"start":9,"end":18,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":18}},
"imported": {
"type": "Identifier",
"start":9,"end":18,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":18},"identifierName":"Component"},
"name": "Component"
},
"local": {
"type": "Identifier",
"start":9,"end":18,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":18},"identifierName":"Component"},
"name": "Component"
},
"importKind": "value"
},
{
"type": "ImportSpecifier",
"start":20,"end":39,"loc":{"start":{"line":1,"column":20},"end":{"line":1,"column":39}},
"imported": {
"type": "Identifier",
"start":25,"end":39,"loc":{"start":{"line":1,"column":25},"end":{"line":1,"column":39},"identifierName":"ComponentProps"},
"name": "ComponentProps"
},
"local": {
"type": "Identifier",
"start":25,"end":39,"loc":{"start":{"line":1,"column":25},"end":{"line":1,"column":39},"identifierName":"ComponentProps"},
"name": "ComponentProps"
},
"importKind": "type"
}
],
"source": {
"type": "StringLiteral",
"start":47,"end":61,"loc":{"start":{"line":1,"column":47},"end":{"line":1,"column":61}},
"extra": {
"rawValue": "./exports.js",
"raw": "\"./exports.js\""
},
"value": "./exports.js"
}
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
import { type as as } from "./mod.js";

View File

@ -0,0 +1,44 @@
{
"type": "File",
"start":0,"end":38,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":38}},
"program": {
"type": "Program",
"start":0,"end":38,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":38}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ImportDeclaration",
"start":0,"end":38,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":38}},
"importKind": "value",
"specifiers": [
{
"type": "ImportSpecifier",
"start":9,"end":19,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":19}},
"imported": {
"type": "Identifier",
"start":9,"end":13,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":13},"identifierName":"type"},
"name": "type"
},
"local": {
"type": "Identifier",
"start":17,"end":19,"loc":{"start":{"line":1,"column":17},"end":{"line":1,"column":19},"identifierName":"as"},
"name": "as"
},
"importKind": "value"
}
],
"source": {
"type": "StringLiteral",
"start":27,"end":37,"loc":{"start":{"line":1,"column":27},"end":{"line":1,"column":37}},
"extra": {
"rawValue": "./mod.js",
"raw": "\"./mod.js\""
},
"value": "./mod.js"
}
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
import { type } from "./mod.js";

View File

@ -0,0 +1,44 @@
{
"type": "File",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":32}},
"program": {
"type": "Program",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":32}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ImportDeclaration",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":32}},
"importKind": "value",
"specifiers": [
{
"type": "ImportSpecifier",
"start":9,"end":13,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":13}},
"imported": {
"type": "Identifier",
"start":9,"end":13,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":13},"identifierName":"type"},
"name": "type"
},
"importKind": "value",
"local": {
"type": "Identifier",
"start":9,"end":13,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":13},"identifierName":"type"},
"name": "type"
}
}
],
"source": {
"type": "StringLiteral",
"start":21,"end":31,"loc":{"start":{"line":1,"column":21},"end":{"line":1,"column":31}},
"extra": {
"rawValue": "./mod.js",
"raw": "\"./mod.js\""
},
"value": "./mod.js"
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,2 @@
import { type Foo1 } from "mod";
export { Foo1 };

View File

@ -0,0 +1,68 @@
{
"type": "File",
"start":0,"end":49,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":16}},
"program": {
"type": "Program",
"start":0,"end":49,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":16}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ImportDeclaration",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":32}},
"importKind": "value",
"specifiers": [
{
"type": "ImportSpecifier",
"start":9,"end":18,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":18}},
"imported": {
"type": "Identifier",
"start":14,"end":18,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":18},"identifierName":"Foo1"},
"name": "Foo1"
},
"local": {
"type": "Identifier",
"start":14,"end":18,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":18},"identifierName":"Foo1"},
"name": "Foo1"
},
"importKind": "type"
}
],
"source": {
"type": "StringLiteral",
"start":26,"end":31,"loc":{"start":{"line":1,"column":26},"end":{"line":1,"column":31}},
"extra": {
"rawValue": "mod",
"raw": "\"mod\""
},
"value": "mod"
}
},
{
"type": "ExportNamedDeclaration",
"start":33,"end":49,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":16}},
"exportKind": "value",
"specifiers": [
{
"type": "ExportSpecifier",
"start":42,"end":46,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":13}},
"local": {
"type": "Identifier",
"start":42,"end":46,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":13},"identifierName":"Foo1"},
"name": "Foo1"
},
"exportKind": "value",
"exported": {
"type": "Identifier",
"start":42,"end":46,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":13},"identifierName":"Foo1"},
"name": "Foo1"
}
}
],
"source": null,
"declaration": null
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
import { type as } from "./mod.js";

View File

@ -0,0 +1,44 @@
{
"type": "File",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}},
"program": {
"type": "Program",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ImportDeclaration",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}},
"importKind": "value",
"specifiers": [
{
"type": "ImportSpecifier",
"start":9,"end":16,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":16}},
"imported": {
"type": "Identifier",
"start":14,"end":16,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":16},"identifierName":"as"},
"name": "as"
},
"importKind": "type",
"local": {
"type": "Identifier",
"start":14,"end":16,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":16},"identifierName":"as"},
"name": "as"
}
}
],
"source": {
"type": "StringLiteral",
"start":24,"end":34,"loc":{"start":{"line":1,"column":24},"end":{"line":1,"column":34}},
"extra": {
"rawValue": "./mod.js",
"raw": "\"./mod.js\""
},
"value": "./mod.js"
}
}
],
"directives": []
}
}

View File

@ -32,6 +32,7 @@
"start":26,"end":29,"loc":{"start":{"line":1,"column":26},"end":{"line":1,"column":29},"identifierName":"Bar"}, "start":26,"end":29,"loc":{"start":{"line":1,"column":26},"end":{"line":1,"column":29},"identifierName":"Bar"},
"name": "Bar" "name": "Bar"
}, },
"importKind": "value",
"local": { "local": {
"type": "Identifier", "type": "Identifier",
"start":26,"end":29,"loc":{"start":{"line":1,"column":26},"end":{"line":1,"column":29},"identifierName":"Bar"}, "start":26,"end":29,"loc":{"start":{"line":1,"column":26},"end":{"line":1,"column":29},"identifierName":"Bar"},
@ -46,6 +47,7 @@
"start":31,"end":34,"loc":{"start":{"line":1,"column":31},"end":{"line":1,"column":34},"identifierName":"Baz"}, "start":31,"end":34,"loc":{"start":{"line":1,"column":31},"end":{"line":1,"column":34},"identifierName":"Baz"},
"name": "Baz" "name": "Baz"
}, },
"importKind": "value",
"local": { "local": {
"type": "Identifier", "type": "Identifier",
"start":31,"end":34,"loc":{"start":{"line":1,"column":31},"end":{"line":1,"column":34},"identifierName":"Baz"}, "start":31,"end":34,"loc":{"start":{"line":1,"column":31},"end":{"line":1,"column":34},"identifierName":"Baz"},

View File

@ -45,6 +45,7 @@
"start":42,"end":43,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":15},"identifierName":"A"}, "start":42,"end":43,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":15},"identifierName":"A"},
"name": "A" "name": "A"
}, },
"importKind": "value",
"local": { "local": {
"type": "Identifier", "type": "Identifier",
"start":42,"end":43,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":15},"identifierName":"A"}, "start":42,"end":43,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":15},"identifierName":"A"},
@ -59,6 +60,7 @@
"start":45,"end":46,"loc":{"start":{"line":2,"column":17},"end":{"line":2,"column":18},"identifierName":"B"}, "start":45,"end":46,"loc":{"start":{"line":2,"column":17},"end":{"line":2,"column":18},"identifierName":"B"},
"name": "B" "name": "B"
}, },
"importKind": "value",
"local": { "local": {
"type": "Identifier", "type": "Identifier",
"start":45,"end":46,"loc":{"start":{"line":2,"column":17},"end":{"line":2,"column":18},"identifierName":"B"}, "start":45,"end":46,"loc":{"start":{"line":2,"column":17},"end":{"line":2,"column":18},"identifierName":"B"},

View File

@ -265,6 +265,25 @@ export default declare((api: ConfigAPI, opts: Options): Plugin => {
continue; continue;
} }
const importsToRemove: Set<NodePath<t.Node>> = new Set();
const specifiersLength = stmt.node.specifiers.length;
const isAllSpecifiersElided = () =>
specifiersLength > 0 &&
specifiersLength === importsToRemove.size;
for (const specifier of stmt.node.specifiers) {
if (
specifier.type === "ImportSpecifier" &&
specifier.importKind === "type"
) {
registerGlobalType(programNode, specifier.local.name);
const binding = stmt.scope.getBinding(specifier.local.name);
if (binding) {
importsToRemove.add(binding.path);
}
}
}
// If onlyRemoveTypeImports is `true`, only remove type-only imports // If onlyRemoveTypeImports is `true`, only remove type-only imports
// and exports introduced in TypeScript 3.8. // and exports introduced in TypeScript 3.8.
if (onlyRemoveTypeImports) { if (onlyRemoveTypeImports) {
@ -277,9 +296,6 @@ export default declare((api: ConfigAPI, opts: Options): Plugin => {
continue; continue;
} }
let allElided = true;
const importsToRemove: NodePath<t.Node>[] = [];
for (const specifier of stmt.node.specifiers) { for (const specifier of stmt.node.specifiers) {
const binding = stmt.scope.getBinding(specifier.local.name); const binding = stmt.scope.getBinding(specifier.local.name);
@ -289,28 +305,29 @@ export default declare((api: ConfigAPI, opts: Options): Plugin => {
// just bail if there is no binding, since chances are good that if // just bail if there is no binding, since chances are good that if
// the import statement was injected then it wasn't a typescript type // the import statement was injected then it wasn't a typescript type
// import anyway. // import anyway.
if ( if (!importsToRemove.has(binding.path)) {
binding && if (
isImportTypeOnly({ binding &&
binding, isImportTypeOnly({
programPath: path, binding,
pragmaImportName, programPath: path,
pragmaFragImportName, pragmaImportName,
}) pragmaFragImportName,
) { })
importsToRemove.push(binding.path); ) {
} else { importsToRemove.add(binding.path);
allElided = false; } else {
NEEDS_EXPLICIT_ESM.set(path.node, false); NEEDS_EXPLICIT_ESM.set(path.node, false);
}
} }
} }
}
if (allElided) { if (isAllSpecifiersElided()) {
stmt.remove(); stmt.remove();
} else { } else {
for (const importPath of importsToRemove) { for (const importPath of importsToRemove) {
importPath.remove(); importPath.remove();
}
} }
} }
@ -365,6 +382,21 @@ export default declare((api: ConfigAPI, opts: Options): Plugin => {
return; return;
} }
// remove export declaration that is filled with type-only specifiers
// export { type A1, type A2 } from "a";
if (
path.node.source &&
path.node.specifiers.length > 0 &&
path.node.specifiers.every(
specifier =>
specifier.type === "ExportSpecifier" &&
specifier.exportKind === "type",
)
) {
path.remove();
return;
}
// remove export declaration if it's exporting only types // remove export declaration if it's exporting only types
// This logic is needed when exportKind is "value", because // This logic is needed when exportKind is "value", because
// currently the "type" keyword is optional. // currently the "type" keyword is optional.
@ -392,7 +424,10 @@ export default declare((api: ConfigAPI, opts: Options): Plugin => {
// remove type exports // remove type exports
type Parent = t.ExportDeclaration & { source?: t.StringLiteral }; type Parent = t.ExportDeclaration & { source?: t.StringLiteral };
const parent = path.parent as Parent; const parent = path.parent as Parent;
if (!parent.source && isGlobalType(path, path.node.local.name)) { if (
(!parent.source && isGlobalType(path, path.node.local.name)) ||
path.node.exportKind === "type"
) {
path.remove(); path.remove();
} }
}, },

View File

@ -0,0 +1,2 @@
class Foo {}
export { type Foo };

View File

@ -0,0 +1,3 @@
class Foo {}
export {};

View File

@ -0,0 +1 @@
export { type A1, type A2 } from "a"

View File

@ -0,0 +1 @@
export { type A1, type A2, A3 } from "a"

View File

@ -0,0 +1 @@
export { A3 } from "a";

View File

@ -10,4 +10,6 @@ import "g";
import type H from "h"; import type H from "h";
import type { I, I2 } from "i"; import type { I, I2 } from "i";
import type * as J from "j"; import type * as J from "j";
import { type K1, type K2 } from "k";
import { type L1, L2, type L3 } from "l";
; ;

View File

@ -5,4 +5,5 @@ import d, { d2 } from "d";
import e, { e3 as e4 } from "e"; import e, { e3 as e4 } from "e";
import "f"; import "f";
import "g"; import "g";
import { L2 } from "l";
; ;

View File

@ -0,0 +1,2 @@
import { Foo1, type Foo2 } from "Foo";
Foo1;

View File

@ -0,0 +1,2 @@
import { Foo1 } from "Foo";
Foo1;

View File

@ -0,0 +1 @@
import { type Foo1, type Foo2 } from "Foo";

View File

@ -0,0 +1,2 @@
import { type Foo1, type Foo2 } from "Foo";
export { Foo1, Foo2 };

View File

@ -0,0 +1 @@
import { type A } from "x";

View File

@ -0,0 +1,10 @@
{
"plugins": [
[
"transform-typescript",
{
"onlyRemoveTypeImports": true
}
]
]
}

View File

@ -812,6 +812,7 @@ export interface ExportSpecifier extends BaseNode {
type: "ExportSpecifier"; type: "ExportSpecifier";
local: Identifier; local: Identifier;
exported: Identifier | StringLiteral; exported: Identifier | StringLiteral;
exportKind?: "type" | "value" | null;
} }
export interface ForOfStatement extends BaseNode { export interface ForOfStatement extends BaseNode {
@ -846,7 +847,7 @@ export interface ImportSpecifier extends BaseNode {
type: "ImportSpecifier"; type: "ImportSpecifier";
local: Identifier; local: Identifier;
imported: Identifier | StringLiteral; imported: Identifier | StringLiteral;
importKind?: "type" | "typeof" | null; importKind?: "type" | "typeof" | "value" | null;
} }
export interface MetaProperty extends BaseNode { export interface MetaProperty extends BaseNode {

View File

@ -1549,6 +1549,11 @@ defineType("ExportSpecifier", {
exported: { exported: {
validate: assertNodeType("Identifier", "StringLiteral"), validate: assertNodeType("Identifier", "StringLiteral"),
}, },
exportKind: {
// And TypeScript's "export { type foo } from"
validate: assertOneOf("type", "value"),
optional: true,
},
}, },
}); });
@ -1666,7 +1671,8 @@ defineType("ImportSpecifier", {
}, },
importKind: { importKind: {
// Handle Flowtype's extension "import {typeof foo} from" // Handle Flowtype's extension "import {typeof foo} from"
validate: assertOneOf("type", "typeof"), // And TypeScript's "import { type foo } from"
validate: assertOneOf("type", "typeof", "value"),
optional: true, optional: true,
}, },
}, },