@effected/yaml 0.22.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/Yaml.js +23 -30
  2. package/YamlDiagnostic.js +1 -2
  3. package/YamlDocument.js +125 -51
  4. package/YamlEdit.js +1 -2
  5. package/YamlFormat.js +115 -57
  6. package/YamlLint.js +1 -2
  7. package/YamlLintRule.js +1 -2
  8. package/YamlNode.js +1 -2
  9. package/YamlToken.js +1 -2
  10. package/YamlVisitor.js +1 -2
  11. package/index.d.ts +158 -32
  12. package/internal/composer/anchors.js +1 -2
  13. package/internal/composer/block.js +1 -2
  14. package/internal/composer/comments.js +1 -2
  15. package/internal/composer/document.js +1 -2
  16. package/internal/composer/flow.js +1 -2
  17. package/internal/composer/scalars.js +1 -2
  18. package/internal/composer/state.js +1 -2
  19. package/internal/composer/tags.js +1 -2
  20. package/internal/cst-parser.js +1 -2
  21. package/internal/diagnostics.js +1 -2
  22. package/internal/diff.js +1 -2
  23. package/internal/fold.js +1 -2
  24. package/internal/lexer.js +1 -2
  25. package/internal/requote.js +1 -2
  26. package/internal/rules/catalog.js +1 -2
  27. package/internal/rules/colon-spacing.js +1 -2
  28. package/internal/rules/comments-spacing.js +1 -2
  29. package/internal/rules/document-end.js +1 -2
  30. package/internal/rules/document-start.js +1 -2
  31. package/internal/rules/empty-lines.js +1 -2
  32. package/internal/rules/eof-newline.js +1 -2
  33. package/internal/rules/hyphen-spacing.js +1 -2
  34. package/internal/rules/indentation.js +1 -2
  35. package/internal/rules/key-duplicates.js +1 -2
  36. package/internal/rules/line-length.js +1 -2
  37. package/internal/rules/parse-validity.js +1 -2
  38. package/internal/rules/quoted-strings.js +1 -2
  39. package/internal/rules/trailing-spaces.js +1 -2
  40. package/internal/rules/truthy.js +1 -2
  41. package/internal/rules/util.js +1 -2
  42. package/internal/stringifier.js +1 -2
  43. package/package.json +1 -1
package/Yaml.js CHANGED
@@ -5,7 +5,7 @@ import { StringifyDepthExceeded, StringifyFailure, stringifyValue } from "./inte
5
5
  import { YamlDiagnostic } from "./YamlDiagnostic.js";
6
6
  import { Effect, Result, Schema, SchemaIssue, SchemaTransformation } from "effect";
7
7
 
8
- //#region src/Yaml.ts
8
+ // src/Yaml.ts
9
9
  /**
10
10
  * Options controlling parse behavior. All fields are omissible; absent fields
11
11
  * resolve to `strict` `true`, `maxAliasCount` `100` (the alias-based
@@ -224,8 +224,12 @@ const aliasCountExceededError = (message, text) => new YamlParseError({
224
224
  /**
225
225
  * Map an internal stringifier throw to its typed {@link YamlStringifyError},
226
226
  * or return `undefined` for any other defect (which the caller re-throws).
227
- * Shared by the Effect and synchronous stringify paths so both surface the
228
- * hardening guards (circular reference, nesting-depth cap) identically.
227
+ * Shared by every stringify path — `Yaml.stringify`/`stringifyResult`, the
228
+ * schema encoders, `YamlDocument#stringifyResult` and `YamlFormat.modify`'s
229
+ * backstop — so all of them surface the hardening guards (circular
230
+ * reference, nesting-depth cap) identically.
231
+ *
232
+ * @internal
229
233
  */
