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
3 changes: 2 additions & 1 deletion internal/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -2281,6 +2281,7 @@ func declarationIsWriteAccess(decl *Node) bool {
KindParameter,
KindShorthandPropertyAssignment,
KindTypeAliasDeclaration,
KindJSTypeAliasDeclaration,
KindTypeParameter:
return true

Expand Down Expand Up @@ -5139,7 +5140,7 @@ func (node *ExportAssignment) Clone(f NodeFactoryCoercible) *Node {
}

func (node *ExportAssignment) computeSubtreeFacts() SubtreeFacts {
return propagateModifierListSubtreeFacts(node.modifiers) | propagateSubtreeFacts(node.Type) | propagateSubtreeFacts(node.Expression)
return propagateModifierListSubtreeFacts(node.modifiers) | propagateSubtreeFacts(node.Type) | propagateSubtreeFacts(node.Expression) | core.IfElse(node.IsExportEquals, SubtreeContainsTypeScript, SubtreeFactsNone)
}

func IsExportAssignment(node *Node) bool {
Expand Down
4 changes: 4 additions & 0 deletions internal/ast/utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -3894,3 +3894,7 @@ func IsExpandoInitializer(initializer *Node) bool {
func GetContainingFunction(node *Node) *Node {
return FindAncestor(node.Parent, IsFunctionLike)
}

func IsImplicitlyExportedJSTypeAlias(node *Node) bool {
return IsJSTypeAliasDeclaration(node) && IsSourceFile(node.Parent) && IsExternalOrCommonJSModule(node.Parent.AsSourceFile())
}
2 changes: 1 addition & 1 deletion internal/binder/binder.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ func (b *Binder) declareModuleMember(node *ast.Node, symbolFlags ast.SymbolFlags
if node.Kind == ast.KindCommonJSExport {
container = b.file.AsNode()
}
hasExportModifier := ast.GetCombinedModifierFlags(node)&ast.ModifierFlagsExport != 0
hasExportModifier := ast.GetCombinedModifierFlags(node)&ast.ModifierFlagsExport != 0 || ast.IsImplicitlyExportedJSTypeAlias(node)
if symbolFlags&ast.SymbolFlagsAlias != 0 {
if node.Kind == ast.KindExportSpecifier || (node.Kind == ast.KindImportEqualsDeclaration && hasExportModifier) {
return b.declareSymbol(ast.GetExports(container.Symbol()), container.Symbol(), node, symbolFlags, symbolExcludes)
Expand Down
2 changes: 1 addition & 1 deletion internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -6805,7 +6805,7 @@ func (c *Checker) checkUnusedClassMembers(node *ast.Node) {
c.reportUnused(parameter, UnusedKindLocal, NewDiagnosticForNode(parameter.Name(), diagnostics.Property_0_is_declared_but_its_value_is_never_read, ast.SymbolName(parameter.Symbol())))
}
}
case ast.KindIndexSignature, ast.KindSemicolonClassElement, ast.KindClassStaticBlockDeclaration:
case ast.KindIndexSignature, ast.KindSemicolonClassElement, ast.KindClassStaticBlockDeclaration, ast.KindJSTypeAliasDeclaration:
// Can't be private
default:
panic("Unhandled case in checkUnusedClassMembers")
Expand Down
5 changes: 3 additions & 2 deletions internal/checker/emitresolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,9 @@ func (r *EmitResolver) determineIfDeclarationIsVisible(node *ast.Node) bool {
}
// falls through
}
// external module augmentation is always visible
if ast.IsExternalModuleAugmentation(node) {
// External module augmentation is always visible
// A @typedef at top-level in an external module is always visible
if ast.IsExternalModuleAugmentation(node) || ast.IsImplicitlyExportedJSTypeAlias(node) {
return true
}
parent := ast.GetDeclarationContainer(node)
Expand Down
2 changes: 1 addition & 1 deletion internal/ls/importTracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ func getImportOrExportSymbol(node *ast.Node, symbol *ast.Symbol, checker *checke
} else {
exportNode := getExportNode(parent, node)
switch {
case exportNode != nil && ast.HasSyntacticModifier(exportNode, ast.ModifierFlagsExport):
case exportNode != nil && (ast.HasSyntacticModifier(exportNode, ast.ModifierFlagsExport) || ast.IsImplicitlyExportedJSTypeAlias(exportNode)):
if ast.IsImportEqualsDeclaration(exportNode) && exportNode.AsImportEqualsDeclaration().ModuleReference == node {
// We're at `Y` in `export import X = Y`. This is not the exported symbol, the left-hand-side is. So treat this as an import statement.
if comingFromExport {
Expand Down
8 changes: 1 addition & 7 deletions internal/parser/reparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,11 @@ func (p *Parser) reparseTags(parent *ast.Node, jsDoc []*ast.Node) {
func (p *Parser) reparseUnhosted(tag *ast.Node, parent *ast.Node, jsDoc *ast.Node) {
switch tag.Kind {
case ast.KindJSDocTypedefTag:
// !!! Don't mark typedefs as exported if they are not in a module
typeExpression := tag.AsJSDocTypedefTag().TypeExpression
if typeExpression == nil {
break
}
export := p.factory.NewModifier(ast.KindExportKeyword)
export.Loc = tag.Loc
export.Flags = p.contextFlags | ast.NodeFlagsReparsed
modifiers := p.newModifierList(export.Loc, p.nodeSlicePool.NewSlice1(export))

typeAlias := p.factory.NewJSTypeAliasDeclaration(modifiers, p.factory.DeepCloneReparse(tag.AsJSDocTypedefTag().Name()), nil, nil)
typeAlias := p.factory.NewJSTypeAliasDeclaration(nil, p.factory.DeepCloneReparse(tag.AsJSDocTypedefTag().Name()), nil, nil)
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

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

According to custom coding guideline 1000000, the comment on line 73 states '!!! Don't mark typedefs as exported if they are not in a module'. However, the fix now relies on later stages to determine if the typedef is in a module. Consider updating this comment to clarify that export modifiers are added during declaration transformation based on module context, not during parsing.

Copilot generated this review using guidance from repository custom instructions.
typeAlias.AsTypeAliasDeclaration().TypeParameters = p.gatherTypeParameters(jsDoc, tag)
var t *ast.Node
switch typeExpression.Kind {
Expand Down
3 changes: 3 additions & 0 deletions internal/transformers/declarations/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -1582,6 +1582,9 @@ func (tx *DeclarationTransformer) ensureModifierFlags(node *ast.Node) ast.Modifi
mask ^= ast.ModifierFlagsAmbient
additions = ast.ModifierFlagsNone
}
if ast.IsImplicitlyExportedJSTypeAlias(node) {
additions |= ast.ModifierFlagsExport
}
return maskModifierFlags(tx.host, node, mask, additions)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ var unrelated;
/** @typedef {number} B */

//// [emitEndOfFileJSDocComments.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/** @typedef {number} A */
var unrelated;
/** @typedef {number} B */
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ function test(param) {


//// [emitEndOfFileJSDocComments2.js]
"use strict";
/** @typedef {number} A */
Object.defineProperty(exports, "__esModule", { value: true });
/**
* JSDoc comment for function
* @param {string} param - A string parameter
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
b.js(3,24): error TS2306: File 'a.js' is not a module.


==== a.js (0 errors) ====
/** @typedef {string} A */

==== b.js (1 errors) ====
module.exports = {
create() {
/** @param {import("./a").A} x */
~~~~~
!!! error TS2306: File 'a.js' is not a module.
function f(x) {}
return f("hi");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ export type test = test;


//// [test.js]
export = {
message: ""
};
module.exports = {
message: ""
};
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@ var x = 1


//// [index.js]
export = {};
module.exports = {};
var x = 1;

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,4 @@ class Foo {
}
class Bar extends Foo {
}
export = Bar;
module.exports = Bar;

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,4 @@ class Foo {
}
class Bar extends Foo {
}
export = Bar;
module.exports = Bar;

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,4 @@ class Foo {
}
class Bar extends Foo {
}
export = Bar;
module.exports = Bar;

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,6 @@ module.exports = function loader(options) {}

//// [index.js]
"use strict";
/**
* @typedef Options
* @property {string} opt
*/
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @param {Options} options
*/
export = function loader(options) { };
/**
* @typedef Options
* @property {string} opt
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,6 @@
--- old.jsDeclarationEmitExportAssignedFunctionWithExtraTypedefsMembers.js
+++ new.jsDeclarationEmitExportAssignedFunctionWithExtraTypedefsMembers.js
@@= skipped -17, +17 lines =@@
* @typedef Options
* @property {string} opt
*/
+Object.defineProperty(exports, "__esModule", { value: true });
+/**
+ * @param {Options} options
+ */
+export = function loader(options) { };
+/**
+ * @typedef Options
+ * @property {string} opt
+ */
/**
* @param {Options} options
*/
@@= skipped -7, +16 lines =@@
@@= skipped -24, +24 lines =@@


//// [index.d.ts]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,31 @@ class C3 extends C1 {
* @typedef A
* @property {string} a
*/
export type A = {
type A = {
a: string;
};
export type B = {
type B = {
b: number;
};
/**
* @typedef B
* @property {number} b
*/
declare class C1 {
/**
* @type {A}
*/
value: A;
}
declare class C2 extends C1 {
/**
* @type {A}
*/
value: A;
}
declare class C3 extends C1 {
/**
* @type {A & B}
*/
value: A & B;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,33 @@
* @typedef A
* @property {string} a
*/
-/**
- * @typedef B
- * @property {number} b
- */
-declare class C1 {
- /**
- * @type {A}
- */
- value: A;
-}
-declare class C2 extends C1 {
-}
-declare class C3 extends C1 {
- /**
- * @type {A & B}
- */
- value: A & B;
-}
+type A = {
+ a: string;
+};
+type B = {
+ b: number;
+};
/**
* @typedef B
* @property {number} b
@@= skipped -11, +17 lines =@@
value: A;
}
declare class C2 extends C1 {
+ /**
+ * @type {A}
+ */
+ value: A;
}
declare class C3 extends C1 {
/**
@@= skipped -7, +11 lines =@@
*/
value: A & B;
}
-type A = {
+export type A = {
a: string;
};
- a: string;
-};
-type B = {
+export type B = {
b: number;
};
- b: number;
-};
Loading
Loading