@ttsc/wasm 0.11.0-dev.20260517
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/LICENSE +21 -0
- package/README.md +125 -0
- package/build/build-wasm.cjs +240 -0
- package/build/pack-prepare.cjs +68 -0
- package/cmd/ttsc-wasm/main.go +130 -0
- package/cmd/ttsc-wasm/main_wasm.go +17 -0
- package/dist/go.mod +54 -0
- package/dist/ttsc.wasm +0 -0
- package/dist/wasm_exec.js +575 -0
- package/go.mod +54 -0
- package/go.sum +26 -0
- package/host/api.go +205 -0
- package/host/doc.go +31 -0
- package/host/host.go +317 -0
- package/host/host_native.go +12 -0
- package/host/plugin.go +59 -0
- package/lib/src/MemFS.d.ts +68 -0
- package/lib/src/MemFS.js +384 -0
- package/lib/src/MemFS.js.map +1 -0
- package/lib/src/api.d.ts +87 -0
- package/lib/src/api.js +20 -0
- package/lib/src/api.js.map +1 -0
- package/lib/src/index.d.ts +6 -0
- package/lib/src/index.js +10 -0
- package/lib/src/index.js.map +1 -0
- package/lib/src/instantiate.d.ts +27 -0
- package/lib/src/instantiate.js +71 -0
- package/lib/src/instantiate.js.map +1 -0
- package/package.json +49 -0
- package/src/MemFS.ts +566 -0
- package/src/api.ts +112 -0
- package/src/index.ts +28 -0
- package/src/instantiate.ts +114 -0
- package/vendor/shim/ast/extra-shim.json +4 -0
- package/vendor/shim/ast/go.mod +5 -0
- package/vendor/shim/ast/lint.go +328 -0
- package/vendor/shim/ast/shim.go +220 -0
- package/vendor/shim/ast/surface.go +685 -0
- package/vendor/shim/bundled/extra-shim.json +1 -0
- package/vendor/shim/bundled/go.mod +5 -0
- package/vendor/shim/bundled/shim.go +23 -0
- package/vendor/shim/checker/extra-shim.json +31 -0
- package/vendor/shim/checker/go.mod +5 -0
- package/vendor/shim/checker/shim.go +174 -0
- package/vendor/shim/compiler/extra-shim.json +4 -0
- package/vendor/shim/compiler/go.mod +5 -0
- package/vendor/shim/compiler/shim.go +65 -0
- package/vendor/shim/core/extra-shim.json +4 -0
- package/vendor/shim/core/go.mod +5 -0
- package/vendor/shim/core/shim.go +29 -0
- package/vendor/shim/diagnosticwriter/go.mod +5 -0
- package/vendor/shim/diagnosticwriter/lint.go +145 -0
- package/vendor/shim/diagnosticwriter/shim.go +29 -0
- package/vendor/shim/lsp/extra-shim.json +4 -0
- package/vendor/shim/lsp/go.mod +16 -0
- package/vendor/shim/lsp/go.sum +26 -0
- package/vendor/shim/lsp/shim.go +42 -0
- package/vendor/shim/parser/extra-shim.json +4 -0
- package/vendor/shim/parser/go.mod +5 -0
- package/vendor/shim/parser/shim.go +61 -0
- package/vendor/shim/printer/go.mod +5 -0
- package/vendor/shim/printer/shim.go +23 -0
- package/vendor/shim/scanner/extra-shim.json +4 -0
- package/vendor/shim/scanner/go.mod +5 -0
- package/vendor/shim/scanner/shim.go +134 -0
- package/vendor/shim/tsoptions/extra-shim.json +4 -0
- package/vendor/shim/tsoptions/go.mod +5 -0
- package/vendor/shim/tsoptions/shim.go +173 -0
- package/vendor/shim/tspath/extra-shim.json +4 -0
- package/vendor/shim/tspath/go.mod +5 -0
- package/vendor/shim/tspath/shim.go +236 -0
- package/vendor/shim/vfs/cachedvfs/extra-shim.json +4 -0
- package/vendor/shim/vfs/cachedvfs/go.mod +5 -0
- package/vendor/shim/vfs/cachedvfs/shim.go +12 -0
- package/vendor/shim/vfs/extra-shim.json +4 -0
- package/vendor/shim/vfs/go.mod +5 -0
- package/vendor/shim/vfs/osvfs/extra-shim.json +4 -0
- package/vendor/shim/vfs/osvfs/go.mod +5 -0
- package/vendor/shim/vfs/osvfs/shim.go +13 -0
- package/vendor/shim/vfs/shim.go +22 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jeongho Nam
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# @ttsc/wasm
|
|
2
|
+
|
|
3
|
+
> **API stability: experimental until v1.0.** Public signatures (`Plugin.Run`, the `host.Expose` argv shape, the JS `ITtscApi` surface, the linker-symbol contract below) may change between minor releases. Pin exact versions in production playgrounds.
|
|
4
|
+
|
|
5
|
+
In-browser ttsc playground scaffolding. Compose ttsc + typescript-go with your own plugins by writing a single Go entry that calls `host.Expose(...)`, then boot it from JS with `bootTtsc(...)`.
|
|
6
|
+
|
|
7
|
+
## What you get
|
|
8
|
+
|
|
9
|
+
- A base `ttsc.wasm` (under `dist/`) that exposes vanilla `build` / `check` / `transform` — no plugins linked. Useful as a sanity test or a no-plugin baseline.
|
|
10
|
+
- A Go helper package (`host/`) plugin authors import from their own `main_wasm.go` to bind a wasm to `globalThis[yourApiName]`.
|
|
11
|
+
- A JS runtime (`bootTtsc`, `createMemFS`, typed `ITtscApi` surface) that loads any host-built wasm into a Web Worker.
|
|
12
|
+
|
|
13
|
+
The package is plugin-agnostic. Downstream playgrounds (the ttsc.dev website, typia, anything else) build their own wasm against the same `host/` package.
|
|
14
|
+
|
|
15
|
+
## Build your own playground in 30 lines
|
|
16
|
+
|
|
17
|
+
1. Add the dependency:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -D @ttsc/wasm
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
2. Create `your-pkg/cmd/your-wasm/main_wasm.go`:
|
|
24
|
+
|
|
25
|
+
```go
|
|
26
|
+
//go:build js && wasm
|
|
27
|
+
|
|
28
|
+
package main
|
|
29
|
+
|
|
30
|
+
import (
|
|
31
|
+
"github.com/samchon/ttsc/packages/wasm/host"
|
|
32
|
+
yourplugin "example.com/your/plugin"
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
func main() {
|
|
36
|
+
host.Expose("yourApi", host.Config{
|
|
37
|
+
Plugins: []host.Plugin{yourplugin.New()},
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The native sibling `main.go` is recommended so `go run ./cmd/your-wasm` exercises the same host helpers without the browser MemFS bridge — see `packages/wasm/cmd/ttsc-wasm/main.go` in the repo for a reference layout:
|
|
43
|
+
|
|
44
|
+
```go
|
|
45
|
+
//go:build !js
|
|
46
|
+
|
|
47
|
+
package main
|
|
48
|
+
|
|
49
|
+
import (
|
|
50
|
+
"os"
|
|
51
|
+
|
|
52
|
+
"github.com/samchon/ttsc/packages/wasm/host"
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
func main() {
|
|
56
|
+
os.Exit(host.Run(os.Args[1:]))
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
3. Build the wasm:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
GOOS=js GOARCH=wasm go build -trimpath -ldflags "-s -w" \
|
|
64
|
+
-o public/your.wasm ./cmd/your-wasm
|
|
65
|
+
cp node_modules/@ttsc/wasm/dist/wasm_exec.js public/wasm_exec.js
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Stamping version metadata at link time
|
|
69
|
+
|
|
70
|
+
The `host` package exposes a build-time variable contract you can override via `-ldflags "-X ..."`:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
GOOS=js GOARCH=wasm go build -trimpath \
|
|
74
|
+
-ldflags "-s -w -X github.com/samchon/ttsc/packages/wasm/host.version=$(cat package.json | jq -r .version)" \
|
|
75
|
+
-o public/your.wasm ./cmd/your-wasm
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The `version`, `commit`, and `date` variables in `host/host.go` are all overridable. `globalThis[apiName].version()` reads from them.
|
|
79
|
+
|
|
80
|
+
4. Boot it from JS (a Web Worker is **required** — Go's `syscall/js` blocks the runtime while the wasm is alive; running on the main thread freezes the page):
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { bootTtsc } from "@ttsc/wasm";
|
|
84
|
+
|
|
85
|
+
const { api, host } = await bootTtsc({
|
|
86
|
+
wasmUrl: "/your.wasm",
|
|
87
|
+
apiName: "yourApi",
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
host.writeFile("/work/tsconfig.json", '{"compilerOptions":{"strict":true}}');
|
|
91
|
+
host.writeFile("/work/src/index.ts", "export const x: number = 1;");
|
|
92
|
+
|
|
93
|
+
const result = await api.build({ cwd: "/work" });
|
|
94
|
+
console.log(result.result); // JSON: { diagnostics, output }
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Booting two wasms with the same `apiName` panics; pick a unique `apiName` per binary.
|
|
98
|
+
|
|
99
|
+
## Plugin contract
|
|
100
|
+
|
|
101
|
+
`host.Plugin` matches ttsc's existing CLI sidecar dispatch:
|
|
102
|
+
|
|
103
|
+
```go
|
|
104
|
+
type Plugin interface {
|
|
105
|
+
Name() string // e.g. "@ttsc/banner"
|
|
106
|
+
Run(command string, args []string) int // returns CLI exit code
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The host installs `globalThis[apiName].plugin({ name, command, ...opts })` that translates the JS options object into a CLI-shaped argv and calls your plugin's `Run`. Your `Run` body can forward to the same function the native sidecar's `main.go` calls — for example `utility.RunBuild(args)` for plugins backed by `packages/ttsc/utility`.
|
|
111
|
+
|
|
112
|
+
## Published-tarball Go module layout
|
|
113
|
+
|
|
114
|
+
The published `@ttsc/wasm` tarball ships:
|
|
115
|
+
|
|
116
|
+
- A rewritten root `go.mod` whose `replace` directives point at `./vendor/shim/*` (vendored at pack time from `packages/ttsc/shim/`).
|
|
117
|
+
- The full `host/`, `cmd/`, `build/` Go source so consumers can `go build -tags '...'` their own wasm against your host helper.
|
|
118
|
+
- `dist/ttsc.wasm` + `dist/wasm_exec.js` — the no-plugin sanity binary and the Go runtime loader.
|
|
119
|
+
|
|
120
|
+
The tarball intentionally drops the `replace github.com/samchon/ttsc/packages/ttsc => ../ttsc` directive that the in-repo `go.mod` carries: consumers of the published module who want to rebuild the wasm must supply their own `replace` (or vendor `packages/ttsc` themselves). The published `dist/ttsc.wasm` is plug-and-play for runtime use; the Go module is for **plugin authors extending the host**, not for vanilla consumers.
|
|
121
|
+
|
|
122
|
+
## Documents
|
|
123
|
+
|
|
124
|
+
- The base wasm (`dist/ttsc.wasm`) is the binary `cmd/ttsc-wasm/main_wasm.go` produces. Look there for a minimal example.
|
|
125
|
+
- Plugin authors should also read `docs/wasm-plugin.md` (TBD) for the Go host helper deep-dive.
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
// Build the base `ttsc.wasm` and stage the matching `wasm_exec.js`.
|
|
2
|
+
//
|
|
3
|
+
// Usage: node build/build-wasm.cjs [--force]
|
|
4
|
+
//
|
|
5
|
+
// Behavior:
|
|
6
|
+
// * Skips the Go build when `dist/ttsc.wasm` is newer than every .go file
|
|
7
|
+
// under `packages/{ttsc,wasm}/`. Pass `--force` or set
|
|
8
|
+
// `TTSC_WASM_FORCE=1` to rebuild unconditionally.
|
|
9
|
+
// * Hard failure if the Go toolchain is missing.
|
|
10
|
+
//
|
|
11
|
+
// Outputs:
|
|
12
|
+
// * packages/wasm/dist/ttsc.wasm
|
|
13
|
+
// * packages/wasm/dist/wasm_exec.js
|
|
14
|
+
//
|
|
15
|
+
// Downstream consumers (the website, plugin-author playgrounds) point their
|
|
16
|
+
// own bundle pipelines at `node_modules/@ttsc/wasm/dist/wasm_exec.js` and
|
|
17
|
+
// build their own .wasm against the same Go module.
|
|
18
|
+
|
|
19
|
+
const cp = require("child_process");
|
|
20
|
+
const fs = require("fs");
|
|
21
|
+
const path = require("path");
|
|
22
|
+
|
|
23
|
+
const packageRoot = path.resolve(__dirname, "..");
|
|
24
|
+
const repoRoot = path.resolve(packageRoot, "..", "..");
|
|
25
|
+
const ttscDir = path.join(repoRoot, "packages", "ttsc");
|
|
26
|
+
const shimSrc = path.join(ttscDir, "shim");
|
|
27
|
+
const vendorDir = path.join(packageRoot, "vendor");
|
|
28
|
+
const vendorShimDir = path.join(vendorDir, "shim");
|
|
29
|
+
const outDir = path.join(packageRoot, "dist");
|
|
30
|
+
const wasmOut = path.join(outDir, "ttsc.wasm");
|
|
31
|
+
const wasmExecOut = path.join(outDir, "wasm_exec.js");
|
|
32
|
+
const goModPath = path.join(packageRoot, "go.mod");
|
|
33
|
+
const publishedGoModOut = path.join(outDir, "go.mod");
|
|
34
|
+
const forceRebuild =
|
|
35
|
+
process.argv.includes("--force") || !!process.env.TTSC_WASM_FORCE;
|
|
36
|
+
|
|
37
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
38
|
+
|
|
39
|
+
function hasGoToolchain() {
|
|
40
|
+
try {
|
|
41
|
+
cp.execSync("go env GOROOT", { stdio: "ignore" });
|
|
42
|
+
return true;
|
|
43
|
+
} catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function locateWasmExec() {
|
|
49
|
+
if (!hasGoToolchain()) return null;
|
|
50
|
+
const goroot =
|
|
51
|
+
process.env.GOROOT ??
|
|
52
|
+
cp.execSync("go env GOROOT", { encoding: "utf8" }).trim();
|
|
53
|
+
// Go 1.24+ ships wasm_exec.js under lib/wasm/. Older releases kept it
|
|
54
|
+
// under misc/wasm/. Try both so the build works across Go installs.
|
|
55
|
+
const candidates = [
|
|
56
|
+
path.join(goroot, "lib", "wasm", "wasm_exec.js"),
|
|
57
|
+
path.join(goroot, "misc", "wasm", "wasm_exec.js"),
|
|
58
|
+
];
|
|
59
|
+
for (const candidate of candidates) {
|
|
60
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function newestMtime(...roots) {
|
|
66
|
+
let max = 0;
|
|
67
|
+
for (const root of roots) {
|
|
68
|
+
if (!root || !fs.existsSync(root)) continue;
|
|
69
|
+
walk(root, (_file, stat) => {
|
|
70
|
+
if (stat.mtimeMs > max) max = stat.mtimeMs;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return max;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function walk(root, visit) {
|
|
77
|
+
const stack = [root];
|
|
78
|
+
while (stack.length) {
|
|
79
|
+
const cur = stack.pop();
|
|
80
|
+
let stat;
|
|
81
|
+
try {
|
|
82
|
+
stat = fs.statSync(cur);
|
|
83
|
+
} catch {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (stat.isDirectory()) {
|
|
87
|
+
const base = path.basename(cur);
|
|
88
|
+
if (
|
|
89
|
+
base === "node_modules" ||
|
|
90
|
+
base === ".ttsc" ||
|
|
91
|
+
base === ".git" ||
|
|
92
|
+
base === "lib" ||
|
|
93
|
+
base === "dist"
|
|
94
|
+
)
|
|
95
|
+
continue;
|
|
96
|
+
for (const entry of fs.readdirSync(cur)) {
|
|
97
|
+
stack.push(path.join(cur, entry));
|
|
98
|
+
}
|
|
99
|
+
} else if (stat.isFile() && cur.endsWith(".go")) {
|
|
100
|
+
visit(cur, stat);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function buildWasm() {
|
|
106
|
+
console.log(`build/build-wasm.cjs: building ${wasmOut}`);
|
|
107
|
+
cp.execFileSync(
|
|
108
|
+
"go",
|
|
109
|
+
[
|
|
110
|
+
"build",
|
|
111
|
+
"-trimpath",
|
|
112
|
+
"-ldflags",
|
|
113
|
+
"-s -w",
|
|
114
|
+
"-o",
|
|
115
|
+
wasmOut,
|
|
116
|
+
"./cmd/ttsc-wasm",
|
|
117
|
+
],
|
|
118
|
+
{
|
|
119
|
+
cwd: packageRoot,
|
|
120
|
+
env: { ...process.env, GOOS: "js", GOARCH: "wasm" },
|
|
121
|
+
stdio: "inherit",
|
|
122
|
+
},
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Mirror packages/ttsc/shim/* into packages/wasm/vendor/shim/* so the
|
|
127
|
+
// published @ttsc/wasm tarball is self-contained: consumers extending the
|
|
128
|
+
// wasm binary against the @ttsc/wasm Go module no longer need a sibling
|
|
129
|
+
// `packages/ttsc/shim/` working tree. The vendored copy is checked in so
|
|
130
|
+
// `pnpm pack --dry-run` agrees with what `go build` would see at install
|
|
131
|
+
// time. The working-tree `go.mod` still points at `../ttsc/shim/*` for
|
|
132
|
+
// local dev; the published `go.mod` is rewritten into `dist/go.mod` and
|
|
133
|
+
// swapped in via prepack/postpack.
|
|
134
|
+
function vendorShim() {
|
|
135
|
+
if (!fs.existsSync(shimSrc)) {
|
|
136
|
+
throw new Error(
|
|
137
|
+
`build/build-wasm.cjs: shim source missing at ${shimSrc}; run from a full repo checkout`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
fs.rmSync(vendorShimDir, { recursive: true, force: true });
|
|
141
|
+
fs.mkdirSync(vendorShimDir, { recursive: true });
|
|
142
|
+
copyTree(shimSrc, vendorShimDir);
|
|
143
|
+
console.log(
|
|
144
|
+
`build/build-wasm.cjs: vendored shim/* → ${path.relative(packageRoot, vendorShimDir)}`,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function copyTree(src, dst) {
|
|
149
|
+
const stat = fs.statSync(src);
|
|
150
|
+
if (stat.isDirectory()) {
|
|
151
|
+
const base = path.basename(src);
|
|
152
|
+
if (base === "node_modules" || base === ".git") return;
|
|
153
|
+
fs.mkdirSync(dst, { recursive: true });
|
|
154
|
+
for (const entry of fs.readdirSync(src)) {
|
|
155
|
+
copyTree(path.join(src, entry), path.join(dst, entry));
|
|
156
|
+
}
|
|
157
|
+
} else if (stat.isFile()) {
|
|
158
|
+
fs.copyFileSync(src, dst);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Rewrite go.mod so the published copy points at ./vendor/shim/* instead of
|
|
163
|
+
// ../ttsc/shim/*. The `replace github.com/samchon/ttsc/packages/ttsc => ...`
|
|
164
|
+
// line is dropped: consumers of the published tarball who want to compile
|
|
165
|
+
// their own wasm binary must supply that module themselves (documented in
|
|
166
|
+
// README.md). The working-tree go.mod is untouched.
|
|
167
|
+
function rewritePublishedGoMod() {
|
|
168
|
+
const src = fs.readFileSync(goModPath, "utf8");
|
|
169
|
+
const lines = src.split(/\r?\n/);
|
|
170
|
+
const out = [];
|
|
171
|
+
for (const line of lines) {
|
|
172
|
+
const trimmed = line.trim();
|
|
173
|
+
// Drop the ../ttsc consumer-module replace (handled at consumer side).
|
|
174
|
+
if (
|
|
175
|
+
/^github\.com\/samchon\/ttsc\/packages\/ttsc\s+=>\s+\.\.\/ttsc\b/.test(
|
|
176
|
+
trimmed,
|
|
177
|
+
)
|
|
178
|
+
) {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
// Rewrite each shim replace from ../ttsc/shim/X to ./vendor/shim/X.
|
|
182
|
+
const shimMatch = trimmed.match(
|
|
183
|
+
/^(github\.com\/microsoft\/typescript-go\/shim\/[A-Za-z0-9_/]+)\s+=>\s+\.\.\/ttsc\/shim\/([A-Za-z0-9_/]+)$/,
|
|
184
|
+
);
|
|
185
|
+
if (shimMatch) {
|
|
186
|
+
const indent = line.match(/^\s*/)[0];
|
|
187
|
+
out.push(`${indent}${shimMatch[1]} => ./vendor/shim/${shimMatch[2]}`);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
out.push(line);
|
|
191
|
+
}
|
|
192
|
+
fs.writeFileSync(publishedGoModOut, out.join("\n"));
|
|
193
|
+
console.log(
|
|
194
|
+
`build/build-wasm.cjs: emitted published go.mod → ${path.relative(packageRoot, publishedGoModOut)}`,
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const wasmExecSrc = locateWasmExec();
|
|
199
|
+
|
|
200
|
+
if (!forceRebuild && fs.existsSync(wasmOut)) {
|
|
201
|
+
const wasmMtime = fs.statSync(wasmOut).mtimeMs;
|
|
202
|
+
const sourceMtime = newestMtime(packageRoot, ttscDir);
|
|
203
|
+
if (sourceMtime > 0 && wasmMtime >= sourceMtime) {
|
|
204
|
+
console.log(
|
|
205
|
+
`build/build-wasm.cjs: cached ttsc.wasm is up to date (${(
|
|
206
|
+
fs.statSync(wasmOut).size /
|
|
207
|
+
1024 /
|
|
208
|
+
1024
|
|
209
|
+
).toFixed(2)} MiB) — skipping rebuild`,
|
|
210
|
+
);
|
|
211
|
+
if (wasmExecSrc && !fs.existsSync(wasmExecOut)) {
|
|
212
|
+
fs.copyFileSync(wasmExecSrc, wasmExecOut);
|
|
213
|
+
}
|
|
214
|
+
// Even on cache hit, refresh the vendored shim + published go.mod so
|
|
215
|
+
// `pnpm pack` always sees up-to-date publish artifacts.
|
|
216
|
+
vendorShim();
|
|
217
|
+
rewritePublishedGoMod();
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (!wasmExecSrc) {
|
|
223
|
+
console.error(
|
|
224
|
+
"build/build-wasm.cjs: wasm_exec.js not located. Install Go 1.24+.",
|
|
225
|
+
);
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
vendorShim();
|
|
230
|
+
rewritePublishedGoMod();
|
|
231
|
+
buildWasm();
|
|
232
|
+
fs.copyFileSync(wasmExecSrc, wasmExecOut);
|
|
233
|
+
|
|
234
|
+
console.log(
|
|
235
|
+
`build/build-wasm.cjs: done. ttsc.wasm = ${(
|
|
236
|
+
fs.statSync(wasmOut).size /
|
|
237
|
+
1024 /
|
|
238
|
+
1024
|
|
239
|
+
).toFixed(2)} MiB`,
|
|
240
|
+
);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// prepack/postpack helper for @ttsc/wasm.
|
|
2
|
+
//
|
|
3
|
+
// `pnpm pack` and `npm publish` both honor `files` against the working
|
|
4
|
+
// directory's `go.mod`, so the published tarball would otherwise carry the
|
|
5
|
+
// dev-time `replace ../ttsc/shim/*` paths. Those paths don't exist inside
|
|
6
|
+
// the consumer's `node_modules/@ttsc/wasm/`, so the module would fail to
|
|
7
|
+
// resolve.
|
|
8
|
+
//
|
|
9
|
+
// build-wasm.cjs emits a rewritten `dist/go.mod` that points at the
|
|
10
|
+
// vendored `./vendor/shim/*` tree. Pack-prepare swaps the working-tree
|
|
11
|
+
// `go.mod` for that copy just before pack, then restores the original
|
|
12
|
+
// afterwards. The original is stashed in `build/.go.mod.stash` so an
|
|
13
|
+
// interrupted pack can be recovered by running `--restore`.
|
|
14
|
+
//
|
|
15
|
+
// Usage:
|
|
16
|
+
// node build/pack-prepare.cjs --stash # prepack: stash + swap
|
|
17
|
+
// node build/pack-prepare.cjs --restore # postpack: restore stash
|
|
18
|
+
|
|
19
|
+
const fs = require("fs");
|
|
20
|
+
const path = require("path");
|
|
21
|
+
|
|
22
|
+
const packageRoot = path.resolve(__dirname, "..");
|
|
23
|
+
const goModPath = path.join(packageRoot, "go.mod");
|
|
24
|
+
const publishedGoMod = path.join(packageRoot, "dist", "go.mod");
|
|
25
|
+
// Stash lives in node_modules/.cache to keep it out of the tarball (node_modules
|
|
26
|
+
// is never packed). Using package-local dist/ would risk shipping the stash;
|
|
27
|
+
// __dirname (`build/`) is in `files` so the stash would leak too.
|
|
28
|
+
const stashDir = path.join(packageRoot, "node_modules", ".cache", "ttsc-wasm");
|
|
29
|
+
const stashPath = path.join(stashDir, "go.mod.stash");
|
|
30
|
+
|
|
31
|
+
function stash() {
|
|
32
|
+
if (!fs.existsSync(publishedGoMod)) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`pack-prepare: dist/go.mod missing. Run \`pnpm --filter @ttsc/wasm build\` first.`,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
if (fs.existsSync(stashPath)) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
`pack-prepare: stale stash at ${stashPath}. Run \`--restore\` first or delete the stash.`,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
fs.mkdirSync(stashDir, { recursive: true });
|
|
43
|
+
fs.copyFileSync(goModPath, stashPath);
|
|
44
|
+
fs.copyFileSync(publishedGoMod, goModPath);
|
|
45
|
+
console.log("pack-prepare: swapped go.mod for published copy");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function restore() {
|
|
49
|
+
if (!fs.existsSync(stashPath)) {
|
|
50
|
+
console.log("pack-prepare: no stash to restore");
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
fs.copyFileSync(stashPath, goModPath);
|
|
54
|
+
fs.rmSync(stashPath);
|
|
55
|
+
console.log("pack-prepare: restored working-tree go.mod");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const mode = process.argv[2];
|
|
59
|
+
if (mode === "--stash") {
|
|
60
|
+
stash();
|
|
61
|
+
} else if (mode === "--restore") {
|
|
62
|
+
restore();
|
|
63
|
+
} else {
|
|
64
|
+
console.error(
|
|
65
|
+
"pack-prepare: usage: node build/pack-prepare.cjs [--stash|--restore]",
|
|
66
|
+
);
|
|
67
|
+
process.exit(2);
|
|
68
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
//go:build !js
|
|
2
|
+
|
|
3
|
+
// Command ttsc-wasm is the non-wasm sanity entrypoint for `@ttsc/wasm`.
|
|
4
|
+
//
|
|
5
|
+
// The same binary, compiled with GOOS=js GOARCH=wasm, becomes the browser
|
|
6
|
+
// wasm consumed by `bootTtsc`. For native targets we expose a minimal CLI so
|
|
7
|
+
// `go run ./cmd/ttsc-wasm` exercises the same host helpers without needing
|
|
8
|
+
// the browser MemFS bridge.
|
|
9
|
+
package main
|
|
10
|
+
|
|
11
|
+
import (
|
|
12
|
+
"fmt"
|
|
13
|
+
"io"
|
|
14
|
+
"os"
|
|
15
|
+
"runtime"
|
|
16
|
+
|
|
17
|
+
"github.com/samchon/ttsc/packages/wasm/host"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
// Build metadata. Overridden via -ldflags from build/build-wasm.cjs.
|
|
21
|
+
var (
|
|
22
|
+
version = "0.0.0-dev"
|
|
23
|
+
commit = "dev"
|
|
24
|
+
date = "unknown"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
func main() {
|
|
28
|
+
os.Exit(run(os.Args[1:]))
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
func run(args []string) int {
|
|
32
|
+
if len(args) == 0 {
|
|
33
|
+
printHelp(os.Stdout)
|
|
34
|
+
return 0
|
|
35
|
+
}
|
|
36
|
+
switch args[0] {
|
|
37
|
+
case "-h", "--help", "help":
|
|
38
|
+
printHelp(os.Stdout)
|
|
39
|
+
return 0
|
|
40
|
+
case "-v", "--version", "version":
|
|
41
|
+
printVersion(os.Stdout)
|
|
42
|
+
return 0
|
|
43
|
+
case "build":
|
|
44
|
+
return runBuild(args[1:])
|
|
45
|
+
case "check":
|
|
46
|
+
return runCheck(args[1:])
|
|
47
|
+
case "transform":
|
|
48
|
+
return runTransform(args[1:])
|
|
49
|
+
default:
|
|
50
|
+
fmt.Fprintf(os.Stderr, "ttsc-wasm: unknown command %q\n", args[0])
|
|
51
|
+
printHelp(os.Stderr)
|
|
52
|
+
return 2
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
func runBuild(args []string) int {
|
|
57
|
+
cwd, tsconfig := parseProject(args)
|
|
58
|
+
data, code, err := host.Build(cwd, tsconfig)
|
|
59
|
+
if err != nil {
|
|
60
|
+
fmt.Fprintf(os.Stderr, "ttsc-wasm build: %v\n", err)
|
|
61
|
+
return 2
|
|
62
|
+
}
|
|
63
|
+
_, _ = os.Stdout.Write(append(data, '\n'))
|
|
64
|
+
return code
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
func runCheck(args []string) int {
|
|
68
|
+
cwd, tsconfig := parseProject(args)
|
|
69
|
+
data, code, err := host.Check(cwd, tsconfig)
|
|
70
|
+
if err != nil {
|
|
71
|
+
fmt.Fprintf(os.Stderr, "ttsc-wasm check: %v\n", err)
|
|
72
|
+
return 2
|
|
73
|
+
}
|
|
74
|
+
_, _ = os.Stdout.Write(append(data, '\n'))
|
|
75
|
+
return code
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
func runTransform(args []string) int {
|
|
79
|
+
cwd, tsconfig := parseProject(args)
|
|
80
|
+
data, code, err := host.Transform(cwd, tsconfig)
|
|
81
|
+
if err != nil {
|
|
82
|
+
fmt.Fprintf(os.Stderr, "ttsc-wasm transform: %v\n", err)
|
|
83
|
+
return 2
|
|
84
|
+
}
|
|
85
|
+
_, _ = os.Stdout.Write(append(data, '\n'))
|
|
86
|
+
return code
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
func parseProject(args []string) (string, string) {
|
|
90
|
+
cwd, _ := os.Getwd()
|
|
91
|
+
tsconfig := "tsconfig.json"
|
|
92
|
+
for i := 0; i < len(args); i++ {
|
|
93
|
+
arg := args[i]
|
|
94
|
+
switch {
|
|
95
|
+
case arg == "--cwd" && i+1 < len(args):
|
|
96
|
+
cwd = args[i+1]
|
|
97
|
+
i++
|
|
98
|
+
case len(arg) > len("--cwd=") && arg[:6] == "--cwd=":
|
|
99
|
+
cwd = arg[6:]
|
|
100
|
+
case arg == "--tsconfig" && i+1 < len(args):
|
|
101
|
+
tsconfig = args[i+1]
|
|
102
|
+
i++
|
|
103
|
+
case len(arg) > len("--tsconfig=") && arg[:11] == "--tsconfig=":
|
|
104
|
+
tsconfig = arg[11:]
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return cwd, tsconfig
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
func printHelp(w io.Writer) {
|
|
111
|
+
fmt.Fprintln(w, "Usage: ttsc-wasm <command> [--cwd=<dir>] [--tsconfig=<path>]")
|
|
112
|
+
fmt.Fprintln(w, "Commands:")
|
|
113
|
+
fmt.Fprintln(w, " build compile a project and print the JSON result")
|
|
114
|
+
fmt.Fprintln(w, " check type-check a project without emit")
|
|
115
|
+
fmt.Fprintln(w, " transform return every source file the program saw")
|
|
116
|
+
fmt.Fprintln(w, " version print version banner")
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
func printVersion(w io.Writer) {
|
|
120
|
+
fmt.Fprintf(
|
|
121
|
+
w,
|
|
122
|
+
"ttsc-wasm %s (commit %s, built %s, %s/%s, go %s)\n",
|
|
123
|
+
version,
|
|
124
|
+
commit,
|
|
125
|
+
date,
|
|
126
|
+
runtime.GOOS,
|
|
127
|
+
runtime.GOARCH,
|
|
128
|
+
runtime.Version(),
|
|
129
|
+
)
|
|
130
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//go:build js && wasm
|
|
2
|
+
|
|
3
|
+
// Browser entry for the base `ttsc.wasm`. Ships ttsc + typescript-go only —
|
|
4
|
+
// no first-party plugins are linked here. Downstream playgrounds bundle their
|
|
5
|
+
// own plugins by writing their own `main_wasm.go` against the same host
|
|
6
|
+
// helper and producing a separate `.wasm`.
|
|
7
|
+
package main
|
|
8
|
+
|
|
9
|
+
import (
|
|
10
|
+
"github.com/samchon/ttsc/packages/wasm/host"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
func main() {
|
|
14
|
+
host.Expose("ttsc", host.Config{
|
|
15
|
+
Plugins: nil,
|
|
16
|
+
})
|
|
17
|
+
}
|
package/dist/go.mod
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module github.com/samchon/ttsc/packages/wasm
|
|
2
|
+
|
|
3
|
+
go 1.26
|
|
4
|
+
|
|
5
|
+
// The wasm package is a thin Go-side shell around `packages/ttsc/driver`.
|
|
6
|
+
// It re-uses the same shim/* tree that the native CLI ships with, so every
|
|
7
|
+
// replace directive mirrors `packages/ttsc/go.mod`. Without these, the
|
|
8
|
+
// public proxy cannot resolve the in-tree shim modules.
|
|
9
|
+
replace (
|
|
10
|
+
github.com/microsoft/typescript-go/shim/ast => ./vendor/shim/ast
|
|
11
|
+
github.com/microsoft/typescript-go/shim/bundled => ./vendor/shim/bundled
|
|
12
|
+
github.com/microsoft/typescript-go/shim/checker => ./vendor/shim/checker
|
|
13
|
+
github.com/microsoft/typescript-go/shim/compiler => ./vendor/shim/compiler
|
|
14
|
+
github.com/microsoft/typescript-go/shim/core => ./vendor/shim/core
|
|
15
|
+
github.com/microsoft/typescript-go/shim/diagnosticwriter => ./vendor/shim/diagnosticwriter
|
|
16
|
+
github.com/microsoft/typescript-go/shim/lsp => ./vendor/shim/lsp
|
|
17
|
+
github.com/microsoft/typescript-go/shim/parser => ./vendor/shim/parser
|
|
18
|
+
github.com/microsoft/typescript-go/shim/printer => ./vendor/shim/printer
|
|
19
|
+
github.com/microsoft/typescript-go/shim/scanner => ./vendor/shim/scanner
|
|
20
|
+
github.com/microsoft/typescript-go/shim/tsoptions => ./vendor/shim/tsoptions
|
|
21
|
+
github.com/microsoft/typescript-go/shim/tspath => ./vendor/shim/tspath
|
|
22
|
+
github.com/microsoft/typescript-go/shim/vfs => ./vendor/shim/vfs
|
|
23
|
+
github.com/microsoft/typescript-go/shim/vfs/cachedvfs => ./vendor/shim/vfs/cachedvfs
|
|
24
|
+
github.com/microsoft/typescript-go/shim/vfs/osvfs => ./vendor/shim/vfs/osvfs
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
require (
|
|
28
|
+
github.com/microsoft/typescript-go/shim/compiler v0.0.0
|
|
29
|
+
github.com/samchon/ttsc/packages/ttsc v0.0.0
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
require (
|
|
33
|
+
github.com/Microsoft/go-winio v0.6.2 // indirect
|
|
34
|
+
github.com/go-json-experiment/json v0.0.0-20260214004413-d219187c3433 // indirect
|
|
35
|
+
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
|
36
|
+
github.com/mackerelio/go-osstat v0.2.7 // indirect
|
|
37
|
+
github.com/microsoft/typescript-go v0.0.0-20260429010842-56ab4af42157 // indirect
|
|
38
|
+
github.com/microsoft/typescript-go/shim/ast v0.0.0 // indirect
|
|
39
|
+
github.com/microsoft/typescript-go/shim/bundled v0.0.0 // indirect
|
|
40
|
+
github.com/microsoft/typescript-go/shim/checker v0.0.0 // indirect
|
|
41
|
+
github.com/microsoft/typescript-go/shim/core v0.0.0 // indirect
|
|
42
|
+
github.com/microsoft/typescript-go/shim/diagnosticwriter v0.0.0 // indirect
|
|
43
|
+
github.com/microsoft/typescript-go/shim/lsp v0.0.0 // indirect
|
|
44
|
+
github.com/microsoft/typescript-go/shim/scanner v0.0.0 // indirect
|
|
45
|
+
github.com/microsoft/typescript-go/shim/tsoptions v0.0.0 // indirect
|
|
46
|
+
github.com/microsoft/typescript-go/shim/tspath v0.0.0 // indirect
|
|
47
|
+
github.com/microsoft/typescript-go/shim/vfs v0.0.0 // indirect
|
|
48
|
+
github.com/microsoft/typescript-go/shim/vfs/cachedvfs v0.0.0 // indirect
|
|
49
|
+
github.com/microsoft/typescript-go/shim/vfs/osvfs v0.0.0 // indirect
|
|
50
|
+
github.com/zeebo/xxh3 v1.1.0 // indirect
|
|
51
|
+
golang.org/x/sync v0.20.0 // indirect
|
|
52
|
+
golang.org/x/sys v0.43.0 // indirect
|
|
53
|
+
golang.org/x/text v0.36.0 // indirect
|
|
54
|
+
)
|
package/dist/ttsc.wasm
ADDED
|
Binary file
|