@ttsc/wasm 0.30.4 → 0.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/build/build-wasm.cjs +5 -4
- package/build/go-build-cache.cjs +347 -0
- package/build/pack-prepare.cjs +3 -2
- package/cmd/ttsc-wasm/main.go +22 -10
- package/cmd/ttsc-wasm/main_wasm.go +2 -2
- package/dist/.ttsc-wasm-build.json +138 -58
- package/dist/go.mod +7 -5
- package/dist/ttsc.wasm +2 -2
- package/go.mod +7 -5
- package/go.sum +10 -10
- package/host/api.go +34 -41
- package/host/doc.go +7 -6
- package/host/expose.go +42 -0
- package/host/fountain.go +192 -22
- package/host/host.go +10 -25
- package/host/host_native.go +3 -5
- package/host/invoke.go +133 -0
- package/host/plugin.go +37 -72
- package/host/result.go +108 -0
- package/lib/src/BootTtscWorkerTerminationError.d.ts +20 -0
- package/lib/src/BootTtscWorkerTerminationError.js +20 -0
- package/lib/src/BootTtscWorkerTerminationError.js.map +1 -1
- package/lib/src/MemFSError.d.ts +21 -2
- package/lib/src/MemFSError.js +25 -2
- package/lib/src/MemFSError.js.map +1 -1
- package/lib/src/bootTtsc.d.ts +49 -2
- package/lib/src/bootTtsc.js +89 -23
- package/lib/src/bootTtsc.js.map +1 -1
- package/lib/src/createMemFS.d.ts +45 -0
- package/lib/src/createMemFS.js +269 -66
- package/lib/src/createMemFS.js.map +1 -1
- package/lib/src/parseResult.d.ts +19 -0
- package/lib/src/parseResult.js +19 -0
- package/lib/src/parseResult.js.map +1 -1
- package/lib/src/structures/IBootResult.d.ts +20 -2
- package/lib/src/structures/IBootTtscOptions.d.ts +28 -6
- package/lib/src/structures/IFileStats.d.ts +51 -0
- package/lib/src/structures/IMemFSHost.d.ts +89 -0
- package/lib/src/structures/ITtscApi.d.ts +154 -9
- package/lib/src/structures/ITtscBuildOpts.d.ts +18 -1
- package/lib/src/structures/ITtscCompileResult.d.ts +20 -2
- package/lib/src/structures/ITtscDiagnostic.d.ts +25 -1
- package/lib/src/structures/ITtscFileQuery.d.ts +19 -1
- package/lib/src/structures/ITtscFountainDiagnosticsResult.d.ts +20 -1
- package/lib/src/structures/ITtscNodeAtPositionResult.d.ts +18 -1
- package/lib/src/structures/ITtscNodeInfo.d.ts +23 -2
- package/lib/src/structures/ITtscPluginOpts.d.ts +24 -3
- package/lib/src/structures/ITtscPositionQuery.d.ts +21 -4
- package/lib/src/structures/ITtscReleaseSnapshotResult.d.ts +22 -2
- package/lib/src/structures/ITtscResult.d.ts +31 -5
- package/lib/src/structures/ITtscSnapshotHandle.d.ts +19 -1
- package/lib/src/structures/ITtscSnapshotResult.d.ts +22 -1
- package/lib/src/structures/ITtscSnapshotsResult.d.ts +19 -1
- package/lib/src/structures/ITtscSourceFileTextResult.d.ts +19 -1
- package/lib/src/structures/ITtscSourceFilesResult.d.ts +23 -2
- package/lib/src/structures/ITtscSymbolAtPositionResult.d.ts +18 -1
- package/lib/src/structures/ITtscSymbolDeclaration.d.ts +25 -2
- package/lib/src/structures/ITtscSymbolInfo.d.ts +19 -1
- package/lib/src/structures/ITtscTransformResult.d.ts +21 -3
- package/lib/src/structures/ITtscTypeAtPositionResult.d.ts +18 -1
- package/lib/src/structures/ITtscTypeInfo.d.ts +19 -1
- package/lib/src/structures/ITtscVersion.d.ts +28 -1
- package/lib/src/structures/IWasmExecFS.d.ts +310 -0
- package/package.json +4 -2
- package/shim-vendor/shim/ast/enums_gen.go +4 -2
- package/shim-vendor/shim/ast/go.mod +5 -5
- package/shim-vendor/shim/ast/go.sum +10 -10
- package/shim-vendor/shim/ast/lint.go +1088 -20
- package/shim-vendor/shim/ast/parent.go +38 -22
- package/shim-vendor/shim/ast/safe_text.go +48 -26
- package/shim-vendor/shim/ast/shim.go +1307 -20
- package/shim-vendor/shim/ast/test/next_jsdoc_comment_location_reaches_variable_statement_test.go +51 -0
- package/shim-vendor/shim/ast/test/node_text_joins_multi_hop_qualified_name_test.go +24 -9
- package/shim-vendor/shim/ast/test/node_text_joins_one_hop_qualified_name_test.go +9 -5
- package/shim-vendor/shim/ast/test/node_text_returns_empty_for_nil_test.go +13 -5
- package/shim-vendor/shim/ast/test/node_text_returns_identifier_text_test.go +12 -5
- package/shim-vendor/shim/ast/test/node_text_skips_empty_qualified_left_test.go +35 -5
- package/shim-vendor/shim/astnav/go.mod +5 -5
- package/shim-vendor/shim/astnav/go.sum +12 -10
- package/shim-vendor/shim/astnav/shim.go +9 -0
- package/shim-vendor/shim/bundled/go.mod +7 -1
- package/shim-vendor/shim/bundled/go.sum +12 -0
- package/shim-vendor/shim/checker/enums_gen.go +4 -2
- package/shim-vendor/shim/checker/extra-shim.json +6 -0
- package/shim-vendor/shim/checker/go.mod +5 -5
- package/shim-vendor/shim/checker/go.sum +10 -10
- package/shim-vendor/shim/checker/node_builder_fields_gen.go +19 -0
- package/shim-vendor/shim/checker/shim.go +827 -114
- package/shim-vendor/shim/compiler/emit_sourcemap.go +68 -29
- package/shim-vendor/shim/compiler/emitassemble.go +36 -2
- package/shim-vendor/shim/compiler/emithook.go +13 -3
- package/shim-vendor/shim/compiler/go.mod +5 -5
- package/shim-vendor/shim/compiler/go.sum +10 -10
- package/shim-vendor/shim/compiler/incremental.go +56 -20
- package/shim-vendor/shim/compiler/resolution.go +92 -9
- package/shim-vendor/shim/core/enums_gen.go +2 -2
- package/shim-vendor/shim/core/go.mod +6 -1
- package/shim-vendor/shim/core/go.sum +10 -0
- package/shim-vendor/shim/core/modulekind.go +9 -0
- package/shim-vendor/shim/core/shim.go +157 -6
- package/shim-vendor/shim/diagnosticwriter/go.mod +10 -1
- package/shim-vendor/shim/diagnosticwriter/go.sum +20 -0
- package/shim-vendor/shim/diagnosticwriter/lint.go +188 -10
- package/shim-vendor/shim/diagnosticwriter/shim.go +14 -0
- package/shim-vendor/shim/lsp/go.mod +5 -5
- package/shim-vendor/shim/lsp/go.sum +10 -10
- package/shim-vendor/shim/lsp/shim.go +78 -2
- package/shim-vendor/shim/parser/go.mod +10 -1
- package/shim-vendor/shim/parser/go.sum +22 -0
- package/shim-vendor/shim/printer/emithost.go +46 -1
- package/shim-vendor/shim/printer/go.mod +5 -5
- package/shim-vendor/shim/printer/go.sum +10 -10
- package/shim-vendor/shim/printer/shim.go +114 -7
- package/shim-vendor/shim/printer/sourcemap.go +55 -0
- package/shim-vendor/shim/scanner/go.mod +10 -1
- package/shim-vendor/shim/scanner/go.sum +20 -0
- package/shim-vendor/shim/scanner/regexp.go +19 -4
- package/shim-vendor/shim/scanner/shim.go +3 -0
- package/shim-vendor/shim/stringutil/extra-shim.json +1 -0
- package/shim-vendor/shim/stringutil/go.mod +5 -0
- package/shim-vendor/shim/stringutil/go.sum +2 -0
- package/shim-vendor/shim/stringutil/shim.go +119 -0
- package/shim-vendor/shim/transformers/go.mod +5 -5
- package/shim-vendor/shim/transformers/go.sum +12 -10
- package/shim-vendor/shim/transformers/shim.go +12 -3
- package/shim-vendor/shim/tsoptions/command_line_raw.go +44 -0
- package/shim-vendor/shim/tsoptions/go.mod +10 -1
- package/shim-vendor/shim/tsoptions/go.sum +22 -0
- package/shim-vendor/shim/tsoptions/shim.go +1 -1
- package/shim-vendor/shim/tspath/go.mod +1 -1
- package/shim-vendor/shim/tspath/go.sum +6 -0
- package/shim-vendor/shim/vfs/cachedvfs/go.mod +3 -1
- package/shim-vendor/shim/vfs/cachedvfs/go.sum +12 -0
- package/shim-vendor/shim/vfs/decode.go +26 -0
- package/shim-vendor/shim/vfs/decode_test.go +42 -0
- package/shim-vendor/shim/vfs/go.mod +7 -1
- package/shim-vendor/shim/vfs/go.sum +12 -0
- package/shim-vendor/shim/vfs/osvfs/go.mod +7 -1
- package/shim-vendor/shim/vfs/osvfs/go.sum +12 -0
- package/src/BootTtscWorkerTerminationError.ts +22 -0
- package/src/MemFSError.ts +29 -2
- package/src/bootTtsc.ts +104 -28
- package/src/createMemFS.ts +291 -64
- package/src/parseResult.ts +19 -0
- package/src/structures/IBootResult.ts +21 -2
- package/src/structures/IBootTtscOptions.ts +32 -6
- package/src/structures/IFileStats.ts +65 -0
- package/src/structures/IMemFSHost.ts +97 -0
- package/src/structures/ITtscApi.ts +154 -9
- package/src/structures/ITtscBuildOpts.ts +19 -1
- package/src/structures/ITtscCompileResult.ts +21 -2
- package/src/structures/ITtscDiagnostic.ts +32 -1
- package/src/structures/ITtscFileQuery.ts +19 -1
- package/src/structures/ITtscFountainDiagnosticsResult.ts +20 -1
- package/src/structures/ITtscNodeAtPositionResult.ts +18 -1
- package/src/structures/ITtscNodeInfo.ts +27 -2
- package/src/structures/ITtscPluginOpts.ts +28 -3
- package/src/structures/ITtscPositionQuery.ts +21 -4
- package/src/structures/ITtscReleaseSnapshotResult.ts +22 -2
- package/src/structures/ITtscResult.ts +34 -5
- package/src/structures/ITtscSnapshotHandle.ts +19 -1
- package/src/structures/ITtscSnapshotResult.ts +22 -1
- package/src/structures/ITtscSnapshotsResult.ts +19 -1
- package/src/structures/ITtscSourceFileTextResult.ts +19 -1
- package/src/structures/ITtscSourceFilesResult.ts +23 -2
- package/src/structures/ITtscSymbolAtPositionResult.ts +18 -1
- package/src/structures/ITtscSymbolDeclaration.ts +27 -2
- package/src/structures/ITtscSymbolInfo.ts +23 -1
- package/src/structures/ITtscTransformResult.ts +22 -3
- package/src/structures/ITtscTypeAtPositionResult.ts +18 -1
- package/src/structures/ITtscTypeInfo.ts +20 -1
- package/src/structures/ITtscVersion.ts +33 -1
- package/src/structures/IWasmExecFS.ts +336 -0
package/host/api.go
CHANGED
|
@@ -16,50 +16,22 @@ import (
|
|
|
16
16
|
"github.com/samchon/ttsc/packages/ttsc/driver"
|
|
17
17
|
)
|
|
18
18
|
|
|
19
|
-
// APIResult is the stdout/stderr capture returned by InvokePlugin. The
|
|
20
|
-
// js/wasm binding wraps it in the same JS result envelope that build/check/
|
|
21
|
-
// transform use, adding `result` when an endpoint has a JSON payload. `code`
|
|
22
|
-
// follows the native CLI exit-code contract (0 success, 2 compiler/config/
|
|
23
|
-
// usage error, 3 runtime error).
|
|
24
|
-
type APIResult struct {
|
|
25
|
-
Code int `json:"code"`
|
|
26
|
-
Stdout string `json:"stdout"`
|
|
27
|
-
Stderr string `json:"stderr"`
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// CompileResult mirrors `ttsc api-compile`. Field names are TypeScript-style
|
|
31
|
-
// so JS callers can use it directly without remapping.
|
|
32
|
-
type CompileResult struct {
|
|
33
|
-
Diagnostics []CompileDiagnostic `json:"diagnostics,omitempty"`
|
|
34
|
-
// Output maps cwd-relative paths to emitted JS / d.ts text. Empty when
|
|
35
|
-
// the program produced no files (e.g. `noEmit` projects).
|
|
36
|
-
Output map[string]string `json:"output"`
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// TransformResult is the no-emit companion. The `typescript` map keys files
|
|
40
|
-
// the same way `output` does in compile mode.
|
|
41
|
-
type TransformResult struct {
|
|
42
|
-
Diagnostics []CompileDiagnostic `json:"diagnostics,omitempty"`
|
|
43
|
-
TypeScript map[string]string `json:"typescript"`
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// CompileDiagnostic is the public TypeScript-side diagnostic DTO. Mirrors the
|
|
47
|
-
// shape `ttsc api-compile` writes so the JS host can render it without
|
|
48
|
-
// remapping fields.
|
|
49
|
-
type CompileDiagnostic struct {
|
|
50
|
-
File *string `json:"file"`
|
|
51
|
-
Category string `json:"category"`
|
|
52
|
-
Code int32 `json:"code"`
|
|
53
|
-
Start *int `json:"start,omitempty"`
|
|
54
|
-
Length *int `json:"length,omitempty"`
|
|
55
|
-
Line int `json:"line,omitempty"`
|
|
56
|
-
Character int `json:"character,omitempty"`
|
|
57
|
-
MessageText string `json:"messageText"`
|
|
58
|
-
}
|
|
59
|
-
|
|
60
19
|
// Build runs `ttsc build`-shaped emit: load the project, emit JS, return the
|
|
61
20
|
// emitted text map + diagnostics as JSON. `cwd` must be an absolute path
|
|
62
21
|
// inside the host filesystem; `tsconfigPath` may be relative to cwd.
|
|
22
|
+
//
|
|
23
|
+
// The loaded Program is closed on every return after acquisition. Compiler
|
|
24
|
+
// diagnostics still accompany emitted files; code 2 reports compiler errors,
|
|
25
|
+
// while code 3 reports emit or serialization failures.
|
|
26
|
+
//
|
|
27
|
+
// @evidence contracts/common.md#principled-implementation LoadProgram and EmitAll own compiler behavior; encoding/json projects their results through the documented envelope.
|
|
28
|
+
// @evidence contracts/common.md#clear-and-simple-design One emit pipeline owns project acquisition, supported WriteFile capture and diagnostics; shared projection helpers centralize path and diagnostic policy.
|
|
29
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts Emit uses supported compiler hooks, without patching foreign emitters or synthesizing expected outputs.
|
|
30
|
+
// @evidence contracts/common.md#meaningful-documentation Native paragraphs explain paths, ownership and failure stages under the documentation skill's rationale guidance.
|
|
31
|
+
// @evidence contracts/portability.md#os-neutral-implementation LoadProgram owns filesystem access through the driver's supported host. Native filepath.Rel identifies inside/outside destinations, including volume differences, and ToSlash changes JSON spelling without lowercasing identity.
|
|
32
|
+
// @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Build closes its Program before returning and transfers the output to the caller, so it retains nothing.
|
|
33
|
+
// @evidenceExclude contracts/performance.md#efficient-algorithms Build delegates parsing, checking and emit to the driver and adds one pass over the diagnostics and the emitted output map.
|
|
34
|
+
// @evidenceExclude contracts/performance.md#reuse-equivalent-work Build loads a fresh Program per call because the virtual filesystem may have changed; sharing a loaded Program is the snapshot verbs' purpose.
|
|
63
35
|
func Build(cwd, tsconfigPath string) ([]byte, int, error) {
|
|
64
36
|
prog, diags, err := driver.LoadProgram(cwd, tsconfigPath, driver.LoadProgramOptions{
|
|
65
37
|
ForceEmit: true,
|
|
@@ -106,6 +78,15 @@ func Build(cwd, tsconfigPath string) ([]byte, int, error) {
|
|
|
106
78
|
|
|
107
79
|
// Check runs the typecheck pipeline without emitting JS. The returned JSON
|
|
108
80
|
// has the same shape as Build but with an empty `output` map.
|
|
81
|
+
//
|
|
82
|
+
// @evidence contracts/common.md#principled-implementation ForceNoEmit selects the driver's check pipeline and a deferred Close owns the loaded program.
|
|
83
|
+
// @evidence contracts/common.md#clear-and-simple-design The no-emit entry keeps loading and diagnostic projection explicit while sharing DTO and path helpers with the emit entry.
|
|
84
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts No-emit is requested from the compiler rather than hiding an unnecessary emit behind an empty result.
|
|
85
|
+
// @evidence contracts/common.md#meaningful-documentation Native comments explain no-emit and payload equivalence under the documentation skill's context guidance.
|
|
86
|
+
// @evidence contracts/portability.md#os-neutral-implementation The driver resolves cwd/config through its filesystem host; diagnostic paths use filepath.ToSlash only for wire spelling. The adapter neither guesses case policy nor constructs a shell command.
|
|
87
|
+
// @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Check closes its Program before returning and transfers the diagnostics to the caller, so it retains nothing.
|
|
88
|
+
// @evidenceExclude contracts/performance.md#efficient-algorithms Check delegates loading and checking to the driver and adds one pass over the diagnostics.
|
|
89
|
+
// @evidenceExclude contracts/performance.md#reuse-equivalent-work Check loads a fresh Program per call because the virtual filesystem may have changed; sharing a loaded Program is the snapshot verbs' purpose.
|
|
109
90
|
func Check(cwd, tsconfigPath string) ([]byte, int, error) {
|
|
110
91
|
prog, diags, err := driver.LoadProgram(cwd, tsconfigPath, driver.LoadProgramOptions{
|
|
111
92
|
ForceNoEmit: true,
|
|
@@ -138,6 +119,18 @@ func Check(cwd, tsconfigPath string) ([]byte, int, error) {
|
|
|
138
119
|
// Transform returns every source file the program saw, keyed by
|
|
139
120
|
// project-relative path. The playground uses this to render the TS view
|
|
140
121
|
// after source rewrites (e.g. paths rewriting) have been applied.
|
|
122
|
+
//
|
|
123
|
+
// Sources inside cwd use relative keys; outside sources retain absolute slash
|
|
124
|
+
// paths. The invocation closes the loaded Program after copying its source text.
|
|
125
|
+
//
|
|
126
|
+
// @evidence contracts/common.md#principled-implementation LoadProgram supplies post-plugin SourceFiles and encoding/json preserves their source-text projection.
|
|
127
|
+
// @evidence contracts/common.md#clear-and-simple-design The source projection is separate from emit, and common path/diagnostic helpers keep their shared representation policy in one place.
|
|
128
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts The program's own text is authoritative, without a secondary emitter-based reconstruction.
|
|
129
|
+
// @evidence contracts/common.md#meaningful-documentation Separate paragraphs explain stage, path convention and ownership under the documentation skill.
|
|
130
|
+
// @evidence contracts/portability.md#os-neutral-implementation Source identities come from LoadProgram, then the shared filepath relative/absolute mapping preserves native case and handles outside/other-volume paths before slash serialization.
|
|
131
|
+
// @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Transform closes its Program after copying the source text, so it retains nothing.
|
|
132
|
+
// @evidenceExclude contracts/performance.md#efficient-algorithms Transform delegates loading to the driver and adds one pass over the source files and diagnostics.
|
|
133
|
+
// @evidenceExclude contracts/performance.md#reuse-equivalent-work Transform loads a fresh Program per call because the virtual filesystem may have changed; sharing a loaded Program is the snapshot verbs' purpose.
|
|
141
134
|
func Transform(cwd, tsconfigPath string) ([]byte, int, error) {
|
|
142
135
|
prog, diags, err := driver.LoadProgram(cwd, tsconfigPath, driver.LoadProgramOptions{
|
|
143
136
|
ForceNoEmit: true,
|
package/host/doc.go
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
// A consumer wasm looks like this:
|
|
5
5
|
//
|
|
6
|
-
// //go:build js
|
|
6
|
+
// //go:build js && wasm
|
|
7
7
|
// package main
|
|
8
8
|
//
|
|
9
9
|
// import (
|
|
@@ -12,14 +12,15 @@
|
|
|
12
12
|
// )
|
|
13
13
|
//
|
|
14
14
|
// func main() {
|
|
15
|
-
// //
|
|
15
|
+
// // A valid registration installs the JS API until Worker termination.
|
|
16
16
|
// host.Expose("yourApi", host.Config{
|
|
17
17
|
// Plugins: []host.Plugin{yourplugin.New()},
|
|
18
18
|
// })
|
|
19
19
|
// }
|
|
20
20
|
//
|
|
21
21
|
// Expose binds `globalThis[name]` to an object that exposes ttsc's base
|
|
22
|
-
// project commands (build, check, transform, version)
|
|
22
|
+
// project commands (build, check, transform, version), the retained-program
|
|
23
|
+
// queries (snapshot and the get* verbs), `plugins()`, and
|
|
23
24
|
// `plugin({ name, command, ...opts })`, which routes into a Plugin's
|
|
24
25
|
// CLI-shaped Run callback. Every async endpoint returns the JS result envelope;
|
|
25
26
|
// build/check/transform place JSON payloads in `result`, while plugin output
|
|
@@ -27,7 +28,7 @@
|
|
|
27
28
|
// contract — the same shape the native sidecars implement — so the wasm and
|
|
28
29
|
// the native CLI can share their Run* entry points byte-for-byte.
|
|
29
30
|
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
31
|
+
// JavaScript bindings use //go:build js && wasm. A native build selects a
|
|
32
|
+
// no-op Expose with the same signature and the shared project/plugin helpers;
|
|
33
|
+
// checking the bodies of js/wasm-only files requires a js/wasm build.
|
|
33
34
|
package host
|
package/host/expose.go
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
package host
|
|
2
|
+
|
|
3
|
+
// API stability: experimental until v1.0; signatures may change between
|
|
4
|
+
// minor releases. Pin exact versions in production playgrounds.
|
|
5
|
+
//
|
|
6
|
+
// Expose installs `globalThis[apiName]` with the base API endpoints and the
|
|
7
|
+
// plugin dispatcher, then keeps the Go runtime alive until Worker termination.
|
|
8
|
+
// Invalid or duplicate registration reports failure and returns before binding.
|
|
9
|
+
// A native build (without js/wasm) selects an alternative that installs nothing
|
|
10
|
+
// and returns immediately, so native entrypoints can import the package.
|
|
11
|
+
//
|
|
12
|
+
// The contract:
|
|
13
|
+
//
|
|
14
|
+
// - globalThis[apiName].version() → { version, commit, date, go, goos, goarch }
|
|
15
|
+
// - globalThis[apiName].build({ cwd, tsconfig }) → Promise<ITtscResult>
|
|
16
|
+
// - globalThis[apiName].check({ cwd, tsconfig }) → Promise<ITtscResult>
|
|
17
|
+
// - globalThis[apiName].transform({ cwd, tsconfig }) → Promise<ITtscResult>
|
|
18
|
+
// - globalThis[apiName].plugin({ name, command, ...opts}) → Promise<ITtscResult>
|
|
19
|
+
// - globalThis[apiName].plugins() → string[] of registered names
|
|
20
|
+
//
|
|
21
|
+
// The retained-program verbs (snapshot, releaseSnapshot, snapshots,
|
|
22
|
+
// getSourceFiles, getSourceFileText, getDiagnostics, getNodeAtPosition,
|
|
23
|
+
// getTypeAtPosition, getSymbolAtPosition) are installed beside them and return
|
|
24
|
+
// the same envelope.
|
|
25
|
+
//
|
|
26
|
+
// build/check/transform encode their structured payloads as JSON in
|
|
27
|
+
// ITtscResult.result. Plugin stdout/stderr are captured in the envelope streams.
|
|
28
|
+
//
|
|
29
|
+
// A matching readiness resolver is invoked: `globalThis[`${apiName}Ready`]`.
|
|
30
|
+
// JS callers register this BEFORE go.run begins so they can await wasm boot.
|
|
31
|
+
//
|
|
32
|
+
// @evidence contracts/common.md#principled-implementation syscall/js bindings and explicit Ready/Failed callbacks implement the Go wasm host protocol; an atomic gate owns one installation per instance, and build constraints select a no-op native alternative behind the same signature.
|
|
33
|
+
// @evidence contracts/common.md#clear-and-simple-design Expose owns one registration and readiness boundary; project adapters, plugin invocation and fountain queries remain named helpers with their own state instead of duplicating binding policy.
|
|
34
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts Registered plugins use owned invocation streams rather than foreign global-output replacement; rejected duplicate installation is reported through the boot failure boundary.
|
|
35
|
+
// @evidence contracts/common.md#meaningful-documentation Native paragraphs explain setup order, payload channels and runtime lifetime under the documentation skill's context guidance.
|
|
36
|
+
// @evidence contracts/performance.md#efficient-algorithms Registration visits P supplied plugins once with map duplicate checks and creates a fixed set of endpoint bindings. Snapshot lookup uses a map; source lookup uses the driver's existing compiler index, with path normalization and hashing proportional to path length. A relative path may require a second indexed lookup. List/diagnostic queries traverse their requested results; parsing, checking and printing remain driver Program work.
|
|
37
|
+
// @evidence contracts/performance.md#reuse-equivalent-work Fountain queries reuse the explicitly acquired Program and its checker under one opaque handle; registry and entry locks keep queries within that snapshot's lifetime. Editing MemFS does not refresh an existing snapshot, so callers release and reacquire when they need a new project view rather than sharing by path alone.
|
|
38
|
+
// @evidence contracts/performance.md#bound-retention-and-release-resources The wasm instance owns P plugin registrations, pinned js.Func bindings and its keepalive until Worker termination. Each acquired snapshot owns a Program; registry readers finish before release deletes and closes it. Snapshot count, Program bytes and concurrent invocation tasks have no fixed bound. Promise executors release their js.Func after settlement, and InvokePlugin owns its own streams and child work.
|
|
39
|
+
// @evidenceExclude contracts/portability.md#os-neutral-implementation Expose binds a JavaScript global in the wasm runtime and performs no native filesystem, path or process operation; the native alternative does nothing.
|
|
40
|
+
func Expose(apiName string, cfg Config) {
|
|
41
|
+
expose(apiName, cfg)
|
|
42
|
+
}
|
package/host/fountain.go
CHANGED
|
@@ -22,6 +22,7 @@ package host
|
|
|
22
22
|
import (
|
|
23
23
|
"encoding/json"
|
|
24
24
|
"fmt"
|
|
25
|
+
"math"
|
|
25
26
|
"path/filepath"
|
|
26
27
|
"sync"
|
|
27
28
|
"sync/atomic"
|
|
@@ -73,79 +74,234 @@ func fountainAPIMap() map[string]any {
|
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
// SnapshotResult is the response shape for `snapshot()`.
|
|
77
|
+
// The caller owns Handle and must pass it to releaseSnapshot after its queries.
|
|
78
|
+
//
|
|
79
|
+
// @evidence contracts/common.md#principled-implementation An opaque string projects registry identity without exposing a Go Program through JSON.
|
|
80
|
+
// @evidence contracts/common.md#clear-and-simple-design One opaque identity transfers query access while the Program and its ownership remain in the native registry.
|
|
81
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts Identity refers to an actual retained program rather than a reconstructed project path.
|
|
82
|
+
// @evidence contracts/common.md#meaningful-documentation The Go comment explains opaque identity and caller release ownership under the documentation skill.
|
|
83
|
+
// @evidenceExclude contracts/performance.md#bound-retention-and-release-resources SnapshotResult is a data type and acquires no handle, task or retained state.
|
|
84
|
+
// @evidenceExclude contracts/performance.md#efficient-algorithms SnapshotResult is a data type and chooses no algorithm or processing strategy.
|
|
85
|
+
// @evidenceExclude contracts/performance.md#reuse-equivalent-work SnapshotResult is a data type and coordinates no shared or repeated computation.
|
|
86
|
+
// @evidenceExclude contracts/portability.md#os-neutral-implementation SnapshotResult is a data type and performs no native filesystem, path or process operation.
|
|
76
87
|
type SnapshotResult struct {
|
|
88
|
+
// Handle is opaque and valid until released in this wasm instance.
|
|
77
89
|
Handle string `json:"handle"`
|
|
78
90
|
}
|
|
79
91
|
|
|
80
92
|
// ReleaseSnapshotResult is the response shape for `releaseSnapshot()`.
|
|
93
|
+
//
|
|
94
|
+
// @evidence contracts/common.md#principled-implementation A boolean distinguishes a removed registry entry from idempotent absent-handle release.
|
|
95
|
+
// @evidence contracts/common.md#clear-and-simple-design One outcome bit reports removal without duplicating the request handle or native cleanup state.
|
|
96
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts An absent entry is not reported as a fabricated successful removal.
|
|
97
|
+
// @evidence contracts/common.md#meaningful-documentation Native comments explain the release outcome under the documentation skill's absence guidance.
|
|
98
|
+
// @evidenceExclude contracts/performance.md#bound-retention-and-release-resources ReleaseSnapshotResult is a data type and acquires no handle, task or retained state.
|
|
99
|
+
// @evidenceExclude contracts/performance.md#efficient-algorithms ReleaseSnapshotResult is a data type and chooses no algorithm or processing strategy.
|
|
100
|
+
// @evidenceExclude contracts/performance.md#reuse-equivalent-work ReleaseSnapshotResult is a data type and coordinates no shared or repeated computation.
|
|
101
|
+
// @evidenceExclude contracts/portability.md#os-neutral-implementation ReleaseSnapshotResult is a data type and performs no native filesystem, path or process operation.
|
|
81
102
|
type ReleaseSnapshotResult struct {
|
|
103
|
+
// Released is false when the handle was never present or already removed.
|
|
82
104
|
Released bool `json:"released"`
|
|
83
105
|
}
|
|
84
106
|
|
|
85
107
|
// ListSnapshotsResult is the response shape for `snapshots()`.
|
|
108
|
+
//
|
|
109
|
+
// @evidence contracts/common.md#principled-implementation A string slice projects registry identities without a second public program representation.
|
|
110
|
+
// @evidence contracts/common.md#clear-and-simple-design A flat current-handle list exposes membership without expanding each entry into an unused snapshot descriptor.
|
|
111
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts Current map membership supplies the list rather than a history of expected handles.
|
|
112
|
+
// @evidence contracts/common.md#meaningful-documentation Native member comments identify live state and unspecified order under the documentation skill.
|
|
113
|
+
// @evidenceExclude contracts/performance.md#bound-retention-and-release-resources ListSnapshotsResult is a data type and acquires no handle, task or retained state.
|
|
114
|
+
// @evidenceExclude contracts/performance.md#efficient-algorithms ListSnapshotsResult is a data type and chooses no algorithm or processing strategy.
|
|
115
|
+
// @evidenceExclude contracts/performance.md#reuse-equivalent-work ListSnapshotsResult is a data type and coordinates no shared or repeated computation.
|
|
116
|
+
// @evidenceExclude contracts/portability.md#os-neutral-implementation ListSnapshotsResult is a data type and performs no native filesystem, path or process operation.
|
|
86
117
|
type ListSnapshotsResult struct {
|
|
118
|
+
// Handles lists live registry keys in unspecified order; empty encodes as [].
|
|
87
119
|
Handles []string `json:"handles"`
|
|
88
120
|
}
|
|
89
121
|
|
|
90
122
|
// GetSourceFilesResult is the response shape for `getSourceFiles()`.
|
|
123
|
+
//
|
|
124
|
+
// @evidence contracts/common.md#principled-implementation The program's SourceFiles are projected into path strings through the shared output-key policy.
|
|
125
|
+
// @evidence contracts/common.md#clear-and-simple-design File identities are separate from source text and semantic metadata, keeping listing focused on program membership.
|
|
126
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts Compiler membership determines files instead of a guessed filesystem glob.
|
|
127
|
+
// @evidence contracts/common.md#meaningful-documentation The member comment explains path bases and declaration exclusion under the documentation skill.
|
|
128
|
+
// @evidenceExclude contracts/performance.md#bound-retention-and-release-resources GetSourceFilesResult is a data type and acquires no handle, task or retained state.
|
|
129
|
+
// @evidenceExclude contracts/performance.md#efficient-algorithms GetSourceFilesResult is a data type and chooses no algorithm or processing strategy.
|
|
130
|
+
// @evidenceExclude contracts/performance.md#reuse-equivalent-work GetSourceFilesResult is a data type and coordinates no shared or repeated computation.
|
|
131
|
+
// @evidenceExclude contracts/portability.md#os-neutral-implementation GetSourceFilesResult is a data type and performs no native filesystem, path or process operation.
|
|
91
132
|
type GetSourceFilesResult struct {
|
|
133
|
+
// Files excludes declarations; paths outside cwd remain absolute slash paths.
|
|
92
134
|
Files []string `json:"files"`
|
|
93
135
|
}
|
|
94
136
|
|
|
95
137
|
// GetSourceFileTextResult is the response shape for `getSourceFileText()`.
|
|
138
|
+
//
|
|
139
|
+
// @evidence contracts/common.md#principled-implementation A required string projects program text while file lookup failures use the error envelope.
|
|
140
|
+
// @evidence contracts/common.md#clear-and-simple-design One text field represents the selected file; request identity and transport status remain in their existing shapes.
|
|
141
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts Text comes from the snapshot instead of a separately read file that may have changed.
|
|
142
|
+
// @evidence contracts/common.md#meaningful-documentation The member comment names retained-program provenance under the documentation skill's context guidance.
|
|
143
|
+
// @evidenceExclude contracts/performance.md#bound-retention-and-release-resources GetSourceFileTextResult is a data type and acquires no handle, task or retained state.
|
|
144
|
+
// @evidenceExclude contracts/performance.md#efficient-algorithms GetSourceFileTextResult is a data type and chooses no algorithm or processing strategy.
|
|
145
|
+
// @evidenceExclude contracts/performance.md#reuse-equivalent-work GetSourceFileTextResult is a data type and coordinates no shared or repeated computation.
|
|
146
|
+
// @evidenceExclude contracts/portability.md#os-neutral-implementation GetSourceFileTextResult is a data type and performs no native filesystem, path or process operation.
|
|
96
147
|
type GetSourceFileTextResult struct {
|
|
148
|
+
// Text is the source currently held by the retained Program, including rewrites.
|
|
97
149
|
Text string `json:"text"`
|
|
98
150
|
}
|
|
99
151
|
|
|
100
152
|
// GetDiagnosticsResult is the response shape for `getDiagnostics()`.
|
|
153
|
+
//
|
|
154
|
+
// @evidence contracts/common.md#principled-implementation The shared CompileDiagnostic slice preserves the compiler's public diagnostic projection.
|
|
155
|
+
// @evidence contracts/common.md#clear-and-simple-design The selected messages reuse the compile diagnostic DTO rather than introducing a snapshot-specific message model.
|
|
156
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts Queries return compiler messages rather than source-pattern approximations of diagnostics.
|
|
157
|
+
// @evidence contracts/common.md#meaningful-documentation Native comments identify the payload and empty-array meaning under the documentation skill.
|
|
158
|
+
// @evidenceExclude contracts/performance.md#bound-retention-and-release-resources GetDiagnosticsResult is a data type and acquires no handle, task or retained state.
|
|
159
|
+
// @evidenceExclude contracts/performance.md#efficient-algorithms GetDiagnosticsResult is a data type and chooses no algorithm or processing strategy.
|
|
160
|
+
// @evidenceExclude contracts/performance.md#reuse-equivalent-work GetDiagnosticsResult is a data type and coordinates no shared or repeated computation.
|
|
161
|
+
// @evidenceExclude contracts/portability.md#os-neutral-implementation GetDiagnosticsResult is a data type and performs no native filesystem, path or process operation.
|
|
101
162
|
type GetDiagnosticsResult struct {
|
|
163
|
+
// Diagnostics is an initialized slice, so no selected messages encodes as [].
|
|
102
164
|
Diagnostics []CompileDiagnostic `json:"diagnostics"`
|
|
103
165
|
}
|
|
104
166
|
|
|
105
167
|
// NodeInfo is the serialized AST node returned by `getNodeAtPosition`.
|
|
168
|
+
//
|
|
169
|
+
// @evidence contracts/common.md#principled-implementation Kind metadata and native byte ranges project a token without exposing Go AST objects.
|
|
170
|
+
// @evidence contracts/common.md#clear-and-simple-design A flat kind/range/spelling value carries syntax information without mutable AST links or another token hierarchy.
|
|
171
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts Native ranges remain byte coordinates rather than guessed JavaScript character indices.
|
|
172
|
+
// @evidence contracts/common.md#meaningful-documentation Member comments explain native identity, units and optional text under the documentation skill.
|
|
173
|
+
// @evidenceExclude contracts/performance.md#bound-retention-and-release-resources NodeInfo is a data type and acquires no handle, task or retained state.
|
|
174
|
+
// @evidenceExclude contracts/performance.md#efficient-algorithms NodeInfo is a data type and chooses no algorithm or processing strategy.
|
|
175
|
+
// @evidenceExclude contracts/performance.md#reuse-equivalent-work NodeInfo is a data type and coordinates no shared or repeated computation.
|
|
176
|
+
// @evidenceExclude contracts/portability.md#os-neutral-implementation NodeInfo is a data type and performs no native filesystem, path or process operation.
|
|
106
177
|
type NodeInfo struct {
|
|
107
|
-
Kind
|
|
178
|
+
// Kind is the numeric TypeScript-Go AST kind.
|
|
179
|
+
Kind int `json:"kind"`
|
|
180
|
+
|
|
181
|
+
// KindName is its human-readable Stringer name.
|
|
108
182
|
KindName string `json:"kindName"`
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
183
|
+
|
|
184
|
+
// Pos is the inclusive UTF-8 byte offset of the token's first byte, after any
|
|
185
|
+
// leading whitespace and comments.
|
|
186
|
+
Pos int `json:"pos"`
|
|
187
|
+
|
|
188
|
+
// End is the exclusive UTF-8 byte offset.
|
|
189
|
+
End int `json:"end"`
|
|
190
|
+
|
|
191
|
+
// Text is omitted when the scanner has no nonempty source spelling.
|
|
192
|
+
Text string `json:"text,omitempty"`
|
|
112
193
|
}
|
|
113
194
|
|
|
114
195
|
// GetNodeAtPositionResult is the response shape for `getNodeAtPosition()`.
|
|
196
|
+
//
|
|
197
|
+
// @evidence contracts/common.md#principled-implementation A nullable pointer distinguishes successful absence from the query's error envelope.
|
|
198
|
+
// @evidence contracts/common.md#clear-and-simple-design One nullable token projection conveys lookup outcome without another status flag or duplicated source identity.
|
|
199
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts No fabricated node fills whitespace or an absent token.
|
|
200
|
+
// @evidence contracts/common.md#meaningful-documentation The member comment explains null token absence under the documentation skill.
|
|
201
|
+
// @evidenceExclude contracts/performance.md#bound-retention-and-release-resources GetNodeAtPositionResult is a data type and acquires no handle, task or retained state.
|
|
202
|
+
// @evidenceExclude contracts/performance.md#efficient-algorithms GetNodeAtPositionResult is a data type and chooses no algorithm or processing strategy.
|
|
203
|
+
// @evidenceExclude contracts/performance.md#reuse-equivalent-work GetNodeAtPositionResult is a data type and coordinates no shared or repeated computation.
|
|
204
|
+
// @evidenceExclude contracts/portability.md#os-neutral-implementation GetNodeAtPositionResult is a data type and performs no native filesystem, path or process operation.
|
|
115
205
|
type GetNodeAtPositionResult struct {
|
|
206
|
+
// Node encodes as null when no syntax token touches the queried position.
|
|
116
207
|
Node *NodeInfo `json:"node"`
|
|
117
208
|
}
|
|
118
209
|
|
|
119
210
|
// TypeInfo is the serialized type returned by `getTypeAtPosition`.
|
|
211
|
+
//
|
|
212
|
+
// @evidence contracts/common.md#principled-implementation Checker-printed text and native flags avoid a parallel incomplete public type model.
|
|
213
|
+
// @evidence contracts/common.md#clear-and-simple-design Presentation text and native classification bits are sufficient for this query; structural compiler types stay behind the checker boundary.
|
|
214
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts The checker supplies type presentation rather than inferring it from token spelling.
|
|
215
|
+
// @evidence contracts/common.md#meaningful-documentation Native comments identify printing authority and flag provenance under the documentation skill.
|
|
216
|
+
// @evidenceExclude contracts/performance.md#bound-retention-and-release-resources TypeInfo is a data type and acquires no handle, task or retained state.
|
|
217
|
+
// @evidenceExclude contracts/performance.md#efficient-algorithms TypeInfo is a data type and chooses no algorithm or processing strategy.
|
|
218
|
+
// @evidenceExclude contracts/performance.md#reuse-equivalent-work TypeInfo is a data type and coordinates no shared or repeated computation.
|
|
219
|
+
// @evidenceExclude contracts/portability.md#os-neutral-implementation TypeInfo is a data type and performs no native filesystem, path or process operation.
|
|
120
220
|
type TypeInfo struct {
|
|
121
|
-
Text
|
|
122
|
-
|
|
221
|
+
// Text is the checker's TypeToString presentation.
|
|
222
|
+
Text string `json:"text"`
|
|
223
|
+
|
|
224
|
+
// Flags is the numeric TypeScript-Go TypeFlags bitmask.
|
|
225
|
+
Flags int `json:"flags"`
|
|
123
226
|
}
|
|
124
227
|
|
|
125
228
|
// GetTypeAtPositionResult is the response shape for `getTypeAtPosition()`.
|
|
229
|
+
//
|
|
230
|
+
// @evidence contracts/common.md#principled-implementation Nullable semantic output mirrors the TypeScript request result without overloading an error type.
|
|
231
|
+
// @evidence contracts/common.md#clear-and-simple-design One nullable type field separates semantic absence from transport errors without duplicating the type metadata representation.
|
|
232
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts Positions without type semantics remain absent rather than receiving a fabricated any type.
|
|
233
|
+
// @evidence contracts/common.md#meaningful-documentation The member comment explains null meaning under the documentation skill's absence guidance.
|
|
234
|
+
// @evidenceExclude contracts/performance.md#bound-retention-and-release-resources GetTypeAtPositionResult is a data type and acquires no handle, task or retained state.
|
|
235
|
+
// @evidenceExclude contracts/performance.md#efficient-algorithms GetTypeAtPositionResult is a data type and chooses no algorithm or processing strategy.
|
|
236
|
+
// @evidenceExclude contracts/performance.md#reuse-equivalent-work GetTypeAtPositionResult is a data type and coordinates no shared or repeated computation.
|
|
237
|
+
// @evidenceExclude contracts/portability.md#os-neutral-implementation GetTypeAtPositionResult is a data type and performs no native filesystem, path or process operation.
|
|
126
238
|
type GetTypeAtPositionResult struct {
|
|
239
|
+
// Type encodes as null when the touching token has no semantic type result.
|
|
127
240
|
Type *TypeInfo `json:"type"`
|
|
128
241
|
}
|
|
129
242
|
|
|
130
243
|
// SymbolDeclaration is the serialized declaration site returned by
|
|
131
244
|
// `getSymbolAtPosition`.
|
|
245
|
+
//
|
|
246
|
+
// @evidence contracts/common.md#principled-implementation Nullable source identity and native ranges preserve declaration provenance through JSON.
|
|
247
|
+
// @evidence contracts/common.md#clear-and-simple-design A declaration site contains only file identity and its byte interval; source text and compiler node ownership remain elsewhere.
|
|
248
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts A source-less declaration keeps nil identity rather than a placeholder filename.
|
|
249
|
+
// @evidence contracts/common.md#meaningful-documentation Member comments explain path identity and byte interval units under the documentation skill.
|
|
250
|
+
// @evidenceExclude contracts/performance.md#bound-retention-and-release-resources SymbolDeclaration is a data type and acquires no handle, task or retained state.
|
|
251
|
+
// @evidenceExclude contracts/performance.md#efficient-algorithms SymbolDeclaration is a data type and chooses no algorithm or processing strategy.
|
|
252
|
+
// @evidenceExclude contracts/performance.md#reuse-equivalent-work SymbolDeclaration is a data type and coordinates no shared or repeated computation.
|
|
253
|
+
// @evidenceExclude contracts/portability.md#os-neutral-implementation SymbolDeclaration is a data type and performs no native filesystem, path or process operation.
|
|
132
254
|
type SymbolDeclaration struct {
|
|
255
|
+
// File is a project-relative or outside absolute path, nil for source-less nodes.
|
|
133
256
|
File *string `json:"file"`
|
|
134
|
-
|
|
135
|
-
|
|
257
|
+
|
|
258
|
+
// Pos is the inclusive UTF-8 byte offset of the declaration's first token,
|
|
259
|
+
// after any leading whitespace, comments and JSDoc.
|
|
260
|
+
Pos int `json:"pos"`
|
|
261
|
+
|
|
262
|
+
// End is the declaration's exclusive UTF-8 byte offset.
|
|
263
|
+
End int `json:"end"`
|
|
136
264
|
}
|
|
137
265
|
|
|
138
266
|
// SymbolInfo is the serialized symbol returned by `getSymbolAtPosition`.
|
|
267
|
+
//
|
|
268
|
+
// @evidence contracts/common.md#principled-implementation Raw and printed names, flags and declaration projections preserve the native checker result.
|
|
269
|
+
// @evidence contracts/common.md#clear-and-simple-design Identity and display text are distinct, and one capped site list plus its original total explains truncation without separate declaration handles.
|
|
270
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts The response cap preserves the original total rather than presenting a shortened declaration list as complete.
|
|
271
|
+
// @evidence contracts/common.md#meaningful-documentation Native comments distinguish internal names, display text and capped metadata under the documentation skill.
|
|
272
|
+
// @evidenceExclude contracts/performance.md#bound-retention-and-release-resources SymbolInfo is a data type and acquires no handle, task or retained state.
|
|
273
|
+
// @evidenceExclude contracts/performance.md#efficient-algorithms SymbolInfo is a data type and chooses no algorithm or processing strategy.
|
|
274
|
+
// @evidenceExclude contracts/performance.md#reuse-equivalent-work SymbolInfo is a data type and coordinates no shared or repeated computation.
|
|
275
|
+
// @evidenceExclude contracts/portability.md#os-neutral-implementation SymbolInfo is a data type and performs no native filesystem, path or process operation.
|
|
139
276
|
type SymbolInfo struct {
|
|
140
|
-
Name
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
277
|
+
// Name is the raw name, including TypeScript internal prefix markers.
|
|
278
|
+
Name string `json:"name"`
|
|
279
|
+
|
|
280
|
+
// Text is the optional checker-printed symbol representation.
|
|
281
|
+
Text string `json:"text,omitempty"`
|
|
282
|
+
|
|
283
|
+
// Flags is the numeric TypeScript-Go SymbolFlags bitmask.
|
|
284
|
+
Flags int `json:"flags"`
|
|
285
|
+
|
|
286
|
+
// Declarations contains at most 16 sites and is omitted when empty.
|
|
287
|
+
Declarations []SymbolDeclaration `json:"declarations,omitempty"`
|
|
288
|
+
|
|
289
|
+
// DeclarationCount retains the original total and is omitted when zero.
|
|
290
|
+
DeclarationCount int `json:"declarationCount,omitempty"`
|
|
145
291
|
}
|
|
146
292
|
|
|
147
293
|
// GetSymbolAtPositionResult is the response shape for `getSymbolAtPosition()`.
|
|
294
|
+
//
|
|
295
|
+
// @evidence contracts/common.md#principled-implementation A nullable symbol pointer distinguishes absent semantics from a failed request.
|
|
296
|
+
// @evidence contracts/common.md#clear-and-simple-design One nullable symbol field expresses the binding outcome while symbol metadata and request status remain separate.
|
|
297
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts Missing binding does not produce a symbol guessed from the token's name.
|
|
298
|
+
// @evidence contracts/common.md#meaningful-documentation The member comment explains null result meaning under the documentation skill.
|
|
299
|
+
// @evidenceExclude contracts/performance.md#bound-retention-and-release-resources GetSymbolAtPositionResult is a data type and acquires no handle, task or retained state.
|
|
300
|
+
// @evidenceExclude contracts/performance.md#efficient-algorithms GetSymbolAtPositionResult is a data type and chooses no algorithm or processing strategy.
|
|
301
|
+
// @evidenceExclude contracts/performance.md#reuse-equivalent-work GetSymbolAtPositionResult is a data type and coordinates no shared or repeated computation.
|
|
302
|
+
// @evidenceExclude contracts/portability.md#os-neutral-implementation GetSymbolAtPositionResult is a data type and performs no native filesystem, path or process operation.
|
|
148
303
|
type GetSymbolAtPositionResult struct {
|
|
304
|
+
// Symbol encodes as null when the touching token has no associated symbol.
|
|
149
305
|
Symbol *SymbolInfo `json:"symbol"`
|
|
150
306
|
}
|
|
151
307
|
|
|
@@ -298,7 +454,7 @@ func jsGetDiagnostics(this js.Value, args []js.Value) any {
|
|
|
298
454
|
func jsGetNodeAtPosition(this js.Value, args []js.Value) any {
|
|
299
455
|
return withSnapshotPosition(args, func(_ *snapshotEntry, file *ast.SourceFile, pos int) any {
|
|
300
456
|
node := tokenAtPosition(file, pos)
|
|
301
|
-
return fountainOK(GetNodeAtPositionResult{Node: nodeInfoOf(node)})
|
|
457
|
+
return fountainOK(GetNodeAtPositionResult{Node: nodeInfoOf(file, node)})
|
|
302
458
|
})
|
|
303
459
|
}
|
|
304
460
|
|
|
@@ -391,17 +547,18 @@ func withSnapshotPosition(args []js.Value, fn func(*snapshotEntry, *ast.SourceFi
|
|
|
391
547
|
if posVal.Type() != js.TypeNumber {
|
|
392
548
|
return errorResponse(2, "host: \"position\" must be a number (byte offset)")
|
|
393
549
|
}
|
|
394
|
-
|
|
395
|
-
if
|
|
396
|
-
return errorResponse(2, "host: \"position\" must be non-negative")
|
|
550
|
+
offset := posVal.Float()
|
|
551
|
+
if math.IsNaN(offset) || math.IsInf(offset, 0) || math.Trunc(offset) != offset || offset < 0 {
|
|
552
|
+
return errorResponse(2, "host: \"position\" must be a finite non-negative integer byte offset")
|
|
397
553
|
}
|
|
398
554
|
file := resolveSnapshotFile(entry, path)
|
|
399
555
|
if file == nil {
|
|
400
556
|
return errorResponse(2, fmt.Sprintf("host: file %q not found in snapshot", path))
|
|
401
557
|
}
|
|
402
|
-
if
|
|
403
|
-
return errorResponse(2, fmt.Sprintf("host: \"position\" %
|
|
558
|
+
if offset >= float64(len(file.Text())) {
|
|
559
|
+
return errorResponse(2, fmt.Sprintf("host: \"position\" %v is outside file length %d", offset, len(file.Text())))
|
|
404
560
|
}
|
|
561
|
+
pos := int(offset)
|
|
405
562
|
return fn(entry, file, pos)
|
|
406
563
|
})
|
|
407
564
|
}
|
|
@@ -446,7 +603,7 @@ func resolveSnapshotFile(entry *snapshotEntry, path string) *ast.SourceFile {
|
|
|
446
603
|
return nil
|
|
447
604
|
}
|
|
448
605
|
|
|
449
|
-
// snapshotFileKey
|
|
606
|
+
// snapshotFileKey delegates to apiOutputKey for use by all
|
|
450
607
|
// fountain endpoints that return file paths.
|
|
451
608
|
func snapshotFileKey(cwd, fileName string) string {
|
|
452
609
|
return apiOutputKey(cwd, fileName)
|
|
@@ -469,14 +626,18 @@ func fountainOK(payload any) any {
|
|
|
469
626
|
}
|
|
470
627
|
|
|
471
628
|
// nodeInfoOf converts a *ast.Node into the JSON-serializable NodeInfo.
|
|
472
|
-
|
|
629
|
+
//
|
|
630
|
+
// Pos is the token's first byte, after leading whitespace and comments.
|
|
631
|
+
// TypeScript-Go's Node.Pos is the full start, which includes that trivia, so
|
|
632
|
+
// reporting it would give an interval wider than the Text it describes.
|
|
633
|
+
func nodeInfoOf(file *ast.SourceFile, node *ast.Node) *NodeInfo {
|
|
473
634
|
if node == nil {
|
|
474
635
|
return nil
|
|
475
636
|
}
|
|
476
637
|
info := &NodeInfo{
|
|
477
638
|
Kind: int(node.Kind),
|
|
478
639
|
KindName: astKindName(node.Kind),
|
|
479
|
-
Pos: node
|
|
640
|
+
Pos: tokenStart(file, node),
|
|
480
641
|
End: node.End(),
|
|
481
642
|
}
|
|
482
643
|
if text := shimscanner.GetTextOfNode(node); text != "" {
|
|
@@ -516,6 +677,7 @@ func symbolInfoOf(entry *snapshotEntry, sym *ast.Symbol) *SymbolInfo {
|
|
|
516
677
|
}
|
|
517
678
|
item := SymbolDeclaration{Pos: d.Pos(), End: d.End()}
|
|
518
679
|
if file := ast.GetSourceFileOfNode(d); file != nil {
|
|
680
|
+
item.Pos = tokenStart(file, d)
|
|
519
681
|
key := snapshotFileKey(entry.cwd, file.FileName())
|
|
520
682
|
item.File = &key
|
|
521
683
|
}
|
|
@@ -527,6 +689,14 @@ func symbolInfoOf(entry *snapshotEntry, sym *ast.Symbol) *SymbolInfo {
|
|
|
527
689
|
return info
|
|
528
690
|
}
|
|
529
691
|
|
|
692
|
+
// tokenStart returns the byte offset of node's first token. It skips the leading
|
|
693
|
+
// whitespace and comments that TypeScript-Go's Node.Pos includes; JSDoc attached
|
|
694
|
+
// to a declaration is such a comment, so a declaration starts at its own first
|
|
695
|
+
// token rather than at its documentation.
|
|
696
|
+
func tokenStart(file *ast.SourceFile, node *ast.Node) int {
|
|
697
|
+
return shimscanner.GetTokenPosOfNode(node, file, false)
|
|
698
|
+
}
|
|
699
|
+
|
|
530
700
|
// astKindName renders an ast.Kind to its string representation. ast.Kind has
|
|
531
701
|
// a Stringer impl in tsgo (`%v` produces "FunctionDeclaration" etc.).
|
|
532
702
|
func astKindName(k ast.Kind) string {
|
package/host/host.go
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
// JS-side bindings for the host package.
|
|
4
4
|
//
|
|
5
5
|
// `Expose` installs `globalThis[apiName]` with the base ttsc endpoints
|
|
6
|
-
// (version, build, check, transform)
|
|
7
|
-
//
|
|
6
|
+
// (version, build, check, transform), the retained-program verbs of
|
|
7
|
+
// fountain.go, and `plugin({ name, command, ...opts })`, routing into the
|
|
8
|
+
// consumer's registered plugins. Every async endpoint returns
|
|
8
9
|
// the JS result envelope so callers can build a single boot helper that works
|
|
9
10
|
// against any host-built binary.
|
|
10
11
|
package host
|
|
@@ -14,6 +15,7 @@ import (
|
|
|
14
15
|
"fmt"
|
|
15
16
|
"os"
|
|
16
17
|
"runtime"
|
|
18
|
+
"strconv"
|
|
17
19
|
"sync/atomic"
|
|
18
20
|
"syscall/js"
|
|
19
21
|
"time"
|
|
@@ -27,31 +29,12 @@ var (
|
|
|
27
29
|
date = "unknown"
|
|
28
30
|
)
|
|
29
31
|
|
|
30
|
-
// exposed gates Expose so a duplicate call
|
|
32
|
+
// exposed gates Expose so a duplicate call reports failure instead of leaking the
|
|
31
33
|
// previous batch of js.Funcs + spawning a second keepalive goroutine.
|
|
32
34
|
var exposed atomic.Bool
|
|
33
35
|
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
//
|
|
37
|
-
// Expose installs `globalThis[apiName]` with the base API endpoints and the
|
|
38
|
-
// plugin dispatcher, then keeps the Go runtime alive forever.
|
|
39
|
-
//
|
|
40
|
-
// The contract:
|
|
41
|
-
//
|
|
42
|
-
// - globalThis[apiName].version() → version banner
|
|
43
|
-
// - globalThis[apiName].build({ cwd, tsconfig }) → Promise<ITtscResult>
|
|
44
|
-
// - globalThis[apiName].check({ cwd, tsconfig }) → Promise<ITtscResult>
|
|
45
|
-
// - globalThis[apiName].transform({ cwd, tsconfig }) → Promise<ITtscResult>
|
|
46
|
-
// - globalThis[apiName].plugin({ name, command, ...opts}) → Promise<ITtscResult>
|
|
47
|
-
// - globalThis[apiName].plugins() → string[] of registered names
|
|
48
|
-
//
|
|
49
|
-
// build/check/transform encode their structured payloads as JSON in
|
|
50
|
-
// ITtscResult.result. Plugin stdout/stderr are captured in the envelope streams.
|
|
51
|
-
//
|
|
52
|
-
// A matching readiness resolver is invoked: `globalThis[`${apiName}Ready`]`.
|
|
53
|
-
// JS callers register this BEFORE go.run begins so they can await wasm boot.
|
|
54
|
-
func Expose(apiName string, cfg Config) {
|
|
36
|
+
// expose is the js/wasm implementation behind Expose.
|
|
37
|
+
func expose(apiName string, cfg Config) {
|
|
55
38
|
// Refuse double-Expose: the second call would leak every js.FuncOf from
|
|
56
39
|
// the first batch (Go pins js.Funcs and they're not GC'd), spin a second
|
|
57
40
|
// keepalive goroutine forever, and overwrite the ready resolver so JS
|
|
@@ -258,7 +241,9 @@ func buildPluginArgv(opts js.Value) []string {
|
|
|
258
241
|
out = append(out, "--"+key)
|
|
259
242
|
}
|
|
260
243
|
case js.TypeNumber:
|
|
261
|
-
|
|
244
|
+
// 'f' with the shortest precision that round-trips keeps an integer such
|
|
245
|
+
// as 1234567 as "1234567"; `%v` would spell it "1.234567e+06".
|
|
246
|
+
out = append(out, "--"+key+"="+strconv.FormatFloat(value.Float(), 'f', -1, 64))
|
|
262
247
|
}
|
|
263
248
|
}
|
|
264
249
|
return out
|
package/host/host_native.go
CHANGED
|
@@ -5,11 +5,9 @@
|
|
|
5
5
|
// without GOOS=js, which native CI jobs need.
|
|
6
6
|
package host
|
|
7
7
|
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
// non-wasm sanity-test entrypoint.
|
|
12
|
-
func Expose(apiName string, cfg Config) {
|
|
8
|
+
// expose is the native alternative behind Expose: it installs no JavaScript API
|
|
9
|
+
// and returns immediately.
|
|
10
|
+
func expose(apiName string, cfg Config) {
|
|
13
11
|
_ = apiName
|
|
14
12
|
_ = cfg
|
|
15
13
|
}
|