Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 76 additions & 1 deletion internal/transformers/declarations/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ func (tx *DeclarationTransformer) visit(node *ast.Node) *ast.Node {
ast.KindJSImportDeclaration,
ast.KindExportDeclaration,
ast.KindJSExportAssignment,
ast.KindExportAssignment:
ast.KindExportAssignment,
ast.KindCommonJSExport:
return tx.visitDeclarationStatements(node)
// statements we elide
case ast.KindBreakStatement,
Expand Down Expand Up @@ -924,6 +925,80 @@ func (tx *DeclarationTransformer) visitDeclarationStatements(input *ast.Node) *a
tx.rewriteModuleSpecifier(input, input.AsExportDeclaration().ModuleSpecifier),
tx.tryGetResolutionModeOverride(input.AsExportDeclaration().Attributes),
)
case ast.KindCommonJSExport:
if ast.IsSourceFile(input.Parent) {
tx.resultHasExternalModuleIndicator = true
}
tx.resultHasScopeMarker = true
name := input.AsCommonJSExport().Name()
if ast.IsIdentifier(name) {
if name.AsIdentifier().Text == "default" {
// const _default: Type; export default _default;
newId := tx.Factory().NewUniqueNameEx("_default", printer.AutoGenerateOptions{Flags: printer.GeneratedIdentifierFlagsOptimistic})
tx.state.getSymbolAccessibilityDiagnostic = func(_ printer.SymbolAccessibilityResult) *SymbolAccessibilityDiagnostic {
return &SymbolAccessibilityDiagnostic{
diagnosticMessage: diagnostics.Default_export_of_the_module_has_or_is_using_private_name_0,
errorNode: input,
}
}
tx.tracker.PushErrorFallbackNode(input)
type_ := tx.ensureType(input, false)
varDecl := tx.Factory().NewVariableDeclaration(newId, nil, type_, nil)
tx.tracker.PopErrorFallbackNode()
var modList *ast.ModifierList
if tx.needsDeclare {
modList = tx.Factory().NewModifierList([]*ast.Node{tx.Factory().NewModifier(ast.KindDeclareKeyword)})
} else {
modList = tx.Factory().NewModifierList([]*ast.Node{})
}
statement := tx.Factory().NewVariableStatement(modList, tx.Factory().NewVariableDeclarationList(ast.NodeFlagsConst, tx.Factory().NewNodeList([]*ast.Node{varDecl})))

assignment := tx.Factory().NewExportAssignment(input.Modifiers(), false, nil, newId)
// Remove comments from the export declaration and copy them onto the synthetic _default declaration
tx.preserveJsDoc(statement, input)
tx.removeAllComments(assignment)
return tx.Factory().NewSyntaxList([]*ast.Node{statement, assignment})
} else {
// export var name: Type
tx.tracker.PushErrorFallbackNode(input)
type_ := tx.ensureType(input, false)
varDecl := tx.Factory().NewVariableDeclaration(name, nil, type_, nil)
tx.tracker.PopErrorFallbackNode()
var modList *ast.ModifierList
if tx.needsDeclare {
modList = tx.Factory().NewModifierList([]*ast.Node{tx.Factory().NewModifier(ast.KindExportKeyword), tx.Factory().NewModifier(ast.KindDeclareKeyword)})
} else {
modList = tx.Factory().NewModifierList([]*ast.Node{tx.Factory().NewModifier(ast.KindExportKeyword)})
}
return tx.Factory().NewVariableStatement(modList, tx.Factory().NewVariableDeclarationList(ast.NodeFlagsNone, tx.Factory().NewNodeList([]*ast.Node{varDecl})))
}
} else {
// const _exported: Type; export {_exported as "name"};
newId := tx.Factory().NewUniqueNameEx("_exported", printer.AutoGenerateOptions{Flags: printer.GeneratedIdentifierFlagsOptimistic})
tx.state.getSymbolAccessibilityDiagnostic = func(_ printer.SymbolAccessibilityResult) *SymbolAccessibilityDiagnostic {
return &SymbolAccessibilityDiagnostic{
diagnosticMessage: diagnostics.Default_export_of_the_module_has_or_is_using_private_name_0,
errorNode: input,
}
}
tx.tracker.PushErrorFallbackNode(input)
type_ := tx.ensureType(input, false)
varDecl := tx.Factory().NewVariableDeclaration(newId, nil, type_, nil)
tx.tracker.PopErrorFallbackNode()
var modList *ast.ModifierList
if tx.needsDeclare {
modList = tx.Factory().NewModifierList([]*ast.Node{tx.Factory().NewModifier(ast.KindDeclareKeyword)})
} else {
modList = tx.Factory().NewModifierList([]*ast.Node{})
}
statement := tx.Factory().NewVariableStatement(modList, tx.Factory().NewVariableDeclarationList(ast.NodeFlagsConst, tx.Factory().NewNodeList([]*ast.Node{varDecl})))

assignment := tx.Factory().NewExportDeclaration(nil, false, tx.Factory().NewNamedExports(tx.Factory().NewNodeList([]*ast.Node{tx.Factory().NewExportSpecifier(false, newId, name)})), nil, nil)
// Remove comments from the export declaration and copy them onto the synthetic _default declaration
tx.preserveJsDoc(statement, input)
tx.removeAllComments(assignment)
return tx.Factory().NewSyntaxList([]*ast.Node{statement, assignment})
}
case ast.KindExportAssignment, ast.KindJSExportAssignment:
if ast.IsSourceFile(input.Parent) {
tx.resultHasExternalModuleIndicator = true
Expand Down
3 changes: 2 additions & 1 deletion internal/transformers/declarations/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ func hasInferredType(node *ast.Node) bool {
ast.KindPropertyAssignment,
ast.KindShorthandPropertyAssignment,
ast.KindJSDocParameterTag,
ast.KindJSDocPropertyTag:
ast.KindJSDocPropertyTag,
ast.KindCommonJSExport:
return true
default:
// assertType<never>(node); // !!!
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//// [tests/cases/compiler/jsDeclarationExportDefaultAssignmentCrash.ts] ////

//// [index.js]
exports.default = () => {
return 1234;
}


//// [index.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
export var default = () => {
return 1234;
};
exports.default = () => {
return 1234;
};


//// [index.d.ts]
declare const _default: () => number;
export default _default;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//// [tests/cases/compiler/jsDeclarationExportDefaultAssignmentCrash.ts] ////

=== index.js ===
exports.default = () => {
>exports.default : Symbol(default, Decl(index.js, 0, 0))
>exports : Symbol("index", Decl(index.js, 0, 0))
>default : Symbol(default, Decl(index.js, 0, 0))

return 1234;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//// [tests/cases/compiler/jsDeclarationExportDefaultAssignmentCrash.ts] ////

=== index.js ===
exports.default = () => {
>exports.default = () => { return 1234;} : () => number
>exports.default : () => number
>exports : typeof import("index")
>default : () => number
>() => { return 1234;} : () => number

return 1234;
>1234 : 1234
}

Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ declare const _default: {
customSymbol: symbol;
};
export = _default;
export var customSymbol2 = Symbol("custom");
export declare var customSymbol2: symbol;
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@
+ customSymbol: symbol;
+};
+export = _default;
+export var customSymbol2 = Symbol("custom");
+export declare var customSymbol2: symbol;
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ export {}; // Silly test harness

//// [a.d.ts]
export declare const x = 0;
export var y = 0;
export declare var y: number;
//// [b.d.ts]
declare const _default: number;
export default _default;
Expand All @@ -217,16 +217,15 @@ export = _default;
declare const _default: number;
export default _default;
//// [g.d.ts]
export var default = 0;
export {};
declare const _default: number;
export default _default;
//// [main1.d.ts]
export {};
//// [main2.d.mts]
export {};
//// [main3.d.cts]
export {};
//// [main4.d.cts]
export var x = require("./g");
export {};
export declare var x: typeof import("./g");
//// [dummy.d.ts]
export {};
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
//// [a.d.ts]
-export const x: 0;
+export declare const x = 0;
+export var y = 0;
+export declare var y: number;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw this when trying to fix this crash too; definitely some weird widening interplay here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the old output was because the KindCommonJSExport declaration was just being emitted as-is. :S That's why we had things like export var x = { x: "x" } in the output which just...isn't actually something we should ever have in a declaration file? And is an error?

//// [b.d.ts]
-declare const _default: 0;
+declare const _default: number;
Expand All @@ -50,18 +50,15 @@
export default _default;
//// [g.d.ts]
-declare const _default: 0;
-export default _default;
+export var default = 0;
+export {};
+declare const _default: number;
export default _default;
//// [main1.d.ts]
export {};
//// [main2.d.mts]
@@= skipped -15, +15 lines =@@
//// [main3.d.cts]
export {};
//// [main4.d.cts]
-export const x: typeof import("./g");
+export var x = require("./g");
+export {};
+export declare var x: typeof import("./g");
//// [dummy.d.ts]
export {};
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ exports.y = 2;


//// [assignmentToVoidZero1.d.ts]
export var y = exports.x = void 0;
export var x = 1;
export var y = 2;
export {};
export declare var y: undefined;
export declare var x: number;
export declare var y: undefined;
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
//// [assignmentToVoidZero1.d.ts]
-export const x: 1;
-export const y: 2;
+export var y = exports.x = void 0;
+export var x = 1;
+export var y = 2;
+export {};
+export declare var y: undefined;
+export declare var x: number;
+export declare var y: undefined;
Comment on lines +22 to +24
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird, we're taking the initial assignment for the type of these?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ensureType uses the serialized type of the declaration which, generally speaking, is inferred from the first initializer. It's just whatever getTypeOfSymbol returns, without any special handling for const-y-ness, excluding some special cases it already handles for TS code.

Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,13 @@ assignmentToVoidZero2_1.j + assignmentToVoidZero2_1.k;


//// [assignmentToVoidZero2.d.ts]
export var j = 1;
export var k = void 0;
export declare var j: number;
export declare var k: undefined;
declare namespace o {
var x: number;
}
declare namespace o {
var y: any;
}
export {};
//// [importer.d.ts]
export {};
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,13 @@

//// [assignmentToVoidZero2.d.ts]
-export const j: 1;
+export var j = 1;
+export var k = void 0;
+export declare var j: number;
+export declare var k: undefined;
+declare namespace o {
+ var x: number;
+}
+declare namespace o {
+ var y: any;
+}
+export {};
//// [importer.d.ts]
export {};
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ var diddy = funky(1);


//// [commonJSAliasedExport.d.ts]
declare function funky(declaration: any): boolean;
export = donkey;
export var funky = funky;
export declare var funky: typeof funky;
//// [bug43713.d.ts]
export {};
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@
module.exports.funky = funky;
//// [bug43713.js]
const { funky } = require('./commonJSAliasedExport');
@@= skipped -15, +19 lines =@@
@@= skipped -14, +18 lines =@@


//// [commonJSAliasedExport.d.ts]
export = donkey;
-export = donkey;
-declare function donkey(ast: any): any;
-declare namespace donkey {
- export { funky };
-}
-declare function funky(declaration: any): boolean;
+export var funky = funky;
declare function funky(declaration: any): boolean;
+export = donkey;
+export declare var funky: typeof funky;
//// [bug43713.d.ts]
export {};
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ function f(k) {


//// [mod1.d.ts]
export var K = K;
export {};
declare class K {
values(): K;
}
export declare var K: typeof K;
//// [main.d.ts]
export {};
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@

//// [mod1.d.ts]
-export class K {
- values(): K;
-}
+export var K = K;
+export {};
+declare class K {
values(): K;
}
+export declare var K: typeof K;
//// [main.d.ts]
export {};
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ function f(k) {


//// [mod1.d.ts]
export var K = class K {
values(): void;
export declare var K: {
new (): {
values(): void;
};
};
export {};
//// [main.d.ts]
export {};
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@

//// [mod1.d.ts]
-export class K {
+export var K = class K {
values(): void;
- values(): void;
-}
+export declare var K: {
+ new (): {
+ values(): void;
+ };
+};
+export {};
//// [main.d.ts]
export {};
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ declare namespace NS {
};
};
}
export var K = NS.K;
export {};
export declare var K: {
new (): {
values(): /*elided*/ any;
};
};
//// [main.d.ts]
export {};
Loading