@effected/yaml 0.24.0 → 0.25.1

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 CHANGED
@@ -171,11 +171,14 @@ var YamlParseError = class extends Schema.TaggedError()("YamlParseError", {
171
171
  }
172
172
  };
173
173
  /**
174
- * Stringification failure (the circular-reference guard), carrying structured
175
- * {@link YamlDiagnostic} entries and the offending value. Raised by
176
- * {@link Yaml.stringify}, `YamlDocument#stringify` and the encode direction of
177
- * the schema factories. The error itself has no `code` field: read the code
178
- * from the diagnostics — `error.diagnostics[0].code` is the primary failure.
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
  */
@@ -227,14 +230,14 @@ const aliasCountExceededError = (message, text) => new YamlParseError({
227
230
  * Shared by every stringify path — `Yaml.stringify`/`stringifyResult`, the
228
231
  * schema encoders, `YamlDocument#stringifyResult` and `YamlFormat.modify`'s
229
232
  * backstop — so all of them surface the hardening guards (circular
230
- * reference, nesting-depth cap) identically.
233
+ * reference, unrepresentable value, nesting-depth cap) identically.
231
234
  *
232
235
  * @internal
233
236
  */
234
237
  const stringifyDefectToError = (defect, value) => {
235
238
  if (defect instanceof StringifyFailure) return new YamlStringifyError({
236
239
  diagnostics: [YamlDiagnostic.make({
237
- code: "CircularReference",
240
+ code: defect.code,
238
241
  message: defect.reason,
239
242
  offset: 0,
240
243
  length: 0,
@@ -309,9 +312,9 @@ const parseAllResultImpl = (text, options) => {
309
312
  };
310
313
  /**
311
314
  * Synchronous stringify returning a `Result`. Mirrors {@link Yaml.stringify}
312
- * without the Effect wrapper: a circular reference or a value nested past the
313
- * recursion budget yields a `Failure` carrying a typed {@link YamlStringifyError},
314
- * 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.
315
318
  */
316
319
  const stringifyResultImpl = (value, options) => Result.try({
317
320
  try: () => stringifyValue(value, toStringifyInput(options)),
@@ -401,10 +404,14 @@ var Yaml = class Yaml {
401
404
  static parseAll = Effect.fn("Yaml.parseAll")((text, options) => Effect.fromResult(Yaml.parseAllResult(text, options)));
402
405
  /**
403
406
  * Stringify a plain JavaScript value as YAML. Fails with
404
- * {@link YamlStringifyError} on circular references (`CircularReference`)
405
- * or on a value nested deeper than the stringifier's recursion budget
406
- * (`NestingDepthExceeded`) — both surface through the typed error channel
407
- * rather than as an unhandled stack-overflow defect.
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`.
408
415
  *
409
416
  * @remarks
410
417
  * A `"<<"` object key is emitted **quoted** (`'<<': …`). This is the
@@ -504,10 +511,11 @@ var Yaml = class Yaml {
504
511
  * The pure counterpart to {@link Yaml.stringify} for config-time callers
505
512
  * that cannot `await`.
506
513
  *
507
- * Preserves the package contract — a circular reference (`CircularReference`)
508
- * or a value nested past the recursion budget (`NestingDepthExceeded`)
509
- * yields a `Failure` carrying a {@link YamlStringifyError} rather than a
510
- * thrown stack-overflow defect; the method never throws.
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.
511
519
  *
512
520
  * @example
513
521
  * ```ts
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 circular-reference guard).
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
@@ -174,13 +174,16 @@ var YamlDocument = class YamlDocument extends Schema.Class("YamlDocument")({
174
174
  }
175
175
  /**
176
176
  * Stringify this document (contents, directives and framing) as YAML.
177
- * Fails with {@link YamlStringifyError} (`NestingDepthExceeded`) on a
178
- * synthetic AST nested deeper than the stringifier's recursion budget. A
179
- * cycle introduced into a synthetic AST fails the same way: the node path
180
- * keeps no ancestor set, so the cycle is caught by the depth cap rather
181
- * than reported as `CircularReference`. Either way the failure surfaces
182
- * through the typed error channel, never as an unhandled stack-overflow
183
- * defect.
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.
184
187
  * Defined in terms of {@link YamlDocument.stringifyResult} behind a
185
188
  * `YamlDocument.stringify` span — synchronous callers can use that variant
186
189
  * directly.
@@ -209,11 +212,10 @@ var YamlDocument = class YamlDocument extends Schema.Class("YamlDocument")({
209
212
  * primitive {@link YamlDocument.stringify} is defined in terms of, so a
210
213
  * synchronous host can round-trip a document parsed with
211
214
  * {@link YamlDocument.parseResult} without an Effect runtime. Fails with
212
- * {@link YamlStringifyError} exactly where `stringify` does: a synthetic
213
- * AST nested deeper than the stringifier's recursion budget, or one
214
- * containing a cycle, both as `NestingDepthExceeded` (the node path keeps
215
- * no ancestor set, so a cycle is caught by the depth cap, not reported as
216
- * `CircularReference`).
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`).
217
219
  *
218
220
  * @remarks
219
221
  * `YamlStringifyOptions.lineWidth` is not honored here, for the reason
package/YamlFormat.js CHANGED
@@ -137,17 +137,8 @@ function requoteNode(node, text, quote) {
137
137
  if (node instanceof YamlScalar) {
138
138
  if (requoteScalarText(text, node, quote, "escaping") === void 0) return node;
139
139
  return YamlScalar.make({
140
- value: node.value,
141
- style: quote === "\"" ? "double-quoted" : "single-quoted",
142
- ...definedFields({
143
- commentBefore: node.commentBefore,
144
- comment: node.comment,
145
- spaceBefore: node.spaceBefore,
146
- raw: node.raw,
147
- sourceMultiline: node.sourceMultiline
148
- }),
149
- offset: node.offset,
150
- length: node.length
140
+ ...node,
141
+ style: quote === "\"" ? "double-quoted" : "single-quoted"
151
142
  });
152
143
  }
153
144
  if (node instanceof YamlMap) return rebuildMap(node, node.items.map((pair) => YamlPair.make({
@@ -259,12 +250,16 @@ function formatStream(text, documents, streamErrors, options) {
259
250
  * Before this was recursive, a mapping or sequence value fell through to the
260
251
  * node stringifier's `String(value)` fallback and landed in the document as
261
252
  * the literal text `[object Object]` — a silent corruption that only surfaced
262
- * on the next read.
253
+ * on the next read. Every other value becomes a plain {@link YamlScalar} and
254
+ * renders exactly as the value path renders it: a `bigint` bare, `undefined`
255
+ * as `null`.
263
256
  *
264
- * The two conditions with no finite rendering fail typed rather than hanging
265
- * or overflowing the stack: a cycle raises `CircularReference` and a graph
266
- * that would sit deeper than `MAX_NESTING_DEPTH` in the output document
267
- * raises `NestingDepthExceeded`. `depth` is measured in the stringifier's own
257
+ * Three conditions fail typed rather than hanging, overflowing the stack or
258
+ * corrupting the document: a cycle raises `CircularReference`, a graph that
259
+ * would sit deeper than `MAX_NESTING_DEPTH` in the output document raises
260
+ * `NestingDepthExceeded`, and a function or symbol — which has no YAML
261
+ * rendering, and whose `String()` form the value path refuses to write too —
262
+ * raises `UnrepresentableValue`. `depth` is measured in the stringifier's own
268
263
  * units — one per node from the document root — so the caller passes the
269
264
  * target's depth, not zero. `seen` holds
270
265
  * the ancestors of the value being lowered, so a value repeated across
@@ -302,7 +297,14 @@ function jsValueToNode(value, seen, depth) {
302
297
  seen.delete(value);
303
298
  }
304
299
  }
305
- return YamlScalar.make({
300
+ if (typeof value === "function" || typeof value === "symbol") throw new ModifyFailure("UnrepresentableValue", `A ${typeof value} value has no YAML representation`, 0, 0);
301
+ return value === null || value === void 0 ? YamlScalar.make({
302
+ value: null,
303
+ style: "plain",
304
+ raw: "null",
305
+ offset: 0,
306
+ length: 0
307
+ }) : YamlScalar.make({
306
308
  value,
307
309
  style: "plain",
308
310
  offset: 0,
@@ -390,34 +392,14 @@ function modifyNode(node, path, depth, value) {
390
392
  }
391
393
  function rebuildMap(node, items) {
392
394
  return YamlMap.make({
393
- items,
394
- style: node.style,
395
- ...definedFields({
396
- tag: node.tag,
397
- anchor: node.anchor,
398
- commentBefore: node.commentBefore,
399
- comment: node.comment,
400
- spaceBefore: node.spaceBefore,
401
- sourceMultiline: node.sourceMultiline
402
- }),
403
- offset: node.offset,
404
- length: node.length
395
+ ...node,
396
+ items
405
397
  });
406
398
  }
407
399
  function rebuildSeq(node, items) {
408
400
  return YamlSeq.make({
409
- items,
410
- style: node.style,
411
- ...definedFields({
412
- tag: node.tag,
413
- anchor: node.anchor,
414
- commentBefore: node.commentBefore,
415
- comment: node.comment,
416
- spaceBefore: node.spaceBefore,
417
- sourceMultiline: node.sourceMultiline
418
- }),
419
- offset: node.offset,
420
- length: node.length
401
+ ...node,
402
+ items
421
403
  });
422
404
  }
423
405
  /**
@@ -698,7 +680,10 @@ var YamlFormat = class YamlFormat {
698
680
  * sequence and any other non-null object as a block mapping over its own
699
681
  * enumerable string keys, recursively — the same lowering
700
682
  * {@link Yaml.stringify} applies to the same value, so `modify` and
701
- * `stringify` agree on what a given JavaScript value means. For a synthesized
683
+ * `stringify` agree on what a given JavaScript value means: a `bigint`
684
+ * renders bare (`a: 10`, never `a: "10"`), `null` renders as `null`, and a
685
+ * function or symbol fails `UnrepresentableValue` on both paths rather
686
+ * than landing in the document as its `String()` form. For a synthesized
702
687
  * subtree (an object/array value) only the surrounding document is
703
688
  * preserved byte-for-byte; the subtree carries no comments and takes the
704
689
  * stringifier's styles.
@@ -722,12 +707,13 @@ var YamlFormat = class YamlFormat {
722
707
  * whole document, which normalises line endings to LF, applies those
723
708
  * options, and renders the replacement in the stringifier's styles.
724
709
  *
725
- * Two replacement values have no finite rendering and fail typed rather
726
- * than hanging or overflowing the stack: one containing a circular
727
- * reference (`CircularReference`) and one that would sit deeper than 256
728
- * levels in the output document (`NestingDepthExceeded`). The depth is
729
- * counted from the document root, so the same value can fit at `[]` and
730
- * fail a few keys down.
710
+ * Three replacement values have no rendering and fail typed rather than
711
+ * hanging, overflowing the stack or corrupting the document: one
712
+ * containing a circular reference (`CircularReference`), one that would
713
+ * sit deeper than 256 levels in the output document
714
+ * (`NestingDepthExceeded`) and one containing a function or symbol
715
+ * (`UnrepresentableValue`). The depth is counted from the document root,
716
+ * so the same value can fit at `[]` and fail a few keys down.
731
717
  *
732
718
  * **Single-document contract.** A `path` carries no document index, so on
733
719
  * a multi-document stream there is no rule for which document it names —
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 circular-reference guard).
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 (the circular-reference guard), carrying structured
292
- * {@link YamlDiagnostic} entries and the offending value. Raised by
293
- * {@link Yaml.stringify}, `YamlDocument#stringify` and the encode direction of
294
- * the schema factories. The error itself has no `code` field: read the code
295
- * from the diagnostics — `error.diagnostics[0].code` is the primary failure.
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
- * or on a value nested deeper than the stringifier's recursion budget
389
- * (`NestingDepthExceeded`) — both surface through the typed error channel
390
- * rather than as an unhandled stack-overflow defect.
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
- * or a value nested past the recursion budget (`NestingDepthExceeded`)
488
- * yields a `Failure` carrying a {@link YamlStringifyError} rather than a
489
- * thrown stack-overflow defect; the method never throws.
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
@@ -1131,13 +1142,16 @@ export declare class YamlDocument extends YamlDocument_base {
1131
1142
  static schema(options?: YamlParseOptions): Schema.Codec<YamlDocument, string>;
1132
1143
  /**
1133
1144
  * Stringify this document (contents, directives and framing) as YAML.
1134
- * Fails with {@link YamlStringifyError} (`NestingDepthExceeded`) on a
1135
- * synthetic AST nested deeper than the stringifier's recursion budget. A
1136
- * cycle introduced into a synthetic AST fails the same way: the node path
1137
- * keeps no ancestor set, so the cycle is caught by the depth cap rather
1138
- * than reported as `CircularReference`. Either way the failure surfaces
1139
- * through the typed error channel, never as an unhandled stack-overflow
1140
- * defect.
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.
1141
1155
  * Defined in terms of {@link YamlDocument.stringifyResult} behind a
1142
1156
  * `YamlDocument.stringify` span — synchronous callers can use that variant
1143
1157
  * directly.
@@ -1164,11 +1178,10 @@ export declare class YamlDocument extends YamlDocument_base {
1164
1178
  * primitive {@link YamlDocument.stringify} is defined in terms of, so a
1165
1179
  * synchronous host can round-trip a document parsed with
1166
1180
  * {@link YamlDocument.parseResult} without an Effect runtime. Fails with
1167
- * {@link YamlStringifyError} exactly where `stringify` does: a synthetic
1168
- * AST nested deeper than the stringifier's recursion budget, or one
1169
- * containing a cycle, both as `NestingDepthExceeded` (the node path keeps
1170
- * no ancestor set, so a cycle is caught by the depth cap, not reported as
1171
- * `CircularReference`).
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`).
1172
1185
  *
1173
1186
  * @remarks
1174
1187
  * `YamlStringifyOptions.lineWidth` is not honored here, for the reason
@@ -1420,7 +1433,10 @@ export declare class YamlFormat {
1420
1433
  * sequence and any other non-null object as a block mapping over its own
1421
1434
  * enumerable string keys, recursively — the same lowering
1422
1435
  * {@link Yaml.stringify} applies to the same value, so `modify` and
1423
- * `stringify` agree on what a given JavaScript value means. For a synthesized
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
1424
1440
  * subtree (an object/array value) only the surrounding document is
1425
1441
  * preserved byte-for-byte; the subtree carries no comments and takes the
1426
1442
  * stringifier's styles.
@@ -1444,12 +1460,13 @@ export declare class YamlFormat {
1444
1460
  * whole document, which normalises line endings to LF, applies those
1445
1461
  * options, and renders the replacement in the stringifier's styles.
1446
1462
  *
1447
- * Two replacement values have no finite rendering and fail typed rather
1448
- * than hanging or overflowing the stack: one containing a circular
1449
- * reference (`CircularReference`) and one that would sit deeper than 256
1450
- * levels in the output document (`NestingDepthExceeded`). The depth is
1451
- * counted from the document root, so the same value can fit at `[]` and
1452
- * fail a few keys down.
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.
1453
1470
  *
1454
1471
  * **Single-document contract.** A `path` carries no document index, so on
1455
1472
  * a multi-document stream there is no rule for which document it names —
@@ -169,44 +169,22 @@ function columnAt(text, offset) {
169
169
  * included.
170
170
  */
171
171
  function withCommentFields(node, fields) {
172
+ const merged = mergedCommentFields(node, fields);
172
173
  if (node instanceof YamlScalar) return new YamlScalar({
173
- value: node.value,
174
- style: node.style,
175
- ...node.tag !== void 0 ? { tag: node.tag } : {},
176
- ...node.anchor !== void 0 ? { anchor: node.anchor } : {},
177
- ...mergedCommentFields(node, fields),
178
- ...node.chomp !== void 0 ? { chomp: node.chomp } : {},
179
- ...node.blockIndent !== void 0 ? { blockIndent: node.blockIndent } : {},
180
- ...node.raw !== void 0 ? { raw: node.raw } : {},
181
- ...node.sourceMultiline !== void 0 ? { sourceMultiline: node.sourceMultiline } : {},
182
- offset: node.offset,
183
- length: node.length
174
+ ...node,
175
+ ...merged
184
176
  });
185
177
  if (node instanceof YamlMap) return new YamlMap({
186
- items: node.items,
187
- style: node.style,
188
- ...node.tag !== void 0 ? { tag: node.tag } : {},
189
- ...node.anchor !== void 0 ? { anchor: node.anchor } : {},
190
- ...mergedCommentFields(node, fields),
191
- ...node.sourceMultiline !== void 0 ? { sourceMultiline: node.sourceMultiline } : {},
192
- offset: node.offset,
193
- length: node.length
178
+ ...node,
179
+ ...merged
194
180
  });
195
181
  if (node instanceof YamlSeq) return new YamlSeq({
196
- items: node.items,
197
- style: node.style,
198
- ...node.tag !== void 0 ? { tag: node.tag } : {},
199
- ...node.anchor !== void 0 ? { anchor: node.anchor } : {},
200
- ...mergedCommentFields(node, fields),
201
- ...node.sourceMultiline !== void 0 ? { sourceMultiline: node.sourceMultiline } : {},
202
- offset: node.offset,
203
- length: node.length
182
+ ...node,
183
+ ...merged
204
184
  });
205
185
  return new YamlAlias({
206
- name: node.name,
207
- ...mergedCommentFields(node, fields),
208
- offset: node.offset,
209
- length: node.length
186
+ ...node,
187
+ ...merged
210
188
  });
211
189
  }
212
190
  function mergedCommentFields(existing, incoming) {
@@ -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
 
@@ -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 only deliberate
39
- * stringify failure is the circular-reference guard (thrown as
40
- * `StringifyFailure`); the facade materializes it under this code so
41
- * `YamlStringifyError` carries structured diagnostics rather than a
42
- * `reason` string.
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 `NestingDepthExceeded` are the two limits on the
57
- * replacement value itself: `modify` lowers a plain JavaScript value into
58
- * AST nodes, and an object graph that points back at itself or nests deeper
59
- * than `MAX_NESTING_DEPTH` has no finite YAML rendering. Both names are
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
@@ -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 (circular references). The
7
- * facade catches this and materializes the public stringify error.
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
- return [renderDoubleQuoted(String(value))];
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) return stringifyMapNodeLines(node, ctx, depth);
607
- if (node instanceof YamlSeq) return stringifySeqNodeLines(node, ctx, depth);
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 = [renderDoubleQuoted(String(val))];
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effected/yaml",
3
- "version": "0.24.0",
3
+ "version": "0.25.1",
4
4
  "private": false,
5
5
  "description": "Zero-dependency YAML parsing, editing, formatting and linting as Effect schemas.",
6
6
  "keywords": [