sh-ast 0.4.0 → 0.5.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 CHANGED
@@ -6,6 +6,11 @@ mutable records preserving upstream fields, defaults, nulls, numeric operators,
6
6
  byte strings, and token positions. First use initializes WebAssembly synchronously
7
7
  in Node.js; no initialization promise is required.
8
8
 
9
+ Traversal uses ordinary TypeScript arrays with explicit mutation limits. The
10
+ [accepted representation decision](../../design/WALK-MUTATION-DECISION.md) records
11
+ which live edits are supported and why this interface does not model Go storage
12
+ capacity, reslicing, or value-slot addresses.
13
+
9
14
  ```ts
10
15
  import { LangBash, nodeEnd, parseSync } from 'sh-ast';
11
16
 
@@ -58,15 +63,93 @@ Positions }`. `Positions.get(node)` reads immutable original bounds by node
58
63
  a value does not promise every upstream operation accepts it.
59
64
  - `SYNTAX_SCHEMA` and `SYNTAX_INTERFACES` are deeply frozen field/interface
60
65
  metadata. Their order is not upstream Walk order.
66
+ - `walk(node, callback)` calls the callback synchronously on entry and with `null`
67
+ on exit. Return `false` on entry to prune that occurrence, including its exit;
68
+ exit boolean values do not control traversal. Every callback result must be a
69
+ boolean; Promises and other values throw `InputError`. Child reads happen live, and
70
+ nested calls keep independent state. Specialized statement/item comment loops
71
+ visit value copies; ordinary comment lists visit their stored objects. The
72
+ array reference and initial length are captured when each list starts. Future
73
+ existing slots are read live; indices added beyond the captured extent are
74
+ ignored by that active traversal. Replacing the owner's array field does not retarget an active list.
75
+ See the mutation limits below.
76
+ - `printSync(node, options?)` reconstructs the current edited tree and collects a
77
+ fresh upstream printer's output as `GoString`. Supported roots are File, Stmt,
78
+ Word, Assign, Command and WordPart alternatives. Only File gets a guaranteed
79
+ final newline. Printing applies upstream formatting; it does not replay the
80
+ original source or promise source-byte identity.
81
+ - `PrintOptions` exposes `Indent`, `BinaryNextLine`, `SwitchCaseIndent`,
82
+ `SpaceRedirects`, `KeepPadding`, `Minify`, `SingleLine`, and `FunctionNextLine`.
83
+ Indent accepts an exact uint64 as a safe number or bigint, with zero selecting
84
+ tabs. Boolean defaults are false. KeepPadding is upstream's best-effort,
85
+ deprecated option; Minify and SingleLine together return an upstream error.
61
86
 
62
87
  `ParseError` and `LangError` preserve upstream fields, exact `Message` bytes, and
63
88
  any partial `File`. Their ordinary `Error.message` is a display string.
64
89
  `InputError` reports invalid binding inputs, upstream option constraints, or
65
90
  unsupported constructed nodes whose requested bound panics upstream.
66
91
  `ShInternalError` reports transport failures or unexpected upstream panics.
92
+ `PrintError` retains ordinary upstream printer failures, and `PrintPanicError`
93
+ retains panics from printing representable inputs. `WalkPanicError` represents
94
+ upstream-equivalent traversal panics; callback exceptions retain their identity.
67
95
  All extend `ShAstError`. The conservative structural-depth guard throws
68
96
  `ShParseMaxDepthError` before potentially exhausting the WASM stack. It is a
69
97
  binding resource constraint and can reject deeply nested quoted or commented text.
