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.
Files changed (73) hide show
  1. package/README.md +147 -0
  2. package/dist/analyze/ansi-c-escapes.d.ts +53 -0
  3. package/dist/analyze/ansi-c-escapes.d.ts.map +1 -0
  4. package/dist/analyze/ansi-c-escapes.js +255 -0
  5. package/dist/analyze/ansi-c-escapes.js.map +1 -0
  6. package/dist/analyze/decode-lit.d.ts +74 -0
  7. package/dist/analyze/decode-lit.d.ts.map +1 -0
  8. package/dist/analyze/decode-lit.js +114 -0
  9. package/dist/analyze/decode-lit.js.map +1 -0
  10. package/dist/analyze/enumerate-commands.d.ts +159 -0
  11. package/dist/analyze/enumerate-commands.d.ts.map +1 -0
  12. package/dist/analyze/enumerate-commands.js +390 -0
  13. package/dist/analyze/enumerate-commands.js.map +1 -0
  14. package/dist/analyze/index.d.ts +18 -0
  15. package/dist/analyze/index.d.ts.map +1 -0
  16. package/dist/analyze/index.js +27 -0
  17. package/dist/analyze/index.js.map +1 -0
  18. package/dist/analyze/node-helpers.d.ts +28 -0
  19. package/dist/analyze/node-helpers.d.ts.map +1 -0
  20. package/dist/analyze/node-helpers.js +37 -0
  21. package/dist/analyze/node-helpers.js.map +1 -0
  22. package/dist/analyze/resolve-word.d.ts +146 -0
  23. package/dist/analyze/resolve-word.d.ts.map +1 -0
  24. package/dist/analyze/resolve-word.js +202 -0
  25. package/dist/analyze/resolve-word.js.map +1 -0
  26. package/dist/analyze.d.ts +390 -0
  27. package/dist/deep-freeze.d.ts +14 -0
  28. package/dist/deep-freeze.d.ts.map +1 -0
  29. package/dist/deep-freeze.js +25 -0
  30. package/dist/deep-freeze.js.map +1 -0
  31. package/dist/errors.d.ts +115 -0
  32. package/dist/errors.d.ts.map +1 -0
  33. package/dist/errors.js +106 -0
  34. package/dist/errors.js.map +1 -0
  35. package/dist/index.d.ts +18 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +5 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/normalize.d.ts +52 -0
  40. package/dist/normalize.d.ts.map +1 -0
  41. package/dist/normalize.js +260 -0
  42. package/dist/normalize.js.map +1 -0
  43. package/dist/parse.d.ts +45 -0
  44. package/dist/parse.d.ts.map +1 -0
  45. package/dist/parse.js +118 -0
  46. package/dist/parse.js.map +1 -0
  47. package/dist/sh-ast.d.ts +1270 -0
  48. package/dist/types.d.ts +70 -0
  49. package/dist/types.d.ts.map +1 -0
  50. package/dist/types.js +2 -0
  51. package/dist/types.js.map +1 -0
  52. package/dist/visitor-keys.d.ts +21 -0
  53. package/dist/visitor-keys.d.ts.map +1 -0
  54. package/dist/visitor-keys.js +23 -0
  55. package/dist/visitor-keys.js.map +1 -0
  56. package/dist/walk.d.ts +18 -0
  57. package/dist/walk.d.ts.map +1 -0
  58. package/dist/walk.js +40 -0
  59. package/dist/walk.js.map +1 -0
  60. package/dist/wasm-instance.d.ts +13 -0
  61. package/dist/wasm-instance.d.ts.map +1 -0
  62. package/dist/wasm-instance.js +88 -0
  63. package/dist/wasm-instance.js.map +1 -0
  64. package/generated/child-type-schema.d.ts +14 -0
  65. package/generated/child-type-schema.js +188 -0
  66. package/generated/node-types.d.ts +958 -0
  67. package/generated/position-fields.d.ts +21 -0
  68. package/generated/position-fields.js +50 -0
  69. package/generated/visitor-keys.d.ts +11 -0
  70. package/generated/visitor-keys.js +50 -0
  71. package/package.json +93 -10
  72. package/shim/sh-ast.wasm +0 -0
  73. package/shim/wasm_exec.js +654 -0
