Fix crash on js declaration emit of export assigned default augmented function (#40596)

* Fix crash on js declaration emit of export assigned default augmented function

* {sp}
This commit is contained in:
Wesley Wigham 2020-09-23 00:50:12 -07:00 committed by GitHub
parent 83574ba135
commit ad2a07440c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 86 additions and 8 deletions

View file

@ -6896,7 +6896,7 @@ namespace ts {
const name = unescapeLeadingUnderscores(symbol.escapedName);
const isExportEquals = name === InternalSymbolName.ExportEquals;
const isDefault = name === InternalSymbolName.Default;
const isExportAssignment = isExportEquals || isDefault;
const isExportAssignmentCompatibleSymbolName = isExportEquals || isDefault;
// synthesize export = ref
// ref should refer to either be a locally scoped symbol which we need to emit, or
// a reference to another namespace/module which we may need to emit an `import` statement for
@ -6908,8 +6908,8 @@ namespace ts {
// In case `target` refers to a namespace member, look at the declaration and serialize the leftmost symbol in it
// eg, `namespace A { export class B {} }; exports = A.B;`
// Technically, this is all that's required in the case where the assignment is an entity name expression
const expr = isExportAssignment ? getExportAssignmentExpression(aliasDecl as ExportAssignment | BinaryExpression) : getPropertyAssignmentAliasLikeExpression(aliasDecl as ShorthandPropertyAssignment | PropertyAssignment | PropertyAccessExpression);
const first = isEntityNameExpression(expr) ? getFirstNonModuleExportsIdentifier(expr) : undefined;
const expr = aliasDecl && ((isExportAssignment(aliasDecl) || isBinaryExpression(aliasDecl)) ? getExportAssignmentExpression(aliasDecl) : getPropertyAssignmentAliasLikeExpression(aliasDecl as ShorthandPropertyAssignment | PropertyAssignment | PropertyAccessExpression));
const first = expr && isEntityNameExpression(expr) ? getFirstNonModuleExportsIdentifier(expr) : undefined;
const referenced = first && resolveEntityName(first, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, enclosingDeclaration);
if (referenced || target) {
includePrivateSymbol(referenced || target);
@ -6922,7 +6922,7 @@ namespace ts {
// into the containing scope anyway, so we want to skip the visibility checks.
const oldTrack = context.tracker.trackSymbol;
context.tracker.trackSymbol = noop;
if (isExportAssignment) {
if (isExportAssignmentCompatibleSymbolName) {
results.push(factory.createExportAssignment(
/*decorators*/ undefined,
/*modifiers*/ undefined,
@ -6931,11 +6931,11 @@ namespace ts {
));
}
else {
if (first === expr) {
if (first === expr && first) {
// serialize as `export {target as name}`
serializeExportSpecifier(name, idText(first));
}
else if (isClassExpression(expr)) {
else if (expr && isClassExpression(expr)) {
serializeExportSpecifier(name, getInternalSymbolName(target, symbolName(target)));
}
else {
@ -6961,7 +6961,7 @@ namespace ts {
const typeToSerialize = getWidenedType(getTypeOfSymbol(getMergedSymbol(symbol)));
if (isTypeRepresentableAsFunctionNamespaceMerge(typeToSerialize, symbol)) {
// If there are no index signatures and `typeToSerialize` is an object type, emit as a namespace instead of a const
serializeAsFunctionNamespaceMerge(typeToSerialize, symbol, varName, isExportAssignment ? ModifierFlags.None : ModifierFlags.Export);
serializeAsFunctionNamespaceMerge(typeToSerialize, symbol, varName, isExportAssignmentCompatibleSymbolName ? ModifierFlags.None : ModifierFlags.Export);
}
else {
const statement = factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([
@ -6974,7 +6974,7 @@ namespace ts {
: name === varName ? ModifierFlags.Export
: ModifierFlags.None);
}
if (isExportAssignment) {
if (isExportAssignmentCompatibleSymbolName) {
results.push(factory.createExportAssignment(
/*decorators*/ undefined,
/*modifiers*/ undefined,

View file

@ -0,0 +1,21 @@
//// [index.js]
function foo() {}
foo.foo = foo;
foo.default = foo;
module.exports = foo;
//// [index.js]
function foo() { }
foo.foo = foo;
foo["default"] = foo;
module.exports = foo;
//// [index.d.ts]
export = foo;
declare function foo(): void;
declare namespace foo {
export { foo };
export { foo as default };
}

View file

@ -0,0 +1,22 @@
=== tests/cases/conformance/jsdoc/declarations/index.js ===
function foo() {}
>foo : Symbol(foo, Decl(index.js, 0, 0), Decl(index.js, 0, 17), Decl(index.js, 2, 14))
foo.foo = foo;
>foo.foo : Symbol(foo.foo, Decl(index.js, 0, 17))
>foo : Symbol(foo, Decl(index.js, 0, 0), Decl(index.js, 0, 17), Decl(index.js, 2, 14))
>foo : Symbol(foo.foo, Decl(index.js, 0, 17))
>foo : Symbol(foo, Decl(index.js, 0, 0), Decl(index.js, 0, 17), Decl(index.js, 2, 14))
foo.default = foo;
>foo.default : Symbol(foo.default, Decl(index.js, 2, 14))
>foo : Symbol(foo, Decl(index.js, 0, 0), Decl(index.js, 0, 17), Decl(index.js, 2, 14))
>default : Symbol(foo.default, Decl(index.js, 2, 14))
>foo : Symbol(foo, Decl(index.js, 0, 0), Decl(index.js, 0, 17), Decl(index.js, 2, 14))
module.exports = foo;
>module.exports : Symbol("tests/cases/conformance/jsdoc/declarations/index", Decl(index.js, 0, 0))
>module : Symbol(export=, Decl(index.js, 3, 18))
>exports : Symbol(export=, Decl(index.js, 3, 18))
>foo : Symbol(foo, Decl(index.js, 0, 0), Decl(index.js, 0, 17), Decl(index.js, 2, 14))

View file

@ -0,0 +1,25 @@
=== tests/cases/conformance/jsdoc/declarations/index.js ===
function foo() {}
>foo : typeof foo
foo.foo = foo;
>foo.foo = foo : typeof foo
>foo.foo : typeof foo
>foo : typeof foo
>foo : typeof foo
>foo : typeof foo
foo.default = foo;
>foo.default = foo : typeof foo
>foo.default : typeof foo
>foo : typeof foo
>default : typeof foo
>foo : typeof foo
module.exports = foo;
>module.exports = foo : typeof foo
>module.exports : typeof foo
>module : { "\"tests/cases/conformance/jsdoc/declarations/index\"": typeof foo; }
>exports : typeof foo
>foo : typeof foo

View file

@ -0,0 +1,10 @@
// @allowJs: true
// @checkJs: true
// @outDir: ./out
// @declaration: true
// @filename: index.js
function foo() {}
foo.foo = foo;
foo.default = foo;
module.exports = foo;