Skip to content

Commit 28ff6b6

Browse files
author
Andy
authored
Store import nodes in SourceFile.imports instead of StringLiteral nodes (microsoft#22495)
* Store import nodes in SourceFile.imports instead of StringLiteral nodes * Change SourceFile#imports storage back * Code review * StringLiteral -> StringLiteralLike
1 parent adf3635 commit 28ff6b6

15 files changed

+143
-158
lines changed

src/compiler/binder.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2497,7 +2497,7 @@ namespace ts {
24972497
function bindCallExpression(node: CallExpression) {
24982498
// We're only inspecting call expressions to detect CommonJS modules, so we can skip
24992499
// this check if we've already seen the module indicator
2500-
if (!file.commonJsModuleIndicator && isRequireCall(node, /*checkArgumentIsStringLiteral*/ false)) {
2500+
if (!file.commonJsModuleIndicator && isRequireCall(node, /*checkArgumentIsStringLiteralLike*/ false)) {
25012501
setCommonJsModuleIndicator(node);
25022502
}
25032503
}

src/compiler/checker.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -18229,7 +18229,7 @@ namespace ts {
1822918229
}
1823018230

1823118231
function isCommonJsRequire(node: Node): boolean {
18232-
if (!isRequireCall(node, /*checkArgumentIsStringLiteral*/ true)) {
18232+
if (!isRequireCall(node, /*checkArgumentIsStringLiteralLike*/ true)) {
1823318233
return false;
1823418234
}
1823518235

@@ -19689,7 +19689,7 @@ namespace ts {
1968919689
function getTypeOfExpression(node: Expression, cache?: boolean) {
1969019690
// Optimize for the common case of a call to a function with a single non-generic call
1969119691
// signature where we can just fetch the return type without checking the arguments.
19692-
if (node.kind === SyntaxKind.CallExpression && (<CallExpression>node).expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(node, /*checkArgumentIsStringLiteral*/ true) && !isSymbolOrSymbolForCall(node)) {
19692+
if (node.kind === SyntaxKind.CallExpression && (<CallExpression>node).expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(node, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(node)) {
1969319693
const funcType = checkNonNullExpression((<CallExpression>node).expression);
1969419694
const signature = getSingleCallSignature(funcType);
1969519695
if (signature && !signature.typeParameters) {
@@ -25039,7 +25039,7 @@ namespace ts {
2503925039
// 3). Dynamic import call or require in javascript
2504025040
if ((isExternalModuleImportEqualsDeclaration(node.parent.parent) && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node) ||
2504125041
((node.parent.kind === SyntaxKind.ImportDeclaration || node.parent.kind === SyntaxKind.ExportDeclaration) && (<ImportDeclaration>node.parent).moduleSpecifier === node) ||
25042-
((isInJavaScriptFile(node) && isRequireCall(node.parent, /*checkArgumentIsStringLiteral*/ false)) || isImportCall(node.parent))) {
25042+
((isInJavaScriptFile(node) && isRequireCall(node.parent, /*checkArgumentIsStringLiteralLike*/ false)) || isImportCall(node.parent))) {
2504325043
return resolveExternalModuleName(node, <LiteralExpression>node);
2504425044
}
2504525045
// falls through
@@ -25879,8 +25879,8 @@ namespace ts {
2587925879
}
2588025880
}
2588125881

25882-
function getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration): SourceFile {
25883-
const specifier = getExternalModuleName(declaration);
25882+
function getExternalModuleFileFromDeclaration(declaration: AnyImportOrReExport | ModuleDeclaration): SourceFile {
25883+
const specifier = declaration.kind === SyntaxKind.ModuleDeclaration ? tryCast(declaration.name, isStringLiteral) : getExternalModuleName(declaration);
2588425884
const moduleSymbol = resolveExternalModuleNameWorker(specifier, specifier, /*moduleNotFoundError*/ undefined);
2588525885
if (!moduleSymbol) {
2588625886
return undefined;

src/compiler/factory.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1984,7 +1984,7 @@ namespace ts {
19841984
decorators: ReadonlyArray<Decorator> | undefined,
19851985
modifiers: ReadonlyArray<Modifier> | undefined,
19861986
importClause: ImportClause | undefined,
1987-
moduleSpecifier?: Expression): ImportDeclaration {
1987+
moduleSpecifier: Expression): ImportDeclaration {
19881988
const node = <ImportDeclaration>createSynthesizedNode(SyntaxKind.ImportDeclaration);
19891989
node.decorators = asNodeArray(decorators);
19901990
node.modifiers = asNodeArray(modifiers);

src/compiler/program.ts

+44-55
Original file line numberDiff line numberDiff line change
@@ -1574,10 +1574,10 @@ namespace ts {
15741574
return a.fileName === b.fileName;
15751575
}
15761576

1577-
function moduleNameIsEqualTo(a: StringLiteral | Identifier, b: StringLiteral | Identifier): boolean {
1578-
return a.kind === SyntaxKind.StringLiteral
1579-
? b.kind === SyntaxKind.StringLiteral && a.text === b.text
1580-
: b.kind === SyntaxKind.Identifier && a.escapedText === b.escapedText;
1577+
function moduleNameIsEqualTo(a: StringLiteralLike | Identifier, b: StringLiteralLike | Identifier): boolean {
1578+
return a.kind === SyntaxKind.Identifier
1579+
? b.kind === SyntaxKind.Identifier && a.escapedText === b.escapedText
1580+
: b.kind === SyntaxKind.StringLiteral && a.text === b.text;
15811581
}
15821582

15831583
function collectExternalModuleReferences(file: SourceFile): void {
@@ -1589,7 +1589,7 @@ namespace ts {
15891589
const isExternalModuleFile = isExternalModule(file);
15901590

15911591
// file.imports may not be undefined if there exists dynamic import
1592-
let imports: StringLiteral[];
1592+
let imports: StringLiteralLike[] | undefined;
15931593
let moduleAugmentations: (StringLiteral | Identifier)[];
15941594
let ambientModules: string[];
15951595

@@ -1600,7 +1600,7 @@ namespace ts {
16001600
&& !file.isDeclarationFile) {
16011601
// synthesize 'import "tslib"' declaration
16021602
const externalHelpersModuleReference = createLiteral(externalHelpersModuleNameText);
1603-
const importDecl = createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*importClause*/ undefined);
1603+
const importDecl = createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*importClause*/ undefined, externalHelpersModuleReference);
16041604
addEmitFlags(importDecl, EmitFlags.NeverApplyImportHelper);
16051605
externalHelpersModuleReference.parent = importDecl;
16061606
importDecl.parent = file;
@@ -1621,66 +1621,55 @@ namespace ts {
16211621
return;
16221622

16231623
function collectModuleReferences(node: Statement, inAmbientModule: boolean): void {
1624-
switch (node.kind) {
1625-
case SyntaxKind.ImportDeclaration:
1626-
case SyntaxKind.ImportEqualsDeclaration:
1627-
case SyntaxKind.ExportDeclaration:
1628-
const moduleNameExpr = getExternalModuleName(node);
1629-
if (!moduleNameExpr || !isStringLiteral(moduleNameExpr)) {
1630-
break;
1631-
}
1632-
if (!moduleNameExpr.text) {
1633-
break;
1634-
}
1635-
1636-
// TypeScript 1.0 spec (April 2014): 12.1.6
1637-
// An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference other external modules
1638-
// only through top - level external module names. Relative external module names are not permitted.
1639-
if (!inAmbientModule || !isExternalModuleNameRelative(moduleNameExpr.text)) {
1640-
(imports || (imports = [])).push(moduleNameExpr);
1624+
if (isAnyImportOrReExport(node)) {
1625+
const moduleNameExpr = getExternalModuleName(node);
1626+
// TypeScript 1.0 spec (April 2014): 12.1.6
1627+
// An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference other external modules
1628+
// only through top - level external module names. Relative external module names are not permitted.
1629+
if (moduleNameExpr && isStringLiteral(moduleNameExpr) && moduleNameExpr.text && (!inAmbientModule || !isExternalModuleNameRelative(moduleNameExpr.text))) {
1630+
imports = append(imports, moduleNameExpr);
1631+
}
1632+
}
1633+
else if (isModuleDeclaration(node)) {
1634+
if (isAmbientModule(node) && (inAmbientModule || hasModifier(node, ModifierFlags.Ambient) || file.isDeclarationFile)) {
1635+
const nameText = getTextOfIdentifierOrLiteral(node.name);
1636+
// Ambient module declarations can be interpreted as augmentations for some existing external modules.
1637+
// This will happen in two cases:
1638+
// - if current file is external module then module augmentation is a ambient module declaration defined in the top level scope
1639+
// - if current file is not external module then module augmentation is an ambient module declaration with non-relative module name
1640+
// immediately nested in top level ambient module declaration .
1641+
if (isExternalModuleFile || (inAmbientModule && !isExternalModuleNameRelative(nameText))) {
1642+
(moduleAugmentations || (moduleAugmentations = [])).push(node.name);
16411643
}
1642-
break;
1643-
case SyntaxKind.ModuleDeclaration:
1644-
if (isAmbientModule(<ModuleDeclaration>node) && (inAmbientModule || hasModifier(node, ModifierFlags.Ambient) || file.isDeclarationFile)) {
1645-
const moduleName = (<ModuleDeclaration>node).name;
1646-
const nameText = getTextOfIdentifierOrLiteral(moduleName);
1647-
// Ambient module declarations can be interpreted as augmentations for some existing external modules.
1648-
// This will happen in two cases:
1649-
// - if current file is external module then module augmentation is a ambient module declaration defined in the top level scope
1650-
// - if current file is not external module then module augmentation is an ambient module declaration with non-relative module name
1651-
// immediately nested in top level ambient module declaration .
1652-
if (isExternalModuleFile || (inAmbientModule && !isExternalModuleNameRelative(nameText))) {
1653-
(moduleAugmentations || (moduleAugmentations = [])).push(moduleName);
1644+
else if (!inAmbientModule) {
1645+
if (file.isDeclarationFile) {
1646+
// for global .d.ts files record name of ambient module
1647+
(ambientModules || (ambientModules = [])).push(nameText);
16541648
}
1655-
else if (!inAmbientModule) {
1656-
if (file.isDeclarationFile) {
1657-
// for global .d.ts files record name of ambient module
1658-
(ambientModules || (ambientModules = [])).push(nameText);
1659-
}
1660-
// An AmbientExternalModuleDeclaration declares an external module.
1661-
// This type of declaration is permitted only in the global module.
1662-
// The StringLiteral must specify a top - level external module name.
1663-
// Relative external module names are not permitted
1664-
1665-
// NOTE: body of ambient module is always a module block, if it exists
1666-
const body = <ModuleBlock>(<ModuleDeclaration>node).body;
1667-
if (body) {
1668-
for (const statement of body.statements) {
1669-
collectModuleReferences(statement, /*inAmbientModule*/ true);
1670-
}
1649+
// An AmbientExternalModuleDeclaration declares an external module.
1650+
// This type of declaration is permitted only in the global module.
1651+
// The StringLiteral must specify a top - level external module name.
1652+
// Relative external module names are not permitted
1653+
1654+
// NOTE: body of ambient module is always a module block, if it exists
1655+
const body = <ModuleBlock>(<ModuleDeclaration>node).body;
1656+
if (body) {
1657+
for (const statement of body.statements) {
1658+
collectModuleReferences(statement, /*inAmbientModule*/ true);
16711659
}
16721660
}
16731661
}
1662+
}
16741663
}
16751664
}
16761665

16771666
function collectDynamicImportOrRequireCalls(node: Node): void {
1678-
if (isRequireCall(node, /*checkArgumentIsStringLiteral*/ true)) {
1679-
(imports || (imports = [])).push(<StringLiteral>(<CallExpression>node).arguments[0]);
1667+
if (isRequireCall(node, /*checkArgumentIsStringLiteralLike*/ true)) {
1668+
imports = append(imports, node.arguments[0]);
16801669
}
16811670
// we have to check the argument list has length of 1. We will still have to process these even though we have parsing error.
1682-
else if (isImportCall(node) && node.arguments.length === 1 && node.arguments[0].kind === SyntaxKind.StringLiteral) {
1683-
(imports || (imports = [])).push(<StringLiteral>(<CallExpression>node).arguments[0]);
1671+
else if (isImportCall(node) && node.arguments.length === 1 && isStringLiteralLike(node.arguments[0])) {
1672+
imports = append(imports, node.arguments[0] as StringLiteralLike);
16841673
}
16851674
else {
16861675
forEachChild(node, collectDynamicImportOrRequireCalls);

src/compiler/types.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -2568,7 +2568,7 @@ namespace ts {
25682568
// Content of this field should never be used directly - use getResolvedModuleFileName/setResolvedModuleFileName functions instead
25692569
/* @internal */ resolvedModules: Map<ResolvedModuleFull | undefined>;
25702570
/* @internal */ resolvedTypeReferenceDirectiveNames: Map<ResolvedTypeReferenceDirective>;
2571-
/* @internal */ imports: ReadonlyArray<StringLiteral>;
2571+
/* @internal */ imports: ReadonlyArray<StringLiteralLike>;
25722572
// Identifier only if `declare global`
25732573
/* @internal */ moduleAugmentations: ReadonlyArray<StringLiteral | Identifier>;
25742574
/* @internal */ patternAmbientModules?: PatternAmbientModule[];
@@ -3159,6 +3159,18 @@ namespace ts {
31593159
/* @internal */
31603160
export type AnyImportSyntax = ImportDeclaration | ImportEqualsDeclaration;
31613161

3162+
/* @internal */
3163+
export type AnyImportOrReExport = AnyImportSyntax | ExportDeclaration;
3164+
3165+
/* @internal */
3166+
export type AnyValidImportOrReExport =
3167+
| (ImportDeclaration | ExportDeclaration) & { moduleSpecifier: StringLiteral }
3168+
| ImportEqualsDeclaration & { moduleReference: ExternalModuleReference & { expression: StringLiteral } }
3169+
| RequireOrImportCall;
3170+
3171+
/* @internal */
3172+
export type RequireOrImportCall = CallExpression & { arguments: [StringLiteralLike] };
3173+
31623174
/* @internal */
31633175
export interface SymbolVisibilityResult {
31643176
accessibility: SymbolAccessibility;

src/compiler/utilities.ts

+31-19
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,10 @@ namespace ts {
538538
}
539539
}
540540

541+
export function isAnyImportOrReExport(node: Node): node is AnyImportOrReExport {
542+
return isAnyImportSyntax(node) || isExportDeclaration(node);
543+
}
544+
541545
// Gets the nearest enclosing block scope container that has the provided node
542546
// as a descendant, that is not the provided node.
543547
export function getEnclosingBlockScopeContainer(node: Node): Node {
@@ -1452,9 +1456,9 @@ namespace ts {
14521456
* exactly one argument (of the form 'require("name")').
14531457
* This function does not test if the node is in a JavaScript file or not.
14541458
*/
1455-
export function isRequireCall(callExpression: Node, checkArgumentIsStringLiteral: true): callExpression is CallExpression & { expression: Identifier, arguments: [StringLiteralLike] };
1456-
export function isRequireCall(callExpression: Node, checkArgumentIsStringLiteral: boolean): callExpression is CallExpression;
1457-
export function isRequireCall(callExpression: Node, checkArgumentIsStringLiteral: boolean): callExpression is CallExpression {
1459+
export function isRequireCall(callExpression: Node, checkArgumentIsStringLiteralLike: true): callExpression is RequireOrImportCall & { expression: Identifier, arguments: [StringLiteralLike] };
1460+
export function isRequireCall(callExpression: Node, checkArgumentIsStringLiteralLike: boolean): callExpression is CallExpression;
1461+
export function isRequireCall(callExpression: Node, checkArgumentIsStringLiteralLike: boolean): callExpression is CallExpression {
14581462
if (callExpression.kind !== SyntaxKind.CallExpression) {
14591463
return false;
14601464
}
@@ -1468,14 +1472,14 @@ namespace ts {
14681472
return false;
14691473
}
14701474
const arg = args[0];
1471-
return !checkArgumentIsStringLiteral || arg.kind === SyntaxKind.StringLiteral || arg.kind === SyntaxKind.NoSubstitutionTemplateLiteral;
1475+
return !checkArgumentIsStringLiteralLike || isStringLiteralLike(arg);
14721476
}
14731477

14741478
export function isSingleOrDoubleQuote(charCode: number) {
14751479
return charCode === CharacterCodes.singleQuote || charCode === CharacterCodes.doubleQuote;
14761480
}
14771481

1478-
export function isStringDoubleQuoted(str: StringLiteral, sourceFile: SourceFile): boolean {
1482+
export function isStringDoubleQuoted(str: StringLiteralLike, sourceFile: SourceFile): boolean {
14791483
return getSourceTextOfNodeFromSourceFile(sourceFile, str).charCodeAt(0) === CharacterCodes.doubleQuote;
14801484
}
14811485

@@ -1658,21 +1662,29 @@ namespace ts {
16581662
!!getJSDocTypeTag(expr.parent);
16591663
}
16601664

1661-
export function getExternalModuleName(node: Node): Expression {
1662-
if (node.kind === SyntaxKind.ImportDeclaration) {
1663-
return (<ImportDeclaration>node).moduleSpecifier;
1664-
}
1665-
if (node.kind === SyntaxKind.ImportEqualsDeclaration) {
1666-
const reference = (<ImportEqualsDeclaration>node).moduleReference;
1667-
if (reference.kind === SyntaxKind.ExternalModuleReference) {
1668-
return reference.expression;
1669-
}
1670-
}
1671-
if (node.kind === SyntaxKind.ExportDeclaration) {
1672-
return (<ExportDeclaration>node).moduleSpecifier;
1665+
export function importFromModuleSpecifier(node: StringLiteralLike): AnyValidImportOrReExport {
1666+
switch (node.parent.kind) {
1667+
case SyntaxKind.ImportDeclaration:
1668+
case SyntaxKind.ExportDeclaration:
1669+
return node.parent as AnyValidImportOrReExport;
1670+
case SyntaxKind.ExternalModuleReference:
1671+
return (node.parent as ExternalModuleReference).parent as AnyValidImportOrReExport;
1672+
case SyntaxKind.CallExpression:
1673+
return node.parent as AnyValidImportOrReExport;
1674+
default:
1675+
return Debug.fail(Debug.showSyntaxKind(node));
16731676
}
1674-
if (isModuleWithStringLiteralName(node)) {
1675-
return node.name;
1677+
}
1678+
1679+
export function getExternalModuleName(node: AnyImportOrReExport): Expression {
1680+
switch (node.kind) {
1681+
case SyntaxKind.ImportDeclaration:
1682+
case SyntaxKind.ExportDeclaration:
1683+
return node.moduleSpecifier;
1684+
case SyntaxKind.ImportEqualsDeclaration:
1685+
return node.moduleReference.kind === SyntaxKind.ExternalModuleReference ? node.moduleReference.expression : undefined;
1686+
default:
1687+
return Debug.assertNever(node);
16761688
}
16771689
}
16781690

0 commit comments

Comments
 (0)