@effected/yaml 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -7
- package/Yaml.js +80 -32
- package/YamlDocument.js +23 -2
- package/YamlFormat.js +162 -21
- package/YamlLint.js +239 -0
- package/YamlLintRule.js +36 -0
- package/YamlNode.js +43 -4
- package/YamlToken.js +139 -0
- package/YamlVisitor.js +52 -16
- package/index.d.ts +446 -12
- package/index.js +4 -1
- package/internal/composer/anchors.js +2 -27
- package/internal/composer/block.js +291 -67
- package/internal/composer/comments.js +217 -0
- package/internal/composer/document.js +141 -14
- package/internal/composer/flow.js +103 -10
- package/internal/composer/scalars.js +48 -11
- package/internal/composer/state.js +16 -2
- package/internal/cst-parser.js +2 -1
- package/internal/diagnostics.js +12 -3
- package/internal/fold.js +22 -10
- package/internal/rules/catalog.js +39 -0
- package/internal/rules/colon-spacing.js +77 -0
- package/internal/rules/comments-spacing.js +68 -0
- package/internal/rules/document-end.js +65 -0
- package/internal/rules/document-start.js +64 -0
- package/internal/rules/empty-lines.js +70 -0
- package/internal/rules/eof-newline.js +33 -0
- package/internal/rules/hyphen-spacing.js +52 -0
- package/internal/rules/indentation.js +103 -0
- package/internal/rules/key-duplicates.js +49 -0
- package/internal/rules/line-length.js +36 -0
- package/internal/rules/parse-validity.js +33 -0
- package/internal/rules/quoted-strings.js +81 -0
- package/internal/rules/trailing-spaces.js +39 -0
- package/internal/rules/truthy.js +84 -0
- package/internal/rules/util.js +92 -0
- package/internal/stringifier.js +342 -54
- package/package.json +3 -2
package/index.js
CHANGED
|
@@ -4,6 +4,9 @@ import { Yaml, YamlParseError, YamlParseOptions, YamlStringifyError, YamlStringi
|
|
|
4
4
|
import { YamlDirective, YamlDocument } from "./YamlDocument.js";
|
|
5
5
|
import { YamlEdit, YamlRange } from "./YamlEdit.js";
|
|
6
6
|
import { YamlFormat, YamlFormattingOptions, YamlModificationError } from "./YamlFormat.js";
|
|
7
|
+
import { YamlLintDiagnostic, YamlLintSeverity } from "./YamlLintRule.js";
|
|
8
|
+
import { YamlToken, YamlTokenKind, YamlTokens } from "./YamlToken.js";
|
|
9
|
+
import { YamlLint, YamlLintConfig, YamlLintRuleSetting } from "./YamlLint.js";
|
|
7
10
|
import { YamlVisitor, YamlVisitorEvent } from "./YamlVisitor.js";
|
|
8
11
|
|
|
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 };
|
|
12
|
+
export { CollectionStyle, QuoteStyle, ScalarChomp, ScalarStyle, Yaml, YamlAlias, YamlComposerErrorCode, YamlDiagnostic, YamlDirective, YamlDocument, YamlEdit, YamlErrorCode, YamlFormat, YamlFormattingOptions, YamlLexErrorCode, YamlLint, YamlLintConfig, YamlLintDiagnostic, YamlLintRuleSetting, YamlLintSeverity, YamlMap, YamlModificationError, YamlModifyErrorCode, YamlNode, YamlPair, YamlParseError, YamlParseErrorCode, YamlParseOptions, YamlRange, YamlScalar, YamlSeq, YamlStringifyError, YamlStringifyErrorCode, YamlStringifyOptions, YamlToken, YamlTokenKind, YamlTokens, YamlVisitor, YamlVisitorEvent };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { YamlAlias
|
|
1
|
+
import { YamlAlias } from "../../YamlNode.js";
|
|
2
2
|
|
|
3
3
|
//#region src/internal/composer/anchors.ts
|
|
4
4
|
/**
|
|
@@ -67,31 +67,6 @@ function scanName(text, start) {
|
|
|
67
67
|
}
|
|
68
68
|
return text.slice(start, end);
|
|
69
69
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Build an anchor map by walking the AST, collecting nodes that have anchors.
|
|
72
|
-
* Used to resolve aliases when extracting plain JavaScript values from
|
|
73
|
-
* parsed YAML documents.
|
|
74
|
-
*/
|
|
75
|
-
function buildAnchorMap(node) {
|
|
76
|
-
const anchors = /* @__PURE__ */ new Map();
|
|
77
|
-
collectAnchors(node, anchors);
|
|
78
|
-
return anchors;
|
|
79
|
-
}
|
|
80
|
-
function collectAnchors(node, anchors) {
|
|
81
|
-
if (node === null) return;
|
|
82
|
-
if (node instanceof YamlScalar) {
|
|
83
|
-
if (node.anchor !== void 0) anchors.set(node.anchor, node);
|
|
84
|
-
} else if (node instanceof YamlMap) {
|
|
85
|
-
if (node.anchor !== void 0) anchors.set(node.anchor, node);
|
|
86
|
-
for (const pair of node.items) {
|
|
87
|
-
collectAnchors(pair.key, anchors);
|
|
88
|
-
collectAnchors(pair.value, anchors);
|
|
89
|
-
}
|
|
90
|
-
} else if (node instanceof YamlSeq) {
|
|
91
|
-
if (node.anchor !== void 0) anchors.set(node.anchor, node);
|
|
92
|
-
for (const item of node.items) collectAnchors(item, anchors);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
70
|
|
|
96
71
|
//#endregion
|
|
97
|
-
export {
|
|
72
|
+
export { checkAnchorOnAlias, getAliasName, getAnchorName, makeAlias, registerAnchor, scanName };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { YamlMap, YamlPair, YamlScalar, YamlSeq } from "../../YamlNode.js";
|
|
1
|
+
import { YamlAlias, YamlMap, YamlPair, YamlScalar, YamlSeq } from "../../YamlNode.js";
|
|
2
2
|
import { checkAnchorOnAlias, getAnchorName, makeAlias, registerAnchor } from "./anchors.js";
|
|
3
|
+
import { blankAboveIsKeepChompContent, columnAt, hasBlankLineAbove, isAfterIndicatorOnly, isOwnLineAt, joinComments, rawCommentText, sameLineSpan, withCommentFields } from "./comments.js";
|
|
3
4
|
import { enterNesting, exitNesting, hasMeta, hasNonWhitespaceBeforeOnLine, lineCol, lineIndentColumn, sameLine } from "./state.js";
|
|
4
5
|
import { blockMapStartsWithValueSep, classifyPlainNumeric, collectMultilineKey, collectMultilinePlainScalar, findFirstContent, findLastContent, findNextContentInList, findNextSignificantChild, findValueSepOffset, getScalarStyle, hasValueSepAfterInList, hasValueSepBetween, hasValueSepThroughPlainScalars, makeScalar, resolveScalar, shouldPreserveRaw } from "./scalars.js";
|
|
5
6
|
|
|
@@ -35,11 +36,12 @@ function composeBlockMapInner(blockMapCst, state, externalFirstKey, meta) {
|
|
|
35
36
|
kind: "key",
|
|
36
37
|
node: externalFirstKey
|
|
37
38
|
});
|
|
38
|
-
buildPairs(items, pairs, state.text);
|
|
39
|
+
const trailingComment = buildPairs(items, pairs, state.text, state.escapedComments);
|
|
39
40
|
if (state.options.uniqueKeys) checkDuplicateKeys(pairs, state);
|
|
40
41
|
checkMultilineImplicitKeys(pairs, state);
|
|
41
42
|
const offset = externalFirstKey ? "offset" in externalFirstKey ? externalFirstKey.offset : blockMapCst.offset : blockMapCst.offset;
|
|
42
43
|
const length = blockMapCst.offset + blockMapCst.length - offset;
|
|
44
|
+
const mapComment = meta?.comment !== void 0 ? trailingComment !== void 0 ? `${meta.comment}\n${trailingComment}` : meta.comment : trailingComment;
|
|
43
45
|
const map = new YamlMap({
|
|
44
46
|
items: pairs,
|
|
45
47
|
style: "block",
|
|
@@ -47,7 +49,7 @@ function composeBlockMapInner(blockMapCst, state, externalFirstKey, meta) {
|
|
|
47
49
|
length,
|
|
48
50
|
...meta?.tag !== void 0 ? { tag: meta.tag } : {},
|
|
49
51
|
...meta?.anchor !== void 0 ? { anchor: meta.anchor } : {},
|
|
50
|
-
...
|
|
52
|
+
...mapComment !== void 0 ? { comment: mapComment } : {}
|
|
51
53
|
});
|
|
52
54
|
if (meta?.anchor) registerAnchor(map, meta.anchor, state, offset);
|
|
53
55
|
return map;
|
|
@@ -104,6 +106,14 @@ function flattenBlockMapChildren(children, state, externalKeyColumn, externalKey
|
|
|
104
106
|
kind: "node",
|
|
105
107
|
node
|
|
106
108
|
});
|
|
109
|
+
if (state.escapedComments.length > 0) {
|
|
110
|
+
for (const ec of state.escapedComments) items.push({
|
|
111
|
+
kind: "comment",
|
|
112
|
+
comment: ec.text,
|
|
113
|
+
offset: ec.offset
|
|
114
|
+
});
|
|
115
|
+
state.escapedComments.length = 0;
|
|
116
|
+
}
|
|
107
117
|
afterValueSep = false;
|
|
108
118
|
}
|
|
109
119
|
for (let i = 0; i < children.length; i++) {
|
|
@@ -132,7 +142,7 @@ function flattenBlockMapChildren(children, state, externalKeyColumn, externalKey
|
|
|
132
142
|
const sliceChildren = children.slice(i + 1, lookahead.endIdx);
|
|
133
143
|
const innerItems = flattenBlockMapChildren(sliceChildren, state);
|
|
134
144
|
const innerPairs = [];
|
|
135
|
-
buildPairs(innerItems, innerPairs, state.text);
|
|
145
|
+
const innerTrailing = buildPairs(innerItems, innerPairs, state.text);
|
|
136
146
|
const firstC = findFirstContent(sliceChildren);
|
|
137
147
|
const lastC = findLastContent(sliceChildren);
|
|
138
148
|
const innerOffset = firstC ? firstC.offset : child.offset;
|
|
@@ -141,7 +151,8 @@ function flattenBlockMapChildren(children, state, externalKeyColumn, externalKey
|
|
|
141
151
|
items: innerPairs,
|
|
142
152
|
style: "block",
|
|
143
153
|
offset: innerOffset,
|
|
144
|
-
length: innerEnd - innerOffset
|
|
154
|
+
length: innerEnd - innerOffset,
|
|
155
|
+
...innerTrailing !== void 0 ? { comment: innerTrailing } : {}
|
|
145
156
|
}), innerOffset);
|
|
146
157
|
i = lookahead.endIdx - 1;
|
|
147
158
|
continue;
|
|
@@ -187,10 +198,10 @@ function flattenBlockMapChildren(children, state, externalKeyColumn, externalKey
|
|
|
187
198
|
continue;
|
|
188
199
|
}
|
|
189
200
|
if (child.type === "comment") {
|
|
190
|
-
const text = child.source.startsWith("#") ? child.source.slice(1).trim() : child.source;
|
|
191
201
|
items.push({
|
|
192
202
|
kind: "comment",
|
|
193
|
-
comment:
|
|
203
|
+
comment: rawCommentText(child.source),
|
|
204
|
+
offset: child.offset
|
|
194
205
|
});
|
|
195
206
|
continue;
|
|
196
207
|
}
|
|
@@ -479,9 +490,74 @@ function flattenBlockMapChildren(children, state, externalKeyColumn, externalKey
|
|
|
479
490
|
* Pattern: node, value-sep, node produces a key:value pair.
|
|
480
491
|
* Pattern: node, value-sep (no node) produces a key:null pair.
|
|
481
492
|
* Pattern: value-sep, node produces a null:value pair.
|
|
493
|
+
*
|
|
494
|
+
* Comment attribution (#127): a comment on the same line as the end of the
|
|
495
|
+
* previous pair attaches to it as the trailing `comment`; an own-line
|
|
496
|
+
* comment attaches FORWARD to the next pair as `commentBefore` (consecutive
|
|
497
|
+
* lines join with `\n`); a blank line before a pair (or before its
|
|
498
|
+
* `commentBefore` block) sets `spaceBefore`. Own-line comments left over
|
|
499
|
+
* after the last pair are returned so the caller can attach them as the
|
|
500
|
+
* containing collection's trailing `comment`.
|
|
482
501
|
*/
|
|
483
|
-
function buildPairs(items, pairs, text) {
|
|
502
|
+
function buildPairs(items, pairs, text, escaped) {
|
|
484
503
|
let i = 0;
|
|
504
|
+
let pending = [];
|
|
505
|
+
let pendingSpace = false;
|
|
506
|
+
let lastEnd = -1;
|
|
507
|
+
let lastNode;
|
|
508
|
+
let contentColumn = -1;
|
|
509
|
+
const nodeEnd = (n) => n.offset + n.length;
|
|
510
|
+
/**
|
|
511
|
+
* Rebuild `pair` with `text` appended to the trailing comment of whichever
|
|
512
|
+
* node owns the pair's last line: the value when present, otherwise the key.
|
|
513
|
+
*/
|
|
514
|
+
const withTrailingComment = (pair, text, onKey = false) => pair.value !== null && !onKey ? new YamlPair({
|
|
515
|
+
key: pair.key,
|
|
516
|
+
value: withCommentFields(pair.value, { comment: text })
|
|
517
|
+
}) : new YamlPair({
|
|
518
|
+
key: withCommentFields(pair.key, { comment: text }),
|
|
519
|
+
value: pair.value
|
|
520
|
+
});
|
|
521
|
+
/**
|
|
522
|
+
* Finish a pair: the pending leading fields go to its KEY node, the entry's
|
|
523
|
+
* trailing comment to whichever node owns the last line. The one place the
|
|
524
|
+
* node-level split is applied, so no construction site has to know it.
|
|
525
|
+
*/
|
|
526
|
+
const pushPair = (pair, leading, trailing, trailingOnKey = false) => {
|
|
527
|
+
const withLeading = Object.keys(leading).length === 0 ? pair : new YamlPair({
|
|
528
|
+
key: withCommentFields(pair.key, leading),
|
|
529
|
+
value: pair.value
|
|
530
|
+
});
|
|
531
|
+
return trailing === void 0 ? withLeading : withTrailingComment(withLeading, trailing, trailingOnKey);
|
|
532
|
+
};
|
|
533
|
+
const noteContentColumn = (offset) => {
|
|
534
|
+
if (contentColumn < 0 && offset >= 0) contentColumn = columnAt(text, offset);
|
|
535
|
+
};
|
|
536
|
+
/** Join pending parts: `\n` between lines, an extra `\n` per embedded blank. */
|
|
537
|
+
const joinPending = (parts) => {
|
|
538
|
+
if (parts.length === 0) return void 0;
|
|
539
|
+
let out = parts[0].text;
|
|
540
|
+
for (let k = 1; k < parts.length; k++) {
|
|
541
|
+
const part = parts[k];
|
|
542
|
+
out += part.blankAbove ? `\n\n${part.text}` : `\n${part.text}`;
|
|
543
|
+
}
|
|
544
|
+
return out;
|
|
545
|
+
};
|
|
546
|
+
/** The pending comment fields for the pair being constructed, then reset. */
|
|
547
|
+
const takePendingFields = (anchorOffset) => {
|
|
548
|
+
let commentBefore = joinPending(pending);
|
|
549
|
+
if (anchorOffset >= 0 && hasBlankLineAbove(text, anchorOffset)) {
|
|
550
|
+
if (commentBefore !== void 0) commentBefore = `${commentBefore}\n`;
|
|
551
|
+
else if (!pendingSpace && lastEnd >= 0 && !blankAboveIsKeepChompContent(text, anchorOffset, lastNode)) pendingSpace = true;
|
|
552
|
+
}
|
|
553
|
+
const fields = {
|
|
554
|
+
...commentBefore !== void 0 ? { commentBefore } : {},
|
|
555
|
+
...pendingSpace ? { spaceBefore: true } : {}
|
|
556
|
+
};
|
|
557
|
+
pending = [];
|
|
558
|
+
pendingSpace = false;
|
|
559
|
+
return fields;
|
|
560
|
+
};
|
|
485
561
|
while (i < items.length) {
|
|
486
562
|
const item = items[i];
|
|
487
563
|
if (!item) {
|
|
@@ -489,12 +565,18 @@ function buildPairs(items, pairs, text) {
|
|
|
489
565
|
continue;
|
|
490
566
|
}
|
|
491
567
|
if (item.kind === "comment") {
|
|
492
|
-
|
|
568
|
+
const cOff = item.offset ?? -1;
|
|
569
|
+
const cText = item.comment ?? "";
|
|
570
|
+
if (!(cOff < 0 ? true : isOwnLineAt(text, cOff) || isAfterIndicatorOnly(text, cOff)) && pairs.length > 0) {
|
|
493
571
|
const last = pairs[pairs.length - 1];
|
|
494
|
-
if (last) pairs[pairs.length - 1] =
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
572
|
+
if (last) pairs[pairs.length - 1] = withTrailingComment(last, cText);
|
|
573
|
+
} else {
|
|
574
|
+
const blankAbove = cOff >= 0 && hasBlankLineAbove(text, cOff) && !blankAboveIsKeepChompContent(text, cOff, lastNode);
|
|
575
|
+
if (blankAbove && pending.length === 0 && lastEnd >= 0) pendingSpace = true;
|
|
576
|
+
pending.push({
|
|
577
|
+
text: cText,
|
|
578
|
+
offset: cOff,
|
|
579
|
+
blankAbove: blankAbove && pending.length > 0
|
|
498
580
|
});
|
|
499
581
|
}
|
|
500
582
|
i++;
|
|
@@ -503,30 +585,30 @@ function buildPairs(items, pairs, text) {
|
|
|
503
585
|
if (item.kind === "value-sep") {
|
|
504
586
|
const valueSepOffset = item.offset ?? 0;
|
|
505
587
|
i++;
|
|
588
|
+
const pendingFields = takePendingFields(valueSepOffset);
|
|
589
|
+
noteContentColumn(valueSepOffset);
|
|
506
590
|
const valueNode = consumeValueNodeForNullKey(items, i, text, valueSepOffset);
|
|
591
|
+
const nullKey = new YamlScalar({
|
|
592
|
+
value: null,
|
|
593
|
+
style: "plain",
|
|
594
|
+
offset: valueSepOffset,
|
|
595
|
+
length: 0
|
|
596
|
+
});
|
|
507
597
|
if (valueNode) {
|
|
508
|
-
|
|
509
|
-
value: null,
|
|
510
|
-
style: "plain",
|
|
511
|
-
offset: valueSepOffset,
|
|
512
|
-
length: 0
|
|
513
|
-
});
|
|
514
|
-
pairs.push(new YamlPair({
|
|
598
|
+
pairs.push(pushPair(new YamlPair({
|
|
515
599
|
key: nullKey,
|
|
516
600
|
value: valueNode.node ?? null
|
|
517
|
-
}));
|
|
601
|
+
}), pendingFields, void 0));
|
|
518
602
|
i = valueNode.nextIdx;
|
|
603
|
+
lastEnd = valueNode.node ? nodeEnd(valueNode.node) : valueSepOffset + 1;
|
|
604
|
+
lastNode = valueNode.node ?? void 0;
|
|
519
605
|
} else {
|
|
520
|
-
|
|
521
|
-
value: null,
|
|
522
|
-
style: "plain",
|
|
523
|
-
offset: valueSepOffset,
|
|
524
|
-
length: 0
|
|
525
|
-
});
|
|
526
|
-
pairs.push(new YamlPair({
|
|
606
|
+
pairs.push(pushPair(new YamlPair({
|
|
527
607
|
key: nullKey,
|
|
528
608
|
value: null
|
|
529
|
-
}));
|
|
609
|
+
}), pendingFields, void 0));
|
|
610
|
+
lastEnd = valueSepOffset + 1;
|
|
611
|
+
lastNode = void 0;
|
|
530
612
|
}
|
|
531
613
|
continue;
|
|
532
614
|
}
|
|
@@ -540,62 +622,124 @@ function buildPairs(items, pairs, text) {
|
|
|
540
622
|
i++;
|
|
541
623
|
}
|
|
542
624
|
}
|
|
543
|
-
|
|
625
|
+
if (keyNode) noteContentColumn(keyNode.offset);
|
|
626
|
+
const pendingFields = takePendingFields(keyNode ? keyNode.offset : -1);
|
|
627
|
+
let pairTrailing;
|
|
628
|
+
while (i < items.length && items[i]?.kind === "comment") {
|
|
629
|
+
const c = items[i]?.comment;
|
|
630
|
+
if (c !== void 0) pairTrailing = joinComments(pairTrailing, c);
|
|
631
|
+
i++;
|
|
632
|
+
}
|
|
633
|
+
const keyOrNull = () => keyNode ?? new YamlScalar({
|
|
634
|
+
value: null,
|
|
635
|
+
style: "plain",
|
|
636
|
+
offset: 0,
|
|
637
|
+
length: 0
|
|
638
|
+
});
|
|
544
639
|
if (i < items.length && items[i]?.kind === "value-sep") {
|
|
640
|
+
const sepOffset = items[i]?.offset ?? (keyNode ? nodeEnd(keyNode) : 0);
|
|
545
641
|
i++;
|
|
546
|
-
const valueResult = consumeValueNode(items, i);
|
|
642
|
+
const valueResult = consumeValueNode(items, i, text, sepOffset);
|
|
547
643
|
if (valueResult) {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
value: valueResult.node ?? null
|
|
556
|
-
}));
|
|
644
|
+
for (const c of valueResult.sameLineComments) pairTrailing = joinComments(pairTrailing, c);
|
|
645
|
+
let valNode = valueResult.node;
|
|
646
|
+
if (valNode !== null && valueResult.leadingComments.length > 0) valNode = withCommentFields(valNode, { commentBefore: valueResult.leadingComments.join("\n") });
|
|
647
|
+
pairs.push(pushPair(new YamlPair({
|
|
648
|
+
key: keyOrNull(),
|
|
649
|
+
value: valNode
|
|
650
|
+
}), pendingFields, pairTrailing, keyIsSimple(keyNode) && (valNode === null || !sameLineSpan(text, sepOffset, valNode.offset))));
|
|
557
651
|
i = valueResult.nextIdx;
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
}),
|
|
652
|
+
lastEnd = valNode ? nodeEnd(valNode) : sepOffset + 1;
|
|
653
|
+
lastNode = valNode ?? void 0;
|
|
654
|
+
} else {
|
|
655
|
+
pairs.push(pushPair(new YamlPair({
|
|
656
|
+
key: keyOrNull(),
|
|
657
|
+
value: null
|
|
658
|
+
}), pendingFields, pairTrailing));
|
|
659
|
+
lastEnd = sepOffset + 1;
|
|
660
|
+
lastNode = void 0;
|
|
661
|
+
}
|
|
662
|
+
} else {
|
|
663
|
+
pairs.push(pushPair(new YamlPair({
|
|
664
|
+
key: keyOrNull(),
|
|
565
665
|
value: null
|
|
566
|
-
}));
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
style: "plain",
|
|
571
|
-
offset: 0,
|
|
572
|
-
length: 0
|
|
573
|
-
}),
|
|
574
|
-
value: null
|
|
575
|
-
}));
|
|
666
|
+
}), pendingFields, pairTrailing));
|
|
667
|
+
lastEnd = keyNode ? nodeEnd(keyNode) : lastEnd;
|
|
668
|
+
if (keyNode) lastNode = keyNode;
|
|
669
|
+
}
|
|
576
670
|
continue;
|
|
577
671
|
}
|
|
578
672
|
i++;
|
|
579
673
|
}
|
|
674
|
+
if (pending.length === 0) return void 0;
|
|
675
|
+
const withLeadingBlank = (parts) => {
|
|
676
|
+
const joined = joinPending(parts);
|
|
677
|
+
const first = parts[0];
|
|
678
|
+
return joined !== void 0 && first !== void 0 && lastEnd >= 0 && first.offset >= 0 && hasBlankLineAbove(text, first.offset) && !blankAboveIsKeepChompContent(text, first.offset, lastNode) ? `\n${joined}` : joined;
|
|
679
|
+
};
|
|
680
|
+
if (escaped !== void 0 && contentColumn > 0) {
|
|
681
|
+
const kept = [];
|
|
682
|
+
for (const part of pending) if (part.offset >= 0 && columnAt(text, part.offset) < contentColumn) escaped.push({
|
|
683
|
+
text: part.text,
|
|
684
|
+
offset: part.offset
|
|
685
|
+
});
|
|
686
|
+
else kept.push(part);
|
|
687
|
+
return withLeadingBlank(kept);
|
|
688
|
+
}
|
|
689
|
+
return withLeadingBlank(pending);
|
|
580
690
|
}
|
|
581
|
-
|
|
691
|
+
/**
|
|
692
|
+
* True when a key renders in implicit `key: value` form, so the `:` sits on
|
|
693
|
+
* the key's own line. A multi-line or block-scalar key forces the explicit
|
|
694
|
+
* `? key` / `: value` spelling, where the `:` gets a line of its own.
|
|
695
|
+
*/
|
|
696
|
+
function keyIsSimple(keyNode) {
|
|
697
|
+
if (keyNode instanceof YamlAlias) return true;
|
|
698
|
+
if (!(keyNode instanceof YamlScalar)) return false;
|
|
699
|
+
if (typeof keyNode.value === "string" && keyNode.value.includes("\n")) return false;
|
|
700
|
+
return keyNode.style !== "block-literal" && keyNode.style !== "block-folded";
|
|
701
|
+
}
|
|
702
|
+
function consumeValueNode(items, startIdx, text, sepOffset) {
|
|
703
|
+
let peek = startIdx;
|
|
704
|
+
while (peek < items.length && items[peek]?.kind === "comment") peek++;
|
|
705
|
+
const candidate = peek < items.length ? items[peek] : void 0;
|
|
706
|
+
if (candidate?.kind === "node" && peek + 1 < items.length && items[peek + 1]?.kind === "value-sep" && candidate.node !== void 0 && text.slice(sepOffset, candidate.node.offset).includes("\n")) return null;
|
|
582
707
|
let i = startIdx;
|
|
708
|
+
const sameLineComments = [];
|
|
709
|
+
const leadingComments = [];
|
|
710
|
+
let firstOwnLineIdx = -1;
|
|
583
711
|
while (i < items.length) {
|
|
584
712
|
const item = items[i];
|
|
585
713
|
if (!item) break;
|
|
586
714
|
if (item.kind === "comment") {
|
|
715
|
+
const cText = item.comment ?? "";
|
|
716
|
+
if (item.offset !== void 0 && sameLineSpan(text, sepOffset, item.offset)) sameLineComments.push(cText);
|
|
717
|
+
else {
|
|
718
|
+
if (firstOwnLineIdx < 0) firstOwnLineIdx = i;
|
|
719
|
+
leadingComments.push(cText);
|
|
720
|
+
}
|
|
587
721
|
i++;
|
|
588
722
|
continue;
|
|
589
723
|
}
|
|
590
724
|
if (item.kind === "node") return {
|
|
591
725
|
node: item.node ?? null,
|
|
592
|
-
nextIdx: i + 1
|
|
726
|
+
nextIdx: i + 1,
|
|
727
|
+
sameLineComments,
|
|
728
|
+
leadingComments
|
|
593
729
|
};
|
|
594
730
|
break;
|
|
595
731
|
}
|
|
732
|
+
if (firstOwnLineIdx >= 0) return {
|
|
733
|
+
node: null,
|
|
734
|
+
nextIdx: firstOwnLineIdx,
|
|
735
|
+
sameLineComments,
|
|
736
|
+
leadingComments: []
|
|
737
|
+
};
|
|
596
738
|
return i > startIdx ? {
|
|
597
739
|
node: null,
|
|
598
|
-
nextIdx: i
|
|
740
|
+
nextIdx: i,
|
|
741
|
+
sameLineComments,
|
|
742
|
+
leadingComments
|
|
599
743
|
} : null;
|
|
600
744
|
}
|
|
601
745
|
/**
|
|
@@ -609,10 +753,12 @@ function consumeValueNode(items, startIdx) {
|
|
|
609
753
|
*/
|
|
610
754
|
function consumeValueNodeForNullKey(items, startIdx, text, valueSepOffset) {
|
|
611
755
|
let i = startIdx;
|
|
756
|
+
let firstOwnLineIdx = -1;
|
|
612
757
|
while (i < items.length) {
|
|
613
758
|
const item = items[i];
|
|
614
759
|
if (!item) break;
|
|
615
760
|
if (item.kind === "comment") {
|
|
761
|
+
if (firstOwnLineIdx < 0 && item.offset !== void 0 && !sameLineSpan(text, valueSepOffset, item.offset)) firstOwnLineIdx = i;
|
|
616
762
|
i++;
|
|
617
763
|
continue;
|
|
618
764
|
}
|
|
@@ -628,6 +774,10 @@ function consumeValueNodeForNullKey(items, startIdx, text, valueSepOffset) {
|
|
|
628
774
|
}
|
|
629
775
|
break;
|
|
630
776
|
}
|
|
777
|
+
if (firstOwnLineIdx >= 0) return {
|
|
778
|
+
node: null,
|
|
779
|
+
nextIdx: firstOwnLineIdx
|
|
780
|
+
};
|
|
631
781
|
return i > startIdx ? {
|
|
632
782
|
node: null,
|
|
633
783
|
nextIdx: i
|
|
@@ -950,11 +1100,59 @@ function composeBlockSeq(cst, state, meta) {
|
|
|
950
1100
|
}
|
|
951
1101
|
function composeBlockSeqInner(cst, state, meta) {
|
|
952
1102
|
const children = cst.children ?? [];
|
|
953
|
-
const
|
|
1103
|
+
const rawItems = [];
|
|
954
1104
|
let pendingMeta = {};
|
|
955
1105
|
let sawEntry = false;
|
|
956
1106
|
const seqIndent = lineIndentColumn(state.text, cst.offset);
|
|
957
1107
|
let sawNewlineSincePending = false;
|
|
1108
|
+
let pending = [];
|
|
1109
|
+
let pendingSpace = false;
|
|
1110
|
+
let lastItemEnd = -1;
|
|
1111
|
+
let lastItemNode;
|
|
1112
|
+
const joinPending = (parts) => {
|
|
1113
|
+
if (parts.length === 0) return void 0;
|
|
1114
|
+
let out = parts[0].text;
|
|
1115
|
+
for (let k = 1; k < parts.length; k++) {
|
|
1116
|
+
const part = parts[k];
|
|
1117
|
+
out += part.blankAbove ? `\n\n${part.text}` : `\n${part.text}`;
|
|
1118
|
+
}
|
|
1119
|
+
return out;
|
|
1120
|
+
};
|
|
1121
|
+
const acceptOwnLineComment = (cText, cOff) => {
|
|
1122
|
+
const blankAbove = cOff >= 0 && hasBlankLineAbove(state.text, cOff) && !blankAboveIsKeepChompContent(state.text, cOff, lastItemNode);
|
|
1123
|
+
if (blankAbove && pending.length === 0 && lastItemEnd >= 0) pendingSpace = true;
|
|
1124
|
+
pending.push({
|
|
1125
|
+
text: cText,
|
|
1126
|
+
offset: cOff,
|
|
1127
|
+
blankAbove: blankAbove && pending.length > 0
|
|
1128
|
+
});
|
|
1129
|
+
};
|
|
1130
|
+
const items = {
|
|
1131
|
+
get length() {
|
|
1132
|
+
return rawItems.length;
|
|
1133
|
+
},
|
|
1134
|
+
push(node) {
|
|
1135
|
+
let commentBefore = joinPending(pending);
|
|
1136
|
+
if (node.length > 0 && hasBlankLineAbove(state.text, node.offset)) {
|
|
1137
|
+
if (commentBefore !== void 0) commentBefore = `${commentBefore}\n`;
|
|
1138
|
+
else if (!pendingSpace && lastItemEnd >= 0 && !blankAboveIsKeepChompContent(state.text, node.offset, lastItemNode)) pendingSpace = true;
|
|
1139
|
+
}
|
|
1140
|
+
let decorated = node;
|
|
1141
|
+
if (commentBefore !== void 0 || pendingSpace) decorated = withCommentFields(node, {
|
|
1142
|
+
...commentBefore !== void 0 ? { commentBefore } : {},
|
|
1143
|
+
...pendingSpace ? { spaceBefore: true } : {}
|
|
1144
|
+
});
|
|
1145
|
+
pending = [];
|
|
1146
|
+
pendingSpace = false;
|
|
1147
|
+
rawItems.push(decorated);
|
|
1148
|
+
lastItemEnd = node.offset + node.length;
|
|
1149
|
+
lastItemNode = node;
|
|
1150
|
+
if (state.escapedComments.length > 0) {
|
|
1151
|
+
for (const ec of state.escapedComments) acceptOwnLineComment(ec.text, ec.offset);
|
|
1152
|
+
state.escapedComments.length = 0;
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
958
1156
|
for (let ci = 0; ci < children.length; ci++) {
|
|
959
1157
|
const child = children[ci];
|
|
960
1158
|
if (!child) continue;
|
|
@@ -962,7 +1160,14 @@ function composeBlockSeqInner(cst, state, meta) {
|
|
|
962
1160
|
if (hasMeta(pendingMeta)) sawNewlineSincePending = true;
|
|
963
1161
|
continue;
|
|
964
1162
|
}
|
|
965
|
-
if (child.type === "comment")
|
|
1163
|
+
if (child.type === "comment") {
|
|
1164
|
+
const cText = rawCommentText(child.source);
|
|
1165
|
+
if (rawItems.length > 0 && !isOwnLineAt(state.text, child.offset)) {
|
|
1166
|
+
const prev = rawItems[rawItems.length - 1];
|
|
1167
|
+
if (prev) rawItems[rawItems.length - 1] = withCommentFields(prev, { comment: cText });
|
|
1168
|
+
} else acceptOwnLineComment(cText, child.offset);
|
|
1169
|
+
continue;
|
|
1170
|
+
}
|
|
966
1171
|
if (child.type === "whitespace") {
|
|
967
1172
|
if (child.source.trim() === "-") {
|
|
968
1173
|
if (sawEntry) {
|
|
@@ -1121,14 +1326,32 @@ function composeBlockSeqInner(cst, state, meta) {
|
|
|
1121
1326
|
if (pendingMeta.anchor) registerAnchor(scalar, pendingMeta.anchor, state, 0);
|
|
1122
1327
|
items.push(scalar);
|
|
1123
1328
|
}
|
|
1329
|
+
const withLeadingBlank = (parts) => {
|
|
1330
|
+
const joined = joinPending(parts);
|
|
1331
|
+
const first = parts[0];
|
|
1332
|
+
return joined !== void 0 && first !== void 0 && lastItemEnd >= 0 && first.offset >= 0 && hasBlankLineAbove(state.text, first.offset) && !blankAboveIsKeepChompContent(state.text, first.offset, lastItemNode) ? `\n${joined}` : joined;
|
|
1333
|
+
};
|
|
1334
|
+
let seqTrailing;
|
|
1335
|
+
if (pending.length > 0) {
|
|
1336
|
+
if (seqIndent > 0) {
|
|
1337
|
+
const kept = [];
|
|
1338
|
+
for (const part of pending) if (part.offset >= 0 && columnAt(state.text, part.offset) < seqIndent) state.escapedComments.push({
|
|
1339
|
+
text: part.text,
|
|
1340
|
+
offset: part.offset
|
|
1341
|
+
});
|
|
1342
|
+
else kept.push(part);
|
|
1343
|
+
seqTrailing = withLeadingBlank(kept);
|
|
1344
|
+
} else seqTrailing = withLeadingBlank(pending);
|
|
1345
|
+
}
|
|
1346
|
+
const seqComment = meta?.comment !== void 0 ? seqTrailing !== void 0 ? `${meta.comment}\n${seqTrailing}` : meta.comment : seqTrailing;
|
|
1124
1347
|
const seq = new YamlSeq({
|
|
1125
|
-
items,
|
|
1348
|
+
items: rawItems,
|
|
1126
1349
|
style: "block",
|
|
1127
1350
|
offset: cst.offset,
|
|
1128
1351
|
length: cst.length,
|
|
1129
1352
|
...meta?.tag !== void 0 ? { tag: meta.tag } : {},
|
|
1130
1353
|
...meta?.anchor !== void 0 ? { anchor: meta.anchor } : {},
|
|
1131
|
-
...
|
|
1354
|
+
...seqComment !== void 0 ? { comment: seqComment } : {}
|
|
1132
1355
|
});
|
|
1133
1356
|
if (meta?.anchor) registerAnchor(seq, meta.anchor, state, cst.offset);
|
|
1134
1357
|
return seq;
|
|
@@ -1144,11 +1367,12 @@ function composeFlatBlockMap(children, startIdx, parentCst, state, externalFirst
|
|
|
1144
1367
|
node: externalFirstKey
|
|
1145
1368
|
});
|
|
1146
1369
|
const pairs = [];
|
|
1147
|
-
buildPairs(items, pairs, state.text);
|
|
1370
|
+
const trailingComment = buildPairs(items, pairs, state.text, state.escapedComments);
|
|
1148
1371
|
if (state.options.uniqueKeys) checkDuplicateKeys(pairs, state);
|
|
1149
1372
|
checkMultilineImplicitKeys(pairs, state);
|
|
1150
1373
|
const offset = "offset" in externalFirstKey ? externalFirstKey.offset : parentCst.offset;
|
|
1151
1374
|
const end = parentCst.offset + parentCst.length;
|
|
1375
|
+
const mapComment = meta?.comment !== void 0 ? trailingComment !== void 0 ? `${meta.comment}\n${trailingComment}` : meta.comment : trailingComment;
|
|
1152
1376
|
const map = new YamlMap({
|
|
1153
1377
|
items: pairs,
|
|
1154
1378
|
style: "block",
|
|
@@ -1156,11 +1380,11 @@ function composeFlatBlockMap(children, startIdx, parentCst, state, externalFirst
|
|
|
1156
1380
|
length: end - offset,
|
|
1157
1381
|
...meta?.tag !== void 0 ? { tag: meta.tag } : {},
|
|
1158
1382
|
...meta?.anchor !== void 0 ? { anchor: meta.anchor } : {},
|
|
1159
|
-
...
|
|
1383
|
+
...mapComment !== void 0 ? { comment: mapComment } : {}
|
|
1160
1384
|
});
|
|
1161
1385
|
if (meta?.anchor) registerAnchor(map, meta.anchor, state, offset);
|
|
1162
1386
|
return map;
|
|
1163
1387
|
}
|
|
1164
1388
|
|
|
1165
1389
|
//#endregion
|
|
1166
|
-
export { buildPairs, checkDuplicateKeys, checkMultilineImplicitKeys, checkTrailingContentOnSameLine, composeBlockMap, composeBlockSeq, composeFlatBlockMap, flattenBlockMapChildren };
|
|
1390
|
+
export { buildPairs, checkDuplicateKeys, checkMultilineImplicitKeys, checkTrailingContentOnSameLine, composeBlockMap, composeBlockSeq, composeFlatBlockMap, flattenBlockMapChildren, keyIdentity };
|