sh-ast 0.0.0 → 0.2.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 (81) 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 +165 -0
  11. package/dist/analyze/enumerate-commands.d.ts.map +1 -0
  12. package/dist/analyze/enumerate-commands.js +396 -0
  13. package/dist/analyze/enumerate-commands.js.map +1 -0
  14. package/dist/analyze/index.d.ts +26 -0
  15. package/dist/analyze/index.d.ts.map +1 -0
  16. package/dist/analyze/index.js +30 -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-argv0.d.ts +335 -0
  23. package/dist/analyze/resolve-argv0.d.ts.map +1 -0
  24. package/dist/analyze/resolve-argv0.js +510 -0
  25. package/dist/analyze/resolve-argv0.js.map +1 -0
  26. package/dist/analyze/resolve-word.d.ts +151 -0
  27. package/dist/analyze/resolve-word.d.ts.map +1 -0
  28. package/dist/analyze/resolve-word.js +207 -0
  29. package/dist/analyze/resolve-word.js.map +1 -0
  30. package/dist/analyze.d.ts +771 -0
  31. package/dist/deep-freeze.d.ts +14 -0
  32. package/dist/deep-freeze.d.ts.map +1 -0
  33. package/dist/deep-freeze.js +25 -0
  34. package/dist/deep-freeze.js.map +1 -0
  35. package/dist/errors.d.ts +180 -0
  36. package/dist/errors.d.ts.map +1 -0
  37. package/dist/errors.js +179 -0
  38. package/dist/errors.js.map +1 -0
  39. package/dist/index.d.ts +18 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +5 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/normalize.d.ts +52 -0
  44. package/dist/normalize.d.ts.map +1 -0
  45. package/dist/normalize.js +260 -0
  46. package/dist/normalize.js.map +1 -0
  47. package/dist/parse-depth-guard.d.ts +11 -0
  48. package/dist/parse-depth-guard.d.ts.map +1 -0
  49. package/dist/parse-depth-guard.js +633 -0
  50. package/dist/parse-depth-guard.js.map +1 -0
  51. package/dist/parse.d.ts +50 -0
  52. package/dist/parse.d.ts.map +1 -0
  53. package/dist/parse.js +125 -0
  54. package/dist/parse.js.map +1 -0
  55. package/dist/sh-ast.d.ts +1346 -0
  56. package/dist/types.d.ts +74 -0
  57. package/dist/types.d.ts.map +1 -0
  58. package/dist/types.js +2 -0
  59. package/dist/types.js.map +1 -0
  60. package/dist/visitor-keys.d.ts +21 -0
  61. package/dist/visitor-keys.d.ts.map +1 -0
  62. package/dist/visitor-keys.js +23 -0
  63. package/dist/visitor-keys.js.map +1 -0
  64. package/dist/walk.d.ts +18 -0
  65. package/dist/walk.d.ts.map +1 -0
  66. package/dist/walk.js +40 -0
  67. package/dist/walk.js.map +1 -0
  68. package/dist/wasm-instance.d.ts +13 -0
  69. package/dist/wasm-instance.d.ts.map +1 -0
  70. package/dist/wasm-instance.js +88 -0
  71. package/dist/wasm-instance.js.map +1 -0
  72. package/generated/child-type-schema.d.ts +14 -0
  73. package/generated/child-type-schema.js +188 -0
  74. package/generated/node-types.d.ts +958 -0
  75. package/generated/position-fields.d.ts +21 -0
  76. package/generated/position-fields.js +50 -0
  77. package/generated/visitor-keys.d.ts +11 -0
  78. package/generated/visitor-keys.js +50 -0
  79. package/package.json +93 -10
  80. package/shim/sh-ast.wasm +0 -0
  81. package/shim/wasm_exec.js +654 -0
