jsonc-effect 0.1.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 (4) hide show
  1. package/README.md +17 -0
  2. package/index.d.ts +1375 -143
  3. package/index.js +410 -380
  4. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -16,8 +16,49 @@ import { Stream } from 'effect';
16
16
  import { YieldableError } from 'effect/Cause';
17
17
 
18
18
  /**
19
- * Apply an array of edits to JSONC source text.
20
- * Edits are applied in reverse offset order to avoid offset shifting.
19
+ * Apply an array of text edits to JSONC source text.
20
+ *
21
+ * This is a {@link https://effect.website/docs/function-dual | Function.dual}
22
+ * that supports both data-first and data-last (pipeline) usage.
23
+ *
24
+ * @param text - The original JSONC source text.
25
+ * @param edits - A read-only array of {@link JsoncEdit} objects, typically
26
+ * produced by {@link format} or {@link modify}.
27
+ * @returns An `Effect` that succeeds with the edited string.
28
+ *
29
+ * @remarks
30
+ * Edits are sorted in reverse offset order before application so that
31
+ * earlier edits do not shift the offsets of later ones. The original `edits`
32
+ * array is not mutated.
33
+ *
34
+ * @see {@link format} to compute formatting edits.
35
+ * @see {@link modify} to compute structural edits (insert, replace, remove).
36
+ *
37
+ * @example Data-first usage
38
+ * ```ts
39
+ * import { Effect } from "effect";
40
+ * import { format, applyEdits } from "jsonc-effect";
41
+ *
42
+ * const input = '{"a":1}';
43
+ * const edits = Effect.runSync(format(input));
44
+ * const result: string = Effect.runSync(applyEdits(input, edits));
45
+ * ```
46
+ *
47
+ * @example Pipeline with modify
48
+ * ```ts
49
+ * import { Effect, pipe } from "effect";
50
+ * import { modify, applyEdits } from "jsonc-effect";
51
+ *
52
+ * const input = '{ "a": 1 }';
53
+ * const result = pipe(
54
+ * input,
55
+ * modify(["a"], 42),
56
+ * Effect.flatMap((edits) => applyEdits(input, edits)),
57
+ * Effect.runSync,
58
+ * );
59
+ * ```
60
+ *
61
+ * @public
21
62
  */
