@ttsc/playground 0.30.4 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/lib/src/compiler/buildTsconfigJSON.d.ts +5 -0
- package/lib/src/compiler/buildTsconfigJSON.js +5 -0
- package/lib/src/compiler/buildTsconfigJSON.js.map +1 -1
- package/lib/src/compiler/createTypiaSourcePackMount.d.ts +9 -3
- package/lib/src/compiler/createTypiaSourcePackMount.js +9 -3
- package/lib/src/compiler/createTypiaSourcePackMount.js.map +1 -1
- package/lib/src/compiler/createWorkerCompiler.d.ts +5 -0
- package/lib/src/compiler/createWorkerCompiler.js +5 -0
- package/lib/src/compiler/createWorkerCompiler.js.map +1 -1
- package/lib/src/compiler/installDependenciesIntoMemFS.d.ts +5 -0
- package/lib/src/compiler/installDependenciesIntoMemFS.js +5 -0
- package/lib/src/compiler/installDependenciesIntoMemFS.js.map +1 -1
- package/lib/src/compiler/installTypiaSourcePack.d.ts +7 -2
- package/lib/src/compiler/installTypiaSourcePack.js +7 -2
- package/lib/src/compiler/installTypiaSourcePack.js.map +1 -1
- package/lib/src/compiler/internal/createWorkerCompilerService.d.ts +31 -0
- package/lib/src/compiler/internal/createWorkerCompilerService.js +22 -4
- package/lib/src/compiler/internal/createWorkerCompilerService.js.map +1 -1
- package/lib/src/compiler/internal/joinUnder.d.ts +5 -0
- package/lib/src/compiler/internal/joinUnder.js +5 -0
- package/lib/src/compiler/internal/joinUnder.js.map +1 -1
- package/lib/src/compiler/internal/parseLintDiagnostics.d.ts +5 -0
- package/lib/src/compiler/internal/parseLintDiagnostics.js +8 -3
- package/lib/src/compiler/internal/parseLintDiagnostics.js.map +1 -1
- package/lib/src/compiler/internal/safeParseTypiaTransform.d.ts +14 -1
- package/lib/src/compiler/internal/safeParseTypiaTransform.js +12 -1
- package/lib/src/compiler/internal/safeParseTypiaTransform.js.map +1 -1
- package/lib/src/compiler/lineColumnOf.d.ts +9 -1
- package/lib/src/compiler/lineColumnOf.js +23 -7
- package/lib/src/compiler/lineColumnOf.js.map +1 -1
- package/lib/src/compiler/loadTypiaSourcePack.d.ts +23 -1
- package/lib/src/compiler/loadTypiaSourcePack.js +48 -12
- package/lib/src/compiler/loadTypiaSourcePack.js.map +1 -1
- package/lib/src/compiler/mapDiagnostic.d.ts +7 -2
- package/lib/src/compiler/mapDiagnostic.js +53 -6
- package/lib/src/compiler/mapDiagnostic.js.map +1 -1
- package/lib/src/compiler/normalizeError.d.ts +9 -1
- package/lib/src/compiler/normalizeError.js +9 -1
- package/lib/src/compiler/normalizeError.js.map +1 -1
- package/lib/src/compiler/normalizeNodeModulePath.d.ts +5 -0
- package/lib/src/compiler/normalizeNodeModulePath.js +5 -0
- package/lib/src/compiler/normalizeNodeModulePath.js.map +1 -1
- package/lib/src/compiler/pickEmittedJS.d.ts +9 -2
- package/lib/src/compiler/pickEmittedJS.js +23 -6
- package/lib/src/compiler/pickEmittedJS.js.map +1 -1
- package/lib/src/npm/collectExternalPackageNames.d.ts +17 -0
- package/lib/src/npm/collectExternalPackageNames.js +51 -11
- package/lib/src/npm/collectExternalPackageNames.js.map +1 -1
- package/lib/src/npm/installPlaygroundDependencies.d.ts +10 -2
- package/lib/src/npm/installPlaygroundDependencies.js +18 -4
- package/lib/src/npm/installPlaygroundDependencies.js.map +1 -1
- package/lib/src/npm/internal/npmRegistry.d.ts +149 -2
- package/lib/src/npm/internal/npmRegistry.js +95 -4
- package/lib/src/npm/internal/npmRegistry.js.map +1 -1
- package/lib/src/npm/packageNameFromSpecifier.d.ts +5 -0
- package/lib/src/npm/packageNameFromSpecifier.js +7 -0
- package/lib/src/npm/packageNameFromSpecifier.js.map +1 -1
- package/lib/src/react/ConsoleViewer.d.ts +9 -0
- package/lib/src/react/ConsoleViewer.js +11 -2
- package/lib/src/react/ConsoleViewer.js.map +1 -1
- package/lib/src/react/DependencyProgressModal.d.ts +9 -0
- package/lib/src/react/DependencyProgressModal.js +9 -0
- package/lib/src/react/DependencyProgressModal.js.map +1 -1
- package/lib/src/react/DiagnosticsPanel.d.ts +9 -0
- package/lib/src/react/DiagnosticsPanel.js +9 -0
- package/lib/src/react/DiagnosticsPanel.js.map +1 -1
- package/lib/src/react/ExamplePicker.d.ts +9 -0
- package/lib/src/react/ExamplePicker.js +14 -2
- package/lib/src/react/ExamplePicker.js.map +1 -1
- package/lib/src/react/LintPane.d.ts +5 -0
- package/lib/src/react/LintPane.js +5 -0
- package/lib/src/react/LintPane.js.map +1 -1
- package/lib/src/react/OptionsPanel.d.ts +10 -0
- package/lib/src/react/OptionsPanel.js +19 -4
- package/lib/src/react/OptionsPanel.js.map +1 -1
- package/lib/src/react/PlaygroundShell.d.ts +13 -0
- package/lib/src/react/PlaygroundShell.js +17 -5
- package/lib/src/react/PlaygroundShell.js.map +1 -1
- package/lib/src/react/ResultViewer.d.ts +5 -0
- package/lib/src/react/ResultViewer.js +27 -7
- package/lib/src/react/ResultViewer.js.map +1 -1
- package/lib/src/react/SourceEditor.d.ts +10 -0
- package/lib/src/react/SourceEditor.js +10 -0
- package/lib/src/react/SourceEditor.js.map +1 -1
- package/lib/src/react/createCompilerClient.d.ts +5 -0
- package/lib/src/react/createCompilerClient.js +5 -0
- package/lib/src/react/createCompilerClient.js.map +1 -1
- package/lib/src/react/internal/PlaygroundCompilerLifecycle.d.ts +64 -1
- package/lib/src/react/internal/PlaygroundCompilerLifecycle.js +48 -0
- package/lib/src/react/internal/PlaygroundCompilerLifecycle.js.map +1 -1
- package/lib/src/react/internal/PlaygroundExecutionLifecycle.d.ts +42 -2
- package/lib/src/react/internal/PlaygroundExecutionLifecycle.js +18 -0
- package/lib/src/react/internal/PlaygroundExecutionLifecycle.js.map +1 -1
- package/lib/src/react/internal/recoverTerminalCompilerWorker.d.ts +46 -4
- package/lib/src/react/internal/recoverTerminalCompilerWorker.js +14 -1
- package/lib/src/react/internal/recoverTerminalCompilerWorker.js.map +1 -1
- package/lib/src/sandbox/createSandboxRequire.d.ts +12 -3
- package/lib/src/sandbox/createSandboxRequire.js +26 -12
- package/lib/src/sandbox/createSandboxRequire.js.map +1 -1
- package/lib/src/sandbox/loadTypiaRuntimePack.d.ts +22 -0
- package/lib/src/sandbox/loadTypiaRuntimePack.js +30 -1
- package/lib/src/sandbox/loadTypiaRuntimePack.js.map +1 -1
- package/lib/src/structures/IBuildTsconfigOptions.d.ts +9 -1
- package/lib/src/structures/ICompilerService.d.ts +112 -2
- package/lib/src/structures/IConsoleMessage.d.ts +5 -0
- package/lib/src/structures/ICreateCompilerClientOptions.d.ts +9 -2
- package/lib/src/structures/ICreateWorkerCompilerOptions.d.ts +11 -3
- package/lib/src/structures/IInstallTypiaSourcePackOptions.d.ts +7 -1
- package/lib/src/structures/ILintPluginConfig.d.ts +8 -1
- package/lib/src/structures/ILoadTypiaRuntimePackOptions.d.ts +8 -1
- package/lib/src/structures/IOptionToggle.d.ts +5 -0
- package/lib/src/structures/IPlaygroundDependencyInstallOptions.d.ts +41 -6
- package/lib/src/structures/IPlaygroundDependencyInstallResult.d.ts +8 -1
- package/lib/src/structures/IPlaygroundDependencyPackage.d.ts +9 -1
- package/lib/src/structures/IPlaygroundDependencyProgress.d.ts +9 -1
- package/lib/src/structures/IPlaygroundDependencyProgressPhase.d.ts +7 -2
- package/lib/src/structures/IPlaygroundDependencyRequest.d.ts +8 -1
- package/lib/src/structures/IPlaygroundExample.d.ts +5 -0
- package/lib/src/structures/IPlaygroundInstalledDependency.d.ts +8 -1
- package/lib/src/structures/IPlaygroundShellProps.d.ts +53 -19
- package/lib/src/structures/ISourceEditorProps.d.ts +16 -1
- package/lib/src/structures/ITransformOptions.d.ts +5 -0
- package/lib/src/structures/ITypiaPluginConfig.d.ts +25 -7
- package/package.json +6 -4
- package/src/compiler/buildTsconfigJSON.ts +5 -0
- package/src/compiler/createTypiaSourcePackMount.ts +9 -3
- package/src/compiler/createWorkerCompiler.ts +5 -0
- package/src/compiler/installDependenciesIntoMemFS.ts +5 -0
- package/src/compiler/installTypiaSourcePack.ts +7 -2
- package/src/compiler/internal/createWorkerCompilerService.ts +47 -4
- package/src/compiler/internal/joinUnder.ts +5 -0
- package/src/compiler/internal/parseLintDiagnostics.ts +8 -3
- package/src/compiler/internal/safeParseTypiaTransform.ts +25 -2
- package/src/compiler/lineColumnOf.ts +24 -8
- package/src/compiler/loadTypiaSourcePack.ts +57 -14
- package/src/compiler/mapDiagnostic.ts +67 -7
- package/src/compiler/normalizeError.ts +9 -1
- package/src/compiler/normalizeNodeModulePath.ts +5 -0
- package/src/compiler/pickEmittedJS.ts +22 -5
- package/src/npm/collectExternalPackageNames.ts +54 -13
- package/src/npm/installPlaygroundDependencies.ts +18 -6
- package/src/npm/internal/npmRegistry.ts +156 -4
- package/src/npm/packageNameFromSpecifier.ts +6 -0
- package/src/react/ConsoleViewer.tsx +10 -1
- package/src/react/DependencyProgressModal.tsx +9 -0
- package/src/react/DiagnosticsPanel.tsx +9 -0
- package/src/react/ExamplePicker.tsx +22 -6
- package/src/react/LintPane.tsx +5 -0
- package/src/react/OptionsPanel.tsx +22 -4
- package/src/react/PlaygroundShell.tsx +17 -5
- package/src/react/ResultViewer.tsx +28 -7
- package/src/react/SourceEditor.tsx +10 -0
- package/src/react/createCompilerClient.ts +5 -0
- package/src/react/internal/PlaygroundCompilerLifecycle.ts +64 -1
- package/src/react/internal/PlaygroundExecutionLifecycle.ts +44 -2
- package/src/react/internal/recoverTerminalCompilerWorker.ts +48 -4
- package/src/sandbox/createSandboxRequire.ts +28 -15
- package/src/sandbox/loadTypiaRuntimePack.ts +35 -2
- package/src/structures/IBuildTsconfigOptions.ts +13 -1
- package/src/structures/ICompilerService.ts +119 -2
- package/src/structures/IConsoleMessage.ts +5 -0
- package/src/structures/ICreateCompilerClientOptions.ts +9 -2
- package/src/structures/ICreateWorkerCompilerOptions.ts +15 -3
- package/src/structures/IInstallTypiaSourcePackOptions.ts +11 -1
- package/src/structures/ILintPluginConfig.ts +8 -1
- package/src/structures/ILoadTypiaRuntimePackOptions.ts +8 -1
- package/src/structures/IOptionToggle.ts +5 -0
- package/src/structures/IPlaygroundDependencyInstallOptions.ts +56 -6
- package/src/structures/IPlaygroundDependencyInstallResult.ts +12 -1
- package/src/structures/IPlaygroundDependencyPackage.ts +11 -1
- package/src/structures/IPlaygroundDependencyProgress.ts +9 -1
- package/src/structures/IPlaygroundDependencyProgressPhase.ts +7 -2
- package/src/structures/IPlaygroundDependencyRequest.ts +10 -1
- package/src/structures/IPlaygroundExample.ts +6 -0
- package/src/structures/IPlaygroundInstalledDependency.ts +11 -1
- package/src/structures/IPlaygroundShellProps.ts +62 -22
- package/src/structures/ISourceEditorProps.ts +20 -1
- package/src/structures/ITransformOptions.ts +7 -0
- package/src/structures/ITypiaPluginConfig.ts +31 -7
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
* verbs `createWorkerCompiler` calls by default; sites that wire additional
|
|
5
5
|
* plugins can extend this interface via TypeScript declaration merging or pass
|
|
6
6
|
* a richer shape through `[key: string]: boolean | undefined`.
|
|
7
|
+
*
|
|
8
|
+
* @evidence contracts/common.md#principled-implementation Optional boolean flags distinguish default integration behavior from explicit disabling; the index signature permits additional boolean site flags.
|
|
9
|
+
* @evidence contracts/common.md#clear-and-simple-design Per-call flags stay independent of factory plugin registration and UI labels.
|
|
10
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Extensible keys pass through the declared option boundary instead of adding site-specific dispatcher branches.
|
|
11
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose explains extension, default enablement and forwarding, with documentation-skill paragraphs and member spacing.
|
|
7
12
|
*/
|
|
8
13
|
export interface ITransformOptions {
|
|
9
14
|
/** Enable the typia transform plugin. Defaults to true. */
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { IMemFSHost } from "@ttsc/wasm";
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Options for the typia integration of {@link createWorkerCompiler}.
|
|
4
|
+
*
|
|
5
|
+
* @evidence contracts/common.md#principled-implementation Host registration id, transform module and source mounting callback represent the three distinct integration inputs.
|
|
6
|
+
* @evidence contracts/common.md#clear-and-simple-design Typia-specific settings are nested away from runtime boot and per-call enablement.
|
|
7
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Default identities are supported typia configuration and remain explicitly replaceable by the site.
|
|
8
|
+
* @evidence contracts/common.md#meaningful-documentation Members explain host identity, transform module and forwarded virtual work directory, with documentation-skill paragraphs and spacing.
|
|
9
|
+
*/
|
|
3
10
|
export interface ITypiaPluginConfig {
|
|
4
11
|
/** Plugin id registered with `host.Expose` (default: `"typia"`). */
|
|
5
12
|
name?: string;
|
|
@@ -9,11 +16,22 @@ export interface ITypiaPluginConfig {
|
|
|
9
16
|
*/
|
|
10
17
|
transformModule?: string;
|
|
11
18
|
/**
|
|
12
|
-
* Optional hook to mount typia source files into the MemFS
|
|
13
|
-
*
|
|
14
|
-
* `<workDir>/node_modules/`.
|
|
15
|
-
*
|
|
16
|
-
*
|
|
19
|
+
* Optional hook to mount typia source files into the MemFS once the wasm
|
|
20
|
+
* runtime is ready, before the first request runs. The site fetches its
|
|
21
|
+
* pre-built typia pack and writes it under `<workDir>/node_modules/`. A
|
|
22
|
+
* rejected mount is retried by the next request without starting another
|
|
23
|
+
* runtime. `workDir` is forwarded from `createWorkerCompiler` so the mount
|
|
24
|
+
* can honor a non-default project root without the site rewiring the URL.
|
|
17
25
|
*/
|
|
18
|
-
mount?:
|
|
26
|
+
mount?: TypiaSourceMount;
|
|
19
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Mount typia sources into the live virtual host after boot at the actual work
|
|
30
|
+
* directory.
|
|
31
|
+
*
|
|
32
|
+
* @evidence contracts/common.md#principled-implementation Host and workDir identify the filesystem and project root that compilation actually uses.
|
|
33
|
+
* @evidence contracts/common.md#clear-and-simple-design One asynchronous mount hook leaves boot and serial compilation with the worker factory.
|
|
34
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Mounting uses IMemFSHost without patching compiler internals or guessing the project root.
|
|
35
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose names timing, filesystem and directory ownership before the separated tags.
|
|
36
|
+
*/
|
|
37
|
+
export type TypiaSourceMount = (host: IMemFSHost, workDir: string) => Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttsc/playground",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.0",
|
|
4
4
|
"description": "Reusable React + Web Worker scaffolding for in-browser ttsc playgrounds built on @ttsc/wasm.",
|
|
5
5
|
"main": "lib/src/index.js",
|
|
6
6
|
"types": "lib/src/index.d.ts",
|
|
@@ -39,9 +39,10 @@
|
|
|
39
39
|
"react": "^18.0.0",
|
|
40
40
|
"react-dom": "^18.0.0",
|
|
41
41
|
"tgrid": "^1.0.3",
|
|
42
|
-
"@ttsc/wasm": "^0.
|
|
42
|
+
"@ttsc/wasm": "^0.31.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
+
"@wrtnlabs/evidence": "^0.3.1",
|
|
45
46
|
"@monaco-editor/react": "^4.6.0",
|
|
46
47
|
"@types/semver": "^7.7.1",
|
|
47
48
|
"@types/node": "^25.3.0",
|
|
@@ -52,7 +53,7 @@
|
|
|
52
53
|
"rimraf": "^6.1.2",
|
|
53
54
|
"tgrid": "^1.0.3",
|
|
54
55
|
"typescript": "^7.0.2",
|
|
55
|
-
"@ttsc/wasm": "^0.
|
|
56
|
+
"@ttsc/wasm": "^0.31.0"
|
|
56
57
|
},
|
|
57
58
|
"keywords": [
|
|
58
59
|
"ttsc",
|
|
@@ -63,6 +64,7 @@
|
|
|
63
64
|
"react"
|
|
64
65
|
],
|
|
65
66
|
"scripts": {
|
|
66
|
-
"build": "rimraf lib && tsc -p ."
|
|
67
|
+
"build": "rimraf lib && tsc -p .",
|
|
68
|
+
"evidence": "evidence"
|
|
67
69
|
}
|
|
68
70
|
}
|
|
@@ -7,6 +7,11 @@ import { DEFAULT_PLAYGROUND_COMPILER_OPTIONS } from "./DEFAULT_PLAYGROUND_COMPIL
|
|
|
7
7
|
* `buildTsconfigJSON` is deliberately conservative — it returns a string the
|
|
8
8
|
* caller writes to MemFS as-is, so there's no schema validation here. Bad
|
|
9
9
|
* compiler options surface as wasm-side errors on the next build call.
|
|
10
|
+
*
|
|
11
|
+
* @evidence contracts/common.md#principled-implementation Object spread applies documented default-then-caller precedence and JSON.stringify emits the compiler's JSON input; compiler validation remains with the compiler.
|
|
12
|
+
* @evidence contracts/common.md#clear-and-simple-design This operation only serializes configuration; the caller owns virtual writes and execution.
|
|
13
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Defaults are supported project settings and caller overrides remain explicit, without fixture-dependent branches.
|
|
14
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose explains serialization ownership and validation timing in separate paragraphs under the documentation skill.
|
|
10
15
|
*/
|
|
11
16
|
export function buildTsconfigJSON(options: IBuildTsconfigOptions): string {
|
|
12
17
|
return JSON.stringify({
|
|
@@ -7,9 +7,15 @@ import { installTypiaSourcePack } from "./installTypiaSourcePack";
|
|
|
7
7
|
* Build a `mount` callback for the `typiaPlugin` config of
|
|
8
8
|
* {@link createWorkerCompiler}.
|
|
9
9
|
*
|
|
10
|
-
* The returned function
|
|
11
|
-
* {@link loadTypiaSourcePack}
|
|
12
|
-
*
|
|
10
|
+
* The returned function shares loading by URL and fetch function identity
|
|
11
|
+
* through {@link loadTypiaSourcePack}, then writes every entry to the MemFS on
|
|
12
|
+
* each invocation. Network records are cached, but mounting repeats so a caller
|
|
13
|
+
* can restore files removed from the virtual host.
|
|
14
|
+
*
|
|
15
|
+
* @evidence contracts/common.md#principled-implementation Explicit mountRoot overrides the actual worker workDir; absent both, installation uses its documented virtual root.
|
|
16
|
+
* @evidence contracts/common.md#clear-and-simple-design One adapter derives the root and delegates transport and writes to their owning operations.
|
|
17
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The optional workDir preserves the supported single-argument callback while supplied project roots are honored instead of patched with fixed paths.
|
|
18
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose distinguishes cached loading from repeated mounting and explains callback compatibility, following documentation-skill paragraph separation.
|
|
13
19
|
*/
|
|
14
20
|
export function createTypiaSourcePackMount(
|
|
15
21
|
options: IInstallTypiaSourcePackOptions,
|
|
@@ -37,6 +37,11 @@ import { createWorkerCompilerService } from "./internal/createWorkerCompilerServ
|
|
|
37
37
|
* };
|
|
38
38
|
* void main();
|
|
39
39
|
* ```
|
|
40
|
+
*
|
|
41
|
+
* @evidence contracts/common.md#principled-implementation The wrapper supplies the real WASM boot and result parser to the same typed service core exposed over tgrid.
|
|
42
|
+
* @evidence contracts/common.md#clear-and-simple-design Runtime binding stays in this thin factory while pipeline state and serialization remain in the service core.
|
|
43
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Dependency injection is a supported binding seam, without replacement of foreign APIs or test-only production paths.
|
|
44
|
+
* @evidence contracts/common.md#meaningful-documentation Native JSDoc demonstrates WorkerServer registration and required runtime identity, with descriptive text separated from tags under the documentation skill.
|
|
40
45
|
*/
|
|
41
46
|
export function createWorkerCompiler(
|
|
42
47
|
options: ICreateWorkerCompilerOptions,
|
|
@@ -11,6 +11,11 @@ import { normalizeNodeModulePath } from "./normalizeNodeModulePath";
|
|
|
11
11
|
* `ICompilerService`. The dependency installer (UI side) feeds keys like
|
|
12
12
|
* `node_modules/uuid/dist/index.js`; we normalize, sanity-check, and copy each
|
|
13
13
|
* entry under the project root.
|
|
14
|
+
*
|
|
15
|
+
* @evidence contracts/common.md#principled-implementation Every file passes the node_modules-relative path gate before virtual writes; count reports accepted writes and metadata remains the caller's submitted list.
|
|
16
|
+
* @evidence contracts/common.md#clear-and-simple-design Mounting is one loop with path policy delegated to normalizeNodeModulePath and no registry-resolution responsibility.
|
|
17
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Malformed paths are uniformly skipped according to the declared mounting contract, without package-specific exemptions.
|
|
18
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose defines input namespace, project-root mapping and consumer ownership, following documentation-skill paragraphs.
|
|
14
19
|
*/
|
|
15
20
|
export function installDependenciesIntoMemFS(
|
|
16
21
|
host: IMemFSHost,
|
|
@@ -8,8 +8,13 @@ import { loadTypiaSourcePack } from "./loadTypiaSourcePack";
|
|
|
8
8
|
* wasm-side compiler can resolve `import typia, { tags } from "typia"` against
|
|
9
9
|
* the same code the published package uses.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* Repeated calls write the same loaded records again; this restores any entries
|
|
12
|
+
* the caller removed from the virtual host and replaces values at pack paths.
|
|
13
|
+
*
|
|
14
|
+
* @evidence contracts/common.md#principled-implementation Source-pack entries are written under the selected virtual mount root after the shared transport completes; the pack is a site-produced trusted record map.
|
|
15
|
+
* @evidence contracts/common.md#clear-and-simple-design Loading is delegated and this operation owns only root creation and entry writes.
|
|
16
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The caller supplies the pack URL and root; no consumer or fixture determines which source contents are mounted.
|
|
17
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose explains resolution purpose and repeated-write behavior without claiming MemFS suppresses writes, following documentation-skill paragraphs.
|
|
13
18
|
*/
|
|
14
19
|
export async function installTypiaSourcePack(
|
|
15
20
|
host: IMemFSHost,
|
|
@@ -36,9 +36,31 @@ import { safeParseTypiaTransform } from "./safeParseTypiaTransform";
|
|
|
36
36
|
* `createWorkerCompiler` binds the real implementations; tests bind fakes that
|
|
37
37
|
* resolve a synthetic `IBootResult` so the plugin-envelope handling can be
|
|
38
38
|
* verified without a real WASM boot.
|
|
39
|
+
*
|
|
40
|
+
* @evidence contracts/common.md#principled-implementation Boot and generic envelope parsing retain the WASM host signatures and null parse outcome needed by the service.
|
|
41
|
+
* @evidence contracts/common.md#clear-and-simple-design A two-collaborator record isolates runtime binding from pipeline control flow.
|
|
42
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Collaborators are explicit production dependencies, not global replacements or fixture-specific dispatch.
|
|
43
|
+
* @evidence contracts/common.md#meaningful-documentation Native paragraphs explain runtime binding and the injection purpose under the documentation skill.
|
|
39
44
|
*/
|
|
40
45
|
export interface IWorkerCompilerDeps {
|
|
46
|
+
/**
|
|
47
|
+
* Start the configured WASM runtime and return its ready host and API.
|
|
48
|
+
*
|
|
49
|
+
* @evidence contracts/common.md#principled-implementation The host's typed options and ready result preserve runtime identity and boot failure semantics.
|
|
50
|
+
* @evidence contracts/common.md#clear-and-simple-design This dependency owns runtime startup while the service owns mounting and request serialization.
|
|
51
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Injection uses the declared host API rather than replacing runtime globals.
|
|
52
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose states readiness and ownership with tag separation under the documentation skill.
|
|
53
|
+
*/
|
|
41
54
|
bootTtsc: (options: IBootTtscOptions) => Promise<IBootResult>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Decode one host envelope; null denotes absent or unusable payload.
|
|
58
|
+
*
|
|
59
|
+
* @evidence contracts/common.md#principled-implementation The generic parser maps the typed host envelope to the requested payload shape while exposing parse failure as null.
|
|
60
|
+
* @evidence contracts/common.md#clear-and-simple-design Decoding stays distinct from exit-code interpretation in the service.
|
|
61
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Null remains failure information and does not fabricate a successful empty compile result.
|
|
62
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose defines null and decoding responsibility, separated from tags under the documentation skill.
|
|
63
|
+
*/
|
|
42
64
|
parseResult: <T>(result: ITtscResult) => T | null;
|
|
43
65
|
}
|
|
44
66
|
|
|
@@ -48,6 +70,16 @@ type ITransformOutcome = { ok: true } | { ok: false; message: string };
|
|
|
48
70
|
/**
|
|
49
71
|
* Dependency-injected worker `ICompilerService` factory. See
|
|
50
72
|
* `createWorkerCompiler` for the public entry documentation.
|
|
73
|
+
*
|
|
74
|
+
* Runtime boot and source mounting have separate retry state. Requests
|
|
75
|
+
* serialize every mutation of the shared virtual project; configured transform
|
|
76
|
+
* or lint failures remain visible instead of yielding untransformed or clean
|
|
77
|
+
* results.
|
|
78
|
+
*
|
|
79
|
+
* @evidence contracts/common.md#principled-implementation A promise chain orders virtual-file mutations; transform envelopes are validated before writes, and compile and lint outcomes preserve producer failure semantics. Post-start boot rejection remains terminal because an existing Go runtime cannot be replaced inside its Worker.
|
|
80
|
+
* @evidence contracts/common.md#clear-and-simple-design Boot, mounting, project writes and result interpretation are local responsibilities behind one RPC factory; ESM and CommonJS lanes share the build pipeline.
|
|
81
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Retry is limited to pre-runtime boot or source mounting; failed configured plugins never silently fall through to successful untransformed emit or a clean lint list.
|
|
82
|
+
* @evidence contracts/common.md#meaningful-documentation Native paragraphs state serialization and retry boundaries; helper comments explain plugin-envelope failures and the runtime replacement reason under the documentation skill.
|
|
51
83
|
*/
|
|
52
84
|
export function createWorkerCompilerService(
|
|
53
85
|
deps: IWorkerCompilerDeps,
|
|
@@ -69,12 +101,23 @@ export function createWorkerCompilerService(
|
|
|
69
101
|
|
|
70
102
|
// tsconfig variants. ESM for the "Compiled JS" preview lane, CommonJS for
|
|
71
103
|
// the bundle/Execute lane (whose `new Function` driver expects CJS).
|
|
72
|
-
|
|
73
|
-
|
|
104
|
+
//
|
|
105
|
+
// The typia entry is appended after the site's own `plugins` entries, as the
|
|
106
|
+
// option documents, so enabling typia never discards a site-provided plugin.
|
|
107
|
+
const siteCompilerOptions = options.extraCompilerOptions ?? {};
|
|
108
|
+
const sitePlugins: unknown = siteCompilerOptions.plugins;
|
|
109
|
+
const extraPlugins: unknown[] = Array.isArray(sitePlugins)
|
|
110
|
+
? sitePlugins.filter(
|
|
111
|
+
(entry) =>
|
|
112
|
+
(entry as { transform?: unknown } | null)?.transform !==
|
|
113
|
+
typiaTransformModule,
|
|
114
|
+
)
|
|
74
115
|
: [];
|
|
75
116
|
const extraCompilerOptions = {
|
|
76
|
-
...
|
|
77
|
-
...(
|
|
117
|
+
...siteCompilerOptions,
|
|
118
|
+
...(typiaPlugin
|
|
119
|
+
? { plugins: [...extraPlugins, { transform: typiaTransformModule }] }
|
|
120
|
+
: {}),
|
|
78
121
|
};
|
|
79
122
|
const tsconfigESM = buildTsconfigJSON({
|
|
80
123
|
module: "ESNext",
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Join a relative path under a base directory, ignoring base when `rel` is
|
|
3
3
|
* absolute.
|
|
4
|
+
*
|
|
5
|
+
* @evidence contracts/common.md#principled-implementation Absolute virtual paths retain their meaning and relative paths receive the configured virtual base; this helper is not a confinement check.
|
|
6
|
+
* @evidence contracts/common.md#clear-and-simple-design A narrow virtual join keeps source mapping independent of host filesystem APIs.
|
|
7
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Absolute paths are a supported input form rather than a workaround for a particular package.
|
|
8
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose states absolute precedence, with tag separation following the documentation skill.
|
|
4
9
|
*/
|
|
5
10
|
export function joinUnder(base: string, rel: string): string {
|
|
6
11
|
if (rel.startsWith("/")) return rel;
|
|
@@ -15,6 +15,11 @@ const ANSI_REGEXP = /\x1b\[[0-9;]*m/g;
|
|
|
15
15
|
/**
|
|
16
16
|
* Parse the lint plugin's stderr (tsgo-style pretty diagnostics) into the
|
|
17
17
|
* playground's normalized diagnostic shape.
|
|
18
|
+
*
|
|
19
|
+
* @evidence contracts/common.md#principled-implementation The parser recognizes the supported pretty-diagnostic grammar after removing actual ANSI SGR escapes and carries its one-based line and column unchanged into UI records.
|
|
20
|
+
* @evidence contracts/common.md#clear-and-simple-design Matching and record construction stay in one pass; token-span inference remains a local helper rather than a second diagnostic protocol.
|
|
21
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Unknown lines are omitted as non-diagnostics; the owning pipeline separately reports plugin failure instead of treating every empty parse as success.
|
|
22
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose identifies producer format and normalization responsibility; nearby comments explain ANSI matching reasons under the documentation skill.
|
|
18
23
|
*/
|
|
19
24
|
export function parseLintDiagnostics(
|
|
20
25
|
stderr: string,
|
|
@@ -22,6 +27,7 @@ export function parseLintDiagnostics(
|
|
|
22
27
|
): ICompilerService.IDiagnostic[] {
|
|
23
28
|
const stripped = stderr.replace(ANSI_REGEXP, "");
|
|
24
29
|
const lines = stripped.split(/\r?\n/);
|
|
30
|
+
const sourceLines = source.split(/\r?\n/);
|
|
25
31
|
const out: ICompilerService.IDiagnostic[] = [];
|
|
26
32
|
for (const line of lines) {
|
|
27
33
|
const m = line.match(LINT_LINE_REGEXP);
|
|
@@ -33,7 +39,7 @@ export function parseLintDiagnostics(
|
|
|
33
39
|
out.push({
|
|
34
40
|
line: lineNum,
|
|
35
41
|
column: colNum,
|
|
36
|
-
length: lengthOfTokenAt(
|
|
42
|
+
length: lengthOfTokenAt(sourceLines, lineNum, colNum) ?? 1,
|
|
37
43
|
severity: sev === "warning" ? "warning" : "error",
|
|
38
44
|
message: rule ? `[${rule}] ${message ?? ""}` : (message ?? ""),
|
|
39
45
|
code: `TS${codeStr ?? ""}`,
|
|
@@ -47,11 +53,10 @@ export function parseLintDiagnostics(
|
|
|
47
53
|
* `column`) in `source`. Falls back to 1 when no token is found.
|
|
48
54
|
*/
|
|
49
55
|
function lengthOfTokenAt(
|
|
50
|
-
|
|
56
|
+
lines: readonly string[],
|
|
51
57
|
line: number,
|
|
52
58
|
column: number,
|
|
53
59
|
): number | null {
|
|
54
|
-
const lines = source.split(/\r?\n/);
|
|
55
60
|
if (line < 1 || line > lines.length) return null;
|
|
56
61
|
const text = lines[line - 1] ?? "";
|
|
57
62
|
const start = Math.max(0, column - 1);
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Typia transform stdout envelope; typescript maps virtual paths to source
|
|
3
|
+
* text.
|
|
4
|
+
*
|
|
5
|
+
* @evidence contracts/common.md#principled-implementation A string-valued source map expresses files the host can write; diagnostics are intentionally opaque because this lane does not consume them.
|
|
6
|
+
* @evidence contracts/common.md#clear-and-simple-design The narrow envelope separates transform payload decoding from compiler result parsing.
|
|
7
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The map models the registered transform protocol rather than guessed output for a particular source.
|
|
8
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose defines path and text meaning with tag separation under the documentation skill.
|
|
9
|
+
*/
|
|
2
10
|
export interface ITypiaTransformOutput {
|
|
3
11
|
diagnostics?: unknown;
|
|
4
12
|
typescript: Record<string, string>;
|
|
@@ -8,13 +16,28 @@ export interface ITypiaTransformOutput {
|
|
|
8
16
|
* Parse the typia transform plugin's stdout into the expected shape. Returns
|
|
9
17
|
* null on any parse / shape mismatch — the caller treats null as "transform
|
|
10
18
|
* produced no usable output".
|
|
19
|
+
*
|
|
20
|
+
* @evidence contracts/common.md#principled-implementation JSON decoding and a non-array object containing only string source values establish the host-write precondition; malformed payloads return null.
|
|
21
|
+
* @evidence contracts/common.md#clear-and-simple-design One decoder validates the source map before the service mutates MemFS.
|
|
22
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Rejected payloads remain failures instead of coercing unknown values into source text.
|
|
23
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose explains null's failure meaning and decoding boundary, separated from tags under the documentation skill.
|
|
11
24
|
*/
|
|
12
25
|
export function safeParseTypiaTransform(
|
|
13
26
|
text: string,
|
|
14
27
|
): ITypiaTransformOutput | null {
|
|
15
28
|
try {
|
|
16
29
|
const parsed = JSON.parse(text) as ITypiaTransformOutput;
|
|
17
|
-
if (
|
|
30
|
+
if (
|
|
31
|
+
parsed &&
|
|
32
|
+
typeof parsed === "object" &&
|
|
33
|
+
!Array.isArray(parsed) &&
|
|
34
|
+
parsed.typescript &&
|
|
35
|
+
typeof parsed.typescript === "object" &&
|
|
36
|
+
!Array.isArray(parsed.typescript) &&
|
|
37
|
+
Object.values(parsed.typescript).every(
|
|
38
|
+
(value) => typeof value === "string",
|
|
39
|
+
)
|
|
40
|
+
) {
|
|
18
41
|
return parsed;
|
|
19
42
|
}
|
|
20
43
|
return null;
|
|
@@ -1,14 +1,30 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Compute one-based line and column from a zero-based UTF-16 source offset.
|
|
3
|
+
* Missing or negative offsets point to the beginning; offsets past EOF clamp.
|
|
4
|
+
*
|
|
5
|
+
* @evidence contracts/common.md#principled-implementation ECMAScript line terminators advance the line, CRLF counts once, and columns count JavaScript UTF-16 units.
|
|
6
|
+
* @evidence contracts/common.md#clear-and-simple-design A stateless coordinate helper keeps source-location policy separate from diagnostic mapping and rendering.
|
|
7
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Beginning and EOF behavior are general coordinate defaults rather than source-specific exceptions.
|
|
8
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose states bases, units and boundary behavior, separated from tags under the documentation skill.
|
|
9
|
+
*/
|
|
2
10
|
export function lineColumnOf(
|
|
3
11
|
source: string,
|
|
4
12
|
start: number | undefined,
|
|
5
13
|
): { line: number; column: number } {
|
|
6
|
-
if (typeof start !== "number" || start < 0)
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
if (typeof start !== "number" || Number.isNaN(start) || start < 0)
|
|
15
|
+
return { line: 1, column: 1 };
|
|
16
|
+
const end = Math.min(Math.trunc(start), source.length);
|
|
17
|
+
let line = 1;
|
|
18
|
+
let lastNewline = -1;
|
|
19
|
+
for (let index = 0; index < end; ++index) {
|
|
20
|
+
const code = source.charCodeAt(index);
|
|
21
|
+
if (code === 13 || code === 10 || code === 0x2028 || code === 0x2029) {
|
|
22
|
+
if (code === 13 && source.charCodeAt(index + 1) === 10 && index + 1 < end)
|
|
23
|
+
++index;
|
|
24
|
+
++line;
|
|
25
|
+
lastNewline = index;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const column = end - lastNewline;
|
|
13
29
|
return { line, column };
|
|
14
30
|
}
|
|
@@ -15,33 +15,65 @@ interface SourcePackCancellation {
|
|
|
15
15
|
dispose: () => void;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const
|
|
18
|
+
const packCaches = new WeakMap<
|
|
19
|
+
NonNullable<IInstallTypiaSourcePackOptions["fetch"]>,
|
|
20
|
+
Map<string, SourcePackEntry>
|
|
21
|
+
>();
|
|
19
22
|
|
|
20
23
|
/**
|
|
21
|
-
* Fetch the typia source pack JSON once per URL.
|
|
24
|
+
* Fetch the typia source pack JSON once per URL and transport identity.
|
|
22
25
|
*
|
|
23
26
|
* Concurrent callers share one load. A caller abort cancels that shared
|
|
24
27
|
* attempt; rejection removes it from the cache so the next call retries from
|
|
25
28
|
* scratch. Nothing else ends the load: how long a fetch takes belongs to the
|
|
26
29
|
* network, not to a number chosen here.
|
|
30
|
+
*
|
|
31
|
+
* @evidence contracts/common.md#principled-implementation
|
|
32
|
+
* The source-pack loader uses fetch/AbortController and Promise sharing,
|
|
33
|
+
* with an explicit fetch injection seam for the same transport contract. It
|
|
34
|
+
* supplies source records to the existing mounting operation rather than
|
|
35
|
+
* coupling network loading to compiler execution.
|
|
36
|
+
*
|
|
37
|
+
* @evidence contracts/common.md#clear-and-simple-design
|
|
38
|
+
* One transport-specific URL map owns attempt sharing; cancellation helpers
|
|
39
|
+
* keep event ownership separate from response decoding and source mounting.
|
|
40
|
+
*
|
|
41
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts
|
|
42
|
+
* The site supplies the URL and transport; no package name, test case or
|
|
43
|
+
* fixed deadline decides success. The injected transport leaves global fetch
|
|
44
|
+
* intact. Rejection evicts only this attempt, preserving the real failure
|
|
45
|
+
* instead of inventing a successful empty source pack.
|
|
46
|
+
*
|
|
47
|
+
* @evidence contracts/common.md#meaningful-documentation
|
|
48
|
+
* JSDoc explains the once-per-URL purpose, shared cancellation, rejection
|
|
49
|
+
* eviction and why an arbitrary timeout is not the network policy. Purpose
|
|
50
|
+
* and reasons use separate native paragraphs under the documentation skill;
|
|
51
|
+
* IInstallTypiaSourcePackOptions owns option documentation.
|
|
27
52
|
*/
|
|
28
53
|
export function loadTypiaSourcePack(
|
|
29
54
|
options: IInstallTypiaSourcePackOptions,
|
|
30
55
|
): Promise<Record<string, string>> {
|
|
31
|
-
const
|
|
32
|
-
if (cached) {
|
|
33
|
-
attachSourcePackCancellation(cached, options.signal);
|
|
34
|
-
return cached.promise;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis);
|
|
56
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
38
57
|
if (!fetchImpl) {
|
|
39
58
|
throw new Error(
|
|
40
59
|
"loadTypiaSourcePack: no fetch implementation available in this environment.",
|
|
41
60
|
);
|
|
42
61
|
}
|
|
43
62
|
|
|
63
|
+
let packCache = packCaches.get(fetchImpl);
|
|
64
|
+
if (!packCache) {
|
|
65
|
+
packCache = new Map();
|
|
66
|
+
packCaches.set(fetchImpl, packCache);
|
|
67
|
+
}
|
|
68
|
+
const cache = packCache;
|
|
69
|
+
const cached = cache.get(options.url);
|
|
70
|
+
if (cached) {
|
|
71
|
+
attachSourcePackCancellation(cached, options.signal);
|
|
72
|
+
return cached.promise;
|
|
73
|
+
}
|
|
74
|
+
|
|
44
75
|
const url = options.url;
|
|
76
|
+
const fetchPack = options.fetch ? fetchImpl : fetchImpl.bind(globalThis);
|
|
45
77
|
const controller = new AbortController();
|
|
46
78
|
let phase = `fetching ${url}`;
|
|
47
79
|
const cancellation = createSourcePackCancellation(
|
|
@@ -51,7 +83,7 @@ export function loadTypiaSourcePack(
|
|
|
51
83
|
let entry!: SourcePackEntry;
|
|
52
84
|
const promise = (async () => {
|
|
53
85
|
const response = await raceSourcePackCancellation(
|
|
54
|
-
|
|
86
|
+
fetchPack(url, { signal: controller.signal }),
|
|
55
87
|
cancellation.promise,
|
|
56
88
|
controller.signal,
|
|
57
89
|
() => phase,
|
|
@@ -63,21 +95,32 @@ export function loadTypiaSourcePack(
|
|
|
63
95
|
}
|
|
64
96
|
|
|
65
97
|
phase = `reading JSON from ${url}`;
|
|
66
|
-
|
|
98
|
+
const pack: unknown = await raceSourcePackCancellation(
|
|
67
99
|
response.json(),
|
|
68
100
|
cancellation.promise,
|
|
69
101
|
controller.signal,
|
|
70
102
|
() => phase,
|
|
71
|
-
)
|
|
103
|
+
);
|
|
104
|
+
if (
|
|
105
|
+
!pack ||
|
|
106
|
+
typeof pack !== "object" ||
|
|
107
|
+
Array.isArray(pack) ||
|
|
108
|
+
!Object.values(pack).every((value) => typeof value === "string")
|
|
109
|
+
) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
"loadTypiaSourcePack: expected a source-text record map.",
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
return pack as Record<string, string>;
|
|
72
115
|
})()
|
|
73
116
|
.catch((error) => {
|
|
74
|
-
if (
|
|
117
|
+
if (cache.get(url) === entry) cache.delete(url);
|
|
75
118
|
throw error;
|
|
76
119
|
})
|
|
77
120
|
.finally(cancellation.dispose);
|
|
78
121
|
|
|
79
122
|
entry = { controller, promise };
|
|
80
|
-
|
|
123
|
+
cache.set(url, entry);
|
|
81
124
|
attachSourcePackCancellation(entry, options.signal);
|
|
82
125
|
return promise;
|
|
83
126
|
}
|
|
@@ -6,21 +6,81 @@ import { lineColumnOf } from "./lineColumnOf";
|
|
|
6
6
|
/**
|
|
7
7
|
* Convert a `@ttsc/wasm` diagnostic into the playground's normalized shape.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* Native positions and spans count UTF-8 bytes; the editor counts UTF-16 units.
|
|
10
|
+
* Source text converts that boundary, including optional coordinates.
|
|
11
|
+
*
|
|
12
|
+
* @evidence contracts/common.md#principled-implementation Native byte offsets and spans are converted against the same source into UTF-16 editor coordinates; optional line/byte-column metadata supplies the start only when the absolute offset is absent.
|
|
13
|
+
* @evidence contracts/common.md#clear-and-simple-design A single mapping keeps WASM diagnostic fields and UI conventions separate from rendering.
|
|
14
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Fallback is based on omitted producer metadata, not special casing a diagnostic code or source fixture.
|
|
15
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose explains producer-to-UI conversion and fallback purpose, following documentation-skill paragraph separation.
|
|
11
16
|
*/
|
|
12
17
|
export function mapDiagnostic(
|
|
13
18
|
diag: NonNullable<ITtscCompileResult["diagnostics"]>[number],
|
|
14
19
|
source: string,
|
|
15
20
|
): ICompilerService.IDiagnostic {
|
|
16
|
-
const
|
|
21
|
+
const start =
|
|
22
|
+
typeof diag.start === "number" &&
|
|
23
|
+
Number.isFinite(diag.start) &&
|
|
24
|
+
diag.start >= 0
|
|
25
|
+
? utf16OffsetOfBytes(source, diag.start)
|
|
26
|
+
: optionalStart(source, diag.line, diag.character);
|
|
27
|
+
const location = lineColumnOf(source, start);
|
|
28
|
+
const byteLength =
|
|
29
|
+
typeof diag.length === "number" && Number.isFinite(diag.length)
|
|
30
|
+
? Math.max(0, Math.trunc(diag.length))
|
|
31
|
+
: 0;
|
|
32
|
+
const end = utf16OffsetOfBytes(source, byteLength, start);
|
|
17
33
|
return {
|
|
18
|
-
line:
|
|
19
|
-
column:
|
|
20
|
-
|
|
21
|
-
length: typeof diag.length === "number" ? diag.length : 1,
|
|
34
|
+
line: location.line,
|
|
35
|
+
column: location.column,
|
|
36
|
+
length: Math.max(1, end - start),
|
|
22
37
|
severity: diag.category === "warning" ? "warning" : "error",
|
|
23
38
|
message: diag.messageText,
|
|
24
39
|
code: typeof diag.code === "number" ? `TS${diag.code}` : String(diag.code),
|
|
25
40
|
};
|
|
26
41
|
}
|
|
42
|
+
|
|
43
|
+
/** Convert a UTF-8 byte boundary to its JavaScript string offset. */
|
|
44
|
+
function utf16OffsetOfBytes(source: string, bytes: number, start = 0): number {
|
|
45
|
+
let offset = start;
|
|
46
|
+
let consumed = 0;
|
|
47
|
+
while (offset < source.length && consumed < bytes) {
|
|
48
|
+
const code = source.codePointAt(offset)!;
|
|
49
|
+
const width = code <= 0x7f ? 1 : code <= 0x7ff ? 2 : code <= 0xffff ? 3 : 4;
|
|
50
|
+
if (consumed + width > bytes) break;
|
|
51
|
+
consumed += width;
|
|
52
|
+
offset += code > 0xffff ? 2 : 1;
|
|
53
|
+
}
|
|
54
|
+
return offset;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Optional native line and byte-column metadata uses the same source domain. */
|
|
58
|
+
function optionalStart(
|
|
59
|
+
source: string,
|
|
60
|
+
line: number | undefined,
|
|
61
|
+
character: number | undefined,
|
|
62
|
+
): number {
|
|
63
|
+
let start = 0;
|
|
64
|
+
const targetLine =
|
|
65
|
+
typeof line === "number" && Number.isFinite(line)
|
|
66
|
+
? Math.max(1, Math.trunc(line))
|
|
67
|
+
: 1;
|
|
68
|
+
for (
|
|
69
|
+
let current = 1;
|
|
70
|
+
current < targetLine && start < source.length;
|
|
71
|
+
++current
|
|
72
|
+
) {
|
|
73
|
+
while (
|
|
74
|
+
start < source.length &&
|
|
75
|
+
![10, 13, 0x2028, 0x2029].includes(source.charCodeAt(start))
|
|
76
|
+
)
|
|
77
|
+
++start;
|
|
78
|
+
const code = source.charCodeAt(start++);
|
|
79
|
+
if (code === 13 && source.charCodeAt(start) === 10) ++start;
|
|
80
|
+
}
|
|
81
|
+
const column =
|
|
82
|
+
typeof character === "number" && Number.isFinite(character)
|
|
83
|
+
? Math.max(0, Math.trunc(character) - 1)
|
|
84
|
+
: 0;
|
|
85
|
+
return Math.min(source.length, utf16OffsetOfBytes(source, column, start));
|
|
86
|
+
}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Normalize native errors to enumerable fields for tgrid transport; preserve
|
|
3
|
+
* message-bearing records and stringify other thrown values.
|
|
4
|
+
*
|
|
5
|
+
* @evidence contracts/common.md#principled-implementation Explicit Error field copying preserves non-enumerable message and stack while carrying the terminal-runtime string code across RPC.
|
|
6
|
+
* @evidence contracts/common.md#clear-and-simple-design One normalization boundary leaves rendering and recovery classification to their consumers.
|
|
7
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The mapper carries actual errors without converting rejection into fabricated compiler success.
|
|
8
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose states copying and preservation policies, separated from tags under the documentation skill.
|
|
9
|
+
*/
|
|
2
10
|
export function normalizeError(error: unknown): unknown {
|
|
3
11
|
if (error instanceof Error) {
|
|
4
12
|
const normalized: {
|
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Returns `null` for paths that don't match the expected shape — the caller
|
|
6
6
|
* skips those entries instead of writing them to the MemFS.
|
|
7
|
+
*
|
|
8
|
+
* @evidence contracts/common.md#principled-implementation Separator normalization establishes the virtual namespace, prefix checking restricts writes to node_modules and rejecting parent segments prevents root escape.
|
|
9
|
+
* @evidence contracts/common.md#clear-and-simple-design One path gate returns a normalized key or null; callers own writes and rejection policy.
|
|
10
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The same structural checks apply to every package entry without allowlisting consumers.
|
|
11
|
+
* @evidence contracts/common.md#meaningful-documentation Native paragraphs explain accepted spelling, confinement and null meaning under the documentation skill.
|
|
7
12
|
*/
|
|
8
13
|
export function normalizeNodeModulePath(path: string): string | null {
|
|
9
14
|
const normalized = path.replace(/\\/g, "/").replace(/^\/+/, "");
|