230
234
  const stringifyDefectToError = (defect, value) => {
231
235
  if (defect instanceof StringifyFailure) return new YamlStringifyError({
@@ -266,12 +270,13 @@ const parseResultImpl = (text, options) => {
266
270
  input: text
267
271
  }));
268
272
  const anchors = /* @__PURE__ */ new Map();
269
- try {
270
- return Result.succeed(nodeToJsValue(doc.contents, anchors, options?.maxAliasCount ?? 100));
271
- } catch (defect) {
272
- if (defect instanceof AliasExpansionBudgetExceeded) return Result.fail(aliasCountExceededError(defect.message, text));
273
- throw defect;
274
- }
273
+ return Result.try({
274
+ try: () => nodeToJsValue(doc.contents, anchors, options?.maxAliasCount ?? 100),
275
+ catch: (defect) => {
276
+ if (defect instanceof AliasExpansionBudgetExceeded) return aliasCountExceededError(defect.message, text);
277
+ throw defect;
278
+ }
279
+ });
275
280
  };
276
281
  /**
277
282
  * Synchronous multi-document parse returning a `Result`. Mirrors
@@ -308,15 +313,14 @@ const parseAllResultImpl = (text, options) => {
308
313
  * recursion budget yields a `Failure` carrying a typed {@link YamlStringifyError},
309
314
  * never a thrown defect.
310
315
  */