22
63
  export declare const applyEdits: {
23
64
  (edits: ReadonlyArray<JsoncEdit>): (text: string) => Effect.Effect<string>;
@@ -25,35 +66,232 @@ export declare const applyEdits: {
25
66
  };
26
67
 
27
68
  /**
28
- * Create a JSONC scanner.
69
+ * Create a stateful {@link JsoncScanner} for the given JSONC string.
70
+ *
71
+ * @param text - JSONC string to tokenize
72
+ * @param ignoreTrivia - If `true`, the scanner automatically skips whitespace,
73
+ * line-break, and comment tokens so that only structural tokens are returned
74
+ * (default: `false`).
75
+ * @returns A stateful {@link JsoncScanner} positioned before the first token.
76
+ *
77
+ * @remarks
78
+ * When `ignoreTrivia` is `true` the scanner is suitable for building parsers
79
+ * that only care about structural tokens (`OpenBrace`, `String`, `Number`,
80
+ * etc.). Set it to `false` (the default) when you need to preserve comments
81
+ * or whitespace — for example in a formatter or a comment-stripping pass.
82
+ *
83
+ * @see {@link JsoncScanner} — the interface returned by this factory
84
+ * @see {@link parse} — higher-level API that uses a scanner internally
85
+ *
86
+ * @example
87
+ * Tokenizing a JSONC string and printing each token:
88
+ * ```ts
89
+ * import type { JsoncSyntaxKind } from "jsonc-effect";
90
+ * import { createScanner } from "jsonc-effect";
91
+ *
92
+ * const scanner = createScanner('{ "name": "jsonc" }', true);
93
+ * let kind: JsoncSyntaxKind;
94
+ * do {
95
+ * kind = scanner.scan();
96
+ * console.log(kind, scanner.getTokenValue());
97
+ * } while (kind !== "EOF");
98
+ * ```
99
+ *
100
+ * @privateRemarks
101
+ * Ported from Microsoft's jsonc-parser (MIT), adapted to use string literal
102
+ * token types instead of numeric enums.
29
103
  *
30
- * @param text - The JSONC string to scan
31
- * @param ignoreTrivia - If true, skip whitespace, line breaks, and comments
32
- * @returns A JsoncScanner for iterating over tokens
104
+ * @public
33
105
  */
34
106
  export declare const createScanner: (text: string, ignoreTrivia?: boolean) => JsoncScanner;
35
107
 
36
108
  /**
37
- * Find a node at a specific path in the AST.
109
+ * Compare two JSONC strings for semantic equality.
38
110
  *
39
- * Traverses the AST following property names (strings) and
40
- * array indices (numbers) in the path.
111
+ * Supports {@link https://effect.website/docs/effect/function#dual | Function.dual}
112
+ * for both data-first and data-last (pipeline) usage.
41
113
  *
42
- * @example
114
+ * @param self - The first JSONC string.
115
+ * @param that - The second JSONC string.
116
+ *
117
+ * @returns `Effect<boolean, JsoncParseError>` — `true` when both strings parse to
118
+ * semantically equivalent values, `false` otherwise. Fails with
119
+ * {@link JsoncParseError} if either string is malformed.
120
+ *
121
+ * @remarks
122
+ * Both strings are parsed via {@link parse} and then deep-compared. The comparison
123
+ * ignores comments, whitespace, formatting, and object key ordering. Array order
124
+ * IS significant. Uses `Effect.all` internally, so the effect fails on the first
125
+ * parse error encountered.
126
+ *
127
+ * @see {@link equalsValue} — compare a JSONC string against an existing JS value
128
+ * @see {@link parse} — the underlying parser used for both strings
129
+ *
130
+ * @example Data-first comparison
43
131
  * ```ts
44
- * import { Effect, Option, pipe } from "effect";
45
- * import { parseTree, findNode } from "@spencerbeggs/jsonc-effect";
132
+ * import { Effect } from "effect";
133
+ * import { equals } from "jsonc-effect";
134
+ *
135
+ * const result = Effect.runSync(
136
+ * equals('{ "a": 1, "b": 2 }', '{"b":2,"a":1}')
137
+ * );
138
+ * // result is true
139
+ * ```
140
+ *
141
+ * @example Key-order independence
142
+ * ```ts
143
+ * import { Effect } from "effect";
144
+ * import { equals } from "jsonc-effect";
145
+ *
146
+ * // Object key order does not matter
147
+ * const sameKeys = Effect.runSync(
148
+ * equals('{"z":1,"a":2}', '{"a":2,"z":1}')
149
+ * );
150
+ * // sameKeys is true
151
+ *
152
+ * // Array order DOES matter
153
+ * const differentOrder = Effect.runSync(
154
+ * equals('[1, 2]', '[2, 1]')
155
+ * );
156
+ * // differentOrder is false
157
+ * ```
158
+ *
159
+ * @example Error handling
160
+ * ```ts
161
+ * import { Effect, Either } from "effect";
162
+ * import type { JsoncParseError } from "jsonc-effect";
163
+ * import { equals } from "jsonc-effect";
164
+ *
165
+ * const result: Either.Either<boolean, JsoncParseError> = Effect.runSync(
166
+ * Effect.either(equals('{ invalid }', '{}'))
167
+ * );
168
+ * // result is Either.left(JsoncParseError)
169
+ * ```
170
+ *
171
+ * @privateRemarks
172
+ * Uses a simple recursive `deepEqual` helper rather than Effect's `Equal` module
173
+ * because the parsed values are plain JS objects and arrays, not Effect data types.
174
+ *
175
+ * @public
176
+ */
177
+ export declare const equals: {
178
+ (that: string): (self: string) => Effect.Effect<boolean, JsoncParseError>;
179
+ (self: string, that: string): Effect.Effect<boolean, JsoncParseError>;
180
+ };
181
+
182
+ /**
183
+ * Compare a JSONC string against a JavaScript value for semantic equality.
184
+ *
185
+ * Supports {@link https://effect.website/docs/effect/function#dual | Function.dual}
186
+ * for both data-first and data-last (pipeline) usage.
187
+ *
188
+ * @param self - The JSONC string to parse.
189
+ * @param value - The JavaScript value to compare against.
190
+ *
191
+ * @returns `Effect<boolean, JsoncParseError>` — `true` when the parsed JSONC
192
+ * is semantically equivalent to the provided value, `false` otherwise.
193
+ * Fails with {@link JsoncParseError} if the string is malformed.
194
+ *
195
+ * @remarks
196
+ * Only the JSONC string is parsed; the JS value is used as-is. This makes
197
+ * `equalsValue` useful for assertions and testing where the expected value
198
+ * is already a JS object. The comparison semantics are the same as
199
+ * {@link equals}: comments, whitespace, formatting, and object key ordering
200
+ * are ignored, while array order IS significant.
201
+ *
202
+ * @see {@link equals} — compare two JSONC strings against each other
203
+ * @see {@link parse} — the underlying parser
204
+ *
205
+ * @example Basic comparison
206
+ * ```ts
207
+ * import { Effect } from "effect";
208
+ * import { equalsValue } from "jsonc-effect";
209
+ *
210
+ * const result = Effect.runSync(
211
+ * equalsValue('{"port": 3000, "host": "localhost"}', { host: "localhost", port: 3000 })
212
+ * );
213
+ * // result is true
214
+ * ```
215
+ *
216
+ * @example Pipeline usage for testing
217
+ * ```ts
218
+ * import { Effect, pipe } from "effect";
219
+ * import { equalsValue } from "jsonc-effect";
220
+ *
221
+ * const jsonc = '{ "enabled": true, "count": 5 }';
222
+ * const expected = { enabled: true, count: 5 };
223
+ *
224
+ * const result = Effect.runSync(
225
+ * pipe(jsonc, equalsValue(expected))
226
+ * );
227
+ * // result is true
228
+ * ```
229
+ *
230
+ * @public
231
+ */
232
+ export declare const equalsValue: {
233
+ (value: unknown): (self: string) => Effect.Effect<boolean, JsoncParseError>;
234
+ (self: string, value: unknown): Effect.Effect<boolean, JsoncParseError>;
235
+ };
236
+
237
+ /**
238
+ * Find an AST node at a specific JSON path.
46
239
  *
47
- * // Data-first
48
- * const node = Effect.gen(function* () {
49
- * const root = yield* parseTree('{ "a": { "b": 1 } }');
240
+ * Supports {@link https://effect.website/docs/effect/function#dual | Function.dual}
241
+ * for both data-first and data-last (pipeline) usage.
242
+ *
243
+ * @param root - The AST root node obtained from {@link parseTree}.
244
+ * @param path - An array of string keys and numeric indices describing the path to traverse.
245
+ *
246
+ * @returns `Effect<Option<JsoncNode>>` — the node at the given path, or `Option.none()` if the
247
+ * path does not exist in the tree.
248
+ *
249
+ * @remarks
250
+ * String segments navigate object properties and number segments navigate array indices.
251
+ * Returns `Option.none()` when any segment along the path cannot be resolved — for example,
252
+ * accessing a property on a non-object node or an out-of-bounds array index.
253
+ *
254
+ * @see {@link parseTree} — produces the AST root this function operates on
255
+ * @see {@link getNodeValue} — reconstructs a JS value from a found node
256
+ * @see {@link JsoncNode} — the AST node type
257
+ * @see {@link JsoncPath} — the path segment array type
258
+ *
259
+ * @example Data-first usage
260
+ * ```ts
261
+ * import { Effect, Option } from "effect";
262
+ * import type { JsoncNode } from "jsonc-effect";
263
+ * import { parseTree, findNode } from "jsonc-effect";
264
+ *
265
+ * const program = Effect.gen(function* () {
266
+ * const root: Option.Option<JsoncNode> = yield* parseTree('{ "a": { "b": 1 } }');
50
267
  * if (Option.isNone(root)) return Option.none();
51
268
  * return yield* findNode(root.value, ["a", "b"]);
52
269
  * });
53
270
  *
54
- * // Data-last (pipeline)
55
- * const node2 = pipe(root, findNode(["a", "b"]));
271
+ * const result = Effect.runSync(program);
272
+ * // result is Option.some(node) where node.value === 1
273
+ * ```
274
+ *
275
+ * @example Data-last pipeline usage
276
+ * ```ts
277
+ * import { Effect, Option, pipe } from "effect";
278
+ * import type { JsoncNode } from "jsonc-effect";
279
+ * import { parseTree, findNode } from "jsonc-effect";
280
+ *
281
+ * const program = Effect.gen(function* () {
282
+ * const root: Option.Option<JsoncNode> = yield* parseTree('{ "x": [10, 20] }');
283
+ * if (Option.isNone(root)) return Option.none();
284
+ * return yield* pipe(root.value, findNode(["x", 1]));
285
+ * });
286
+ *
287
+ * const result = Effect.runSync(program);
288
+ * // result is Option.some(node) where node.value === 20
56
289
  * ```
290
+ *
291
+ * @privateRemarks
292
+ * Wrapped in `Effect.sync`; the underlying traversal is fully synchronous.
293
+ *
294
+ * @public
57
295
  */
58
296
  export declare const findNode: {
59
297
  (path: JsoncPath): (root: JsoncNode) => Effect.Effect<Option.Option<JsoncNode>>;
@@ -61,16 +299,45 @@ export declare const findNode: {
61
299
  };
62
300
 
63
301
  /**
64
- * Find the innermost node covering a character offset.
302
+ * Find the innermost AST node covering a character offset.
65
303
  *
66
- * @example
304
+ * Supports {@link https://effect.website/docs/effect/function#dual | Function.dual}
305
+ * for both data-first and data-last (pipeline) usage.
306
+ *
307
+ * @param root - The AST root node obtained from {@link parseTree}.
308
+ * @param offset - A zero-based character offset into the original JSONC string.
309
+ *
310
+ * @returns `Effect<Option<JsoncNode>>` — the most deeply nested node whose span
311
+ * includes the offset, or `Option.none()` if the offset is outside the tree.
312
+ *
313
+ * @remarks
314
+ * This is useful for editor integrations such as hover information, go-to-definition,
315
+ * and code completions where you need to identify the token under the cursor.
316
+ *
317
+ * @see {@link parseTree} — produces the AST root this function operates on
318
+ * @see {@link getNodePath} — returns the JSON path to the node at an offset
319
+ *
320
+ * @example Finding a node at an offset
67
321
  * ```ts
68
- * import { Effect, Option, pipe } from "effect";
69
- * import { parseTree, findNodeAtOffset } from "@spencerbeggs/jsonc-effect";
322
+ * import { Effect, Option } from "effect";
323
+ * import type { JsoncNode } from "jsonc-effect";
324
+ * import { parseTree, findNodeAtOffset } from "jsonc-effect";
325
+ *
326
+ * const program = Effect.gen(function* () {
327
+ * const root: Option.Option<JsoncNode> = yield* parseTree('{ "key": "value" }');
328
+ * if (Option.isNone(root)) return Option.none();
329
+ * // Offset 10 is inside the "value" string literal
330
+ * return yield* findNodeAtOffset(root.value, 10);
331
+ * });
70
332
  *
71
- * // Data-last (pipeline)
72
- * const node = pipe(root, findNodeAtOffset(5));
333
+ * const result = Effect.runSync(program);
334
+ * // result is Option.some(node) where node.type === "string"
73
335
  * ```
336
+ *
337
+ * @privateRemarks
338
+ * Wrapped in `Effect.sync`; the underlying traversal is fully synchronous.
339
+ *
340
+ * @public
74
341
  */
75
342
  export declare const findNodeAtOffset: {
76
343
  (offset: number): (root: JsoncNode) => Effect.Effect<Option.Option<JsoncNode>>;
@@ -80,36 +347,115 @@ export declare const findNodeAtOffset: {
80
347
  /**
81
348
  * Compute formatting edits for a JSONC document.
82
349
  *
83
- * Does NOT mutate the input returns an array of edits to apply
84
- * with applyEdits().
350
+ * Returns an array of {@link JsoncEdit} objects describing text replacements
351
+ * that, when applied, produce a well-formatted document. The input text is
352
+ * never mutated — apply the returned edits with {@link applyEdits}.
353
+ *
354
+ * @param text - The JSONC source text to format.
355
+ * @param range - Optional sub-range to format. When provided, only edits
356
+ * within the range are returned.
357
+ * @param options - Partial {@link JsoncFormattingOptions} controlling indent
358
+ * size, tabs vs. spaces, EOL style, and final-newline insertion.
359
+ * @returns An `Effect` that succeeds with a read-only array of
360
+ * {@link JsoncEdit} objects.
361
+ *
362
+ * @remarks
363
+ * This function is non-mutating by design. It computes a minimal set of
364
+ * whitespace edits; structural changes (inserting or removing properties)
365
+ * are handled by {@link modify}. The `range` parameter allows formatting a
366
+ * subset of the document without touching surrounding text.
367
+ *
368
+ * @see {@link applyEdits} to apply the returned edits to the source text.
369
+ * @see {@link formatAndApply} for a one-step format-and-apply convenience.
370
+ * @see {@link JsoncFormattingOptions} for available formatting controls.
85
371
  *
86
372
  * @example
87
373
  * ```ts
88
374
  * import { Effect } from "effect";
89
- * import { format, applyEdits } from "@spencerbeggs/jsonc-effect";
375
+ * import type { JsoncEdit } from "jsonc-effect";
376
+ * import { format, applyEdits } from "jsonc-effect";
90
377
  *
91
- * const edits = Effect.runSync(format('{"a":1}'));
92
- * const formatted = Effect.runSync(applyEdits('{"a":1}', edits));
378
+ * const input = '{"a":1, "b" :2}';
379
+ * const edits: ReadonlyArray<JsoncEdit> = Effect.runSync(format(input));
380
+ * const formatted: string = Effect.runSync(applyEdits(input, edits));
93
381
  * ```
382
+ *
383
+ * @privateRemarks
384
+ * Uses {@link createScanner} internally to tokenize the input and compute
385
+ * whitespace adjustments between consecutive non-trivia tokens.
386
+ *
387
+ * @public
94
388
  */
95
389
  export declare const format: (text: string, range?: JsoncRange | undefined, options?: Partial<JsoncFormattingOptions> | undefined) => Effect.Effect<readonly JsoncEdit[], never, never>;
96
390
 
97
391
  /**
98
- * Format a JSONC document in one step (format + apply).
392
+ * Format a JSONC document in one step by computing edits and immediately
393
+ * applying them.
394
+ *
395
+ * This is a convenience that combines {@link format} and {@link applyEdits}
396
+ * into a single call.
397
+ *
398
+ * @param text - The JSONC source text to format.
399
+ * @param range - Optional sub-range to restrict formatting to.
400
+ * @param options - Partial {@link JsoncFormattingOptions} controlling indent
401
+ * size, tabs vs. spaces, EOL style, and final-newline insertion.
402
+ * @returns An `Effect` that succeeds with the fully formatted string.
403
+ *
404
+ * @see {@link format} to obtain the edits without applying them.
405
+ * @see {@link applyEdits} to apply edits separately.
406
+ *
407
+ * @example
408
+ * ```ts
409
+ * import { Effect } from "effect";
410
+ * import { formatAndApply } from "jsonc-effect";
411
+ *
412
+ * const input = '{"a":1, "b" :2}';
413
+ * const formatted: string = Effect.runSync(formatAndApply(input));
414
+ * ```
415
+ *
416
+ * @public
99
417
  */
100
418
  export declare const formatAndApply: (text: string, range?: JsoncRange | undefined, options?: Partial<JsoncFormattingOptions> | undefined) => Effect.Effect<string, never, never>;
101
419
 
102
420
  /**
103
- * Get the JSON path to the node at a specific offset.
421
+ * Get the JSON path to the node at a specific character offset.
104
422
  *
105
- * @example
423
+ * Supports {@link https://effect.website/docs/effect/function#dual | Function.dual}
424
+ * for both data-first and data-last (pipeline) usage.
425
+ *
426
+ * @param root - The AST root node obtained from {@link parseTree}.
427
+ * @param targetOffset - A zero-based character offset into the original JSONC string.
428
+ *
429
+ * @returns `Effect<Option<JsoncPath>>` — an array of path segments (string keys
430
+ * and numeric indices) leading to the innermost node at the offset, or
431
+ * `Option.none()` if the offset is outside the tree.
432
+ *
433
+ * @remarks
434
+ * Returns the path segments leading to the innermost node that spans the given
435
+ * offset. This is the inverse of {@link findNode} — given an offset you get the path,
436
+ * and given a path you get the node.
437
+ *
438
+ * @see {@link findNodeAtOffset} — returns the node itself rather than its path
439
+ * @see {@link JsoncPath} — the path segment array type
440
+ *
441
+ * @example Getting the path at an offset
106
442
  * ```ts
107
- * import { Effect, pipe } from "effect";
108
- * import { parseTree, getNodePath } from "@spencerbeggs/jsonc-effect";
443
+ * import { Effect, Option } from "effect";
444
+ * import type { JsoncNode, JsoncPath } from "jsonc-effect";
445
+ * import { parseTree, getNodePath } from "jsonc-effect";
109
446
  *
110
- * // Data-last (pipeline)
111
- * const path = pipe(root, getNodePath(5));
447
+ * const program = Effect.gen(function* () {
448
+ * const root: Option.Option<JsoncNode> = yield* parseTree('{ "a": { "b": 42 } }');
449
+ * if (Option.isNone(root)) return Option.none();
450
+ * // Offset 15 points inside the value 42
451
+ * return yield* getNodePath(root.value, 15);
452
+ * });
453
+ *
454
+ * const result: Option.Option<JsoncPath> = Effect.runSync(program);
455
+ * // result is Option.some(["a", "b"])
112
456
  * ```
457
+ *
458
+ * @public
113
459
  */
114
460
  export declare const getNodePath: {
115
461
  (targetOffset: number): (root: JsoncNode) => Effect.Effect<Option.Option<JsoncPath>>;
@@ -117,13 +463,78 @@ export declare const getNodePath: {
117
463
  };
118
464
 
119
465
  /**
120
- * Evaluate a node subtree into a plain JavaScript value.
121
- * Reconstructs objects and arrays from the AST.
466
+ * Reconstruct a plain JavaScript value from an AST subtree.
467
+ *
468
+ * @param node - The AST node to evaluate, typically obtained via {@link findNode} or
469
+ * as the root from {@link parseTree}.
470
+ *
471
+ * @returns `Effect<unknown>` — the reconstructed JS value (object, array, string,
472
+ * number, boolean, or null).
473
+ *
474
+ * @remarks
475
+ * Recursively evaluates the node tree to produce a plain JavaScript value.
476
+ * This is the inverse of {@link parseTree}: where `parseTree` turns a JSONC string
477
+ * into an AST, `getNodeValue` turns an AST subtree back into a JS value.
478
+ *
479
+ * @see {@link parseTree} — produces the AST that this function evaluates
480
+ * @see {@link findNode} — locates a subtree to pass to this function
481
+ *
482
+ * @example Extracting the value of a found node
483
+ * ```ts
484
+ * import { Effect, Option } from "effect";
485
+ * import type { JsoncNode } from "jsonc-effect";
486
+ * import { parseTree, findNode, getNodeValue } from "jsonc-effect";
487
+ *
488
+ * const program = Effect.gen(function* () {
489
+ * const root: Option.Option<JsoncNode> = yield* parseTree('{ "items": [1, 2, 3] }');
490
+ * if (Option.isNone(root)) return undefined;
491
+ * const node: Option.Option<JsoncNode> = yield* findNode(root.value, ["items"]);
492
+ * if (Option.isNone(node)) return undefined;
493
+ * return yield* getNodeValue(node.value);
494
+ * });
495
+ *
496
+ * const result = Effect.runSync(program);
497
+ * // result is [1, 2, 3]
498
+ * ```
499
+ *
500
+ * @privateRemarks
501
+ * Useful after {@link findNode} to extract a subtree's value without manual
502
+ * AST traversal.
503
+ *
504
+ * @public
122
505
  */
123
506
  export declare const getNodeValue: (node: JsoncNode) => Effect.Effect<unknown, never, never>;
124
507
 
125
508
  /**
126
- * A text edit to apply to a JSONC document.
509
+ * A non-mutating text edit describing a replacement within a JSONC document.
510
+ *
511
+ * @remarks
512
+ * Edits use zero-based `offset` and `length` to identify the span of text
513
+ * to replace, and `content` for the replacement string. To insert without
514
+ * removing text, set `length` to `0`. To delete without inserting, set
515
+ * `content` to `""`.
516
+ *
517
+ * Edits returned by {@link format} and {@link modify} should be applied
518
+ * via {@link applyEdits}, which processes them in reverse order so that
519
+ * earlier offsets remain valid.
520
+ *
521
+ * @see {@link format} — produces edits for formatting
522
+ * @see {@link modify} — produces edits for value changes
523
+ * @see {@link applyEdits} — applies an array of edits to a source string
524
+ *
525
+ * @example
526
+ * ```ts
527
+ * import { JsoncEdit } from "jsonc-effect";
528
+ *
529
+ * // An edit that inserts ", true" at offset 10
530
+ * const edit = new JsoncEdit({ offset: 10, length: 0, content: ", true" });
531
+ *
532
+ * console.log(edit.offset); // 10
533
+ * console.log(edit.length); // 0
534
+ * console.log(edit.content); // ", true"
535
+ * ```
536
+ *
537
+ * @public
127
538
  */
128
539
  export declare class JsoncEdit extends JsoncEdit_base {
129
540
  }
@@ -145,14 +556,20 @@ declare const JsoncEdit_base: Schema.Class<JsoncEdit, {
145
556
  }, {}, {}>;
146
557
 
147
558
  /**
148
- * Union of all JSONC error types for exhaustive error handling.
559
+ * Union of all JSONC error types, useful for exhaustive error handling
560
+ * with `Effect.catchTags`.
561
+ *
562
+ * @see {@link JsoncParseError}
563
+ * @see {@link JsoncNodeNotFoundError}
564
+ * @see {@link JsoncModificationError}
149
565
  *
150
566
  * @example
151
567
  * ```ts
152
568
  * import { Effect } from "effect";
153
- * import { parse, type JsoncError } from "jsonc-effect";
569
+ * import type { JsoncError } from "jsonc-effect";
570
+ * import { parse, parseTree, findNode, modify } from "jsonc-effect";
154
571
  *
155
- * const program = someJsoncOperation.pipe(
572
+ * const program = parse("{}").pipe(
156
573
  * Effect.catchTags({
157
574
  * JsoncParseError: (e) => Effect.succeed("parse failed"),
158
575
  * JsoncModificationError: (e) => Effect.succeed("modify failed"),
@@ -160,11 +577,44 @@ declare const JsoncEdit_base: Schema.Class<JsoncEdit, {
160
577
  * }),
161
578
  * );
162
579
  * ```
580
+ *
581
+ * @public
163
582
  */
164
583
  export declare type JsoncError = JsoncParseError | JsoncNodeNotFoundError | JsoncModificationError;
165
584
 
166
585
  /**
167
586
  * Options controlling JSONC formatting behavior.
587
+ *
588
+ * @remarks
589
+ * - `tabSize` — number of spaces per indentation level. Defaults to `2`.
590
+ * - `insertSpaces` — when `true`, use spaces for indentation; when `false`,
591
+ * use tab characters. Defaults to `true`.
592
+ * - `eol` — the end-of-line sequence. Defaults to `"\n"`.
593
+ * - `insertFinalNewline` — when `true`, ensure the formatted output ends
594
+ * with a newline. Defaults to `false`.
595
+ * - `keepLines` — when `true`, preserve existing line breaks in the source
596
+ * rather than reflowing. Defaults to `false`.
597
+ *
598
+ * @see {@link format} — uses these options to produce formatting edits
599
+ * @see {@link formatAndApply} — formats and applies edits in one step
600
+ *
601
+ * @example
602
+ * ```ts
603
+ * import { Effect } from "effect";
604
+ * import { formatAndApply, JsoncFormattingOptions } from "jsonc-effect";
605
+ *
606
+ * const options = new JsoncFormattingOptions({
607
+ * tabSize: 4,
608
+ * insertSpaces: true,
609
+ * insertFinalNewline: true,
610
+ * });
611
+ *
612
+ * const program = formatAndApply('{"key":"value"}', options).pipe(
613
+ * Effect.map((formatted) => console.log(formatted)),
614
+ * );
615
+ * ```
616
+ *
617
+ * @public
168
618
  */
169
619
  export declare class JsoncFormattingOptions extends JsoncFormattingOptions_base {
170
620
  }
@@ -214,24 +664,66 @@ declare const JsoncFormattingOptions_base: Schema.Class<JsoncFormattingOptions,
214
664
  }, {}, {}>;
215
665
 
216
666
  /**
217
- * Schema that transforms a JSONC string into an unknown JavaScript value.
667
+ * Pre-built `Schema<unknown, string>` that decodes a JSONC string into an
668
+ * unknown JavaScript value using default parse options.
218
669
  *
219
- * This is the first stage of a parsing pipeline:
220
- * JSONC string → unknown → (your typed schema)
670
+ * This is the first stage of a typical parsing pipeline:
221
671
  *
222
- * @example
223
- * ```typescript
224
- * import { Schema } from "effect"
225
- * import { JsoncFromString } from "jsonc-effect"
672
+ * ```
673
+ * JSONC string --JsoncFromString--> unknown --YourSchema--> A
674
+ * ```
675
+ *
676
+ * @remarks
677
+ * Default parse options are used (comments allowed, trailing commas
678
+ * allowed). The encode direction uses `JSON.stringify` with 2-space
679
+ * indentation, which means comments present in the original JSONC
680
+ * input are not preserved during a round-trip encode.
226
681
  *
227
- * const MyConfigFromJsonc = Schema.compose(JsoncFromString, MyConfigSchema)
228
- * const config = Schema.decodeUnknownSync(MyConfigFromJsonc)(jsoncText)
682
+ * For custom parse options, use {@link makeJsoncFromString} instead.
683
+ *
684
+ * @see {@link makeJsoncFromString} to create a schema with custom options.
685
+ * @see {@link makeJsoncSchema} to compose JSONC parsing with a domain schema
686
+ * in one step.
687
+ *
688
+ * @example Decode a JSONC string
689
+ * ```ts
690
+ * import { Schema } from "effect";
691
+ * import { JsoncFromString } from "jsonc-effect";
692
+ *
693
+ * const value: unknown = Schema.decodeUnknownSync(JsoncFromString)(
694
+ * '{ "key": 42 // comment\n}',
695
+ * );
229
696
  * ```
697
+ *
698
+ * @example Compose with a domain schema
699
+ * ```ts
700
+ * import { Schema } from "effect";
701
+ * import { JsoncFromString } from "jsonc-effect";
702
+ *
703
+ * const MyConfig = Schema.Struct({
704
+ * name: Schema.String,
705
+ * version: Schema.Number,
706
+ * });
707
+ *
708
+ * const MyConfigFromJsonc = Schema.compose(JsoncFromString, MyConfig);
709
+ * const config = Schema.decodeUnknownSync(MyConfigFromJsonc)(
710
+ * '{ "name": "app", "version": 1 }',
711
+ * );
712
+ * ```
713
+ *
714
+ * @public
230
715
  */
231
716
  export declare const JsoncFromString: Schema.Schema<unknown, string>;
232
717
 
233
718
  /**
234
- * Error raised when modify() produces invalid edits.
719
+ * Error raised when {@link modify} produces invalid edits or encounters
720
+ * an unsupported modification scenario.
721
+ *
722
+ * @remarks
723
+ * Contains the `path` where modification was attempted and a `reason`
724
+ * string explaining why it failed.
725
+ *
726
+ * @see {@link modify} — may fail with this error
235
727
  *
236
728
  * @example
237
729
  * ```ts
@@ -240,11 +732,13 @@ export declare const JsoncFromString: Schema.Schema<unknown, string>;
240
732
  *
241
733
  * const program = modify("{}", ["deep", "path"], 42).pipe(
242
734
  * Effect.catchTag("JsoncModificationError", (e) => {
243
- * console.error(e.path, e.reason);
735
+ * console.error(`Failed at [${e.path.join(", ")}]: ${e.reason}`);
244
736
  * return Effect.succeed([]);
245
737
  * }),
246
738
  * );
247
739
  * ```
740
+ *
741
+ * @public
248
742
  */
249
743
  export declare class JsoncModificationError extends JsoncModificationErrorBase<{
250
744
  readonly path: ReadonlyArray<string | number>;
@@ -253,14 +747,65 @@ export declare class JsoncModificationError extends JsoncModificationErrorBase<{
253
747
  get message(): string;
254
748
  }
255
749
 
256
- /** @internal */
750
+ /**
751
+ * Base class for {@link JsoncModificationError}.
752
+ *
753
+ * @privateRemarks
754
+ * Uses the same `*Base` pattern as {@link JsoncParseErrorBase} to work
755
+ * around api-extractor's inability to roll up the complex type produced
756
+ * by `Data.TaggedError` into a single `.d.ts` declaration.
757
+ *
758
+ * @internal
759
+ */
257
760
  export declare const JsoncModificationErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
258
761
  readonly _tag: "JsoncModificationError";
259
762
  } & Readonly<A>;
260
763
 
261
764
  /**
262
- * AST node representing a parsed JSONC element.
263
- * Parent field is intentionally omitted to avoid circular references.
765
+ * AST node representing a parsed JSONC element, produced by {@link parseTree}.
766
+ *
767
+ * @remarks
768
+ * The `parent` field present in Microsoft's `jsonc-parser` is intentionally
769
+ * omitted here to avoid circular references, which would break structural
770
+ * equality, serialization, and Effect's `Schema.encode`/`Schema.decode`
771
+ * pipelines. Child relationships are expressed via the `children` array,
772
+ * and the recursive type is handled with `Schema.suspend`.
773
+ *
774
+ * - `type` — the {@link JsoncNodeType} discriminator.
775
+ * - `value` — the decoded JavaScript value for leaf nodes (`string`,
776
+ * `number`, `boolean`, `null`); `undefined` for structural nodes.
777
+ * - `offset` — zero-based character offset of this node in the source.
778
+ * - `length` — character length of this node in the source.
779
+ * - `colonOffset` — for `"property"` nodes, the offset of the `:` separator.
780
+ * - `children` — child nodes; present for `"object"`, `"array"`, and
781
+ * `"property"` nodes.
782
+ *
783
+ * @see {@link parseTree} — produces the root `JsoncNode`
784
+ * @see {@link findNode} — locates a descendant by path
785
+ *
786
+ * @example
787
+ * ```ts
788
+ * import { Effect } from "effect";
789
+ * import { parseTree } from "jsonc-effect";
790
+ *
791
+ * const program = parseTree('{ "key": [1, 2] }').pipe(
792
+ * Effect.map((root) => {
793
+ * // root.type === "object"
794
+ * const property = root.children?.[0]; // "property" node
795
+ * const array = property?.children?.[1]; // "array" node
796
+ * console.log(array?.children?.length); // 2
797
+ * }),
798
+ * );
799
+ * ```
800
+ *
801
+ * @privateRemarks
802
+ * Unlike the `*Base` pattern needed for `Data.TaggedError` subclasses,
803
+ * `Schema.Class` works directly for data types — api-extractor can roll up
804
+ * the generated `.d.ts` without issues. The `Schema.suspend` call for
805
+ * `children` is required to break the circular type reference at the schema
806
+ * level while still allowing recursive decode/encode.
807
+ *
808
+ * @public
264
809
  */
265
810
  export declare class JsoncNode extends JsoncNode_base {
266
811
  }
@@ -295,6 +840,28 @@ declare const JsoncNode_base: Schema.Class<JsoncNode, {
295
840
 
296
841
  /**
297
842
  * Error raised when AST navigation fails to find a node at the given path.
843
+ *
844
+ * @remarks
845
+ * Contains the `path` that was searched and the `rootNodeType` of the tree
846
+ * that was traversed.
847
+ *
848
+ * @see {@link findNode} — may fail with this error
849
+ *
850
+ * @example
851
+ * ```ts
852
+ * import { Effect } from "effect";
853
+ * import { parseTree, findNode } from "jsonc-effect";
854
+ *
855
+ * const program = parseTree('{ "a": 1 }').pipe(
856
+ * Effect.flatMap((root) => findNode(root, ["missing", "path"])),
857
+ * Effect.catchTag("JsoncNodeNotFoundError", (e) => {
858
+ * console.error(`Not found: [${e.path.join(", ")}] in ${e.rootNodeType}`);
859
+ * return Effect.succeed(undefined);
860
+ * }),
861
+ * );
862
+ * ```
863
+ *
864
+ * @public
298
865
  */
299
866
  export declare class JsoncNodeNotFoundError extends JsoncNodeNotFoundErrorBase<{
300
867
  readonly path: ReadonlyArray<string | number>;
@@ -303,34 +870,86 @@ export declare class JsoncNodeNotFoundError extends JsoncNodeNotFoundErrorBase<{
303
870
  get message(): string;
304
871
  }
305
872
 
306
- /** @internal */
873
+ /**
874
+ * Base class for {@link JsoncNodeNotFoundError}.
875
+ *
876
+ * @privateRemarks
877
+ * Uses the same `*Base` pattern as {@link JsoncParseErrorBase} to work
878
+ * around api-extractor's inability to roll up the complex type produced
879
+ * by `Data.TaggedError` into a single `.d.ts` declaration.
880
+ *
881
+ * @internal
882
+ */
307
883
  export declare const JsoncNodeNotFoundErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
308
884
  readonly _tag: "JsoncNodeNotFoundError";
309
885
  } & Readonly<A>;
310
886
 
311
887
  /**
312
- * AST node types.
888
+ * Discriminator values for JSONC AST node types.
889
+ *
890
+ * @remarks
891
+ * These correspond to the JSON value types (`"string"`, `"number"`,
892
+ * `"boolean"`, `"null"`) plus structural types (`"object"`, `"array"`)
893
+ * and the special `"property"` type representing a key-value pair inside
894
+ * an object.
895
+ *
896
+ * @see {@link JsoncNode} — the AST node that carries this discriminator
897
+ *
898
+ * @public
313
899
  */
314
900
  export declare const JsoncNodeType: Schema.Literal<["object", "array", "property", "string", "number", "boolean", "null"]>;
315
901
 
902
+ /**
903
+ * The union of all JSONC AST node type string literals.
904
+ *
905
+ * @see {@link JsoncNodeType}
906
+ *
907
+ * @public
908
+ */
316
909
  export declare type JsoncNodeType = Schema.Schema.Type<typeof JsoncNodeType>;
317
910
 
318
911
  /**
319
- * Error raised when JSONC parsing encounters syntax errors.
320
- * Contains an array of error details with position information.
912
+ * Error raised when JSONC parsing encounters one or more syntax errors.
913
+ *
914
+ * @remarks
915
+ * Contains the full source `text`, the `options` used for parsing, and an
916
+ * `errors` array of {@link JsoncParseErrorDetail} instances with precise
917
+ * position information for each problem found.
918
+ *
919
+ * @see {@link parse} — may fail with this error
920
+ * @see {@link parseTree} — may fail with this error
921
+ *
922
+ * @example Catching with `Effect.catchTag`
923
+ * ```ts
924
+ * import { Effect } from "effect";
925
+ * import { parse } from "jsonc-effect";
926
+ *
927
+ * const program = parse("{ invalid }").pipe(
928
+ * Effect.catchTag("JsoncParseError", (e) => {
929
+ * console.error(e.errors); // Array of JsoncParseErrorDetail
930
+ * return Effect.succeed({});
931
+ * }),
932
+ * );
933
+ * ```
321
934
  *
322
- * @example
935
+ * @example Inspecting error details
323
936
  * ```ts
324
937
  * import { Effect } from "effect";
325
- * import { parse, JsoncParseError } from "jsonc-effect";
938
+ * import { parse } from "jsonc-effect";
326
939
  *
327
940
  * const program = parse("{ invalid }").pipe(
328
941
  * Effect.catchTag("JsoncParseError", (e) => {
329
- * console.error(e.errors); // Array of JsoncParseErrorDetail
942
+ * for (const detail of e.errors) {
943
+ * console.error(
944
+ * `[${detail.code}] ${detail.message} at line ${detail.startLine}:${detail.startCharacter}`,
945
+ * );
946
+ * }
330
947
  * return Effect.succeed({});
331
948
  * }),
332
949
  * );
333
950
  * ```
951
+ *
952
+ * @public
334
953
  */
335
954
  export declare class JsoncParseError extends JsoncParseErrorBase<{
336
955
  readonly errors: ReadonlyArray<JsoncParseErrorDetail>;
@@ -340,20 +959,79 @@ export declare class JsoncParseError extends JsoncParseErrorBase<{
340
959
  get message(): string;
341
960
  }
342
961
 
343
- /** @internal */
962
+ /**
963
+ * Base class for {@link JsoncParseError}.
964
+ *
965
+ * @privateRemarks
966
+ * The `*Base` pattern is required because `Data.TaggedError` produces complex
967
+ * type signatures involving intersection types and branded generics that
968
+ * api-extractor cannot roll up into a single `.d.ts` bundle. By exporting
969
+ * the base separately as `@internal`, the public `JsoncParseError` class
970
+ * extends it with concrete fields, giving api-extractor a simple class
971
+ * declaration to work with.
972
+ *
973
+ * @internal
974
+ */
344
975
  export declare const JsoncParseErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
345
976
  readonly _tag: "JsoncParseError";
346
977
  } & Readonly<A>;
347
978
 
348
979
  /**
349
- * Error codes for JSONC parse errors.
980
+ * Error codes representing specific JSONC parse failures.
981
+ *
982
+ * @remarks
983
+ * Each code maps to a distinct syntactic error the parser can encounter,
984
+ * from invalid symbols and number formats to missing delimiters and
985
+ * unexpected end-of-input conditions.
986
+ *
987
+ * @see {@link JsoncParseErrorDetail} — carries one of these codes alongside
988
+ * position information
989
+ *
990
+ * @public
350
991
  */
351
992
  export declare const JsoncParseErrorCode: Schema.Literal<["InvalidSymbol", "InvalidNumberFormat", "PropertyNameExpected", "ValueExpected", "ColonExpected", "CommaExpected", "CloseBraceExpected", "CloseBracketExpected", "EndOfFileExpected", "InvalidCommentToken", "UnexpectedEndOfComment", "UnexpectedEndOfString", "UnexpectedEndOfNumber", "InvalidUnicode", "InvalidEscapeCharacter", "InvalidCharacter"]>;
352
993
 
994
+ /**
995
+ * The union of all JSONC parse error code string literals.
996
+ *
997
+ * @see {@link JsoncParseErrorCode}
998
+ *
999
+ * @public
1000
+ */
353
1001
  export declare type JsoncParseErrorCode = Schema.Schema.Type<typeof JsoncParseErrorCode>;
354
1002
 
355
1003
  /**
356
- * Detail for a single parse error with location information.
1004
+ * Detail for a single parse error, including the error code, a human-readable
1005
+ * message, and the exact position within the source document.
1006
+ *
1007
+ * @remarks
1008
+ * - `code` — a {@link JsoncParseErrorCode} identifying the error kind.
1009
+ * - `message` — a descriptive message suitable for display.
1010
+ * - `offset` — zero-based character offset where the error occurred.
1011
+ * - `length` — character length of the problematic span.
1012
+ * - `startLine` — zero-based line number of the error.
1013
+ * - `startCharacter` — zero-based column within `startLine`.
1014
+ *
1015
+ * @see {@link JsoncParseError} — aggregates an array of these details
1016
+ *
1017
+ * @example
1018
+ * ```ts
1019
+ * import { JsoncParseErrorDetail } from "jsonc-effect";
1020
+ *
1021
+ * const detail = new JsoncParseErrorDetail({
1022
+ * code: "ValueExpected",
1023
+ * message: "Value expected",
1024
+ * offset: 5,
1025
+ * length: 1,
1026
+ * startLine: 0,
1027
+ * startCharacter: 5,
1028
+ * });
1029
+ *
1030
+ * console.log(detail.code); // "ValueExpected"
1031
+ * console.log(detail.offset); // 5
1032
+ * ```
1033
+ *
1034
+ * @public
357
1035
  */
358
1036
  export declare class JsoncParseErrorDetail extends JsoncParseErrorDetail_base {
359
1037
  }
@@ -388,6 +1066,35 @@ declare const JsoncParseErrorDetail_base: Schema.Class<JsoncParseErrorDetail, {
388
1066
 
389
1067
  /**
390
1068
  * Options controlling JSONC parse behavior.
1069
+ *
1070
+ * @remarks
1071
+ * - `disallowComments` — when `true`, line and block comments are treated
1072
+ * as parse errors. Defaults to `false`.
1073
+ * - `allowTrailingComma` — when `true`, trailing commas after the last
1074
+ * element in arrays and objects are permitted. Defaults to `true`, which
1075
+ * differs from Microsoft's `jsonc-parser` (where the default is `false`).
1076
+ * - `allowEmptyContent` — when `true`, an empty string parses as
1077
+ * `undefined` rather than producing an error. Defaults to `false`.
1078
+ *
1079
+ * @see {@link parse} — parses JSONC text into a JavaScript value
1080
+ * @see {@link parseTree} — parses JSONC text into an AST
1081
+ *
1082
+ * @example
1083
+ * ```ts
1084
+ * import { Effect } from "effect";
1085
+ * import { parse, JsoncParseOptions } from "jsonc-effect";
1086
+ *
1087
+ * const options = new JsoncParseOptions({
1088
+ * disallowComments: true,
1089
+ * allowTrailingComma: false,
1090
+ * });
1091
+ *
1092
+ * const program = parse('{ "key": "value" }', options).pipe(
1093
+ * Effect.map((value) => console.log(value)),
1094
+ * );
1095
+ * ```
1096
+ *
1097
+ * @public
391
1098
  */
392
1099
  export declare class JsoncParseOptions extends JsoncParseOptions_base {
393
1100
  }
@@ -421,14 +1128,48 @@ declare const JsoncParseOptions_base: Schema.Class<JsoncParseOptions, {
421
1128
  }, {}, {}>;
422
1129
 
423
1130
  /**
424
- * A path to a location in a JSONC document.
1131
+ * An ordered sequence of {@link JsoncSegment} values describing a location
1132
+ * within a JSONC document tree.
1133
+ *
1134
+ * @see {@link findNode} — resolves a `JsoncPath` to an AST node
1135
+ * @see {@link modify} — applies a modification at a `JsoncPath`
1136
+ *
1137
+ * @example
1138
+ * ```ts
1139
+ * import type { JsoncPath } from "jsonc-effect";
1140
+ *
1141
+ * // Path to the "strict" property inside "compilerOptions"
1142
+ * const path: JsoncPath = ["compilerOptions", "strict"];
1143
+ *
1144
+ * // Path to the second element of the "include" array
1145
+ * const arrayPath: JsoncPath = ["include", 1];
1146
+ * ```
1147
+ *
1148
+ * @public
425
1149
  */
426
1150
  export declare const JsoncPath: Schema.Array$<Schema.Union<[typeof Schema.String, typeof Schema.Number]>>;
427
1151
 
1152
+ /**
1153
+ * An array of path segments — `ReadonlyArray<string | number>`.
1154
+ *
1155
+ * @see {@link JsoncPath}
1156
+ *
1157
+ * @public
1158
+ */
428
1159
  export declare type JsoncPath = Schema.Schema.Type<typeof JsoncPath>;
429
1160
 
430
1161
  /**
431
- * A range within a JSONC document.
1162
+ * A range within a JSONC document, expressed as a zero-based character
1163
+ * offset and a length in characters.
1164
+ *
1165
+ * @remarks
1166
+ * Both `offset` and `length` are measured in UTF-16 code units (JavaScript
1167
+ * string indices). Pass a `JsoncRange` to {@link format} to restrict
1168
+ * formatting to a specific region of the document rather than the whole file.
1169
+ *
1170
+ * @see {@link format} — accepts an optional `JsoncRange` parameter
1171
+ *
1172
+ * @public
432
1173
  */
433
1174
  export declare class JsoncRange extends JsoncRange_base {
434
1175
  }
@@ -446,55 +1187,180 @@ declare const JsoncRange_base: Schema.Class<JsoncRange, {
446
1187
  }, {}, {}>;
447
1188
 
448
1189
  /**
449
- * Scan error codes produced by the scanner.
1190
+ * Scanner error codes produced by the JSONC scanner.
1191
+ *
1192
+ * @remarks
1193
+ * `"None"` indicates a successful scan with no errors. All other values
1194
+ * describe a specific lexical error encountered while tokenizing input.
1195
+ *
1196
+ * @see {@link JsoncScanner} — the scanner interface that reports these errors
1197
+ *
1198
+ * @public
450
1199
  */
451
1200
  export declare const JsoncScanError: Schema.Literal<["None", "UnexpectedEndOfComment", "UnexpectedEndOfString", "UnexpectedEndOfNumber", "InvalidUnicode", "InvalidEscapeCharacter", "InvalidCharacter", "InvalidSymbol"]>;
452
1201
 
1202
+ /**
1203
+ * The union of all JSONC scan error string literals.
1204
+ *
1205
+ * @see {@link JsoncScanError}
1206
+ *
1207
+ * @public
1208
+ */
453
1209
  export declare type JsoncScanError = Schema.Schema.Type<typeof JsoncScanError>;
454
1210
 
455
1211
  /**
456
- * JSONC Scanner interface a stateful cursor over input text.
1212
+ * Stateful cursor over JSONC text that produces tokens on demand.
1213
+ *
1214
+ * @remarks
1215
+ * The scanner is the lowest-level API in jsonc-effect. It exposes an
1216
+ * imperative scan-loop pattern: call {@link JsoncScanner.scan | scan()} in a
1217
+ * loop until it returns `"EOF"`, inspecting the current token with the
1218
+ * getter methods after each call.
1219
+ *
1220
+ * Unlike the rest of the library, the scanner is **mutable** — each call to
1221
+ * `scan()` advances an internal cursor and updates all token-related state.
1222
+ *
1223
+ * @see {@link createScanner} — factory function that produces a `JsoncScanner`
1224
+ * @see {@link JsoncSyntaxKind} — string literal union of all token types
1225
+ *
1226
+ * @example
1227
+ * Collecting all structural tokens from a JSONC string:
1228
+ * ```ts
1229
+ * import type { JsoncSyntaxKind } from "jsonc-effect";
1230
+ * import { createScanner } from "jsonc-effect";
1231
+ *
1232
+ * const scanner = createScanner('{ "key": 42 }', true);
1233
+ * const tokens: JsoncSyntaxKind[] = [];
1234
+ * let kind: JsoncSyntaxKind;
1235
+ * do {
1236
+ * kind = scanner.scan();
1237
+ * tokens.push(kind);
1238
+ * } while (kind !== "EOF");
1239
+ * console.log(tokens);
1240
+ * // ["OpenBrace", "String", "Colon", "Number", "CloseBrace", "EOF"]
1241
+ * ```
1242
+ *
1243
+ * @privateRemarks
1244
+ * The scanner is the only mutable/stateful part of the library. All other
1245
+ * APIs are pure Effect pipelines built on top of it.
1246
+ *
1247
+ * @public
457
1248
  */
458
1249
  export declare interface JsoncScanner {
459
- /** Advance to the next token and return its kind */
1250
+ /** Advance the cursor to the next token and return its {@link JsoncSyntaxKind}. */
460
1251
  scan(): JsoncSyntaxKind;
461
- /** Get the current token kind */
1252
+ /** Return the {@link JsoncSyntaxKind} of the current token without advancing. */
462
1253
  getToken(): JsoncSyntaxKind;
463
- /** Get the string value of the current token */
1254
+ /** Return the string value of the current token (e.g. the unescaped content of a string literal). */
464
1255
  getTokenValue(): string;
465
- /** Get the character offset of the current token */
1256
+ /** Return the zero-based character offset where the current token begins. */
466
1257
  getTokenOffset(): number;
467
- /** Get the length of the current token */
1258
+ /** Return the character length of the current token. */
468
1259
  getTokenLength(): number;
469
- /** Get the line number of the current token start */
1260
+ /** Return the zero-based line number where the current token starts. */
470
1261
  getTokenStartLine(): number;
471
- /** Get the character position within the line */
1262
+ /** Return the zero-based character position within the line where the current token starts. */
472
1263
  getTokenStartCharacter(): number;
473
- /** Get the scan error for the current token */
1264
+ /** Return the {@link JsoncScanError} for the current token, or `"None"` if no error. */
474
1265
  getTokenError(): JsoncScanError;
475
- /** Get the current scanner position */
1266
+ /** Return the current cursor position (byte offset into the source text). */
476
1267
  getPosition(): number;
477
- /** Set the scanner position */
1268
+ /** Set the cursor position, resetting the current token state. */
478
1269
  setPosition(pos: number): void;
479
1270
  }
480
1271
 
481
1272
  /**
482
- * A path segment: string for object keys, number for array indices.
1273
+ * A single segment of a {@link JsoncPath}: a `string` for object property
1274
+ * keys or a `number` for array indices.
1275
+ *
1276
+ * @see {@link findNode} — resolves a path to an AST node
1277
+ * @see {@link modify} — applies a value change at a path
1278
+ *
1279
+ * @example
1280
+ * ```ts
1281
+ * import type { JsoncSegment } from "jsonc-effect";
1282
+ *
1283
+ * const objectKey: JsoncSegment = "compilerOptions";
1284
+ * const arrayIndex: JsoncSegment = 0;
1285
+ * ```
1286
+ *
1287
+ * @public
483
1288
  */
484
1289
  export declare const JsoncSegment: Schema.Union<[typeof Schema.String, typeof Schema.Number]>;
485
1290
 
1291
+ /**
1292
+ * A single path segment type — `string | number`.
1293
+ *
1294
+ * @see {@link JsoncSegment}
1295
+ *
1296
+ * @public
1297
+ */
486
1298
  export declare type JsoncSegment = Schema.Schema.Type<typeof JsoncSegment>;
487
1299
 
488
1300
  /**
489
1301
  * Token types produced by the JSONC scanner.
490
- * Uses string literals instead of numeric enums for self-documenting debug output.
1302
+ *
1303
+ * @remarks
1304
+ * Uses string literals instead of numeric enums so that token kinds are
1305
+ * self-documenting in debug output, log messages, and test assertions.
1306
+ * This avoids the "reverse-mapping" confusion of TypeScript numeric enums
1307
+ * and makes pattern-matching with `Schema.Literal` straightforward.
1308
+ *
1309
+ * @see {@link createScanner} — creates a scanner that emits these token types
1310
+ *
1311
+ * @public
491
1312
  */
492
1313
  export declare const JsoncSyntaxKind: Schema.Literal<["OpenBrace", "CloseBrace", "OpenBracket", "CloseBracket", "Comma", "Colon", "Null", "True", "False", "String", "Number", "LineComment", "BlockComment", "LineBreak", "Trivia", "Unknown", "EOF"]>;
493
1314
 
1315
+ /**
1316
+ * The union of all JSONC token kind string literals.
1317
+ *
1318
+ * @see {@link JsoncSyntaxKind}
1319
+ *
1320
+ * @public
1321
+ */
494
1322
  export declare type JsoncSyntaxKind = Schema.Schema.Type<typeof JsoncSyntaxKind>;
495
1323
 
496
1324
  /**
497
- * A single token produced by the JSONC scanner.
1325
+ * A single token produced by the JSONC scanner, carrying its kind, textual
1326
+ * value, position within the source, and any scan error.
1327
+ *
1328
+ * @remarks
1329
+ * - `kind` — the {@link JsoncSyntaxKind} discriminator for this token.
1330
+ * - `value` — the raw text slice from the source document.
1331
+ * - `offset` — zero-based character offset from the start of the document.
1332
+ * - `length` — character length of this token in the source.
1333
+ * - `startLine` — zero-based line number where the token begins.
1334
+ * - `startCharacter` — zero-based column within `startLine`.
1335
+ * - `error` — a {@link JsoncScanError} code; `"None"` when the token is valid.
1336
+ *
1337
+ * @see {@link createScanner} — produces a stream of `JsoncToken` instances
1338
+ *
1339
+ * @example
1340
+ * ```ts
1341
+ * import { JsoncToken } from "jsonc-effect";
1342
+ *
1343
+ * const token = new JsoncToken({
1344
+ * kind: "String",
1345
+ * value: '"hello"',
1346
+ * offset: 0,
1347
+ * length: 7,
1348
+ * startLine: 0,
1349
+ * startCharacter: 0,
1350
+ * error: "None",
1351
+ * });
1352
+ *
1353
+ * console.log(token.kind); // "String"
1354
+ * console.log(token.value); // '"hello"'
1355
+ * ```
1356
+ *
1357
+ * @privateRemarks
1358
+ * `Schema.Class` gives `JsoncToken` structural equality via `Data.Class`
1359
+ * under the hood, so two tokens with identical fields are considered equal
1360
+ * by `Equal.equals`. This is essential for test assertions and Effect's
1361
+ * structural comparison semantics.
1362
+ *
1363
+ * @public
498
1364
  */
499
1365
  export declare class JsoncToken extends JsoncToken_base {
500
1366
  }
@@ -533,6 +1399,51 @@ declare const JsoncToken_base: Schema.Class<JsoncToken, {
533
1399
 
534
1400
  /**
535
1401
  * Discriminated union of JSONC visitor events.
1402
+ *
1403
+ * Each variant carries an `_tag` discriminant, an `offset`, and a `length`
1404
+ * describing where the event occurred in the source text. Some variants
1405
+ * include additional fields such as `path`, `value`, or `property`.
1406
+ *
1407
+ * @remarks
1408
+ * The nine event types are:
1409
+ *
1410
+ * - **ObjectBegin** — opening `{` of an object, includes `path`.
1411
+ * - **ObjectEnd** — closing `}` of an object.
1412
+ * - **ObjectProperty** — a property key, includes `property` and `path`.
1413
+ * - **ArrayBegin** — opening `[` of an array, includes `path`.
1414
+ * - **ArrayEnd** — closing `]` of an array.
1415
+ * - **LiteralValue** — a string, number, boolean, or null literal,
1416
+ * includes `value` and `path`.
1417
+ * - **Separator** — a `,` or `:` character.
1418
+ * - **Comment** — a line or block comment.
1419
+ * - **Error** — a parse error, includes a {@link JsoncParseErrorCode} `code`.
1420
+ *
1421
+ * Use the `_tag` field to discriminate between variants in `switch`
1422
+ * statements or {@link https://effect.website/docs/stream/operations | Stream}
1423
+ * filter predicates.
1424
+ *
1425
+ * @see {@link visit} to produce a stream of these events.
1426
+ * @see {@link visitCollect} to collect matching events in one step.
1427
+ *
1428
+ * @example Filtering events by tag
1429
+ * ```ts
1430
+ * import { Chunk, Effect, Stream } from "effect";
1431
+ * import type { JsoncVisitorEvent } from "jsonc-effect";
1432
+ * import { visit } from "jsonc-effect";
1433
+ *
1434
+ * const literals = Effect.runSync(
1435
+ * visit('{ "a": 1 }').pipe(
1436
+ * Stream.filter(
1437
+ * (e): e is Extract<JsoncVisitorEvent, { _tag: "LiteralValue" }> =>
1438
+ * e._tag === "LiteralValue",
1439
+ * ),
1440
+ * Stream.runCollect,
1441
+ * Effect.map(Chunk.toReadonlyArray),
1442
+ * ),
1443
+ * );
1444
+ * ```
1445
+ *
1446
+ * @public
536
1447
  */
537
1448
  export declare type JsoncVisitorEvent = {
538
1449
  readonly _tag: "ObjectBegin";
@@ -581,66 +1492,182 @@ export declare type JsoncVisitorEvent = {
581
1492
  };
582
1493
 
583
1494
  /**
584
- * Create a JSONC-to-unknown Schema with custom parse options.
1495
+ * Create a `Schema<unknown, string>` that decodes JSONC with custom
1496
+ * parse options.
1497
+ *
1498
+ * @param options - Partial {@link JsoncParseOptions} controlling comment
1499
+ * handling and trailing-comma tolerance.
1500
+ * @returns A `Schema<unknown, string>` configured with the given options.
585
1501
  *
586
1502
  * @remarks
587
- * The encode direction uses `JSON.stringify` which produces standard
588
- * JSON. Comments present in the original JSONC input are not preserved
589
- * during round-trip encode/decode.
1503
+ * The encode direction uses `JSON.stringify` with 2-space indentation,
1504
+ * which produces standard JSON. Comments present in the original JSONC
1505
+ * input are not preserved during a round-trip encode.
590
1506
  *
591
- * @example
592
- * ```typescript
593
- * import { makeJsoncFromString } from "jsonc-effect"
1507
+ * @see {@link JsoncFromString} for a zero-config default instance.
1508
+ * @see {@link makeJsoncSchema} to compose JSONC parsing with a domain
1509
+ * schema in one step.
1510
+ *
1511
+ * @example Strict mode (no comments, no trailing commas)
1512
+ * ```ts
1513
+ * import { Schema } from "effect";
1514
+ * import { makeJsoncFromString } from "jsonc-effect";
594
1515
  *
595
- * // Strict mode: no comments allowed
596
1516
  * const StrictJsoncFromString = makeJsoncFromString({
597
1517
  * disallowComments: true,
598
1518
  * allowTrailingComma: false,
599
- * })
1519
+ * });
1520
+ *
1521
+ * const value: unknown = Schema.decodeUnknownSync(StrictJsoncFromString)(
1522
+ * '{ "key": 42 }',
1523
+ * );
600
1524
  * ```
1525
+ *
1526
+ * @privateRemarks
1527
+ * Internally delegates to `Schema.transformOrFail` to wire up the decode
1528
+ * and encode directions.
1529
+ *
1530
+ * @public
601
1531
  */
602
1532
  export declare function makeJsoncFromString(options?: Partial<JsoncParseOptions>): Schema.Schema<unknown, string>;
603
1533
 
604
1534
  /**
605
- * Create a composed Schema that parses JSONC and validates against
606
- * a target schema in one step.
1535
+ * Create a composed `Schema<A, string>` that parses a JSONC string and
1536
+ * validates the result against a target domain schema in one step.
607
1537
  *
608
- * @example
609
- * ```typescript
610
- * import { Schema } from "effect"
611
- * import { makeJsoncSchema } from "jsonc-effect"
1538
+ * @param targetSchema - The domain schema to validate the parsed value
1539
+ * against. Its input type `I` must be assignable from `unknown`.
1540
+ * @param options - Optional partial {@link JsoncParseOptions} forwarded to
1541
+ * the underlying JSONC parser.
1542
+ * @returns A `Schema<A, string>` that goes directly from a JSONC string
1543
+ * to a fully validated domain value of type `A`.
1544
+ *
1545
+ * @remarks
1546
+ * Internally composes two schema stages:
1547
+ *
1548
+ * 1. JSONC string to `unknown` (via {@link makeJsoncFromString}).
1549
+ * 2. `unknown` to `A` (via the provided `targetSchema`).
1550
+ *
1551
+ * This avoids the need to manually call `Schema.compose`.
1552
+ *
1553
+ * @see {@link makeJsoncFromString} for the first stage of the pipeline.
1554
+ *
1555
+ * @example Typed configuration from JSONC
1556
+ * ```ts
1557
+ * import { Schema } from "effect";
1558
+ * import { makeJsoncSchema } from "jsonc-effect";
612
1559
  *
613
1560
  * const MyConfig = Schema.Struct({
614
1561
  * name: Schema.String,
615
1562
  * version: Schema.Number,
616
- * })
1563
+ * });
1564
+ *
1565
+ * const MyConfigFromJsonc = makeJsoncSchema(MyConfig);
1566
+ * const config = Schema.decodeUnknownSync(MyConfigFromJsonc)(
1567
+ * '{ "name": "app", "version": 1 }',
1568
+ * );
1569
+ * ```
617
1570
  *
618
- * const MyConfigFromJsonc = makeJsoncSchema(MyConfig)
619
- * const config = Schema.decodeUnknownSync(MyConfigFromJsonc)(jsoncText)
1571
+ * @example With custom parse options
1572
+ * ```ts
1573
+ * import { Schema } from "effect";
1574
+ * import { makeJsoncSchema } from "jsonc-effect";
1575
+ *
1576
+ * const MyConfig = Schema.Struct({ debug: Schema.Boolean });
1577
+ *
1578
+ * const StrictConfig = makeJsoncSchema(MyConfig, {
1579
+ * disallowComments: true,
1580
+ * allowTrailingComma: false,
1581
+ * });
1582
+ *
1583
+ * const config = Schema.decodeUnknownSync(StrictConfig)(
1584
+ * '{ "debug": true }',
1585
+ * );
620
1586
  * ```
1587
+ *
1588
+ * @privateRemarks
1589
+ * Uses `Schema.compose` internally to chain the JSONC-from-string schema
1590
+ * with the provided target schema.
1591
+ *
1592
+ * @public
621
1593
  */
622
1594
  export declare const makeJsoncSchema: <A, I>(targetSchema: Schema.Schema<A, I, never>, options?: Partial<JsoncParseOptions> | undefined) => Schema.Schema<A, string, never>;
623
1595
 
624
1596
  /**
625
1597
  * Compute edits to insert, replace, or remove a value at a JSON path.
626
- * Setting value to undefined removes the property/element.
627
1598
  *
628
- * @example
1599
+ * This is a {@link https://effect.website/docs/function-dual | Function.dual}
1600
+ * that supports both data-first and data-last (pipeline) usage.
1601
+ *
1602
+ * @param text - The JSONC source text to modify.
1603
+ * @param path - A {@link JsoncPath} (array of string keys and numeric indices)
1604
+ * identifying the target location in the JSON structure.
1605
+ * @param value - The value to set. Pass `undefined` to remove the
1606
+ * property or array element at the given path.
1607
+ * @param options - Optional object with `formattingOptions` controlling
1608
+ * indent size, tabs vs. spaces, and EOL style for generated text.
1609
+ * @returns An `Effect` that succeeds with a read-only array of
1610
+ * {@link JsoncEdit} objects, or fails with a
1611
+ * {@link JsoncModificationError} if the path cannot be navigated.
1612
+ *
1613
+ * @remarks
1614
+ * Setting `value` to `undefined` removes the targeted property or element,
1615
+ * including its surrounding comma. When inserting a new property into an
1616
+ * object, it is appended after the last existing property.
1617
+ *
1618
+ * @see {@link applyEdits} to apply the returned edits to the source text.
1619
+ * @see {@link JsoncModificationError} for the error type on navigation failure.
1620
+ *
1621
+ * @example Update an existing property
629
1622
  * ```ts
630
- * import { Effect, pipe } from "effect";
631
- * import { modify, applyEdits } from "@spencerbeggs/jsonc-effect";
1623
+ * import { Effect } from "effect";
1624
+ * import { modify, applyEdits } from "jsonc-effect";
1625
+ *
1626
+ * const input = '{ "a": 1 }';
1627
+ * const edits = Effect.runSync(modify(input, ["a"], 2));
1628
+ * const result: string = Effect.runSync(applyEdits(input, edits));
1629
+ * ```
1630
+ *
1631
+ * @example Insert a new property
1632
+ * ```ts
1633
+ * import { Effect } from "effect";
1634
+ * import { modify, applyEdits } from "jsonc-effect";
1635
+ *
1636
+ * const input = '{ "a": 1 }';
1637
+ * const edits = Effect.runSync(modify(input, ["b"], "hello"));
1638
+ * const result: string = Effect.runSync(applyEdits(input, edits));
1639
+ * ```
1640
+ *
1641
+ * @example Remove a property
1642
+ * ```ts
1643
+ * import { Effect } from "effect";
1644
+ * import { modify, applyEdits } from "jsonc-effect";
632
1645
  *
633
- * // Data-first
634
- * const edits = Effect.runSync(modify('{ "a": 1 }', ["a"], 2));
1646
+ * const input = '{ "a": 1, "b": 2 }';
1647
+ * const edits = Effect.runSync(modify(input, ["a"], undefined));
1648
+ * const result: string = Effect.runSync(applyEdits(input, edits));
1649
+ * ```
1650
+ *
1651
+ * @example Pipeline (data-last) usage
1652
+ * ```ts
1653
+ * import { Effect, pipe } from "effect";
1654
+ * import { modify, applyEdits } from "jsonc-effect";
635
1655
  *
636
- * // Data-last (pipeline)
1656
+ * const input = '{ "a": 1 }';
637
1657
  * const result = pipe(
638
- * '{ "a": 1 }',
639
- * modify(["a"], 2),
640
- * Effect.flatMap((edits) => applyEdits('{ "a": 1 }', edits)),
1658
+ * input,
1659
+ * modify(["a"], 42),
1660
+ * Effect.flatMap((edits) => applyEdits(input, edits)),
641
1661
  * Effect.runSync,
642
1662
  * );
643
1663
  * ```
1664
+ *
1665
+ * @privateRemarks
1666
+ * Uses its own scanner-based navigation to locate the target path rather
1667
+ * than building a full AST via `parseTree`. This keeps the implementation
1668
+ * lightweight and avoids an intermediate allocation.
1669
+ *
1670
+ * @public
644
1671
  */
645
1672
  export declare const modify: {
646
1673
  (path: JsoncPath, value: unknown, options?: {
@@ -654,21 +1681,80 @@ export declare const modify: {
654
1681
  /**
655
1682
  * Parse a JSONC string into a JavaScript value.
656
1683
  *
657
- * @param text - The JSONC string to parse
658
- * @param options - Optional parse options
659
- * @returns An Effect that produces the parsed value or fails with JsoncParseError
1684
+ * @param text - JSONC string to parse
1685
+ * @param options - Optional {@link JsoncParseOptions} controlling comment and
1686
+ * trailing-comma handling.
1687
+ * @returns `Effect<unknown, JsoncParseError>` — succeeds with the parsed value
1688
+ * or fails with a {@link JsoncParseError} containing every error encountered.
1689
+ *
1690
+ * @remarks
1691
+ * The return type is `unknown` (not `any`) so consumers are forced to narrow
1692
+ * the result, which is safer in Effect pipelines. By default
1693
+ * `allowTrailingComma` is `true`, matching common JSONC conventions used in
1694
+ * VS Code settings and `tsconfig.json`.
1695
+ *
1696
+ * @see {@link parseTree} — parse into an AST instead of a plain value
1697
+ * @see {@link JsoncParseOptions} — available parse options
1698
+ * @see {@link JsoncParseError} — the tagged error type on the failure channel
660
1699
  *
661
1700
  * @example
1701
+ * Basic parsing:
662
1702
  * ```ts
663
1703
  * import { Effect } from "effect";
664
- * import { parse } from "@spencerbeggs/jsonc-effect";
1704
+ * import { parse } from "jsonc-effect";
665
1705
  *
666
- * // Basic usage
667
1706
  * const value = Effect.runSync(parse('{ "key": 42 }'));
1707
+ * console.log(value); // { key: 42 }
1708
+ * ```
1709
+ *
1710
+ * @example
1711
+ * Parsing with options:
1712
+ * ```ts
1713
+ * import { Effect } from "effect";
1714
+ * import { parse } from "jsonc-effect";
1715
+ *
1716
+ * const value = Effect.runSync(
1717
+ * parse('{ "key": 42 }', { disallowComments: true }),
1718
+ * );
1719
+ * ```
1720
+ *
1721
+ * @example
1722
+ * Error handling with `catchTag`:
1723
+ * ```ts
1724
+ * import { Effect } from "effect";
1725
+ * import { parse } from "jsonc-effect";
1726
+ *
1727
+ * const program = parse("{ bad }").pipe(
1728
+ * Effect.catchTag("JsoncParseError", (err) =>
1729
+ * Effect.succeed({ fallback: true, errors: err.errors }),
1730
+ * ),
1731
+ * );
1732
+ *
1733
+ * const result = Effect.runSync(program);
1734
+ * console.log(result);
1735
+ * ```
1736
+ *
1737
+ * @example
1738
+ * Using `Effect.gen`:
1739
+ * ```ts
1740
+ * import { Effect } from "effect";
1741
+ * import { parse } from "jsonc-effect";
1742
+ *
1743
+ * const program = Effect.gen(function* () {
1744
+ * const config = yield* parse('{ "port": 3000 }');
1745
+ * return config;
1746
+ * });
668
1747
  *
669
- * // With options
670
- * const strict = Effect.runSync(parse('{ "key": 42 }', { disallowComments: true }));
1748
+ * const result = Effect.runSync(program);
1749
+ * console.log(result); // { port: 3000 }
671
1750
  * ```
1751
+ *
1752
+ * @privateRemarks
1753
+ * Uses {@link createScanner} internally with a recursive descent parser.
1754
+ * The scanner is created with `ignoreTrivia = false` so the parser can
1755
+ * report comment-related errors when `disallowComments` is set.
1756
+ *
1757
+ * @public
672
1758
  */
673
1759
  export declare const parse: {
674
1760
  (text: string): Effect.Effect<unknown, JsoncParseError>;
@@ -676,22 +1762,53 @@ export declare const parse: {
676
1762
  };
677
1763
 
678
1764
  /**
679
- * Parse a JSONC string into an AST.
1765
+ * Parse a JSONC string into an immutable AST.
1766
+ *
1767
+ * @param text - JSONC string to parse
1768
+ * @param options - Optional {@link JsoncParseOptions} controlling comment and
1769
+ * trailing-comma handling.
1770
+ * @returns `Effect<Option<JsoncNode>, JsoncParseError>` — succeeds with
1771
+ * `Option.some(root)` for non-empty documents or `Option.none()` when the
1772
+ * input is empty (and `allowEmptyContent` is set).
1773
+ *
1774
+ * @remarks
1775
+ * The returned AST is immutable and does **not** contain parent pointers, which
1776
+ * keeps nodes safe to share across fibers. Use the AST navigation helpers
1777
+ * ({@link findNode}, {@link getNodeValue}) to traverse and extract values from
1778
+ * the tree.
680
1779
  *
681
- * @param text - The JSONC string to parse
682
- * @param options - Optional parse options
683
- * @returns An Effect that produces Option.some(node) or Option.none() for empty content
1780
+ * `Option.none()` is returned only when the document contains no value tokens
1781
+ * and `allowEmptyContent` is enabled; otherwise an empty document produces a
1782
+ * {@link JsoncParseError}.
1783
+ *
1784
+ * @see {@link parse} — parse into a plain JavaScript value instead of an AST
1785
+ * @see {@link findNode} — locate a node by JSON path segments
1786
+ * @see {@link getNodeValue} — extract the JavaScript value from a subtree
1787
+ * @see {@link JsoncNode} — the AST node type
684
1788
  *
685
1789
  * @example
1790
+ * Parsing a JSONC string and navigating the tree:
686
1791
  * ```ts
687
1792
  * import { Effect, Option } from "effect";
688
- * import { parseTree } from "@spencerbeggs/jsonc-effect";
1793
+ * import { parseTree } from "jsonc-effect";
1794
+ *
1795
+ * const program = Effect.gen(function* () {
1796
+ * const maybeRoot = yield* parseTree('{ "a": [1, 2, 3] }');
1797
+ * if (Option.isSome(maybeRoot)) {
1798
+ * const root = maybeRoot.value;
1799
+ * console.log(root.type); // "object"
1800
+ * console.log(root.children?.length); // 1
1801
+ * }
1802
+ * });
689
1803
  *
690
- * const result = Effect.runSync(parseTree('{ "a": 1 }'));
691
- * if (Option.isSome(result)) {
692
- * console.log(result.value.type); // "object"
693
- * }
1804
+ * Effect.runSync(program);
694
1805
  * ```
1806
+ *
1807
+ * @privateRemarks
1808
+ * Internally the parser builds a mutable tree using `MutableJsoncNode` and
1809
+ * casts to the readonly `JsoncNode` on output.
1810
+ *
1811
+ * @public
695
1812
  */
696
1813
  export declare const parseTree: {
697
1814
  (text: string): Effect.Effect<Option.Option<JsoncNode>, JsoncParseError>;
@@ -701,18 +1818,46 @@ export declare const parseTree: {
701
1818
  /**
702
1819
  * Remove all comments from JSONC text, producing valid JSON.
703
1820
  *
704
- * @param text - The JSONC string to strip comments from
705
- * @param replaceCh - Optional character to replace comments with (preserves offsets)
706
- * @returns An Effect that produces the text with comments removed
1821
+ * @param text - JSONC string to strip comments from
1822
+ * @param replaceCh - Optional single character used to replace each character of
1823
+ * every comment. When provided, the output has the **same length** as the
1824
+ * input so that all offsets are preserved (line breaks inside block comments
1825
+ * are kept as-is).
1826
+ * @returns `Effect<string>` — the text with all comments removed (or replaced).
1827
+ *
1828
+ * @remarks
1829
+ * When `replaceCh` is omitted the comment text is simply deleted, which means
1830
+ * character offsets in the output no longer match the original document. Pass a
1831
+ * space (`" "`) as `replaceCh` to keep offsets stable — this is useful when you
1832
+ * need to correlate positions between the original JSONC and the stripped JSON.
1833
+ *
1834
+ * @see {@link parse} — parse JSONC directly without a stripping step
707
1835
  *
708
1836
  * @example
1837
+ * Basic comment stripping:
709
1838
  * ```ts
710
1839
  * import { Effect } from "effect";
711
- * import { stripComments } from "@spencerbeggs/jsonc-effect";
1840
+ * import { stripComments } from "jsonc-effect";
712
1841
  *
713
- * const json = Effect.runSync(stripComments('{ "a": 1 // comment\n}'));
714
- * // '{ "a": 1 \n}'
1842
+ * const json = Effect.runSync(
1843
+ * stripComments('{ "a": 1 // comment\n}'),
1844
+ * );
1845
+ * console.log(json); // '{ "a": 1 \n}'
1846
+ * ```
1847
+ *
1848
+ * @example
1849
+ * Using a replacement character to preserve offsets:
1850
+ * ```ts
1851
+ * import { Effect } from "effect";
1852
+ * import { stripComments } from "jsonc-effect";
1853
+ *
1854
+ * const json = Effect.runSync(
1855
+ * stripComments('{ "a": 1 // comment\n}', " "),
1856
+ * );
1857
+ * console.log(json.length === '{ "a": 1 // comment\n}'.length); // true
715
1858
  * ```
1859
+ *
1860
+ * @public
716
1861
  */
717
1862
  export declare const stripComments: {
718
1863
  (text: string): Effect.Effect<string>;
@@ -720,31 +1865,118 @@ export declare const stripComments: {
720
1865
  };
721
1866
 
722
1867
  /**
723
- * Create a Stream of visitor events from JSONC text.
1868
+ * Create a lazy `Stream` of {@link JsoncVisitorEvent} from JSONC text.
724
1869
  *
725
- * Uses a lazy generator internally events are produced on demand
726
- * as the stream is consumed, not pre-collected into memory.
1870
+ * Events are produced on demand as the stream is consumed, not
1871
+ * pre-collected into memory. This makes `visit` suitable for large
1872
+ * documents and supports early termination via `Stream.take` or
1873
+ * `Stream.takeWhile` without scanning the entire input.
727
1874
  *
728
- * @example
1875
+ * @param text - The JSONC source text to visit.
1876
+ * @param options - Optional partial {@link JsoncParseOptions} controlling
1877
+ * comment handling and trailing-comma tolerance.
1878
+ * @returns A `Stream` of {@link JsoncVisitorEvent} objects.
1879
+ *
1880
+ * @remarks
1881
+ * The stream is backed by a lazy generator — no work is performed until
1882
+ * the stream is consumed. Because evaluation is demand-driven, combining
1883
+ * `visit` with `Stream.take` allows efficient partial scans of large
1884
+ * documents without allocating a full AST.
1885
+ *
1886
+ * @see {@link visitCollect} for a one-step filter-and-collect convenience.
1887
+ * @see {@link JsoncVisitorEvent} for the event type definitions.
1888
+ *
1889
+ * @example Collect all events
729
1890
  * ```ts
730
1891
  * import { Chunk, Effect, Stream } from "effect";
731
- * import { visit } from "@spencerbeggs/jsonc-effect";
1892
+ * import { visit } from "jsonc-effect";
732
1893
  *
733
- * // Collect all events
734
1894
  * const all = Effect.runSync(
735
- * visit('{ "a": 1 }').pipe(Stream.runCollect, Effect.map(Chunk.toReadonlyArray)),
1895
+ * visit('{ "a": 1 }').pipe(
1896
+ * Stream.runCollect,
1897
+ * Effect.map(Chunk.toReadonlyArray),
1898
+ * ),
1899
+ * );
1900
+ * ```
1901
+ *
1902
+ * @example Filter and take the first match
1903
+ * ```ts
1904
+ * import { Chunk, Effect, Stream } from "effect";
1905
+ * import { visit } from "jsonc-effect";
1906
+ *
1907
+ * const firstLiteral = Effect.runSync(
1908
+ * visit('{ "a": 1, "b": 2 }').pipe(
1909
+ * Stream.filter((e) => e._tag === "LiteralValue"),
1910
+ * Stream.take(1),
1911
+ * Stream.runCollect,
1912
+ * Effect.map(Chunk.toReadonlyArray),
1913
+ * ),
736
1914
  * );
1915
+ * ```
1916
+ *
1917
+ * @example Extract property names
1918
+ * ```ts
1919
+ * import { Chunk, Effect, Stream } from "effect";
1920
+ * import { visit } from "jsonc-effect";
737
1921
  *
738
- * // Take only the first 3 events (lazy — won't scan entire document)
739
- * const first3 = Effect.runSync(
740
- * visit(largeDoc).pipe(Stream.take(3), Stream.runCollect, Effect.map(Chunk.toReadonlyArray)),
1922
+ * const propertyNames = Effect.runSync(
1923
+ * visit('{ "name": "Alice", "age": 30 }').pipe(
1924
+ * Stream.filter((e) => e._tag === "ObjectProperty"),
1925
+ * Stream.map((e) => (e as { property: string }).property),
1926
+ * Stream.runCollect,
1927
+ * Effect.map(Chunk.toReadonlyArray),
1928
+ * ),
741
1929
  * );
742
1930
  * ```
1931
+ *
1932
+ * @privateRemarks
1933
+ * Internally wraps a generator function with `Stream.fromIterable`,
1934
+ * preserving laziness. The generator yields events as it encounters
1935
+ * tokens from the scanner.
1936
+ *
1937
+ * @public
743
1938
  */
744
1939
  export declare const visit: (text: string, options?: Partial<JsoncParseOptions> | undefined) => Stream.Stream<JsoncVisitorEvent, never, never>;
745
1940
 
746
1941
  /**
747
- * Visit JSONC text and collect all events matching a predicate.
1942
+ * Visit JSONC text and collect all events matching a type-guard predicate.
1943
+ *
1944
+ * This is a convenience that composes {@link visit}, `Stream.filter`, and
1945
+ * `Stream.runCollect` into a single call.
1946
+ *
1947
+ * @param text - The JSONC source text to visit.
1948
+ * @param predicate - A type-guard function that narrows
1949
+ * {@link JsoncVisitorEvent} to the desired subtype `A`.
1950
+ * @param options - Optional partial {@link JsoncParseOptions}.
1951
+ * @returns An `Effect` that succeeds with a read-only array of the
1952
+ * matched events.
1953
+ *
1954
+ * @remarks
1955
+ * Equivalent to:
1956
+ * ```
1957
+ * visit(text, options) |> Stream.filter(predicate) |> Stream.runCollect
1958
+ * ```
1959
+ * Use this when you need all matching events and do not require
1960
+ * intermediate stream transformations.
1961
+ *
1962
+ * @see {@link visit} for full stream-level control.
1963
+ *
1964
+ * @example Collecting literal values
1965
+ * ```ts
1966
+ * import { Effect } from "effect";
1967
+ * import type { JsoncVisitorEvent } from "jsonc-effect";
1968
+ * import { visitCollect } from "jsonc-effect";
1969
+ *
1970
+ * const literals = Effect.runSync(
1971
+ * visitCollect(
1972
+ * '{ "a": 1, "b": true }',
1973
+ * (e): e is Extract<JsoncVisitorEvent, { _tag: "LiteralValue" }> =>
1974
+ * e._tag === "LiteralValue",
1975
+ * ),
1976
+ * );
1977
+ * ```
1978
+ *
1979
+ * @public
748
1980
  */
749
1981
  export declare const visitCollect: <A extends JsoncVisitorEvent>(text: string, predicate: (event: JsoncVisitorEvent) => event is A, options?: Partial<JsoncParseOptions> | undefined) => Effect.Effect<readonly A[], never, never>;
750
1982