sh-ast 0.0.0 → 0.1.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 +147 -0
- package/dist/analyze/ansi-c-escapes.d.ts +53 -0
- package/dist/analyze/ansi-c-escapes.d.ts.map +1 -0
- package/dist/analyze/ansi-c-escapes.js +255 -0
- package/dist/analyze/ansi-c-escapes.js.map +1 -0
- package/dist/analyze/decode-lit.d.ts +74 -0
- package/dist/analyze/decode-lit.d.ts.map +1 -0
- package/dist/analyze/decode-lit.js +114 -0
- package/dist/analyze/decode-lit.js.map +1 -0
- package/dist/analyze/enumerate-commands.d.ts +159 -0
- package/dist/analyze/enumerate-commands.d.ts.map +1 -0
- package/dist/analyze/enumerate-commands.js +390 -0
- package/dist/analyze/enumerate-commands.js.map +1 -0
- package/dist/analyze/index.d.ts +18 -0
- package/dist/analyze/index.d.ts.map +1 -0
- package/dist/analyze/index.js +27 -0
- package/dist/analyze/index.js.map +1 -0
- package/dist/analyze/node-helpers.d.ts +28 -0
- package/dist/analyze/node-helpers.d.ts.map +1 -0
- package/dist/analyze/node-helpers.js +37 -0
- package/dist/analyze/node-helpers.js.map +1 -0
- package/dist/analyze/resolve-word.d.ts +146 -0
- package/dist/analyze/resolve-word.d.ts.map +1 -0
- package/dist/analyze/resolve-word.js +202 -0
- package/dist/analyze/resolve-word.js.map +1 -0
- package/dist/analyze.d.ts +390 -0
- package/dist/deep-freeze.d.ts +14 -0
- package/dist/deep-freeze.d.ts.map +1 -0
- package/dist/deep-freeze.js +25 -0
- package/dist/deep-freeze.js.map +1 -0
- package/dist/errors.d.ts +115 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +106 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/normalize.d.ts +52 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +260 -0
- package/dist/normalize.js.map +1 -0
- package/dist/parse.d.ts +45 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +118 -0
- package/dist/parse.js.map +1 -0
- package/dist/sh-ast.d.ts +1270 -0
- package/dist/types.d.ts +70 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/visitor-keys.d.ts +21 -0
- package/dist/visitor-keys.d.ts.map +1 -0
- package/dist/visitor-keys.js +23 -0
- package/dist/visitor-keys.js.map +1 -0
- package/dist/walk.d.ts +18 -0
- package/dist/walk.d.ts.map +1 -0
- package/dist/walk.js +40 -0
- package/dist/walk.js.map +1 -0
- package/dist/wasm-instance.d.ts +13 -0
- package/dist/wasm-instance.d.ts.map +1 -0
- package/dist/wasm-instance.js +88 -0
- package/dist/wasm-instance.js.map +1 -0
- package/generated/child-type-schema.d.ts +14 -0
- package/generated/child-type-schema.js +188 -0
- package/generated/node-types.d.ts +958 -0
- package/generated/position-fields.d.ts +21 -0
- package/generated/position-fields.js +50 -0
- package/generated/visitor-keys.d.ts +11 -0
- package/generated/visitor-keys.js +50 -0
- package/package.json +93 -10
- package/shim/sh-ast.wasm +0 -0
- package/shim/wasm_exec.js +654 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell dialect (mvdan/sh `LangVariant`) to parse against. Mapped to
|
|
3
|
+
* `LangVariant` by string name via `LangVariant.Set()` — never by numeric
|
|
4
|
+
* value, since the bit-flag encoding of `LangVariant` is not a stable
|
|
5
|
+
* contract across mvdan/sh versions. See design/ARCHITECTURE.md, "Parse
|
|
6
|
+
* errors and dialects".
|
|
7
|
+
*
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export type ShellDialect = 'bash' | 'posix' | 'mksh' | 'bats' | 'zsh';
|
|
11
|
+
/**
|
|
12
|
+
* Options accepted by {@link parseSync}.
|
|
13
|
+
*
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
export interface ParseOptions {
|
|
17
|
+
/**
|
|
18
|
+
* The shell dialect to parse against.
|
|
19
|
+
* @defaultValue `"bash"`
|
|
20
|
+
*/
|
|
21
|
+
readonly dialect?: ShellDialect;
|
|
22
|
+
/**
|
|
23
|
+
* Filename used only to annotate error messages and positions; the source
|
|
24
|
+
* is never read from disk.
|
|
25
|
+
* @defaultValue `"input.sh"`
|
|
26
|
+
*/
|
|
27
|
+
readonly filename?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A 1-based line/column position. Columns are UTF-16 code units, matching
|
|
31
|
+
* JavaScript string indexing (see {@link ShNode.range}).
|
|
32
|
+
*
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
export interface Position {
|
|
36
|
+
readonly line: number;
|
|
37
|
+
readonly column: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A normalized AST node produced by {@link parseSync}.
|
|
41
|
+
*
|
|
42
|
+
* `range` and `loc` are expressed in UTF-16 code units, so
|
|
43
|
+
* `code.slice(node.range[0], node.range[1])` reproduces the node's exact
|
|
44
|
+
* source text — even though mvdan/sh itself reports byte offsets and
|
|
45
|
+
* byte-counting columns internally (see design/ARCHITECTURE.md's
|
|
46
|
+
* "Serialization contract"). Every other field copied over from mvdan/sh's
|
|
47
|
+
* typedjson tree keeps its original value but with the field name
|
|
48
|
+
* lowercased (`Stmts` becomes `stmts`, `CondLast` becomes `condlast`, etc.).
|
|
49
|
+
*
|
|
50
|
+
* @public
|
|
51
|
+
*/
|
|
52
|
+
export interface ShNode {
|
|
53
|
+
readonly type: string;
|
|
54
|
+
readonly range: readonly [number, number];
|
|
55
|
+
readonly loc: {
|
|
56
|
+
readonly start: Position;
|
|
57
|
+
readonly end: Position;
|
|
58
|
+
};
|
|
59
|
+
[field: string]: unknown;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The root node of a parsed shell script.
|
|
63
|
+
*
|
|
64
|
+
* @public
|
|
65
|
+
*/
|
|
66
|
+
export interface ShFile extends ShNode {
|
|
67
|
+
readonly type: 'File';
|
|
68
|
+
readonly stmts: readonly ShNode[];
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAEtE;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC;IAEhC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,QAAQ,CAAC,GAAG,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAA;KAAE,CAAC;IACnE,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,WAAW,MAAO,SAAQ,MAAM;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps each normalized node `type` to the field names (lowercased, matching
|
|
3
|
+
* the normalized node shape produced by `normalize`) whose values hold child
|
|
4
|
+
* nodes.
|
|
5
|
+
*
|
|
6
|
+
* Generated from mvdan/sh's `syntax` package struct definitions by
|
|
7
|
+
* `tools/gen-visitor-keys` (see design/ARCHITECTURE.md, "The schema table is
|
|
8
|
+
* generated, not hand-written") — this module only re-exports the generated
|
|
9
|
+
* table under the public name, frozen. {@link walk} does not depend on this
|
|
10
|
+
* table for correctness — it discovers children structurally — so any gap
|
|
11
|
+
* here (there shouldn't be one; the kitchen-sink golden test guards it)
|
|
12
|
+
* affects only external consumers that choose to traverse via this table.
|
|
13
|
+
*
|
|
14
|
+
* Frozen (including each per-type field-name array) so immutability of this
|
|
15
|
+
* shared, module-scoped table is a contract, not just a convention any
|
|
16
|
+
* importer happens to honor.
|
|
17
|
+
*
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
export declare const visitorKeys: Readonly<Record<string, readonly string[]>>;
|
|
21
|
+
//# sourceMappingURL=visitor-keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visitor-keys.d.ts","sourceRoot":"","sources":["../src/visitor-keys.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAClC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { deepFreeze } from './deep-freeze.js';
|
|
2
|
+
import { visitorKeys as generatedVisitorKeys } from '../generated/visitor-keys.js';
|
|
3
|
+
/**
|
|
4
|
+
* Maps each normalized node `type` to the field names (lowercased, matching
|
|
5
|
+
* the normalized node shape produced by `normalize`) whose values hold child
|
|
6
|
+
* nodes.
|
|
7
|
+
*
|
|
8
|
+
* Generated from mvdan/sh's `syntax` package struct definitions by
|
|
9
|
+
* `tools/gen-visitor-keys` (see design/ARCHITECTURE.md, "The schema table is
|
|
10
|
+
* generated, not hand-written") — this module only re-exports the generated
|
|
11
|
+
* table under the public name, frozen. {@link walk} does not depend on this
|
|
12
|
+
* table for correctness — it discovers children structurally — so any gap
|
|
13
|
+
* here (there shouldn't be one; the kitchen-sink golden test guards it)
|
|
14
|
+
* affects only external consumers that choose to traverse via this table.
|
|
15
|
+
*
|
|
16
|
+
* Frozen (including each per-type field-name array) so immutability of this
|
|
17
|
+
* shared, module-scoped table is a contract, not just a convention any
|
|
18
|
+
* importer happens to honor.
|
|
19
|
+
*
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
export const visitorKeys = deepFreeze(generatedVisitorKeys);
|
|
23
|
+
//# sourceMappingURL=visitor-keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visitor-keys.js","sourceRoot":"","sources":["../src/visitor-keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,WAAW,IAAI,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAEnF;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,WAAW,GACtB,UAAU,CAAC,oBAAoB,CAAC,CAAC"}
|
package/dist/walk.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ShNode } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Visits every node in a normalized tree, pre-order (parent before
|
|
4
|
+
* children), starting at `node`.
|
|
5
|
+
*
|
|
6
|
+
* Children are discovered structurally: any field on a visited node whose
|
|
7
|
+
* value is itself a normalized node (or an array of normalized nodes) is
|
|
8
|
+
* treated as a child. This is deliberately not driven off {@link
|
|
9
|
+
* visitorKeys} — the spike's hand-written visitor-keys table missed
|
|
10
|
+
* `DeclClause.Variant` (see design/ARCHITECTURE.md) and silently
|
|
11
|
+
* under-walked the tree, and `visitorKeys` remains hand-maintained pending a
|
|
12
|
+
* schema generator (tracked separately). Walking structurally means this
|
|
13
|
+
* function's completeness never depends on that table's accuracy.
|
|
14
|
+
*
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export declare function walk(node: ShNode, visit: (node: ShNode, parent: ShNode | null) => void): void;
|
|
18
|
+
//# sourceMappingURL=walk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walk.d.ts","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AA6BzC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAE7F"}
|
package/dist/walk.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
function isShNode(value) {
|
|
2
|
+
return (typeof value === 'object' &&
|
|
3
|
+
value !== null &&
|
|
4
|
+
!Array.isArray(value) &&
|
|
5
|
+
typeof value.type === 'string' &&
|
|
6
|
+
Array.isArray(value.range));
|
|
7
|
+
}
|
|
8
|
+
function walkNode(node, parent, visit) {
|
|
9
|
+
visit(node, parent);
|
|
10
|
+
for (const value of Object.values(node)) {
|
|
11
|
+
if (isShNode(value)) {
|
|
12
|
+
walkNode(value, node, visit);
|
|
13
|
+
}
|
|
14
|
+
else if (Array.isArray(value)) {
|
|
15
|
+
for (const item of value) {
|
|
16
|
+
if (isShNode(item))
|
|
17
|
+
walkNode(item, node, visit);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Visits every node in a normalized tree, pre-order (parent before
|
|
24
|
+
* children), starting at `node`.
|
|
25
|
+
*
|
|
26
|
+
* Children are discovered structurally: any field on a visited node whose
|
|
27
|
+
* value is itself a normalized node (or an array of normalized nodes) is
|
|
28
|
+
* treated as a child. This is deliberately not driven off {@link
|
|
29
|
+
* visitorKeys} — the spike's hand-written visitor-keys table missed
|
|
30
|
+
* `DeclClause.Variant` (see design/ARCHITECTURE.md) and silently
|
|
31
|
+
* under-walked the tree, and `visitorKeys` remains hand-maintained pending a
|
|
32
|
+
* schema generator (tracked separately). Walking structurally means this
|
|
33
|
+
* function's completeness never depends on that table's accuracy.
|
|
34
|
+
*
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
export function walk(node, visit) {
|
|
38
|
+
walkNode(node, null, visit);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=walk.js.map
|
package/dist/walk.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walk.js","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"AAEA,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACrB,OAAQ,KAA4B,CAAC,IAAI,KAAK,QAAQ;QACtD,KAAK,CAAC,OAAO,CAAE,KAA6B,CAAC,KAAK,CAAC,CACpD,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CACf,IAAY,EACZ,MAAqB,EACrB,KAAoD;IAEpD,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACpB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACpB,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAChC,KAAK,MAAM,IAAI,IAAI,KAAkB,EAAE,CAAC;gBACtC,IAAI,QAAQ,CAAC,IAAI,CAAC;oBAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,IAAI,CAAC,IAAY,EAAE,KAAoD;IACrF,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import '../shim/wasm_exec.js';
|
|
2
|
+
/**
|
|
3
|
+
* Calls into the WASM shim's `process` export, instantiating the shim on
|
|
4
|
+
* first use. Encodes `text`/`dialect`/`filename` into shim-owned linear
|
|
5
|
+
* memory, reads the NUL-terminated JSON result back via `TextDecoder`
|
|
6
|
+
* (rather than syscall/js's `js.ValueOf(string)`, which dominated the parse
|
|
7
|
+
* cost — see design/ARCHITECTURE.md's "Performance"), and frees every buffer
|
|
8
|
+
* the call allocated.
|
|
9
|
+
*
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export declare function callParse(text: string, dialect: string, filename: string): string;
|
|
13
|
+
//# sourceMappingURL=wasm-instance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wasm-instance.d.ts","sourceRoot":"","sources":["../src/wasm-instance.ts"],"names":[],"mappings":"AAGA,OAAO,sBAAsB,CAAC;AA2F9B;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAuBjF"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import '../shim/wasm_exec.js';
|
|
5
|
+
import { ShBridgeInternalError } from './errors.js';
|
|
6
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
// `shim/` is a sibling of both `src/` (test-time) and `dist/` (build-time).
|
|
8
|
+
const wasmPath = path.join(here, '..', 'shim', 'sh-ast.wasm');
|
|
9
|
+
function isShimExports(value) {
|
|
10
|
+
const candidate = value;
|
|
11
|
+
return (candidate.mem instanceof WebAssembly.Memory &&
|
|
12
|
+
typeof candidate.alloc === 'function' &&
|
|
13
|
+
typeof candidate.free === 'function' &&
|
|
14
|
+
typeof candidate.process === 'function');
|
|
15
|
+
}
|
|
16
|
+
let wasmModule;
|
|
17
|
+
let shimExports;
|
|
18
|
+
/**
|
|
19
|
+
* Instantiates the WASM shim synchronously in Node, exactly once, and
|
|
20
|
+
* reuses the instance across parses (see design/ARCHITECTURE.md,
|
|
21
|
+
* "Synchronous parse: solved, two mechanisms"). Node imposes no size limit
|
|
22
|
+
* on synchronous `WebAssembly.Module` compilation — that restriction is
|
|
23
|
+
* browser-main-thread-only.
|
|
24
|
+
*/
|
|
25
|
+
function ensureInstance() {
|
|
26
|
+
if (shimExports)
|
|
27
|
+
return shimExports;
|
|
28
|
+
wasmModule ??= new WebAssembly.Module(fs.readFileSync(wasmPath));
|
|
29
|
+
const go = new Go();
|
|
30
|
+
const instance = new WebAssembly.Instance(wasmModule, go.importObject);
|
|
31
|
+
void go.run(instance);
|
|
32
|
+
if (!isShimExports(instance.exports)) {
|
|
33
|
+
throw new ShBridgeInternalError('bridge: WASM shim did not export the expected alloc/process/free/mem linear-memory ABI');
|
|
34
|
+
}
|
|
35
|
+
shimExports = instance.exports;
|
|
36
|
+
return shimExports;
|
|
37
|
+
}
|
|
38
|
+
const encoder = new TextEncoder();
|
|
39
|
+
const decoder = new TextDecoder();
|
|
40
|
+
/**
|
|
41
|
+
* Writes `text` (UTF-8 encoded) into a freshly `alloc`ed buffer and returns
|
|
42
|
+
* its (pointer, length). The caller owns the buffer and must `free` it once
|
|
43
|
+
* `process` has consumed it.
|
|
44
|
+
*/
|
|
45
|
+
function writeString(exports, text) {
|
|
46
|
+
const bytes = encoder.encode(text);
|
|
47
|
+
const ptr = exports.alloc(bytes.length);
|
|
48
|
+
// `exports.mem.buffer` is re-read here rather than cached across calls:
|
|
49
|
+
// a Go-side allocation can grow WASM linear memory, which detaches any
|
|
50
|
+
// previously created `ArrayBuffer` view (see `callParse` below for the
|
|
51
|
+
// same reasoning on the read side).
|
|
52
|
+
new Uint8Array(exports.mem.buffer, ptr, bytes.length).set(bytes);
|
|
53
|
+
return { ptr, len: bytes.length };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Calls into the WASM shim's `process` export, instantiating the shim on
|
|
57
|
+
* first use. Encodes `text`/`dialect`/`filename` into shim-owned linear
|
|
58
|
+
* memory, reads the NUL-terminated JSON result back via `TextDecoder`
|
|
59
|
+
* (rather than syscall/js's `js.ValueOf(string)`, which dominated the parse
|
|
60
|
+
* cost — see design/ARCHITECTURE.md's "Performance"), and frees every buffer
|
|
61
|
+
* the call allocated.
|
|
62
|
+
*
|
|
63
|
+
* @internal
|
|
64
|
+
*/
|
|
65
|
+
export function callParse(text, dialect, filename) {
|
|
66
|
+
const exports = ensureInstance();
|
|
67
|
+
const t = writeString(exports, text);
|
|
68
|
+
const d = writeString(exports, dialect);
|
|
69
|
+
const f = writeString(exports, filename);
|
|
70
|
+
const resultPtr = exports.process(t.ptr, t.len, d.ptr, d.len, f.ptr, f.len);
|
|
71
|
+
exports.free(t.ptr);
|
|
72
|
+
exports.free(d.ptr);
|
|
73
|
+
exports.free(f.ptr);
|
|
74
|
+
if (resultPtr === 0) {
|
|
75
|
+
throw new ShBridgeInternalError('bridge: WASM shim returned a null result pointer');
|
|
76
|
+
}
|
|
77
|
+
// Re-read `mem.buffer` fresh (see `writeString`'s comment) and scan for the
|
|
78
|
+
// shim's NUL sentinel — valid JSON from Go's encoding/json never contains
|
|
79
|
+
// a raw 0x00 byte, since every control character is \u-escaped.
|
|
80
|
+
const memory = new Uint8Array(exports.mem.buffer);
|
|
81
|
+
let end = resultPtr;
|
|
82
|
+
while (memory[end] !== 0)
|
|
83
|
+
end++;
|
|
84
|
+
const json = decoder.decode(memory.subarray(resultPtr, end));
|
|
85
|
+
exports.free(resultPtr);
|
|
86
|
+
return json;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=wasm-instance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wasm-instance.js","sourceRoot":"","sources":["../src/wasm-instance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Code generated by tools/gen-visitor-keys from mvdan.cc/sh/v3 v3.13.1. DO NOT EDIT.
|
|
2
|
+
// See design/ARCHITECTURE.md, "The schema table is generated, not hand-written".
|
|
3
|
+
/**
|
|
4
|
+
* `(parentType, fieldName) -> childType` for node fields whose static Go
|
|
5
|
+
* type is a concrete struct rather than an interface — typedjson only
|
|
6
|
+
* emits a "Type" discriminator for interface-typed fields, so these need
|
|
7
|
+
* the child type injected during normalization. A `null` value means the
|
|
8
|
+
* field's static type is a Node-derived interface (already
|
|
9
|
+
* self-discriminating). See design/ARCHITECTURE.md, "The schema table is
|
|
10
|
+
* generated, not hand-written".
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export declare const CHILD_TYPE_SCHEMA: Record<string, Record<string, string | null>>;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// Code generated by tools/gen-visitor-keys from mvdan.cc/sh/v3 v3.13.1. DO NOT EDIT.
|
|
2
|
+
// See design/ARCHITECTURE.md, "The schema table is generated, not hand-written".
|
|
3
|
+
export const CHILD_TYPE_SCHEMA = {
|
|
4
|
+
ArithmCmd: {
|
|
5
|
+
X: null,
|
|
6
|
+
},
|
|
7
|
+
ArithmExp: {
|
|
8
|
+
X: null,
|
|
9
|
+
},
|
|
10
|
+
ArrayElem: {
|
|
11
|
+
Comments: 'Comment',
|
|
12
|
+
Index: null,
|
|
13
|
+
Value: 'Word',
|
|
14
|
+
},
|
|
15
|
+
ArrayExpr: {
|
|
16
|
+
Elems: 'ArrayElem',
|
|
17
|
+
Last: 'Comment',
|
|
18
|
+
},
|
|
19
|
+
Assign: {
|
|
20
|
+
Array: 'ArrayExpr',
|
|
21
|
+
Index: null,
|
|
22
|
+
Name: 'Lit',
|
|
23
|
+
Value: 'Word',
|
|
24
|
+
},
|
|
25
|
+
BinaryArithm: {
|
|
26
|
+
X: null,
|
|
27
|
+
Y: null,
|
|
28
|
+
},
|
|
29
|
+
BinaryCmd: {
|
|
30
|
+
X: 'Stmt',
|
|
31
|
+
Y: 'Stmt',
|
|
32
|
+
},
|
|
33
|
+
BinaryTest: {
|
|
34
|
+
X: null,
|
|
35
|
+
Y: null,
|
|
36
|
+
},
|
|
37
|
+
Block: {
|
|
38
|
+
Last: 'Comment',
|
|
39
|
+
Stmts: 'Stmt',
|
|
40
|
+
},
|
|
41
|
+
BraceExp: {
|
|
42
|
+
Elems: 'Word',
|
|
43
|
+
},
|
|
44
|
+
CStyleLoop: {
|
|
45
|
+
Cond: null,
|
|
46
|
+
Init: null,
|
|
47
|
+
Post: null,
|
|
48
|
+
},
|
|
49
|
+
CallExpr: {
|
|
50
|
+
Args: 'Word',
|
|
51
|
+
Assigns: 'Assign',
|
|
52
|
+
},
|
|
53
|
+
CaseClause: {
|
|
54
|
+
Items: 'CaseItem',
|
|
55
|
+
Last: 'Comment',
|
|
56
|
+
Word: 'Word',
|
|
57
|
+
},
|
|
58
|
+
CaseItem: {
|
|
59
|
+
Comments: 'Comment',
|
|
60
|
+
Last: 'Comment',
|
|
61
|
+
Patterns: 'Word',
|
|
62
|
+
Stmts: 'Stmt',
|
|
63
|
+
},
|
|
64
|
+
CmdSubst: {
|
|
65
|
+
Last: 'Comment',
|
|
66
|
+
Stmts: 'Stmt',
|
|
67
|
+
},
|
|
68
|
+
Comment: {},
|
|
69
|
+
CoprocClause: {
|
|
70
|
+
Name: 'Word',
|
|
71
|
+
Stmt: 'Stmt',
|
|
72
|
+
},
|
|
73
|
+
DblQuoted: {
|
|
74
|
+
Parts: null,
|
|
75
|
+
},
|
|
76
|
+
DeclClause: {
|
|
77
|
+
Args: 'Assign',
|
|
78
|
+
Variant: 'Lit',
|
|
79
|
+
},
|
|
80
|
+
Expansion: {
|
|
81
|
+
Word: 'Word',
|
|
82
|
+
},
|
|
83
|
+
ExtGlob: {
|
|
84
|
+
Pattern: 'Lit',
|
|
85
|
+
},
|
|
86
|
+
File: {
|
|
87
|
+
Last: 'Comment',
|
|
88
|
+
Stmts: 'Stmt',
|
|
89
|
+
},
|
|
90
|
+
FlagsArithm: {
|
|
91
|
+
Flags: 'Lit',
|
|
92
|
+
X: null,
|
|
93
|
+
},
|
|
94
|
+
ForClause: {
|
|
95
|
+
Do: 'Stmt',
|
|
96
|
+
DoLast: 'Comment',
|
|
97
|
+
Loop: null,
|
|
98
|
+
},
|
|
99
|
+
FuncDecl: {
|
|
100
|
+
Body: 'Stmt',
|
|
101
|
+
Name: 'Lit',
|
|
102
|
+
Names: 'Lit',
|
|
103
|
+
},
|
|
104
|
+
IfClause: {
|
|
105
|
+
Cond: 'Stmt',
|
|
106
|
+
CondLast: 'Comment',
|
|
107
|
+
Else: 'IfClause',
|
|
108
|
+
Last: 'Comment',
|
|
109
|
+
Then: 'Stmt',
|
|
110
|
+
ThenLast: 'Comment',
|
|
111
|
+
},
|
|
112
|
+
LetClause: {
|
|
113
|
+
Exprs: null,
|
|
114
|
+
},
|
|
115
|
+
Lit: {},
|
|
116
|
+
ParamExp: {
|
|
117
|
+
Exp: 'Expansion',
|
|
118
|
+
Flags: 'Lit',
|
|
119
|
+
Index: null,
|
|
120
|
+
Modifiers: 'Lit',
|
|
121
|
+
NestedParam: null,
|
|
122
|
+
Param: 'Lit',
|
|
123
|
+
Repl: 'Replace',
|
|
124
|
+
Slice: 'Slice',
|
|
125
|
+
},
|
|
126
|
+
ParenArithm: {
|
|
127
|
+
X: null,
|
|
128
|
+
},
|
|
129
|
+
ParenTest: {
|
|
130
|
+
X: null,
|
|
131
|
+
},
|
|
132
|
+
ProcSubst: {
|
|
133
|
+
Last: 'Comment',
|
|
134
|
+
Stmts: 'Stmt',
|
|
135
|
+
},
|
|
136
|
+
Redirect: {
|
|
137
|
+
Hdoc: 'Word',
|
|
138
|
+
N: 'Lit',
|
|
139
|
+
Word: 'Word',
|
|
140
|
+
},
|
|
141
|
+
Replace: {
|
|
142
|
+
Orig: 'Word',
|
|
143
|
+
With: 'Word',
|
|
144
|
+
},
|
|
145
|
+
SglQuoted: {},
|
|
146
|
+
Slice: {
|
|
147
|
+
Length: null,
|
|
148
|
+
Offset: null,
|
|
149
|
+
},
|
|
150
|
+
Stmt: {
|
|
151
|
+
Cmd: null,
|
|
152
|
+
Comments: 'Comment',
|
|
153
|
+
Redirs: 'Redirect',
|
|
154
|
+
},
|
|
155
|
+
Subshell: {
|
|
156
|
+
Last: 'Comment',
|
|
157
|
+
Stmts: 'Stmt',
|
|
158
|
+
},
|
|
159
|
+
TestClause: {
|
|
160
|
+
X: null,
|
|
161
|
+
},
|
|
162
|
+
TestDecl: {
|
|
163
|
+
Body: 'Stmt',
|
|
164
|
+
Description: 'Word',
|
|
165
|
+
},
|
|
166
|
+
TimeClause: {
|
|
167
|
+
Stmt: 'Stmt',
|
|
168
|
+
},
|
|
169
|
+
UnaryArithm: {
|
|
170
|
+
X: null,
|
|
171
|
+
},
|
|
172
|
+
UnaryTest: {
|
|
173
|
+
X: null,
|
|
174
|
+
},
|
|
175
|
+
WhileClause: {
|
|
176
|
+
Cond: 'Stmt',
|
|
177
|
+
CondLast: 'Comment',
|
|
178
|
+
Do: 'Stmt',
|
|
179
|
+
DoLast: 'Comment',
|
|
180
|
+
},
|
|
181
|
+
Word: {
|
|
182
|
+
Parts: null,
|
|
183
|
+
},
|
|
184
|
+
WordIter: {
|
|
185
|
+
Items: 'Word',
|
|
186
|
+
Name: 'Lit',
|
|
187
|
+
},
|
|
188
|
+
};
|