Fix nodeFlags: bit 6 is ExportContext, not GlobalAugmentation

TS7 binary AST uses bit 6 for ExportContext (set on all nodes inside
`declare module` contexts), not GlobalAugmentation as previously assumed.
GlobalAugmentation is not a flag in the TS7 binary format at all.

Fix by using a synthetic flag bit (1<<30) for GlobalAugmentation that the
converter sets on `declare global {}` nodes based on the name identifier
being "global". This lets the Java extractor correctly distinguish
`declare global {}` from regular namespace declarations.

Also corrects the flag shift: ExportContext=64 (bit 6), ContainsThis=128
(bit 7), etc., matching the actual TS7 binary layout.

TRAP test results: 494/495 passing (99.8%)
Remaining: badimport.ts (TS7 binary API doesn't report parse diagnostics)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Asger F
2026-04-13 15:22:58 +02:00
parent 637ce99e44
commit fbaf648e4f
2 changed files with 45 additions and 26 deletions

View File

@@ -82,11 +82,11 @@ func (c *Converter) convertNode(i int) (map[string]interface{}, error) {
// Add defined-bits-based properties
c.addDefinedBitProperties(i, kindName, node)
// TS7 doesn't set the NestedNamespace flag in the binary AST, but the Java
// extractor needs it to wrap inner namespace declarations in ExportNamedDeclaration.
// Detect nested namespaces (ModuleDeclaration whose body is another ModuleDeclaration)
// and add the flag to the inner declaration.
if kindName == "ModuleDeclaration" {
// TS7 doesn't set the NestedNamespace flag in the binary AST, but the Java
// extractor needs it to wrap inner namespace declarations in ExportNamedDeclaration.
// Detect nested namespaces (ModuleDeclaration whose body is another ModuleDeclaration)
// and add the flag to the inner declaration.
if body, ok := node["body"].(map[string]interface{}); ok {
if bodyKind, ok := body["kind"].(int); ok && bodyKind == 268 { // 268 = ModuleDeclaration
if flags, ok := body["flags"].(int); ok {
@@ -94,6 +94,19 @@ func (c *Converter) convertNode(i int) (map[string]interface{}, error) {
}
}
}
// TS7 binary AST doesn't have a GlobalAugmentation flag. Detect `declare global {}`
// by checking if the name is "global" (Identifier), and set a synthetic flag bit
// so the Java extractor can distinguish it from regular namespace declarations.
if name, ok := node["name"].(map[string]interface{}); ok {
if nameKind, ok := name["kind"].(int); ok && nameKind == 79 { // 79 = Identifier
if text, _ := name["escapedText"].(string); text == "global" {
if flags, ok := node["flags"].(int); ok {
node["flags"] = flags | (1 << 30) // synthetic GlobalAugmentation
}
}
}
}
}
return node, nil

View File

@@ -372,34 +372,40 @@ var syntaxKinds = map[string]int{
"JSDocImportTag": 344,
}
// nodeFlags maps NodeFlags names to their numeric values in TypeScript 7.
// TS7 removed the Synthesized flag, shifting all subsequent flags down by one bit
// compared to TS5. The Java extractor only checks Using, NestedNamespace, and
// GlobalAugmentation, but we include all flags for completeness.
// nodeFlags maps NodeFlags names to their numeric values sent to the Java extractor.
// The Java extractor only checks Using, NestedNamespace, and GlobalAugmentation.
//
// TS7 binary AST flag layout (differs from TS5):
// bit 0: Let, bit 1: Const, bit 2: Using, bit 3: NestedNamespace (not set in binary),
// bit 4: Namespace, bit 5: OptionalChain, bit 6: ExportContext (was GlobalAugmentation
// in TS5 at bit 11), bit 7: ContainsThis, ...
//
// GlobalAugmentation is NOT a flag in the TS7 binary format. We use a synthetic bit (30)
// that the converter sets on `declare global {}` nodes so the Java extractor can detect them.
var nodeFlags = map[string]int{
"None": 0,
"Let": 1,
"Const": 2,
"Using": 4, // Let | Const
"AwaitUsing": 6, // Using | Const
"NestedNamespace": 8, // bit 3 (TS7 binary AST doesn't set this)
"Namespace": 16, // bit 4 (was 32 in TS5)
"OptionalChain": 32, // bit 5 (was 64 in TS5)
"GlobalAugmentation": 64, // bit 6 — on `declare global { }` (was 2048 in TS5)
"ExportContext": 128, // bit 7
"ContainsThis": 256, // bit 8
"HasImplicitReturn": 512, // bit 9
"HasExplicitReturn": 1024, // bit 10
"HasAsyncFunctions": 2048, // bit 11
"DisallowInContext": 4096, // bit 12
"YieldContext": 8192, // bit 13
"DecoratorContext": 16384, // bit 14
"AwaitContext": 32768, // bit 15
"DisallowConditionalTypesContext": 65536, // bit 16
"ThisNodeHasError": 131072, // bit 17
"JavaScriptFile": 262144, // bit 18
"ThisNodeOrAnySubNodesHasError": 524288, // bit 19
"HasAggregatedChildData": 1048576, // bit 20
"NestedNamespace": 8, // bit 3 — synthetic, set by converter
"Namespace": 16, // bit 4
"OptionalChain": 32, // bit 5
"ExportContext": 64, // bit 6
"GlobalAugmentation": 1 << 30, // synthetic — set by converter for `declare global {}`
"ContainsThis": 128, // bit 7
"HasImplicitReturn": 256, // bit 8
"HasExplicitReturn": 512, // bit 9
"HasAsyncFunctions": 1024, // bit 10
"DisallowInContext": 2048, // bit 11
"YieldContext": 4096, // bit 12
"DecoratorContext": 8192, // bit 13
"AwaitContext": 16384, // bit 14
"DisallowConditionalTypesContext": 32768, // bit 15
"ThisNodeHasError": 65536, // bit 16
"JavaScriptFile": 131072, // bit 17
"ThisNodeOrAnySubNodesHasError": 262144, // bit 18
"HasAggregatedChildData": 524288, // bit 19
"JSDoc": 8388608, // bit 23
"JsonFile": 67108864, // bit 26
}