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.
- package/README.md +17 -0
- package/index.d.ts +1375 -143
- package/index.js +410 -380
- 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
|
-
*
|
|
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
|
|
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
|
-
* @
|
|
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
|
-
*
|
|
109
|
+
* Compare two JSONC strings for semantic equality.
|
|
38
110
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
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
|
-
* @
|
|
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
|
|
45
|
-
* import {
|
|
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
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
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
|
-
*
|
|
55
|
-
*
|
|
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
|
-
* @
|
|
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
|
|
69
|
-
* import {
|
|
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
|
-
*
|
|
72
|
-
*
|
|
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
|
-
*
|
|
84
|
-
*
|
|
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 {
|
|
375
|
+
* import type { JsoncEdit } from "jsonc-effect";
|
|
376
|
+
* import { format, applyEdits } from "jsonc-effect";
|
|
90
377
|
*
|
|
91
|
-
* const
|
|
92
|
-
* const
|
|
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
|
|
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
|
-
* @
|
|
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,
|
|
108
|
-
* import {
|
|
443
|
+
* import { Effect, Option } from "effect";
|
|
444
|
+
* import type { JsoncNode, JsoncPath } from "jsonc-effect";
|
|
445
|
+
* import { parseTree, getNodePath } from "jsonc-effect";
|
|
109
446
|
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
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
|
-
*
|
|
121
|
-
*
|
|
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
|
|
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 {
|
|
569
|
+
* import type { JsoncError } from "jsonc-effect";
|
|
570
|
+
* import { parse, parseTree, findNode, modify } from "jsonc-effect";
|
|
154
571
|
*
|
|
155
|
-
* const program =
|
|
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
|
|
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
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
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
|
-
*
|
|
228
|
-
*
|
|
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
|
|
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
|
-
/**
|
|
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
|
-
*
|
|
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
|
-
/**
|
|
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
|
-
*
|
|
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
|
|
938
|
+
* import { parse } from "jsonc-effect";
|
|
326
939
|
*
|
|
327
940
|
* const program = parse("{ invalid }").pipe(
|
|
328
941
|
* Effect.catchTag("JsoncParseError", (e) => {
|
|
329
|
-
*
|
|
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
|
-
/**
|
|
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
|
|
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
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
|
1250
|
+
/** Advance the cursor to the next token and return its {@link JsoncSyntaxKind}. */
|
|
460
1251
|
scan(): JsoncSyntaxKind;
|
|
461
|
-
/**
|
|
1252
|
+
/** Return the {@link JsoncSyntaxKind} of the current token without advancing. */
|
|
462
1253
|
getToken(): JsoncSyntaxKind;
|
|
463
|
-
/**
|
|
1254
|
+
/** Return the string value of the current token (e.g. the unescaped content of a string literal). */
|
|
464
1255
|
getTokenValue(): string;
|
|
465
|
-
/**
|
|
1256
|
+
/** Return the zero-based character offset where the current token begins. */
|
|
466
1257
|
getTokenOffset(): number;
|
|
467
|
-
/**
|
|
1258
|
+
/** Return the character length of the current token. */
|
|
468
1259
|
getTokenLength(): number;
|
|
469
|
-
/**
|
|
1260
|
+
/** Return the zero-based line number where the current token starts. */
|
|
470
1261
|
getTokenStartLine(): number;
|
|
471
|
-
/**
|
|
1262
|
+
/** Return the zero-based character position within the line where the current token starts. */
|
|
472
1263
|
getTokenStartCharacter(): number;
|
|
473
|
-
/**
|
|
1264
|
+
/** Return the {@link JsoncScanError} for the current token, or `"None"` if no error. */
|
|
474
1265
|
getTokenError(): JsoncScanError;
|
|
475
|
-
/**
|
|
1266
|
+
/** Return the current cursor position (byte offset into the source text). */
|
|
476
1267
|
getPosition(): number;
|
|
477
|
-
/** Set the
|
|
1268
|
+
/** Set the cursor position, resetting the current token state. */
|
|
478
1269
|
setPosition(pos: number): void;
|
|
479
1270
|
}
|
|
480
1271
|
|
|
481
1272
|
/**
|
|
482
|
-
* A
|
|
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
|
-
*
|
|
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
|
|
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`
|
|
588
|
-
* JSON. Comments present in the original JSONC
|
|
589
|
-
* during round-trip encode
|
|
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
|
-
* @
|
|
592
|
-
*
|
|
593
|
-
*
|
|
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
|
|
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
|
-
* @
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
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
|
-
*
|
|
619
|
-
*
|
|
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
|
-
* @
|
|
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
|
|
631
|
-
* import { modify, applyEdits } from "
|
|
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
|
-
*
|
|
634
|
-
* const edits = Effect.runSync(modify(
|
|
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
|
-
*
|
|
1656
|
+
* const input = '{ "a": 1 }';
|
|
637
1657
|
* const result = pipe(
|
|
638
|
-
*
|
|
639
|
-
* modify(["a"],
|
|
640
|
-
* Effect.flatMap((edits) => applyEdits(
|
|
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 -
|
|
658
|
-
* @param options - Optional
|
|
659
|
-
*
|
|
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 "
|
|
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
|
-
*
|
|
670
|
-
*
|
|
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
|
-
*
|
|
682
|
-
*
|
|
683
|
-
* @
|
|
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 "
|
|
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
|
-
*
|
|
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 -
|
|
705
|
-
* @param replaceCh - Optional character to replace
|
|
706
|
-
*
|
|
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 "
|
|
1840
|
+
* import { stripComments } from "jsonc-effect";
|
|
712
1841
|
*
|
|
713
|
-
* const json = Effect.runSync(
|
|
714
|
-
*
|
|
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
|
|
1868
|
+
* Create a lazy `Stream` of {@link JsoncVisitorEvent} from JSONC text.
|
|
724
1869
|
*
|
|
725
|
-
*
|
|
726
|
-
*
|
|
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
|
-
* @
|
|
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 "
|
|
1892
|
+
* import { visit } from "jsonc-effect";
|
|
732
1893
|
*
|
|
733
|
-
* // Collect all events
|
|
734
1894
|
* const all = Effect.runSync(
|
|
735
|
-
* visit('{ "a": 1 }').pipe(
|
|
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
|
-
*
|
|
739
|
-
*
|
|
740
|
-
*
|
|
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
|
|