98
+ Printing collects complete output; large trees or indentation widths can consume
99
+ substantial memory and time. The parse guard does not bound arbitrary constructed
100
+ printing inputs. No arbitrary writer, partial-output, or reusable-printer protocol
101
+ is exposed.
102
+
103
+ ## Traversal mutation limits
104
+
105
+ Supported edits preserve a node's kind and shape: change syntax fields, replace
106
+ pointer children before their read, replace future existing list slots, append
107
+ beyond an active list's captured extent, or assign a new array to the owner field.
108
+ Changes before a list starts are included in its captured reference and length.
109
+ Pruning and synchronous nested walks retain their control behavior; nested walks
110
+ see the tree at their own entry, while edits to shared objects remain live.
111
+
112
+ Keep every index in an active list's captured extent present. Removing one,
113
+ leaving a hole there, or shrinking below that extent is outside the supported
114
+ contract, including through aliases. Truncation, `delete`, `pop`, `shift`, or a
115
+ length-reducing `splice` can do this; removing appended indices beyond the captured
116
+ extent does not affect the active list. No mutation detector or specific
117
+ error/result is promised for those edits. Assign a new owner array
118
+ instead; the active list keeps its original array and later walks see the new one.
119
+ Length-preserving replacement or reordering, including `sort` and `reverse`,
120
+ follows live slot reads and may revisit an object moved into a later slot. Walk
121
+ does not promise to visit each object only once. An appended object moved into an
122
+ original future slot is visited through that slot.
123
+
124
+ Stored Comment callbacks receive JavaScript objects. Replacing a Comment slot
125
+ leaves a retained callback object unchanged; it does not behave as a pointer to a
126
+ Go value slot. Specialized Stmt/CaseItem/ArrayElem comment callbacks receive
127
+ copies, so editing those callback values does not edit the original comments.
128
+ Ordinary JavaScript aliases remain live; this interface does not clone shared
129
+ arrays or objects. It does not model Go slice capacity, distinct slice headers
130
+ sharing backing stores, or reslicing. These limits preclude unrestricted Go
131
+ storage mutation parity while preserving live field edits and upstream traversal control.
132
+
133
+ ## Editing and printing
134
+
135
+ ```ts
136
+ import { parseSync, printSync, walk } from 'sh-ast';
137
+
138
+ const file = parseSync("printf '%s\\n' 'old 🎉'\n", { KeepComments: true });
139
+ walk(file, (node) => {
140
+ if (node?.Type === 'SglQuoted' && node.Value === 'old 🎉') {
141
+ node.Value = 'new 🎉';
142
+ }
143
+ return true;
144
+ });
145
+ const output = printSync(file);
146
+ ```
147
+
148
+ This edits a field without replacing array storage. Node positions still describe
149
+ their upstream token values; live `nodePos` and `nodeEnd` compute from current
150
+ fields, while a separately captured parse snapshot remains tied to original
151
+ source. Consumers such as ESLint can edit a separate tree and use printed output
152
+ as a fix without mutating their original lint view or traversal cache.
70
153
 
71
154
  `sh-ast/analyze` remains a separate syntactic interpretation layer. Its word,
72
155
  command, and wrapper analysis consumes the faithful records; it does not define
@@ -77,11 +160,12 @@ parser behavior or the core tree representation.
77
160
  Fields now use upstream spelling (`Type`, `Stmts`, `Cmd`, `Value`) and explicit
78
161
  null/default values. Replace dialect strings with numeric `Variant` constants,
79
162
  request comments explicitly, and handle structured errors and byte positions.
80
- The root no longer exports normalized `ShNode`/`ShNodes`, `range`/`loc`, `walk`, or
81
- `visitorKeys`. Consumers such as ESLint own their source-coordinate and traversal
82
- views. Whole-file parsing is the present scope; public upstream traversal and
83
- printing belong to the following minor release. Stateful/incremental parser
84
- protocols and full syntax-package parity are deferred.
163
+ The root no longer exports normalized `ShNode`/`ShNodes`, `range`/`loc`, or
164
+ `visitorKeys`. The new walker uses entry/null-exit callbacks rather than the former
165
+ structural helper's protocol. Consumers such as ESLint own their source-coordinate
166
+ and traversal views. Whole-file parsing, collected printing and the live walker
167
+ with the mutation limits above form this candidate's scope. Stateful/incremental parser protocols
168
+ and full syntax-package parity are deferred.
85
169
 
86
170
  The [design collection](../../design/ARCHITECTURE.md) and
87
171
  [implementation evidence](../../design/IMPLEMENTATION.md) describe the release
package/dist/index.d.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  export { InputError, LangError, ParseError, newPos, nodeEnd, nodePos, parseSync, parseWithPositionsSync, rawOperator, } from './syntax.js';
2
2
  export type { ParseOptions, ParsedFile, PositionSnapshot, NodePositions } from './syntax.js';
3
+ export { printSync } from './syntax-print.js';
4
+ export type { PrintOptions } from './syntax-print.js';
5
+ export { PrintError, PrintPanicError } from './syntax-print-errors.js';
6
+ export { walk, WalkPanicError } from './syntax-walk.js';
3
7
  export type * from '../generated/syntax-types.js';
4
8
  export * from '../generated/syntax-constants.js';
5
9
  export type { SyntaxFieldSchema, SyntaxRecordSchema } from '../generated/syntax-schema.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,UAAU,EACV,SAAS,EACT,UAAU,EACV,MAAM,EACN,OAAO,EACP,OAAO,EACP,SAAS,EACT,sBAAsB,EACtB,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC7F,mBAAmB,8BAA8B,CAAC;AAClD,cAAc,kCAAkC,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAC3F,OAAO,EACL,gCAAgC,EAChC,sBAAsB,EACtB,UAAU,EACV,eAAe,EACf,oBAAoB,GACrB,MAAM,aAAa,CAAC;AAErB;;;;;GAKG;AACH,eAAO,MAAM,aAAa,gGAAqB,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,uDAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,UAAU,EACV,SAAS,EACT,UAAU,EACV,MAAM,EACN,OAAO,EACP,OAAO,EACP,SAAS,EACT,sBAAsB,EACtB,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC7F,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACxD,mBAAmB,8BAA8B,CAAC;AAClD,cAAc,kCAAkC,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAC3F,OAAO,EACL,gCAAgC,EAChC,sBAAsB,EACtB,UAAU,EACV,eAAe,EACf,oBAAoB,GACrB,MAAM,aAAa,CAAC;AAErB;;;;;GAKG;AACH,eAAO,MAAM,aAAa,gGAAqB,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,uDAAyB,CAAC"}
package/dist/index.js CHANGED
@@ -1,11 +1,14 @@
1
1
  /**
2
2
  * A faithful synchronous interface to mvdan/sh syntax. The root exposes upstream
3
- * records, constants, parser controls and position operations. Consumer-specific
3
+ * records, constants, parser controls, traversal, printing and position operations. Consumer-specific
4
4
  * source views and semantic analysis are separate responsibilities.
5
5
  */
6
6
  import { SYNTAX_INTERFACES as interfaces, SYNTAX_SCHEMA as schema, } from '../generated/syntax-schema.js';
7
7
  import { deepFreeze } from './deep-freeze.js';
8
8
  export { InputError, LangError, ParseError, newPos, nodeEnd, nodePos, parseSync, parseWithPositionsSync, rawOperator, } from './syntax.js';
9
+ export { printSync } from './syntax-print.js';
10
+ export { PrintError, PrintPanicError } from './syntax-print-errors.js';
11
+ export { walk, WalkPanicError } from './syntax-walk.js';
9
12
  export * from '../generated/syntax-constants.js';
10
13
  export { ShAnalyzeInvalidWrapperSpecError, ShAnalyzeMaxDepthError, ShAstError, ShInternalError, ShParseMaxDepthError, } from './errors.js';
11
14
  /**
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,iBAAiB,IAAI,UAAU,EAC/B,aAAa,IAAI,MAAM,GACxB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EACL,UAAU,EACV,SAAS,EACT,UAAU,EACV,MAAM,EACN,OAAO,EACP,OAAO,EACP,SAAS,EACT,sBAAsB,EACtB,WAAW,GACZ,MAAM,aAAa,CAAC;AAGrB,cAAc,kCAAkC,CAAC;AAEjD,OAAO,EACL,gCAAgC,EAChC,sBAAsB,EACtB,UAAU,EACV,eAAe,EACf,oBAAoB,GACrB,MAAM,aAAa,CAAC;AAErB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;AAEhD;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,iBAAiB,IAAI,UAAU,EAC/B,aAAa,IAAI,MAAM,GACxB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EACL,UAAU,EACV,SAAS,EACT,UAAU,EACV,MAAM,EACN,OAAO,EACP,OAAO,EACP,SAAS,EACT,sBAAsB,EACtB,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAExD,cAAc,kCAAkC,CAAC;AAEjD,OAAO,EACL,gCAAgC,EAChC,sBAAsB,EACtB,UAAU,EACV,eAAe,EACf,oBAAoB,GACrB,MAAM,aAAa,CAAC;AAErB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;AAEhD;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC"}
package/dist/sh-ast.d.ts CHANGED
@@ -2338,6 +2338,79 @@ export declare const Pow: 44;
2338
2338
  */