311
- const stringifyResultImpl = (value, options) => {
312
- try {
313
- return Result.succeed(stringifyValue(value, toStringifyInput(options)));
314
- } catch (defect) {
316
+ const stringifyResultImpl = (value, options) => Result.try({
317
+ try: () => stringifyValue(value, toStringifyInput(options)),
318
+ catch: (defect) => {
315
319
  const error = stringifyDefectToError(defect, value);
316
- if (error !== void 0) return Result.fail(error);
320
+ if (error !== void 0) return error;
317
321
  throw defect;
318
322
  }
319
- };
323
+ });
320
324
  /**
321
325
  * Collect the raw diagnostics that make a composed document a parse failure:
322
326
  * every fatal-code error, plus DuplicateKey warnings promoted to errors when
@@ -328,14 +332,6 @@ const failureRecords = (doc, uniqueKeys) => {
328
332
  if (fatal.length > 0) return fatal;
329
333
  return uniqueKeys ? doc.warnings.filter((w) => w.code === "DuplicateKey") : [];
330
334
  };
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
335
  /**
340
336
  * Static entry points for YAML parsing, stringification, comment stripping,
341
337
  * semantic equality and the schema factories. Not instantiable.
@@ -425,9 +421,7 @@ var Yaml = class Yaml {
425
421
  * @returns An `Effect` that succeeds with the YAML text, or fails with
426
422
  * {@link YamlStringifyError}.
427
423
  */
428
- static stringify = Effect.fn("Yaml.stringify")(function* (value, options) {
429
- return yield* stringifyOrFail(value, options);
430
- });
424
+ static stringify = Effect.fn("Yaml.stringify")((value, options) => Effect.fromResult(stringifyResultImpl(value, options)));
431
425
  /**
432
426
  * Synchronous single-document parse, returning a `Result` instead of
433
427
  * an `Effect`. A pure escape hatch for config-time callers that cannot
@@ -631,7 +625,7 @@ var Yaml = class Yaml {
631
625
  static fromString(options) {
632
626
  return Schema.String.pipe(Schema.decodeTo(Schema.Unknown, SchemaTransformation.transformEffect({
633
627
  decode: (input) => Yaml.parse(input, options).pipe(Effect.mapError((error) => new SchemaIssue.InvalidValue({ message: error.message }, input))),
634
- encode: (value) => stringifyOrFail(value).pipe(Effect.mapError((error) => new SchemaIssue.InvalidValue({ message: error.message }, value)))
628
+ encode: (value) => Effect.fromResult(stringifyResultImpl(value)).pipe(Effect.mapError((error) => new SchemaIssue.InvalidValue({ message: error.message }, value)))
635
629
  })));
636
630
  }
637
631
  /**
@@ -655,7 +649,7 @@ var Yaml = class Yaml {
655
649
  if (values.length === 0) return "";
656
650
  const parts = [];
657
651
  for (let index = 0; index < values.length; index++) {
658
- const yaml = yield* stringifyOrFail(values[index]).pipe(Effect.mapError((error) => new SchemaIssue.InvalidValue({ message: error.message }, values)));
652
+ const yaml = yield* Effect.fromResult(stringifyResultImpl(values[index])).pipe(Effect.mapError((error) => new SchemaIssue.InvalidValue({ message: error.message }, values)));
659
653
  parts.push(index > 0 ? `---\n${yaml}` : yaml);
660
654
  }
661
655
  return parts.join("");
@@ -774,5 +768,4 @@ function deepEqualValues(a, b) {
774
768
  return false;
775
769
  }
776
770
 
777
- //#endregion
778
- export { Yaml, YamlParseError, YamlParseOptions, YamlStringifyError, YamlStringifyOptions };
771
+ export { Yaml, YamlParseError, YamlParseOptions, YamlStringifyError, YamlStringifyOptions, stringifyDefectToError };
package/YamlDiagnostic.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { YAML_COMPOSE_ERROR_CODES, YAML_LEX_ERROR_CODES, YAML_MODIFY_ERROR_CODES, YAML_PARSE_ERROR_CODES, YAML_STRINGIFY_ERROR_CODES, isFatalCode } from "./internal/diagnostics.js";
2
2
  import { Schema } from "effect";
3
3
 
4
- //#region src/YamlDiagnostic.ts
4
+ // src/YamlDiagnostic.ts
5
5
  /**
6
6
  * Error codes emitted by the lexer stage.
7
7
  *
@@ -128,5 +128,4 @@ function lineChar(text, offset) {
128
128
  };
129
129
  }
130
130
 
131
- //#endregion
132
131
  export { YamlComposerErrorCode, YamlDiagnostic, YamlErrorCode, YamlLexErrorCode, YamlModifyErrorCode, YamlParseErrorCode, YamlStringifyErrorCode };
package/YamlDocument.js CHANGED
@@ -1,12 +1,12 @@
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 { StringifyDepthExceeded, StringifyFailure, stringifyDocument } from "./internal/stringifier.js";
4
+ import { stringifyDocument } from "./internal/stringifier.js";
5
5
  import { YamlDiagnostic } from "./YamlDiagnostic.js";
6
- import { YamlParseError, YamlStringifyError } from "./Yaml.js";
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
- //#region src/YamlDocument.ts
9
+ // src/YamlDocument.ts
10
10
  /**
11
11
  * A YAML directive appearing before a document (e.g. `%YAML 1.2` or
12
12
  * `%TAG ! tag:example.com,2000:`). `"YAML"` and `"TAG"` are the YAML 1.2
@@ -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")(function* (text, options) {
74
- const raw = composeFirstDocument(text, toParseInput(options));
75
- const fatal = raw.errors.filter((e) => isFatalCode(e.code));
76
- if (fatal.length > 0) return yield* new YamlParseError({
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")(function* (text, options) {
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,16 @@ var YamlDocument = class YamlDocument extends Schema.Class("YamlDocument")({
119
174
  }
120
175
  /**
121
176
  * Stringify this document (contents, directives and framing) as YAML.
122
- * Fails with {@link YamlStringifyError} on circular references introduced
123
- * into a synthetic AST (`CircularReference`) or on a synthetic AST nested
124
- * deeper than the stringifier's recursion budget (`NestingDepthExceeded`)
125
- * — both surface through the typed error channel rather than as an
126
- * unhandled stack-overflow defect.
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.
184
+ * Defined in terms of {@link YamlDocument.stringifyResult} behind a
185
+ * `YamlDocument.stringify` span — synchronous callers can use that variant
186
+ * directly.
127
187
  *
128
188
  * @remarks
129
189
  * `YamlStringifyOptions.lineWidth` is not honored here: column-based
@@ -142,31 +202,46 @@ var YamlDocument = class YamlDocument extends Schema.Class("YamlDocument")({
142
202
  * {@link YamlStringifyError}.
143
203
  */
144
204
  stringify(options) {
145
- return Effect.try({
205
+ return Effect.suspend(() => Effect.fromResult(this.stringifyResult(options))).pipe(Effect.withSpan("YamlDocument.stringify"));
206
+ }
207
+ /**
208
+ * Synchronous stringify, returning a `Result` instead of an `Effect` — the
209
+ * primitive {@link YamlDocument.stringify} is defined in terms of, so a
210
+ * synchronous host can round-trip a document parsed with
211
+ * {@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`).
217
+ *
218
+ * @remarks
219
+ * `YamlStringifyOptions.lineWidth` is not honored here, for the reason
220
+ * given on {@link YamlDocument.stringify}.
221
+ *
222
+ * @example
223
+ * ```ts
224
+ * import { YamlDocument } from "@effected/yaml";
225
+ * import { Result } from "effect";
226
+ *
227
+ * const parsed = YamlDocument.parseResult("# keep\nname: Alice\n");
228
+ * if (Result.isSuccess(parsed)) {
229
+ * const text = parsed.success.stringifyResult();
230
+ * if (Result.isSuccess(text)) console.log(text.success); // => "# keep\nname: Alice\n"
231
+ * }
232
+ * ```
233
+ *
234
+ * @param options - Optional {@link YamlStringifyOptions}; defaults apply for
235
+ * omitted fields.
236
+ * @returns A `Result` succeeding with the YAML text, or failing with
237
+ * {@link YamlStringifyError}.
238
+ */
239
+ stringifyResult(options) {
240
+ return Result.try({
146
241
  try: () => stringifyDocument(toRawDocument(this), toStringifyInput(options)),
147
242
  catch: (defect) => {
148
- if (defect instanceof StringifyFailure) return new YamlStringifyError({
149
- diagnostics: [YamlDiagnostic.make({
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
- });
243
+ const error = stringifyDefectToError(defect, this);
244
+ if (error !== void 0) return error;
170
245
  throw defect;
171
246
  }
172
247
  });
@@ -243,5 +318,4 @@ function toRawDocument(doc) {
243
318
  };
244
319
  }
245
320
 
246
- //#endregion
247
321
  export { YamlDirective, YamlDocument, documentFromRaw };
package/YamlEdit.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Schema } from "effect";
2
2
 
3
- //#region src/YamlEdit.ts
3
+ // src/YamlEdit.ts
4
4
  /**
5
5
  * A range within a YAML document, expressed as a zero-based character
6
6
  * `offset` and a `length` in UTF-16 code units. Pass to `YamlFormat.format`
@@ -52,5 +52,4 @@ var YamlEdit = class extends Schema.Class("YamlEdit")({
52
52
  }
53
53
  };
54
54
 
55
- //#endregion
56
55
  export { YamlEdit, YamlRange };
package/YamlFormat.js CHANGED
@@ -3,13 +3,13 @@ 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
- //#region src/YamlFormat.ts
12
+ // src/YamlFormat.ts
13
13
  /**
14
14
  * Options controlling formatting behavior: every {@link YamlStringifyOptions}
15
15
  * field (derived, not hand-duplicated — including `indentSequences`,
@@ -263,7 +263,10 @@ function formatStream(text, documents, streamErrors, options) {
263
263
  *
264
264
  * The two conditions with no finite rendering fail typed rather than hanging
265
265
  * or overflowing the stack: a cycle raises `CircularReference` and a graph
266
- * deeper than `MAX_NESTING_DEPTH` raises `NestingDepthExceeded`. `seen` holds
266
+ * that would sit deeper than `MAX_NESTING_DEPTH` in the output document
267
+ * raises `NestingDepthExceeded`. `depth` is measured in the stringifier's own
268
+ * units — one per node from the document root — so the caller passes the
269
+ * target's depth, not zero. `seen` holds
267
270
  * the ancestors of the value being lowered, so a value repeated across
268
271
  * siblings (a shared, acyclic sub-object) is lowered twice rather than
269
272
  * rejected.
@@ -306,12 +309,17 @@ function jsValueToNode(value, seen, depth) {
306
309
  length: 0
307
310
  });
308
311
  }
309
- /** Entry point for {@link jsValueToNode}: one `seen` set per lowering. */
310
- function lowerValue(value) {
311
- return jsValueToNode(value, /* @__PURE__ */ new Set(), 0);
312
+ /**
313
+ * Entry point for {@link jsValueToNode}: one `seen` set per lowering, counting
314
+ * depth from `targetDepth` — the depth the value will occupy in the output
315
+ * document (the path length: a root replacement sits at 0, a value one key
316
+ * down at 1).
317
+ */
318
+ function lowerValue(value, targetDepth) {
319
+ return jsValueToNode(value, /* @__PURE__ */ new Set(), targetDepth);
312
320
  }
313
321
  function modifyDocument(doc, path, value) {
314
- if (path.length === 0) return value === void 0 ? null : lowerValue(value);
322
+ if (path.length === 0) return value === void 0 ? null : lowerValue(value, 0);
315
323
  if (doc.contents === null) throw new ModifyFailure("EmptyDocument", "Cannot navigate path in empty document", 0, 0);
316
324
  return modifyNode(doc.contents, path, 0, value);
317
325
  }
@@ -327,7 +335,7 @@ function modifyNode(node, path, depth, value) {
327
335
  newItems.splice(pairIndex, 1);
328
336
  return rebuildMap(node, newItems);
329
337
  }
330
- const newValueNode = lowerValue(value);
338
+ const newValueNode = lowerValue(value, depth + 1);
331
339
  if (pairIndex >= 0) {
332
340
  const newItems = [...node.items];
333
341
  const oldPair = newItems[pairIndex];
@@ -367,8 +375,8 @@ function modifyNode(node, path, depth, value) {
367
375
  const newItems = [...node.items];
368
376
  if (value === void 0) {
369
377
  if (idx < newItems.length) newItems.splice(idx, 1);
370
- } else if (idx < newItems.length) newItems[idx] = lowerValue(value);
371
- else newItems.push(lowerValue(value));
378
+ } else if (idx < newItems.length) newItems[idx] = lowerValue(value, depth + 1);
379
+ else newItems.push(lowerValue(value, depth + 1));
372
380
  return rebuildSeq(node, newItems);
373
381
  }
374
382
  if (idx >= node.items.length) throw new ModifyFailure("InvalidIndex", `Index ${idx} out of bounds`, node.offset, node.length);
@@ -678,7 +686,9 @@ var YamlFormat = class YamlFormat {
678
686
  return YamlEdit.applyAll(text, YamlFormat.format(text, range, options));
679
687
  }
680
688
  /**
681
- * Compute the edits that insert, replace, or remove a value at `path`.
689
+ * Compute the edits that insert, replace, or remove a value at `path`,
690
+ * synchronously — the primitive {@link YamlFormat.modify} is defined in
691
+ * terms of, so a synchronous host can call it without an Effect runtime.
682
692
  * Passing `value === undefined` removes the target key/element; a missing
683
693
  * insertion target appends after the last pair/element. Fails with
684
694
  * {@link YamlModificationError} on a fatal parse error or a structural
@@ -714,8 +724,10 @@ var YamlFormat = class YamlFormat {
714
724
  *
715
725
  * Two replacement values have no finite rendering and fail typed rather
716
726
  * than hanging or overflowing the stack: one containing a circular
717
- * reference (`CircularReference`) and one nesting deeper than 256 levels
718
- * (`NestingDepthExceeded`).
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.
719
731
  *
720
732
  * **Single-document contract.** A `path` carries no document index, so on
721
733
  * a multi-document stream there is no rule for which document it names —
@@ -740,63 +752,109 @@ var YamlFormat = class YamlFormat {
740
752
  * target instead.
741
753
  * @param options - Optional {@link YamlStringifyOptions} for the
742
754
  * re-stringify step.
743
- * @returns An `Effect` that succeeds with the edits to apply (via
744
- * `YamlEdit.applyAll`), or fails with {@link YamlModificationError}.
755
+ * @returns A `Result` succeeding with the edits to apply (via
756
+ * `YamlEdit.applyAll`), or failing with {@link YamlModificationError}.
745
757
  *
746
758
  * @remarks
747
759
  * `options` is a bare {@link YamlStringifyOptions} — it controls only the
748
760
  * internal re-stringify step, not a range (there is no range to restrict
749
761
  * for a path-targeted modification).
750
762
  */
751
- static modify = Effect.fn("YamlFormat.modify")(function* (text, path, value, options) {
752
- const { document: doc, documentCount } = composeFirstDocumentCounted(text, {});
753
- if (documentCount > 1) return yield* new YamlModificationError({
763
+ static modifyResult(text, path, value, options) {
764
+ const fail = (diagnostics) => Result.fail(new YamlModificationError({
754
765
  path,
755
- diagnostics: [YamlDiagnostic.fromRaw({
756
- code: "MultiDocumentStream",
757
- message: `Cannot modify a multi-document stream (${documentCount} documents): modify re-emits exactly one document`,
758
- offset: 0,
759
- length: 0
760
- }, text)]
761
- });
766
+ diagnostics
767
+ }));
768
+ const { document: doc, documentCount } = composeFirstDocumentCounted(text, {});
769
+ if (documentCount > 1) return fail([YamlDiagnostic.fromRaw({
770
+ code: "MultiDocumentStream",
771
+ message: `Cannot modify a multi-document stream (${documentCount} documents): modify re-emits exactly one document`,
772
+ offset: 0,
773
+ length: 0
774
+ }, text)]);
762
775
  const fatal = doc.errors.filter((e) => isFatalCode(e.code));
763
- if (fatal.length > 0) return yield* new YamlModificationError({
764
- path,
765
- diagnostics: fatal.map((e) => YamlDiagnostic.fromRaw(e, text))
766
- });
767
- if (doc.directives.length > 0) return yield* new YamlModificationError({
768
- path,
769
- diagnostics: [YamlDiagnostic.fromRaw({
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
- });
776
+ if (fatal.length > 0) return fail(fatal.map((e) => YamlDiagnostic.fromRaw(e, text)));
777
+ if (doc.directives.length > 0) return fail([YamlDiagnostic.fromRaw({
778
+ code: "DirectiveCarryingDocument",
779
+ 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",
780
+ offset: 0,
781
+ length: 0
782
+ }, text)]);
776
783
  const regional = tryRegionalScalarEdit(text, doc, path, value, options);
777
- if (regional !== void 0) return regional.map((e) => YamlEdit.make(e));
784
+ if (regional !== void 0) return Result.succeed(regional.map((e) => YamlEdit.make(e)));
778
785
  let newContents;
779
786
  try {
780
787
  newContents = modifyDocument(doc, path, value);
781
788
  } catch (err) {
782
789
  if (!(err instanceof ModifyFailure)) throw err;
783
- return yield* new YamlModificationError({
784
- path,
785
- diagnostics: [YamlDiagnostic.fromRaw({
786
- code: err.code,
787
- message: err.message,
788
- offset: err.offset,
789
- length: err.length
790
- }, text)]
791
- });
790
+ return fail([YamlDiagnostic.fromRaw({
791
+ code: err.code,
792
+ message: err.message,
793
+ offset: err.offset,
794
+ length: err.length
795
+ }, text)]);
792
796
  }
793
797
  const outputDoc = {
794
798
  ...doc,
795
799
  contents: newContents
796
800
  };
797
- const formatted = stringifyDocument(outputDoc, toStringifyInput(options));
798
- return computeEdits(text, withSourceBom(text, formatted)).map((e) => YamlEdit.make(e));
799
- });
801
+ let formatted;
802
+ try {
803
+ formatted = stringifyDocument(outputDoc, toStringifyInput(options));
804
+ } catch (defect) {
805
+ const error = stringifyDefectToError(defect, value);
806
+ if (error === void 0) throw defect;
807
+ return fail(error.diagnostics);
808
+ }
809
+ return Result.succeed(computeEdits(text, withSourceBom(text, formatted)).map((e) => YamlEdit.make(e)));
810
+ }
811
+ /**
812
+ * Compute the edits that insert, replace, or remove a value at `path`.
813
+ * Defined in terms of {@link YamlFormat.modifyResult}, which carries the
814
+ * full contract — value lowering, region-confined scalar replacement, the
815
+ * single-document contract and the directive refusal — behind a
816
+ * `YamlFormat.modify` span; synchronous callers can use that variant
817
+ * directly.
818
+ *
819
+ * @param text - The YAML source to modify.
820
+ * @param path - The location to insert, replace or remove.
821
+ * @param value - The JavaScript value to write; `undefined` removes the
822
+ * target instead.
823
+ * @param options - Optional {@link YamlStringifyOptions} for the
824
+ * re-stringify step.
825
+ * @returns An `Effect` that succeeds with the edits to apply (via
826
+ * `YamlEdit.applyAll`), or fails with {@link YamlModificationError}.
827
+ */
828
+ static modify = Effect.fn("YamlFormat.modify")((text, path, value, options) => Effect.fromResult(YamlFormat.modifyResult(text, path, value, options)));
829
+ /**
830
+ * Synchronous {@link YamlFormat.modifyToString}: modify `text` and apply the
831
+ * resulting edits in one step (`YamlEdit.applyAll ∘ modifyResult`),
832
+ * returning a `Result`. Inherits the {@link YamlFormat.modifyResult} error
833
+ * channel.
834
+ *
835
+ * @example
836
+ * ```ts
837
+ * import { YamlFormat } from "@effected/yaml";
838
+ * import { Result } from "effect";
839
+ *
840
+ * const result = YamlFormat.modifyToStringResult("port: 3000 # dev\n", ["port"], 8080);
841
+ * if (Result.isSuccess(result)) {
842
+ * console.log(result.success); // => "port: 8080 # dev\n"
843
+ * }
844
+ * ```
845
+ *
846
+ * @param text - The YAML source to modify.
847
+ * @param path - The location to insert, replace or remove.
848
+ * @param value - The JavaScript value to write; `undefined` removes the
849
+ * target instead.
850
+ * @param options - Optional {@link YamlStringifyOptions} for the
851
+ * re-stringify step.
852
+ * @returns A `Result` succeeding with the modified text, or failing with
853
+ * {@link YamlModificationError}.
854
+ */
855
+ static modifyToStringResult(text, path, value, options) {
856
+ return Result.map(YamlFormat.modifyResult(text, path, value, options), (edits) => YamlEdit.applyAll(text, edits));
857
+ }
800
858
  /**
801
859
  * Modify `text` and apply the resulting edits in one step
802
860
  * (`YamlEdit.applyAll ∘ modify`). Inherits the {@link YamlFormat.modify}
@@ -812,12 +870,12 @@ var YamlFormat = class YamlFormat {
812
870
  * re-stringify step.
813
871
  * @returns An `Effect` that succeeds with the modified text, or fails with
814
872
  * {@link YamlModificationError}.
873
+ *
874
+ * @remarks
875
+ * Defined in terms of {@link YamlFormat.modifyToStringResult}; it opens its
876
+ * own span, with no nested `YamlFormat.modify` child span.
815
877
  */
816
- static modifyToString = Effect.fn("YamlFormat.modifyToString")(function* (text, path, value, options) {
817
- const edits = yield* YamlFormat.modify(text, path, value, options);
818
- return YamlEdit.applyAll(text, edits);
819
- });
878
+ static modifyToString = Effect.fn("YamlFormat.modifyToString")((text, path, value, options) => Effect.fromResult(YamlFormat.modifyToStringResult(text, path, value, options)));
820
879
  };
821
880
 
822
- //#endregion
823
881
  export { YamlFormat, YamlFormattingOptions, YamlModificationError };
package/YamlLint.js CHANGED
@@ -8,7 +8,7 @@ import { builtinOptionsSchemas, builtinRules } from "./internal/rules/catalog.js
8
8
  import { YamlTokens } from "./YamlToken.js";
9
9
  import { Result, Schema } from "effect";
10
10
 
11
- //#region src/YamlLint.ts
11
+ // src/YamlLint.ts
12
12
  /**
13
13
  * One entry of the config `rules` map: a bare severity literal (the common
14
14
  * case), `"off"` to disable, or a typed per-rule options object (the tuning
@@ -551,5 +551,4 @@ var YamlLint = class YamlLint {
551
551
  }
552
552
  };
553
553
 
554
- //#endregion
555
554
  export { StyleConflict, StyleEvidence, StyleFloorTally, StyleVoteTally, YamlLint, YamlLintConfig, YamlLintRuleSetting, YamlStyleConflictError };