Store import nodes in SourceFile.imports instead of StringLiteral nodes (#22495)

* Store import nodes in SourceFile.imports instead of StringLiteral nodes

* Change SourceFile#imports storage back

* Code review

* StringLiteral -> StringLiteralLike
This commit is contained in:
Andy 2018-03-16 14:01:00 -07:00 committed by GitHub
parent adf3635a1f
commit 28ff6b6ef3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 142 additions and 157 deletions

View File

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

View File

@ -18229,7 +18229,7 @@ namespace ts {
}
function isCommonJsRequire(node: Node): boolean {
if (!isRequireCall(node, /*checkArgumentIsStringLiteral*/ true)) {
if (!isRequireCall(node, /*checkArgumentIsStringLiteralLike*/ true)) {
return false;
}
@ -19689,7 +19689,7 @@ namespace ts {
function getTypeOfExpression(node: Expression, cache?: boolean) {
// Optimize for the common case of a call to a function with a single non-generic call
// signature where we can just fetch the return type without checking the arguments.
if (node.kind === SyntaxKind.CallExpression && (<CallExpression>node).expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(node, /*checkArgumentIsStringLiteral*/ true) && !isSymbolOrSymbolForCall(node)) {
if (node.kind === SyntaxKind.CallExpression && (<CallExpression>node).expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(node, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(node)) {
const funcType = checkNonNullExpression((<CallExpression>node).expression);
const signature = getSingleCallSignature(funcType);
if (signature && !signature.typeParameters) {
@ -25039,7 +25039,7 @@ namespace ts {
// 3). Dynamic import call or require in javascript
if ((isExternalModuleImportEqualsDeclaration(node.parent.parent) && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node) ||
((node.parent.kind === SyntaxKind.ImportDeclaration || node.parent.kind === SyntaxKind.ExportDeclaration) && (<ImportDeclaration>node.parent).moduleSpecifier === node) ||
((isInJavaScriptFile(node) && isRequireCall(node.parent, /*checkArgumentIsStringLiteral*/ false)) || isImportCall(node.parent))) {
((isInJavaScriptFile(node) && isRequireCall(node.parent, /*checkArgumentIsStringLiteralLike*/ false)) || isImportCall(node.parent))) {
return resolveExternalModuleName(node, <LiteralExpression>node);
}
// falls through
@ -25879,8 +25879,8 @@ namespace ts {
}
}
function getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration): SourceFile {
const specifier = getExternalModuleName(declaration);
function getExternalModuleFileFromDeclaration(declaration: AnyImportOrReExport | ModuleDeclaration): SourceFile {
const specifier = declaration.kind === SyntaxKind.ModuleDeclaration ? tryCast(declaration.name, isStringLiteral) : getExternalModuleName(declaration);
const moduleSymbol = resolveExternalModuleNameWorker(specifier, specifier, /*moduleNotFoundError*/ undefined);
if (!moduleSymbol) {
return undefined;

View File

@ -1984,7 +1984,7 @@ namespace ts {
decorators: ReadonlyArray<Decorator> | undefined,
modifiers: ReadonlyArray<Modifier> | undefined,
importClause: ImportClause | undefined,
moduleSpecifier?: Expression): ImportDeclaration {
moduleSpecifier: Expression): ImportDeclaration {
const node = <ImportDeclaration>createSynthesizedNode(SyntaxKind.ImportDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);

View File

@ -1574,10 +1574,10 @@ namespace ts {
return a.fileName === b.fileName;
}
function moduleNameIsEqualTo(a: StringLiteral | Identifier, b: StringLiteral | Identifier): boolean {
return a.kind === SyntaxKind.StringLiteral
? b.kind === SyntaxKind.StringLiteral && a.text === b.text
: b.kind === SyntaxKind.Identifier && a.escapedText === b.escapedText;
function moduleNameIsEqualTo(a: StringLiteralLike | Identifier, b: StringLiteralLike | Identifier): boolean {
return a.kind === SyntaxKind.Identifier
? b.kind === SyntaxKind.Identifier && a.escapedText === b.escapedText
: b.kind === SyntaxKind.StringLiteral && a.text === b.text;
}
function collectExternalModuleReferences(file: SourceFile): void {
@ -1589,7 +1589,7 @@ namespace ts {
const isExternalModuleFile = isExternalModule(file);
// file.imports may not be undefined if there exists dynamic import
let imports: StringLiteral[];
let imports: StringLiteralLike[] | undefined;
let moduleAugmentations: (StringLiteral | Identifier)[];
let ambientModules: string[];
@ -1600,7 +1600,7 @@ namespace ts {
&& !file.isDeclarationFile) {
// synthesize 'import "tslib"' declaration
const externalHelpersModuleReference = createLiteral(externalHelpersModuleNameText);
const importDecl = createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*importClause*/ undefined);
const importDecl = createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*importClause*/ undefined, externalHelpersModuleReference);
addEmitFlags(importDecl, EmitFlags.NeverApplyImportHelper);
externalHelpersModuleReference.parent = importDecl;
importDecl.parent = file;
@ -1621,66 +1621,55 @@ namespace ts {
return;
function collectModuleReferences(node: Statement, inAmbientModule: boolean): void {
switch (node.kind) {
case SyntaxKind.ImportDeclaration:
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.ExportDeclaration:
const moduleNameExpr = getExternalModuleName(node);
if (!moduleNameExpr || !isStringLiteral(moduleNameExpr)) {
break;
if (isAnyImportOrReExport(node)) {
const moduleNameExpr = getExternalModuleName(node);
// TypeScript 1.0 spec (April 2014): 12.1.6
// An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference other external modules
// only through top - level external module names. Relative external module names are not permitted.
if (moduleNameExpr && isStringLiteral(moduleNameExpr) && moduleNameExpr.text && (!inAmbientModule || !isExternalModuleNameRelative(moduleNameExpr.text))) {
imports = append(imports, moduleNameExpr);
}
}
else if (isModuleDeclaration(node)) {
if (isAmbientModule(node) && (inAmbientModule || hasModifier(node, ModifierFlags.Ambient) || file.isDeclarationFile)) {
const nameText = getTextOfIdentifierOrLiteral(node.name);
// Ambient module declarations can be interpreted as augmentations for some existing external modules.
// This will happen in two cases:
// - if current file is external module then module augmentation is a ambient module declaration defined in the top level scope
// - if current file is not external module then module augmentation is an ambient module declaration with non-relative module name
// immediately nested in top level ambient module declaration .
if (isExternalModuleFile || (inAmbientModule && !isExternalModuleNameRelative(nameText))) {
(moduleAugmentations || (moduleAugmentations = [])).push(node.name);
}
if (!moduleNameExpr.text) {
break;
}
// TypeScript 1.0 spec (April 2014): 12.1.6
// An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference other external modules
// only through top - level external module names. Relative external module names are not permitted.
if (!inAmbientModule || !isExternalModuleNameRelative(moduleNameExpr.text)) {
(imports || (imports = [])).push(moduleNameExpr);
}
break;
case SyntaxKind.ModuleDeclaration:
if (isAmbientModule(<ModuleDeclaration>node) && (inAmbientModule || hasModifier(node, ModifierFlags.Ambient) || file.isDeclarationFile)) {
const moduleName = (<ModuleDeclaration>node).name;
const nameText = getTextOfIdentifierOrLiteral(moduleName);
// Ambient module declarations can be interpreted as augmentations for some existing external modules.
// This will happen in two cases:
// - if current file is external module then module augmentation is a ambient module declaration defined in the top level scope
// - if current file is not external module then module augmentation is an ambient module declaration with non-relative module name
// immediately nested in top level ambient module declaration .
if (isExternalModuleFile || (inAmbientModule && !isExternalModuleNameRelative(nameText))) {
(moduleAugmentations || (moduleAugmentations = [])).push(moduleName);
else if (!inAmbientModule) {
if (file.isDeclarationFile) {
// for global .d.ts files record name of ambient module
(ambientModules || (ambientModules = [])).push(nameText);
}
else if (!inAmbientModule) {
if (file.isDeclarationFile) {
// for global .d.ts files record name of ambient module
(ambientModules || (ambientModules = [])).push(nameText);
}
// An AmbientExternalModuleDeclaration declares an external module.
// This type of declaration is permitted only in the global module.
// The StringLiteral must specify a top - level external module name.
// Relative external module names are not permitted
// An AmbientExternalModuleDeclaration declares an external module.
// This type of declaration is permitted only in the global module.
// The StringLiteral must specify a top - level external module name.
// Relative external module names are not permitted
// NOTE: body of ambient module is always a module block, if it exists
const body = <ModuleBlock>(<ModuleDeclaration>node).body;
if (body) {
for (const statement of body.statements) {
collectModuleReferences(statement, /*inAmbientModule*/ true);
}
// NOTE: body of ambient module is always a module block, if it exists
const body = <ModuleBlock>(<ModuleDeclaration>node).body;
if (body) {
for (const statement of body.statements) {
collectModuleReferences(statement, /*inAmbientModule*/ true);
}
}
}
}
}
}
function collectDynamicImportOrRequireCalls(node: Node): void {
if (isRequireCall(node, /*checkArgumentIsStringLiteral*/ true)) {
(imports || (imports = [])).push(<StringLiteral>(<CallExpression>node).arguments[0]);
if (isRequireCall(node, /*checkArgumentIsStringLiteralLike*/ true)) {
imports = append(imports, node.arguments[0]);
}
// we have to check the argument list has length of 1. We will still have to process these even though we have parsing error.
else if (isImportCall(node) && node.arguments.length === 1 && node.arguments[0].kind === SyntaxKind.StringLiteral) {
(imports || (imports = [])).push(<StringLiteral>(<CallExpression>node).arguments[0]);
else if (isImportCall(node) && node.arguments.length === 1 && isStringLiteralLike(node.arguments[0])) {
imports = append(imports, node.arguments[0] as StringLiteralLike);
}
else {
forEachChild(node, collectDynamicImportOrRequireCalls);

View File

@ -2568,7 +2568,7 @@ namespace ts {
// Content of this field should never be used directly - use getResolvedModuleFileName/setResolvedModuleFileName functions instead
/* @internal */ resolvedModules: Map<ResolvedModuleFull | undefined>;
/* @internal */ resolvedTypeReferenceDirectiveNames: Map<ResolvedTypeReferenceDirective>;
/* @internal */ imports: ReadonlyArray<StringLiteral>;
/* @internal */ imports: ReadonlyArray<StringLiteralLike>;
// Identifier only if `declare global`
/* @internal */ moduleAugmentations: ReadonlyArray<StringLiteral | Identifier>;
/* @internal */ patternAmbientModules?: PatternAmbientModule[];
@ -3159,6 +3159,18 @@ namespace ts {
/* @internal */
export type AnyImportSyntax = ImportDeclaration | ImportEqualsDeclaration;
/* @internal */
export type AnyImportOrReExport = AnyImportSyntax | ExportDeclaration;
/* @internal */
export type AnyValidImportOrReExport =
| (ImportDeclaration | ExportDeclaration) & { moduleSpecifier: StringLiteral }
| ImportEqualsDeclaration & { moduleReference: ExternalModuleReference & { expression: StringLiteral } }
| RequireOrImportCall;
/* @internal */
export type RequireOrImportCall = CallExpression & { arguments: [StringLiteralLike] };
/* @internal */
export interface SymbolVisibilityResult {
accessibility: SymbolAccessibility;

View File

@ -538,6 +538,10 @@ namespace ts {
}
}
export function isAnyImportOrReExport(node: Node): node is AnyImportOrReExport {
return isAnyImportSyntax(node) || isExportDeclaration(node);
}
// Gets the nearest enclosing block scope container that has the provided node
// as a descendant, that is not the provided node.
export function getEnclosingBlockScopeContainer(node: Node): Node {
@ -1452,9 +1456,9 @@ namespace ts {
* exactly one argument (of the form 'require("name")').
* This function does not test if the node is in a JavaScript file or not.
*/
export function isRequireCall(callExpression: Node, checkArgumentIsStringLiteral: true): callExpression is CallExpression & { expression: Identifier, arguments: [StringLiteralLike] };
export function isRequireCall(callExpression: Node, checkArgumentIsStringLiteral: boolean): callExpression is CallExpression;
export function isRequireCall(callExpression: Node, checkArgumentIsStringLiteral: boolean): callExpression is CallExpression {
export function isRequireCall(callExpression: Node, checkArgumentIsStringLiteralLike: true): callExpression is RequireOrImportCall & { expression: Identifier, arguments: [StringLiteralLike] };
export function isRequireCall(callExpression: Node, checkArgumentIsStringLiteralLike: boolean): callExpression is CallExpression;
export function isRequireCall(callExpression: Node, checkArgumentIsStringLiteralLike: boolean): callExpression is CallExpression {
if (callExpression.kind !== SyntaxKind.CallExpression) {
return false;
}
@ -1468,14 +1472,14 @@ namespace ts {
return false;
}
const arg = args[0];
return !checkArgumentIsStringLiteral || arg.kind === SyntaxKind.StringLiteral || arg.kind === SyntaxKind.NoSubstitutionTemplateLiteral;
return !checkArgumentIsStringLiteralLike || isStringLiteralLike(arg);
}
export function isSingleOrDoubleQuote(charCode: number) {
return charCode === CharacterCodes.singleQuote || charCode === CharacterCodes.doubleQuote;
}
export function isStringDoubleQuoted(str: StringLiteral, sourceFile: SourceFile): boolean {
export function isStringDoubleQuoted(str: StringLiteralLike, sourceFile: SourceFile): boolean {
return getSourceTextOfNodeFromSourceFile(sourceFile, str).charCodeAt(0) === CharacterCodes.doubleQuote;
}
@ -1658,21 +1662,29 @@ namespace ts {
!!getJSDocTypeTag(expr.parent);
}
export function getExternalModuleName(node: Node): Expression {
if (node.kind === SyntaxKind.ImportDeclaration) {
return (<ImportDeclaration>node).moduleSpecifier;
export function importFromModuleSpecifier(node: StringLiteralLike): AnyValidImportOrReExport {
switch (node.parent.kind) {
case SyntaxKind.ImportDeclaration:
case SyntaxKind.ExportDeclaration:
return node.parent as AnyValidImportOrReExport;
case SyntaxKind.ExternalModuleReference:
return (node.parent as ExternalModuleReference).parent as AnyValidImportOrReExport;
case SyntaxKind.CallExpression:
return node.parent as AnyValidImportOrReExport;
default:
return Debug.fail(Debug.showSyntaxKind(node));
}
if (node.kind === SyntaxKind.ImportEqualsDeclaration) {
const reference = (<ImportEqualsDeclaration>node).moduleReference;
if (reference.kind === SyntaxKind.ExternalModuleReference) {
return reference.expression;
}
}
if (node.kind === SyntaxKind.ExportDeclaration) {
return (<ExportDeclaration>node).moduleSpecifier;
}
if (isModuleWithStringLiteralName(node)) {
return node.name;
}
export function getExternalModuleName(node: AnyImportOrReExport): Expression {
switch (node.kind) {
case SyntaxKind.ImportDeclaration:
case SyntaxKind.ExportDeclaration:
return node.moduleSpecifier;
case SyntaxKind.ImportEqualsDeclaration:
return node.moduleReference.kind === SyntaxKind.ExternalModuleReference ? node.moduleReference.expression : undefined;
default:
return Debug.assertNever(node);
}
}

View File

@ -20,25 +20,22 @@ namespace ts.codefix {
function fixImportOfModuleExports(importingFile: SourceFile, exportingFile: SourceFile, changes: textChanges.ChangeTracker) {
for (const moduleSpecifier of importingFile.imports) {
const imported = getResolvedModule(importingFile, moduleSpecifier.text);
const { text } = moduleSpecifier;
const imported = getResolvedModule(importingFile, text);
if (!imported || imported.resolvedFileName !== exportingFile.fileName) {
continue;
}
const { parent } = moduleSpecifier;
switch (parent.kind) {
case SyntaxKind.ExternalModuleReference: {
const importEq = (parent as ExternalModuleReference).parent;
changes.replaceNode(importingFile, importEq, makeImport(importEq.name, /*namedImports*/ undefined, moduleSpecifier.text));
const importNode = importFromModuleSpecifier(moduleSpecifier);
switch (importNode.kind) {
case SyntaxKind.ImportEqualsDeclaration:
changes.replaceNode(importingFile, importNode, makeImport(importNode.name, /*namedImports*/ undefined, text));
break;
}
case SyntaxKind.CallExpression: {
const call = parent as CallExpression;
if (isRequireCall(call, /*checkArgumentIsStringLiteral*/ false)) {
changes.replaceNode(importingFile, parent, createPropertyAccess(getSynthesizedDeepClone(call), "default"));
case SyntaxKind.CallExpression:
if (isRequireCall(importNode, /*checkArgumentIsStringLiteralLike*/ false)) {
changes.replaceNode(importingFile, importNode, createPropertyAccess(getSynthesizedDeepClone(importNode), "default"));
}
break;
}
}
}
}
@ -112,7 +109,7 @@ namespace ts.codefix {
const { expression } = statement as ExpressionStatement;
switch (expression.kind) {
case SyntaxKind.CallExpression: {
if (isRequireCall(expression, /*checkArgumentIsStringLiteral*/ true)) {
if (isRequireCall(expression, /*checkArgumentIsStringLiteralLike*/ true)) {
// For side-effecting require() call, just make a side-effecting import.
changes.replaceNode(sourceFile, statement, makeImport(/*name*/ undefined, /*namedImports*/ undefined, expression.arguments[0].text));
}
@ -140,11 +137,11 @@ namespace ts.codefix {
foundImport = true;
return [];
}
if (isRequireCall(initializer, /*checkArgumentIsStringLiteral*/ true)) {
if (isRequireCall(initializer, /*checkArgumentIsStringLiteralLike*/ true)) {
foundImport = true;
return convertSingleImport(sourceFile, name, initializer.arguments[0].text, changes, checker, identifiers, target);
}
else if (isPropertyAccessExpression(initializer) && isRequireCall(initializer.expression, /*checkArgumentIsStringLiteral*/ true)) {
else if (isPropertyAccessExpression(initializer) && isRequireCall(initializer.expression, /*checkArgumentIsStringLiteralLike*/ true)) {
foundImport = true;
return convertPropertyAccessImport(name, initializer.name.text, initializer.expression.arguments[0].text, identifiers);
}
@ -279,7 +276,7 @@ namespace ts.codefix {
return [[classExpressionToDeclaration(cls.name && cls.name.text, modifiers, cls)], true];
}
case SyntaxKind.CallExpression:
if (isRequireCall(exported, /*checkArgumentIsStringLiteral*/ true)) {
if (isRequireCall(exported, /*checkArgumentIsStringLiteralLike*/ true)) {
return convertReExportAll(exported.arguments[0], checker);
}
// falls through

View File

@ -158,29 +158,15 @@ namespace ts.codefix {
const moduleSymbolId = getUniqueSymbolId(moduleSymbol, checker);
let cached = cachedImportDeclarations[moduleSymbolId];
if (!cached) {
cached = cachedImportDeclarations[moduleSymbolId] = mapDefined<StringLiteral, ExistingImportInfo>(imports, importModuleSpecifier => {
const declaration = checker.getSymbolAtLocation(importModuleSpecifier) === moduleSymbol ? getImportDeclaration(importModuleSpecifier) : undefined;
return declaration && { declaration, importKind };
cached = cachedImportDeclarations[moduleSymbolId] = mapDefined<StringLiteralLike, ExistingImportInfo>(imports, moduleSpecifier => {
const i = importFromModuleSpecifier(moduleSpecifier);
return (i.kind === SyntaxKind.ImportDeclaration || i.kind === SyntaxKind.ImportEqualsDeclaration)
&& checker.getSymbolAtLocation(moduleSpecifier) === moduleSymbol ? { declaration: i, importKind } : undefined;
});
}
return cached;
}
function getImportDeclaration({ parent }: LiteralExpression): AnyImportSyntax | undefined {
switch (parent.kind) {
case SyntaxKind.ImportDeclaration:
return parent as ImportDeclaration;
case SyntaxKind.ExternalModuleReference:
return (parent as ExternalModuleReference).parent;
case SyntaxKind.ExportDeclaration:
case SyntaxKind.CallExpression: // For "require()" calls
// Ignore these, can't add imports to them.
return undefined;
default:
Debug.fail();
}
}
function getCodeActionForNewImport(context: SymbolContext, { moduleSpecifier, importKind }: NewImportInfo): CodeFixAction {
const { sourceFile, symbolName } = context;
const lastImportDeclaration = findLast(sourceFile.statements, isAnyImportSyntax);

View File

@ -406,7 +406,7 @@ namespace ts.Completions {
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
if (!isRequireCall(node.parent, /*checkArgumentIsStringLiteral*/ false) && !isImportCall(node.parent)) {
if (!isRequireCall(node.parent, /*checkArgumentIsStringLiteralLike*/ false) && !isImportCall(node.parent)) {
const argumentInfo = SignatureHelp.getImmediatelyContainingArgumentInfo(node, position, sourceFile);
// Get string literal completions from specialized signatures of the target
// i.e. declare function f(a: 'A');

View File

@ -278,7 +278,7 @@ namespace ts.FindAllReferences.Core {
case SyntaxKind.ExportDeclaration:
return true;
case SyntaxKind.CallExpression:
return isRequireCall(node.parent as CallExpression, /*checkArgumentIsStringLiteral*/ false) || isImportCall(node.parent as CallExpression);
return isRequireCall(node.parent as CallExpression, /*checkArgumentIsStringLiteralLike*/ false) || isImportCall(node.parent as CallExpression);
default:
return false;
}

View File

@ -33,17 +33,17 @@ namespace ts.FindAllReferences {
interface AmbientModuleDeclaration extends ModuleDeclaration { body?: ModuleBlock; }
type SourceFileLike = SourceFile | AmbientModuleDeclaration;
// Identifier for the case of `const x = require("y")`.
type Importer = AnyImportSyntax | Identifier | ExportDeclaration;
type Importer = AnyImportOrReExport | Identifier;
type ImporterOrCallExpression = Importer | CallExpression;
/** Returns import statements that directly reference the exporting module, and a list of files that may access the module through a namespace. */
function getImportersForExport(
sourceFiles: ReadonlyArray<SourceFile>,
allDirectImports: Map<ImporterOrCallExpression[]>,
{ exportingModuleSymbol, exportKind }: ExportInfo,
checker: TypeChecker,
cancellationToken: CancellationToken
): { directImports: Importer[], indirectUsers: ReadonlyArray<SourceFile> } {
sourceFiles: ReadonlyArray<SourceFile>,
allDirectImports: Map<ImporterOrCallExpression[]>,
{ exportingModuleSymbol, exportKind }: ExportInfo,
checker: TypeChecker,
cancellationToken: CancellationToken
): { directImports: Importer[], indirectUsers: ReadonlyArray<SourceFile> } {
const markSeenDirectImport = nodeSeenTracker<ImporterOrCallExpression>();
const markSeenIndirectUser = nodeSeenTracker<SourceFileLike>();
const directImports: Importer[] = [];
@ -321,7 +321,7 @@ namespace ts.FindAllReferences {
export type ModuleReference =
/** "import" also includes require() calls. */
| { kind: "import", literal: StringLiteral }
| { kind: "import", literal: StringLiteralLike }
/** <reference path> or <reference types> */
| { kind: "reference", referencingFile: SourceFile, ref: FileReference };
export function findModuleReferences(program: Program, sourceFiles: ReadonlyArray<SourceFile>, searchModuleSymbol: Symbol): ModuleReference[] {
@ -382,10 +382,10 @@ namespace ts.FindAllReferences {
}
/** Calls `action` for each import, re-export, or require() in a file. */
function forEachImport(sourceFile: SourceFile, action: (importStatement: ImporterOrCallExpression, imported: StringLiteral) => void): void {
function forEachImport(sourceFile: SourceFile, action: (importStatement: ImporterOrCallExpression, imported: StringLiteralLike) => void): void {
if (sourceFile.externalModuleIndicator || sourceFile.imports !== undefined) {
for (const moduleSpecifier of sourceFile.imports) {
action(importerFromModuleSpecifier(moduleSpecifier), moduleSpecifier);
for (const i of sourceFile.imports) {
action(importFromModuleSpecifier(i), i);
}
}
else {
@ -414,20 +414,6 @@ namespace ts.FindAllReferences {
}
}
function importerFromModuleSpecifier(moduleSpecifier: StringLiteral): ImporterOrCallExpression {
const decl = moduleSpecifier.parent;
switch (decl.kind) {
case SyntaxKind.CallExpression:
case SyntaxKind.ImportDeclaration:
case SyntaxKind.ExportDeclaration:
return decl as ImportDeclaration | ExportDeclaration | CallExpression;
case SyntaxKind.ExternalModuleReference:
return (decl as ExternalModuleReference).parent;
default:
Debug.fail("Unexpected module specifier parent: " + decl.kind);
}
}
export interface ImportedSymbol {
kind: ImportExport.Import;
symbol: Symbol;

View File

@ -646,7 +646,7 @@ namespace ts {
public nameTable: UnderscoreEscapedMap<number>;
public resolvedModules: Map<ResolvedModuleFull>;
public resolvedTypeReferenceDirectiveNames: Map<ResolvedTypeReferenceDirective>;
public imports: StringLiteral[];
public imports: ReadonlyArray<StringLiteralLike>;
public moduleAugmentations: StringLiteral[];
private namedDeclarations: Map<Declaration[]>;
public ambientModuleNames: string[];

View File

@ -33,10 +33,11 @@ namespace ts {
check(sourceFile);
if (getAllowSyntheticDefaultImports(program.getCompilerOptions())) {
for (const importNode of sourceFile.imports) {
const name = importNameForConvertToDefaultImport(importNode.parent);
for (const moduleSpecifier of sourceFile.imports) {
const importNode = importFromModuleSpecifier(moduleSpecifier);
const name = importNameForConvertToDefaultImport(importNode);
if (!name) continue;
const module = getResolvedModule(sourceFile, importNode.text);
const module = getResolvedModule(sourceFile, moduleSpecifier.text);
const resolvedFile = module && program.getSourceFile(module.resolvedFileName);
if (resolvedFile && resolvedFile.externalModuleIndicator && isExportAssignment(resolvedFile.externalModuleIndicator) && resolvedFile.externalModuleIndicator.isExportEquals) {
diags.push(createDiagnosticForNode(name, Diagnostics.Import_may_be_converted_to_a_default_import));
@ -47,15 +48,17 @@ namespace ts {
return diags.concat(checker.getSuggestionDiagnostics(sourceFile));
}
function importNameForConvertToDefaultImport(node: Node): Identifier | undefined {
if (isExternalModuleReference(node)) {
return node.parent.name;
}
if (isImportDeclaration(node)) {
const { importClause, moduleSpecifier } = node;
return importClause && !importClause.name && importClause.namedBindings.kind === SyntaxKind.NamespaceImport && isStringLiteral(moduleSpecifier)
? importClause.namedBindings.name
: undefined;
function importNameForConvertToDefaultImport(node: AnyValidImportOrReExport): Identifier | undefined {
switch (node.kind) {
case SyntaxKind.ImportDeclaration:
const { importClause, moduleSpecifier } = node;
return importClause && !importClause.name && importClause.namedBindings.kind === SyntaxKind.NamespaceImport && isStringLiteral(moduleSpecifier)
? importClause.namedBindings.name
: undefined;
case SyntaxKind.ImportEqualsDeclaration:
return node.name;
default:
return undefined;
}
}
}

View File

@ -3651,7 +3651,7 @@ declare namespace ts {
function updateNamespaceExportDeclaration(node: NamespaceExportDeclaration, name: Identifier): NamespaceExportDeclaration;
function createImportEqualsDeclaration(decorators: ReadonlyArray<Decorator> | undefined, modifiers: ReadonlyArray<Modifier> | undefined, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
function updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: ReadonlyArray<Decorator> | undefined, modifiers: ReadonlyArray<Modifier> | undefined, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
function createImportDeclaration(decorators: ReadonlyArray<Decorator> | undefined, modifiers: ReadonlyArray<Modifier> | undefined, importClause: ImportClause | undefined, moduleSpecifier?: Expression): ImportDeclaration;
function createImportDeclaration(decorators: ReadonlyArray<Decorator> | undefined, modifiers: ReadonlyArray<Modifier> | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration;
function updateImportDeclaration(node: ImportDeclaration, decorators: ReadonlyArray<Decorator> | undefined, modifiers: ReadonlyArray<Modifier> | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression | undefined): ImportDeclaration;
function createImportClause(name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause;
function updateImportClause(node: ImportClause, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause;

View File

@ -3598,7 +3598,7 @@ declare namespace ts {
function updateNamespaceExportDeclaration(node: NamespaceExportDeclaration, name: Identifier): NamespaceExportDeclaration;
function createImportEqualsDeclaration(decorators: ReadonlyArray<Decorator> | undefined, modifiers: ReadonlyArray<Modifier> | undefined, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
function updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: ReadonlyArray<Decorator> | undefined, modifiers: ReadonlyArray<Modifier> | undefined, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
function createImportDeclaration(decorators: ReadonlyArray<Decorator> | undefined, modifiers: ReadonlyArray<Modifier> | undefined, importClause: ImportClause | undefined, moduleSpecifier?: Expression): ImportDeclaration;
function createImportDeclaration(decorators: ReadonlyArray<Decorator> | undefined, modifiers: ReadonlyArray<Modifier> | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration;
function updateImportDeclaration(node: ImportDeclaration, decorators: ReadonlyArray<Decorator> | undefined, modifiers: ReadonlyArray<Modifier> | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression | undefined): ImportDeclaration;
function createImportClause(name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause;
function updateImportClause(node: ImportClause, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause;