@effected/yaml 0.4.0 → 0.5.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 +57 -24
- package/YamlDocument.js +1 -1
- package/YamlFormat.js +11 -1
- package/YamlNode.js +11 -1
- package/index.d.ts +79 -12
- package/index.js +2 -2
- package/internal/stringifier.js +52 -12
- package/package.json +1 -1
package/Yaml.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AliasExpansionBudgetExceeded, CollectionStyle, ScalarStyle, nodeToJsValue } from "./YamlNode.js";
|
|
1
|
+
import { AliasExpansionBudgetExceeded, CollectionStyle, QuoteStyle, ScalarStyle, nodeToJsValue } from "./YamlNode.js";
|
|
2
2
|
import { buildAnchorMap } from "./internal/composer/anchors.js";
|
|
3
3
|
import { composeAllDocuments, composeFirstDocument } from "./internal/composer/document.js";
|
|
4
4
|
import { isFatalCode } from "./internal/diagnostics.js";
|
|
@@ -36,8 +36,8 @@ var YamlParseOptions = class extends Schema.Class("YamlParseOptions")({
|
|
|
36
36
|
* Options controlling stringify behavior. All fields are omissible; absent
|
|
37
37
|
* fields resolve to `indent` `2`, `lineWidth` `0`, `defaultScalarStyle`
|
|
38
38
|
* `"plain"`, `defaultCollectionStyle` `"block"`, `sortKeys` `false`,
|
|
39
|
-
* `indentSequences` `false`, `
|
|
40
|
-
* `false`.
|
|
39
|
+
* `indentSequences` `false`, `quoteStyle` `"single"`, `finalNewline` `true`
|
|
40
|
+
* and `forceDefaultStyles` `false`.
|
|
41
41
|
*
|
|
42
42
|
* `lineWidth` controls column-based scalar folding. The default `0` (and any
|
|
43
43
|
* value `<= 0`) never wraps, emitting byte-identical output to the historic
|
|
@@ -54,6 +54,18 @@ var YamlParseOptions = class extends Schema.Class("YamlParseOptions")({
|
|
|
54
54
|
* matching the `yaml` npm package's default output. Top-level sequences stay
|
|
55
55
|
* at column zero in both modes.
|
|
56
56
|
*
|
|
57
|
+
* `quoteStyle` selects the quote character used when a `plain`-styled scalar
|
|
58
|
+
* (the `defaultScalarStyle` default) turns out to require quoting: `"single"`
|
|
59
|
+
* (the default) emits `'@parcel/watcher'` — the kit's byte-compatible legacy
|
|
60
|
+
* form — while `"double"` emits `"@parcel/watcher"`, matching the `yaml` npm
|
|
61
|
+
* package's `singleQuote: false` output. It is a fallback selector only:
|
|
62
|
+
* scalars that need no quoting stay plain, and an explicit
|
|
63
|
+
* `defaultScalarStyle` of `"single-quoted"` or `"double-quoted"` still wins.
|
|
64
|
+
* On that plain fallback path, values carrying a tab, a carriage return or
|
|
65
|
+
* any other C0 control character are always emitted double-quoted whichever
|
|
66
|
+
* `quoteStyle` is set, since only double quotes can escape them into a form
|
|
67
|
+
* that round-trips exactly.
|
|
68
|
+
*
|
|
57
69
|
* Construct with the validated `YamlStringifyOptions.make({ ... })` static —
|
|
58
70
|
* the kit convention (never `new`). Call sites that take a
|
|
59
71
|
* `YamlStringifyOptions` also accept a structurally-matching plain literal.
|
|
@@ -79,7 +91,7 @@ var YamlStringifyOptions = class extends Schema.Class("YamlStringifyOptions")({
|
|
|
79
91
|
* (`>`) scalars at approximately that column, never block-literal (`|`).
|
|
80
92
|
*
|
|
81
93
|
* Takes effect only through {@link Yaml.stringify} and
|
|
82
|
-
* {@link Yaml.
|
|
94
|
+
* {@link Yaml.stringifyResult} — the two entry points that accept these
|
|
83
95
|
* options on the value path. The schema factories ({@link Yaml.fromString},
|
|
84
96
|
* {@link Yaml.schema}, {@link Yaml.YamlFromString}) encode with default
|
|
85
97
|
* stringify options (`lineWidth` `0`), so their output never folds. The
|
|
@@ -92,6 +104,17 @@ var YamlStringifyOptions = class extends Schema.Class("YamlStringifyOptions")({
|
|
|
92
104
|
defaultCollectionStyle: Schema.optionalKey(CollectionStyle),
|
|
93
105
|
sortKeys: Schema.optionalKey(Schema.Boolean),
|
|
94
106
|
indentSequences: Schema.optionalKey(Schema.Boolean),
|
|
107
|
+
/**
|
|
108
|
+
* Quote style used when a `plain`-styled scalar requires quoting. Default
|
|
109
|
+
* `"single"` — the released byte-compatible behavior. `"double"` renders
|
|
110
|
+
* the same scalars double-quoted instead, matching the `yaml` npm
|
|
111
|
+
* package's `singleQuote: false` output.
|
|
112
|
+
*
|
|
113
|
+
* Affects only the plain fallback: scalars that need no quoting stay
|
|
114
|
+
* plain, and an explicit `defaultScalarStyle` of `"single-quoted"` or
|
|
115
|
+
* `"double-quoted"` is unaffected.
|
|
116
|
+
*/
|
|
117
|
+
quoteStyle: Schema.optionalKey(QuoteStyle),
|
|
95
118
|
finalNewline: Schema.optionalKey(Schema.Boolean),
|
|
96
119
|
forceDefaultStyles: Schema.optionalKey(Schema.Boolean)
|
|
97
120
|
}) {};
|
|
@@ -141,6 +164,7 @@ const toStringifyInput = (options) => options === void 0 ? {} : {
|
|
|
141
164
|
defaultCollectionStyle: options.defaultCollectionStyle,
|
|
142
165
|
sortKeys: options.sortKeys,
|
|
143
166
|
indentSequences: options.indentSequences,
|
|
167
|
+
quoteStyle: options.quoteStyle,
|
|
144
168
|
finalNewline: options.finalNewline,
|
|
145
169
|
forceDefaultStyles: options.forceDefaultStyles
|
|
146
170
|
};
|
|
@@ -198,7 +222,7 @@ const stringifyDefectToError = (defect, value) => {
|
|
|
198
222
|
* mode (fatal diagnostics, duplicate keys, a "billion laughs" blow-up) yields
|
|
199
223
|
* a `Failure` carrying a typed {@link YamlParseError} — never a throw.
|
|
200
224
|
*/
|
|
201
|
-
const
|
|
225
|
+
const parseResultImpl = (text, options) => {
|
|
202
226
|
const doc = composeFirstDocument(text, toParseInput(options));
|
|
203
227
|
const failures = failureRecords(doc, options?.uniqueKeys ?? true);
|
|
204
228
|
if (failures.length > 0) return Result.fail(new YamlParseError({
|
|
@@ -219,7 +243,7 @@ const parseSyncImpl = (text, options) => {
|
|
|
219
243
|
* recursion budget yields a `Failure` carrying a typed {@link YamlStringifyError},
|
|
220
244
|
* never a thrown defect.
|
|
221
245
|
*/
|
|
222
|
-
const
|
|
246
|
+
const stringifyResultImpl = (value, options) => {
|
|
223
247
|
try {
|
|
224
248
|
return Result.succeed(stringifyValue(value, toStringifyInput(options)));
|
|
225
249
|
} catch (defect) {
|
|
@@ -296,17 +320,11 @@ var Yaml = class Yaml {
|
|
|
296
320
|
* resolved size grows exponentially relative to `maxAliasCount`) also
|
|
297
321
|
* fails through {@link YamlParseError} with an `AliasCountExceeded`
|
|
298
322
|
* diagnostic, never as an unhandled defect.
|
|
323
|
+
*
|
|
324
|
+
* Defined in terms of {@link Yaml.parseResult} — synchronous callers can
|
|
325
|
+
* use that variant directly.
|
|
299
326
|
*/
|
|
300
|
-
static parse = Effect.fn("Yaml.parse")(
|
|
301
|
-
const doc = composeFirstDocument(text, toParseInput(options));
|
|
302
|
-
const failures = failureRecords(doc, options?.uniqueKeys ?? true);
|
|
303
|
-
if (failures.length > 0) return yield* new YamlParseError({
|
|
304
|
-
diagnostics: toDiagnostics(text, failures),
|
|
305
|
-
input: text
|
|
306
|
-
});
|
|
307
|
-
const anchors = /* @__PURE__ */ new Map();
|
|
308
|
-
return yield* extractDocumentValue(doc.contents, anchors, options?.maxAliasCount ?? 100, text);
|
|
309
|
-
});
|
|
327
|
+
static parse = Effect.fn("Yaml.parse")((text, options) => Effect.fromResult(Yaml.parseResult(text, options)));
|
|
310
328
|
/**
|
|
311
329
|
* Parse a multi-document YAML stream into an array of plain JavaScript
|
|
312
330
|
* values (one per document, in order). Any fatal diagnostic in any
|
|
@@ -339,6 +357,15 @@ var Yaml = class Yaml {
|
|
|
339
357
|
* or on a value nested deeper than the stringifier's recursion budget
|
|
340
358
|
* (`NestingDepthExceeded`) — both surface through the typed error channel
|
|
341
359
|
* rather than as an unhandled stack-overflow defect.
|
|
360
|
+
*
|
|
361
|
+
* @remarks
|
|
362
|
+
* A `"<<"` object key is emitted **quoted** (`'<<': …`). This is the
|
|
363
|
+
* opposite of the document path ({@link YamlFormat.format} and
|
|
364
|
+
* `YamlDocument#stringify`), which leaves a parsed plain `<<` key unquoted
|
|
365
|
+
* so it keeps its merge-key meaning, and the asymmetry is deliberate: a
|
|
366
|
+
* `"<<"` key on a plain JavaScript object is an ordinary string key that
|
|
367
|
+
* never carried merge semantics, so emitting it plain would silently turn
|
|
368
|
+
* ordinary data into a merge directive.
|
|
342
369
|
*/
|
|
343
370
|
static stringify = Effect.fn("Yaml.stringify")(function* (value, options) {
|
|
344
371
|
return yield* stringifyOrFail(value, options);
|
|
@@ -346,8 +373,14 @@ var Yaml = class Yaml {
|
|
|
346
373
|
/**
|
|
347
374
|
* Synchronous single-document parse, returning a `Result` instead of
|
|
348
375
|
* an `Effect`. A pure escape hatch for config-time callers that cannot
|
|
349
|
-
* `await` an Effect (a `vitest.config.ts` is the motivating case)
|
|
350
|
-
*
|
|
376
|
+
* `await` an Effect (a `vitest.config.ts` is the motivating case).
|
|
377
|
+
*
|
|
378
|
+
* @remarks
|
|
379
|
+
* This is the package's single parse path. {@link Yaml.parse} is defined in
|
|
380
|
+
* terms of it (`Effect.fromResult` behind the named span), so the two
|
|
381
|
+
* variants cannot diverge. Reach for the `Effect` variant inside Effect
|
|
382
|
+
* code — it carries the `Yaml.parse` tracing span — and for this one at
|
|
383
|
+
* synchronous boundaries.
|
|
351
384
|
*
|
|
352
385
|
* Preserves the package contract — malformed and adversarial input fails
|
|
353
386
|
* typed, never as a defect. Fatal diagnostics, duplicate keys and a
|
|
@@ -359,7 +392,7 @@ var Yaml = class Yaml {
|
|
|
359
392
|
* import { Yaml } from "@effected/yaml";
|
|
360
393
|
* import { Result } from "effect";
|
|
361
394
|
*
|
|
362
|
-
* const result = Yaml.
|
|
395
|
+
* const result = Yaml.parseResult("name: Alice\nage: 30");
|
|
363
396
|
* if (Result.isSuccess(result)) {
|
|
364
397
|
* result.success; // { name: "Alice", age: 30 }
|
|
365
398
|
* } else {
|
|
@@ -369,8 +402,8 @@ var Yaml = class Yaml {
|
|
|
369
402
|
*
|
|
370
403
|
* @public
|
|
371
404
|
*/
|
|
372
|
-
static
|
|
373
|
-
return
|
|
405
|
+
static parseResult(text, options) {
|
|
406
|
+
return parseResultImpl(text, options);
|
|
374
407
|
}
|
|
375
408
|
/**
|
|
376
409
|
* Synchronous stringify, returning a `Result` instead of an `Effect`.
|
|
@@ -387,7 +420,7 @@ var Yaml = class Yaml {
|
|
|
387
420
|
* import { Yaml } from "@effected/yaml";
|
|
388
421
|
* import { Result } from "effect";
|
|
389
422
|
*
|
|
390
|
-
* const result = Yaml.
|
|
423
|
+
* const result = Yaml.stringifyResult({ name: "Alice" });
|
|
391
424
|
* if (Result.isFailure(result)) {
|
|
392
425
|
* result.failure; // YamlStringifyError
|
|
393
426
|
* } else {
|
|
@@ -397,8 +430,8 @@ var Yaml = class Yaml {
|
|
|
397
430
|
*
|
|
398
431
|
* @public
|
|
399
432
|
*/
|
|
400
|
-
static
|
|
401
|
-
return
|
|
433
|
+
static stringifyResult(value, options) {
|
|
434
|
+
return stringifyResultImpl(value, options);
|
|
402
435
|
}
|
|
403
436
|
/**
|
|
404
437
|
* Strip comments from YAML text. Without `replaceCh`, comment characters
|
package/YamlDocument.js
CHANGED
|
@@ -96,7 +96,7 @@ var YamlDocument = class YamlDocument extends Schema.Class("YamlDocument")({
|
|
|
96
96
|
* `YamlStringifyOptions.lineWidth` is not honored here: column-based
|
|
97
97
|
* scalar folding exists only on the value path, through the entry points
|
|
98
98
|
* that accept stringify options ({@link Yaml.stringify} and
|
|
99
|
-
* {@link Yaml.
|
|
99
|
+
* {@link Yaml.stringifyResult}). The
|
|
100
100
|
* document/node path threads `lineWidth` into its render context but
|
|
101
101
|
* never reads it, so long scalars are emitted unfolded regardless of the
|
|
102
102
|
* option. Callers that need folding should render the plain value
|
package/YamlFormat.js
CHANGED
|
@@ -11,7 +11,8 @@ import { Effect, Schema } from "effect";
|
|
|
11
11
|
//#region src/YamlFormat.ts
|
|
12
12
|
/**
|
|
13
13
|
* Options controlling formatting behavior: every {@link YamlStringifyOptions}
|
|
14
|
-
* field (derived, not hand-duplicated — including `indentSequences`
|
|
14
|
+
* field (derived, not hand-duplicated — including `indentSequences` and
|
|
15
|
+
* `quoteStyle`) plus
|
|
15
16
|
* `preserveComments` (default `true`) and `range` (restrict edits to a
|
|
16
17
|
* region; see the module-level remarks on the `range` parameter vs. this
|
|
17
18
|
* field).
|
|
@@ -78,6 +79,7 @@ const toStringifyInput = (options) => options === void 0 ? {} : {
|
|
|
78
79
|
defaultCollectionStyle: options.defaultCollectionStyle,
|
|
79
80
|
sortKeys: options.sortKeys,
|
|
80
81
|
indentSequences: options.indentSequences,
|
|
82
|
+
quoteStyle: options.quoteStyle,
|
|
81
83
|
finalNewline: options.finalNewline,
|
|
82
84
|
forceDefaultStyles: options.forceDefaultStyles
|
|
83
85
|
};
|
|
@@ -251,6 +253,14 @@ var YamlFormat = class YamlFormat {
|
|
|
251
253
|
* `options?.range` when both are given; either accepts a plain
|
|
252
254
|
* `{ offset, length }` object as well as a {@link YamlRange} instance, so
|
|
253
255
|
* callers do not need `YamlRange.make(...)` for the common case.
|
|
256
|
+
*
|
|
257
|
+
* A plain `<<` mapping key is preserved unquoted, keeping its merge-key
|
|
258
|
+
* meaning (`tag:yaml.org,2002:merge`) — quoting it to `'<<'` would produce
|
|
259
|
+
* an ordinary string key that merges nothing, changing what the document
|
|
260
|
+
* means with no error raised. A key the author quoted explicitly keeps its
|
|
261
|
+
* quotes, since that is a literal string key they wrote deliberately. Note
|
|
262
|
+
* that {@link Yaml.stringify} is deliberately the other way round for a
|
|
263
|
+
* `"<<"` key on a plain JavaScript object.
|
|
254
264
|
*/
|
|
255
265
|
static format(text, range, options) {
|
|
256
266
|
const formatted = formatDocument(text, options);
|
package/YamlNode.js
CHANGED
|
@@ -20,6 +20,16 @@ const ScalarStyle = Schema.Literals([
|
|
|
20
20
|
*/
|
|
21
21
|
const CollectionStyle = Schema.Literals(["block", "flow"]);
|
|
22
22
|
/**
|
|
23
|
+
* Quote characters available to the stringifier's plain-scalar fallback: the
|
|
24
|
+
* style a `plain`-styled scalar is rendered in when it turns out to require
|
|
25
|
+
* quoting. Referenced by the `quoteStyle` field of `YamlStringifyOptions`;
|
|
26
|
+
* unlike `ScalarStyle` it is a stringify-option vocabulary, never a property
|
|
27
|
+
* of a composed node.
|
|
28
|
+
*
|
|
29
|
+
* @public
|
|
30
|
+
*/
|
|
31
|
+
const QuoteStyle = Schema.Literals(["single", "double"]);
|
|
32
|
+
/**
|
|
23
33
|
* Block-scalar chomping indicators (`-` strip, default clip, `+` keep).
|
|
24
34
|
* Referenced by the {@link YamlScalar} `chomp` field schema.
|
|
25
35
|
*
|
|
@@ -393,4 +403,4 @@ function nodeToValue(node, anchors, budget, counting = false) {
|
|
|
393
403
|
}
|
|
394
404
|
|
|
395
405
|
//#endregion
|
|
396
|
-
export { AliasExpansionBudgetExceeded, CollectionStyle, ScalarChomp, ScalarStyle, YamlAlias, YamlMap, YamlNode, YamlPair, YamlScalar, YamlSeq, aliasExpansionLimit, nodeToJsValue };
|
|
406
|
+
export { AliasExpansionBudgetExceeded, CollectionStyle, QuoteStyle, ScalarChomp, ScalarStyle, YamlAlias, YamlMap, YamlNode, YamlPair, YamlScalar, YamlSeq, aliasExpansionLimit, nodeToJsValue };
|
package/index.d.ts
CHANGED
|
@@ -151,7 +151,7 @@ declare const YamlStringifyOptions_base: Schema.Class<YamlStringifyOptions, Sche
|
|
|
151
151
|
* (`>`) scalars at approximately that column, never block-literal (`|`).
|
|
152
152
|
*
|
|
153
153
|
* Takes effect only through {@link Yaml.stringify} and
|
|
154
|
-
* {@link Yaml.
|
|
154
|
+
* {@link Yaml.stringifyResult} — the two entry points that accept these
|
|
155
155
|
* options on the value path. The schema factories ({@link Yaml.fromString},
|
|
156
156
|
* {@link Yaml.schema}, {@link Yaml.YamlFromString}) encode with default
|
|
157
157
|
* stringify options (`lineWidth` `0`), so their output never folds. The
|
|
@@ -164,6 +164,17 @@ declare const YamlStringifyOptions_base: Schema.Class<YamlStringifyOptions, Sche
|
|
|
164
164
|
readonly defaultCollectionStyle: Schema.optionalKey<Schema.Literals<readonly ["block", "flow"]>>;
|
|
165
165
|
readonly sortKeys: Schema.optionalKey<Schema.Boolean>;
|
|
166
166
|
readonly indentSequences: Schema.optionalKey<Schema.Boolean>;
|
|
167
|
+
/**
|
|
168
|
+
* Quote style used when a `plain`-styled scalar requires quoting. Default
|
|
169
|
+
* `"single"` — the released byte-compatible behavior. `"double"` renders
|
|
170
|
+
* the same scalars double-quoted instead, matching the `yaml` npm
|
|
171
|
+
* package's `singleQuote: false` output.
|
|
172
|
+
*
|
|
173
|
+
* Affects only the plain fallback: scalars that need no quoting stay
|
|
174
|
+
* plain, and an explicit `defaultScalarStyle` of `"single-quoted"` or
|
|
175
|
+
* `"double-quoted"` is unaffected.
|
|
176
|
+
*/
|
|
177
|
+
readonly quoteStyle: Schema.optionalKey<Schema.Literals<readonly ["single", "double"]>>;
|
|
167
178
|
readonly finalNewline: Schema.optionalKey<Schema.Boolean>;
|
|
168
179
|
readonly forceDefaultStyles: Schema.optionalKey<Schema.Boolean>;
|
|
169
180
|
}>, {}>;
|
|
@@ -171,8 +182,8 @@ declare const YamlStringifyOptions_base: Schema.Class<YamlStringifyOptions, Sche
|
|
|
171
182
|
* Options controlling stringify behavior. All fields are omissible; absent
|
|
172
183
|
* fields resolve to `indent` `2`, `lineWidth` `0`, `defaultScalarStyle`
|
|
173
184
|
* `"plain"`, `defaultCollectionStyle` `"block"`, `sortKeys` `false`,
|
|
174
|
-
* `indentSequences` `false`, `
|
|
175
|
-
* `false`.
|
|
185
|
+
* `indentSequences` `false`, `quoteStyle` `"single"`, `finalNewline` `true`
|
|
186
|
+
* and `forceDefaultStyles` `false`.
|
|
176
187
|
*
|
|
177
188
|
* `lineWidth` controls column-based scalar folding. The default `0` (and any
|
|
178
189
|
* value `<= 0`) never wraps, emitting byte-identical output to the historic
|
|
@@ -189,6 +200,18 @@ declare const YamlStringifyOptions_base: Schema.Class<YamlStringifyOptions, Sche
|
|
|
189
200
|
* matching the `yaml` npm package's default output. Top-level sequences stay
|
|
190
201
|
* at column zero in both modes.
|
|
191
202
|
*
|
|
203
|
+
* `quoteStyle` selects the quote character used when a `plain`-styled scalar
|
|
204
|
+
* (the `defaultScalarStyle` default) turns out to require quoting: `"single"`
|
|
205
|
+
* (the default) emits `'@parcel/watcher'` — the kit's byte-compatible legacy
|
|
206
|
+
* form — while `"double"` emits `"@parcel/watcher"`, matching the `yaml` npm
|
|
207
|
+
* package's `singleQuote: false` output. It is a fallback selector only:
|
|
208
|
+
* scalars that need no quoting stay plain, and an explicit
|
|
209
|
+
* `defaultScalarStyle` of `"single-quoted"` or `"double-quoted"` still wins.
|
|
210
|
+
* On that plain fallback path, values carrying a tab, a carriage return or
|
|
211
|
+
* any other C0 control character are always emitted double-quoted whichever
|
|
212
|
+
* `quoteStyle` is set, since only double quotes can escape them into a form
|
|
213
|
+
* that round-trips exactly.
|
|
214
|
+
*
|
|
192
215
|
* Construct with the validated `YamlStringifyOptions.make({ ... })` static —
|
|
193
216
|
* the kit convention (never `new`). Call sites that take a
|
|
194
217
|
* `YamlStringifyOptions` also accept a structurally-matching plain literal.
|
|
@@ -289,6 +312,9 @@ declare class Yaml {
|
|
|
289
312
|
* resolved size grows exponentially relative to `maxAliasCount`) also
|
|
290
313
|
* fails through {@link YamlParseError} with an `AliasCountExceeded`
|
|
291
314
|
* diagnostic, never as an unhandled defect.
|
|
315
|
+
*
|
|
316
|
+
* Defined in terms of {@link Yaml.parseResult} — synchronous callers can
|
|
317
|
+
* use that variant directly.
|
|
292
318
|
*/
|
|
293
319
|
static readonly parse: (text: string, options?: YamlParseOptions | undefined) => Effect.Effect<unknown, YamlParseError, never>;
|
|
294
320
|
/**
|
|
@@ -308,13 +334,28 @@ declare class Yaml {
|
|
|
308
334
|
* or on a value nested deeper than the stringifier's recursion budget
|
|
309
335
|
* (`NestingDepthExceeded`) — both surface through the typed error channel
|
|
310
336
|
* rather than as an unhandled stack-overflow defect.
|
|
337
|
+
*
|
|
338
|
+
* @remarks
|
|
339
|
+
* A `"<<"` object key is emitted **quoted** (`'<<': …`). This is the
|
|
340
|
+
* opposite of the document path ({@link YamlFormat.format} and
|
|
341
|
+
* `YamlDocument#stringify`), which leaves a parsed plain `<<` key unquoted
|
|
342
|
+
* so it keeps its merge-key meaning, and the asymmetry is deliberate: a
|
|
343
|
+
* `"<<"` key on a plain JavaScript object is an ordinary string key that
|
|
344
|
+
* never carried merge semantics, so emitting it plain would silently turn
|
|
345
|
+
* ordinary data into a merge directive.
|
|
311
346
|
*/
|
|
312
347
|
static readonly stringify: (value: unknown, options?: YamlStringifyOptions | undefined) => Effect.Effect<string, YamlStringifyError, never>;
|
|
313
348
|
/**
|
|
314
349
|
* Synchronous single-document parse, returning a `Result` instead of
|
|
315
350
|
* an `Effect`. A pure escape hatch for config-time callers that cannot
|
|
316
|
-
* `await` an Effect (a `vitest.config.ts` is the motivating case)
|
|
317
|
-
*
|
|
351
|
+
* `await` an Effect (a `vitest.config.ts` is the motivating case).
|
|
352
|
+
*
|
|
353
|
+
* @remarks
|
|
354
|
+
* This is the package's single parse path. {@link Yaml.parse} is defined in
|
|
355
|
+
* terms of it (`Effect.fromResult` behind the named span), so the two
|
|
356
|
+
* variants cannot diverge. Reach for the `Effect` variant inside Effect
|
|
357
|
+
* code — it carries the `Yaml.parse` tracing span — and for this one at
|
|
358
|
+
* synchronous boundaries.
|
|
318
359
|
*
|
|
319
360
|
* Preserves the package contract — malformed and adversarial input fails
|
|
320
361
|
* typed, never as a defect. Fatal diagnostics, duplicate keys and a
|
|
@@ -326,7 +367,7 @@ declare class Yaml {
|
|
|
326
367
|
* import { Yaml } from "@effected/yaml";
|
|
327
368
|
* import { Result } from "effect";
|
|
328
369
|
*
|
|
329
|
-
* const result = Yaml.
|
|
370
|
+
* const result = Yaml.parseResult("name: Alice\nage: 30");
|
|
330
371
|
* if (Result.isSuccess(result)) {
|
|
331
372
|
* result.success; // { name: "Alice", age: 30 }
|
|
332
373
|
* } else {
|
|
@@ -336,7 +377,7 @@ declare class Yaml {
|
|
|
336
377
|
*
|
|
337
378
|
* @public
|
|
338
379
|
*/
|
|
339
|
-
static
|
|
380
|
+
static parseResult(text: string, options?: YamlParseOptions): Result.Result<unknown, YamlParseError>;
|
|
340
381
|
/**
|
|
341
382
|
* Synchronous stringify, returning a `Result` instead of an `Effect`.
|
|
342
383
|
* The pure counterpart to {@link Yaml.stringify} for config-time callers
|
|
@@ -352,7 +393,7 @@ declare class Yaml {
|
|
|
352
393
|
* import { Yaml } from "@effected/yaml";
|
|
353
394
|
* import { Result } from "effect";
|
|
354
395
|
*
|
|
355
|
-
* const result = Yaml.
|
|
396
|
+
* const result = Yaml.stringifyResult({ name: "Alice" });
|
|
356
397
|
* if (Result.isFailure(result)) {
|
|
357
398
|
* result.failure; // YamlStringifyError
|
|
358
399
|
* } else {
|
|
@@ -362,7 +403,7 @@ declare class Yaml {
|
|
|
362
403
|
*
|
|
363
404
|
* @public
|
|
364
405
|
*/
|
|
365
|
-
static
|
|
406
|
+
static stringifyResult(value: unknown, options?: YamlStringifyOptions): Result.Result<string, YamlStringifyError>;
|
|
366
407
|
/**
|
|
367
408
|
* Strip comments from YAML text. Without `replaceCh`, comment characters
|
|
368
409
|
* are removed (line breaks are kept, so line numbers stay stable); with a
|
|
@@ -538,6 +579,22 @@ declare const CollectionStyle: Schema.Literals<readonly ["block", "flow"]>;
|
|
|
538
579
|
* @public
|
|
539
580
|
*/
|
|
540
581
|
type CollectionStyle = typeof CollectionStyle.Type;
|
|
582
|
+
/**
|
|
583
|
+
* Quote characters available to the stringifier's plain-scalar fallback: the
|
|
584
|
+
* style a `plain`-styled scalar is rendered in when it turns out to require
|
|
585
|
+
* quoting. Referenced by the `quoteStyle` field of `YamlStringifyOptions`;
|
|
586
|
+
* unlike `ScalarStyle` it is a stringify-option vocabulary, never a property
|
|
587
|
+
* of a composed node.
|
|
588
|
+
*
|
|
589
|
+
* @public
|
|
590
|
+
*/
|
|
591
|
+
declare const QuoteStyle: Schema.Literals<readonly ["single", "double"]>;
|
|
592
|
+
/**
|
|
593
|
+
* The union of all fallback quote style string literals.
|
|
594
|
+
*
|
|
595
|
+
* @public
|
|
596
|
+
*/
|
|
597
|
+
type QuoteStyle = typeof QuoteStyle.Type;
|
|
541
598
|
/**
|
|
542
599
|
* Block-scalar chomping indicators (`-` strip, default clip, `+` keep).
|
|
543
600
|
* Referenced by the {@link YamlScalar} `chomp` field schema.
|
|
@@ -791,7 +848,7 @@ declare class YamlDocument extends YamlDocument_base {
|
|
|
791
848
|
* `YamlStringifyOptions.lineWidth` is not honored here: column-based
|
|
792
849
|
* scalar folding exists only on the value path, through the entry points
|
|
793
850
|
* that accept stringify options ({@link Yaml.stringify} and
|
|
794
|
-
* {@link Yaml.
|
|
851
|
+
* {@link Yaml.stringifyResult}). The
|
|
795
852
|
* document/node path threads `lineWidth` into its render context but
|
|
796
853
|
* never reads it, so long scalars are emitted unfolded regardless of the
|
|
797
854
|
* option. Callers that need folding should render the plain value
|
|
@@ -826,6 +883,7 @@ declare const YamlFormattingOptions_base: Schema.Class<YamlFormattingOptions, Sc
|
|
|
826
883
|
readonly defaultCollectionStyle: Schema.optionalKey<Schema.Literals<readonly ["block", "flow"]>>;
|
|
827
884
|
readonly sortKeys: Schema.optionalKey<Schema.Boolean>;
|
|
828
885
|
readonly indentSequences: Schema.optionalKey<Schema.Boolean>;
|
|
886
|
+
readonly quoteStyle: Schema.optionalKey<Schema.Literals<readonly ["single", "double"]>>;
|
|
829
887
|
readonly finalNewline: Schema.optionalKey<Schema.Boolean>;
|
|
830
888
|
readonly forceDefaultStyles: Schema.optionalKey<Schema.Boolean>;
|
|
831
889
|
readonly preserveComments: Schema.optionalKey<Schema.Boolean>;
|
|
@@ -833,7 +891,8 @@ declare const YamlFormattingOptions_base: Schema.Class<YamlFormattingOptions, Sc
|
|
|
833
891
|
}>, {}>;
|
|
834
892
|
/**
|
|
835
893
|
* Options controlling formatting behavior: every {@link YamlStringifyOptions}
|
|
836
|
-
* field (derived, not hand-duplicated — including `indentSequences`
|
|
894
|
+
* field (derived, not hand-duplicated — including `indentSequences` and
|
|
895
|
+
* `quoteStyle`) plus
|
|
837
896
|
* `preserveComments` (default `true`) and `range` (restrict edits to a
|
|
838
897
|
* region; see the module-level remarks on the `range` parameter vs. this
|
|
839
898
|
* field).
|
|
@@ -898,6 +957,14 @@ declare class YamlFormat {
|
|
|
898
957
|
* `options?.range` when both are given; either accepts a plain
|
|
899
958
|
* `{ offset, length }` object as well as a {@link YamlRange} instance, so
|
|
900
959
|
* callers do not need `YamlRange.make(...)` for the common case.
|
|
960
|
+
*
|
|
961
|
+
* A plain `<<` mapping key is preserved unquoted, keeping its merge-key
|
|
962
|
+
* meaning (`tag:yaml.org,2002:merge`) — quoting it to `'<<'` would produce
|
|
963
|
+
* an ordinary string key that merges nothing, changing what the document
|
|
964
|
+
* means with no error raised. A key the author quoted explicitly keeps its
|
|
965
|
+
* quotes, since that is a literal string key they wrote deliberately. Note
|
|
966
|
+
* that {@link Yaml.stringify} is deliberately the other way round for a
|
|
967
|
+
* `"<<"` key on a plain JavaScript object.
|
|
901
968
|
*/
|
|
902
969
|
static format(text: string, range?: YamlRangeLike, options?: YamlFormattingOptions): ReadonlyArray<YamlEdit>;
|
|
903
970
|
/**
|
|
@@ -1521,5 +1588,5 @@ declare class YamlVisitor {
|
|
|
1521
1588
|
static visit(text: string, options?: YamlParseOptions): Stream.Stream<YamlVisitorEvent>;
|
|
1522
1589
|
}
|
|
1523
1590
|
//#endregion
|
|
1524
|
-
export { CollectionStyle, ScalarChomp, ScalarStyle, Yaml, YamlAlias, type YamlBoundCodec, YamlComposerErrorCode, YamlDiagnostic, YamlDirective, YamlDocument, YamlEdit, YamlErrorCode, YamlFormat, YamlFormattingOptions, YamlLexErrorCode, YamlMap, YamlModificationError, YamlModifyErrorCode, YamlNode, YamlPair, YamlParseError, YamlParseErrorCode, YamlParseOptions, type YamlPath, YamlRange, type YamlRangeLike, YamlScalar, type YamlSegment, YamlSeq, YamlStringifyError, YamlStringifyErrorCode, YamlStringifyOptions, YamlVisitor, YamlVisitorEvent };
|
|
1591
|
+
export { CollectionStyle, QuoteStyle, ScalarChomp, ScalarStyle, Yaml, YamlAlias, type YamlBoundCodec, YamlComposerErrorCode, YamlDiagnostic, YamlDirective, YamlDocument, YamlEdit, YamlErrorCode, YamlFormat, YamlFormattingOptions, YamlLexErrorCode, YamlMap, YamlModificationError, YamlModifyErrorCode, YamlNode, YamlPair, YamlParseError, YamlParseErrorCode, YamlParseOptions, type YamlPath, YamlRange, type YamlRangeLike, YamlScalar, type YamlSegment, YamlSeq, YamlStringifyError, YamlStringifyErrorCode, YamlStringifyOptions, YamlVisitor, YamlVisitorEvent };
|
|
1525
1592
|
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CollectionStyle, ScalarChomp, ScalarStyle, YamlAlias, YamlMap, YamlNode, YamlPair, YamlScalar, YamlSeq } from "./YamlNode.js";
|
|
1
|
+
import { CollectionStyle, QuoteStyle, ScalarChomp, ScalarStyle, YamlAlias, YamlMap, YamlNode, YamlPair, YamlScalar, YamlSeq } from "./YamlNode.js";
|
|
2
2
|
import { YamlComposerErrorCode, YamlDiagnostic, YamlErrorCode, YamlLexErrorCode, YamlModifyErrorCode, YamlParseErrorCode, YamlStringifyErrorCode } from "./YamlDiagnostic.js";
|
|
3
3
|
import { Yaml, YamlParseError, YamlParseOptions, YamlStringifyError, YamlStringifyOptions } from "./Yaml.js";
|
|
4
4
|
import { YamlDirective, YamlDocument } from "./YamlDocument.js";
|
|
@@ -6,4 +6,4 @@ import { YamlEdit, YamlRange } from "./YamlEdit.js";
|
|
|
6
6
|
import { YamlFormat, YamlFormattingOptions, YamlModificationError } from "./YamlFormat.js";
|
|
7
7
|
import { YamlVisitor, YamlVisitorEvent } from "./YamlVisitor.js";
|
|
8
8
|
|
|
9
|
-
export { CollectionStyle, ScalarChomp, ScalarStyle, Yaml, YamlAlias, YamlComposerErrorCode, YamlDiagnostic, YamlDirective, YamlDocument, YamlEdit, YamlErrorCode, YamlFormat, YamlFormattingOptions, YamlLexErrorCode, YamlMap, YamlModificationError, YamlModifyErrorCode, YamlNode, YamlPair, YamlParseError, YamlParseErrorCode, YamlParseOptions, YamlRange, YamlScalar, YamlSeq, YamlStringifyError, YamlStringifyErrorCode, YamlStringifyOptions, YamlVisitor, YamlVisitorEvent };
|
|
9
|
+
export { CollectionStyle, QuoteStyle, ScalarChomp, ScalarStyle, Yaml, YamlAlias, YamlComposerErrorCode, YamlDiagnostic, YamlDirective, YamlDocument, YamlEdit, YamlErrorCode, YamlFormat, YamlFormattingOptions, YamlLexErrorCode, YamlMap, YamlModificationError, YamlModifyErrorCode, YamlNode, YamlPair, YamlParseError, YamlParseErrorCode, YamlParseOptions, YamlRange, YamlScalar, YamlSeq, YamlStringifyError, YamlStringifyErrorCode, YamlStringifyOptions, YamlVisitor, YamlVisitorEvent };
|
package/internal/stringifier.js
CHANGED
|
@@ -107,7 +107,10 @@ function requiresQuoting(s, ignoreType = false) {
|
|
|
107
107
|
if (s.includes(" #") || s.includes(" #")) return true;
|
|
108
108
|
const last = s[s.length - 1];
|
|
109
109
|
if (last === " " || last === " ") return true;
|
|
110
|
-
for (let i = 0; i < s.length; i++)
|
|
110
|
+
for (let i = 0; i < s.length; i++) {
|
|
111
|
+
const code = s.charCodeAt(i);
|
|
112
|
+
if (code === 9 || code === 13 || isControlChar(code)) return true;
|
|
113
|
+
}
|
|
111
114
|
return false;
|
|
112
115
|
}
|
|
113
116
|
/**
|
|
@@ -164,11 +167,13 @@ function renderSingleQuoted(s) {
|
|
|
164
167
|
*
|
|
165
168
|
* Multi-line strings are routed to block styles regardless of the requested
|
|
166
169
|
* style (except double-quoted). For single-line strings, plain style delegates
|
|
167
|
-
* to {@link requiresQuoting} and falls back to
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
+
* to {@link requiresQuoting} and falls back to `quoteStyle` (single-quoted by
|
|
171
|
+
* default, double-quoted when the caller asked for it) — or to double-quoted
|
|
172
|
+
* regardless when the value needs YAML escapes single quotes cannot express.
|
|
173
|
+
* Block literal and block folded styles are always accepted for single-line
|
|
174
|
+
* strings even though the output is unusual.
|
|
170
175
|
*/
|
|
171
|
-
function renderString(s, style, indent, ignoreType = false, canonical = false, explicitChomp, parentPosition) {
|
|
176
|
+
function renderString(s, style, indent, ignoreType = false, canonical = false, explicitChomp, parentPosition, quoteStyle = "single") {
|
|
172
177
|
if (s.includes("\n")) {
|
|
173
178
|
let hasControl = false;
|
|
174
179
|
for (let i = 0; i < s.length; i++) {
|
|
@@ -202,7 +207,7 @@ function renderString(s, style, indent, ignoreType = false, canonical = false, e
|
|
|
202
207
|
if (requiresQuoting(s, ignoreType)) {
|
|
203
208
|
if (s.includes(" ") || s.includes("\r")) return renderDoubleQuoted(s, canonical);
|
|
204
209
|
for (let i = 0; i < s.length; i++) if (isControlChar(s.charCodeAt(i))) return renderDoubleQuoted(s, canonical);
|
|
205
|
-
return renderSingleQuoted(s);
|
|
210
|
+
return quoteStyle === "double" ? renderDoubleQuoted(s, canonical) : renderSingleQuoted(s);
|
|
206
211
|
}
|
|
207
212
|
return s;
|
|
208
213
|
case "single-quoted": return renderSingleQuoted(s);
|
|
@@ -257,6 +262,7 @@ function createContext(options) {
|
|
|
257
262
|
defaultCollectionStyle: options?.defaultCollectionStyle ?? "block",
|
|
258
263
|
sortKeys: options?.sortKeys ?? false,
|
|
259
264
|
indentSequences: options?.indentSequences ?? false,
|
|
265
|
+
quoteStyle: options?.quoteStyle ?? "single",
|
|
260
266
|
forceDefaultStyles: options?.forceDefaultStyles ?? false,
|
|
261
267
|
seen: /* @__PURE__ */ new Set()
|
|
262
268
|
};
|
|
@@ -276,7 +282,7 @@ function stringifyLines(value, ctx, depth, allowFold = true) {
|
|
|
276
282
|
if (typeof value === "bigint") return [value.toString()];
|
|
277
283
|
if (typeof value === "string") {
|
|
278
284
|
const indentStr = " ".repeat(ctx.indent);
|
|
279
|
-
const rendered = renderString(value, ctx.defaultScalarStyle, indentStr, false, ctx.forceDefaultStyles);
|
|
285
|
+
const rendered = renderString(value, ctx.defaultScalarStyle, indentStr, false, ctx.forceDefaultStyles, void 0, void 0, ctx.quoteStyle);
|
|
280
286
|
return (allowFold && ctx.lineWidth > 0 ? foldRenderedScalar(rendered, indentStr, ctx.lineWidth) : rendered).split("\n");
|
|
281
287
|
}
|
|
282
288
|
if (Array.isArray(value)) {
|
|
@@ -341,10 +347,11 @@ function stringifyObjectLines(obj, ctx, depth) {
|
|
|
341
347
|
const keys = Object.keys(obj);
|
|
342
348
|
if (keys.length === 0) return ["{}"];
|
|
343
349
|
if (ctx.sortKeys) keys.sort();
|
|
350
|
+
const renderPlainKey = (k) => renderString(k, "plain", "", false, false, void 0, void 0, ctx.quoteStyle);
|
|
344
351
|
if (ctx.defaultCollectionStyle === "flow") return [`{${keys.map((k) => {
|
|
345
|
-
return `${
|
|
352
|
+
return `${renderPlainKey(k)}: ${stringifyLines(obj[k], ctx, depth + 1, false).join(" ")}`;
|
|
346
353
|
}).join(", ")}}`];
|
|
347
|
-
const renderKey = (k) => k.includes("\n") ? renderDoubleQuoted(k, ctx.forceDefaultStyles) :
|
|
354
|
+
const renderKey = (k) => k.includes("\n") ? renderDoubleQuoted(k, ctx.forceDefaultStyles) : renderPlainKey(k);
|
|
348
355
|
const pad = " ".repeat(ctx.indent);
|
|
349
356
|
const lines = [];
|
|
350
357
|
for (const k of keys) {
|
|
@@ -531,12 +538,45 @@ function stringifyScalarNodeLines(node, ctx) {
|
|
|
531
538
|
else lines = ["null"];
|
|
532
539
|
else if (typeof val === "boolean") lines = [val ? "true" : "false"];
|
|
533
540
|
else if (typeof val === "number") lines = [node.raw !== void 0 ? node.raw : renderNumber(val)];
|
|
534
|
-
else if (typeof val === "string") lines = renderString(val, style, " ".repeat(ctx.indent), !!node.tag, ctx.forceDefaultStyles, node.chomp, ctx.parentPosition).split("\n");
|
|
541
|
+
else if (typeof val === "string") lines = renderString(val, style, " ".repeat(ctx.indent), !!node.tag, ctx.forceDefaultStyles, node.chomp, ctx.parentPosition, ctx.quoteStyle).split("\n");
|
|
535
542
|
else lines = [renderDoubleQuoted(String(val))];
|
|
536
543
|
if (node.tag) lines[0] = `${node.tag} ${lines[0]}`;
|
|
537
544
|
if (node.anchor) lines[0] = `&${node.anchor} ${lines[0]}`;
|
|
538
545
|
return lines;
|
|
539
546
|
}
|
|
547
|
+
/** The YAML merge key. */
|
|
548
|
+
const MERGE_KEY = "<<";
|
|
549
|
+
/**
|
|
550
|
+
* True when a mapping key must be emitted plain because quoting it would
|
|
551
|
+
* change what the document means.
|
|
552
|
+
*
|
|
553
|
+
* The merge key is the only scalar in this position where the plain and
|
|
554
|
+
* quoted forms resolve to different YAML types: a plain `<<` key resolves to
|
|
555
|
+
* `tag:yaml.org,2002:merge` and splices the aliased mapping into its parent,
|
|
556
|
+
* while `'<<'` is an ordinary string key that merges nothing. The difference
|
|
557
|
+
* is silent — the document still parses and still round-trips — so re-emitting
|
|
558
|
+
* a merge key quoted is a semantic rewrite of the kind the fidelity obligation
|
|
559
|
+
* forbids.
|
|
560
|
+
*
|
|
561
|
+
* Deliberately narrow. It fires only on a plain-styled scalar carrying no tag
|
|
562
|
+
* and no anchor, so an author's explicitly quoted `'<<'` (a literal string key
|
|
563
|
+
* they meant) and any tagged key keep the form they were written in. A key
|
|
564
|
+
* with no style at all counts as plain: an unstyled `<<` built by hand can
|
|
565
|
+
* only have been meant as a merge key, and preserving that meaning outranks
|
|
566
|
+
* normalizing its presentation.
|
|
567
|
+
*/
|
|
568
|
+
function isPlainMergeKey(node) {
|
|
569
|
+
return node instanceof YamlScalar && node.value === MERGE_KEY && (node.style ?? "plain") === "plain" && node.tag === void 0 && node.anchor === void 0;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Renders a mapping key, honoring the keys that must stay plain before
|
|
573
|
+
* falling back to ordinary node rendering. Both the flow and the block
|
|
574
|
+
* mapping branches route through here so the two cannot disagree.
|
|
575
|
+
*/
|
|
576
|
+
function stringifyMappingKeyLines(node, ctx, depth) {
|
|
577
|
+
if (isPlainMergeKey(node)) return [MERGE_KEY];
|
|
578
|
+
return stringifyNodeLines(node, ctx, depth);
|
|
579
|
+
}
|
|
540
580
|
/**
|
|
541
581
|
* Stringifies a YamlMap node into lines, using the node's collection style.
|
|
542
582
|
*/
|
|
@@ -556,7 +596,7 @@ function stringifyMapNodeLines(node, ctx, depth) {
|
|
|
556
596
|
}
|
|
557
597
|
if (style === "flow") {
|
|
558
598
|
let line = `{${items.map((pair) => {
|
|
559
|
-
return `${pair.key ?
|
|
599
|
+
return `${pair.key ? stringifyMappingKeyLines(pair.key, ctx, depth + 1).join(" ") : "null"}: ${pair.value ? stringifyNodeLines(pair.value, ctx, depth + 1).join(" ") : "null"}`;
|
|
560
600
|
}).join(", ")}}`;
|
|
561
601
|
const flowPrefix = buildMetadataPrefix(node.tag, node.anchor);
|
|
562
602
|
if (flowPrefix) line = `${flowPrefix} ${line}`;
|
|
@@ -603,7 +643,7 @@ function stringifyMapNodeLines(node, ctx, depth) {
|
|
|
603
643
|
}
|
|
604
644
|
let resolvedKeyStr;
|
|
605
645
|
if (ctx.forceDefaultStyles && node.style === "flow" && node.sourceMultiline !== true && pair.key instanceof YamlScalar && (pair.key.style === "single-quoted" || pair.key.style === "double-quoted") && typeof pair.key.value === "string" && /^[A-Za-z_][A-Za-z0-9_]*$/.test(pair.key.value)) resolvedKeyStr = pair.key.value;
|
|
606
|
-
else resolvedKeyStr = pair.key ?
|
|
646
|
+
else resolvedKeyStr = pair.key ? stringifyMappingKeyLines(pair.key, ctx, depth + 1).join(" ") : "null";
|
|
607
647
|
const keyStr = resolvedKeyStr;
|
|
608
648
|
const keyIsAnchoredOrTaggedEmpty = pair.key instanceof YamlScalar && pair.key.length === 0 && (pair.key.value === null || pair.key.value === void 0 || pair.key.value === "") && (pair.key.anchor !== void 0 || pair.key.tag !== void 0);
|
|
609
649
|
const sep = pair.key instanceof YamlAlias || keyIsAnchoredOrTaggedEmpty ? " :" : ":";
|