goscript 0.1.4 → 0.2.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.
Files changed (270) hide show
  1. package/README.md +5 -2
  2. package/cmd/go_js_wasm_exec/main.go +201 -0
  3. package/cmd/go_js_wasm_exec/main_test.go +83 -0
  4. package/cmd/goscript/{cmd_compile.go → cmd-compile.go} +7 -0
  5. package/cmd/goscript/cmd-test.go +14 -0
  6. package/cmd/goscript/cmd-test_test.go +1 -1
  7. package/compiler/compile-request.go +12 -9
  8. package/compiler/compliance_test.go +0 -1
  9. package/compiler/config.go +2 -0
  10. package/compiler/gotest/request.go +28 -0
  11. package/compiler/gotest/runner.go +353 -27
  12. package/compiler/gotest/runner_test.go +273 -1
  13. package/compiler/gotest/testdata/browserapi/browserapi_test.go +20 -0
  14. package/compiler/gotest/testdata/browserapi/go.mod +3 -0
  15. package/compiler/lowered-program.go +24 -17
  16. package/compiler/lowering.go +392 -127
  17. package/compiler/lowering_bench_test.go +41 -27
  18. package/compiler/override-facts.go +15 -0
  19. package/compiler/override-parity-verifier.go +450 -0
  20. package/compiler/override-parity.go +122 -0
  21. package/compiler/override-registry_test.go +559 -0
  22. package/compiler/protobuf-ts-binding.go +514 -0
  23. package/compiler/protobuf-ts-binding_test.go +172 -0
  24. package/compiler/semantic-model-types.go +9 -4
  25. package/compiler/semantic-model.go +282 -70
  26. package/compiler/semantic-model_test.go +82 -1
  27. package/compiler/service.go +20 -1
  28. package/compiler/skeleton_test.go +62 -8
  29. package/compiler/typescript-emitter.go +128 -13
  30. package/dist/gs/builtin/slice.d.ts +2 -1
  31. package/dist/gs/builtin/slice.js +29 -4
  32. package/dist/gs/builtin/slice.js.map +1 -1
  33. package/dist/gs/builtin/type.d.ts +13 -5
  34. package/dist/gs/builtin/type.js +153 -60
  35. package/dist/gs/builtin/type.js.map +1 -1
  36. package/dist/gs/builtin/varRef.d.ts +11 -0
  37. package/dist/gs/builtin/varRef.js +57 -2
  38. package/dist/gs/builtin/varRef.js.map +1 -1
  39. package/dist/gs/bytes/buffer.gs.js +1 -1
  40. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  41. package/dist/gs/bytes/reader.gs.js +1 -1
  42. package/dist/gs/bytes/reader.gs.js.map +1 -1
  43. package/dist/gs/compress/zlib/index.d.ts +10 -3
  44. package/dist/gs/compress/zlib/index.js +50 -16
  45. package/dist/gs/compress/zlib/index.js.map +1 -1
  46. package/dist/gs/encoding/json/index.d.ts +114 -0
  47. package/dist/gs/encoding/json/index.js +544 -36
  48. package/dist/gs/encoding/json/index.js.map +1 -1
  49. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +100 -0
  50. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +564 -0
  51. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  52. package/dist/gs/github.com/pkg/errors/errors.js +54 -30
  53. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  54. package/dist/gs/go/scanner/index.d.ts +2 -0
  55. package/dist/gs/go/scanner/index.js +29 -5
  56. package/dist/gs/go/scanner/index.js.map +1 -1
  57. package/dist/gs/go/token/index.js +22 -6
  58. package/dist/gs/go/token/index.js.map +1 -1
  59. package/dist/gs/hash/index.d.ts +6 -0
  60. package/dist/gs/hash/index.js +20 -0
  61. package/dist/gs/hash/index.js.map +1 -1
  62. package/dist/gs/internal/goarch/index.d.ts +43 -3
  63. package/dist/gs/internal/goarch/index.js +42 -10
  64. package/dist/gs/internal/goarch/index.js.map +1 -1
  65. package/dist/gs/io/fs/fs.js +26 -14
  66. package/dist/gs/io/fs/fs.js.map +1 -1
  67. package/dist/gs/io/fs/readdir.js +4 -2
  68. package/dist/gs/io/fs/readdir.js.map +1 -1
  69. package/dist/gs/io/fs/sub.js +8 -1
  70. package/dist/gs/io/fs/sub.js.map +1 -1
  71. package/dist/gs/io/io.d.ts +2 -0
  72. package/dist/gs/io/io.js.map +1 -1
  73. package/dist/gs/math/bits/index.d.ts +5 -0
  74. package/dist/gs/math/bits/index.js +16 -4
  75. package/dist/gs/math/bits/index.js.map +1 -1
  76. package/dist/gs/mime/index.d.ts +16 -0
  77. package/dist/gs/mime/index.js +315 -6
  78. package/dist/gs/mime/index.js.map +1 -1
  79. package/dist/gs/net/http/httptest/index.d.ts +12 -0
  80. package/dist/gs/net/http/httptest/index.js +85 -6
  81. package/dist/gs/net/http/httptest/index.js.map +1 -1
  82. package/dist/gs/net/http/index.d.ts +300 -5
  83. package/dist/gs/net/http/index.js +1598 -58
  84. package/dist/gs/net/http/index.js.map +1 -1
  85. package/dist/gs/os/dir_unix.gs.js +1 -1
  86. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  87. package/dist/gs/os/error.gs.js +1 -1
  88. package/dist/gs/os/error.gs.js.map +1 -1
  89. package/dist/gs/os/exec.gs.d.ts +1 -0
  90. package/dist/gs/os/exec.gs.js +4 -8
  91. package/dist/gs/os/exec.gs.js.map +1 -1
  92. package/dist/gs/os/exec_posix.gs.js +1 -1
  93. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  94. package/dist/gs/os/index.d.ts +1 -1
  95. package/dist/gs/os/index.js +1 -1
  96. package/dist/gs/os/index.js.map +1 -1
  97. package/dist/gs/os/proc.gs.d.ts +4 -0
  98. package/dist/gs/os/proc.gs.js +12 -6
  99. package/dist/gs/os/proc.gs.js.map +1 -1
  100. package/dist/gs/os/root_js.gs.js +1 -1
  101. package/dist/gs/os/root_js.gs.js.map +1 -1
  102. package/dist/gs/os/types.gs.js +1 -1
  103. package/dist/gs/os/types.gs.js.map +1 -1
  104. package/dist/gs/os/types_js.gs.js +1 -1
  105. package/dist/gs/os/types_js.gs.js.map +1 -1
  106. package/dist/gs/os/types_unix.gs.js +1 -1
  107. package/dist/gs/os/types_unix.gs.js.map +1 -1
  108. package/dist/gs/path/path.js +11 -7
  109. package/dist/gs/path/path.js.map +1 -1
  110. package/dist/gs/reflect/index.d.ts +5 -4
  111. package/dist/gs/reflect/index.js +4 -3
  112. package/dist/gs/reflect/index.js.map +1 -1
  113. package/dist/gs/reflect/map.js +15 -0
  114. package/dist/gs/reflect/map.js.map +1 -1
  115. package/dist/gs/reflect/type.d.ts +25 -6
  116. package/dist/gs/reflect/type.js +1418 -228
  117. package/dist/gs/reflect/type.js.map +1 -1
  118. package/dist/gs/reflect/types.d.ts +14 -6
  119. package/dist/gs/reflect/types.js +35 -1
  120. package/dist/gs/reflect/types.js.map +1 -1
  121. package/dist/gs/reflect/value.d.ts +1 -0
  122. package/dist/gs/reflect/value.js +83 -41
  123. package/dist/gs/reflect/value.js.map +1 -1
  124. package/dist/gs/reflect/visiblefields.js +4 -140
  125. package/dist/gs/reflect/visiblefields.js.map +1 -1
  126. package/dist/gs/runtime/pprof/index.d.ts +8 -2
  127. package/dist/gs/runtime/pprof/index.js +50 -30
  128. package/dist/gs/runtime/pprof/index.js.map +1 -1
  129. package/dist/gs/runtime/runtime.js +5 -4
  130. package/dist/gs/runtime/runtime.js.map +1 -1
  131. package/dist/gs/runtime/trace/index.js +5 -19
  132. package/dist/gs/runtime/trace/index.js.map +1 -1
  133. package/dist/gs/strconv/atoi.gs.js +1 -1
  134. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  135. package/dist/gs/strconv/complex.gs.d.ts +3 -0
  136. package/dist/gs/strconv/complex.gs.js +148 -0
  137. package/dist/gs/strconv/complex.gs.js.map +1 -0
  138. package/dist/gs/strconv/index.d.ts +1 -0
  139. package/dist/gs/strconv/index.js +1 -0
  140. package/dist/gs/strconv/index.js.map +1 -1
  141. package/dist/gs/strings/builder.js +1 -1
  142. package/dist/gs/strings/reader.js +9 -5
  143. package/dist/gs/strings/reader.js.map +1 -1
  144. package/dist/gs/strings/replace.js +15 -7
  145. package/dist/gs/strings/replace.js.map +1 -1
  146. package/dist/gs/strings/strings.d.ts +5 -0
  147. package/dist/gs/strings/strings.js +57 -5
  148. package/dist/gs/strings/strings.js.map +1 -1
  149. package/dist/gs/sync/atomic/type.gs.js +9 -9
  150. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  151. package/dist/gs/sync/atomic/value.gs.js +2 -2
  152. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  153. package/dist/gs/syscall/env.js +22 -14
  154. package/dist/gs/syscall/env.js.map +1 -1
  155. package/dist/gs/testing/testing.js +55 -13
  156. package/dist/gs/testing/testing.js.map +1 -1
  157. package/dist/gs/time/time.d.ts +24 -1
  158. package/dist/gs/time/time.js +43 -3
  159. package/dist/gs/time/time.js.map +1 -1
  160. package/dist/gs/unique/index.js +7 -1
  161. package/dist/gs/unique/index.js.map +1 -1
  162. package/go.mod +3 -3
  163. package/go.sum +16 -0
  164. package/gs/builtin/runtime-contract.test.ts +218 -21
  165. package/gs/builtin/slice.ts +44 -4
  166. package/gs/builtin/type.ts +226 -59
  167. package/gs/builtin/varRef.ts +85 -2
  168. package/gs/bytes/buffer.gs.ts +1 -1
  169. package/gs/bytes/reader.gs.ts +1 -1
  170. package/gs/compress/zlib/index.test.ts +62 -1
  171. package/gs/compress/zlib/index.ts +53 -16
  172. package/gs/compress/zlib/parity.json +51 -0
  173. package/gs/encoding/json/index.test.ts +360 -6
  174. package/gs/encoding/json/index.ts +679 -38
  175. package/gs/encoding/json/parity.json +81 -0
  176. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +211 -3
  177. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +857 -1
  178. package/gs/github.com/pkg/errors/errors.ts +54 -30
  179. package/gs/go/scanner/index.test.ts +39 -56
  180. package/gs/go/scanner/index.ts +33 -5
  181. package/gs/go/scanner/parity.json +27 -0
  182. package/gs/go/token/index.ts +22 -6
  183. package/gs/hash/index.test.ts +20 -33
  184. package/gs/hash/index.ts +28 -0
  185. package/gs/hash/parity.json +21 -0
  186. package/gs/internal/goarch/index.test.ts +32 -0
  187. package/gs/internal/goarch/index.ts +45 -13
  188. package/gs/internal/goarch/parity.json +144 -0
  189. package/gs/io/fs/fs.ts +26 -14
  190. package/gs/io/fs/readdir.ts +4 -4
  191. package/gs/io/fs/sub.ts +8 -1
  192. package/gs/io/io.ts +1 -0
  193. package/gs/io/parity.json +162 -0
  194. package/gs/math/bits/index.test.ts +14 -1
  195. package/gs/math/bits/index.ts +23 -4
  196. package/gs/math/bits/parity.json +156 -0
  197. package/gs/mime/index.test.ts +90 -0
  198. package/gs/mime/index.ts +369 -6
  199. package/gs/mime/parity.json +36 -0
  200. package/gs/net/http/httptest/index.test.ts +98 -2
  201. package/gs/net/http/httptest/index.ts +101 -6
  202. package/gs/net/http/httptest/parity.json +15 -0
  203. package/gs/net/http/index.test.ts +781 -12
  204. package/gs/net/http/index.ts +1860 -139
  205. package/gs/net/http/meta.json +16 -1
  206. package/gs/net/http/parity.json +193 -0
  207. package/gs/os/dir_unix.gs.ts +1 -1
  208. package/gs/os/error.gs.ts +1 -1
  209. package/gs/os/exec.gs.ts +4 -8
  210. package/gs/os/exec_posix.gs.ts +1 -1
  211. package/gs/os/index.test.ts +9 -0
  212. package/gs/os/index.ts +1 -0
  213. package/gs/os/parity.json +9 -0
  214. package/gs/os/proc.gs.ts +18 -5
  215. package/gs/os/proc.test.ts +26 -0
  216. package/gs/os/root_js.gs.ts +1 -1
  217. package/gs/os/types.gs.ts +1 -1
  218. package/gs/os/types_js.gs.ts +1 -1
  219. package/gs/os/types_unix.gs.ts +1 -1
  220. package/gs/path/path.ts +11 -7
  221. package/gs/reflect/field.test.ts +37 -15
  222. package/gs/reflect/function-types.test.ts +518 -22
  223. package/gs/reflect/index.ts +8 -6
  224. package/gs/reflect/map.ts +20 -0
  225. package/gs/reflect/meta.json +6 -4
  226. package/gs/reflect/parity.json +234 -0
  227. package/gs/reflect/sliceat.test.ts +156 -0
  228. package/gs/reflect/structof.test.ts +401 -0
  229. package/gs/reflect/type.ts +1897 -317
  230. package/gs/reflect/typefor.test.ts +510 -10
  231. package/gs/reflect/types.ts +43 -18
  232. package/gs/reflect/value.ts +105 -45
  233. package/gs/reflect/visiblefields.ts +5 -168
  234. package/gs/runtime/parity.json +24 -0
  235. package/gs/runtime/pprof/index.test.ts +29 -7
  236. package/gs/runtime/pprof/index.ts +56 -30
  237. package/gs/runtime/pprof/parity.json +27 -0
  238. package/gs/runtime/runtime.test.ts +3 -1
  239. package/gs/runtime/runtime.ts +4 -3
  240. package/gs/runtime/trace/index.test.ts +5 -3
  241. package/gs/runtime/trace/index.ts +8 -20
  242. package/gs/runtime/trace/parity.json +36 -0
  243. package/gs/strconv/atoi.gs.ts +1 -1
  244. package/gs/strconv/complex.gs.ts +174 -0
  245. package/gs/strconv/complex.test.ts +65 -0
  246. package/gs/strconv/index.ts +1 -0
  247. package/gs/strconv/parity.json +120 -0
  248. package/gs/strings/builder.ts +1 -1
  249. package/gs/strings/parity.json +186 -0
  250. package/gs/strings/reader.ts +9 -5
  251. package/gs/strings/replace.ts +15 -7
  252. package/gs/strings/strings.test.ts +22 -2
  253. package/gs/strings/strings.ts +64 -6
  254. package/gs/sync/atomic/type.gs.ts +9 -9
  255. package/gs/sync/atomic/value.gs.ts +2 -2
  256. package/gs/syscall/env.ts +29 -14
  257. package/gs/testing/testing.test.ts +67 -0
  258. package/gs/testing/testing.ts +87 -19
  259. package/gs/time/parity.json +225 -0
  260. package/gs/time/time.test.ts +20 -2
  261. package/gs/time/time.ts +49 -7
  262. package/gs/unique/index.ts +7 -1
  263. package/package.json +4 -2
  264. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +0 -217
  265. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +0 -926
  266. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +0 -1
  267. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +0 -38
  268. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +0 -1361
  269. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +0 -46
  270. /package/compiler/{wasm_api.go → wasm-api.go} +0 -0
