mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
Fix completions crash on transient exported property named 'default' (#42583)
* Fix completions crash on transient exported property named default * Revert simplification, both conditions were needed
This commit is contained in:
parent
05e2f74fbe
commit
258be217a6
@ -2802,7 +2802,7 @@ namespace FourSlash {
|
||||
const matchingName = completions?.filter(e => e.name === options.name);
|
||||
const detailMessage = matchingName?.length
|
||||
? `\n Found ${matchingName.length} with name '${options.name}' from source(s) ${matchingName.map(e => `'${e.source}'`).join(", ")}.`
|
||||
: "";
|
||||
: ` (In fact, there were no completions with name '${options.name}' at all.)`;
|
||||
return this.raiseError(`No completions were found for the given name, source, and preferences.` + detailMessage);
|
||||
}
|
||||
const codeActions = details.codeActions;
|
||||
|
||||
@ -609,7 +609,7 @@ namespace ts.codefix {
|
||||
const exported = getDefaultLikeExportWorker(importingFile, moduleSymbol, checker, compilerOptions);
|
||||
if (!exported) return undefined;
|
||||
const { symbol, kind } = exported;
|
||||
const info = getDefaultExportInfoWorker(symbol, moduleSymbol, checker, compilerOptions);
|
||||
const info = getDefaultExportInfoWorker(symbol, checker, compilerOptions);
|
||||
return info && { symbol, kind, ...info };
|
||||
}
|
||||
|
||||
@ -645,7 +645,7 @@ namespace ts.codefix {
|
||||
return allowSyntheticDefaults ? ImportKind.Default : ImportKind.CommonJS;
|
||||
}
|
||||
|
||||
function getDefaultExportInfoWorker(defaultExport: Symbol, moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions): { readonly symbolForMeaning: Symbol, readonly name: string } | undefined {
|
||||
function getDefaultExportInfoWorker(defaultExport: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions): { readonly symbolForMeaning: Symbol, readonly name: string } | undefined {
|
||||
const localSymbol = getLocalSymbolForExportDefault(defaultExport);
|
||||
if (localSymbol) return { symbolForMeaning: localSymbol, name: localSymbol.name };
|
||||
|
||||
@ -659,7 +659,7 @@ namespace ts.codefix {
|
||||
// but we can still offer completions for it.
|
||||
// - `aliased.parent` will be undefined if the module is exporting `globalThis.something`,
|
||||
// or another expression that resolves to a global.
|
||||
return getDefaultExportInfoWorker(aliased, aliased.parent, checker, compilerOptions);
|
||||
return getDefaultExportInfoWorker(aliased, checker, compilerOptions);
|
||||
}
|
||||
}
|
||||
|
||||
@ -667,15 +667,13 @@ namespace ts.codefix {
|
||||
defaultExport.escapedName !== InternalSymbolName.ExportEquals) {
|
||||
return { symbolForMeaning: defaultExport, name: defaultExport.getName() };
|
||||
}
|
||||
return { symbolForMeaning: defaultExport, name: moduleSymbolToValidIdentifier(moduleSymbol, compilerOptions.target) };
|
||||
return { symbolForMeaning: defaultExport, name: getNameForExportedSymbol(defaultExport, compilerOptions.target) };
|
||||
}
|
||||
|
||||
function getNameForExportDefault(symbol: Symbol): string | undefined {
|
||||
return symbol.declarations && firstDefined(symbol.declarations, declaration => {
|
||||
if (isExportAssignment(declaration)) {
|
||||
if (isIdentifier(declaration.expression)) {
|
||||
return declaration.expression.text;
|
||||
}
|
||||
return tryCast(skipOuterExpressions(declaration.expression), isIdentifier)?.text;
|
||||
}
|
||||
else if (isExportSpecifier(declaration)) {
|
||||
Debug.assert(declaration.name.text === InternalSymbolName.Default, "Expected the specifier to be a default export");
|
||||
|
||||
@ -732,7 +732,7 @@ namespace ts.Completions {
|
||||
exportedSymbol,
|
||||
moduleSymbol,
|
||||
sourceFile,
|
||||
getNameForExportedSymbol(symbol, compilerOptions.target!),
|
||||
getNameForExportedSymbol(symbol, compilerOptions.target),
|
||||
host,
|
||||
program,
|
||||
formatContext,
|
||||
|
||||
@ -2880,10 +2880,10 @@ namespace ts {
|
||||
return isArray(valueOrArray) ? first(valueOrArray) : valueOrArray;
|
||||
}
|
||||
|
||||
export function getNameForExportedSymbol(symbol: Symbol, scriptTarget: ScriptTarget) {
|
||||
if (symbol.escapedName === InternalSymbolName.ExportEquals || symbol.escapedName === InternalSymbolName.Default) {
|
||||
export function getNameForExportedSymbol(symbol: Symbol, scriptTarget: ScriptTarget | undefined) {
|
||||
if (!(symbol.flags & SymbolFlags.Transient) && (symbol.escapedName === InternalSymbolName.ExportEquals || symbol.escapedName === InternalSymbolName.Default)) {
|
||||
// Name of "export default foo;" is "foo". Name of "export default 0" is the filename converted to camelCase.
|
||||
return firstDefined(symbol.declarations, d => isExportAssignment(d) && isIdentifier(d.expression) ? d.expression.text : undefined)
|
||||
return firstDefined(symbol.declarations, d => isExportAssignment(d) ? tryCast(skipOuterExpressions(d.expression), isIdentifier)?.text : undefined)
|
||||
|| codefix.moduleSymbolToValidIdentifier(getSymbolParentOrFail(symbol), scriptTarget);
|
||||
}
|
||||
return symbol.name;
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: /collection.ts
|
||||
//// class Collection {
|
||||
//// public static readonly default: typeof Collection = Collection;
|
||||
//// }
|
||||
//// export = Collection as typeof Collection & { default: typeof Collection };
|
||||
|
||||
// @Filename: /index.ts
|
||||
//// Colle/**/
|
||||
|
||||
verify.applyCodeActionFromCompletion("", {
|
||||
name: "Collection",
|
||||
source: "/collection",
|
||||
description: `Import 'Collection' from module "./collection"`,
|
||||
preferences: {
|
||||
includeCompletionsForModuleExports: true
|
||||
},
|
||||
newFileContent: `import Collection = require("./collection");\n\nColle`
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user