@effected/yaml 0.23.0 → 0.25.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/Yaml.js +47 -45
- package/YamlDiagnostic.js +4 -1
- package/YamlDocument.js +126 -49
- package/YamlFormat.js +136 -62
- package/index.d.ts +196 -33
- package/internal/composer/scalars.js +1 -0
- package/internal/diagnostics.js +18 -11
- package/internal/stringifier.js +31 -9
- package/package.json +1 -1
package/Yaml.js
CHANGED
|
@@ -171,11 +171,14 @@ var YamlParseError = class extends Schema.TaggedError()("YamlParseError", {
|
|
|
171
171
|
}
|
|
172
172
|
};
|
|
173
173
|
/**
|
|
174
|
-
* Stringification failure
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
174
|
+
* Stringification failure, carrying structured {@link YamlDiagnostic} entries
|
|
175
|
+
* and the offending value. Raised by {@link Yaml.stringify},
|
|
176
|
+
* `YamlDocument#stringify` and the encode direction of the schema factories
|
|
177
|
+
* on a circular reference (`CircularReference`), a value nested past the
|
|
178
|
+
* stringifier's recursion budget (`NestingDepthExceeded`) or a value with no
|
|
179
|
+
* YAML representation (`UnrepresentableValue` — a function or a symbol). The
|
|
180
|
+
* error itself has no `code` field: read the code from the diagnostics —
|
|
181
|
+
* `error.diagnostics[0].code` is the primary failure.
|
|
179
182
|
*
|
|
180
183
|
* @public
|
|
181
184
|
*/
|
|
@@ -224,13 +227,17 @@ const aliasCountExceededError = (message, text) => new YamlParseError({
|
|
|
224
227
|
/**
|
|
225
228
|
* Map an internal stringifier throw to its typed {@link YamlStringifyError},
|
|
226
229
|
* or return `undefined` for any other defect (which the caller re-throws).
|
|
227
|
-
* Shared by
|
|
228
|
-
*
|
|
230
|
+
* Shared by every stringify path — `Yaml.stringify`/`stringifyResult`, the
|
|
231
|
+
* schema encoders, `YamlDocument#stringifyResult` and `YamlFormat.modify`'s
|
|
232
|
+
* backstop — so all of them surface the hardening guards (circular
|
|
233
|
+
* reference, unrepresentable value, nesting-depth cap) identically.
|
|
234
|
+
*
|
|
235
|
+
* @internal
|
|
229
236
|
*/
|
|
230
237
|
const stringifyDefectToError = (defect, value) => {
|
|
231
238
|
if (defect instanceof StringifyFailure) return new YamlStringifyError({
|
|
232
239
|
diagnostics: [YamlDiagnostic.make({
|
|
233
|
-
code:
|
|
240
|
+
code: defect.code,
|
|
234
241
|
message: defect.reason,
|
|
235
242
|
offset: 0,
|
|
236
243
|
length: 0,
|
|
@@ -266,12 +273,13 @@ const parseResultImpl = (text, options) => {
|
|
|
266
273
|
input: text
|
|
267
274
|
}));
|
|
268
275
|
const anchors = /* @__PURE__ */ new Map();
|
|
269
|
-
try
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
276
|
+
return Result.try({
|
|
277
|
+
try: () => nodeToJsValue(doc.contents, anchors, options?.maxAliasCount ?? 100),
|
|
278
|
+
catch: (defect) => {
|
|
279
|
+
if (defect instanceof AliasExpansionBudgetExceeded) return aliasCountExceededError(defect.message, text);
|
|
280
|
+
throw defect;
|
|
281
|
+
}
|
|
282
|
+
});
|
|
275
283
|
};
|
|
276
284
|
/**
|
|
277
285
|
* Synchronous multi-document parse returning a `Result`. Mirrors
|
|
@@ -304,19 +312,18 @@ const parseAllResultImpl = (text, options) => {
|
|
|
304
312
|
};
|
|
305
313
|
/**
|
|
306
314
|
* Synchronous stringify returning a `Result`. Mirrors {@link Yaml.stringify}
|
|
307
|
-
* without the Effect wrapper: a circular reference
|
|
308
|
-
* recursion budget yields a `Failure`
|
|
309
|
-
* never a thrown defect.
|
|
315
|
+
* without the Effect wrapper: a circular reference, a function or symbol
|
|
316
|
+
* value, or a value nested past the recursion budget yields a `Failure`
|
|
317
|
+
* carrying a typed {@link YamlStringifyError}, never a thrown defect.
|
|
310
318
|
*/
|
|
311
|
-
const stringifyResultImpl = (value, options) => {
|
|
312
|
-
try
|
|
313
|
-
|
|
314
|
-
} catch (defect) {
|
|
319
|
+
const stringifyResultImpl = (value, options) => Result.try({
|
|
320
|
+
try: () => stringifyValue(value, toStringifyInput(options)),
|
|
321
|
+
catch: (defect) => {
|
|
315
322
|
const error = stringifyDefectToError(defect, value);
|
|
316
|
-
if (error !== void 0) return
|
|
323
|
+
if (error !== void 0) return error;
|
|
317
324
|
throw defect;
|
|
318
325
|
}
|
|
319
|
-
};
|
|
326
|
+
});
|
|
320
327
|
/**
|
|
321
328
|
* Collect the raw diagnostics that make a composed document a parse failure:
|
|
322
329
|
* every fatal-code error, plus DuplicateKey warnings promoted to errors when
|
|
@@ -328,14 +335,6 @@ const failureRecords = (doc, uniqueKeys) => {
|
|
|
328
335
|
if (fatal.length > 0) return fatal;
|
|
329
336
|
return uniqueKeys ? doc.warnings.filter((w) => w.code === "DuplicateKey") : [];
|
|
330
337
|
};
|
|
331
|
-
const stringifyOrFail = (value, options) => Effect.try({
|
|
332
|
-
try: () => stringifyValue(value, toStringifyInput(options)),
|
|
333
|
-
catch: (defect) => {
|
|
334
|
-
const error = stringifyDefectToError(defect, value);
|
|
335
|
-
if (error !== void 0) return error;
|
|
336
|
-
throw defect;
|
|
337
|
-
}
|
|
338
|
-
});
|
|
339
338
|
/**
|
|
340
339
|
* Static entry points for YAML parsing, stringification, comment stripping,
|
|
341
340
|
* semantic equality and the schema factories. Not instantiable.
|
|
@@ -405,10 +404,14 @@ var Yaml = class Yaml {
|
|
|
405
404
|
static parseAll = Effect.fn("Yaml.parseAll")((text, options) => Effect.fromResult(Yaml.parseAllResult(text, options)));
|
|
406
405
|
/**
|
|
407
406
|
* Stringify a plain JavaScript value as YAML. Fails with
|
|
408
|
-
* {@link YamlStringifyError} on circular references (`CircularReference`)
|
|
409
|
-
*
|
|
410
|
-
* (`NestingDepthExceeded`)
|
|
411
|
-
*
|
|
407
|
+
* {@link YamlStringifyError} on circular references (`CircularReference`),
|
|
408
|
+
* on a value nested deeper than the stringifier's recursion budget
|
|
409
|
+
* (`NestingDepthExceeded`) and on a function or symbol anywhere in the
|
|
410
|
+
* value (`UnrepresentableValue`) — all surface through the typed error
|
|
411
|
+
* channel, never as a stack-overflow defect and never as the function's
|
|
412
|
+
* source text or `Symbol(s)` written into the document as a string. A
|
|
413
|
+
* `bigint` is an integer and renders bare, exactly as `YamlFormat.modify`
|
|
414
|
+
* writes one; `null` and `undefined` both render as `null`.
|
|
412
415
|
*
|
|
413
416
|
* @remarks
|
|
414
417
|
* A `"<<"` object key is emitted **quoted** (`'<<': …`). This is the
|
|
@@ -425,9 +428,7 @@ var Yaml = class Yaml {
|
|
|
425
428
|
* @returns An `Effect` that succeeds with the YAML text, or fails with
|
|
426
429
|
* {@link YamlStringifyError}.
|
|
427
430
|
*/
|
|
428
|
-
static stringify = Effect.fn("Yaml.stringify")(
|
|
429
|
-
return yield* stringifyOrFail(value, options);
|
|
430
|
-
});
|
|
431
|
+
static stringify = Effect.fn("Yaml.stringify")((value, options) => Effect.fromResult(stringifyResultImpl(value, options)));
|
|
431
432
|
/**
|
|
432
433
|
* Synchronous single-document parse, returning a `Result` instead of
|
|
433
434
|
* an `Effect`. A pure escape hatch for config-time callers that cannot
|
|
@@ -510,10 +511,11 @@ var Yaml = class Yaml {
|
|
|
510
511
|
* The pure counterpart to {@link Yaml.stringify} for config-time callers
|
|
511
512
|
* that cannot `await`.
|
|
512
513
|
*
|
|
513
|
-
* Preserves the package contract — a circular reference (`CircularReference`)
|
|
514
|
-
*
|
|
515
|
-
*
|
|
516
|
-
* thrown
|
|
514
|
+
* Preserves the package contract — a circular reference (`CircularReference`),
|
|
515
|
+
* a value nested past the recursion budget (`NestingDepthExceeded`) or a
|
|
516
|
+
* function or symbol value (`UnrepresentableValue`) yields a `Failure`
|
|
517
|
+
* carrying a {@link YamlStringifyError} rather than a thrown defect; the
|
|
518
|
+
* method never throws.
|
|
517
519
|
*
|
|
518
520
|
* @example
|
|
519
521
|
* ```ts
|
|
@@ -631,7 +633,7 @@ var Yaml = class Yaml {
|
|
|
631
633
|
static fromString(options) {
|
|
632
634
|
return Schema.String.pipe(Schema.decodeTo(Schema.Unknown, SchemaTransformation.transformEffect({
|
|
633
635
|
decode: (input) => Yaml.parse(input, options).pipe(Effect.mapError((error) => new SchemaIssue.InvalidValue({ message: error.message }, input))),
|
|
634
|
-
encode: (value) =>
|
|
636
|
+
encode: (value) => Effect.fromResult(stringifyResultImpl(value)).pipe(Effect.mapError((error) => new SchemaIssue.InvalidValue({ message: error.message }, value)))
|
|
635
637
|
})));
|
|
636
638
|
}
|
|
637
639
|
/**
|
|
@@ -655,7 +657,7 @@ var Yaml = class Yaml {
|
|
|
655
657
|
if (values.length === 0) return "";
|
|
656
658
|
const parts = [];
|
|
657
659
|
for (let index = 0; index < values.length; index++) {
|
|
658
|
-
const yaml = yield*
|
|
660
|
+
const yaml = yield* Effect.fromResult(stringifyResultImpl(values[index])).pipe(Effect.mapError((error) => new SchemaIssue.InvalidValue({ message: error.message }, values)));
|
|
659
661
|
parts.push(index > 0 ? `---\n${yaml}` : yaml);
|
|
660
662
|
}
|
|
661
663
|
return parts.join("");
|
|
@@ -774,4 +776,4 @@ function deepEqualValues(a, b) {
|
|
|
774
776
|
return false;
|
|
775
777
|
}
|
|
776
778
|
|
|
777
|
-
export { Yaml, YamlParseError, YamlParseOptions, YamlStringifyError, YamlStringifyOptions };
|
|
779
|
+
export { Yaml, YamlParseError, YamlParseOptions, YamlStringifyError, YamlStringifyOptions, stringifyDefectToError };
|
package/YamlDiagnostic.js
CHANGED
|
@@ -21,7 +21,10 @@ const YamlParseErrorCode = Schema.Literals(YAML_PARSE_ERROR_CODES);
|
|
|
21
21
|
*/
|
|
22
22
|
const YamlComposerErrorCode = Schema.Literals(YAML_COMPOSE_ERROR_CODES);
|
|
23
23
|
/**
|
|
24
|
-
* Error codes emitted by the stringifier (the
|
|
24
|
+
* Error codes emitted by the stringifier: `CircularReference` (the value or
|
|
25
|
+
* synthetic AST points back at itself) and `UnrepresentableValue` (a function
|
|
26
|
+
* or symbol, which has no YAML rendering and is never written as its
|
|
27
|
+
* `String()` form).
|
|
25
28
|
*
|
|
26
29
|
* @public
|
|
27
30
|
*/
|
package/YamlDocument.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { YamlNode } from "./YamlNode.js";
|
|
2
2
|
import { composeAllDocuments, composeFirstDocument } from "./internal/composer/document.js";
|
|
3
3
|
import { isFatalCode } from "./internal/diagnostics.js";
|
|
4
|
-
import {
|
|
4
|
+
import { stringifyDocument } from "./internal/stringifier.js";
|
|
5
5
|
import { YamlDiagnostic } from "./YamlDiagnostic.js";
|
|
6
|
-
import { YamlParseError,
|
|
7
|
-
import { Effect, Schema, SchemaIssue, SchemaTransformation } from "effect";
|
|
6
|
+
import { YamlParseError, stringifyDefectToError } from "./Yaml.js";
|
|
7
|
+
import { Effect, Result, Schema, SchemaIssue, SchemaTransformation } from "effect";
|
|
8
8
|
|
|
9
9
|
// src/YamlDocument.ts
|
|
10
10
|
/**
|
|
@@ -58,11 +58,47 @@ var YamlDocument = class YamlDocument extends Schema.Class("YamlDocument")({
|
|
|
58
58
|
hasDocumentEnd: Schema.optionalKey(Schema.Boolean),
|
|
59
59
|
hasDocumentStartTab: Schema.optionalKey(Schema.Boolean)
|
|
60
60
|
}) {
|
|
61
|
+
/**
|
|
62
|
+
* Synchronous single-document parse, returning a `Result` instead of an
|
|
63
|
+
* `Effect`. This is the primitive {@link YamlDocument.parse} is defined in
|
|
64
|
+
* terms of — a synchronous host can call it without an Effect runtime.
|
|
65
|
+
* Keeps the full AST, directives and recovered diagnostics; fails with the
|
|
66
|
+
* aggregate {@link YamlParseError} when any fatal-code diagnostic is
|
|
67
|
+
* present, and non-fatal diagnostics are data on the returned document.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* import { YamlDocument } from "@effected/yaml";
|
|
72
|
+
* import { Result } from "effect";
|
|
73
|
+
*
|
|
74
|
+
* const result = YamlDocument.parseResult("name: Alice\n");
|
|
75
|
+
* if (Result.isSuccess(result)) {
|
|
76
|
+
* console.log(result.success.toValue()); // => { name: "Alice" }
|
|
77
|
+
* }
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* @param text - The YAML source to parse.
|
|
81
|
+
* @param options - Optional {@link YamlParseOptions}; defaults apply for
|
|
82
|
+
* omitted fields.
|
|
83
|
+
* @returns A `Result` succeeding with the {@link YamlDocument}, or failing
|
|
84
|
+
* with {@link YamlParseError}.
|
|
85
|
+
*/
|
|
86
|
+
static parseResult(text, options) {
|
|
87
|
+
const raw = composeFirstDocument(text, toParseInput(options));
|
|
88
|
+
const fatal = raw.errors.filter((e) => isFatalCode(e.code));
|
|
89
|
+
if (fatal.length > 0) return Result.fail(new YamlParseError({
|
|
90
|
+
diagnostics: fatal.map((e) => YamlDiagnostic.fromRaw(e, text)),
|
|
91
|
+
input: text
|
|
92
|
+
}));
|
|
93
|
+
return Result.succeed(fromRawDocument(raw, text));
|
|
94
|
+
}
|
|
61
95
|
/**
|
|
62
96
|
* Parse a single YAML document, keeping the full AST, directives and
|
|
63
97
|
* recovered diagnostics. Fails with the aggregate {@link YamlParseError}
|
|
64
98
|
* when any fatal-code diagnostic is present; non-fatal diagnostics are
|
|
65
|
-
* data on the returned document.
|
|
99
|
+
* data on the returned document. Defined in terms of
|
|
100
|
+
* {@link YamlDocument.parseResult} — synchronous callers can use that
|
|
101
|
+
* variant directly.
|
|
66
102
|
*
|
|
67
103
|
* @param text - The YAML source to parse.
|
|
68
104
|
* @param options - Optional {@link YamlParseOptions}; defaults apply for
|
|
@@ -70,19 +106,46 @@ var YamlDocument = class YamlDocument extends Schema.Class("YamlDocument")({
|
|
|
70
106
|
* @returns An `Effect` that succeeds with the {@link YamlDocument}, or fails
|
|
71
107
|
* with {@link YamlParseError}.
|
|
72
108
|
*/
|
|
73
|
-
static parse = Effect.fn("YamlDocument.parse")(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
109
|
+
static parse = Effect.fn("YamlDocument.parse")((text, options) => Effect.fromResult(YamlDocument.parseResult(text, options)));
|
|
110
|
+
/**
|
|
111
|
+
* Synchronous multi-document parse, returning a `Result` instead of an
|
|
112
|
+
* `Effect` — the primitive {@link YamlDocument.parseAll} is defined in
|
|
113
|
+
* terms of. Any fatal diagnostic in any document — or a stream-level
|
|
114
|
+
* directive-placement error — fails the whole parse with one aggregate
|
|
115
|
+
* {@link YamlParseError}.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* import { YamlDocument } from "@effected/yaml";
|
|
120
|
+
* import { Result } from "effect";
|
|
121
|
+
*
|
|
122
|
+
* const result = YamlDocument.parseAllResult("a: 1\n---\nb: 2\n");
|
|
123
|
+
* if (Result.isSuccess(result)) {
|
|
124
|
+
* console.log(result.success.length); // => 2
|
|
125
|
+
* }
|
|
126
|
+
* ```
|
|
127
|
+
*
|
|
128
|
+
* @param text - The YAML stream to parse.
|
|
129
|
+
* @param options - Optional {@link YamlParseOptions}; defaults apply for
|
|
130
|
+
* omitted fields.
|
|
131
|
+
* @returns A `Result` succeeding with one {@link YamlDocument} per
|
|
132
|
+
* document, or failing with {@link YamlParseError}.
|
|
133
|
+
*/
|
|
134
|
+
static parseAllResult(text, options) {
|
|
135
|
+
const { documents, streamErrors } = composeAllDocuments(text, toParseInput(options));
|
|
136
|
+
const fatal = [...streamErrors.filter((e) => e.code === "InvalidDirective"), ...documents.flatMap((d) => d.errors.filter((e) => isFatalCode(e.code)))];
|
|
137
|
+
if (fatal.length > 0) return Result.fail(new YamlParseError({
|
|
77
138
|
diagnostics: fatal.map((e) => YamlDiagnostic.fromRaw(e, text)),
|
|
78
139
|
input: text
|
|
79
|
-
});
|
|
80
|
-
return fromRawDocument(raw, text);
|
|
81
|
-
}
|
|
140
|
+
}));
|
|
141
|
+
return Result.succeed(documents.map((raw) => fromRawDocument(raw, text)));
|
|
142
|
+
}
|
|
82
143
|
/**
|
|
83
144
|
* Parse a multi-document YAML stream into one {@link YamlDocument} per
|
|
84
145
|
* document. Any fatal diagnostic in any document — or a stream-level
|
|
85
|
-
* directive-placement error — fails the whole Effect.
|
|
146
|
+
* directive-placement error — fails the whole Effect. Defined in terms of
|
|
147
|
+
* {@link YamlDocument.parseAllResult} — synchronous callers can use that
|
|
148
|
+
* variant directly.
|
|
86
149
|
*
|
|
87
150
|
* @param text - The YAML stream to parse.
|
|
88
151
|
* @param options - Optional {@link YamlParseOptions}; defaults apply for
|
|
@@ -90,15 +153,7 @@ var YamlDocument = class YamlDocument extends Schema.Class("YamlDocument")({
|
|
|
90
153
|
* @returns An `Effect` that succeeds with one {@link YamlDocument} per
|
|
91
154
|
* document, or fails with {@link YamlParseError}.
|
|
92
155
|
*/
|
|
93
|
-
static parseAll = Effect.fn("YamlDocument.parseAll")(
|
|
94
|
-
const { documents, streamErrors } = composeAllDocuments(text, toParseInput(options));
|
|
95
|
-
const fatal = [...streamErrors.filter((e) => e.code === "InvalidDirective"), ...documents.flatMap((d) => d.errors.filter((e) => isFatalCode(e.code)))];
|
|
96
|
-
if (fatal.length > 0) return yield* new YamlParseError({
|
|
97
|
-
diagnostics: fatal.map((e) => YamlDiagnostic.fromRaw(e, text)),
|
|
98
|
-
input: text
|
|
99
|
-
});
|
|
100
|
-
return documents.map((raw) => fromRawDocument(raw, text));
|
|
101
|
-
});
|
|
156
|
+
static parseAll = Effect.fn("YamlDocument.parseAll")((text, options) => Effect.fromResult(YamlDocument.parseAllResult(text, options)));
|
|
102
157
|
/**
|
|
103
158
|
* A `Schema<YamlDocument, string>` decoding YAML text into a full
|
|
104
159
|
* document (AST, directives, diagnostics) and encoding a document back to
|
|
@@ -119,11 +174,19 @@ var YamlDocument = class YamlDocument extends Schema.Class("YamlDocument")({
|
|
|
119
174
|
}
|
|
120
175
|
/**
|
|
121
176
|
* Stringify this document (contents, directives and framing) as YAML.
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
177
|
+
* A parsed document always stringifies; the failures belong to hand-built
|
|
178
|
+
* ASTs and surface as {@link YamlStringifyError} through the typed error
|
|
179
|
+
* channel, never as an unhandled stack-overflow defect or as corrupted
|
|
180
|
+
* output: a cycle in the AST fails `CircularReference` on the first
|
|
181
|
+
* re-entry of an ancestor collection (the node path keeps the same
|
|
182
|
+
* ancestor set the value path does), a tree nested deeper than the
|
|
183
|
+
* stringifier's recursion budget fails `NestingDepthExceeded`, and a
|
|
184
|
+
* scalar node holding anything but `null`, a boolean, a number, a bigint
|
|
185
|
+
* or a string — a function, a symbol, an object — fails
|
|
186
|
+
* `UnrepresentableValue` rather than being written as its `String()` form.
|
|
187
|
+
* Defined in terms of {@link YamlDocument.stringifyResult} behind a
|
|
188
|
+
* `YamlDocument.stringify` span — synchronous callers can use that variant
|
|
189
|
+
* directly.
|
|
127
190
|
*
|
|
128
191
|
* @remarks
|
|
129
192
|
* `YamlStringifyOptions.lineWidth` is not honored here: column-based
|
|
@@ -142,31 +205,45 @@ var YamlDocument = class YamlDocument extends Schema.Class("YamlDocument")({
|
|
|
142
205
|
* {@link YamlStringifyError}.
|
|
143
206
|
*/
|
|
144
207
|
stringify(options) {
|
|
145
|
-
return Effect.
|
|
208
|
+
return Effect.suspend(() => Effect.fromResult(this.stringifyResult(options))).pipe(Effect.withSpan("YamlDocument.stringify"));
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Synchronous stringify, returning a `Result` instead of an `Effect` — the
|
|
212
|
+
* primitive {@link YamlDocument.stringify} is defined in terms of, so a
|
|
213
|
+
* synchronous host can round-trip a document parsed with
|
|
214
|
+
* {@link YamlDocument.parseResult} without an Effect runtime. Fails with
|
|
215
|
+
* {@link YamlStringifyError} exactly where `stringify` does: a hand-built
|
|
216
|
+
* AST containing a cycle (`CircularReference`), one nested deeper than the
|
|
217
|
+
* stringifier's recursion budget (`NestingDepthExceeded`) or one whose
|
|
218
|
+
* scalar node holds a value with no YAML form (`UnrepresentableValue`).
|
|
219
|
+
*
|
|
220
|
+
* @remarks
|
|
221
|
+
* `YamlStringifyOptions.lineWidth` is not honored here, for the reason
|
|
222
|
+
* given on {@link YamlDocument.stringify}.
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```ts
|
|
226
|
+
* import { YamlDocument } from "@effected/yaml";
|
|
227
|
+
* import { Result } from "effect";
|
|
228
|
+
*
|
|
229
|
+
* const parsed = YamlDocument.parseResult("# keep\nname: Alice\n");
|
|
230
|
+
* if (Result.isSuccess(parsed)) {
|
|
231
|
+
* const text = parsed.success.stringifyResult();
|
|
232
|
+
* if (Result.isSuccess(text)) console.log(text.success); // => "# keep\nname: Alice\n"
|
|
233
|
+
* }
|
|
234
|
+
* ```
|
|
235
|
+
*
|
|
236
|
+
* @param options - Optional {@link YamlStringifyOptions}; defaults apply for
|
|
237
|
+
* omitted fields.
|
|
238
|
+
* @returns A `Result` succeeding with the YAML text, or failing with
|
|
239
|
+
* {@link YamlStringifyError}.
|
|
240
|
+
*/
|
|
241
|
+
stringifyResult(options) {
|
|
242
|
+
return Result.try({
|
|
146
243
|
try: () => stringifyDocument(toRawDocument(this), toStringifyInput(options)),
|
|
147
244
|
catch: (defect) => {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
code: "CircularReference",
|
|
151
|
-
message: defect.reason,
|
|
152
|
-
offset: 0,
|
|
153
|
-
length: 0,
|
|
154
|
-
line: 0,
|
|
155
|
-
character: 0
|
|
156
|
-
})],
|
|
157
|
-
value: this
|
|
158
|
-
});
|
|
159
|
-
if (defect instanceof StringifyDepthExceeded) return new YamlStringifyError({
|
|
160
|
-
diagnostics: [YamlDiagnostic.make({
|
|
161
|
-
code: "NestingDepthExceeded",
|
|
162
|
-
message: defect.message,
|
|
163
|
-
offset: 0,
|
|
164
|
-
length: 0,
|
|
165
|
-
line: 0,
|
|
166
|
-
character: 0
|
|
167
|
-
})],
|
|
168
|
-
value: this
|
|
169
|
-
});
|
|
245
|
+
const error = stringifyDefectToError(defect, this);
|
|
246
|
+
if (error !== void 0) return error;
|
|
170
247
|
throw defect;
|
|
171
248
|
}
|
|
172
249
|
});
|
package/YamlFormat.js
CHANGED
|
@@ -3,11 +3,11 @@ import { EMPTY_DOCUMENT, composeAllDocuments, composeFirstDocumentCounted } from
|
|
|
3
3
|
import { isFatalCode } from "./internal/diagnostics.js";
|
|
4
4
|
import { renderDoubleQuoted, renderSingleQuoted, stringifyDocument, stringifyValue, stripNodeComments } from "./internal/stringifier.js";
|
|
5
5
|
import { YamlDiagnostic } from "./YamlDiagnostic.js";
|
|
6
|
-
import { YamlStringifyOptions } from "./Yaml.js";
|
|
6
|
+
import { YamlStringifyOptions, stringifyDefectToError } from "./Yaml.js";
|
|
7
7
|
import { YamlEdit, YamlRange } from "./YamlEdit.js";
|
|
8
8
|
import { computeEdits } from "./internal/diff.js";
|
|
9
9
|
import { requoteScalarText } from "./internal/requote.js";
|
|
10
|
-
import { Effect, Schema } from "effect";
|
|
10
|
+
import { Effect, Result, Schema } from "effect";
|
|
11
11
|
|
|
12
12
|
// src/YamlFormat.ts
|
|
13
13
|
/**
|
|
@@ -259,11 +259,18 @@ function formatStream(text, documents, streamErrors, options) {
|
|
|
259
259
|
* Before this was recursive, a mapping or sequence value fell through to the
|
|
260
260
|
* node stringifier's `String(value)` fallback and landed in the document as
|
|
261
261
|
* the literal text `[object Object]` — a silent corruption that only surfaced
|
|
262
|
-
* on the next read.
|
|
262
|
+
* on the next read. Every other value becomes a plain {@link YamlScalar} and
|
|
263
|
+
* renders exactly as the value path renders it: a `bigint` bare, `undefined`
|
|
264
|
+
* as `null`.
|
|
263
265
|
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
* deeper than `MAX_NESTING_DEPTH`
|
|
266
|
+
* Three conditions fail typed rather than hanging, overflowing the stack or
|
|
267
|
+
* corrupting the document: a cycle raises `CircularReference`, a graph that
|
|
268
|
+
* would sit deeper than `MAX_NESTING_DEPTH` in the output document raises
|
|
269
|
+
* `NestingDepthExceeded`, and a function or symbol — which has no YAML
|
|
270
|
+
* rendering, and whose `String()` form the value path refuses to write too —
|
|
271
|
+
* raises `UnrepresentableValue`. `depth` is measured in the stringifier's own
|
|
272
|
+
* units — one per node from the document root — so the caller passes the
|
|
273
|
+
* target's depth, not zero. `seen` holds
|
|
267
274
|
* the ancestors of the value being lowered, so a value repeated across
|
|
268
275
|
* siblings (a shared, acyclic sub-object) is lowered twice rather than
|
|
269
276
|
* rejected.
|
|
@@ -299,19 +306,31 @@ function jsValueToNode(value, seen, depth) {
|
|
|
299
306
|
seen.delete(value);
|
|
300
307
|
}
|
|
301
308
|
}
|
|
302
|
-
|
|
309
|
+
if (typeof value === "function" || typeof value === "symbol") throw new ModifyFailure("UnrepresentableValue", `A ${typeof value} value has no YAML representation`, 0, 0);
|
|
310
|
+
return value === null || value === void 0 ? YamlScalar.make({
|
|
311
|
+
value: null,
|
|
312
|
+
style: "plain",
|
|
313
|
+
raw: "null",
|
|
314
|
+
offset: 0,
|
|
315
|
+
length: 0
|
|
316
|
+
}) : YamlScalar.make({
|
|
303
317
|
value,
|
|
304
318
|
style: "plain",
|
|
305
319
|
offset: 0,
|
|
306
320
|
length: 0
|
|
307
321
|
});
|
|
308
322
|
}
|
|
309
|
-
/**
|
|
310
|
-
|
|
311
|
-
|
|
323
|
+
/**
|
|
324
|
+
* Entry point for {@link jsValueToNode}: one `seen` set per lowering, counting
|
|
325
|
+
* depth from `targetDepth` — the depth the value will occupy in the output
|
|
326
|
+
* document (the path length: a root replacement sits at 0, a value one key
|
|
327
|
+
* down at 1).
|
|
328
|
+
*/
|
|
329
|
+
function lowerValue(value, targetDepth) {
|
|
330
|
+
return jsValueToNode(value, /* @__PURE__ */ new Set(), targetDepth);
|
|
312
331
|
}
|
|
313
332
|
function modifyDocument(doc, path, value) {
|
|
314
|
-
if (path.length === 0) return value === void 0 ? null : lowerValue(value);
|
|
333
|
+
if (path.length === 0) return value === void 0 ? null : lowerValue(value, 0);
|
|
315
334
|
if (doc.contents === null) throw new ModifyFailure("EmptyDocument", "Cannot navigate path in empty document", 0, 0);
|
|
316
335
|
return modifyNode(doc.contents, path, 0, value);
|
|
317
336
|
}
|
|
@@ -327,7 +346,7 @@ function modifyNode(node, path, depth, value) {
|
|
|
327
346
|
newItems.splice(pairIndex, 1);
|
|
328
347
|
return rebuildMap(node, newItems);
|
|
329
348
|
}
|
|
330
|
-
const newValueNode = lowerValue(value);
|
|
349
|
+
const newValueNode = lowerValue(value, depth + 1);
|
|
331
350
|
if (pairIndex >= 0) {
|
|
332
351
|
const newItems = [...node.items];
|
|
333
352
|
const oldPair = newItems[pairIndex];
|
|
@@ -367,8 +386,8 @@ function modifyNode(node, path, depth, value) {
|
|
|
367
386
|
const newItems = [...node.items];
|
|
368
387
|
if (value === void 0) {
|
|
369
388
|
if (idx < newItems.length) newItems.splice(idx, 1);
|
|
370
|
-
} else if (idx < newItems.length) newItems[idx] = lowerValue(value);
|
|
371
|
-
else newItems.push(lowerValue(value));
|
|
389
|
+
} else if (idx < newItems.length) newItems[idx] = lowerValue(value, depth + 1);
|
|
390
|
+
else newItems.push(lowerValue(value, depth + 1));
|
|
372
391
|
return rebuildSeq(node, newItems);
|
|
373
392
|
}
|
|
374
393
|
if (idx >= node.items.length) throw new ModifyFailure("InvalidIndex", `Index ${idx} out of bounds`, node.offset, node.length);
|
|
@@ -678,7 +697,9 @@ var YamlFormat = class YamlFormat {
|
|
|
678
697
|
return YamlEdit.applyAll(text, YamlFormat.format(text, range, options));
|
|
679
698
|
}
|
|
680
699
|
/**
|
|
681
|
-
* Compute the edits that insert, replace, or remove a value at `path
|
|
700
|
+
* Compute the edits that insert, replace, or remove a value at `path`,
|
|
701
|
+
* synchronously — the primitive {@link YamlFormat.modify} is defined in
|
|
702
|
+
* terms of, so a synchronous host can call it without an Effect runtime.
|
|
682
703
|
* Passing `value === undefined` removes the target key/element; a missing
|
|
683
704
|
* insertion target appends after the last pair/element. Fails with
|
|
684
705
|
* {@link YamlModificationError} on a fatal parse error or a structural
|
|
@@ -688,7 +709,10 @@ var YamlFormat = class YamlFormat {
|
|
|
688
709
|
* sequence and any other non-null object as a block mapping over its own
|
|
689
710
|
* enumerable string keys, recursively — the same lowering
|
|
690
711
|
* {@link Yaml.stringify} applies to the same value, so `modify` and
|
|
691
|
-
* `stringify` agree on what a given JavaScript value means
|
|
712
|
+
* `stringify` agree on what a given JavaScript value means: a `bigint`
|
|
713
|
+
* renders bare (`a: 10`, never `a: "10"`), `null` renders as `null`, and a
|
|
714
|
+
* function or symbol fails `UnrepresentableValue` on both paths rather
|
|
715
|
+
* than landing in the document as its `String()` form. For a synthesized
|
|
692
716
|
* subtree (an object/array value) only the surrounding document is
|
|
693
717
|
* preserved byte-for-byte; the subtree carries no comments and takes the
|
|
694
718
|
* stringifier's styles.
|
|
@@ -712,10 +736,13 @@ var YamlFormat = class YamlFormat {
|
|
|
712
736
|
* whole document, which normalises line endings to LF, applies those
|
|
713
737
|
* options, and renders the replacement in the stringifier's styles.
|
|
714
738
|
*
|
|
715
|
-
*
|
|
716
|
-
*
|
|
717
|
-
* reference (`CircularReference`)
|
|
718
|
-
*
|
|
739
|
+
* Three replacement values have no rendering and fail typed rather than
|
|
740
|
+
* hanging, overflowing the stack or corrupting the document: one
|
|
741
|
+
* containing a circular reference (`CircularReference`), one that would
|
|
742
|
+
* sit deeper than 256 levels in the output document
|
|
743
|
+
* (`NestingDepthExceeded`) and one containing a function or symbol
|
|
744
|
+
* (`UnrepresentableValue`). The depth is counted from the document root,
|
|
745
|
+
* so the same value can fit at `[]` and fail a few keys down.
|
|
719
746
|
*
|
|
720
747
|
* **Single-document contract.** A `path` carries no document index, so on
|
|
721
748
|
* a multi-document stream there is no rule for which document it names —
|
|
@@ -740,63 +767,109 @@ var YamlFormat = class YamlFormat {
|
|
|
740
767
|
* target instead.
|
|
741
768
|
* @param options - Optional {@link YamlStringifyOptions} for the
|
|
742
769
|
* re-stringify step.
|
|
743
|
-
* @returns
|
|
744
|
-
* `YamlEdit.applyAll`), or
|
|
770
|
+
* @returns A `Result` succeeding with the edits to apply (via
|
|
771
|
+
* `YamlEdit.applyAll`), or failing with {@link YamlModificationError}.
|
|
745
772
|
*
|
|
746
773
|
* @remarks
|
|
747
774
|
* `options` is a bare {@link YamlStringifyOptions} — it controls only the
|
|
748
775
|
* internal re-stringify step, not a range (there is no range to restrict
|
|
749
776
|
* for a path-targeted modification).
|
|
750
777
|
*/
|
|
751
|
-
static
|
|
752
|
-
const
|
|
753
|
-
if (documentCount > 1) return yield* new YamlModificationError({
|
|
778
|
+
static modifyResult(text, path, value, options) {
|
|
779
|
+
const fail = (diagnostics) => Result.fail(new YamlModificationError({
|
|
754
780
|
path,
|
|
755
|
-
diagnostics
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
}
|
|
761
|
-
|
|
781
|
+
diagnostics
|
|
782
|
+
}));
|
|
783
|
+
const { document: doc, documentCount } = composeFirstDocumentCounted(text, {});
|
|
784
|
+
if (documentCount > 1) return fail([YamlDiagnostic.fromRaw({
|
|
785
|
+
code: "MultiDocumentStream",
|
|
786
|
+
message: `Cannot modify a multi-document stream (${documentCount} documents): modify re-emits exactly one document`,
|
|
787
|
+
offset: 0,
|
|
788
|
+
length: 0
|
|
789
|
+
}, text)]);
|
|
762
790
|
const fatal = doc.errors.filter((e) => isFatalCode(e.code));
|
|
763
|
-
if (fatal.length > 0) return
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
code: "DirectiveCarryingDocument",
|
|
771
|
-
message: "Cannot modify a document carrying %YAML/%TAG directives: modify does not re-emit directive lines, and dropping a %TAG orphans the shorthand tags that depend on it",
|
|
772
|
-
offset: 0,
|
|
773
|
-
length: 0
|
|
774
|
-
}, text)]
|
|
775
|
-
});
|
|
791
|
+
if (fatal.length > 0) return fail(fatal.map((e) => YamlDiagnostic.fromRaw(e, text)));
|
|
792
|
+
if (doc.directives.length > 0) return fail([YamlDiagnostic.fromRaw({
|
|
793
|
+
code: "DirectiveCarryingDocument",
|
|
794
|
+
message: "Cannot modify a document carrying %YAML/%TAG directives: modify does not re-emit directive lines, and dropping a %TAG orphans the shorthand tags that depend on it",
|
|
795
|
+
offset: 0,
|
|
796
|
+
length: 0
|
|
797
|
+
}, text)]);
|
|
776
798
|
const regional = tryRegionalScalarEdit(text, doc, path, value, options);
|
|
777
|
-
if (regional !== void 0) return regional.map((e) => YamlEdit.make(e));
|
|
799
|
+
if (regional !== void 0) return Result.succeed(regional.map((e) => YamlEdit.make(e)));
|
|
778
800
|
let newContents;
|
|
779
801
|
try {
|
|
780
802
|
newContents = modifyDocument(doc, path, value);
|
|
781
803
|
} catch (err) {
|
|
782
804
|
if (!(err instanceof ModifyFailure)) throw err;
|
|
783
|
-
return
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
length: err.length
|
|
790
|
-
}, text)]
|
|
791
|
-
});
|
|
805
|
+
return fail([YamlDiagnostic.fromRaw({
|
|
806
|
+
code: err.code,
|
|
807
|
+
message: err.message,
|
|
808
|
+
offset: err.offset,
|
|
809
|
+
length: err.length
|
|
810
|
+
}, text)]);
|
|
792
811
|
}
|
|
793
812
|
const outputDoc = {
|
|
794
813
|
...doc,
|
|
795
814
|
contents: newContents
|
|
796
815
|
};
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
816
|
+
let formatted;
|
|
817
|
+
try {
|
|
818
|
+
formatted = stringifyDocument(outputDoc, toStringifyInput(options));
|
|
819
|
+
} catch (defect) {
|
|
820
|
+
const error = stringifyDefectToError(defect, value);
|
|
821
|
+
if (error === void 0) throw defect;
|
|
822
|
+
return fail(error.diagnostics);
|
|
823
|
+
}
|
|
824
|
+
return Result.succeed(computeEdits(text, withSourceBom(text, formatted)).map((e) => YamlEdit.make(e)));
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Compute the edits that insert, replace, or remove a value at `path`.
|
|
828
|
+
* Defined in terms of {@link YamlFormat.modifyResult}, which carries the
|
|
829
|
+
* full contract — value lowering, region-confined scalar replacement, the
|
|
830
|
+
* single-document contract and the directive refusal — behind a
|
|
831
|
+
* `YamlFormat.modify` span; synchronous callers can use that variant
|
|
832
|
+
* directly.
|
|
833
|
+
*
|
|
834
|
+
* @param text - The YAML source to modify.
|
|
835
|
+
* @param path - The location to insert, replace or remove.
|
|
836
|
+
* @param value - The JavaScript value to write; `undefined` removes the
|
|
837
|
+
* target instead.
|
|
838
|
+
* @param options - Optional {@link YamlStringifyOptions} for the
|
|
839
|
+
* re-stringify step.
|
|
840
|
+
* @returns An `Effect` that succeeds with the edits to apply (via
|
|
841
|
+
* `YamlEdit.applyAll`), or fails with {@link YamlModificationError}.
|
|
842
|
+
*/
|
|
843
|
+
static modify = Effect.fn("YamlFormat.modify")((text, path, value, options) => Effect.fromResult(YamlFormat.modifyResult(text, path, value, options)));
|
|
844
|
+
/**
|
|
845
|
+
* Synchronous {@link YamlFormat.modifyToString}: modify `text` and apply the
|
|
846
|
+
* resulting edits in one step (`YamlEdit.applyAll ∘ modifyResult`),
|
|
847
|
+
* returning a `Result`. Inherits the {@link YamlFormat.modifyResult} error
|
|
848
|
+
* channel.
|
|
849
|
+
*
|
|
850
|
+
* @example
|
|
851
|
+
* ```ts
|
|
852
|
+
* import { YamlFormat } from "@effected/yaml";
|
|
853
|
+
* import { Result } from "effect";
|
|
854
|
+
*
|
|
855
|
+
* const result = YamlFormat.modifyToStringResult("port: 3000 # dev\n", ["port"], 8080);
|
|
856
|
+
* if (Result.isSuccess(result)) {
|
|
857
|
+
* console.log(result.success); // => "port: 8080 # dev\n"
|
|
858
|
+
* }
|
|
859
|
+
* ```
|
|
860
|
+
*
|
|
861
|
+
* @param text - The YAML source to modify.
|
|
862
|
+
* @param path - The location to insert, replace or remove.
|
|
863
|
+
* @param value - The JavaScript value to write; `undefined` removes the
|
|
864
|
+
* target instead.
|
|
865
|
+
* @param options - Optional {@link YamlStringifyOptions} for the
|
|
866
|
+
* re-stringify step.
|
|
867
|
+
* @returns A `Result` succeeding with the modified text, or failing with
|
|
868
|
+
* {@link YamlModificationError}.
|
|
869
|
+
*/
|
|
870
|
+
static modifyToStringResult(text, path, value, options) {
|
|
871
|
+
return Result.map(YamlFormat.modifyResult(text, path, value, options), (edits) => YamlEdit.applyAll(text, edits));
|
|
872
|
+
}
|
|
800
873
|
/**
|
|
801
874
|
* Modify `text` and apply the resulting edits in one step
|
|
802
875
|
* (`YamlEdit.applyAll ∘ modify`). Inherits the {@link YamlFormat.modify}
|
|
@@ -812,11 +885,12 @@ var YamlFormat = class YamlFormat {
|
|
|
812
885
|
* re-stringify step.
|
|
813
886
|
* @returns An `Effect` that succeeds with the modified text, or fails with
|
|
814
887
|
* {@link YamlModificationError}.
|
|
888
|
+
*
|
|
889
|
+
* @remarks
|
|
890
|
+
* Defined in terms of {@link YamlFormat.modifyToStringResult}; it opens its
|
|
891
|
+
* own span, with no nested `YamlFormat.modify` child span.
|
|
815
892
|
*/
|
|
816
|
-
static modifyToString = Effect.fn("YamlFormat.modifyToString")(
|
|
817
|
-
const edits = yield* YamlFormat.modify(text, path, value, options);
|
|
818
|
-
return YamlEdit.applyAll(text, edits);
|
|
819
|
-
});
|
|
893
|
+
static modifyToString = Effect.fn("YamlFormat.modifyToString")((text, path, value, options) => Effect.fromResult(YamlFormat.modifyToStringResult(text, path, value, options)));
|
|
820
894
|
};
|
|
821
895
|
|
|
822
896
|
export { YamlFormat, YamlFormattingOptions, YamlModificationError };
|
package/index.d.ts
CHANGED
|
@@ -36,11 +36,14 @@ export declare const YamlComposerErrorCode: Schema.Literals<readonly ["Undefined
|
|
|
36
36
|
*/
|
|
37
37
|
export type YamlComposerErrorCode = typeof YamlComposerErrorCode.Type;
|
|
38
38
|
/**
|
|
39
|
-
* Error codes emitted by the stringifier (the
|
|
39
|
+
* Error codes emitted by the stringifier: `CircularReference` (the value or
|
|
40
|
+
* synthetic AST points back at itself) and `UnrepresentableValue` (a function
|
|
41
|
+
* or symbol, which has no YAML rendering and is never written as its
|
|
42
|
+
* `String()` form).
|
|
40
43
|
*
|
|
41
44
|
* @public
|
|
42
45
|
*/
|
|
43
|
-
export declare const YamlStringifyErrorCode: Schema.Literals<readonly ["CircularReference"]>;
|
|
46
|
+
export declare const YamlStringifyErrorCode: Schema.Literals<readonly ["CircularReference", "UnrepresentableValue"]>;
|
|
44
47
|
/**
|
|
45
48
|
* The union of all stringifier-stage error code string literals.
|
|
46
49
|
*
|
|
@@ -53,7 +56,7 @@ export type YamlStringifyErrorCode = typeof YamlStringifyErrorCode.Type;
|
|
|
53
56
|
*
|
|
54
57
|
* @public
|
|
55
58
|
*/
|
|
56
|
-
export declare const YamlModifyErrorCode: Schema.Literals<readonly ["EmptyDocument", "PathNotFound", "InvalidIndex", "NotNavigable", "MultiDocumentStream", "DirectiveCarryingDocument", "CircularReference", "NestingDepthExceeded"]>;
|
|
59
|
+
export declare const YamlModifyErrorCode: Schema.Literals<readonly ["EmptyDocument", "PathNotFound", "InvalidIndex", "NotNavigable", "MultiDocumentStream", "DirectiveCarryingDocument", "CircularReference", "NestingDepthExceeded", "UnrepresentableValue"]>;
|
|
57
60
|
/**
|
|
58
61
|
* The union of all modify-stage error code string literals.
|
|
59
62
|
*
|
|
@@ -66,7 +69,7 @@ export type YamlModifyErrorCode = typeof YamlModifyErrorCode.Type;
|
|
|
66
69
|
*
|
|
67
70
|
* @public
|
|
68
71
|
*/
|
|
69
|
-
export declare const YamlErrorCode: Schema.Union<readonly [Schema.Literals<readonly ["UnexpectedCharacter", "UnterminatedString", "InvalidEscapeSequence", "InvalidUnicode", "UnterminatedBlockScalar", "UnterminatedFlowCollection", "InvalidDirective", "InvalidTagHandle", "InvalidAnchorName", "UnexpectedByteOrderMark"]>, Schema.Literals<readonly ["InvalidIndentation", "DuplicateKey", "UnexpectedToken", "MissingValue", "MissingKey", "TabIndentation", "InvalidBlockStructure", "MalformedFlowCollection", "NestingDepthExceeded"]>, Schema.Literals<readonly ["UndefinedAlias", "DuplicateAnchor", "CircularAlias", "UnresolvedTag", "InvalidTagValue", "AliasCountExceeded", "InvalidDirective"]>, Schema.Literals<readonly ["CircularReference"]>, Schema.Literals<readonly ["EmptyDocument", "PathNotFound", "InvalidIndex", "NotNavigable", "MultiDocumentStream", "DirectiveCarryingDocument", "CircularReference", "NestingDepthExceeded"]>]>;
|
|
72
|
+
export declare const YamlErrorCode: Schema.Union<readonly [Schema.Literals<readonly ["UnexpectedCharacter", "UnterminatedString", "InvalidEscapeSequence", "InvalidUnicode", "UnterminatedBlockScalar", "UnterminatedFlowCollection", "InvalidDirective", "InvalidTagHandle", "InvalidAnchorName", "UnexpectedByteOrderMark"]>, Schema.Literals<readonly ["InvalidIndentation", "DuplicateKey", "UnexpectedToken", "MissingValue", "MissingKey", "TabIndentation", "InvalidBlockStructure", "MalformedFlowCollection", "NestingDepthExceeded"]>, Schema.Literals<readonly ["UndefinedAlias", "DuplicateAnchor", "CircularAlias", "UnresolvedTag", "InvalidTagValue", "AliasCountExceeded", "InvalidDirective"]>, Schema.Literals<readonly ["CircularReference", "UnrepresentableValue"]>, Schema.Literals<readonly ["EmptyDocument", "PathNotFound", "InvalidIndex", "NotNavigable", "MultiDocumentStream", "DirectiveCarryingDocument", "CircularReference", "NestingDepthExceeded", "UnrepresentableValue"]>]>;
|
|
70
73
|
/**
|
|
71
74
|
* The union of all YAML error code string literals.
|
|
72
75
|
*
|
|
@@ -74,7 +77,7 @@ export declare const YamlErrorCode: Schema.Union<readonly [Schema.Literals<reado
|
|
|
74
77
|
*/
|
|
75
78
|
export type YamlErrorCode = typeof YamlErrorCode.Type;
|
|
76
79
|
declare const YamlDiagnostic_base: Schema.Class<YamlDiagnostic, Schema.Struct<{
|
|
77
|
-
readonly code: Schema.Union<readonly [Schema.Literals<readonly ["UnexpectedCharacter", "UnterminatedString", "InvalidEscapeSequence", "InvalidUnicode", "UnterminatedBlockScalar", "UnterminatedFlowCollection", "InvalidDirective", "InvalidTagHandle", "InvalidAnchorName", "UnexpectedByteOrderMark"]>, Schema.Literals<readonly ["InvalidIndentation", "DuplicateKey", "UnexpectedToken", "MissingValue", "MissingKey", "TabIndentation", "InvalidBlockStructure", "MalformedFlowCollection", "NestingDepthExceeded"]>, Schema.Literals<readonly ["UndefinedAlias", "DuplicateAnchor", "CircularAlias", "UnresolvedTag", "InvalidTagValue", "AliasCountExceeded", "InvalidDirective"]>, Schema.Literals<readonly ["CircularReference"]>, Schema.Literals<readonly ["EmptyDocument", "PathNotFound", "InvalidIndex", "NotNavigable", "MultiDocumentStream", "DirectiveCarryingDocument", "CircularReference", "NestingDepthExceeded"]>]>;
|
|
80
|
+
readonly code: Schema.Union<readonly [Schema.Literals<readonly ["UnexpectedCharacter", "UnterminatedString", "InvalidEscapeSequence", "InvalidUnicode", "UnterminatedBlockScalar", "UnterminatedFlowCollection", "InvalidDirective", "InvalidTagHandle", "InvalidAnchorName", "UnexpectedByteOrderMark"]>, Schema.Literals<readonly ["InvalidIndentation", "DuplicateKey", "UnexpectedToken", "MissingValue", "MissingKey", "TabIndentation", "InvalidBlockStructure", "MalformedFlowCollection", "NestingDepthExceeded"]>, Schema.Literals<readonly ["UndefinedAlias", "DuplicateAnchor", "CircularAlias", "UnresolvedTag", "InvalidTagValue", "AliasCountExceeded", "InvalidDirective"]>, Schema.Literals<readonly ["CircularReference", "UnrepresentableValue"]>, Schema.Literals<readonly ["EmptyDocument", "PathNotFound", "InvalidIndex", "NotNavigable", "MultiDocumentStream", "DirectiveCarryingDocument", "CircularReference", "NestingDepthExceeded", "UnrepresentableValue"]>]>;
|
|
78
81
|
readonly message: Schema.String;
|
|
79
82
|
readonly offset: Schema.Number;
|
|
80
83
|
readonly length: Schema.Number;
|
|
@@ -288,11 +291,14 @@ declare const YamlStringifyError_base: Schema.Class<YamlStringifyError, Schema.T
|
|
|
288
291
|
readonly value: Schema.Unknown;
|
|
289
292
|
}>, import("effect/Cause").YieldableError>;
|
|
290
293
|
/**
|
|
291
|
-
* Stringification failure
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
294
|
+
* Stringification failure, carrying structured {@link YamlDiagnostic} entries
|
|
295
|
+
* and the offending value. Raised by {@link Yaml.stringify},
|
|
296
|
+
* `YamlDocument#stringify` and the encode direction of the schema factories
|
|
297
|
+
* on a circular reference (`CircularReference`), a value nested past the
|
|
298
|
+
* stringifier's recursion budget (`NestingDepthExceeded`) or a value with no
|
|
299
|
+
* YAML representation (`UnrepresentableValue` — a function or a symbol). The
|
|
300
|
+
* error itself has no `code` field: read the code from the diagnostics —
|
|
301
|
+
* `error.diagnostics[0].code` is the primary failure.
|
|
296
302
|
*
|
|
297
303
|
* @public
|
|
298
304
|
*/
|
|
@@ -384,10 +390,14 @@ export declare class Yaml {
|
|
|
384
390
|
static readonly parseAll: (text: string, options?: YamlParseOptions | undefined) => Effect.Effect<readonly unknown[], YamlParseError, never>;
|
|
385
391
|
/**
|
|
386
392
|
* Stringify a plain JavaScript value as YAML. Fails with
|
|
387
|
-
* {@link YamlStringifyError} on circular references (`CircularReference`)
|
|
388
|
-
*
|
|
389
|
-
* (`NestingDepthExceeded`)
|
|
390
|
-
*
|
|
393
|
+
* {@link YamlStringifyError} on circular references (`CircularReference`),
|
|
394
|
+
* on a value nested deeper than the stringifier's recursion budget
|
|
395
|
+
* (`NestingDepthExceeded`) and on a function or symbol anywhere in the
|
|
396
|
+
* value (`UnrepresentableValue`) — all surface through the typed error
|
|
397
|
+
* channel, never as a stack-overflow defect and never as the function's
|
|
398
|
+
* source text or `Symbol(s)` written into the document as a string. A
|
|
399
|
+
* `bigint` is an integer and renders bare, exactly as `YamlFormat.modify`
|
|
400
|
+
* writes one; `null` and `undefined` both render as `null`.
|
|
391
401
|
*
|
|
392
402
|
* @remarks
|
|
393
403
|
* A `"<<"` object key is emitted **quoted** (`'<<': …`). This is the
|
|
@@ -483,10 +493,11 @@ export declare class Yaml {
|
|
|
483
493
|
* The pure counterpart to {@link Yaml.stringify} for config-time callers
|
|
484
494
|
* that cannot `await`.
|
|
485
495
|
*
|
|
486
|
-
* Preserves the package contract — a circular reference (`CircularReference`)
|
|
487
|
-
*
|
|
488
|
-
*
|
|
489
|
-
* thrown
|
|
496
|
+
* Preserves the package contract — a circular reference (`CircularReference`),
|
|
497
|
+
* a value nested past the recursion budget (`NestingDepthExceeded`) or a
|
|
498
|
+
* function or symbol value (`UnrepresentableValue`) yields a `Failure`
|
|
499
|
+
* carrying a {@link YamlStringifyError} rather than a thrown defect; the
|
|
500
|
+
* method never throws.
|
|
490
501
|
*
|
|
491
502
|
* @example
|
|
492
503
|
* ```ts
|
|
@@ -1036,11 +1047,39 @@ declare const YamlDocument_base: Schema.Class<YamlDocument, Schema.Struct<{
|
|
|
1036
1047
|
* @public
|
|
1037
1048
|
*/
|
|
1038
1049
|
export declare class YamlDocument extends YamlDocument_base {
|
|
1050
|
+
/**
|
|
1051
|
+
* Synchronous single-document parse, returning a `Result` instead of an
|
|
1052
|
+
* `Effect`. This is the primitive {@link YamlDocument.parse} is defined in
|
|
1053
|
+
* terms of — a synchronous host can call it without an Effect runtime.
|
|
1054
|
+
* Keeps the full AST, directives and recovered diagnostics; fails with the
|
|
1055
|
+
* aggregate {@link YamlParseError} when any fatal-code diagnostic is
|
|
1056
|
+
* present, and non-fatal diagnostics are data on the returned document.
|
|
1057
|
+
*
|
|
1058
|
+
* @example
|
|
1059
|
+
* ```ts
|
|
1060
|
+
* import { YamlDocument } from "@effected/yaml";
|
|
1061
|
+
* import { Result } from "effect";
|
|
1062
|
+
*
|
|
1063
|
+
* const result = YamlDocument.parseResult("name: Alice\n");
|
|
1064
|
+
* if (Result.isSuccess(result)) {
|
|
1065
|
+
* console.log(result.success.toValue()); // => { name: "Alice" }
|
|
1066
|
+
* }
|
|
1067
|
+
* ```
|
|
1068
|
+
*
|
|
1069
|
+
* @param text - The YAML source to parse.
|
|
1070
|
+
* @param options - Optional {@link YamlParseOptions}; defaults apply for
|
|
1071
|
+
* omitted fields.
|
|
1072
|
+
* @returns A `Result` succeeding with the {@link YamlDocument}, or failing
|
|
1073
|
+
* with {@link YamlParseError}.
|
|
1074
|
+
*/
|
|
1075
|
+
static parseResult(text: string, options?: YamlParseOptions): Result.Result<YamlDocument, YamlParseError>;
|
|
1039
1076
|
/**
|
|
1040
1077
|
* Parse a single YAML document, keeping the full AST, directives and
|
|
1041
1078
|
* recovered diagnostics. Fails with the aggregate {@link YamlParseError}
|
|
1042
1079
|
* when any fatal-code diagnostic is present; non-fatal diagnostics are
|
|
1043
|
-
* data on the returned document.
|
|
1080
|
+
* data on the returned document. Defined in terms of
|
|
1081
|
+
* {@link YamlDocument.parseResult} — synchronous callers can use that
|
|
1082
|
+
* variant directly.
|
|
1044
1083
|
*
|
|
1045
1084
|
* @param text - The YAML source to parse.
|
|
1046
1085
|
* @param options - Optional {@link YamlParseOptions}; defaults apply for
|
|
@@ -1049,10 +1088,37 @@ export declare class YamlDocument extends YamlDocument_base {
|
|
|
1049
1088
|
* with {@link YamlParseError}.
|
|
1050
1089
|
*/
|
|
1051
1090
|
static readonly parse: (text: string, options?: YamlParseOptions | undefined) => Effect.Effect<YamlDocument, YamlParseError, never>;
|
|
1091
|
+
/**
|
|
1092
|
+
* Synchronous multi-document parse, returning a `Result` instead of an
|
|
1093
|
+
* `Effect` — the primitive {@link YamlDocument.parseAll} is defined in
|
|
1094
|
+
* terms of. Any fatal diagnostic in any document — or a stream-level
|
|
1095
|
+
* directive-placement error — fails the whole parse with one aggregate
|
|
1096
|
+
* {@link YamlParseError}.
|
|
1097
|
+
*
|
|
1098
|
+
* @example
|
|
1099
|
+
* ```ts
|
|
1100
|
+
* import { YamlDocument } from "@effected/yaml";
|
|
1101
|
+
* import { Result } from "effect";
|
|
1102
|
+
*
|
|
1103
|
+
* const result = YamlDocument.parseAllResult("a: 1\n---\nb: 2\n");
|
|
1104
|
+
* if (Result.isSuccess(result)) {
|
|
1105
|
+
* console.log(result.success.length); // => 2
|
|
1106
|
+
* }
|
|
1107
|
+
* ```
|
|
1108
|
+
*
|
|
1109
|
+
* @param text - The YAML stream to parse.
|
|
1110
|
+
* @param options - Optional {@link YamlParseOptions}; defaults apply for
|
|
1111
|
+
* omitted fields.
|
|
1112
|
+
* @returns A `Result` succeeding with one {@link YamlDocument} per
|
|
1113
|
+
* document, or failing with {@link YamlParseError}.
|
|
1114
|
+
*/
|
|
1115
|
+
static parseAllResult(text: string, options?: YamlParseOptions): Result.Result<ReadonlyArray<YamlDocument>, YamlParseError>;
|
|
1052
1116
|
/**
|
|
1053
1117
|
* Parse a multi-document YAML stream into one {@link YamlDocument} per
|
|
1054
1118
|
* document. Any fatal diagnostic in any document — or a stream-level
|
|
1055
|
-
* directive-placement error — fails the whole Effect.
|
|
1119
|
+
* directive-placement error — fails the whole Effect. Defined in terms of
|
|
1120
|
+
* {@link YamlDocument.parseAllResult} — synchronous callers can use that
|
|
1121
|
+
* variant directly.
|
|
1056
1122
|
*
|
|
1057
1123
|
* @param text - The YAML stream to parse.
|
|
1058
1124
|
* @param options - Optional {@link YamlParseOptions}; defaults apply for
|
|
@@ -1076,11 +1142,19 @@ export declare class YamlDocument extends YamlDocument_base {
|
|
|
1076
1142
|
static schema(options?: YamlParseOptions): Schema.Codec<YamlDocument, string>;
|
|
1077
1143
|
/**
|
|
1078
1144
|
* Stringify this document (contents, directives and framing) as YAML.
|
|
1079
|
-
*
|
|
1080
|
-
*
|
|
1081
|
-
*
|
|
1082
|
-
*
|
|
1083
|
-
*
|
|
1145
|
+
* A parsed document always stringifies; the failures belong to hand-built
|
|
1146
|
+
* ASTs and surface as {@link YamlStringifyError} through the typed error
|
|
1147
|
+
* channel, never as an unhandled stack-overflow defect or as corrupted
|
|
1148
|
+
* output: a cycle in the AST fails `CircularReference` on the first
|
|
1149
|
+
* re-entry of an ancestor collection (the node path keeps the same
|
|
1150
|
+
* ancestor set the value path does), a tree nested deeper than the
|
|
1151
|
+
* stringifier's recursion budget fails `NestingDepthExceeded`, and a
|
|
1152
|
+
* scalar node holding anything but `null`, a boolean, a number, a bigint
|
|
1153
|
+
* or a string — a function, a symbol, an object — fails
|
|
1154
|
+
* `UnrepresentableValue` rather than being written as its `String()` form.
|
|
1155
|
+
* Defined in terms of {@link YamlDocument.stringifyResult} behind a
|
|
1156
|
+
* `YamlDocument.stringify` span — synchronous callers can use that variant
|
|
1157
|
+
* directly.
|
|
1084
1158
|
*
|
|
1085
1159
|
* @remarks
|
|
1086
1160
|
* `YamlStringifyOptions.lineWidth` is not honored here: column-based
|
|
@@ -1099,6 +1173,38 @@ export declare class YamlDocument extends YamlDocument_base {
|
|
|
1099
1173
|
* {@link YamlStringifyError}.
|
|
1100
1174
|
*/
|
|
1101
1175
|
stringify(options?: YamlStringifyOptions): Effect.Effect<string, YamlStringifyError>;
|
|
1176
|
+
/**
|
|
1177
|
+
* Synchronous stringify, returning a `Result` instead of an `Effect` — the
|
|
1178
|
+
* primitive {@link YamlDocument.stringify} is defined in terms of, so a
|
|
1179
|
+
* synchronous host can round-trip a document parsed with
|
|
1180
|
+
* {@link YamlDocument.parseResult} without an Effect runtime. Fails with
|
|
1181
|
+
* {@link YamlStringifyError} exactly where `stringify` does: a hand-built
|
|
1182
|
+
* AST containing a cycle (`CircularReference`), one nested deeper than the
|
|
1183
|
+
* stringifier's recursion budget (`NestingDepthExceeded`) or one whose
|
|
1184
|
+
* scalar node holds a value with no YAML form (`UnrepresentableValue`).
|
|
1185
|
+
*
|
|
1186
|
+
* @remarks
|
|
1187
|
+
* `YamlStringifyOptions.lineWidth` is not honored here, for the reason
|
|
1188
|
+
* given on {@link YamlDocument.stringify}.
|
|
1189
|
+
*
|
|
1190
|
+
* @example
|
|
1191
|
+
* ```ts
|
|
1192
|
+
* import { YamlDocument } from "@effected/yaml";
|
|
1193
|
+
* import { Result } from "effect";
|
|
1194
|
+
*
|
|
1195
|
+
* const parsed = YamlDocument.parseResult("# keep\nname: Alice\n");
|
|
1196
|
+
* if (Result.isSuccess(parsed)) {
|
|
1197
|
+
* const text = parsed.success.stringifyResult();
|
|
1198
|
+
* if (Result.isSuccess(text)) console.log(text.success); // => "# keep\nname: Alice\n"
|
|
1199
|
+
* }
|
|
1200
|
+
* ```
|
|
1201
|
+
*
|
|
1202
|
+
* @param options - Optional {@link YamlStringifyOptions}; defaults apply for
|
|
1203
|
+
* omitted fields.
|
|
1204
|
+
* @returns A `Result` succeeding with the YAML text, or failing with
|
|
1205
|
+
* {@link YamlStringifyError}.
|
|
1206
|
+
*/
|
|
1207
|
+
stringifyResult(options?: YamlStringifyOptions): Result.Result<string, YamlStringifyError>;
|
|
1102
1208
|
/**
|
|
1103
1209
|
* Reconstruct the plain JavaScript value of this document's contents,
|
|
1104
1210
|
* resolving anchors and aliases. `null` for an empty document. Pure and
|
|
@@ -1315,7 +1421,9 @@ export declare class YamlFormat {
|
|
|
1315
1421
|
*/
|
|
1316
1422
|
static formatToString(text: string, range?: YamlRangeLike, options?: YamlFormattingOptions): string;
|
|
1317
1423
|
/**
|
|
1318
|
-
* Compute the edits that insert, replace, or remove a value at `path
|
|
1424
|
+
* Compute the edits that insert, replace, or remove a value at `path`,
|
|
1425
|
+
* synchronously — the primitive {@link YamlFormat.modify} is defined in
|
|
1426
|
+
* terms of, so a synchronous host can call it without an Effect runtime.
|
|
1319
1427
|
* Passing `value === undefined` removes the target key/element; a missing
|
|
1320
1428
|
* insertion target appends after the last pair/element. Fails with
|
|
1321
1429
|
* {@link YamlModificationError} on a fatal parse error or a structural
|
|
@@ -1325,7 +1433,10 @@ export declare class YamlFormat {
|
|
|
1325
1433
|
* sequence and any other non-null object as a block mapping over its own
|
|
1326
1434
|
* enumerable string keys, recursively — the same lowering
|
|
1327
1435
|
* {@link Yaml.stringify} applies to the same value, so `modify` and
|
|
1328
|
-
* `stringify` agree on what a given JavaScript value means
|
|
1436
|
+
* `stringify` agree on what a given JavaScript value means: a `bigint`
|
|
1437
|
+
* renders bare (`a: 10`, never `a: "10"`), `null` renders as `null`, and a
|
|
1438
|
+
* function or symbol fails `UnrepresentableValue` on both paths rather
|
|
1439
|
+
* than landing in the document as its `String()` form. For a synthesized
|
|
1329
1440
|
* subtree (an object/array value) only the surrounding document is
|
|
1330
1441
|
* preserved byte-for-byte; the subtree carries no comments and takes the
|
|
1331
1442
|
* stringifier's styles.
|
|
@@ -1349,10 +1460,13 @@ export declare class YamlFormat {
|
|
|
1349
1460
|
* whole document, which normalises line endings to LF, applies those
|
|
1350
1461
|
* options, and renders the replacement in the stringifier's styles.
|
|
1351
1462
|
*
|
|
1352
|
-
*
|
|
1353
|
-
*
|
|
1354
|
-
* reference (`CircularReference`)
|
|
1355
|
-
*
|
|
1463
|
+
* Three replacement values have no rendering and fail typed rather than
|
|
1464
|
+
* hanging, overflowing the stack or corrupting the document: one
|
|
1465
|
+
* containing a circular reference (`CircularReference`), one that would
|
|
1466
|
+
* sit deeper than 256 levels in the output document
|
|
1467
|
+
* (`NestingDepthExceeded`) and one containing a function or symbol
|
|
1468
|
+
* (`UnrepresentableValue`). The depth is counted from the document root,
|
|
1469
|
+
* so the same value can fit at `[]` and fail a few keys down.
|
|
1356
1470
|
*
|
|
1357
1471
|
* **Single-document contract.** A `path` carries no document index, so on
|
|
1358
1472
|
* a multi-document stream there is no rule for which document it names —
|
|
@@ -1377,15 +1491,60 @@ export declare class YamlFormat {
|
|
|
1377
1491
|
* target instead.
|
|
1378
1492
|
* @param options - Optional {@link YamlStringifyOptions} for the
|
|
1379
1493
|
* re-stringify step.
|
|
1380
|
-
* @returns
|
|
1381
|
-
* `YamlEdit.applyAll`), or
|
|
1494
|
+
* @returns A `Result` succeeding with the edits to apply (via
|
|
1495
|
+
* `YamlEdit.applyAll`), or failing with {@link YamlModificationError}.
|
|
1382
1496
|
*
|
|
1383
1497
|
* @remarks
|
|
1384
1498
|
* `options` is a bare {@link YamlStringifyOptions} — it controls only the
|
|
1385
1499
|
* internal re-stringify step, not a range (there is no range to restrict
|
|
1386
1500
|
* for a path-targeted modification).
|
|
1387
1501
|
*/
|
|
1502
|
+
static modifyResult(text: string, path: YamlPath, value: unknown, options?: YamlStringifyOptions): Result.Result<ReadonlyArray<YamlEdit>, YamlModificationError>;
|
|
1503
|
+
/**
|
|
1504
|
+
* Compute the edits that insert, replace, or remove a value at `path`.
|
|
1505
|
+
* Defined in terms of {@link YamlFormat.modifyResult}, which carries the
|
|
1506
|
+
* full contract — value lowering, region-confined scalar replacement, the
|
|
1507
|
+
* single-document contract and the directive refusal — behind a
|
|
1508
|
+
* `YamlFormat.modify` span; synchronous callers can use that variant
|
|
1509
|
+
* directly.
|
|
1510
|
+
*
|
|
1511
|
+
* @param text - The YAML source to modify.
|
|
1512
|
+
* @param path - The location to insert, replace or remove.
|
|
1513
|
+
* @param value - The JavaScript value to write; `undefined` removes the
|
|
1514
|
+
* target instead.
|
|
1515
|
+
* @param options - Optional {@link YamlStringifyOptions} for the
|
|
1516
|
+
* re-stringify step.
|
|
1517
|
+
* @returns An `Effect` that succeeds with the edits to apply (via
|
|
1518
|
+
* `YamlEdit.applyAll`), or fails with {@link YamlModificationError}.
|
|
1519
|
+
*/
|
|
1388
1520
|
static readonly modify: (text: string, path: YamlPath, value: unknown, options?: YamlStringifyOptions | undefined) => Effect.Effect<readonly YamlEdit[], YamlModificationError, never>;
|
|
1521
|
+
/**
|
|
1522
|
+
* Synchronous {@link YamlFormat.modifyToString}: modify `text` and apply the
|
|
1523
|
+
* resulting edits in one step (`YamlEdit.applyAll ∘ modifyResult`),
|
|
1524
|
+
* returning a `Result`. Inherits the {@link YamlFormat.modifyResult} error
|
|
1525
|
+
* channel.
|
|
1526
|
+
*
|
|
1527
|
+
* @example
|
|
1528
|
+
* ```ts
|
|
1529
|
+
* import { YamlFormat } from "@effected/yaml";
|
|
1530
|
+
* import { Result } from "effect";
|
|
1531
|
+
*
|
|
1532
|
+
* const result = YamlFormat.modifyToStringResult("port: 3000 # dev\n", ["port"], 8080);
|
|
1533
|
+
* if (Result.isSuccess(result)) {
|
|
1534
|
+
* console.log(result.success); // => "port: 8080 # dev\n"
|
|
1535
|
+
* }
|
|
1536
|
+
* ```
|
|
1537
|
+
*
|
|
1538
|
+
* @param text - The YAML source to modify.
|
|
1539
|
+
* @param path - The location to insert, replace or remove.
|
|
1540
|
+
* @param value - The JavaScript value to write; `undefined` removes the
|
|
1541
|
+
* target instead.
|
|
1542
|
+
* @param options - Optional {@link YamlStringifyOptions} for the
|
|
1543
|
+
* re-stringify step.
|
|
1544
|
+
* @returns A `Result` succeeding with the modified text, or failing with
|
|
1545
|
+
* {@link YamlModificationError}.
|
|
1546
|
+
*/
|
|
1547
|
+
static modifyToStringResult(text: string, path: YamlPath, value: unknown, options?: YamlStringifyOptions): Result.Result<string, YamlModificationError>;
|
|
1389
1548
|
/**
|
|
1390
1549
|
* Modify `text` and apply the resulting edits in one step
|
|
1391
1550
|
* (`YamlEdit.applyAll ∘ modify`). Inherits the {@link YamlFormat.modify}
|
|
@@ -1401,6 +1560,10 @@ export declare class YamlFormat {
|
|
|
1401
1560
|
* re-stringify step.
|
|
1402
1561
|
* @returns An `Effect` that succeeds with the modified text, or fails with
|
|
1403
1562
|
* {@link YamlModificationError}.
|
|
1563
|
+
*
|
|
1564
|
+
* @remarks
|
|
1565
|
+
* Defined in terms of {@link YamlFormat.modifyToStringResult}; it opens its
|
|
1566
|
+
* own span, with no nested `YamlFormat.modify` child span.
|
|
1404
1567
|
*/
|
|
1405
1568
|
static readonly modifyToString: (text: string, path: YamlPath, value: unknown, options?: YamlStringifyOptions | undefined) => Effect.Effect<string, YamlModificationError, never>;
|
|
1406
1569
|
}
|
|
@@ -927,6 +927,7 @@ function shouldPreserveRaw(rawValue, value) {
|
|
|
927
927
|
if (Number.isNaN(value) || !Number.isFinite(value)) return false;
|
|
928
928
|
return rawValue !== String(value);
|
|
929
929
|
}
|
|
930
|
+
if (typeof value === "bigint") return rawValue !== value.toString();
|
|
930
931
|
return false;
|
|
931
932
|
}
|
|
932
933
|
|
package/internal/diagnostics.js
CHANGED
|
@@ -35,13 +35,18 @@ const YAML_COMPOSE_ERROR_CODES = [
|
|
|
35
35
|
"InvalidDirective"
|
|
36
36
|
];
|
|
37
37
|
/**
|
|
38
|
-
* Error codes for the stringifier stage. The engine's
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* `
|
|
42
|
-
* `
|
|
38
|
+
* Error codes for the stringifier stage. The engine's deliberate stringify
|
|
39
|
+
* failures are the circular-reference guard and the unrepresentable-value
|
|
40
|
+
* guard (a function or symbol on the value path, or a synthetic scalar node
|
|
41
|
+
* holding anything but `null`, a boolean, a number, a bigint or a string),
|
|
42
|
+
* both thrown as `StringifyFailure` carrying one of these codes; the facade
|
|
43
|
+
* materializes them so `YamlStringifyError` carries structured diagnostics
|
|
44
|
+
* rather than a `reason` string. `UnrepresentableValue` exists because the
|
|
45
|
+
* alternative — writing `String(value)` into the document — turned a function's
|
|
46
|
+
* source text or `Symbol(s)` into a quoted string that only surfaced on the
|
|
47
|
+
* next read.
|
|
43
48
|
*/
|
|
44
|
-
const YAML_STRINGIFY_ERROR_CODES = ["CircularReference"];
|
|
49
|
+
const YAML_STRINGIFY_ERROR_CODES = ["CircularReference", "UnrepresentableValue"];
|
|
45
50
|
/**
|
|
46
51
|
* Error codes for the modify stage (`YamlFormat.modify`'s guards and path
|
|
47
52
|
* navigation against an already-composed AST). Not raised by the
|
|
@@ -53,10 +58,11 @@ const YAML_STRINGIFY_ERROR_CODES = ["CircularReference"];
|
|
|
53
58
|
* without its `%TAG` orphans every shorthand tag that depends on it — the
|
|
54
59
|
* output would be unparseable — so modify fails typed rather than corrupting.
|
|
55
60
|
*
|
|
56
|
-
* `CircularReference` and `
|
|
57
|
-
* replacement value itself: `modify` lowers a plain
|
|
58
|
-
* AST nodes, and an object graph that points back at
|
|
59
|
-
* than `MAX_NESTING_DEPTH` has no finite YAML
|
|
61
|
+
* `CircularReference`, `NestingDepthExceeded` and `UnrepresentableValue` are
|
|
62
|
+
* the three limits on the replacement value itself: `modify` lowers a plain
|
|
63
|
+
* JavaScript value into AST nodes, and an object graph that points back at
|
|
64
|
+
* itself or nests deeper than `MAX_NESTING_DEPTH` has no finite YAML
|
|
65
|
+
* rendering, while a function or symbol has none at all. All three names are
|
|
60
66
|
* deliberately the ones the stringify and compose stages already use for the
|
|
61
67
|
* same conditions, so `YamlErrorCode` gains no member.
|
|
62
68
|
*/
|
|
@@ -68,7 +74,8 @@ const YAML_MODIFY_ERROR_CODES = [
|
|
|
68
74
|
"MultiDocumentStream",
|
|
69
75
|
"DirectiveCarryingDocument",
|
|
70
76
|
"CircularReference",
|
|
71
|
-
"NestingDepthExceeded"
|
|
77
|
+
"NestingDepthExceeded",
|
|
78
|
+
"UnrepresentableValue"
|
|
72
79
|
];
|
|
73
80
|
/**
|
|
74
81
|
* The single source of truth for which diagnostic codes are fatal to a
|
package/internal/stringifier.js
CHANGED
|
@@ -3,18 +3,32 @@ import { foldRenderedScalar, hasInteriorTrailingWhitespace, hasNewlineSpacesTab,
|
|
|
3
3
|
|
|
4
4
|
// src/internal/stringifier.ts
|
|
5
5
|
/**
|
|
6
|
-
* Thrown by the stringifier on its failure paths
|
|
7
|
-
*
|
|
6
|
+
* Thrown by the stringifier on its two deliberate failure paths: a circular
|
|
7
|
+
* reference (`CircularReference`) and a value with no YAML representation
|
|
8
|
+
* (`UnrepresentableValue` — a function or symbol on the value path, or a
|
|
9
|
+
* synthetic scalar node holding anything but `null`, a boolean, a number, a
|
|
10
|
+
* bigint or a string). The facade catches this and materializes the public
|
|
11
|
+
* stringify error under `code`.
|
|
8
12
|
*/
|
|
9
13
|
var StringifyFailure = class extends Error {
|
|
14
|
+
code;
|
|
10
15
|
reason;
|
|
11
|
-
constructor(reason) {
|
|
16
|
+
constructor(code, reason) {
|
|
12
17
|
super(reason);
|
|
13
18
|
this.name = "StringifyFailure";
|
|
19
|
+
this.code = code;
|
|
14
20
|
this.reason = reason;
|
|
15
21
|
}
|
|
16
22
|
};
|
|
17
23
|
/**
|
|
24
|
+
* Build the unrepresentable-value failure for a value of `kind` (its
|
|
25
|
+
* `typeof`). Shared by the value path and the node path so the two report
|
|
26
|
+
* the same condition in the same words.
|
|
27
|
+
*/
|
|
28
|
+
function unrepresentable(kind) {
|
|
29
|
+
return new StringifyFailure("UnrepresentableValue", `A ${kind} value has no YAML representation`);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
18
32
|
* Thrown by the value-stringifier trio when its mutual recursion exceeds
|
|
19
33
|
* {@link MAX_NESTING_DEPTH}. A deeply-nested acyclic value (e.g. a 50 000-deep
|
|
20
34
|
* array) would otherwise overflow the call stack as an unhandled `RangeError`
|
|
@@ -305,7 +319,7 @@ function renderNumber(n) {
|
|
|
305
319
|
*/
|
|
306
320
|
function detectCircular(value, seen) {
|
|
307
321
|
if (value !== null && typeof value === "object") {
|
|
308
|
-
if (seen.has(value)) throw new StringifyFailure("Circular reference detected");
|
|
322
|
+
if (seen.has(value)) throw new StringifyFailure("CircularReference", "Circular reference detected");
|
|
309
323
|
}
|
|
310
324
|
}
|
|
311
325
|
/** Resolves optional stringify options into a fully-defaulted context. */
|
|
@@ -360,7 +374,7 @@ function stringifyLines(value, ctx, depth, allowFold = true) {
|
|
|
360
374
|
ctx.seen.delete(value);
|
|
361
375
|
}
|
|
362
376
|
}
|
|
363
|
-
|
|
377
|
+
throw unrepresentable(typeof value);
|
|
364
378
|
}
|
|
365
379
|
/**
|
|
366
380
|
* Stringifies a JavaScript array into YAML sequence lines (no leading indent).
|
|
@@ -603,8 +617,15 @@ function stripNodeComments(node) {
|
|
|
603
617
|
function stringifyNodeLines(node, ctx, depth) {
|
|
604
618
|
if (depth > 256) throw new StringifyDepthExceeded();
|
|
605
619
|
if (node instanceof YamlScalar) return stringifyScalarNodeLines(node, ctx);
|
|
606
|
-
if (node instanceof YamlMap
|
|
607
|
-
|
|
620
|
+
if (node instanceof YamlMap || node instanceof YamlSeq) {
|
|
621
|
+
if (ctx.seen.has(node)) throw new StringifyFailure("CircularReference", "Circular reference detected in the document AST");
|
|
622
|
+
ctx.seen.add(node);
|
|
623
|
+
try {
|
|
624
|
+
return node instanceof YamlMap ? stringifyMapNodeLines(node, ctx, depth) : stringifySeqNodeLines(node, ctx, depth);
|
|
625
|
+
} finally {
|
|
626
|
+
ctx.seen.delete(node);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
608
629
|
if (node instanceof YamlAlias) return [`*${node.name}`];
|
|
609
630
|
return ["null"];
|
|
610
631
|
}
|
|
@@ -623,12 +644,13 @@ function stringifyScalarNodeLines(node, ctx) {
|
|
|
623
644
|
}
|
|
624
645
|
let lines;
|
|
625
646
|
if (val === null || val === void 0) {
|
|
626
|
-
if (isEmpty) lines = [""];
|
|
647
|
+
if (isEmpty && node.raw === void 0) lines = [""];
|
|
627
648
|
else lines = ["null"];
|
|
628
649
|
} else if (typeof val === "boolean") lines = [val ? "true" : "false"];
|
|
629
650
|
else if (typeof val === "number") lines = [node.raw !== void 0 ? node.raw : renderNumber(val)];
|
|
630
651
|
else if (typeof val === "string") lines = renderString(val, style, " ".repeat(ctx.indent), !!node.tag, ctx.forceDefaultStyles, node.chomp, ctx.parentPosition, ctx.quoteStyle, node.blockIndent, ctx.quoteCompat, ctx.inFlow).split("\n");
|
|
631
|
-
else lines = [
|
|
652
|
+
else if (typeof val === "bigint") lines = [node.raw !== void 0 ? node.raw : val.toString()];
|
|
653
|
+
else throw unrepresentable(typeof val);
|
|
632
654
|
if (node.tag) lines[0] = `${node.tag} ${lines[0]}`;
|
|
633
655
|
if (node.anchor) lines[0] = `&${node.anchor} ${lines[0]}`;
|
|
634
656
|
return lines;
|