2339
2339
  export declare const PowAssgn: 62;
2340
2340
 
2341
+ /**
2342
+ * An error returned by upstream Printer.Print, such as an unsupported root or
2343
+ * incompatible formatting options. No partial writer output is exposed.
2344
+ * @public
2345
+ */
2346
+ export declare class PrintError extends ShAstError {
2347
+ /** Stable identity for an ordinary error returned by upstream Print. @public */
2348
+ readonly code = "SH_AST_SYNTAX_PRINT";
2349
+ /** Exact upstream error bytes; Error.message is only a display rendering. @public */
2350
+ readonly Message: GoString;
2351
+ /** Retains the upstream error without interpreting its human-readable text. @public */
2352
+ constructor(message: GoString);
2353
+ }
2354
+
2355
+ /**
2356
+ * Upstream NewPrinter controls applied to a fresh printer for each call. All
2357
+ * flags default to false; zero indentation selects tabs. The pinned WASM uint
2358
+ * domain is 64-bit, so Indent accepts bigint beyond JavaScript's safe integers.
2359
+ * @public
2360
+ */
2361
+ export declare interface PrintOptions {
2362
+ /** Spaces per level, or zero for tabs. Large values can request expensive output. */
2363
+ Indent?: number | bigint;
2364
+ /** Places multiline binary operators on the next line with a backslash continuation. */
2365
+ BinaryNextLine?: boolean;
2366
+ /** Indents case alternatives, placing their bodies two levels below the case clause. */
2367
+ SwitchCaseIndent?: boolean;
2368
+ /** Adds space after redirection operators except `>&`, `<&`, `>(` and `<(`. */
2369
+ SpaceRedirects?: boolean;
2370
+ /**
2371
+ * Preserves token columns on a best-effort basis.
2372
+ * @deprecated Upstream marks this option as flawed and plans removal in v4.
2373
+ */
2374
+ KeepPadding?: boolean;
2375
+ /** Omits comments, indentation and optional whitespace. Incompatible with SingleLine. */
2376
+ Minify?: boolean;
2377
+ /** Reduces newlines except where comments, heredocs or File output require them. */
2378
+ SingleLine?: boolean;
2379
+ /** Places a function's opening brace on the next line. */
2380
+ FunctionNextLine?: boolean;
2381
+ }
2382
+
2383
+ /**
2384
+ * Upstream Printer.Print panicked for a representable tree or option value.
2385
+ * Partial and typed-nil trees can trigger this independently of root support.
2386
+ * Catching the panic preserves reuse of the binding's shared runtime.
2387
+ * @public
2388
+ */
2389
+ export declare class PrintPanicError extends ShAstError {
2390
+ /** Stable identity for an upstream panic caught at the Print operation. @public */
2391
+ readonly code = "SH_AST_SYNTAX_PRINT_PANIC";
2392
+ /** Exact panic rendering from Go; Error.message is only a display rendering. @public */
2393
+ readonly Message: GoString;
2394
+ /** Retains the panic message separately from ordinary returned Print errors. @public */
2395
+ constructor(message: GoString);
2396
+ }
2397
+
2398
+ /**
2399
+ * Formats the current tree with a fresh upstream printer and collects all output.
2400
+ * Supported roots are File, Stmt, Word, Assign, Command and WordPart; other Nodes
2401
+ * produce PrintError. Only File output has upstream's trailing-newline behavior.
2402
+ * Invalid UTF-8 output remains bytes. Upstream formatting can itself consume
2403
+ * input bytes, including its tabwriter escape byte, so this is not source replay.
2404
+ *
2405
+ * InputError identifies unrepresentable input; PrintError is an ordinary returned
2406
+ * upstream error; PrintPanicError retains an upstream operation panic. No partial
2407
+ * output or arbitrary writer lifecycle is exposed. Full tree reconstruction and
2408
+ * collected output require memory proportional to the values involved; extreme
2409
+ * indentation or tree size is not made resource-safe by panic adaptation.
2410
+ * @public
2411
+ */
2412
+ export declare function printSync(node: Node_2, options?: PrintOptions): GoString;
2413
+
2341
2414
  /**
2342
2415
  * The upstream ProcOperator domain: exact named tokens, the Go zero value, and explicitly validated unnamed uint32 values. Constants shared by upstream families retain their shared numeric identity.
2343
2416
  *
@@ -3695,6 +3768,53 @@ export declare const UpperAll: 97;
3695
3768
  */
