mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-03-02 23:45:51 -06:00
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:
parent
adf3635a1f
commit
28ff6b6ef3
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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');
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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[];
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user