Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
@@ -0,0 +1,36 @@
// === findAllReferences ===
// === /a.ts ===

// interface A {
// /*FIND ALL REFS*/[|foo|]: string;
// }


// === /b.ts ===

// ///<reference path='a.ts'/>
//
//
// function foo(x: A) {
// x.[|foo|]
// }




// === findAllReferences ===
// === /a.ts ===

// interface A {
// [|foo|]: string;
// }


// === /b.ts ===

// ///<reference path='a.ts'/>
//
//
// function foo(x: A) {
// x./*FIND ALL REFS*/[|foo|]
// }
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// === QuickInfo ===
=== /deprecatedInheritedJSDocOverload.ts ===
// interface PartialObserver<T> {}
// interface Subscription {}
// interface Unsubscribable {}
//
// export interface Subscribable<T> {
// subscribe(observer?: PartialObserver<T>): Unsubscribable;
// /** @deprecated Base deprecation 1 */
// subscribe(next: null | undefined, error: null | undefined, complete: () => void): Unsubscribable;
// /** @deprecated Base deprecation 2 */
// subscribe(next: null | undefined, error: (error: any) => void, complete?: () => void): Unsubscribable;
// /** @deprecated Base deprecation 3 */
// subscribe(next: (value: T) => void, error: null | undefined, complete: () => void): Unsubscribable;
// subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): Unsubscribable;
// }
// interface ThingWithDeprecations<T> extends Subscribable<T> {
// subscribe(observer?: PartialObserver<T>): Subscription;
// /** @deprecated 'real' deprecation */
// subscribe(next: null | undefined, error: null | undefined, complete: () => void): Subscription;
// /** @deprecated 'real' deprecation */
// subscribe(next: null | undefined, error: (error: any) => void, complete?: () => void): Subscription;
// }
// declare const a: ThingWithDeprecations<void>
// a.subscribe(() => {
// ^
// | ----------------------------------------------------------------------
// | ```tsx
// | (method) ThingWithDeprecations.subscribe(observer?: PartialObserver<T>): Subscription
// | ```
// |
// | ----------------------------------------------------------------------
// console.log('something happened');
// });
[
{
"marker": {
"Position": 1183,
"LSPosition": {
"line": 22,
"character": 11
},
"Name": "",
"Data": {}
},
"item": {
"contents": {
"kind": "markdown",
"value": "```tsx\n(method) ThingWithDeprecations.subscribe(observer?: PartialObserver<T>): Subscription\n```\n"
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// === QuickInfo ===
=== /quickInfoCircularInstantiationExpression.ts ===
// declare function foo<T>(t: T): typeof foo<T>;
// foo("");
// ^
// | ----------------------------------------------------------------------
// | ```tsx
// | function foo<string>(t: T): (t: T) => ...
// | ```
// |
// | ----------------------------------------------------------------------
[
{
"marker": {
"Position": 46,
"LSPosition": {
"line": 1,
"character": 0
},
"Name": "",
"Data": {}
},
"item": {
"contents": {
"kind": "markdown",
"value": "```tsx\nfunction foo<string>(t: T): (t: T) => ...\n```\n"
}
}
}
]
Loading
Loading