@@ -10,12 +10,13 @@ import (
10
10
  )
11
11
 
12
12
  type loweringBenchFixture struct {
13
- model *SemanticModel
14
- owner *LoweringOwner
15
- semPkg *semanticPackage
16
- file loweringBenchFile
17
- genDecls []loweringBenchGenDecl
18
- stmtLists []loweringBenchStmtList
13
+ model *SemanticModel
14
+ owner *LoweringOwner
15
+ semPkg *semanticPackage
16
+ lazyPackageVarsByPkg map[string]map[types.Object]bool
17
+ file loweringBenchFile
18
+ genDecls []loweringBenchGenDecl
19
+ stmtLists []loweringBenchStmtList
19
20
  }
20
21
 
21
22
  type loweringBenchFile struct {
@@ -42,7 +43,13 @@ func BenchmarkLoweringPackage(b *testing.B) {
42
43
  b.ReportAllocs()
43
44
  b.ResetTimer()
44
45
  for i := 0; i < b.N; i++ {
45
- if _, diagnostics := fixture.owner.lowerPackage(fixture.model, fixture.semPkg); diagnosticsHaveErrors(diagnostics) {
46
+ if _, diagnostics := fixture.owner.lowerPackage(
47
+ fixture.model,
48
+ fixture.semPkg,
49
+ make(map[string]map[types.Object]bool),
50
+ make(runtimeMethodSetCache),
51
+ LoweringOptions{},
52
+ ); diagnosticsHaveErrors(diagnostics) {
46
53
  b.Fatal(diagnostics)
47
54
  }
48
55
  }
@@ -60,6 +67,7 @@ func BenchmarkLoweringAnalyzeLocalFileReferences(b *testing.B) {
60
67
  fixture.file.associated,
61
68
  fixture.file.declFiles,
62
69
  fixture.file.outputNames,
70
+ make(runtimeMethodSetCache),
63
71
  )
64
72
  }
65
73
  }
@@ -77,6 +85,9 @@ func BenchmarkLoweringFile(b *testing.B) {
77
85
  fixture.file.declFiles,
78
86
  fixture.file.outputNames,
79
87
  fixture.file.lazyPackageVars,
88
+ fixture.lazyPackageVarsByPkg,
89
+ make(runtimeMethodSetCache),
90
+ false,
80
91
  ); diagnosticsHaveErrors(diagnostics) {
81
92
  b.Fatal(diagnostics)
82
93
  }
@@ -160,7 +171,8 @@ func newLoweringBenchFixture(tb testing.TB) *loweringBenchFixture {
160
171
  owner := service.LoweringOwner()
161
172
  declFiles := packageDeclFiles(semPkg)
162
173
  outputNames := packageOutputNames(semPkg)
163
- lazyPackageVars := owner.lazyPackageVars(semPkg, declFiles)
174
+ lazyPackageVarsByPkg := make(map[string]map[types.Object]bool)
175
+ lazyPackageVars := owner.packageLazyVars(semPkg, lazyPackageVarsByPkg, declFiles)
164
176
 
165
177
  var benchFile loweringBenchFile
166
178
  var genDecls []loweringBenchGenDecl
@@ -168,20 +180,21 @@ func newLoweringBenchFixture(tb testing.TB) *loweringBenchFixture {
168
180
  for idx, file := range semPkg.source.Syntax {
169
181
  sourcePath := sourceFilePath(semPkg, idx, file)
170
182
  associated := owner.methodDeclsForFileTypes(semPkg, file)
171
- localRefs := owner.analyzeLocalFileReferences(semPkg, file, sourcePath, associated, declFiles, outputNames)
183
+ localRefs := owner.analyzeLocalFileReferences(semPkg, file, sourcePath, associated, declFiles, outputNames, make(runtimeMethodSetCache))
172
184
  ctx := lowerFileContext{
173
- model: model,
174
- semPkg: semPkg,
175
- file: file,
176
- importAliases: make(map[string]string),
177
- importPaths: make(map[string]string),
178
- importNames: make(map[string]string),
179
- importObjects: make(map[*types.PkgName]string),
180
- sourcePath: sourcePath,
181
- localAliases: localRefs.aliases,
182
- lazyPackageVars: lazyPackageVars,
183
- tempNames: newTempNameOwner(),
184
- topLevel: true,
185
+ model: model,
186
+ semPkg: semPkg,
187
+ file: file,
188
+ importAliases: make(map[string]string),
189
+ importPaths: make(map[string]string),
190
+ importNames: make(map[string]string),
191
+ importObjects: make(map[*types.PkgName]string),
192
+ sourcePath: sourcePath,
193
+ localAliases: localRefs.aliases,
194
+ lazyPackageVars: lazyPackageVars,
195
+ lazyPackageVarsByPkg: lazyPackageVarsByPkg,
196
+ tempNames: newTempNameOwner(),
197
+ topLevel: true,
185
198
  }
186
199
  if filepath.Base(sourcePath) == "bench.go" {
187
200
  benchFile = loweringBenchFile{
@@ -214,12 +227,13 @@ func newLoweringBenchFixture(tb testing.TB) *loweringBenchFixture {
214
227
  tb.Fatalf("incomplete lowering benchmark fixture: genDecls=%d stmtLists=%d", len(genDecls), len(stmtLists))
215
228
  }
216
229
  return &loweringBenchFixture{
217
- model: model,
218
- owner: owner,
219
- semPkg: semPkg,
220
- file: benchFile,
221
- genDecls: genDecls,
222
- stmtLists: stmtLists,
230
+ model: model,
231
+ owner: owner,
232
+ semPkg: semPkg,
233
+ lazyPackageVarsByPkg: lazyPackageVarsByPkg,
234
+ file: benchFile,
235
+ genDecls: genDecls,
236
+ stmtLists: stmtLists,
223
237
  }
224
238
  }
225
239
 
@@ -24,6 +24,7 @@ type OverrideFacts struct {
24
24
 
25
25
  type overridePackageFacts struct {
26
26
  metadata OverrideMetadata
27
+ parity overrideParityLedger
27
28
  copyPackage overrideCopyPackage
28
29
  dependencies []string
29
30
  }
@@ -52,6 +53,14 @@ func (f *OverrideFacts) Metadata(pkgPath string) OverrideMetadata {
52
53
  return cloneOverrideMetadata(pkg.metadata)
53
54
  }
54
55
 
56
+ func (f *OverrideFacts) parityLedger(pkgPath string) overrideParityLedger {
57
+ if f == nil {
58
+ return newOverrideParityLedger()
59
+ }
60
+ pkg := f.packages[pkgPath]
61
+ return cloneOverrideParityLedger(pkg.parity)
62
+ }
63
+
55
64
  // IsMethodAsync returns true when override metadata marks a method async.
56
65
  func (f *OverrideFacts) IsMethodAsync(pkgPath, method string) bool {
57
66
  if f == nil {
@@ -122,6 +131,11 @@ func buildOverrideFacts(ctx context.Context, overrideDirs []string) (*OverrideFa
122
131
  diagnostics = append(diagnostics, overrideError("read override metadata", pkgPath, err))
123
132
  continue
124
133
  }
134
+ parity, err := loadOverrideParityLedger(roots[pkgPath])
135
+ if err != nil {
136
+ diagnostics = append(diagnostics, overrideError("read override parity ledger", pkgPath, err))
137
+ continue
138
+ }
125
139
  copyPackage, dependencies, packageDiagnostics := loadOverrideCopyPackage(roots[pkgPath], roots, metadata)
126
140
  diagnostics = append(diagnostics, packageDiagnostics...)
127
141
  if diagnosticsHaveErrors(packageDiagnostics) {
@@ -129,6 +143,7 @@ func buildOverrideFacts(ctx context.Context, overrideDirs []string) (*OverrideFa
129
143
  }
130
144
  facts.packages[pkgPath] = overridePackageFacts{
131
145
  metadata: cloneOverrideMetadata(metadata),
146
+ parity: cloneOverrideParityLedger(parity),
132
147
  copyPackage: copyPackage,
133
148
  dependencies: dependencies,
134
149
  }
@@ -0,0 +1,450 @@
1
+ package compiler
2
+
3
+ import (
4
+ "context"
5
+ "go/ast"
6
+ "go/types"
7
+ "path"
8
+ "regexp"
9
+ "slices"
10
+ "strings"
11
+
12
+ "github.com/pkg/errors"
13
+ )
14
+
15
+ var (
16
+ overrideExportDeclarationPattern = regexp.MustCompile(`(?m)^\s*export\s+(?:async\s+)?(const|let|var|function|class|interface|type|enum)\s+([A-Za-z_$][A-Za-z0-9_$]*)`)
17
+ overrideLocalDeclarationPattern = regexp.MustCompile(`(?m)^\s*(?:export\s+)?(?:async\s+)?(const|let|var|function|class|interface|type|enum)\s+([A-Za-z_$][A-Za-z0-9_$]*)`)
18
+ overrideImportNamedPattern = regexp.MustCompile(`(?s)import\s+(type\s+)?\{([^}]*)\}\s+from\s+['"][^'"]+['"]`)
19
+ overrideExportNamedPattern = regexp.MustCompile(`(?s)export\s+(type\s+)?\{([^}]*)\}\s*(?:from\s+['"]([^'"]+)['"])?`)
20
+ overrideExportAllPattern = regexp.MustCompile(`(?m)^\s*export\s+\*\s+from\s+['"]([^'"]+)['"]`)
21
+ )
22
+
23
+ type goPackageExport struct {
24
+ name string
25
+ requiresValue bool
26
+ }
27
+
28
+ type typeScriptExport struct {
29
+ value bool
30
+ typ bool
31
+ }
32
+
33
+ type namedTypeScriptExport struct {
34
+ source string
35
+ target string
36
+ typeOnly bool
37
+ }
38
+
39
+ // OverrideParityVerifier owns compiler-side parity checks for ledgered overrides.
40
+ type OverrideParityVerifier struct{}
41
+
42
+ // NewOverrideParityVerifier creates the override parity verifier.
43
+ func NewOverrideParityVerifier() *OverrideParityVerifier {
44
+ return &OverrideParityVerifier{}
45
+ }
46
+
47
+ // Verify checks ledgered override packages against JS/WASM Go exports and
48
+ // effective TypeScript package exports.
49
+ func (v *OverrideParityVerifier) Verify(
50
+ ctx context.Context,
51
+ graph *PackageGraph,
52
+ facts *OverrideFacts,
53
+ ) []Diagnostic {
54
+ if err := ctx.Err(); err != nil {
55
+ return []Diagnostic{contextCanceledDiagnostic(err)}
56
+ }
57
+ if graph == nil || facts == nil {
58
+ return nil
59
+ }
60
+
61
+ var diagnostics []Diagnostic
62
+ for _, node := range graph.Nodes {
63
+ if err := ctx.Err(); err != nil {
64
+ return append(diagnostics, contextCanceledDiagnostic(err))
65
+ }
66
+ if node == nil || !node.OverrideCandidate {
67
+ continue
68
+ }
69
+ ledger := facts.parityLedger(node.PkgPath)
70
+ if !ledger.Strict && len(ledger.Symbols) == 0 {
71
+ continue
72
+ }
73
+ pkg := graph.packagesByPath[node.PkgPath]
74
+ if pkg == nil || pkg.Types == nil {
75
+ diagnostics = append(diagnostics, Diagnostic{
76
+ Severity: DiagnosticSeverityError,
77
+ Code: "goscript/overrides:parity-no-package",
78
+ Message: "override parity verification requires typed Go package facts",
79
+ Detail: node.PkgPath,
80
+ })
81
+ continue
82
+ }
83
+ exports, err := facts.effectiveTypeScriptExports(node.PkgPath)
84
+ if err != nil {
85
+ diagnostics = append(diagnostics, Diagnostic{
86
+ Severity: DiagnosticSeverityError,
87
+ Code: "goscript/overrides:parity-export-scan",
88
+ Message: "override parity verification failed to scan TypeScript exports",
89
+ Detail: node.PkgPath + ": " + err.Error(),
90
+ })
91
+ continue
92
+ }
93
+ diagnostics = append(diagnostics, verifyOverrideParityPackage(node.PkgPath, pkg.Types, ledger, exports)...)
94
+ }
95
+ diagnostics = append(diagnostics, verifyBlockedOverrideUses(graph, facts)...)
96
+ return diagnostics
97
+ }
98
+
99
+ // VerifyNoDeferred reports transient parity entries that remain in packages
100
+ // whose parity surface is expected to be closed.
101
+ func (v *OverrideParityVerifier) VerifyNoDeferred(facts *OverrideFacts, pkgPaths ...string) []Diagnostic {
102
+ if facts == nil {
103
+ return nil
104
+ }
105
+ var diagnostics []Diagnostic
106
+ for _, pkgPath := range pkgPaths {
107
+ ledger := facts.parityLedger(pkgPath)
108
+ symbols := make([]string, 0, len(ledger.Symbols))
109
+ for symbol := range ledger.Symbols {
110
+ symbols = append(symbols, symbol)
111
+ }
112
+ slices.Sort(symbols)
113
+ for _, symbol := range symbols {
114
+ entry := ledger.Symbols[symbol]
115
+ if entry.Status != overrideParityStatusDeferred {
116
+ continue
117
+ }
118
+ diagnostics = append(diagnostics, Diagnostic{
119
+ Severity: DiagnosticSeverityError,
120
+ Code: "goscript/overrides:parity-deferred",
121
+ Message: "override parity ledger still contains a transient deferred symbol",
122
+ Detail: pkgPath + "." + symbol,
123
+ })
124
+ }
125
+ }
126
+ return diagnostics
127
+ }
128
+
129
+ func verifyOverrideParityPackage(
130
+ pkgPath string,
131
+ goPkg *types.Package,
132
+ ledger overrideParityLedger,
133
+ tsExports map[string]typeScriptExport,
134
+ ) []Diagnostic {
135
+ goExports := exportedPackageSymbols(goPkg)
136
+ goExportSet := make(map[string]bool, len(goExports))
137
+ var diagnostics []Diagnostic
138
+ for _, symbol := range goExports {
139
+ goExportSet[symbol.name] = true
140
+ entry, ok := ledger.Symbols[symbol.name]
141
+ if ledger.Strict && !ok {
142
+ diagnostics = append(diagnostics, Diagnostic{
143
+ Severity: DiagnosticSeverityError,
144
+ Code: "goscript/overrides:parity-unclassified",
145
+ Message: "Go export is missing from override parity ledger",
146
+ Detail: pkgPath + "." + symbol.name,
147
+ })
148
+ continue
149
+ }
150
+ if !ok {
151
+ continue
152
+ }
153
+ if entry.Status.requiresExport() && !symbol.satisfiedBy(tsExports[symbol.name]) {
154
+ diagnostics = append(diagnostics, Diagnostic{
155
+ Severity: DiagnosticSeverityError,
156
+ Code: "goscript/overrides:parity-missing-export",
157
+ Message: "override parity ledger requires a TypeScript export that is missing",
158
+ Detail: pkgPath + "." + symbol.name + " is classified as " + string(entry.Status),
159
+ })
160
+ }
161
+ if entry.Status.forbidsExport() && tsExports[symbol.name].present() {
162
+ diagnostics = append(diagnostics, Diagnostic{
163
+ Severity: DiagnosticSeverityError,
164
+ Code: "goscript/overrides:parity-unexpected-export",
165
+ Message: "override parity ledger marks a Go export blocked, but TypeScript exports it",
166
+ Detail: pkgPath + "." + symbol.name + " is classified as " + string(entry.Status),
167
+ })
168
+ }
169
+ }
170
+ for symbol := range ledger.Symbols {
171
+ if !goExportSet[symbol] {
172
+ diagnostics = append(diagnostics, Diagnostic{
173
+ Severity: DiagnosticSeverityError,
174
+ Code: "goscript/overrides:parity-unknown-symbol",
175
+ Message: "override parity ledger references a symbol not exported by the Go package",
176
+ Detail: pkgPath + "." + symbol,
177
+ })
178
+ }
179
+ }
180
+ return diagnostics
181
+ }
182
+
183
+ func (symbol goPackageExport) satisfiedBy(export typeScriptExport) bool {
184
+ if symbol.requiresValue {
185
+ return export.value
186
+ }
187
+ return export.typ
188
+ }
189
+
190
+ func (export typeScriptExport) present() bool {
191
+ return export.value || export.typ
192
+ }
193
+
194
+ func exportedPackageSymbols(goPkg *types.Package) []goPackageExport {
195
+ if goPkg == nil || goPkg.Scope() == nil {
196
+ return nil
197
+ }
198
+ names := goPkg.Scope().Names()
199
+ symbols := make([]goPackageExport, 0, len(names))
200
+ for _, name := range names {
201
+ if !ast.IsExported(name) {
202
+ continue
203
+ }
204
+ obj := goPkg.Scope().Lookup(name)
205
+ typeName, isTypeName := obj.(*types.TypeName)
206
+ symbols = append(symbols, goPackageExport{
207
+ name: name,
208
+ requiresValue: !isTypeName || typeNameRequiresValue(typeName),
209
+ })
210
+ }
211
+ slices.SortFunc(symbols, func(a, b goPackageExport) int {
212
+ return strings.Compare(a.name, b.name)
213
+ })
214
+ return symbols
215
+ }
216
+
217
+ func typeNameRequiresValue(typeName *types.TypeName) bool {
218
+ if typeName == nil || typeName.Type() == nil {
219
+ return false
220
+ }
221
+ _, ok := types.Unalias(typeName.Type()).Underlying().(*types.Struct)
222
+ return ok
223
+ }
224
+
225
+ func verifyBlockedOverrideUses(graph *PackageGraph, facts *OverrideFacts) []Diagnostic {
226
+ if graph == nil || facts == nil {
227
+ return nil
228
+ }
229
+ seen := make(map[string]bool)
230
+ var diagnostics []Diagnostic
231
+ for _, node := range graph.Nodes {
232
+ if node == nil || node.OverrideCandidate {
233
+ continue
234
+ }
235
+ pkg := graph.packagesByPath[node.PkgPath]
236
+ if pkg == nil || pkg.TypesInfo == nil {
237
+ continue
238
+ }
239
+ sourcePkgPath := packagePath(pkg)
240
+ for ident, obj := range pkg.TypesInfo.Uses {
241
+ if ident == nil || obj == nil || obj.Pkg() == nil {
242
+ continue
243
+ }
244
+ if sourcePkgPath == obj.Pkg().Path() {
245
+ continue
246
+ }
247
+ ledger := facts.parityLedger(obj.Pkg().Path())
248
+ entry, ok := ledger.Symbols[obj.Name()]
249
+ if !ok || entry.Status != overrideParityStatusBlocked {
250
+ continue
251
+ }
252
+ key := sourcePkgPath + "->" + obj.Pkg().Path() + "." + obj.Name()
253
+ if seen[key] {
254
+ continue
255
+ }
256
+ seen[key] = true
257
+ diagnostics = append(diagnostics, Diagnostic{
258
+ Severity: DiagnosticSeverityError,
259
+ Code: "goscript/overrides:parity-blocked-use",
260
+ Message: "Go code uses an override symbol classified as blocked",
261
+ Detail: obj.Pkg().Path() + "." + obj.Name() + ": " + entry.Reason,
262
+ })
263
+ }
264
+ }
265
+ return diagnostics
266
+ }
267
+
268
+ func (f *OverrideFacts) effectiveTypeScriptExports(pkgPath string) (map[string]typeScriptExport, error) {
269
+ pkg, _, ok := f.copyPackage(pkgPath)
270
+ if !ok {
271
+ return nil, errors.Errorf("override package %q is missing", pkgPath)
272
+ }
273
+ files := make(map[string]string, len(pkg.files))
274
+ for _, file := range pkg.files {
275
+ files[path.Clean(file.path)] = string(file.data)
276
+ }
277
+ exports := make(map[string]typeScriptExport)
278
+ visited := make(map[string]bool)
279
+ if err := collectTypeScriptExports(path.Join(pkgPath, "index.ts"), files, exports, visited); err != nil {
280
+ return nil, err
281
+ }
282
+ return exports, nil
283
+ }
284
+
285
+ func collectTypeScriptExports(
286
+ filePath string,
287
+ files map[string]string,
288
+ exports map[string]typeScriptExport,
289
+ visited map[string]bool,
290
+ ) error {
291
+ filePath = path.Clean(filePath)
292
+ if visited[filePath] {
293
+ return nil
294
+ }
295
+ visited[filePath] = true
296
+ data, ok := files[filePath]
297
+ if !ok {
298
+ return errors.Errorf("missing %s", filePath)
299
+ }
300
+ localBindings := localTypeScriptBindings(data)
301
+ for _, match := range overrideExportDeclarationPattern.FindAllStringSubmatch(data, -1) {
302
+ addTypeScriptExport(exports, match[2], typeScriptExportForDeclaration(match[1]))
303
+ }
304
+ for _, match := range overrideExportNamedPattern.FindAllStringSubmatch(data, -1) {
305
+ namedExports := parseNamedTypeScriptExports(match[2], match[1] != "")
306
+ if match[3] == "" {
307
+ if err := addLocalNamedTypeScriptExports(filePath, exports, localBindings, namedExports); err != nil {
308
+ return err
309
+ }
310
+ continue
311
+ }
312
+ target, ok := resolveOverrideExportPath(filePath, match[3])
313
+ if !ok {
314
+ continue
315
+ }
316
+ targetExports := make(map[string]typeScriptExport)
317
+ if err := collectTypeScriptExports(target, files, targetExports, make(map[string]bool)); err != nil {
318
+ return err
319
+ }
320
+ for _, namedExport := range namedExports {
321
+ sourceExport := targetExports[namedExport.source]
322
+ if !sourceExport.present() {
323
+ return errors.Errorf("%s re-exports missing symbol %s from %s", filePath, namedExport.source, target)
324
+ }
325
+ exportShape := sourceExport
326
+ if namedExport.typeOnly {
327
+ if !sourceExport.typ {
328
+ return errors.Errorf("%s re-exports missing type symbol %s from %s", filePath, namedExport.source, target)
329
+ }
330
+ exportShape = typeScriptExport{typ: true}
331
+ } else if !sourceExport.value {
332
+ return errors.Errorf("%s re-exports missing value symbol %s from %s", filePath, namedExport.source, target)
333
+ }
334
+ addTypeScriptExport(exports, namedExport.target, exportShape)
335
+ }
336
+ }
337
+ for _, match := range overrideExportAllPattern.FindAllStringSubmatch(data, -1) {
338
+ target, ok := resolveOverrideExportPath(filePath, match[1])
339
+ if ok {
340
+ if err := collectTypeScriptExports(target, files, exports, visited); err != nil {
341
+ return err
342
+ }
343
+ }
344
+ }
345
+ return nil
346
+ }
347
+
348
+ func typeScriptExportForDeclaration(kind string) typeScriptExport {
349
+ switch kind {
350
+ case "const", "let", "var", "function":
351
+ return typeScriptExport{value: true}
352
+ case "class", "enum":
353
+ return typeScriptExport{value: true, typ: true}
354
+ case "interface", "type":
355
+ return typeScriptExport{typ: true}
356
+ default:
357
+ return typeScriptExport{}
358
+ }
359
+ }
360
+
361
+ func addTypeScriptExport(exports map[string]typeScriptExport, name string, export typeScriptExport) {
362
+ if name == "" {
363
+ return
364
+ }
365
+ current := exports[name]
366
+ current.value = current.value || export.value
367
+ current.typ = current.typ || export.typ
368
+ exports[name] = current
369
+ }
370
+
371
+ func localTypeScriptBindings(data string) map[string]typeScriptExport {
372
+ bindings := make(map[string]typeScriptExport)
373
+ for _, match := range overrideLocalDeclarationPattern.FindAllStringSubmatch(data, -1) {
374
+ addTypeScriptExport(bindings, match[2], typeScriptExportForDeclaration(match[1]))
375
+ }
376
+ for _, match := range overrideImportNamedPattern.FindAllStringSubmatch(data, -1) {
377
+ for _, namedImport := range parseNamedTypeScriptExports(match[2], match[1] != "") {
378
+ exportShape := typeScriptExport{value: true, typ: true}
379
+ if namedImport.typeOnly {
380
+ exportShape = typeScriptExport{typ: true}
381
+ }
382
+ addTypeScriptExport(bindings, namedImport.target, exportShape)
383
+ }
384
+ }
385
+ return bindings
386
+ }
387
+
388
+ func addLocalNamedTypeScriptExports(
389
+ filePath string,
390
+ exports map[string]typeScriptExport,
391
+ localBindings map[string]typeScriptExport,
392
+ namedExports []namedTypeScriptExport,
393
+ ) error {
394
+ for _, namedExport := range namedExports {
395
+ exportShape := localBindings[namedExport.source]
396
+ if namedExport.typeOnly {
397
+ if !exportShape.typ {
398
+ return errors.Errorf("%s exports missing local type symbol %s", filePath, namedExport.source)
399
+ }
400
+ exportShape = typeScriptExport{typ: true}
401
+ } else if !exportShape.value {
402
+ return errors.Errorf("%s exports missing local value symbol %s", filePath, namedExport.source)
403
+ }
404
+ addTypeScriptExport(exports, namedExport.target, exportShape)
405
+ }
406
+ return nil
407
+ }
408
+
409
+ func parseNamedTypeScriptExports(list string, statementTypeOnly bool) []namedTypeScriptExport {
410
+ var exports []namedTypeScriptExport
411
+ for item := range strings.SplitSeq(list, ",") {
412
+ item = strings.TrimSpace(item)
413
+ if item == "" {
414
+ continue
415
+ }
416
+ typeOnly := statementTypeOnly
417
+ if strings.HasPrefix(item, "type ") {
418
+ typeOnly = true
419
+ item = strings.TrimSpace(strings.TrimPrefix(item, "type "))
420
+ }
421
+ parts := strings.Fields(item)
422
+ if len(parts) == 0 {
423
+ continue
424
+ }
425
+ namedExport := namedTypeScriptExport{
426
+ source: parts[0],
427
+ target: parts[0],
428
+ typeOnly: typeOnly,
429
+ }
430
+ if len(parts) >= 3 && parts[len(parts)-2] == "as" {
431
+ namedExport.target = parts[len(parts)-1]
432
+ }
433
+ exports = append(exports, namedExport)
434
+ }
435
+ return exports
436
+ }
437
+
438
+ func resolveOverrideExportPath(currentFile, spec string) (string, bool) {
439
+ if !strings.HasPrefix(spec, ".") {
440
+ return "", false
441
+ }
442
+ target := path.Clean(path.Join(path.Dir(currentFile), spec))
443
+ switch path.Ext(target) {
444
+ case ".js", ".ts":
445
+ target = strings.TrimSuffix(target, path.Ext(target)) + ".ts"
446
+ case "":
447
+ target = path.Join(target, "index.ts")
448
+ }
449
+ return target, true
450
+ }