Skip to content
Closed
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
2 changes: 1 addition & 1 deletion internal/ast/utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -1477,7 +1477,7 @@ func GetNonAssignedNameOfDeclaration(declaration *Node) *Node {
switch declaration.Kind {
case KindBinaryExpression, KindCallExpression:
switch GetAssignmentDeclarationKind(declaration) {
case JSDeclarationKindProperty, JSDeclarationKindThisProperty, JSDeclarationKindExportsProperty:
case JSDeclarationKindProperty, JSDeclarationKindThisProperty, JSDeclarationKindExportsProperty, JSDeclarationKindModuleExports:
left := declaration.AsBinaryExpression().Left
if name := GetElementOrPropertyAccessName(left); name != nil {
return name
Expand Down
2 changes: 1 addition & 1 deletion internal/binder/binder.go
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ func (b *Binder) bind(node *ast.Node) bool {
}
case ast.KindBinaryExpression:
switch ast.GetAssignmentDeclarationKind(node) {
case ast.JSDeclarationKindProperty:
case ast.JSDeclarationKindModuleExports, ast.JSDeclarationKindExportsProperty, ast.JSDeclarationKindProperty:
b.bindExpandoPropertyAssignment(node)
case ast.JSDeclarationKindThisProperty:
b.bindThisPropertyAssignment(node)
Expand Down
9 changes: 9 additions & 0 deletions internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2328,6 +2328,8 @@ func (c *Checker) checkSourceElementWorker(node *ast.Node) {
c.checkExportDeclaration(node)
case ast.KindExportAssignment:
c.checkExportAssignment(node)
case ast.KindCommonJSExport:
c.checkCommonJSExport(node)
case ast.KindEmptyStatement:
c.checkGrammarStatementInAmbientContext(node)
case ast.KindDebuggerStatement:
Expand Down Expand Up @@ -5579,6 +5581,13 @@ func (c *Checker) checkExternalModuleExports(node *ast.Node) {
}
}

func (c *Checker) checkCommonJSExport(node *ast.Node) {
sourceFile := ast.GetSourceFileOfNode(node)
if sourceFile.ExternalModuleIndicator != nil && sourceFile.ExternalModuleIndicator != sourceFile.AsNode() {
c.error(node, diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements)
}
}

func (c *Checker) hasExportedMembersOfKind(moduleSymbol *ast.Symbol, kind ast.SymbolFlags) bool {
for _, symbol := range moduleSymbol.Exports {
if symbol.Name != ast.InternalSymbolNameExportEquals && c.getSymbolFlags(symbol)&kind != 0 {
Expand Down
68 changes: 67 additions & 1 deletion internal/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ const (
jsdocScannerInfoHasSeeOrLink
)

type ShadowFlags int32
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The type doesn't need to be exported either, technically


const (
ShadowFlagsModule ShadowFlags = 1 << iota // `module` identifier is shadowed
ShadowFlagsExports // `exports` identifier is shadowed
)

type Parser struct {
scanner *scanner.Scanner
factory ast.NodeFactory
Expand All @@ -78,6 +85,7 @@ type Parser struct {
sourceFlags ast.NodeFlags
contextFlags ast.NodeFlags
parsingContexts ParsingContexts
shadowFlags ShadowFlags
statementHasAwaitIdentifier bool
hasDeprecatedTag bool
hasParseError bool
Expand Down Expand Up @@ -338,6 +346,7 @@ func (p *Parser) parseErrorAtRange(loc core.TextRange, message *diagnostics.Mess
type ParserState struct {
scannerState scanner.ScannerState
contextFlags ast.NodeFlags
shadowFlags ShadowFlags
diagnosticsLen int
jsDiagnosticsLen int
jsdocInfosLen int
Expand All @@ -350,6 +359,7 @@ func (p *Parser) mark() ParserState {
return ParserState{
scannerState: p.scanner.Mark(),
contextFlags: p.contextFlags,
shadowFlags: p.shadowFlags,
diagnosticsLen: len(p.diagnostics),
jsDiagnosticsLen: len(p.jsDiagnostics),
jsdocInfosLen: len(p.jsdocInfos),
Expand All @@ -363,6 +373,7 @@ func (p *Parser) rewind(state ParserState) {
p.scanner.Rewind(state.scannerState)
p.token = p.scanner.Token()
p.contextFlags = state.contextFlags
p.shadowFlags = state.shadowFlags
p.diagnostics = p.diagnostics[0:state.diagnosticsLen]
p.jsDiagnostics = p.jsDiagnostics[0:state.jsDiagnosticsLen]
p.jsdocInfos = p.jsdocInfos[0:state.jsdocInfosLen]
Expand Down Expand Up @@ -1209,7 +1220,9 @@ func (p *Parser) parseBlock(ignoreMissingOpenBrace bool, diagnosticMessage *diag
multiline := false
if openBraceParsed || ignoreMissingOpenBrace {
multiline = p.hasPrecedingLineBreak()
saveShadowFlags := p.shadowFlags
statements := p.parseList(PCBlockStatements, (*Parser).parseStatement)
p.shadowFlags = saveShadowFlags
Comment on lines +1223 to +1225
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

Saving/restoring shadowFlags for every { ... } block treats shadowing as purely block-scoped. That’s incorrect for var (and function declarations in non-strict modes), which are function/global scoped even when declared inside a nested block.

Example: if (cond) { var module = {}; } module.exports = 1; should treat module as shadowed after the block, but restoring shadowFlags here will clear the shadow and may incorrectly reparse module.exports as a CommonJS export assignment.

Suggestion: track shadowing with a function-scope layer (for var/hoisted decls) separate from a block-scope layer (for let/const/catch), or otherwise propagate function-scoped shadowing out of the block before restoring.

Suggested change
saveShadowFlags := p.shadowFlags
statements := p.parseList(PCBlockStatements, (*Parser).parseStatement)
p.shadowFlags = saveShadowFlags
statements := p.parseList(PCBlockStatements, (*Parser).parseStatement)

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

@ahejlsberg ahejlsberg Apr 5, 2026

Choose a reason for hiding this comment

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

This is a known limitation. Tracking in the parser can't fully handle hoisting because usages may precede a declaration.

p.parseExpectedMatchingBrackets(ast.KindOpenBraceToken, ast.KindCloseBraceToken, openBraceParsed, openBracePosition)
result := p.finishNode(p.factory.NewBlock(statements, multiline), pos)
p.withJSDoc(result, jsdoc)
Expand Down Expand Up @@ -1288,6 +1301,7 @@ func (p *Parser) parseWhileStatement() *ast.Node {
func (p *Parser) parseForOrForInOrForOfStatement() *ast.Node {
pos := p.nodePos()
jsdoc := p.jsdocScannerInfo()
saveShadowFlags := p.shadowFlags
p.parseExpected(ast.KindForKeyword)
awaitToken := p.parseOptionalToken(ast.KindAwaitKeyword)
p.parseExpected(ast.KindOpenParenToken)
Expand Down Expand Up @@ -1326,6 +1340,7 @@ func (p *Parser) parseForOrForInOrForOfStatement() *ast.Node {
p.parseExpected(ast.KindCloseParenToken)
result = p.factory.NewForStatement(initializer, condition, incrementor, p.parseStatement())
}
p.shadowFlags = saveShadowFlags
p.finishNode(result, pos)
Comment on lines 1301 to 1344
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

Restoring shadowFlags at the end of parsing a for (...) ... statement will drop shadowing introduced by var in the initializer, even though var bindings are visible after the loop.

Example: for (var module of xs) {} module.exports = 1; should treat module as shadowed in the subsequent statement, but the restore here will clear it and may incorrectly reparse module.exports.

Suggestion: only unwind block-scoped shadowing here, while preserving function-scoped shadowing (e.g., var bindings) so it remains in effect after the loop.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Again, this is a known limitation.

p.withJSDoc(result, jsdoc)
return result
Expand Down Expand Up @@ -1491,13 +1506,15 @@ func (p *Parser) parseTryStatement() *ast.Node {

func (p *Parser) parseCatchClause() *ast.Node {
pos := p.nodePos()
saveShadowFlags := p.shadowFlags
p.parseExpected(ast.KindCatchKeyword)
var variableDeclaration *ast.Node
if p.parseOptional(ast.KindOpenParenToken) {
variableDeclaration = p.parseVariableDeclaration()
p.parseExpected(ast.KindCloseParenToken)
}
block := p.parseBlock(false /*ignoreMissingOpenBrace*/, nil)
p.shadowFlags = saveShadowFlags
result := p.finishNode(p.factory.NewCatchClause(variableDeclaration, block), pos)
return result
}
Expand Down Expand Up @@ -1639,7 +1656,20 @@ func (p *Parser) parseIdentifierOrPatternWithDiagnostic(privateIdentifierDiagnos
if p.token == ast.KindOpenBraceToken {
return p.parseObjectBindingPattern()
}
return p.parseBindingIdentifierWithDiagnostic(privateIdentifierDiagnosticMessage)
id := p.parseBindingIdentifierWithDiagnostic(privateIdentifierDiagnosticMessage)
p.updateShadowFlags(id)
return id
}

func (p *Parser) updateShadowFlags(name *ast.Node) {
if p.isJavaScript() && name != nil {
if ast.IsModuleIdentifier(name) {
p.shadowFlags |= ShadowFlagsModule
}
if ast.IsExportsIdentifier(name) {
p.shadowFlags |= ShadowFlagsExports
}
}
Comment on lines +1664 to +1672
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

shadowFlags is parser-global state, so it needs to be saved/restored for all constructs that introduce a new binding scope. The current saves/restores cover blocks, for, catch, and some function/class forms, but arrow functions and switch case blocks don’t appear to reset shadowFlags when exiting their scope.

That can cause bindings like (module) => {} or switch { case 0: let exports; } to permanently set ShadowFlagsModule/Exports and suppress later CommonJS export reparsing at the outer scope.

Suggestion: apply the same save/restore pattern around arrow function parameter+body parsing and around parseCaseBlock (or otherwise centralize scope management for shadow tracking).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Arrow functions are now handled. Case blocks don't have their own scope so need no additional handing.

}

func (p *Parser) parseArrayBindingPattern() *ast.Node {
Expand Down Expand Up @@ -1687,6 +1717,7 @@ func (p *Parser) parseObjectBindingElement() *ast.Node {
if tokenIsIdentifier && p.token != ast.KindColonToken {
name = propertyName
propertyName = nil
p.updateShadowFlags(name)
} else {
p.parseExpected(ast.KindColonToken)
name = p.parseIdentifierOrPattern()
Expand Down Expand Up @@ -1716,16 +1747,19 @@ func (p *Parser) parseFunctionDeclaration(pos int, jsdoc jsdocScannerInfo, modif
var name *ast.Node
if modifiers == nil || modifiers.ModifierFlags&ast.ModifierFlagsDefault == 0 || p.isBindingIdentifier() {
name = p.parseBindingIdentifier()
p.updateShadowFlags(name)
}
signatureFlags := core.IfElse(asteriskToken != nil, ParseFlagsYield, ParseFlagsNone) | core.IfElse(modifiers != nil && modifiers.ModifierFlags&ast.ModifierFlagsAsync != 0, ParseFlagsAwait, ParseFlagsNone)
typeParameters := p.parseTypeParameters()
saveContextFlags := p.contextFlags
saveShadowFlags := p.shadowFlags
if modifiers != nil && modifiers.ModifierFlags&ast.ModifierFlagsExport != 0 {
p.setContextFlags(ast.NodeFlagsAwaitContext, true)
}
parameters := p.parseParameters(signatureFlags)
returnType := p.parseReturnType(ast.KindColonToken, false /*isType*/)
body := p.parseFunctionBlockOrSemicolon(signatureFlags, diagnostics.X_or_expected)
p.shadowFlags = saveShadowFlags
p.contextFlags = saveContextFlags
result := p.finishNode(p.factory.NewFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, returnType, nil /*fullSignature*/, body), pos)
p.withJSDoc(result, jsdoc)
Expand All @@ -1747,6 +1781,9 @@ func (p *Parser) parseClassDeclarationOrExpression(pos int, jsdoc jsdocScannerIn
p.parseExpected(ast.KindClassKeyword)
// We don't parse the name here in await context, instead we will report a grammar error in the checker.
name := p.parseNameOfClassDeclarationOrExpression()
if kind == ast.KindClassDeclaration && name != nil {
p.updateShadowFlags(name)
}
typeParameters := p.parseTypeParameters()
if modifiers != nil && core.Some(modifiers.Nodes, isExportModifier) {
p.setContextFlags(ast.NodeFlagsAwaitContext, true /*value*/)
Expand Down Expand Up @@ -1918,10 +1955,12 @@ func (p *Parser) tryParseConstructorDeclaration(pos int, jsdoc jsdocScannerInfo,
state := p.mark()
if p.token == ast.KindConstructorKeyword || p.token == ast.KindStringLiteral && p.scanner.TokenValue() == "constructor" && p.lookAhead((*Parser).nextTokenIsOpenParen) {
p.nextToken()
saveShadowFlags := p.shadowFlags
typeParameters := p.parseTypeParameters()
parameters := p.parseParameters(ParseFlagsNone)
returnType := p.parseReturnType(ast.KindColonToken, false /*isType*/)
body := p.parseFunctionBlockOrSemicolon(ParseFlagsNone, diagnostics.X_or_expected)
p.shadowFlags = saveShadowFlags
result := p.finishNode(p.factory.NewConstructorDeclaration(modifiers, typeParameters, parameters, returnType, nil /*fullSignature*/, body), pos)
p.withJSDoc(result, jsdoc)
p.checkJSSyntax(result)
Expand Down Expand Up @@ -1949,10 +1988,12 @@ func (p *Parser) parsePropertyOrMethodDeclaration(pos int, jsdoc jsdocScannerInf

func (p *Parser) parseMethodDeclaration(pos int, jsdoc jsdocScannerInfo, modifiers *ast.ModifierList, asteriskToken *ast.Node, name *ast.Node, questionToken *ast.Node, diagnosticMessage *diagnostics.Message) *ast.Node {
signatureFlags := core.IfElse(asteriskToken != nil, ParseFlagsYield, ParseFlagsNone) | core.IfElse(modifierListHasAsync(modifiers), ParseFlagsAwait, ParseFlagsNone)
saveShadowFlags := p.shadowFlags
typeParameters := p.parseTypeParameters()
parameters := p.parseParameters(signatureFlags)
typeNode := p.parseReturnType(ast.KindColonToken, false /*isType*/)
body := p.parseFunctionBlockOrSemicolon(signatureFlags, diagnosticMessage)
p.shadowFlags = saveShadowFlags
result := p.finishNode(p.factory.NewMethodDeclaration(modifiers, asteriskToken, name, questionToken, typeParameters, parameters, typeNode, nil /*fullSignature*/, body), pos)
p.withJSDoc(result, jsdoc)
p.checkJSSyntax(result)
Expand Down Expand Up @@ -2353,6 +2394,7 @@ func (p *Parser) parseImportClause(identifier *ast.Node, pos int, phaseModifier
// parse namespace or named imports
var namedBindings *ast.Node
saveHasAwaitIdentifier := p.statementHasAwaitIdentifier
p.updateShadowFlags(identifier)
if identifier == nil || p.parseOptional(ast.KindCommaToken) {
if skipJSDocLeadingAsterisks {
p.scanner.SetSkipJSDocLeadingAsterisks(true)
Expand All @@ -2378,6 +2420,7 @@ func (p *Parser) parseNamespaceImport() *ast.Node {
p.parseExpected(ast.KindAsteriskToken)
p.parseExpected(ast.KindAsKeyword)
name := p.parseIdentifier()
p.updateShadowFlags(name)
return p.finishNode(p.factory.NewNamespaceImport(name), pos)
}

Expand All @@ -2396,6 +2439,9 @@ func (p *Parser) parseImportSpecifier() *ast.Node {
isTypeOnly, propertyName, name := p.parseImportOrExportSpecifier(ast.KindImportSpecifier)
var identifierName *ast.Node
if name.Kind == ast.KindIdentifier {
if !isTypeOnly {
p.updateShadowFlags(name)
}
identifierName = name
} else {
p.parseErrorAtRange(p.skipRangeTrivia(name.Loc), diagnostics.Identifier_expected)
Expand Down Expand Up @@ -3204,10 +3250,12 @@ func (p *Parser) parseSignatureMember(kind ast.Kind) *ast.Node {
if kind == ast.KindConstructSignature {
p.parseExpected(ast.KindNewKeyword)
}
saveShadowFlags := p.shadowFlags
typeParameters := p.parseTypeParameters()
parameters := p.parseParameters(ParseFlagsType)
typeNode := p.parseReturnType(ast.KindColonToken /*isType*/, true)
p.parseTypeMemberSemicolon()
p.shadowFlags = saveShadowFlags
var result *ast.Node
if kind == ast.KindCallSignature {
result = p.factory.NewCallSignatureDeclaration(typeParameters, parameters, typeNode)
Expand Down Expand Up @@ -3426,10 +3474,12 @@ func (p *Parser) parseTypeMemberSemicolon() {

func (p *Parser) parseAccessorDeclaration(pos int, jsdoc jsdocScannerInfo, modifiers *ast.ModifierList, kind ast.Kind, flags ParseFlags) *ast.Node {
name := p.parsePropertyName()
saveShadowFlags := p.shadowFlags
typeParameters := p.parseTypeParameters()
parameters := p.parseParameters(ParseFlagsNone)
returnType := p.parseReturnType(ast.KindColonToken, false /*isType*/)
body := p.parseFunctionBlockOrSemicolon(flags, nil /*diagnosticMessage*/)
p.shadowFlags = saveShadowFlags
var result *ast.Node
// Keep track of `typeParameters` (for both) and `type` (for setters) if they were parsed those indicate grammar errors
if kind == ast.KindGetAccessor {
Expand Down Expand Up @@ -3576,9 +3626,11 @@ func (p *Parser) parsePropertyOrMethodSignature(pos int, jsdoc jsdocScannerInfo,
if p.token == ast.KindOpenParenToken || p.token == ast.KindLessThanToken {
// Method signatures don't exist in expression contexts. So they have neither
// [Yield] nor [Await]
saveShadowFlags := p.shadowFlags
typeParameters := p.parseTypeParameters()
parameters := p.parseParameters(ParseFlagsType)
returnType := p.parseReturnType(ast.KindColonToken /*isType*/, true)
p.shadowFlags = saveShadowFlags
result = p.factory.NewMethodSignatureDeclaration(modifiers, name, questionToken, typeParameters, parameters, returnType)
} else {
typeNode := p.parseTypeAnnotation()
Expand Down Expand Up @@ -3780,9 +3832,11 @@ func (p *Parser) parseFunctionOrConstructorType() *ast.TypeNode {
modifiers := p.parseModifiersForConstructorType()
isConstructorType := p.parseOptional(ast.KindNewKeyword)
debug.Assert(modifiers == nil || isConstructorType, "Per isStartOfFunctionOrConstructorType, a function type cannot have modifiers.")
saveShadowFlags := p.shadowFlags
typeParameters := p.parseTypeParameters()
parameters := p.parseParameters(ParseFlagsType)
returnType := p.parseReturnType(ast.KindEqualsGreaterThanToken, false /*isType*/)
p.shadowFlags = saveShadowFlags
var result *ast.TypeNode
if isConstructorType {
result = p.factory.NewConstructorTypeNode(modifiers, typeParameters, parameters, returnType)
Expand Down Expand Up @@ -4340,6 +4394,13 @@ func (p *Parser) tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInA
}

func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, allowReturnTypeInArrowFunction bool) *ast.Node {
saveShadowFlags := p.shadowFlags
result := p.parseParenthesizedArrowFunctionExpressionWorker(allowAmbiguity, allowReturnTypeInArrowFunction)
p.shadowFlags = saveShadowFlags
return result
}

func (p *Parser) parseParenthesizedArrowFunctionExpressionWorker(allowAmbiguity bool, allowReturnTypeInArrowFunction bool) *ast.Node {
pos := p.nodePos()
jsdoc := p.jsdocScannerInfo()
modifiers := p.parseModifiersForArrowFunction()
Expand Down Expand Up @@ -4540,10 +4601,13 @@ func (p *Parser) nextIsUnParenthesizedAsyncArrowFunction() bool {

func (p *Parser) parseSimpleArrowFunctionExpression(pos int, identifier *ast.Node, allowReturnTypeInArrowFunction bool, jsdoc jsdocScannerInfo, asyncModifier *ast.ModifierList) *ast.Node {
debug.Assert(p.token == ast.KindEqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>")
saveShadowFlags := p.shadowFlags
parameter := p.finishNode(p.factory.NewParameterDeclaration(nil /*modifiers*/, nil /*dotDotDotToken*/, identifier, nil /*questionToken*/, nil /*typeNode*/, nil /*initializer*/), identifier.Pos())
p.updateShadowFlags(identifier)
parameters := p.newNodeList(parameter.Loc, []*ast.Node{parameter})
equalsGreaterThanToken := p.parseExpectedToken(ast.KindEqualsGreaterThanToken)
body := p.parseArrowFunctionExpressionBody(asyncModifier != nil /*isAsync*/, allowReturnTypeInArrowFunction)
p.shadowFlags = saveShadowFlags
result := p.finishNode(p.factory.NewArrowFunction(asyncModifier, nil /*typeParameters*/, parameters, nil /*returnType*/, nil /*fullSignature*/, equalsGreaterThanToken, body), pos)
p.withJSDoc(result, jsdoc)
return result
Expand Down Expand Up @@ -5692,10 +5756,12 @@ func (p *Parser) parseFunctionExpression() *ast.Expression {
default:
name = p.parseOptionalBindingIdentifier()
}
saveShadowFlags := p.shadowFlags
typeParameters := p.parseTypeParameters()
parameters := p.parseParameters(signatureFlags)
returnType := p.parseReturnType(ast.KindColonToken, false /*isType*/)
body := p.parseFunctionBlock(signatureFlags, nil /*diagnosticMessage*/)
p.shadowFlags = saveShadowFlags
p.contextFlags = saveContexFlags
result := p.factory.NewFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, returnType, nil /*fullSignature*/, body)
p.finishNode(result, pos)
Expand Down
20 changes: 14 additions & 6 deletions internal/parser/reparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,22 @@ func (p *Parser) reparseCommonJS(node *ast.Node, jsdoc []*ast.Node) {
var export *ast.Node
switch ast.GetAssignmentDeclarationKind(expr) {
case ast.JSDeclarationKindModuleExports:
export = p.factory.NewJSExportAssignment(nil, p.factory.DeepCloneReparse(expr.AsBinaryExpression().Right))
// Reparse a JSExportAssignment if `module` identifier is not shadowed
if p.shadowFlags&ShadowFlagsModule == 0 {
export = p.factory.NewJSExportAssignment(nil, p.factory.DeepCloneReparse(expr.AsBinaryExpression().Right))
}
case ast.JSDeclarationKindExportsProperty:
// TODO: Name can sometimes be a string literal, so downstream code needs to handle this
export = p.factory.NewCommonJSExport(
nil,
p.factory.DeepCloneReparse(ast.GetElementOrPropertyAccessName(expr.AsBinaryExpression().Left)),
nil, /*typeNode*/
p.factory.DeepCloneReparse(expr.AsBinaryExpression().Right))
// Reparse a CommonJSExport if `exports` identifier is not shadowed in `exports.xxx` or
// `module` identifier is not shadowed in `module.exports.xxx`
shadowFlag := core.IfElse(ast.IsIdentifier(expr.AsBinaryExpression().Left.Expression()), ShadowFlagsExports, ShadowFlagsModule)
if p.shadowFlags&shadowFlag == 0 {
export = p.factory.NewCommonJSExport(
nil,
p.factory.DeepCloneReparse(ast.GetElementOrPropertyAccessName(expr.AsBinaryExpression().Left)),
nil, /*typeNode*/
p.factory.DeepCloneReparse(expr.AsBinaryExpression().Right))
}
}
if export == nil {
break
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//// [tests/cases/compiler/esModuleWithShadowedModuleIdentifier.ts] ////

=== dep.js ===
function something(module) {
>something : Symbol(something, Decl(dep.js, 0, 0))
>module : Symbol(module, Decl(dep.js, 0, 19))

module.exports = 8;
>module : Symbol(module, Decl(dep.js, 0, 19))
}

export default 7;

=== main.ts ===
import DefaultExport from "./dep.js";
>DefaultExport : Symbol(DefaultExport, Decl(main.ts, 0, 6))

export default 3 + DefaultExport;
>DefaultExport : Symbol(DefaultExport, Decl(main.ts, 0, 6))

Loading
Loading