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.
- 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 +165 -0
- package/dist/analyze/enumerate-commands.d.ts.map +1 -0
- package/dist/analyze/enumerate-commands.js +396 -0
- package/dist/analyze/enumerate-commands.js.map +1 -0
- package/dist/analyze/index.d.ts +26 -0
- package/dist/analyze/index.d.ts.map +1 -0
- package/dist/analyze/index.js +30 -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-argv0.d.ts +335 -0
- package/dist/analyze/resolve-argv0.d.ts.map +1 -0
- package/dist/analyze/resolve-argv0.js +510 -0
- package/dist/analyze/resolve-argv0.js.map +1 -0
- package/dist/analyze/resolve-word.d.ts +151 -0
- package/dist/analyze/resolve-word.d.ts.map +1 -0
- package/dist/analyze/resolve-word.js +207 -0
- package/dist/analyze/resolve-word.js.map +1 -0
- package/dist/analyze.d.ts +771 -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 +180 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +179 -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-depth-guard.d.ts +11 -0
- package/dist/parse-depth-guard.d.ts.map +1 -0
- package/dist/parse-depth-guard.js +633 -0
- package/dist/parse-depth-guard.js.map +1 -0
- package/dist/parse.d.ts +50 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +125 -0
- package/dist/parse.js.map +1 -0
- package/dist/sh-ast.d.ts +1346 -0
- package/dist/types.d.ts +74 -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/parse.d.ts
ADDED
|
@@ -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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"}
|