ttsc 0.18.4 → 0.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/README.md +5 -6
  2. package/cmd/graphbench/main.go +1 -1
  3. package/cmd/platform/main.go +1 -48
  4. package/cmd/ttsc/build_branches_test.go +5 -1
  5. package/cmd/ttsc/main.go +0 -50
  6. package/cmd/ttsc/main_alias_branches_test.go +6 -12
  7. package/cmd/ttscgraph/dump.go +13 -3
  8. package/cmd/ttscserver/main.go +5 -3
  9. package/driver/lsp.go +13 -1
  10. package/driver/plugins.go +35 -0
  11. package/driver/program.go +7 -8
  12. package/driver/rewrite.go +381 -21
  13. package/go.mod +1 -0
  14. package/internal/graph/build.go +297 -3
  15. package/internal/graph/build_records_a_node_per_top_level_declaration_test.go +16 -2
  16. package/internal/graph/diagnostics.go +5 -4
  17. package/internal/graph/dump.go +60 -4
  18. package/internal/graph/dump_is_a_function_of_the_source_test.go +71 -0
  19. package/internal/graph/dump_serializes_the_full_graph_test.go +16 -4
  20. package/internal/graph/edges.go +122 -11
  21. package/internal/graph/exports.go +74 -17
  22. package/internal/graph/graph.go +33 -1
  23. package/internal/graph/node_identity_is_position_invariant_test.go +4 -2
  24. package/internal/graph/resolve.go +24 -0
  25. package/internal/graphsymbols/provider.go +50 -14
  26. package/internal/lspserver/lsp_native_plugin_source.go +77 -23
  27. package/internal/lspserver/lsp_plugin.go +19 -2
  28. package/internal/lspserver/lsp_proxy.go +244 -52
  29. package/internal/lspserver/lsp_server.go +35 -27
  30. package/internal/lspserver/lsp_symbols.go +25 -16
  31. package/lib/TtscCompiler.d.ts +10 -0
  32. package/lib/TtscCompiler.js +24 -6
  33. package/lib/TtscCompiler.js.map +1 -1
  34. package/lib/TtscService.js +9 -7
  35. package/lib/TtscService.js.map +1 -1
  36. package/lib/compiler/internal/compileProjectInMemory.js +1 -0
  37. package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
  38. package/lib/compiler/internal/project/createNativeProjectContextArgs.d.ts +3 -0
  39. package/lib/compiler/internal/project/createNativeProjectContextArgs.js +14 -0
  40. package/lib/compiler/internal/project/createNativeProjectContextArgs.js.map +1 -0
  41. package/lib/compiler/internal/project/readProjectConfig.js +53 -4
  42. package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
  43. package/lib/compiler/internal/project/resolveProjectConfig.d.ts +9 -2
  44. package/lib/compiler/internal/project/resolveProjectConfig.js +45 -16
  45. package/lib/compiler/internal/project/resolveProjectConfig.js.map +1 -1
  46. package/lib/compiler/internal/residentTransformProcess.d.ts +16 -5
  47. package/lib/compiler/internal/residentTransformProcess.js +68 -20
  48. package/lib/compiler/internal/residentTransformProcess.js.map +1 -1
  49. package/lib/compiler/internal/runBuild.d.ts +11 -0
  50. package/lib/compiler/internal/runBuild.js +44 -8
  51. package/lib/compiler/internal/runBuild.js.map +1 -1
  52. package/lib/compiler/internal/runSingleFileEmit.js +7 -4
  53. package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
  54. package/lib/compiler/internal/sharedHostHelpers.d.ts +16 -0
  55. package/lib/compiler/internal/sharedHostHelpers.js +23 -0
  56. package/lib/compiler/internal/sharedHostHelpers.js.map +1 -1
  57. package/lib/compiler/internal/startResidentTransform.js +18 -1
  58. package/lib/compiler/internal/startResidentTransform.js.map +1 -1
  59. package/lib/compiler/internal/transformProjectInMemory.js +34 -8
  60. package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
  61. package/lib/flags/parser.d.ts +17 -0
  62. package/lib/flags/parser.js +11 -1
  63. package/lib/flags/parser.js.map +1 -1
  64. package/lib/flags/schema.js +7 -0
  65. package/lib/flags/schema.js.map +1 -1
  66. package/lib/launcher/internal/prepareExecution.js +21 -2
  67. package/lib/launcher/internal/prepareExecution.js.map +1 -1
  68. package/lib/launcher/internal/runTtsc.js +13 -53
  69. package/lib/launcher/internal/runTtsc.js.map +1 -1
  70. package/lib/launcher/internal/runTtscserver.js +11 -0
  71. package/lib/launcher/internal/runTtscserver.js.map +1 -1
  72. package/lib/launcher/internal/runTtsx.js +27 -11
  73. package/lib/launcher/internal/runTtsx.js.map +1 -1
  74. package/lib/launcher/internal/runtimeHooks.d.ts +81 -0
  75. package/lib/launcher/internal/runtimeHooks.js +632 -43
  76. package/lib/launcher/internal/runtimeHooks.js.map +1 -1
  77. package/lib/launcher/internal/servedSourceMap.d.ts +25 -0
  78. package/lib/launcher/internal/servedSourceMap.js +164 -0
  79. package/lib/launcher/internal/servedSourceMap.js.map +1 -0
  80. package/lib/plugin/internal/buildSourcePlugin.d.ts +146 -2
  81. package/lib/plugin/internal/buildSourcePlugin.js +651 -113
  82. package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
  83. package/lib/plugin/internal/loadProjectPlugins.d.ts +7 -0
  84. package/lib/plugin/internal/loadProjectPlugins.js +33 -10
  85. package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
  86. package/lib/structures/ITtscCompilerContext.d.ts +16 -2
  87. package/lib/structures/ITtscPluginCapabilities.d.ts +8 -0
  88. package/lib/structures/ITtscPluginFactoryContext.d.ts +14 -0
  89. package/lib/structures/internal/ITtscParsedProjectConfig.d.ts +3 -0
  90. package/lib/structures/internal/ITtscProjectIdentity.d.ts +17 -0
  91. package/lib/structures/internal/ITtscProjectIdentity.js +3 -0
  92. package/lib/structures/internal/ITtscProjectIdentity.js.map +1 -0
  93. package/lib/structures/internal/TtscCommonOptions.d.ts +8 -0
  94. package/package.json +11 -8
  95. package/shim/ast/lint.go +10 -0
  96. package/shim/ast/shim.go +44 -0
  97. package/shim/checker/enums_gen.go +19 -0
  98. package/shim/checker/shim.go +130 -0
  99. package/shim/diagnosticwriter/lint.go +30 -3
  100. package/shim/scanner/regexp.go +27 -0
  101. package/src/TtscCompiler.ts +25 -6
  102. package/src/TtscService.ts +15 -7
  103. package/src/compiler/internal/compileProjectInMemory.ts +1 -0
  104. package/src/compiler/internal/project/createNativeProjectContextArgs.ts +15 -0
  105. package/src/compiler/internal/project/readProjectConfig.ts +61 -5
  106. package/src/compiler/internal/project/resolveProjectConfig.ts +51 -21
  107. package/src/compiler/internal/residentTransformProcess.ts +95 -21
  108. package/src/compiler/internal/runBuild.ts +76 -9
  109. package/src/compiler/internal/runSingleFileEmit.ts +7 -4
  110. package/src/compiler/internal/sharedHostHelpers.ts +24 -0
  111. package/src/compiler/internal/startResidentTransform.ts +21 -1
  112. package/src/compiler/internal/transformProjectInMemory.ts +49 -6
  113. package/src/flags/parser.ts +28 -1
  114. package/src/flags/schema.ts +8 -0
  115. package/src/launcher/internal/prepareExecution.ts +22 -2
  116. package/src/launcher/internal/runTtsc.ts +13 -61
  117. package/src/launcher/internal/runTtscserver.ts +14 -0
  118. package/src/launcher/internal/runTtsx.ts +28 -13
  119. package/src/launcher/internal/runtimeHooks.ts +771 -53
  120. package/src/launcher/internal/servedSourceMap.ts +183 -0
  121. package/src/plugin/internal/buildSourcePlugin.ts +859 -122
  122. package/src/plugin/internal/loadProjectPlugins.ts +36 -6
  123. package/src/structures/ITtscCompilerContext.ts +17 -2
  124. package/src/structures/ITtscPluginCapabilities.ts +9 -0
  125. package/src/structures/ITtscPluginFactoryContext.ts +15 -0
  126. package/src/structures/internal/ITtscParsedProjectConfig.ts +3 -0
  127. package/src/structures/internal/ITtscProjectIdentity.ts +17 -0
  128. package/src/structures/internal/TtscCommonOptions.ts +8 -0
  129. package/tools/shim_audit/baseline.json +16 -7
  130. package/tools/shim_audit/main.go +777 -71
  131. package/tools/shim_audit/main_test.go +28 -1
  132. package/tools/shim_audit/producer_exemptions_require_rationale_test.go +42 -0
  133. package/tools/shim_audit/producer_surface_includes_exposed_methods_test.go +154 -0
  134. package/tools/shim_audit/producer_surface_rejects_unproducible_reference_test.go +142 -0
  135. package/utility/host.go +46 -20
  136. package/utility/serve.go +1 -1
  137. package/shim/checker/signature_api_completeness.go +0 -58