@@ -0,0 +1,18 @@
1
+ export { parseSync } from './parse.js';
2
+ export { ShAnalyzeMaxDepthError, ShBridgeError, ShBridgeInternalError, ShInvalidDialectError, ShParseError, } from './errors.js';
3
+ export type { ShParseErrorInfo } from './errors.js';
4
+ export type { ParseOptions, Position, ShellDialect, ShFile, ShNode } from './types.js';
5
+ export { visitorKeys } from './visitor-keys.js';
6
+ export { walk } from './walk.js';
7
+ /**
8
+ * Strongly-typed `ShNode` subtypes for every mvdan/sh node type — generated
9
+ * by `tools/gen-visitor-keys` alongside {@link visitorKeys} (see
10
+ * design/ARCHITECTURE.md, "The schema table is generated, not
11
+ * hand-written"). {@link ShNode}'s index signature remains the base
12
+ * contract; these are an additive, opt-in stronger typing for consumers
13
+ * that want e.g. `ShNodes.ShCallExprNode` instead of a generic `ShNode`.
14
+ *
15
+ * @public
16
+ */
17
+ export type * as ShNodes from '../generated/node-types.js';
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EACL,sBAAsB,EACtB,aAAa,EACb,qBAAqB,EACrB,qBAAqB,EACrB,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;;;;;GASG;AACH,YAAY,KAAK,OAAO,MAAM,4BAA4B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { parseSync } from './parse.js';
2
+ export { ShAnalyzeMaxDepthError, ShBridgeError, ShBridgeInternalError, ShInvalidDialectError, ShParseError, } from './errors.js';
3
+ export { visitorKeys } from './visitor-keys.js';
4
+ export { walk } from './walk.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EACL,sBAAsB,EACtB,aAAa,EACb,qBAAqB,EACrB,qBAAqB,EACrB,YAAY,GACb,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,52 @@
1
+ import type { ShNode } from './types.js';
2
+ /**
3
+ * A JSON value as produced by `JSON.parse`.
4
+ *
5
+ * @internal
6
+ */
7
+ export type JsonValue = string | number | boolean | null | JsonValue[] | {
8
+ [key: string]: JsonValue;
9
+ };
10
+ /**
11
+ * Builds a byte-offset -> UTF-16-index lookup for `text`. mvdan/sh reports
12
+ * byte offsets; ESLint (and JavaScript strings generally) index by UTF-16
13
+ * code unit, so every position needs this conversion. Throws if asked to
14
+ * convert an offset that does not fall on a UTF-8 code-point boundary — an
15
+ * invariant every offset the parser emits must satisfy (see
16
+ * design/ARCHITECTURE.md's "Serialization contract").
17
+ *
18
+ * @internal
19
+ */
20
+ export declare function makeByteToUtf16(text: string): (byteOffset: number) => number;
21
+ /**
22
+ * Converts a byte offset and the 1-based line mvdan/sh already computed for
23
+ * it into a 1-based, UTF-16-code-unit column — the same conversion
24
+ * `normalize` applies to every node's `loc.start`/`loc.end` below, extracted
25
+ * so a parse error's reported position (see `errors.ts`'s
26
+ * `ShParseErrorInfo`) can use the identical algorithm instead of the raw
27
+ * byte-counting column mvdan/sh itself reports. See design/ARCHITECTURE.md's
28
+ * "Byte→UTF-16 conversion".
29
+ *
30
+ * @internal
31
+ */
32
+ export declare function toUtf16Column(text: string, byteOffset: number, line: number): number;
33
+ /**
34
+ * Normalizes mvdan/sh's typedjson tree into the shape ESLint expects: every
35
+ * node gets `type`, `range` (UTF-16), `loc` (1-based, UTF-16 columns), and
36
+ * every other field copied over with its name lowercased. See
37
+ * design/ARCHITECTURE.md's "Normalized node shape".
38
+ *
39
+ * Three of mvdan/sh's struct types — `Slice`, `Replace`, `Expansion`, all
40
+ * reachable only via `ParamExp.Slice`/`.Repl`/`.Exp` — do not implement
41
+ * `syntax.Node` (no `Pos()`/`End()`), so typedjson never gives them a `Pos`/
42
+ * `End` pair, let alone a `Type` discriminator. They still hold real child
43
+ * nodes (`Slice.Offset`/`.Length`, `Replace.Orig`/`.With`,
44
+ * `Expansion.Word`), so dropping them would silently lose that subtree (see
45
+ * issue #13 — `${USER:-nobody}`'s `nobody` literal). This function
46
+ * synthesizes a `type`/`range`/`loc` for these from their own children's
47
+ * already-computed positions instead, via `walkSynthetic` below.
48
+ *
49
+ * @internal
50
+ */
51
+ export declare function normalize(root: JsonValue, text: string): ShNode;
52
+ //# sourceMappingURL=normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAY,MAAM,EAAE,MAAM,YAAY,CAAC;AAkBnD;;;;GAIG;AACH,MAAM,MAAM,SAAS,GACnB,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAoEhF;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAsB5E;AAkBD;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAIpF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAsI/D"}
@@ -0,0 +1,260 @@
1
+ import { deepFreeze } from './deep-freeze.js';
2
+ import { CHILD_TYPE_SCHEMA } from '../generated/child-type-schema.js';
3
+ import { POSITION_FIELDS } from '../generated/position-fields.js';
4
+ /**
5
+ * Frozen (including each per-type field record) so immutability of this
6
+ * shared, module-scoped table is a contract, not just a convention any
7
+ * importer happens to honor — mirrors {@link visitorKeys}'s freezing in
8
+ * `visitor-keys.ts`.
9
+ */
10
+ const FROZEN_CHILD_TYPE_SCHEMA = deepFreeze(CHILD_TYPE_SCHEMA);
11
+ /**
12
+ * Frozen (including each per-type field-name array), same rationale as
13
+ * {@link FROZEN_CHILD_TYPE_SCHEMA} above.
14
+ */
15
+ const FROZEN_POSITION_FIELDS = deepFreeze(POSITION_FIELDS);
16
+ /**
17
+ * `Pos`/`End` are synthesized top-level keys every raw node carries (see
18
+ * `shim/internal/nodeencode/encode.go`'s `posField`/`endField`) — never a
19
+ * literal Go struct field, so they're checked directly rather than through
20
+ * {@link FROZEN_POSITION_FIELDS} (which is keyed by node *type*, and these
21
+ * two keys are universal, not type-specific).
22
+ */
23
+ const UNIVERSAL_POSITION_KEYS = new Set(['Pos', 'End']);
24
+ /**
25
+ * Reports whether `key` on a raw node of type `type` holds a position
26
+ * (`syntax.Pos`) rather than child/scalar data — driving the "drop this
27
+ * field" decision `buildFields` below makes, in place of the bare-name
28
+ * `POS_KEYS` denylist this replaced (see issue #8, "replace the bare-name
29
+ * POS_KEYS denylist with generated per-(type,field) position data").
30
+ *
31
+ * Scoping the check per (type, key) — via the generated
32
+ * {@link FROZEN_POSITION_FIELDS} table, itself derived from mvdan/sh's own
33
+ * struct definitions by `tools/gen-visitor-keys` — is what closes the
34
+ * collision class a single global bare-name set could never close: mvdan/sh
35
+ * reuses field names across unrelated struct shapes. `Do` is both
36
+ * `WhileClause.DoPos Pos` (a position) and `ForClause.Do []*Stmt` (the loop
37
+ * body — real data, issue #2); `Dollar` is both `ParamExp.Dollar Pos` and
38
+ * `SglQuoted.Dollar`/`DblQuoted.Dollar bool` (the `$'...'`/`$"..."` ANSI-C
39
+ * quoting flag — real data, issue #3); `Select` (`ForClause.Select bool`),
40
+ * `Until` (`WhileClause.Until bool`), and `Unsigned`
41
+ * (`ArithmExp`/`ArithmCmd.Unsigned bool`) were never positions in *any*
42
+ * mvdan/sh v3.13.1 struct at all, yet the old bare-name denylist dropped
43
+ * them unconditionally regardless of node type.
44
+ */
45
+ function isPositionField(type, key) {
46
+ if (UNIVERSAL_POSITION_KEYS.has(key))
47
+ return true;
48
+ return (FROZEN_POSITION_FIELDS[type] ?? []).includes(key);
49
+ }
50
+ function isJsonObject(value) {
51
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
52
+ }
53
+ function isRawPos(value) {
54
+ if (!isJsonObject(value))
55
+ return false;
56
+ const keys = Object.keys(value);
57
+ return (keys.length === 3 &&
58
+ typeof value.Offset === 'number' &&
59
+ typeof value.Line === 'number' &&
60
+ typeof value.Col === 'number');
61
+ }
62
+ function isRawNode(value) {
63
+ return isJsonObject(value) && isRawPos(value.Pos) && isRawPos(value.End);
64
+ }
65
+ /**
66
+ * Builds a byte-offset -> UTF-16-index lookup for `text`. mvdan/sh reports
67
+ * byte offsets; ESLint (and JavaScript strings generally) index by UTF-16
68
+ * code unit, so every position needs this conversion. Throws if asked to
69
+ * convert an offset that does not fall on a UTF-8 code-point boundary — an
70
+ * invariant every offset the parser emits must satisfy (see
71
+ * design/ARCHITECTURE.md's "Serialization contract").
72
+ *
73
+ * @internal
74
+ */
75
+ export function makeByteToUtf16(text) {
76
+ const map = new Map();
77
+ let byte = 0;
78
+ map.set(0, 0);
79
+ for (let i = 0; i < text.length;) {
80
+ const codePoint = text.codePointAt(i);
81
+ // codePointAt(i) is always defined for i < text.length; this guards the
82
+ // type only (strict null checks require it, not a reachable branch).
83
+ if (codePoint === undefined)
84
+ break;
85
+ const units = codePoint > 0xffff ? 2 : 1;
86
+ const bytes = codePoint <= 0x7f ? 1 : codePoint <= 0x7ff ? 2 : codePoint <= 0xffff ? 3 : 4;
87
+ byte += bytes;
88
+ i += units;
89
+ map.set(byte, i);
90
+ }
91
+ return (byteOffset) => {
92
+ const value = map.get(byteOffset);
93
+ if (value === undefined) {
94
+ throw new Error(`byte offset ${String(byteOffset)} is not a UTF-8 code point boundary`);
95
+ }
96
+ return value;
97
+ };
98
+ }
99
+ /**
100
+ * The UTF-16 index of the start of each 1-based source line (`lineStarts[0]`
101
+ * is line 1's start, always `0`).
102
+ */
103
+ function computeLineStarts(text) {
104
+ const lineStarts = [0];
105
+ for (let i = 0; i < text.length; i++) {
106
+ if (text[i] === '\n')
107
+ lineStarts.push(i + 1);
108
+ }
109
+ return lineStarts;
110
+ }
111
+ /**
112
+ * Converts a byte offset and the 1-based line mvdan/sh already computed for
113
+ * it into a 1-based, UTF-16-code-unit column — the same conversion
114
+ * `normalize` applies to every node's `loc.start`/`loc.end` below, extracted
115
+ * so a parse error's reported position (see `errors.ts`'s
116
+ * `ShParseErrorInfo`) can use the identical algorithm instead of the raw
117
+ * byte-counting column mvdan/sh itself reports. See design/ARCHITECTURE.md's
118
+ * "Byte→UTF-16 conversion".
119
+ *
120
+ * @internal
121
+ */
122
+ export function toUtf16Column(text, byteOffset, line) {
123
+ const index = makeByteToUtf16(text)(byteOffset);
124
+ const lineStart = computeLineStarts(text)[line - 1] ?? 0;
125
+ return index - lineStart + 1;
126
+ }
127
+ /**
128
+ * Normalizes mvdan/sh's typedjson tree into the shape ESLint expects: every
129
+ * node gets `type`, `range` (UTF-16), `loc` (1-based, UTF-16 columns), and
130
+ * every other field copied over with its name lowercased. See
131
+ * design/ARCHITECTURE.md's "Normalized node shape".
132
+ *
133
+ * Three of mvdan/sh's struct types — `Slice`, `Replace`, `Expansion`, all
134
+ * reachable only via `ParamExp.Slice`/`.Repl`/`.Exp` — do not implement
135
+ * `syntax.Node` (no `Pos()`/`End()`), so typedjson never gives them a `Pos`/
136
+ * `End` pair, let alone a `Type` discriminator. They still hold real child
137
+ * nodes (`Slice.Offset`/`.Length`, `Replace.Orig`/`.With`,
138
+ * `Expansion.Word`), so dropping them would silently lose that subtree (see
139
+ * issue #13 — `${USER:-nobody}`'s `nobody` literal). This function
140
+ * synthesizes a `type`/`range`/`loc` for these from their own children's
141
+ * already-computed positions instead, via `walkSynthetic` below.
142
+ *
143
+ * @internal
144
+ */
145
+ export function normalize(root, text) {
146
+ const toUtf16 = makeByteToUtf16(text);
147
+ const lineStarts = computeLineStarts(text);
148
+ const toLoc = (pos) => {
149
+ const index = toUtf16(pos.Offset);
150
+ const lineStart = lineStarts[pos.Line - 1] ?? 0;
151
+ const column = index - lineStart + 1;
152
+ return { line: pos.Line, column, index };
153
+ };
154
+ const startOf = (node) => ({
155
+ index: node.range[0],
156
+ line: node.loc.start.line,
157
+ column: node.loc.start.column,
158
+ });
159
+ const endOf = (node) => ({
160
+ index: node.range[1],
161
+ line: node.loc.end.line,
162
+ column: node.loc.end.column,
163
+ });
164
+ const earlier = (a, b) => (a.index <= b.index ? a : b);
165
+ const later = (a, b) => (a.index >= b.index ? a : b);
166
+ /**
167
+ * Builds `node`'s own lowercased field map, recursing into schema-declared
168
+ * children (real or synthetic). `fallback` is the nearest enclosing *real*
169
+ * node's start/end — used only if a synthetic child ends up with no
170
+ * positioned children of its own to derive a span from (see
171
+ * `walkSynthetic`).
172
+ */
173
+ function buildFields(node, type, fallback) {
174
+ const schema = FROZEN_CHILD_TYPE_SCHEMA[type] ?? {};
175
+ const out = {};
176
+ const children = [];
177
+ const resolve = (value, childType) => {
178
+ if (isRawNode(value)) {
179
+ const child = walkNode(value, childType);
180
+ children.push(child);
181
+ return child;
182
+ }
183
+ if (childType !== null && isJsonObject(value)) {
184
+ const child = walkSynthetic(value, childType, fallback);
185
+ children.push(child);
186
+ return child;
187
+ }
188
+ return value;
189
+ };
190
+ for (const [key, value] of Object.entries(node)) {
191
+ if (key === 'Type' || isPositionField(type, key))
192
+ continue;
193
+ const outKey = key.toLowerCase();
194
+ const childType = schema[key] ?? null;
195
+ if (Array.isArray(value)) {
196
+ out[outKey] = value.map((item) => resolve(item, childType));
197
+ }
198
+ else if (isRawNode(value) || (childType !== null && isJsonObject(value))) {
199
+ out[outKey] = resolve(value, childType);
200
+ }
201
+ else if (!isRawPos(value)) {
202
+ out[outKey] = value;
203
+ }
204
+ }
205
+ return { fields: out, children };
206
+ }
207
+ function walkNode(node, staticType) {
208
+ const rawType = node.Type;
209
+ const type = typeof rawType === 'string' ? rawType : staticType;
210
+ if (type === null) {
211
+ throw new Error(`node without resolvable type: ${JSON.stringify(node).slice(0, 120)}`);
212
+ }
213
+ if (!isRawPos(node.Pos) || !isRawPos(node.End)) {
214
+ throw new Error(`node of type ${type} is missing Pos/End`);
215
+ }
216
+ const start = toLoc(node.Pos);
217
+ const end = toLoc(node.End);
218
+ const { fields } = buildFields(node, type, { start, end });
219
+ return {
220
+ type,
221
+ range: [start.index, end.index],
222
+ loc: {
223
+ start: { line: start.line, column: start.column },
224
+ end: { line: end.line, column: end.column },
225
+ },
226
+ ...fields,
227
+ };
228
+ }
229
+ /**
230
+ * Normalizes a struct-typed field's value that has no `Pos`/`End` of its
231
+ * own — one of mvdan/sh's three non-`Node` "auxiliary" structs (`Slice`,
232
+ * `Replace`, `Expansion`). Its `range`/`loc` are synthesized from the
233
+ * union of its own children's already-computed spans (the exact source
234
+ * span its children cover — e.g. a `Replace`'s span is `Orig`'s start
235
+ * through `With`'s end, which for `${var/foo/bar}` is exactly `foo/bar`).
236
+ * Falls back to the nearest enclosing real node's span only when there
237
+ * are no positioned children at all to derive one from — e.g.
238
+ * `Expansion.Word` is nil (omitted from typedjson's output entirely, via
239
+ * `omitempty`) for an empty default like `${a:-}`.
240
+ */
241
+ function walkSynthetic(node, type, fallback) {
242
+ const { fields, children } = buildFields(node, type, fallback);
243
+ const start = children.length > 0 ? children.map(startOf).reduce(earlier) : fallback.start;
244
+ const end = children.length > 0 ? children.map(endOf).reduce(later) : fallback.end;
245
+ return {
246
+ type,
247
+ range: [start.index, end.index],
248
+ loc: {
249
+ start: { line: start.line, column: start.column },
250
+ end: { line: end.line, column: end.column },
251
+ },
252
+ ...fields,
253
+ };
254
+ }
255
+ if (!isRawNode(root)) {
256
+ throw new Error('normalize: root value is not a node (missing Pos/End)');
257
+ }
258
+ return walkNode(root, 'File');
259
+ }
260
+ //# sourceMappingURL=normalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import { type JsonValue } from './normalize.js';
2
+ import type { ParseOptions, ShFile } from './types.js';
3
+ interface ParseErrorPayload {
4
+ message: string;
5
+ filename: string;
6
+ line: number;
7
+ column: number;
8
+ offset: number;
9
+ }
10
+ interface ErrorPayload {
11
+ message: string;
12
+ }
13
+ interface ResultEnvelope {
14
+ file?: JsonValue;
15
+ parseError?: ParseErrorPayload;
16
+ error?: ErrorPayload;
17
+ }
18
+ /**
19
+ * @internal
20
+ */
21
+ export declare function isResultEnvelope(value: unknown): value is ResultEnvelope;
22
+ /**
23
+ * Synchronously parses shell source into a normalized AST.
24
+ *
25
+ * The first call instantiates the WASM shim synchronously (Node-only); the
26
+ * instance is reused across subsequent calls, so repeated calls do not
27
+ * re-instantiate (see design/ARCHITECTURE.md).
28
+ *
29
+ * Throws {@link ShParseError} on a shell syntax error, carrying the position
30
+ * mvdan/sh reported: `.line` is 1-based exactly as mvdan/sh reports it;
31
+ * `.column` is converted to UTF-16 code units so it agrees with
32
+ * {@link ShNode.loc}'s columns (mvdan/sh itself reports `column` as a byte
33
+ * count — see {@link ShParseErrorInfo.column}). That unconverted, raw
34
+ * position appears only inside `.message`, which is mvdan/sh's own
35
+ * formatted string, verbatim. Throws {@link ShInvalidDialectError} when
36
+ * {@link ParseOptions.dialect} is not a supported dialect. Throws
37
+ * {@link ShBridgeInternalError} for failures that should never happen given
38
+ * a correctly-behaving shim (malformed envelope, unexpected root node
39
+ * type, shim contract violations).
40
+ *
41
+ * @public
42
+ */
43
+ export declare function parseSync(text: string, options?: ParseOptions): ShFile;
44
+ export {};
45
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AACA,OAAO,EAA4B,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE1E,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,EAAE,MAAM,YAAY,CAAC;AAcrE,UAAU,iBAAiB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,YAAY;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,cAAc;IACtB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB;AAoCD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAKxE;AAcD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,MAAM,CAoCtE"}
package/dist/parse.js ADDED
@@ -0,0 +1,118 @@
1
+ import { ShBridgeInternalError, ShInvalidDialectError, ShParseError } from './errors.js';
2
+ import { normalize, toUtf16Column } from './normalize.js';
3
+ import { callParse } from './wasm-instance.js';
4
+ /**
5
+ * The full set of dialects {@link parseSync} accepts, in the order surfaced
6
+ * by {@link ShInvalidDialectError}'s message. Kept as a runtime value
7
+ * distinct from the {@link ShellDialect} union so `parseSync` can validate
8
+ * `options.dialect` before ever calling into the WASM shim.
9
+ */
10
+ const SUPPORTED_SHELL_DIALECTS = ['bash', 'posix', 'mksh', 'bats', 'zsh'];
11
+ function isSupportedShellDialect(value) {
12
+ return SUPPORTED_SHELL_DIALECTS.includes(value);
13
+ }
14
+ /**
15
+ * Checks that `value` is a plain object — rejects arrays, `null`, wrapped
16
+ * primitives, class instances, and symbol-keyed objects. `isResultEnvelope`
17
+ * and its field-level helpers below all validate `unknown` input coming
18
+ * straight out of `JSON.parse`, so this is the full-rigor check, not just
19
+ * `typeof value === 'object'`.
20
+ *
21
+ * @internal
22
+ */
23
+ function isPlainObject(value) {
24
+ return (typeof value === 'object' &&
25
+ value !== null &&
26
+ !Array.isArray(value) &&
27
+ Object.getPrototypeOf(value) === Object.prototype &&
28
+ Object.getOwnPropertySymbols(value).length === 0);
29
+ }
30
+ function isParseErrorPayload(value) {
31
+ return (isPlainObject(value) &&
32
+ typeof value.message === 'string' &&
33
+ typeof value.filename === 'string' &&
34
+ typeof value.line === 'number' &&
35
+ typeof value.column === 'number' &&
36
+ typeof value.offset === 'number');
37
+ }
38
+ function isErrorPayload(value) {
39
+ return isPlainObject(value) && typeof value.message === 'string';
40
+ }
41
+ /**
42
+ * @internal
43
+ */
44
+ export function isResultEnvelope(value) {
45
+ if (!isPlainObject(value))
46
+ return false;
47
+ if (value.parseError !== undefined && !isParseErrorPayload(value.parseError))
48
+ return false;
49
+ if (value.error !== undefined && !isErrorPayload(value.error))
50
+ return false;
51
+ return true;
52
+ }
53
+ function asShFile(node) {
54
+ if (node.type !== 'File') {
55
+ throw new ShBridgeInternalError(`bridge: expected root node of type "File", got "${node.type}"`);
56
+ }
57
+ if (!Array.isArray(node.stmts)) {
58
+ throw new ShBridgeInternalError('bridge: expected root node to have an array "stmts" field');
59
+ }
60
+ return node;
61
+ }
62
+ /**
63
+ * Synchronously parses shell source into a normalized AST.
64
+ *
65
+ * The first call instantiates the WASM shim synchronously (Node-only); the
66
+ * instance is reused across subsequent calls, so repeated calls do not
67
+ * re-instantiate (see design/ARCHITECTURE.md).
68
+ *
69
+ * Throws {@link ShParseError} on a shell syntax error, carrying the position
70
+ * mvdan/sh reported: `.line` is 1-based exactly as mvdan/sh reports it;
71
+ * `.column` is converted to UTF-16 code units so it agrees with
72
+ * {@link ShNode.loc}'s columns (mvdan/sh itself reports `column` as a byte
73
+ * count — see {@link ShParseErrorInfo.column}). That unconverted, raw
74
+ * position appears only inside `.message`, which is mvdan/sh's own
75
+ * formatted string, verbatim. Throws {@link ShInvalidDialectError} when
76
+ * {@link ParseOptions.dialect} is not a supported dialect. Throws
77
+ * {@link ShBridgeInternalError} for failures that should never happen given
78
+ * a correctly-behaving shim (malformed envelope, unexpected root node
79
+ * type, shim contract violations).
80
+ *
81
+ * @public
82
+ */
83
+ export function parseSync(text, options) {
84
+ const dialect = options?.dialect ?? 'bash';
85
+ const filename = options?.filename ?? 'input.sh';
86
+ if (!isSupportedShellDialect(dialect)) {
87
+ throw new ShInvalidDialectError(dialect, SUPPORTED_SHELL_DIALECTS);
88
+ }
89
+ const raw = callParse(text, dialect, filename);
90
+ const result = JSON.parse(raw);
91
+ if (!isResultEnvelope(result)) {
92
+ throw new ShBridgeInternalError('bridge: WASM shim returned an unexpected payload shape');
93
+ }
94
+ if (result.parseError) {
95
+ // mvdan/sh reports `column` as a byte count on the source line, not a
96
+ // UTF-16 code unit count — inconsistent with ShNode.loc.column, which is
97
+ // always UTF-16 (see design/ARCHITECTURE.md's "Byte→UTF-16 conversion").
98
+ // Recompute it from `offset` (a byte offset from the start of the file,
99
+ // which every position mvdan/sh reports carries) via the same
100
+ // conversion `normalize` applies to every node, so a thrown
101
+ // ShParseError's column always agrees with the column a ShNode at that
102
+ // position would report.
103
+ const column = toUtf16Column(text, result.parseError.offset, result.parseError.line);
104
+ throw new ShParseError(result.parseError.message, {
105
+ line: result.parseError.line,
106
+ column,
107
+ filename: result.parseError.filename,
108
+ });
109
+ }
110
+ if (result.error) {
111
+ throw new ShBridgeInternalError(result.error.message);
112
+ }
113
+ if (result.file === undefined) {
114
+ throw new ShBridgeInternalError('bridge: WASM shim returned neither a file nor an error');
115
+ }
116
+ return asShFile(normalize(result.file, text));
117
+ }
118
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}