ttsc 0.18.4 → 0.19.0
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.
- package/README.md +5 -6
- package/cmd/graphbench/main.go +1 -1
- package/cmd/platform/main.go +1 -48
- package/cmd/ttsc/build_branches_test.go +5 -1
- package/cmd/ttsc/main.go +0 -50
- package/cmd/ttsc/main_alias_branches_test.go +6 -12
- package/cmd/ttscgraph/dump.go +13 -3
- package/cmd/ttscserver/main.go +5 -3
- package/driver/lsp.go +13 -1
- package/driver/plugins.go +35 -0
- package/driver/program.go +7 -8
- package/driver/rewrite.go +381 -21
- package/go.mod +1 -0
- package/internal/graph/build.go +297 -3
- package/internal/graph/build_records_a_node_per_top_level_declaration_test.go +16 -2
- package/internal/graph/diagnostics.go +5 -4
- package/internal/graph/dump.go +60 -4
- package/internal/graph/dump_is_a_function_of_the_source_test.go +71 -0
- package/internal/graph/dump_serializes_the_full_graph_test.go +16 -4
- package/internal/graph/edges.go +122 -11
- package/internal/graph/exports.go +74 -17
- package/internal/graph/graph.go +33 -1
- package/internal/graph/node_identity_is_position_invariant_test.go +4 -2
- package/internal/graph/resolve.go +24 -0
- package/internal/graphsymbols/provider.go +50 -14
- package/internal/lspserver/lsp_native_plugin_source.go +77 -23
- package/internal/lspserver/lsp_plugin.go +19 -2
- package/internal/lspserver/lsp_proxy.go +244 -52
- package/internal/lspserver/lsp_server.go +35 -27
- package/internal/lspserver/lsp_symbols.go +25 -16
- package/lib/TtscCompiler.d.ts +10 -0
- package/lib/TtscCompiler.js +24 -6
- package/lib/TtscCompiler.js.map +1 -1
- package/lib/TtscService.js +9 -7
- package/lib/TtscService.js.map +1 -1
- package/lib/compiler/internal/compileProjectInMemory.js +1 -0
- package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/project/createNativeProjectContextArgs.d.ts +3 -0
- package/lib/compiler/internal/project/createNativeProjectContextArgs.js +14 -0
- package/lib/compiler/internal/project/createNativeProjectContextArgs.js.map +1 -0
- package/lib/compiler/internal/project/readProjectConfig.js +53 -4
- package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
- package/lib/compiler/internal/project/resolveProjectConfig.d.ts +9 -2
- package/lib/compiler/internal/project/resolveProjectConfig.js +45 -16
- package/lib/compiler/internal/project/resolveProjectConfig.js.map +1 -1
- package/lib/compiler/internal/residentTransformProcess.d.ts +16 -5
- package/lib/compiler/internal/residentTransformProcess.js +68 -20
- package/lib/compiler/internal/residentTransformProcess.js.map +1 -1
- package/lib/compiler/internal/runBuild.d.ts +11 -0
- package/lib/compiler/internal/runBuild.js +44 -8
- package/lib/compiler/internal/runBuild.js.map +1 -1
- package/lib/compiler/internal/runSingleFileEmit.js +7 -4
- package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
- package/lib/compiler/internal/sharedHostHelpers.d.ts +16 -0
- package/lib/compiler/internal/sharedHostHelpers.js +23 -0
- package/lib/compiler/internal/sharedHostHelpers.js.map +1 -1
- package/lib/compiler/internal/startResidentTransform.js +18 -1
- package/lib/compiler/internal/startResidentTransform.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js +34 -8
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/flags/parser.d.ts +17 -0
- package/lib/flags/parser.js +11 -1
- package/lib/flags/parser.js.map +1 -1
- package/lib/flags/schema.js +7 -0
- package/lib/flags/schema.js.map +1 -1
- package/lib/launcher/internal/prepareExecution.js +21 -2
- package/lib/launcher/internal/prepareExecution.js.map +1 -1
- package/lib/launcher/internal/runTtsc.js +13 -53
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runTtscserver.js +11 -0
- package/lib/launcher/internal/runTtscserver.js.map +1 -1
- package/lib/launcher/internal/runTtsx.js +27 -11
- package/lib/launcher/internal/runTtsx.js.map +1 -1
- package/lib/launcher/internal/runtimeHooks.d.ts +81 -0
- package/lib/launcher/internal/runtimeHooks.js +632 -43
- package/lib/launcher/internal/runtimeHooks.js.map +1 -1
- package/lib/launcher/internal/servedSourceMap.d.ts +25 -0
- package/lib/launcher/internal/servedSourceMap.js +164 -0
- package/lib/launcher/internal/servedSourceMap.js.map +1 -0
- package/lib/plugin/internal/buildSourcePlugin.d.ts +146 -2
- package/lib/plugin/internal/buildSourcePlugin.js +651 -113
- package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/loadProjectPlugins.d.ts +7 -0
- package/lib/plugin/internal/loadProjectPlugins.js +33 -10
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/lib/structures/ITtscCompilerContext.d.ts +16 -2
- package/lib/structures/ITtscPluginCapabilities.d.ts +8 -0
- package/lib/structures/ITtscPluginFactoryContext.d.ts +14 -0
- package/lib/structures/internal/ITtscParsedProjectConfig.d.ts +3 -0
- package/lib/structures/internal/ITtscProjectIdentity.d.ts +17 -0
- package/lib/structures/internal/ITtscProjectIdentity.js +3 -0
- package/lib/structures/internal/ITtscProjectIdentity.js.map +1 -0
- package/lib/structures/internal/TtscCommonOptions.d.ts +8 -0
- package/package.json +11 -8
- package/shim/ast/lint.go +10 -0
- package/shim/ast/shim.go +44 -0
- package/shim/checker/enums_gen.go +19 -0
- package/shim/checker/shim.go +130 -0
- package/shim/diagnosticwriter/lint.go +30 -3
- package/shim/scanner/regexp.go +27 -0
- package/src/TtscCompiler.ts +25 -6
- package/src/TtscService.ts +15 -7
- package/src/compiler/internal/compileProjectInMemory.ts +1 -0
- package/src/compiler/internal/project/createNativeProjectContextArgs.ts +15 -0
- package/src/compiler/internal/project/readProjectConfig.ts +61 -5
- package/src/compiler/internal/project/resolveProjectConfig.ts +51 -21
- package/src/compiler/internal/residentTransformProcess.ts +95 -21
- package/src/compiler/internal/runBuild.ts +76 -9
- package/src/compiler/internal/runSingleFileEmit.ts +7 -4
- package/src/compiler/internal/sharedHostHelpers.ts +24 -0
- package/src/compiler/internal/startResidentTransform.ts +21 -1
- package/src/compiler/internal/transformProjectInMemory.ts +49 -6
- package/src/flags/parser.ts +28 -1
- package/src/flags/schema.ts +8 -0
- package/src/launcher/internal/prepareExecution.ts +22 -2
- package/src/launcher/internal/runTtsc.ts +13 -61
- package/src/launcher/internal/runTtscserver.ts +14 -0
- package/src/launcher/internal/runTtsx.ts +28 -13
- package/src/launcher/internal/runtimeHooks.ts +771 -53
- package/src/launcher/internal/servedSourceMap.ts +183 -0
- package/src/plugin/internal/buildSourcePlugin.ts +859 -122
- package/src/plugin/internal/loadProjectPlugins.ts +36 -6
- package/src/structures/ITtscCompilerContext.ts +17 -2
- package/src/structures/ITtscPluginCapabilities.ts +9 -0
- package/src/structures/ITtscPluginFactoryContext.ts +15 -0
- package/src/structures/internal/ITtscParsedProjectConfig.ts +3 -0
- package/src/structures/internal/ITtscProjectIdentity.ts +17 -0
- package/src/structures/internal/TtscCommonOptions.ts +8 -0
- package/tools/shim_audit/baseline.json +16 -7
- package/tools/shim_audit/main.go +777 -71
- package/tools/shim_audit/main_test.go +28 -1
- package/tools/shim_audit/producer_exemptions_require_rationale_test.go +42 -0
- package/tools/shim_audit/producer_surface_includes_exposed_methods_test.go +154 -0
- package/tools/shim_audit/producer_surface_rejects_unproducible_reference_test.go +142 -0
- package/utility/host.go +46 -20
- package/utility/serve.go +1 -1
- 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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|