package/driver/rewrite.go CHANGED
@@ -23,13 +23,19 @@ import (
23
23
  "strings"
24
24
  "sync"
25
25
  "unicode"
26
+ "unicode/utf8"
26
27
 
27
28
  "github.com/microsoft/typescript-go/shim/ast"
28
29
  shimcompiler "github.com/microsoft/typescript-go/shim/compiler"
30
+ shimcore "github.com/microsoft/typescript-go/shim/core"
31
+ shimparser "github.com/microsoft/typescript-go/shim/parser"
29
32
  )
30
33
 
31
34
  // Rewrite describes one emit-time patch. Produced by CollectCallSites after
32
- // the engine has generated a replacement JS fragment for the call.
35
+ // the engine has generated a replacement JS fragment for the call. When
36
+ // RootName names a default or namespace import, emit resolves it through the
37
+ // matching emitted require declaration, including any collision suffix chosen
38
+ // by TypeScript-Go.
33
39
  type Rewrite struct {
34
40
  File *ast.SourceFile
35
41
  RootName string
@@ -232,12 +238,25 @@ func applyRewrites(outputName, text string, rs *RewriteSet, cursors map[string]i
232
238
  return text, nil
233
239
  }
234
240
  rewrites := rs.byPath[srcPath]
241
+ emittedBindings := map[string][]emittedImportBinding{}
242
+ for _, rewrite := range rewrites {
243
+ if _, imported := sourceImportForRoot(rewrite.File, rewrite.RootName); imported {
244
+ emittedBindings = collectEmittedImportBindings(outputName, text)
245
+ break
246
+ }
247
+ }
235
248
  pos := cursors[srcPath]
236
249
  out := text
237
250
  searchFrom := 0
251
+ aliasesByRoot := map[string][]string{}
238
252
  for pos < len(rewrites) {
239
253
  r := rewrites[pos]
240
- replaced, nextSearchFrom, ok, err := spliceCall(out, r, searchFrom)
254
+ aliases, cached := aliasesByRoot[r.RootName]
255
+ if !cached {
256
+ aliases = rewriteAliases(r, emittedBindings)
257
+ aliasesByRoot[r.RootName] = aliases
258
+ }
259
+ replaced, nextSearchFrom, ok, err := spliceCallWithAliases(out, r, aliases, searchFrom)
241
260
  if err != nil {
242
261
  return "", err
243
262
  }
@@ -246,7 +265,7 @@ func applyRewrites(outputName, text string, rs *RewriteSet, cursors map[string]i
246
265
  if len(preview) > 400 {
247
266
  preview = preview[:400] + "…"
248
267
  }
249
- return "", fmt.Errorf("driver: could not locate %s.%s(…) call in %s (tried roots %v; preview: %q)", joinRootAndNamespaces(r), r.Method, outputName, candidateRoots(r.RootName), preview)
268
+ return "", fmt.Errorf("driver: could not locate %s.%s(…) call in %s (tried roots %v; preview: %q)", joinRootAndNamespaces(r), r.Method, outputName, aliases, preview)
250
269
  }
251
270
  out = replaced
252
271
  searchFrom = nextSearchFrom
@@ -348,7 +367,15 @@ func sourceTail(srcPath, commonDir string) string {
348
367
  // Returns the patched text, the byte position to resume from on the next
349
368
  // call, a found flag, and any error from the paren-matching step.
350
369
  func spliceCall(text string, r Rewrite, searchFrom int) (string, int, bool, error) {
351
- aliases := candidateRoots(r.RootName)
370
+ emittedBindings := map[string][]emittedImportBinding{}
371
+ if _, imported := sourceImportForRoot(r.File, r.RootName); imported {
372
+ emittedBindings = collectEmittedImportBindings("/rewrite.js", text)
373
+ }
374
+ aliases := rewriteAliases(r, emittedBindings)
375
+ return spliceCallWithAliases(text, r, aliases, searchFrom)
376
+ }
377
+
378
+ func spliceCallWithAliases(text string, r Rewrite, aliases []string, searchFrom int) (string, int, bool, error) {
352
379
  pattern := callRegexFor(aliases, r.Namespaces, r.Method)
353
380
  idx, needleLen := findCallMatch(text, pattern, searchFrom)
354
381
  if idx < 0 {
@@ -367,6 +394,349 @@ func spliceCall(text string, r Rewrite, searchFrom int) (string, int, bool, erro
367
394
  return replaced, idx + len(r.Replacement), true, nil
368
395
  }
369
396
 
397
+ // collectEmittedImportBindings recovers the identifiers TypeScript-Go
398
+ // actually assigned to top-level CommonJS imports in one emitted JavaScript
399
+ // file. The source-level import name is not enough: the emitter owns collision
400
+ // suffixes and may choose any free number. Parsing the emitted declarations
401
+ // keeps alias discovery coupled to that output instead of guessing a maximum.
402
+ type emittedImportKind uint8
403
+
404
+ const (
405
+ emittedImportDirect emittedImportKind = iota
406
+ emittedImportDefault
407
+ emittedImportNamespace
408
+ emittedImportRetainedDefault
409
+ emittedImportRetainedNamespace
410
+ )
411
+
412
+ type emittedImportBinding struct {
413
+ name string
414
+ kind emittedImportKind
415
+ }
416
+
417
+ func collectEmittedImportBindings(outputName, text string) map[string][]emittedImportBinding {
418
+ parseName := filepath.ToSlash(outputName)
419
+ if !filepath.IsAbs(outputName) {
420
+ parseName = "/" + strings.TrimPrefix(parseName, "/")
421
+ }
422
+ file := shimparser.ParseSourceFile(ast.SourceFileParseOptions{FileName: parseName}, text, shimcore.ScriptKindJS)
423
+ bindings := map[string][]emittedImportBinding{}
424
+ if file == nil || file.Statements == nil {
425
+ return bindings
426
+ }
427
+ for _, statement := range file.Statements.Nodes {
428
+ if statement == nil {
429
+ continue
430
+ }
431
+ if statement.Kind == ast.KindImportDeclaration {
432
+ collectRetainedImportBinding(bindings, statement.AsImportDeclaration())
433
+ continue
434
+ }
435
+ if statement.Kind != ast.KindVariableStatement {
436
+ continue
437
+ }
438
+ variables := statement.AsVariableStatement()
439
+ if variables == nil || variables.DeclarationList == nil {
440
+ continue
441
+ }
442
+ declarations := variables.DeclarationList.AsVariableDeclarationList()
443
+ if declarations == nil || declarations.Declarations == nil {
444
+ continue
445
+ }
446
+ for _, declaration := range declarations.Declarations.Nodes {
447
+ if declaration == nil {
448
+ continue
449
+ }
450
+ variable := declaration.AsVariableDeclaration()
451
+ if variable == nil {
452
+ continue
453
+ }
454
+ name := identifierName(variable.Name())
455
+ module, kind, ok := emittedRequireModule(variable.Initializer)
456
+ if name == "" || !ok {
457
+ continue
458
+ }
459
+ bindings[module] = append(bindings[module], emittedImportBinding{name: name, kind: kind})
460
+ }
461
+ }
462
+ return bindings
463
+ }
464
+
465
+ func collectRetainedImportBinding(bindings map[string][]emittedImportBinding, declaration *ast.ImportDeclaration) {
466
+ if declaration == nil || declaration.ImportClause == nil {
467
+ return
468
+ }
469
+ module, ok := stringLiteralValue(declaration.ModuleSpecifier)
470
+ if !ok {
471
+ return
472
+ }
473
+ clause := declaration.ImportClause.AsImportClause()
474
+ if clause == nil {
475
+ return
476
+ }
477
+ if name := identifierName(clause.Name()); name != "" {
478
+ bindings[module] = append(bindings[module], emittedImportBinding{name: name, kind: emittedImportRetainedDefault})
479
+ }
480
+ if clause.NamedBindings == nil || clause.NamedBindings.Kind != ast.KindNamespaceImport {
481
+ return
482
+ }
483
+ namespace := clause.NamedBindings.AsNamespaceImport()
484
+ if namespace == nil {
485
+ return
486
+ }
487
+ if name := identifierName(namespace.Name()); name != "" {
488
+ bindings[module] = append(bindings[module], emittedImportBinding{name: name, kind: emittedImportRetainedNamespace})
489
+ }
490
+ }
491
+
492
+ // emittedRequireModule recognizes the declaration shapes TypeScript-Go owns
493
+ // for CommonJS imports: a direct require or a require wrapped in its
494
+ // __importDefault/__importStar helper. User calls with other wrappers are not
495
+ // import declarations and therefore cannot become rewrite aliases.
496
+ func emittedRequireModule(node *ast.Node) (string, emittedImportKind, bool) {
497
+ node = unwrapParentheses(node)
498
+ if node == nil || node.Kind != ast.KindCallExpression {
499
+ return "", emittedImportDirect, false
500
+ }
501
+ call := node.AsCallExpression()
502
+ if call == nil || call.QuestionDotToken != nil || call.Arguments == nil || len(call.Arguments.Nodes) != 1 {
503
+ return "", emittedImportDirect, false
504
+ }
505
+ if identifierName(call.Expression) == "require" {
506
+ module, ok := stringLiteralValue(call.Arguments.Nodes[0])
507
+ return module, emittedImportDirect, ok
508
+ }
509
+ helper := callExpressionName(call.Expression)
510
+ if helper != "__importDefault" && helper != "__importStar" {
511
+ return "", emittedImportDirect, false
512
+ }
513
+ module, _, ok := emittedRequireModule(call.Arguments.Nodes[0])
514
+ if !ok {
515
+ return "", emittedImportDirect, false
516
+ }
517
+ if helper == "__importDefault" {
518
+ return module, emittedImportDefault, true
519
+ }
520
+ return module, emittedImportNamespace, true
521
+ }
522
+
523
+ func callExpressionName(node *ast.Node) string {
524
+ node = unwrapParentheses(node)
525
+ if name := identifierName(node); name != "" {
526
+ return name
527
+ }
528
+ if node == nil || node.Kind != ast.KindPropertyAccessExpression {
529
+ return ""
530
+ }
531
+ access := node.AsPropertyAccessExpression()
532
+ if access == nil {
533
+ return ""
534
+ }
535
+ return identifierName(access.Name())
536
+ }
537
+
538
+ func unwrapParentheses(node *ast.Node) *ast.Node {
539
+ for node != nil && node.Kind == ast.KindParenthesizedExpression {
540
+ expression := node.AsParenthesizedExpression()
541
+ if expression == nil || expression.Expression == nil {
542
+ return nil
543
+ }
544
+ node = expression.Expression
545
+ }
546
+ return node
547
+ }
548
+
549
+ func identifierName(node *ast.Node) string {
550
+ if node == nil || node.Kind != ast.KindIdentifier {
551
+ return ""
552
+ }
553
+ identifier := node.AsIdentifier()
554
+ if identifier == nil {
555
+ return ""
556
+ }
557
+ return identifier.Text
558
+ }
559
+
560
+ func stringLiteralValue(node *ast.Node) (string, bool) {
561
+ if node == nil || node.Kind != ast.KindStringLiteral {
562
+ return "", false
563
+ }
564
+ literal := node.AsStringLiteral()
565
+ if literal == nil {
566
+ return "", false
567
+ }
568
+ return literal.Text, true
569
+ }
570
+
571
+ // rewriteAliases binds one source import to the identifiers recovered from its
572
+ // emitted require declaration. Retained ESM imports and non-import roots keep
573
+ // their source spelling; CommonJS imports use only emitter-owned bindings so a
574
+ // nearby identifier cannot be mistaken for the plugin call.
575
+ type sourceImportKind uint8
576
+
577
+ const (
578
+ sourceImportDefault sourceImportKind = iota
579
+ sourceImportNamespace
580
+ sourceImportEquals
581
+ )
582
+
583
+ type sourceImport struct {
584
+ module string
585
+ kind sourceImportKind
586
+ }
587
+
588
+ func rewriteAliases(r Rewrite, emittedBindings map[string][]emittedImportBinding) []string {
589
+ imported, ok := sourceImportForRoot(r.File, r.RootName)
590
+ if !ok {
591
+ return []string{r.RootName + ".default", r.RootName}
592
+ }
593
+ retainedKind := emittedImportRetainedDefault
594
+ if imported.kind == sourceImportNamespace {
595
+ retainedKind = emittedImportRetainedNamespace
596
+ }
597
+ if imported.kind != sourceImportEquals {
598
+ for _, binding := range emittedBindings[imported.module] {
599
+ if binding.name == r.RootName && binding.kind == retainedKind {
600
+ return []string{r.RootName}
601
+ }
602
+ }
603
+ }
604
+ candidates := []emittedImportBinding{}
605
+ preferred := []emittedImportBinding{}
606
+ sourceBindings := sourceTopLevelVariableNames(r.File)
607
+ wantKind := emittedImportDirect
608
+ switch imported.kind {
609
+ case sourceImportDefault:
610
+ wantKind = emittedImportDefault
611
+ case sourceImportNamespace:
612
+ wantKind = emittedImportNamespace
613
+ }
614
+ for _, binding := range emittedBindings[imported.module] {
615
+ if _, sourceOwned := sourceBindings[binding.name]; sourceOwned {
616
+ continue
617
+ }
618
+ if !emittedNameForRoot(binding.name, r.RootName) {
619
+ continue
620
+ }
621
+ candidates = append(candidates, binding)
622
+ if binding.kind == wantKind {
623
+ preferred = append(preferred, binding)
624
+ }
625
+ }
626
+ var binding emittedImportBinding
627
+ switch {
628
+ case len(preferred) == 1:
629
+ binding = preferred[0]
630
+ case len(preferred) > 1:
631
+ return []string{r.RootName}
632
+ case len(candidates) == 1:
633
+ binding = candidates[0]
634
+ case len(candidates) > 1:
635
+ return []string{r.RootName}
636
+ default:
637
+ // An ESM emit retains the source binding instead of creating a require.
638
+ return []string{r.RootName}
639
+ }
640
+ if imported.kind == sourceImportDefault {
641
+ return []string{binding.name + ".default"}
642
+ }
643
+ return []string{binding.name}
644
+ }
645
+
646
+ func sourceImportForRoot(file *ast.SourceFile, root string) (sourceImport, bool) {
647
+ if file == nil || file.Statements == nil {
648
+ return sourceImport{}, false
649
+ }
650
+ for _, statement := range file.Statements.Nodes {
651
+ if statement == nil {
652
+ continue
653
+ }
654
+ switch statement.Kind {
655
+ case ast.KindImportDeclaration:
656
+ declaration := statement.AsImportDeclaration()
657
+ if declaration == nil || declaration.ImportClause == nil {
658
+ continue
659
+ }
660
+ clause := declaration.ImportClause.AsImportClause()
661
+ if clause == nil {
662
+ continue
663
+ }
664
+ if identifierName(clause.Name()) == root {
665
+ module, ok := stringLiteralValue(declaration.ModuleSpecifier)
666
+ return sourceImport{module: module, kind: sourceImportDefault}, ok
667
+ }
668
+ if clause.NamedBindings != nil && clause.NamedBindings.Kind == ast.KindNamespaceImport {
669
+ namespace := clause.NamedBindings.AsNamespaceImport()
670
+ if namespace != nil && identifierName(namespace.Name()) == root {
671
+ module, ok := stringLiteralValue(declaration.ModuleSpecifier)
672
+ return sourceImport{module: module, kind: sourceImportNamespace}, ok
673
+ }
674
+ }
675
+ case ast.KindImportEqualsDeclaration:
676
+ declaration := statement.AsImportEqualsDeclaration()
677
+ if declaration == nil || identifierName(declaration.Name()) != root || declaration.ModuleReference == nil ||
678
+ declaration.ModuleReference.Kind != ast.KindExternalModuleReference {
679
+ continue
680
+ }
681
+ reference := declaration.ModuleReference.AsExternalModuleReference()
682
+ if reference != nil {
683
+ module, ok := stringLiteralValue(reference.Expression)
684
+ return sourceImport{module: module, kind: sourceImportEquals}, ok
685
+ }
686
+ }
687
+ }
688
+ return sourceImport{}, false
689
+ }
690
+
691
+ func sourceTopLevelVariableNames(file *ast.SourceFile) map[string]struct{} {
692
+ names := map[string]struct{}{}
693
+ if file == nil || file.Statements == nil {
694
+ return names
695
+ }
696
+ for _, statement := range file.Statements.Nodes {
697
+ if statement == nil || statement.Kind != ast.KindVariableStatement {
698
+ continue
699
+ }
700
+ variables := statement.AsVariableStatement()
701
+ if variables == nil || variables.DeclarationList == nil {
702
+ continue
703
+ }
704
+ declarations := variables.DeclarationList.AsVariableDeclarationList()
705
+ if declarations == nil || declarations.Declarations == nil {
706
+ continue
707
+ }
708
+ for _, declaration := range declarations.Declarations.Nodes {
709
+ if declaration == nil {
710
+ continue
711
+ }
712
+ variable := declaration.AsVariableDeclaration()
713
+ if variable == nil {
714
+ continue
715
+ }
716
+ if name := identifierName(variable.Name()); name != "" {
717
+ names[name] = struct{}{}
718
+ }
719
+ }
720
+ }
721
+ return names
722
+ }
723
+
724
+ func emittedNameForRoot(name, root string) bool {
725
+ if name == root {
726
+ return true
727
+ }
728
+ suffix := strings.TrimPrefix(name, root+"_")
729
+ if suffix == "" || suffix == name {
730
+ return false
731
+ }
732
+ for _, ch := range suffix {
733
+ if ch < '0' || ch > '9' {
734
+ return false
735
+ }
736
+ }
737
+ return true
738
+ }
739
+
370
740
  // callRegexFor compiles the loose-match needle pattern used by spliceCall.
371
741
  //
372
742
  // tsgo's emitter preserves source line breaks in property-access chains, so a
@@ -427,7 +797,13 @@ func findCallMatch(text string, pattern *regexp.Regexp, searchFrom int) (int, in
427
797
  }
428
798
  matchStart := start + loc[0]
429
799
  parenStart := start + loc[2]
430
- if matchStart > 0 && isIdentifierPart(rune(text[matchStart-1])) {
800
+ // Decode the whole preceding rune rather than widening the single byte at
801
+ // text[matchStart-1]: for a multi-byte identifier char (e.g. `й`, `한`, an
802
+ // astral letter) that byte is a UTF-8 continuation/lead byte, not the
803
+ // character, so the boundary guard would be bypassed and the rewriter would
804
+ // splice into the middle of a larger identifier.
805
+ prev, _ := utf8.DecodeLastRuneInString(text[:matchStart])
806
+ if matchStart > 0 && isIdentifierPart(prev) {
431
807
  start = matchStart + 1
432
808
  continue
433
809
  }
@@ -436,22 +812,6 @@ func findCallMatch(text string, pattern *regexp.Regexp, searchFrom int) (int, in
436
812
  return -1, 0
437
813
  }
438
814
 
439
- // candidateRoots expands a bare module name into the set of identifier stems
440
- // tsgo's CommonJS emitter may produce for it. For example "typia" becomes
441
- // ["typia", "typia_1.default", "typia_2.default", "typia.default",
442
- // "typia_1", "typia_2"]. The regex alternation built from these candidates
443
- // matches the emitted call regardless of which deduplication suffix tsgo chose.
444
- func candidateRoots(root string) []string {
445
- return []string{
446
- root,
447
- root + "_1.default",
448
- root + "_2.default",
449
- root + ".default",
450
- root + "_1",
451
- root + "_2",
452
- }
453
- }
454
-
455
815
  // joinRootAndNamespaces returns the human-readable "root.ns1.ns2" form of
456
816
  // the rewrite's call head, used in error messages only.
457
817
  func joinRootAndNamespaces(r Rewrite) string {
package/go.mod CHANGED
@@ -31,6 +31,7 @@ require (
31
31
  github.com/microsoft/typescript-go/shim/compiler v0.0.0
32
32
  github.com/microsoft/typescript-go/shim/core v0.0.0
33
33
  github.com/microsoft/typescript-go/shim/diagnosticwriter v0.0.0
34
+ github.com/microsoft/typescript-go/shim/parser v0.0.0
34
35
  github.com/microsoft/typescript-go/shim/printer v0.0.0
35
36
  github.com/microsoft/typescript-go/shim/scanner v0.0.0
36
37
  github.com/microsoft/typescript-go/shim/tsoptions v0.0.0