3696
3769
  export declare const UpperFirst: 96;
3697
3770
 
3771
+ /**
3772
+ * Walks synchronously using the pinned upstream case ordering. Each accepted entry is followed by its
3773
+ * children and a null exit. Returning false prunes the entry without an exit;
3774
+ * boolean exit return values are ignored. Every callback must return a boolean
3775
+ * synchronously; other results produce InputError. Callback exceptions retain their identity,
3776
+ * and upstream deferred comment callbacks still run during exception unwinding.
3777
+ *
3778
+ * Children and later fields are read live. Each list captures its array reference
3779
+ * and length when traversal reaches that list, then reads existing later slots
3780
+ * when reached. Replacing or reordering later slots is observed and can cause
3781
+ * a node to be skipped or revisited. Indices added beyond the captured extent
3782
+ * are not visited by that active list. Replacing the owner's array field does not
3783
+ * redirect an active list, but a later walk or print sees the current field.
3784
+ * Changes made before a list is reached are observed when it starts.
3785
+ *
3786
+ * Supported edits preserve each node's Type (and TypedNil.Kind), required field
3787
+ * shapes and every index within each active list's captured extent. Leaving
3788
+ * holes or shrinking an array below that extent (for example through truncation,
3789
+ * deletion, or length-reducing splice/shift) is outside the mutation contract.
3790
+ * These are not runtime validation rules. Ordinary JavaScript object and array
3791
+ * aliases remain shared; the binding does not model distinct Go slice headers or
3792
+ * capacity-dependent allocation over shared backing storage.
3793
+ *
3794
+ * Comments on Stmt, CaseItem and ArrayElem are copied before their callbacks,
3795
+ * including position and byte-string values; editing a copy does not edit the
3796
+ * stored comment. Last/CondLast/ThenLast/DoLast callbacks receive the stored
3797
+ * JavaScript Comment object. Replacing its array slot leaves any previously
3798
+ * retained callback object unchanged: there is no Go value-slot pointer identity.
3799
+ * Reentrant walks maintain independent traversal state.
3800
+ * @public
3801
+ */
3802
+ export declare function walk(node: Node_2, callback: (node: Node_2 | null) => boolean): void;
3803
+
3804
+ /**
3805
+ * A panic raised by upstream-equivalent traversal, such as a nil dereference or
3806
+ * unsupported concrete node. Exceptions thrown by callbacks are never wrapped.
3807
+ * @public
3808
+ */
3809
+ export declare class WalkPanicError extends ShAstError {
3810
+ /** Stable discriminator for traversal panics. @public */
3811
+ readonly code = "SH_AST_WALK_PANIC";
3812
+ /** Exact upstream panic bytes; Error.message is only a display rendering. @public */
3813
+ readonly Message: GoString;
3814
+ /** Retains the upstream panic text separately from its display rendering. @public */
3815
+ constructor(message: GoString);
3816
+ }
3817
+
3698
3818
  /**
3699
3819
  * WhileClause represents a while or an until clause.
3700
3820
  *
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Printing has two upstream failure modes: returned errors and panics raised by
3
+ * the operation. Both retain exact message bytes; neither is a parser failure
4
+ * or a claim that the transport itself malfunctioned.
5
+ */
6
+ import type { GoString } from '../generated/syntax-types.js';
7
+ import { ShAstError } from './errors.js';
8
+ /**
9
+ * An error returned by upstream Printer.Print, such as an unsupported root or
10
+ * incompatible formatting options. No partial writer output is exposed.
11
+ * @public
12
+ */
13
+ export declare class PrintError extends ShAstError {
14
+ /** Stable identity for an ordinary error returned by upstream Print. @public */
15
+ readonly code = "SH_AST_SYNTAX_PRINT";
16
+ /** Exact upstream error bytes; Error.message is only a display rendering. @public */
17
+ readonly Message: GoString;
18
+ /** Retains the upstream error without interpreting its human-readable text. @public */
19
+ constructor(message: GoString);
20
+ }
21
+ /**
22
+ * Upstream Printer.Print panicked for a representable tree or option value.
23
+ * Partial and typed-nil trees can trigger this independently of root support.
24
+ * Catching the panic preserves reuse of the binding's shared runtime.
25
+ * @public
26
+ */
27
+ export declare class PrintPanicError extends ShAstError {
28
+ /** Stable identity for an upstream panic caught at the Print operation. @public */
29
+ readonly code = "SH_AST_SYNTAX_PRINT_PANIC";
30
+ /** Exact panic rendering from Go; Error.message is only a display rendering. @public */
31
+ readonly Message: GoString;
32
+ /** Retains the panic message separately from ordinary returned Print errors. @public */
33
+ constructor(message: GoString);
34
+ }
35
+ //# sourceMappingURL=syntax-print-errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax-print-errors.d.ts","sourceRoot":"","sources":["../src/syntax-print-errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;GAIG;AACH,qBAAa,UAAW,SAAQ,UAAU;IACxC,gFAAgF;IAChF,QAAQ,CAAC,IAAI,yBAAyB;IAEtC,qFAAqF;IACrF,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAE3B,uFAAuF;gBAC3E,OAAO,EAAE,QAAQ;CAK9B;AAED;;;;;GAKG;AACH,qBAAa,eAAgB,SAAQ,UAAU;IAC7C,mFAAmF;IACnF,QAAQ,CAAC,IAAI,+BAA+B;IAE5C,wFAAwF;IACxF,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAE3B,wFAAwF;gBAC5E,OAAO,EAAE,QAAQ;CAK9B"}
@@ -0,0 +1,37 @@
1
+ import { ShAstError } from './errors.js';
2
+ /**
3
+ * An error returned by upstream Printer.Print, such as an unsupported root or
4
+ * incompatible formatting options. No partial writer output is exposed.
5
+ * @public
6
+ */
7
+ export class PrintError extends ShAstError {
8
+ /** Stable identity for an ordinary error returned by upstream Print. @public */
9
+ code = 'SH_AST_SYNTAX_PRINT';
10
+ /** Exact upstream error bytes; Error.message is only a display rendering. @public */
11
+ Message;
12
+ /** Retains the upstream error without interpreting its human-readable text. @public */
13
+ constructor(message) {
14
+ super(typeof message === 'string' ? message : new TextDecoder().decode(message));
15
+ this.Message = message;
16
+ this.name = 'PrintError';
17
+ }
18
+ }
19
+ /**
20
+ * Upstream Printer.Print panicked for a representable tree or option value.
21
+ * Partial and typed-nil trees can trigger this independently of root support.
22
+ * Catching the panic preserves reuse of the binding's shared runtime.
23
+ * @public
24
+ */
25
+ export class PrintPanicError extends ShAstError {
26
+ /** Stable identity for an upstream panic caught at the Print operation. @public */
27
+ code = 'SH_AST_SYNTAX_PRINT_PANIC';
28
+ /** Exact panic rendering from Go; Error.message is only a display rendering. @public */
29
+ Message;
30
+ /** Retains the panic message separately from ordinary returned Print errors. @public */
31
+ constructor(message) {
32
+ super(typeof message === 'string' ? message : new TextDecoder().decode(message));
33
+ this.Message = message;
34
+ this.name = 'PrintPanicError';
35
+ }
36
+ }
37
+ //# sourceMappingURL=syntax-print-errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax-print-errors.js","sourceRoot":"","sources":["../src/syntax-print-errors.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;GAIG;AACH,MAAM,OAAO,UAAW,SAAQ,UAAU;IACxC,gFAAgF;IACvE,IAAI,GAAG,qBAAqB,CAAC;IAEtC,qFAAqF;IAC5E,OAAO,CAAW;IAE3B,uFAAuF;IACvF,YAAY,OAAiB;QAC3B,KAAK,CAAC,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QACjF,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,OAAO,eAAgB,SAAQ,UAAU;IAC7C,mFAAmF;IAC1E,IAAI,GAAG,2BAA2B,CAAC;IAE5C,wFAAwF;IAC/E,OAAO,CAAW;IAE3B,wFAAwF;IACxF,YAAY,OAAiB;QAC3B,KAAK,CAAC,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QACjF,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Collected-output access to upstream Printer.Print. The reverse codec rebuilds
3
+ * the current faithful tree, and Go owns formatting decisions. This module has
4
+ * no source cache, parser round trip, writer callbacks, or reusable printer state.
5
+ */
6
+ import type { GoString, Node } from '../generated/syntax-types.js';
7
+ /**
8
+ * Upstream NewPrinter controls applied to a fresh printer for each call. All
9
+ * flags default to false; zero indentation selects tabs. The pinned WASM uint
10
+ * domain is 64-bit, so Indent accepts bigint beyond JavaScript's safe integers.
11
+ * @public
12
+ */
13
+ export interface PrintOptions {
14
+ /** Spaces per level, or zero for tabs. Large values can request expensive output. */
15
+ Indent?: number | bigint;
16
+ /** Places multiline binary operators on the next line with a backslash continuation. */
17
+ BinaryNextLine?: boolean;
18
+ /** Indents case alternatives, placing their bodies two levels below the case clause. */
19
+ SwitchCaseIndent?: boolean;
20
+ /** Adds space after redirection operators except `>&`, `<&`, `>(` and `<(`. */
21
+ SpaceRedirects?: boolean;
22
+ /**
23
+ * Preserves token columns on a best-effort basis.
24
+ * @deprecated Upstream marks this option as flawed and plans removal in v4.
25
+ */
26
+ KeepPadding?: boolean;
27
+ /** Omits comments, indentation and optional whitespace. Incompatible with SingleLine. */
28
+ Minify?: boolean;
29
+ /** Reduces newlines except where comments, heredocs or File output require them. */
30
+ SingleLine?: boolean;
31
+ /** Places a function's opening brace on the next line. */
32
+ FunctionNextLine?: boolean;
33
+ }
34
+ /**
35
+ * Formats the current tree with a fresh upstream printer and collects all output.
36
+ * Supported roots are File, Stmt, Word, Assign, Command and WordPart; other Nodes
37
+ * produce PrintError. Only File output has upstream's trailing-newline behavior.
38
+ * Invalid UTF-8 output remains bytes. Upstream formatting can itself consume
39
+ * input bytes, including its tabwriter escape byte, so this is not source replay.
40
+ *
41
+ * InputError identifies unrepresentable input; PrintError is an ordinary returned
42
+ * upstream error; PrintPanicError retains an upstream operation panic. No partial
43
+ * output or arbitrary writer lifecycle is exposed. Full tree reconstruction and
44
+ * collected output require memory proportional to the values involved; extreme
45
+ * indentation or tree size is not made resource-safe by panic adaptation.
46
+ * @public
47
+ */
48
+ export declare function printSync(node: Node, options?: PrintOptions): GoString;
49
+ //# sourceMappingURL=syntax-print.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax-print.d.ts","sourceRoot":"","sources":["../src/syntax-print.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAOnE;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,qFAAqF;IACrF,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,wFAAwF;IACxF,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wFAAwF;IACxF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,+EAA+E;IAC/E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yFAAyF;IACzF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oFAAoF;IACpF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0DAA0D;IAC1D,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,YAAiB,GAAG,QAAQ,CAoC1E"}
@@ -0,0 +1,86 @@
1
+ import { ShInternalError } from './errors.js';
2
+ import { InputError } from './syntax-errors.js';
3
+ import { PrintError, PrintPanicError } from './syntax-print-errors.js';
4
+ import { decodeWire, encodeWire, isGoString, isRecord, isSyntaxNode } from './syntax-wire.js';
5
+ import { callSyntax } from './wasm-instance.js';
6
+ /**
7
+ * Formats the current tree with a fresh upstream printer and collects all output.
8
+ * Supported roots are File, Stmt, Word, Assign, Command and WordPart; other Nodes
9
+ * produce PrintError. Only File output has upstream's trailing-newline behavior.
10
+ * Invalid UTF-8 output remains bytes. Upstream formatting can itself consume
11
+ * input bytes, including its tabwriter escape byte, so this is not source replay.
12
+ *
13
+ * InputError identifies unrepresentable input; PrintError is an ordinary returned
14
+ * upstream error; PrintPanicError retains an upstream operation panic. No partial
15
+ * output or arbitrary writer lifecycle is exposed. Full tree reconstruction and
16
+ * collected output require memory proportional to the values involved; extreme
17
+ * indentation or tree size is not made resource-safe by panic adaptation.
18
+ * @public
19
+ */
20
+ export function printSync(node, options = {}) {
21
+ validatePrintOptions(options);
22
+ if (!isSyntaxNode(node)) {
23
+ throw new InputError('Expected a complete, acyclic upstream Node record');
24
+ }
25
+ const payload = new TextEncoder().encode(encodeWire(node));
26
+ const result = decodeWire(callSyntax('print', payload, encodeWire(options)));
27
+ if (!isRecord(result)) {
28
+ throw new ShInternalError('The syntax printer returned a non-record response');
29
+ }
30
+ if (result.Error !== undefined) {
31
+ const error = result.Error;
32
+ if (!isRecord(error) || !isGoString(error.Message)) {
33
+ throw new ShInternalError('The syntax printer returned a malformed error');
34
+ }
35
+ switch (error.Kind) {
36
+ case 'PrintError':
37
+ throw new PrintError(error.Message);
38
+ case 'PrintPanicError':
39
+ throw new PrintPanicError(error.Message);
40
+ case 'InputError':
41
+ throw new InputError(error.Message);
42
+ case 'InternalError':
43
+ throw new ShInternalError(typeof error.Message === 'string'
44
+ ? error.Message
45
+ : new TextDecoder().decode(error.Message));
46
+ default:
47
+ throw new ShInternalError('The syntax printer returned an unknown error kind');
48
+ }
49
+ }
50
+ if (!isGoString(result.Output)) {
51
+ throw new ShInternalError('The syntax printer returned an invalid output value');
52
+ }
53
+ return result.Output;
54
+ }
55
+ /** Validates exact option domains without imposing a formatting or indentation policy. */
56
+ function validatePrintOptions(options) {
57
+ if (!isRecord(options)) {
58
+ throw new InputError('Printer options must be a data record');
59
+ }
60
+ const flags = new Set([
61
+ 'BinaryNextLine',
62
+ 'SwitchCaseIndent',
63
+ 'SpaceRedirects',
64
+ 'KeepPadding',
65
+ 'Minify',
66
+ 'SingleLine',
67
+ 'FunctionNextLine',
68
+ ]);
69
+ for (const [name, value] of Object.entries(options)) {
70
+ if (name === 'Indent') {
71
+ const valid = typeof value === 'bigint'
72
+ ? value >= 0n && value <= 0xffffffffffffffffn
73
+ : typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
74
+ if (!valid) {
75
+ throw new InputError('Indent must be a safe nonnegative integer or uint64 bigint');
76
+ }
77
+ }
78
+ else if (!flags.has(name)) {
79
+ throw new InputError(`Unknown printer option: ${name}`);
80
+ }
81
+ else if (typeof value !== 'boolean') {
82
+ throw new InputError(`${name} must be boolean`);
83
+ }
84
+ }
85
+ }
86
+ //# sourceMappingURL=syntax-print.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax-print.js","sourceRoot":"","sources":["../src/syntax-print.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Private live boundary evaluation for Walk's comment placement. These methods
3
+ * mirror the pinned mvdan/sh node methods so callback edits are visible without
4
+ * repeatedly serializing subtrees to WASM. They are not public position APIs.
5
+ *
6
+ * Adapted from mvdan.cc/sh/v3 v3.13.1 syntax/nodes.go, copyright Daniel Martí.
7
+ * The upstream BSD license is retained in syntax-walk-license.ts.
8
+ */
9
+ import type { Node, SyntaxPos } from '../generated/syntax-types.js';
10
+ /** Stmt comments at or after the live end become the single deferred comment. @internal */
11
+ export declare function atStatementEnd(node: Extract<Node, {
12
+ Type: 'Stmt';
13
+ }>, hash: SyntaxPos): boolean;
14
+ /** Case/array comments strictly after the live start become deferred. @internal */
15
+ export declare function afterItemStart(node: Extract<Node, {
16
+ Type: 'CaseItem' | 'ArrayElem';
17
+ }>, hash: SyntaxPos): boolean;
18
+ //# sourceMappingURL=syntax-walk-bounds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax-walk-bounds.d.ts","sourceRoot":"","sources":["../src/syntax-walk-bounds.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AA6LpE,2FAA2F;AAC3F,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAE9F;AACD,mFAAmF;AACnF,wBAAgB,cAAc,CAC5B,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,UAAU,GAAG,WAAW,CAAA;CAAE,CAAC,EACvD,IAAI,EAAE,SAAS,GACd,OAAO,CAET"}