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
|
@@ -5,6 +5,8 @@ import (
|
|
|
5
5
|
"go/types"
|
|
6
6
|
"reflect"
|
|
7
7
|
"testing"
|
|
8
|
+
|
|
9
|
+
"golang.org/x/tools/go/packages"
|
|
8
10
|
)
|
|
9
11
|
|
|
10
12
|
// TestLinknameRe pins the two //go:linkname target shapes the reachability scan
|
|
@@ -65,7 +67,7 @@ func TestDedupe(t *testing.T) {
|
|
|
65
67
|
|
|
66
68
|
// TestTierOf pins the kind→tier mapping the gate and report depend on.
|
|
67
69
|
func TestTierOf(t *testing.T) {
|
|
68
|
-
cases := map[string]int{"ENUM": 1, "FUNC": 2, "ESCAPE": 3, "ENUM?": 4, "UNEXPORTED": 4}
|
|
70
|
+
cases := map[string]int{"ENUM": 1, "FUNC": 2, "PRODUCER": 2, "ESCAPE": 3, "ENUM?": 4, "UNEXPORTED": 4}
|
|
69
71
|
for kind, want := range cases {
|
|
70
72
|
if got := tierOf(kind); got != want {
|
|
71
73
|
t.Errorf("tierOf(%q) = %d, want %d", kind, got, want)
|
|
@@ -73,6 +75,31 @@ func TestTierOf(t *testing.T) {
|
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
|
|
78
|
+
// TestIndexInternalPackages proves dependency-only internal type packages stay
|
|
79
|
+
// available to the named producer-contract scanner and load failures stay fatal.
|
|
80
|
+
func TestIndexInternalPackages(t *testing.T) {
|
|
81
|
+
dependencyTypes := types.NewPackage(internalPrefix+"lsp/lsproto", "lsproto")
|
|
82
|
+
dependency := &packages.Package{
|
|
83
|
+
PkgPath: internalPrefix + "lsp/lsproto",
|
|
84
|
+
Types: dependencyTypes,
|
|
85
|
+
}
|
|
86
|
+
root := &packages.Package{
|
|
87
|
+
PkgPath: internalPrefix + "lsp",
|
|
88
|
+
Types: types.NewPackage(internalPrefix+"lsp", "lsp"),
|
|
89
|
+
Imports: map[string]*packages.Package{dependency.PkgPath: dependency},
|
|
90
|
+
}
|
|
91
|
+
indexed, errored := indexInternalPackages([]*packages.Package{root})
|
|
92
|
+
if indexed["lsp"] != root || indexed["lsp/lsproto"] != dependency || len(errored) != 0 {
|
|
93
|
+
t.Fatalf("indexed=%+v errored=%+v, want root and dependency", indexed, errored)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
dependency.Types = nil
|
|
97
|
+
indexed, errored = indexInternalPackages([]*packages.Package{root})
|
|
98
|
+
if indexed["lsp/lsproto"] != nil || errored["lsp/lsproto"] == "" {
|
|
99
|
+
t.Fatalf("failed dependency indexed=%+v errored=%+v, want closed failure", indexed, errored)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
76
103
|
// TestCommonPrefix covers the helper feeding the abbreviation fallback.
|
|
77
104
|
func TestCommonPrefix(t *testing.T) {
|
|
78
105
|
cases := []struct {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import "testing"
|
|
4
|
+
|
|
5
|
+
// Verifies producer exemptions require a non-empty rationale.
|
|
6
|
+
//
|
|
7
|
+
// Producer gaps use a separate zero-tolerance path so an ordinary accepted gap
|
|
8
|
+
// or an empty placeholder cannot silently classify compiler state as a root.
|
|
9
|
+
//
|
|
10
|
+
// 1. Evaluate the same producer gap with no exemption and an empty exemption.
|
|
11
|
+
// 2. Supply a reasoned public-root exemption and accept the unrelated function gap.
|
|
12
|
+
// 3. Confirm only the deliberate classification passes both gate classes.
|
|
13
|
+
func TestProducerExemptionsRequireRationale(t *testing.T) {
|
|
14
|
+
surface := newProducerSurface()
|
|
15
|
+
surface.add(flowConsume, flowType{pkg: "fixture", name: "Root"}, "fixture.UseRoot")
|
|
16
|
+
functionGap := finding{kind: "FUNC", pkg: "fixture", symbol: "Reachable"}
|
|
17
|
+
|
|
18
|
+
absentProducer := evaluateProducerSurface(surface, nil)
|
|
19
|
+
absent := evaluateBaseline(append(absentProducer.gaps, functionGap), baselineFile{}, absentProducer.usedRoots)
|
|
20
|
+
if len(absent.producerGaps) != 1 || len(absent.newGaps) != 1 {
|
|
21
|
+
t.Fatalf("absent exemption evaluation = %+v", absent)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
emptyBaseline := baselineFile{
|
|
25
|
+
ProducerExemptions: map[string]string{"fixture.Root": " "},
|
|
26
|
+
}
|
|
27
|
+
emptyProducer := evaluateProducerSurface(surface, emptyBaseline.ProducerExemptions)
|
|
28
|
+
empty := evaluateBaseline(append(emptyProducer.gaps, functionGap), emptyBaseline, emptyProducer.usedRoots)
|
|
29
|
+
if len(empty.producerGaps) != 1 || len(empty.invalidReasons) != 1 {
|
|
30
|
+
t.Fatalf("empty exemption evaluation = %+v", empty)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
reasonedBaseline := baselineFile{
|
|
34
|
+
Accepted: []string{"FUNC|fixture|Reachable"},
|
|
35
|
+
ProducerExemptions: map[string]string{"fixture.Root": "Caller-owned configuration object."},
|
|
36
|
+
}
|
|
37
|
+
reasonedProducer := evaluateProducerSurface(surface, reasonedBaseline.ProducerExemptions)
|
|
38
|
+
reasoned := evaluateBaseline(append(reasonedProducer.gaps, functionGap), reasonedBaseline, reasonedProducer.usedRoots)
|
|
39
|
+
if len(reasoned.producerGaps) != 0 || len(reasoned.newGaps) != 0 || len(reasoned.invalidReasons) != 0 {
|
|
40
|
+
t.Fatalf("reasoned exemption evaluation = %+v", reasoned)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"go/token"
|
|
5
|
+
"go/types"
|
|
6
|
+
"testing"
|
|
7
|
+
|
|
8
|
+
"golang.org/x/tools/go/packages"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// Verifies producer closure includes exported methods and canonical type aliases.
|
|
12
|
+
//
|
|
13
|
+
// Shim aliases publish upstream method sets without source declarations, while
|
|
14
|
+
// aliases such as Expression and Node can spell the same compiler object twice.
|
|
15
|
+
//
|
|
16
|
+
// 1. Build a rooted exposed owner with consumer and producer methods.
|
|
17
|
+
// 2. Remove the producer and confirm direct and named-callback inputs become a gap.
|
|
18
|
+
// 3. Confirm an alias and canonical producer close the same object edge.
|
|
19
|
+
// 4. Remove the receiver root and confirm its result no longer counts.
|
|
20
|
+
// 5. Restore it explicitly, then prove a rootless self-cycle still fails.
|
|
21
|
+
// 6. Prove reachable receivers do not legitimize argument/result cycles.
|
|
22
|
+
func TestProducerSurfaceIncludesExposedMethods(t *testing.T) {
|
|
23
|
+
build := func(includeProducer bool) (reachable, map[string]*packages.Package) {
|
|
24
|
+
pkg := types.NewPackage(internalPrefix+"fixture", "fixture")
|
|
25
|
+
tokenName := types.NewTypeName(token.NoPos, pkg, "Token", nil)
|
|
26
|
+
tokenType := types.NewNamed(tokenName, types.NewStruct(nil, nil), nil)
|
|
27
|
+
pkg.Scope().Insert(tokenName)
|
|
28
|
+
ownerName := types.NewTypeName(token.NoPos, pkg, "Owner", nil)
|
|
29
|
+
ownerType := types.NewNamed(ownerName, types.NewStruct(nil, nil), nil)
|
|
30
|
+
pkg.Scope().Insert(ownerName)
|
|
31
|
+
receiver := types.NewVar(token.NoPos, pkg, "owner", types.NewPointer(ownerType))
|
|
32
|
+
consume := types.NewSignatureType(
|
|
33
|
+
receiver,
|
|
34
|
+
nil,
|
|
35
|
+
nil,
|
|
36
|
+
types.NewTuple(types.NewVar(token.NoPos, pkg, "value", types.NewPointer(tokenType))),
|
|
37
|
+
types.NewTuple(),
|
|
38
|
+
false,
|
|
39
|
+
)
|
|
40
|
+
ownerType.AddMethod(types.NewFunc(token.NoPos, pkg, "Consume", consume))
|
|
41
|
+
factoryName := types.NewTypeName(token.NoPos, pkg, "TokenFactory", nil)
|
|
42
|
+
factorySignature := types.NewSignatureType(
|
|
43
|
+
nil,
|
|
44
|
+
nil,
|
|
45
|
+
nil,
|
|
46
|
+
types.NewTuple(),
|
|
47
|
+
types.NewTuple(types.NewVar(token.NoPos, pkg, "value", types.NewPointer(tokenType))),
|
|
48
|
+
false,
|
|
49
|
+
)
|
|
50
|
+
factoryType := types.NewNamed(factoryName, factorySignature, nil)
|
|
51
|
+
pkg.Scope().Insert(factoryName)
|
|
52
|
+
register := types.NewSignatureType(
|
|
53
|
+
receiver,
|
|
54
|
+
nil,
|
|
55
|
+
nil,
|
|
56
|
+
types.NewTuple(types.NewVar(token.NoPos, pkg, "factory", factoryType)),
|
|
57
|
+
types.NewTuple(),
|
|
58
|
+
false,
|
|
59
|
+
)
|
|
60
|
+
ownerType.AddMethod(types.NewFunc(token.NoPos, pkg, "Register", register))
|
|
61
|
+
if includeProducer {
|
|
62
|
+
produce := types.NewSignatureType(
|
|
63
|
+
receiver,
|
|
64
|
+
nil,
|
|
65
|
+
nil,
|
|
66
|
+
types.NewTuple(),
|
|
67
|
+
types.NewTuple(types.NewVar(token.NoPos, pkg, "value", types.NewPointer(tokenType))),
|
|
68
|
+
false,
|
|
69
|
+
)
|
|
70
|
+
ownerType.AddMethod(types.NewFunc(token.NoPos, pkg, "Produce", produce))
|
|
71
|
+
}
|
|
72
|
+
exposed := reachable{}
|
|
73
|
+
exposed.add("fixture", "Owner")
|
|
74
|
+
return exposed, map[string]*packages.Package{"fixture": {Types: pkg}}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
completeReachable, completeInner := build(true)
|
|
78
|
+
complete := newProducerSurface()
|
|
79
|
+
complete.add(flowProduce, flowType{pkg: "fixture", name: "Owner"}, "fixture.NewOwner")
|
|
80
|
+
addExposedMethodFlow(completeReachable, completeInner, &complete)
|
|
81
|
+
if findings := evaluateProducerSurface(canonicalizeProducerSurface(complete, completeInner), nil).gaps; len(findings) != 0 {
|
|
82
|
+
t.Fatalf("complete method surface findings = %+v", findings)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
missingReachable, missingInner := build(false)
|
|
86
|
+
missing := newProducerSurface()
|
|
87
|
+
missing.add(flowProduce, flowType{pkg: "fixture", name: "Owner"}, "fixture.NewOwner")
|
|
88
|
+
addExposedMethodFlow(missingReachable, missingInner, &missing)
|
|
89
|
+
canonicalMissing := canonicalizeProducerSurface(missing, missingInner)
|
|
90
|
+
findings := evaluateProducerSurface(canonicalMissing, nil).gaps
|
|
91
|
+
if len(findings) != 1 || findings[0].pkg != "fixture" || findings[0].symbol != "Token" {
|
|
92
|
+
t.Fatalf("missing method producer findings = %+v, want fixture.Token", findings)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
aliasPkg := missingInner["fixture"].Types
|
|
96
|
+
aliasName := types.NewTypeName(token.NoPos, aliasPkg, "TokenAlias", nil)
|
|
97
|
+
types.NewAlias(aliasName, aliasPkg.Scope().Lookup("Token").Type())
|
|
98
|
+
aliasPkg.Scope().Insert(aliasName)
|
|
99
|
+
aliases := newProducerSurface()
|
|
100
|
+
aliases.add(flowConsume, flowType{pkg: "fixture", name: "TokenAlias"}, "fixture.ConsumeAlias")
|
|
101
|
+
aliases.add(flowProduce, flowType{pkg: "fixture", name: "Token"}, "fixture.ProduceToken")
|
|
102
|
+
if findings := evaluateProducerSurface(canonicalizeProducerSurface(aliases, missingInner), nil).gaps; len(findings) != 0 {
|
|
103
|
+
t.Fatalf("canonical alias surface findings = %+v", findings)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
rootless := newProducerSurface()
|
|
107
|
+
token := flowType{pkg: "fixture", name: "Token"}
|
|
108
|
+
owner := flowType{pkg: "fixture", name: "Owner"}
|
|
109
|
+
rootless.add(flowConsume, token, "fixture.UseToken")
|
|
110
|
+
rootless.operations = append(rootless.operations, operationFlow{
|
|
111
|
+
receiver: &owner,
|
|
112
|
+
consumed: map[flowType]map[string]bool{},
|
|
113
|
+
produced: map[flowType]map[string]bool{token: {"fixture.Owner.Produce": true}},
|
|
114
|
+
})
|
|
115
|
+
if findings := evaluateProducerSurface(rootless, nil).gaps; len(findings) != 1 || findings[0].symbol != "Token" {
|
|
116
|
+
t.Fatalf("rootless receiver findings = %+v, want fixture.Token", findings)
|
|
117
|
+
}
|
|
118
|
+
rooted := evaluateProducerSurface(rootless, map[string]string{"fixture.Owner": "Caller-owned root."})
|
|
119
|
+
if len(rooted.gaps) != 0 || !rooted.usedRoots["fixture.Owner"] {
|
|
120
|
+
t.Fatalf("rooted receiver evaluation = %+v, want no gaps and used Owner root", rooted)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
cycle := newProducerSurface()
|
|
124
|
+
cycle.add(flowConsume, owner, "fixture.UseOwner")
|
|
125
|
+
cycle.operations = append(cycle.operations, operationFlow{
|
|
126
|
+
receiver: &owner,
|
|
127
|
+
consumed: map[flowType]map[string]bool{},
|
|
128
|
+
produced: map[flowType]map[string]bool{owner: {"fixture.Owner.Clone": true}},
|
|
129
|
+
})
|
|
130
|
+
if findings := evaluateProducerSurface(cycle, nil).gaps; len(findings) != 1 || findings[0].symbol != "Owner" {
|
|
131
|
+
t.Fatalf("rootless self-cycle findings = %+v, want fixture.Owner", findings)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
methodCycle := newProducerSurface()
|
|
135
|
+
methodCycle.add(flowProduce, owner, "fixture.NewOwner")
|
|
136
|
+
left := flowType{pkg: "fixture", name: "Left"}
|
|
137
|
+
right := flowType{pkg: "fixture", name: "Right"}
|
|
138
|
+
methodCycle.operations = append(methodCycle.operations,
|
|
139
|
+
operationFlow{
|
|
140
|
+
receiver: &owner,
|
|
141
|
+
consumed: map[flowType]map[string]bool{left: {"fixture.Owner.RightFromLeft": true}},
|
|
142
|
+
produced: map[flowType]map[string]bool{right: {"fixture.Owner.RightFromLeft": true}},
|
|
143
|
+
},
|
|
144
|
+
operationFlow{
|
|
145
|
+
receiver: &owner,
|
|
146
|
+
consumed: map[flowType]map[string]bool{right: {"fixture.Owner.LeftFromRight": true}},
|
|
147
|
+
produced: map[flowType]map[string]bool{left: {"fixture.Owner.LeftFromRight": true}},
|
|
148
|
+
},
|
|
149
|
+
)
|
|
150
|
+
methodFindings := evaluateProducerSurface(methodCycle, nil).gaps
|
|
151
|
+
if len(methodFindings) != 2 || methodFindings[0].symbol != "Left" || methodFindings[1].symbol != "Right" {
|
|
152
|
+
t.Fatalf("rootless method argument cycle findings = %+v, want Left and Right", methodFindings)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"go/token"
|
|
5
|
+
"go/types"
|
|
6
|
+
"strings"
|
|
7
|
+
"testing"
|
|
8
|
+
|
|
9
|
+
"golang.org/x/tools/go/packages"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
// Verifies producer closure rejects a consumed reference after its only producer is removed.
|
|
13
|
+
//
|
|
14
|
+
// The regression is type-flow specific: callback inputs are producers, callback
|
|
15
|
+
// results are consumers, named contracts retain that variance, and non-pointer
|
|
16
|
+
// values must not enter the object graph.
|
|
17
|
+
//
|
|
18
|
+
// 1. Scan a generic surface containing returns, callbacks, and a source method.
|
|
19
|
+
// 2. Confirm only the intentionally input-only object is initially unreachable.
|
|
20
|
+
// 3. Remove a package producer and confirm its generic type-keyed gap appears.
|
|
21
|
+
// 4. Remove a method consumer's producer and confirm that gap appears too.
|
|
22
|
+
// 5. Repeat through recursive named callbacks and containers without hanging.
|
|
23
|
+
// 6. Prove package-operation cycles fail until an independent root is added.
|
|
24
|
+
func TestProducerSurfaceRejectsUnproducibleReference(t *testing.T) {
|
|
25
|
+
source := `package fixture
|
|
26
|
+
import inner "github.com/microsoft/typescript-go/internal/fixture"
|
|
27
|
+
func ConsumeToken(value *inner.Token) {}
|
|
28
|
+
func ProduceToken() []*inner.Token { return nil }
|
|
29
|
+
func Register(handler func(*inner.Event) *inner.Reply) {}
|
|
30
|
+
func ProduceReply() *inner.Reply { return nil }
|
|
31
|
+
func RegisterInterface(handler interface { Handle(*inner.Notice) *inner.Ack }) {}
|
|
32
|
+
func ProduceAck() *inner.Ack { return nil }
|
|
33
|
+
type Owner struct{}
|
|
34
|
+
func (*Owner) ConsumeMethod(value *inner.MethodToken) {}
|
|
35
|
+
func ProduceMethodToken() *inner.MethodToken { return nil }
|
|
36
|
+
func ConsumeOrphan(value *inner.Orphan) {}
|
|
37
|
+
func IgnorePointedContainer(value *[]inner.ContainerValue) {}
|
|
38
|
+
func IgnoreValue(value inner.Mode) {}
|
|
39
|
+
func hidden(value *inner.Hidden) {}
|
|
40
|
+
`
|
|
41
|
+
scanWithInner := func(input string, inner map[string]*packages.Package) []finding {
|
|
42
|
+
surface := newProducerSurface()
|
|
43
|
+
definitions, err := scanLocalFlowDefinitions([]byte(input), "fixture.go")
|
|
44
|
+
if err != nil {
|
|
45
|
+
t.Fatal(err)
|
|
46
|
+
}
|
|
47
|
+
if err := scanProducerFile([]byte(input), "fixture.go", "fixture", definitions, inner, &surface); err != nil {
|
|
48
|
+
t.Fatal(err)
|
|
49
|
+
}
|
|
50
|
+
return evaluateProducerSurface(surface, nil).gaps
|
|
51
|
+
}
|
|
52
|
+
scan := func(input string) []finding { return scanWithInner(input, nil) }
|
|
53
|
+
|
|
54
|
+
complete := scan(source)
|
|
55
|
+
if len(complete) != 1 || complete[0].symbol != "Orphan" {
|
|
56
|
+
t.Fatalf("complete surface findings = %+v, want only input-only Orphan", complete)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
mutated := scan(strings.Replace(source, "func ProduceToken() []*inner.Token { return nil }\n", "", 1))
|
|
60
|
+
if len(mutated) != 2 || mutated[0].symbol != "Orphan" || mutated[1].symbol != "Token" {
|
|
61
|
+
t.Fatalf("mutated surface findings = %+v, want Orphan and Token", mutated)
|
|
62
|
+
}
|
|
63
|
+
for _, finding := range mutated {
|
|
64
|
+
if finding.kind != "PRODUCER" || strings.Contains(finding.detail, "Signature") {
|
|
65
|
+
t.Fatalf("finding is not generic producer evidence: %+v", finding)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
mutatedMethod := scan(strings.Replace(source, "func ProduceMethodToken() *inner.MethodToken { return nil }\n", "", 1))
|
|
70
|
+
if len(mutatedMethod) != 2 || mutatedMethod[0].symbol != "MethodToken" || mutatedMethod[1].symbol != "Orphan" {
|
|
71
|
+
t.Fatalf("source-method mutation findings = %+v, want MethodToken and Orphan", mutatedMethod)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
namedSource := `package fixture
|
|
75
|
+
import inner "github.com/microsoft/typescript-go/internal/fixture"
|
|
76
|
+
type Factory func() *inner.FactoryToken
|
|
77
|
+
type Batch []*inner.BatchToken
|
|
78
|
+
type PointerBatch []*inner.PointerBatchToken
|
|
79
|
+
type Recursive func(Recursive)
|
|
80
|
+
func RegisterFactory(factory Factory) {}
|
|
81
|
+
func ConsumeBatch(batch Batch) {}
|
|
82
|
+
func ConsumePointerBatch(batch *PointerBatch) {}
|
|
83
|
+
func RegisterRecursive(callback Recursive) {}
|
|
84
|
+
func ProduceFactoryToken() *inner.FactoryToken { return nil }
|
|
85
|
+
func ProduceBatchToken() *inner.BatchToken { return nil }
|
|
86
|
+
func ProducePointerBatchToken() *inner.PointerBatchToken { return nil }
|
|
87
|
+
`
|
|
88
|
+
if findings := scan(namedSource); len(findings) != 0 {
|
|
89
|
+
t.Fatalf("named callback/container findings = %+v, want none", findings)
|
|
90
|
+
}
|
|
91
|
+
namedMutated := strings.Replace(namedSource, "func ProduceFactoryToken() *inner.FactoryToken { return nil }\n", "", 1)
|
|
92
|
+
namedMutated = strings.Replace(namedMutated, "func ProduceBatchToken() *inner.BatchToken { return nil }\n", "", 1)
|
|
93
|
+
namedMutated = strings.Replace(namedMutated, "func ProducePointerBatchToken() *inner.PointerBatchToken { return nil }\n", "", 1)
|
|
94
|
+
namedFindings := scan(namedMutated)
|
|
95
|
+
if len(namedFindings) != 3 || namedFindings[0].symbol != "BatchToken" || namedFindings[1].symbol != "FactoryToken" || namedFindings[2].symbol != "PointerBatchToken" {
|
|
96
|
+
t.Fatalf("named callback/container mutation findings = %+v, want BatchToken, FactoryToken, and PointerBatchToken", namedFindings)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
upstream := types.NewPackage(internalPrefix+"fixture", "fixture")
|
|
100
|
+
upstreamTokenName := types.NewTypeName(token.NoPos, upstream, "UpstreamToken", nil)
|
|
101
|
+
upstreamToken := types.NewNamed(upstreamTokenName, types.NewStruct(nil, nil), nil)
|
|
102
|
+
upstream.Scope().Insert(upstreamTokenName)
|
|
103
|
+
upstreamFactoryName := types.NewTypeName(token.NoPos, upstream, "UpstreamFactory", nil)
|
|
104
|
+
types.NewNamed(upstreamFactoryName, types.NewSignatureType(
|
|
105
|
+
nil,
|
|
106
|
+
nil,
|
|
107
|
+
nil,
|
|
108
|
+
types.NewTuple(),
|
|
109
|
+
types.NewTuple(types.NewVar(token.NoPos, upstream, "value", types.NewPointer(upstreamToken))),
|
|
110
|
+
false,
|
|
111
|
+
), nil)
|
|
112
|
+
upstream.Scope().Insert(upstreamFactoryName)
|
|
113
|
+
upstreamInner := map[string]*packages.Package{"fixture": {Types: upstream}}
|
|
114
|
+
upstreamSource := `package fixture
|
|
115
|
+
import inner "github.com/microsoft/typescript-go/internal/fixture"
|
|
116
|
+
func RegisterUpstreamFactory(factory inner.UpstreamFactory) {}
|
|
117
|
+
func ProduceUpstreamToken() *inner.UpstreamToken { return nil }
|
|
118
|
+
`
|
|
119
|
+
if findings := scanWithInner(upstreamSource, upstreamInner); len(findings) != 0 {
|
|
120
|
+
t.Fatalf("upstream named callback findings = %+v, want none", findings)
|
|
121
|
+
}
|
|
122
|
+
upstreamMutated := strings.Replace(upstreamSource, "func ProduceUpstreamToken() *inner.UpstreamToken { return nil }\n", "", 1)
|
|
123
|
+
upstreamFindings := scanWithInner(upstreamMutated, upstreamInner)
|
|
124
|
+
if len(upstreamFindings) != 1 || upstreamFindings[0].symbol != "UpstreamToken" {
|
|
125
|
+
t.Fatalf("upstream named callback mutation findings = %+v, want UpstreamToken", upstreamFindings)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
cycleSource := `package fixture
|
|
129
|
+
import inner "github.com/microsoft/typescript-go/internal/fixture"
|
|
130
|
+
func AFromB(value *inner.B) *inner.A { return nil }
|
|
131
|
+
func BFromA(value *inner.A) *inner.B { return nil }
|
|
132
|
+
func UseA(value *inner.A) {}
|
|
133
|
+
`
|
|
134
|
+
cycleFindings := scan(cycleSource)
|
|
135
|
+
if len(cycleFindings) != 2 || cycleFindings[0].symbol != "A" || cycleFindings[1].symbol != "B" {
|
|
136
|
+
t.Fatalf("rootless operation cycle findings = %+v, want A and B", cycleFindings)
|
|
137
|
+
}
|
|
138
|
+
rootedChain := strings.Replace(cycleSource, "func UseA(value *inner.A) {}\n", "func NewA() *inner.A { return nil }\nfunc UseA(value *inner.A) {}\n", 1)
|
|
139
|
+
if findings := scan(rootedChain); len(findings) != 0 {
|
|
140
|
+
t.Fatalf("rooted operation chain findings = %+v, want none", findings)
|
|
141
|
+
}
|
|
142
|
+
}
|
package/utility/host.go
CHANGED
|
@@ -4,6 +4,7 @@ import (
|
|
|
4
4
|
"encoding/json"
|
|
5
5
|
"flag"
|
|
6
6
|
"fmt"
|
|
7
|
+
"io"
|
|
7
8
|
"os"
|
|
8
9
|
"path/filepath"
|
|
9
10
|
"strings"
|
|
@@ -29,6 +30,8 @@ type hostOptions struct {
|
|
|
29
30
|
singleThreaded bool
|
|
30
31
|
checkers int
|
|
31
32
|
tsgoArgs []string
|
|
33
|
+
stdout io.Writer
|
|
34
|
+
stderr io.Writer
|
|
32
35
|
// fs overrides the filesystem the program loads from. Only the resident serve
|
|
33
36
|
// host sets it (to an OverlayFS), so build/check/transform leave it nil and
|
|
34
37
|
// LoadProgram falls back to the default filesystem.
|
|
@@ -46,7 +49,12 @@ type transformResult struct {
|
|
|
46
49
|
// RunCheck validates the project and linked plugin configuration without
|
|
47
50
|
// emitting output.
|
|
48
51
|
func RunCheck(args []string) int {
|
|
49
|
-
|
|
52
|
+
return RunCheckWithIO(args, os.Stdout, os.Stderr)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// RunCheckWithIO runs check with invocation-owned output streams.
|
|
56
|
+
func RunCheckWithIO(args []string, stdout, stderr io.Writer) int {
|
|
57
|
+
opts, ok := parseHostOptions("check", args, stdout, stderr)
|
|
50
58
|
if !ok {
|
|
51
59
|
return 2
|
|
52
60
|
}
|
|
@@ -57,7 +65,7 @@ func RunCheck(args []string) int {
|
|
|
57
65
|
}
|
|
58
66
|
defer prog.Close()
|
|
59
67
|
if err := prog.ApplyLinkedPlugins(); err != nil {
|
|
60
|
-
fmt.Fprintln(
|
|
68
|
+
fmt.Fprintln(opts.stderr, err)
|
|
61
69
|
return 2
|
|
62
70
|
}
|
|
63
71
|
return 0
|
|
@@ -65,7 +73,12 @@ func RunCheck(args []string) int {
|
|
|
65
73
|
|
|
66
74
|
// RunBuild hosts linked transform packages inside one compiler emit.
|
|
67
75
|
func RunBuild(args []string) int {
|
|
68
|
-
|
|
76
|
+
return RunBuildWithIO(args, os.Stdout, os.Stderr)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// RunBuildWithIO runs build with invocation-owned output streams.
|
|
80
|
+
func RunBuildWithIO(args []string, stdout, stderr io.Writer) int {
|
|
81
|
+
opts, ok := parseHostOptions("build", args, stdout, stderr)
|
|
69
82
|
if !ok {
|
|
70
83
|
return 2
|
|
71
84
|
}
|
|
@@ -81,21 +94,21 @@ func RunBuild(args []string) int {
|
|
|
81
94
|
opts.quiet = false // --verbose overrides the default --quiet=true
|
|
82
95
|
}
|
|
83
96
|
if !opts.quiet {
|
|
84
|
-
fmt.Fprintf(
|
|
97
|
+
fmt.Fprintf(opts.stdout, "// ttsc utility: plugins=%d emit=%v\n", len(entries), !opts.noEmit)
|
|
85
98
|
}
|
|
86
99
|
res, eDiags, err := prog.EmitAllRaw(makeSourcePreambleWriteFile(prog))
|
|
87
100
|
if err != nil {
|
|
88
|
-
fmt.Fprintf(
|
|
101
|
+
fmt.Fprintf(opts.stderr, "ttsc utility: emit failed: %v\n", err)
|
|
89
102
|
return 3
|
|
90
103
|
}
|
|
91
104
|
for _, d := range eDiags {
|
|
92
|
-
fmt.Fprintln(
|
|
105
|
+
fmt.Fprintln(opts.stderr, " -", d.String())
|
|
93
106
|
}
|
|
94
107
|
if driver.CountErrors(eDiags) > 0 {
|
|
95
108
|
return 2
|
|
96
109
|
}
|
|
97
110
|
if res != nil && !opts.quiet {
|
|
98
|
-
fmt.Fprintf(
|
|
111
|
+
fmt.Fprintf(opts.stdout, "// ttsc utility: emitted=%d files\n", len(res.EmittedFiles))
|
|
99
112
|
}
|
|
100
113
|
return 0
|
|
101
114
|
}
|
|
@@ -103,7 +116,12 @@ func RunBuild(args []string) int {
|
|
|
103
116
|
// RunTransform returns the project TypeScript text after linked source
|
|
104
117
|
// mutations.
|
|
105
118
|
func RunTransform(args []string) int {
|
|
106
|
-
|
|
119
|
+
return RunTransformWithIO(args, os.Stdout, os.Stderr)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// RunTransformWithIO runs transform with invocation-owned output streams.
|
|
123
|
+
func RunTransformWithIO(args []string, stdout, stderr io.Writer) int {
|
|
124
|
+
opts, ok := parseHostOptions("transform", args, stdout, stderr)
|
|
107
125
|
if !ok {
|
|
108
126
|
return 2
|
|
109
127
|
}
|
|
@@ -113,7 +131,7 @@ func RunTransform(args []string) int {
|
|
|
113
131
|
}
|
|
114
132
|
defer prog.Close()
|
|
115
133
|
if err := prog.ApplyLinkedPlugins(); err != nil {
|
|
116
|
-
fmt.Fprintln(
|
|
134
|
+
fmt.Fprintln(opts.stderr, err)
|
|
117
135
|
return 2
|
|
118
136
|
}
|
|
119
137
|
printer := shimprinter.NewPrinter(shimprinter.PrinterOptions{}, shimprinter.PrintHandlers{}, nil)
|
|
@@ -123,7 +141,7 @@ func RunTransform(args []string) int {
|
|
|
123
141
|
out.TypeScript[apiOutputKey(opts.cwd, file.FileName())] = text
|
|
124
142
|
}
|
|
125
143
|
data, _ := json.Marshal(out)
|
|
126
|
-
fmt.Fprintln(
|
|
144
|
+
fmt.Fprintln(opts.stdout, string(data))
|
|
127
145
|
return 0
|
|
128
146
|
}
|
|
129
147
|
|
|
@@ -131,9 +149,15 @@ func RunTransform(args []string) int {
|
|
|
131
149
|
// Unknown flags forwarded from the JS launcher are stripped by filterHostArgs
|
|
132
150
|
// before flag.FlagSet sees them, so spurious "flag provided but not defined"
|
|
133
151
|
// errors are avoided. Returns (zero, false) on any parse or validation error.
|
|
134
|
-
func parseHostOptions(command string, args []string) (hostOptions, bool) {
|
|
152
|
+
func parseHostOptions(command string, args []string, stdout, stderr io.Writer) (hostOptions, bool) {
|
|
153
|
+
if stdout == nil {
|
|
154
|
+
stdout = io.Discard
|
|
155
|
+
}
|
|
156
|
+
if stderr == nil {
|
|
157
|
+
stderr = io.Discard
|
|
158
|
+
}
|
|
135
159
|
fs := flag.NewFlagSet(command, flag.ContinueOnError)
|
|
136
|
-
fs.SetOutput(
|
|
160
|
+
fs.SetOutput(stderr)
|
|
137
161
|
cwd := fs.String("cwd", "", "project directory")
|
|
138
162
|
emit := fs.Bool("emit", false, "force emit")
|
|
139
163
|
noEmit := fs.Bool("noEmit", false, "force no emit")
|
|
@@ -151,12 +175,12 @@ func parseHostOptions(command string, args []string) (hostOptions, bool) {
|
|
|
151
175
|
var tsgoArgs []string
|
|
152
176
|
if *tsgoArgsRaw != "" {
|
|
153
177
|
if err := json.Unmarshal([]byte(*tsgoArgsRaw), &tsgoArgs); err != nil {
|
|
154
|
-
fmt.Fprintf(
|
|
178
|
+
fmt.Fprintf(stderr, "ttsc utility: invalid --tsgo-args: %v\n", err)
|
|
155
179
|
return hostOptions{}, false
|
|
156
180
|
}
|
|
157
181
|
}
|
|
158
182
|
if *emit && *noEmit {
|
|
159
|
-
fmt.Fprintln(
|
|
183
|
+
fmt.Fprintln(stderr, "ttsc utility: --emit and --noEmit are mutually exclusive")
|
|
160
184
|
return hostOptions{}, false
|
|
161
185
|
}
|
|
162
186
|
resolvedCwd := *cwd
|
|
@@ -164,14 +188,14 @@ func parseHostOptions(command string, args []string) (hostOptions, bool) {
|
|
|
164
188
|
var err error
|
|
165
189
|
resolvedCwd, err = os.Getwd()
|
|
166
190
|
if err != nil {
|
|
167
|
-
fmt.Fprintf(
|
|
191
|
+
fmt.Fprintf(stderr, "ttsc utility: cwd: %v\n", err)
|
|
168
192
|
return hostOptions{}, false
|
|
169
193
|
}
|
|
170
194
|
}
|
|
171
195
|
if !filepath.IsAbs(resolvedCwd) {
|
|
172
196
|
abs, err := filepath.Abs(resolvedCwd)
|
|
173
197
|
if err != nil {
|
|
174
|
-
fmt.Fprintf(
|
|
198
|
+
fmt.Fprintf(stderr, "ttsc utility: cwd: %v\n", err)
|
|
175
199
|
return hostOptions{}, false
|
|
176
200
|
}
|
|
177
201
|
resolvedCwd = abs
|
|
@@ -188,6 +212,8 @@ func parseHostOptions(command string, args []string) (hostOptions, bool) {
|
|
|
188
212
|
singleThreaded: *singleThreaded,
|
|
189
213
|
checkers: *checkers,
|
|
190
214
|
tsgoArgs: tsgoArgs,
|
|
215
|
+
stdout: stdout,
|
|
216
|
+
stderr: stderr,
|
|
191
217
|
}, true
|
|
192
218
|
}
|
|
193
219
|
|
|
@@ -243,7 +269,7 @@ func flagName(arg string) (string, bool) {
|
|
|
243
269
|
func loadUtilityProgram(opts hostOptions) (*driver.Program, []driver.PluginEntry, bool) {
|
|
244
270
|
entries, err := parsePluginEntries(opts.pluginsJSON)
|
|
245
271
|
if err != nil {
|
|
246
|
-
fmt.Fprintln(
|
|
272
|
+
fmt.Fprintln(opts.stderr, err)
|
|
247
273
|
return nil, nil, false
|
|
248
274
|
}
|
|
249
275
|
restoreEnv := setLinkedPluginManifest(opts.pluginsJSON)
|
|
@@ -259,15 +285,15 @@ func loadUtilityProgram(opts hostOptions) (*driver.Program, []driver.PluginEntry
|
|
|
259
285
|
FS: opts.fs,
|
|
260
286
|
})
|
|
261
287
|
if err != nil {
|
|
262
|
-
fmt.Fprintf(
|
|
288
|
+
fmt.Fprintf(opts.stderr, "ttsc utility: %v\n", err)
|
|
263
289
|
return nil, nil, false
|
|
264
290
|
}
|
|
265
291
|
if len(diags) > 0 {
|
|
266
|
-
driver.WritePrettyDiagnostics(
|
|
292
|
+
driver.WritePrettyDiagnostics(opts.stderr, diags, opts.cwd)
|
|
267
293
|
return nil, nil, false
|
|
268
294
|
}
|
|
269
295
|
if diags := prog.Diagnostics(); len(diags) > 0 {
|
|
270
|
-
driver.WritePrettyDiagnostics(
|
|
296
|
+
driver.WritePrettyDiagnostics(opts.stderr, diags, opts.cwd)
|
|
271
297
|
_ = prog.Close()
|
|
272
298
|
return nil, nil, false
|
|
273
299
|
}
|
package/utility/serve.go
CHANGED
|
@@ -56,7 +56,7 @@ type serveUpdateResponse struct {
|
|
|
56
56
|
// in and out are explicit so the request loop is testable; the utility-host
|
|
57
57
|
// command wires them to os.Stdin and os.Stdout.
|
|
58
58
|
func RunServe(in io.Reader, out io.Writer, args []string) int {
|
|
59
|
-
opts, ok := parseHostOptions("serve", args)
|
|
59
|
+
opts, ok := parseHostOptions("serve", args, out, os.Stderr)
|
|
60
60
|
if !ok {
|
|
61
61
|
return 2
|
|
62
62
|
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
package checker
|
|
2
|
-
|
|
3
|
-
// Compile-time guard: the signature-introspection surface that typia's
|
|
4
|
-
// plain.classify from/new construction-strategy detection depends on must
|
|
5
|
-
// compose end-to-end through the shim.
|
|
6
|
-
//
|
|
7
|
-
// 0.15.5 exposed a CONSUMER of a *Signature (Checker_getMinArgumentCount)
|
|
8
|
-
// without the PRODUCER that yields one (Checker_getSignaturesOfType): a
|
|
9
|
-
// *Signature was nameable (the `Signature` alias) but unobtainable. The closure
|
|
10
|
-
// auditor checks that every escaping type can be NAMED, not that it can be
|
|
11
|
-
// PRODUCED, so it did not catch the gap and the feature stayed blocked.
|
|
12
|
-
//
|
|
13
|
-
// This lives in a NORMAL (non-_test) file on purpose. The shim/checker package
|
|
14
|
-
// is a nested Go module that no CI job runs `go test` against, so a _test.go
|
|
15
|
-
// guard would never be compiled and would silently stop guarding. As ordinary
|
|
16
|
-
// package code it is type-checked by every build that links the shim (typia's
|
|
17
|
-
// native plugin, ttsc's lint engine), so dropping or renaming any leg below
|
|
18
|
-
// turns those builds red. It never runs (assigned to blank, never called).
|
|
19
|
-
var _ = func(c *Checker, instanceType *Type) {
|
|
20
|
-
// class instance type -> class symbol -> constructor (static) type, which
|
|
21
|
-
// carries both the construct signatures and the static `from` member.
|
|
22
|
-
classSymbol := Type_getTypeNameSymbol(instanceType)
|
|
23
|
-
ctorType := Checker_getTypeOfSymbol(c, classSymbol)
|
|
24
|
-
|
|
25
|
-
// `new C(seed)` strategy: construct signatures -> arity (min args +
|
|
26
|
-
// parameter count, together disambiguating `()` from `(x?)`) -> return type
|
|
27
|
-
// -> the seed parameter's type. The seed is Signature_parameters[0]'s type,
|
|
28
|
-
// EXCEPT a rest-ONLY parameter `(...xs: S[])` — when
|
|
29
|
-
// `hasRestParameter && parameterCount == 1` — whose seed is the rest ELEMENT
|
|
30
|
-
// (getRestTypeOfSignature). A leading-required + rest-tail `(s, ...r)` still
|
|
31
|
-
// has hasRestParameter true but its seed is the first parameter S.
|
|
32
|
-
for _, sig := range Checker_getSignaturesOfType(c, ctorType, SignatureKindConstruct) {
|
|
33
|
-
_ = Checker_getMinArgumentCount(c, sig)
|
|
34
|
-
_ = Signature_parameterCount(sig)
|
|
35
|
-
_ = Checker_getReturnTypeOfSignature(c, sig)
|
|
36
|
-
if Signature_hasRestParameter(sig) {
|
|
37
|
-
_ = Checker_getRestTypeOfSignature(c, sig)
|
|
38
|
-
}
|
|
39
|
-
for _, p := range Signature_parameters(sig) {
|
|
40
|
-
_ = Checker_getTypeOfSymbol(c, p)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// `C.from(seed)` strategy: static `from` member -> its call signatures, read
|
|
45
|
-
// identically (arity, return type, seed parameter / rest element type).
|
|
46
|
-
fromType := Checker_getTypeOfPropertyOfType(c, ctorType, "from")
|
|
47
|
-
for _, sig := range Checker_getSignaturesOfType(c, fromType, SignatureKindCall) {
|
|
48
|
-
_ = Checker_getMinArgumentCount(c, sig)
|
|
49
|
-
_ = Signature_parameterCount(sig)
|
|
50
|
-
_ = Checker_getReturnTypeOfSignature(c, sig)
|
|
51
|
-
if Signature_hasRestParameter(sig) {
|
|
52
|
-
_ = Checker_getRestTypeOfSignature(c, sig)
|
|
53
|
-
}
|
|
54
|
-
for _, p := range Signature_parameters(sig) {
|
|
55
|
-
_ = Checker_getTypeOfSymbol(c, p)
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|