@@ -0,0 +1,50 @@
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 ShInternalError} for failures that should never happen given
38
+ * a correctly-behaving shim (malformed envelope, unexpected root node
39
+ * type, shim contract violations). Throws {@link ShParseMaxDepthError} if
40
+ * `text`'s conservatively estimated structural nesting depth exceeds the
41
+ * limit this bridge accepts — checked, and thrown, *before* `text` is ever
42
+ * handed to the WASM shim, since mvdan/sh's own parser has no recovery path
43
+ * for exhausting its stack on pathological nesting (see that error's doc
44
+ * comment and `parse-depth-guard.ts`).
45
+ *
46
+ * @public
47
+ */
48
+ export declare function parseSync(text: string, options?: ParseOptions): ShFile;
49
+ export {};
50
+ //# 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;AAG1E,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;AAYD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,MAAM,CAsCtE"}
package/dist/parse.js ADDED
@@ -0,0 +1,125 @@
1
+ import { ShInternalError, ShInvalidDialectError, ShParseError } from './errors.js';
2
+ import { normalize, toUtf16Column } from './normalize.js';
3
+ import { assertParseDepthWithinLimit } from './parse-depth-guard.js';
4
+ import { callParse } from './wasm-instance.js';
5
+ /**
6
+ * The full set of dialects {@link parseSync} accepts, in the order surfaced
7
+ * by {@link ShInvalidDialectError}'s message. Kept as a runtime value
8
+ * distinct from the {@link ShellDialect} union so `parseSync` can validate
9
+ * `options.dialect` before ever calling into the WASM shim.
10
+ */
11
+ const SUPPORTED_SHELL_DIALECTS = ['bash', 'posix', 'mksh', 'bats', 'zsh'];
12
+ function isSupportedShellDialect(value) {
13
+ return SUPPORTED_SHELL_DIALECTS.includes(value);
14
+ }
15
+ /**
16
+ * Checks that `value` is a plain object — rejects arrays, `null`, wrapped
17
+ * primitives, class instances, and symbol-keyed objects. `isResultEnvelope`
18
+ * and its field-level helpers below all validate `unknown` input coming
19
+ * straight out of `JSON.parse`, so this is the full-rigor check, not just
20
+ * `typeof value === 'object'`.
21
+ *
22
+ * @internal
23
+ */
24
+ function isPlainObject(value) {
25
+ return (typeof value === 'object' &&
26
+ value !== null &&
27
+ !Array.isArray(value) &&
28
+ Object.getPrototypeOf(value) === Object.prototype &&
29
+ Object.getOwnPropertySymbols(value).length === 0);
30
+ }
31
+ function isParseErrorPayload(value) {
32
+ return (isPlainObject(value) &&
33
+ typeof value.message === 'string' &&
34
+ typeof value.filename === 'string' &&
35
+ typeof value.line === 'number' &&
36
+ typeof value.column === 'number' &&
37
+ typeof value.offset === 'number');
38
+ }
39
+ function isErrorPayload(value) {
40
+ return isPlainObject(value) && typeof value.message === 'string';
41
+ }
42
+ /**
43
+ * @internal
44
+ */
45
+ export function isResultEnvelope(value) {
46
+ if (!isPlainObject(value))
47
+ return false;
48
+ if (value.parseError !== undefined && !isParseErrorPayload(value.parseError))
49
+ return false;
50
+ if (value.error !== undefined && !isErrorPayload(value.error))
51
+ return false;
52
+ return true;
53
+ }
54
+ function asShFile(node) {
55
+ if (node.type !== 'File') {
56
+ throw new ShInternalError(`bridge: expected root node of type "File", got "${node.type}"`);
57
+ }
58
+ if (!Array.isArray(node.stmts)) {
59
+ throw new ShInternalError('bridge: expected root node to have an array "stmts" field');
60
+ }
61
+ return node;
62
+ }
63
+ /**
64
+ * Synchronously parses shell source into a normalized AST.
65
+ *
66
+ * The first call instantiates the WASM shim synchronously (Node-only); the
67
+ * instance is reused across subsequent calls, so repeated calls do not
68
+ * re-instantiate (see design/ARCHITECTURE.md).
69
+ *
70
+ * Throws {@link ShParseError} on a shell syntax error, carrying the position
71
+ * mvdan/sh reported: `.line` is 1-based exactly as mvdan/sh reports it;
72
+ * `.column` is converted to UTF-16 code units so it agrees with
73
+ * {@link ShNode.loc}'s columns (mvdan/sh itself reports `column` as a byte
74
+ * count — see {@link ShParseErrorInfo.column}). That unconverted, raw
75
+ * position appears only inside `.message`, which is mvdan/sh's own
76
+ * formatted string, verbatim. Throws {@link ShInvalidDialectError} when
77
+ * {@link ParseOptions.dialect} is not a supported dialect. Throws
78
+ * {@link ShInternalError} for failures that should never happen given
79
+ * a correctly-behaving shim (malformed envelope, unexpected root node
80
+ * type, shim contract violations). Throws {@link ShParseMaxDepthError} if
81
+ * `text`'s conservatively estimated structural nesting depth exceeds the
82
+ * limit this bridge accepts — checked, and thrown, *before* `text` is ever
83
+ * handed to the WASM shim, since mvdan/sh's own parser has no recovery path
84
+ * for exhausting its stack on pathological nesting (see that error's doc
85
+ * comment and `parse-depth-guard.ts`).
86
+ *
87
+ * @public
88
+ */
89
+ export function parseSync(text, options) {
90
+ const dialect = options?.dialect ?? 'bash';
91
+ const filename = options?.filename ?? 'input.sh';
92
+ if (!isSupportedShellDialect(dialect)) {
93
+ throw new ShInvalidDialectError(dialect, SUPPORTED_SHELL_DIALECTS);
94
+ }
95
+ assertParseDepthWithinLimit(text);
96
+ const raw = callParse(text, dialect, filename);
97
+ const result = JSON.parse(raw);
98
+ if (!isResultEnvelope(result)) {
99
+ throw new ShInternalError('bridge: WASM shim returned an unexpected payload shape');
100
+ }
101
+ if (result.parseError) {
102
+ // mvdan/sh reports `column` as a byte count on the source line, not a
103
+ // UTF-16 code unit count — inconsistent with ShNode.loc.column, which is
104
+ // always UTF-16 (see design/ARCHITECTURE.md's "Byte→UTF-16 conversion").
105
+ // Recompute it from `offset` (a byte offset from the start of the file,
106
+ // which every position mvdan/sh reports carries) via the same
107
+ // conversion `normalize` applies to every node, so a thrown
108
+ // ShParseError's column always agrees with the column a ShNode at that
109
+ // position would report.
110
+ const column = toUtf16Column(text, result.parseError.offset, result.parseError.line);
111
+ throw new ShParseError(result.parseError.message, {
112
+ line: result.parseError.line,
113
+ column,
114
+ filename: result.parseError.filename,
115
+ });
116
+ }
117
+ if (result.error) {
118
+ throw new ShInternalError(result.error.message);
119
+ }
120
+ if (result.file === undefined) {
121
+ throw new ShInternalError('bridge: WASM shim returned neither a file nor an error');
122
+ }
123
+ return asShFile(normalize(result.file, text));
124
+ }
125
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}