yaml 2.0.0-5 → 2.0.0-6
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/browser/dist/compose/compose-doc.js +1 -1
- package/browser/dist/compose/composer.js +1 -1
- package/browser/dist/compose/resolve-block-map.js +5 -2
- package/browser/dist/compose/resolve-block-scalar.js +1 -1
- package/browser/dist/compose/resolve-block-seq.js +1 -1
- package/browser/dist/compose/resolve-end.js +2 -2
- package/browser/dist/compose/resolve-flow-collection.js +10 -5
- package/browser/dist/compose/resolve-props.js +30 -7
- package/browser/dist/compose/util-map-includes.js +17 -0
- package/browser/dist/options.js +1 -0
- package/browser/dist/parse/parser.js +53 -52
- package/browser/dist/stringify/stringifyCollection.js +23 -9
- package/browser/dist/stringify/stringifyComment.js +14 -0
- package/browser/dist/stringify/stringifyDocument.js +8 -5
- package/browser/dist/stringify/stringifyPair.js +3 -5
- package/dist/compose/compose-doc.js +1 -1
- package/dist/compose/composer.js +1 -1
- package/dist/compose/resolve-block-map.d.ts +2 -1
- package/dist/compose/resolve-block-map.js +5 -2
- package/dist/compose/resolve-block-scalar.js +1 -1
- package/dist/compose/resolve-block-seq.js +1 -1
- package/dist/compose/resolve-end.js +2 -2
- package/dist/compose/resolve-flow-collection.js +10 -5
- package/dist/compose/resolve-props.d.ts +3 -4
- package/dist/compose/resolve-props.js +30 -7
- package/dist/compose/util-map-includes.d.ts +4 -0
- package/dist/compose/util-map-includes.js +19 -0
- package/dist/doc/Document.d.ts +4 -2
- package/dist/errors.d.ts +1 -1
- package/dist/nodes/Node.d.ts +4 -2
- package/dist/options.d.ts +15 -0
- package/dist/options.js +1 -0
- package/dist/parse/parser.d.ts +1 -0
- package/dist/parse/parser.js +53 -52
- package/dist/stringify/stringifyCollection.d.ts +1 -1
- package/dist/stringify/stringifyCollection.js +24 -10
- package/dist/stringify/stringifyComment.d.ts +2 -0
- package/dist/stringify/{addComment.js → stringifyComment.js} +5 -1
- package/dist/stringify/stringifyDocument.js +9 -6
- package/dist/stringify/stringifyPair.js +7 -9
- package/package.json +5 -5
- package/browser/dist/stringify/addComment.js +0 -11
- package/dist/stringify/addComment.d.ts +0 -2
|
@@ -12,8 +12,8 @@ function composeDoc(options, directives, { offset, start, value, end }, onError)
|
|
|
12
12
|
schema: doc.schema
|
|
13
13
|
};
|
|
14
14
|
const props = resolveProps(start, {
|
|
15
|
-
ctx,
|
|
16
15
|
indicator: 'doc-start',
|
|
16
|
+
next: value || (end === null || end === void 0 ? void 0 : end[0]),
|
|
17
17
|
offset,
|
|
18
18
|
onError,
|
|
19
19
|
startOnNewline: true
|
|
@@ -2,6 +2,7 @@ import { Pair } from '../nodes/Pair.js';
|
|
|
2
2
|
import { YAMLMap } from '../nodes/YAMLMap.js';
|
|
3
3
|
import { resolveProps } from './resolve-props.js';
|
|
4
4
|
import { containsNewline } from './util-contains-newline.js';
|
|
5
|
+
import { mapIncludes } from './util-map-includes.js';
|
|
5
6
|
|
|
6
7
|
const startColMsg = 'All mapping items must start at the same column';
|
|
7
8
|
function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
|
|
@@ -11,8 +12,8 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
|
|
|
11
12
|
for (const { start, key, sep, value } of bm.items) {
|
|
12
13
|
// key properties
|
|
13
14
|
const keyProps = resolveProps(start, {
|
|
14
|
-
ctx,
|
|
15
15
|
indicator: 'explicit-key-ind',
|
|
16
|
+
next: key || (sep === null || sep === void 0 ? void 0 : sep[0]),
|
|
16
17
|
offset,
|
|
17
18
|
onError,
|
|
18
19
|
startOnNewline: true
|
|
@@ -46,10 +47,12 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
|
|
|
46
47
|
const keyNode = key
|
|
47
48
|
? composeNode(ctx, key, keyProps, onError)
|
|
48
49
|
: composeEmptyNode(ctx, keyStart, start, null, keyProps, onError);
|
|
50
|
+
if (mapIncludes(ctx, map.items, keyNode))
|
|
51
|
+
onError(keyStart, 'DUPLICATE_KEY', 'Map keys must be unique');
|
|
49
52
|
// value properties
|
|
50
53
|
const valueProps = resolveProps(sep || [], {
|
|
51
|
-
ctx,
|
|
52
54
|
indicator: 'map-value-ind',
|
|
55
|
+
next: value,
|
|
53
56
|
offset: keyNode.range[2],
|
|
54
57
|
onError,
|
|
55
58
|
startOnNewline: !key || key.type === 'block-scalar'
|
|
@@ -149,7 +149,7 @@ function parseBlockScalarHeader({ offset, props }, strict, onError) {
|
|
|
149
149
|
case 'comment':
|
|
150
150
|
if (strict && !hasSpace) {
|
|
151
151
|
const message = 'Comments must be separated from other tokens by white space characters';
|
|
152
|
-
onError(token, '
|
|
152
|
+
onError(token, 'MISSING_CHAR', message);
|
|
153
153
|
}
|
|
154
154
|
length += token.source.length;
|
|
155
155
|
comment = token.source.substring(1);
|
|
@@ -6,8 +6,8 @@ function resolveBlockSeq({ composeNode, composeEmptyNode }, ctx, bs, onError) {
|
|
|
6
6
|
let offset = bs.offset;
|
|
7
7
|
for (const { start, value } of bs.items) {
|
|
8
8
|
const props = resolveProps(start, {
|
|
9
|
-
ctx,
|
|
10
9
|
indicator: 'seq-item-ind',
|
|
10
|
+
next: value,
|
|
11
11
|
offset,
|
|
12
12
|
onError,
|
|
13
13
|
startOnNewline: true
|
|
@@ -11,8 +11,8 @@ function resolveEnd(end, offset, reqSpace, onError) {
|
|
|
11
11
|
break;
|
|
12
12
|
case 'comment': {
|
|
13
13
|
if (reqSpace && !hasSpace)
|
|
14
|
-
onError(token, '
|
|
15
|
-
const cb = source.substring(1);
|
|
14
|
+
onError(token, 'MISSING_CHAR', 'Comments must be separated from other tokens by white space characters');
|
|
15
|
+
const cb = source.substring(1) || ' ';
|
|
16
16
|
if (!comment)
|
|
17
17
|
comment = cb;
|
|
18
18
|
else
|
|
@@ -5,6 +5,7 @@ import { YAMLSeq } from '../nodes/YAMLSeq.js';
|
|
|
5
5
|
import { resolveEnd } from './resolve-end.js';
|
|
6
6
|
import { resolveProps } from './resolve-props.js';
|
|
7
7
|
import { containsNewline } from './util-contains-newline.js';
|
|
8
|
+
import { mapIncludes } from './util-map-includes.js';
|
|
8
9
|
|
|
9
10
|
const blockMsg = 'Block collections are not allowed within flow collections';
|
|
10
11
|
const isBlock = (token) => token && (token.type === 'block-map' || token.type === 'block-seq');
|
|
@@ -19,9 +20,9 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
19
20
|
for (let i = 0; i < fc.items.length; ++i) {
|
|
20
21
|
const { start, key, sep, value } = fc.items[i];
|
|
21
22
|
const props = resolveProps(start, {
|
|
22
|
-
ctx,
|
|
23
23
|
flow: fcName,
|
|
24
24
|
indicator: 'explicit-key-ind',
|
|
25
|
+
next: key || (sep === null || sep === void 0 ? void 0 : sep[0]),
|
|
25
26
|
offset,
|
|
26
27
|
onError,
|
|
27
28
|
startOnNewline: false
|
|
@@ -99,9 +100,9 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
99
100
|
onError(keyNode.range, 'BLOCK_IN_FLOW', blockMsg);
|
|
100
101
|
// value properties
|
|
101
102
|
const valueProps = resolveProps(sep || [], {
|
|
102
|
-
ctx,
|
|
103
103
|
flow: fcName,
|
|
104
104
|
indicator: 'map-value-ind',
|
|
105
|
+
next: value,
|
|
105
106
|
offset: keyNode.range[2],
|
|
106
107
|
onError,
|
|
107
108
|
startOnNewline: false
|
|
@@ -144,8 +145,12 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
144
145
|
keyNode.comment = valueProps.comment;
|
|
145
146
|
}
|
|
146
147
|
const pair = new Pair(keyNode, valueNode);
|
|
147
|
-
if (isMap)
|
|
148
|
-
coll
|
|
148
|
+
if (isMap) {
|
|
149
|
+
const map = coll;
|
|
150
|
+
if (mapIncludes(ctx, map.items, keyNode))
|
|
151
|
+
onError(keyStart, 'DUPLICATE_KEY', 'Map keys must be unique');
|
|
152
|
+
map.items.push(pair);
|
|
153
|
+
}
|
|
149
154
|
else {
|
|
150
155
|
const map = new YAMLMap(ctx.schema);
|
|
151
156
|
map.flow = true;
|
|
@@ -159,7 +164,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
159
164
|
const [ce, ...ee] = fc.end;
|
|
160
165
|
let cePos = offset;
|
|
161
166
|
if (ce && ce.source === expectedEnd)
|
|
162
|
-
cePos
|
|
167
|
+
cePos = ce.offset + ce.source.length;
|
|
163
168
|
else {
|
|
164
169
|
onError(offset + 1, 'MISSING_CHAR', `Expected ${fcName} to end with ${expectedEnd}`);
|
|
165
170
|
if (ce && ce.source.length !== 1)
|
|
@@ -1,16 +1,24 @@
|
|
|
1
|
-
function resolveProps(tokens, {
|
|
1
|
+
function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnNewline }) {
|
|
2
2
|
let spaceBefore = false;
|
|
3
3
|
let atNewline = startOnNewline;
|
|
4
4
|
let hasSpace = startOnNewline;
|
|
5
5
|
let comment = '';
|
|
6
6
|
let commentSep = '';
|
|
7
7
|
let hasNewline = false;
|
|
8
|
+
let reqSpace = false;
|
|
8
9
|
let anchor = null;
|
|
9
10
|
let tag = null;
|
|
10
11
|
let comma = null;
|
|
11
12
|
let found = null;
|
|
12
13
|
let start = null;
|
|
13
14
|
for (const token of tokens) {
|
|
15
|
+
if (reqSpace) {
|
|
16
|
+
if (token.type !== 'space' &&
|
|
17
|
+
token.type !== 'newline' &&
|
|
18
|
+
token.type !== 'comma')
|
|
19
|
+
onError(token.offset, 'MISSING_CHAR', 'Tags and anchors must be separated from the next token by white space');
|
|
20
|
+
reqSpace = false;
|
|
21
|
+
}
|
|
14
22
|
switch (token.type) {
|
|
15
23
|
case 'space':
|
|
16
24
|
// At the doc level, tabs at line start may be parsed
|
|
@@ -24,23 +32,29 @@ function resolveProps(tokens, { ctx, flow, indicator, offset, onError, startOnNe
|
|
|
24
32
|
hasSpace = true;
|
|
25
33
|
break;
|
|
26
34
|
case 'comment': {
|
|
27
|
-
if (
|
|
28
|
-
onError(token, '
|
|
29
|
-
const cb = token.source.substring(1);
|
|
35
|
+
if (!hasSpace)
|
|
36
|
+
onError(token, 'MISSING_CHAR', 'Comments must be separated from other tokens by white space characters');
|
|
37
|
+
const cb = token.source.substring(1) || ' ';
|
|
30
38
|
if (!comment)
|
|
31
39
|
comment = cb;
|
|
32
40
|
else
|
|
33
41
|
comment += commentSep + cb;
|
|
34
42
|
commentSep = '';
|
|
43
|
+
atNewline = false;
|
|
35
44
|
break;
|
|
36
45
|
}
|
|
37
46
|
case 'newline':
|
|
38
|
-
if (atNewline
|
|
39
|
-
|
|
47
|
+
if (atNewline) {
|
|
48
|
+
if (comment)
|
|
49
|
+
comment += token.source;
|
|
50
|
+
else
|
|
51
|
+
spaceBefore = true;
|
|
52
|
+
}
|
|
53
|
+
else
|
|
54
|
+
commentSep += token.source;
|
|
40
55
|
atNewline = true;
|
|
41
56
|
hasNewline = true;
|
|
42
57
|
hasSpace = true;
|
|
43
|
-
commentSep += token.source;
|
|
44
58
|
break;
|
|
45
59
|
case 'anchor':
|
|
46
60
|
if (anchor)
|
|
@@ -50,6 +64,7 @@ function resolveProps(tokens, { ctx, flow, indicator, offset, onError, startOnNe
|
|
|
50
64
|
start = token.offset;
|
|
51
65
|
atNewline = false;
|
|
52
66
|
hasSpace = false;
|
|
67
|
+
reqSpace = true;
|
|
53
68
|
break;
|
|
54
69
|
case 'tag': {
|
|
55
70
|
if (tag)
|
|
@@ -59,6 +74,7 @@ function resolveProps(tokens, { ctx, flow, indicator, offset, onError, startOnNe
|
|
|
59
74
|
start = token.offset;
|
|
60
75
|
atNewline = false;
|
|
61
76
|
hasSpace = false;
|
|
77
|
+
reqSpace = true;
|
|
62
78
|
break;
|
|
63
79
|
}
|
|
64
80
|
case indicator:
|
|
@@ -87,6 +103,13 @@ function resolveProps(tokens, { ctx, flow, indicator, offset, onError, startOnNe
|
|
|
87
103
|
}
|
|
88
104
|
const last = tokens[tokens.length - 1];
|
|
89
105
|
const end = last ? last.offset + last.source.length : offset;
|
|
106
|
+
if (reqSpace &&
|
|
107
|
+
next &&
|
|
108
|
+
next.type !== 'space' &&
|
|
109
|
+
next.type !== 'newline' &&
|
|
110
|
+
next.type !== 'comma' &&
|
|
111
|
+
(next.type !== 'scalar' || next.source !== ''))
|
|
112
|
+
onError(next.offset, 'MISSING_CHAR', 'Tags and anchors must be separated from the next token by white space');
|
|
90
113
|
return {
|
|
91
114
|
comma,
|
|
92
115
|
found,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { isScalar } from '../nodes/Node.js';
|
|
2
|
+
|
|
3
|
+
function mapIncludes(ctx, items, search) {
|
|
4
|
+
const { uniqueKeys } = ctx.options;
|
|
5
|
+
if (uniqueKeys === false)
|
|
6
|
+
return false;
|
|
7
|
+
const isEqual = typeof uniqueKeys === 'function'
|
|
8
|
+
? uniqueKeys
|
|
9
|
+
: (a, b) => a === b ||
|
|
10
|
+
(isScalar(a) &&
|
|
11
|
+
isScalar(b) &&
|
|
12
|
+
a.value === b.value &&
|
|
13
|
+
!(a.value === '<<' && ctx.schema.merge));
|
|
14
|
+
return items.some(pair => isEqual(pair.key, search));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { mapIncludes };
|
package/browser/dist/options.js
CHANGED
|
@@ -20,38 +20,6 @@ function includesNonEmpty(list) {
|
|
|
20
20
|
}
|
|
21
21
|
return false;
|
|
22
22
|
}
|
|
23
|
-
function atFirstEmptyLineAfterComments(start) {
|
|
24
|
-
let hasComment = false;
|
|
25
|
-
for (let i = 0; i < start.length; ++i) {
|
|
26
|
-
switch (start[i].type) {
|
|
27
|
-
case 'space':
|
|
28
|
-
break;
|
|
29
|
-
case 'comment':
|
|
30
|
-
hasComment = true;
|
|
31
|
-
break;
|
|
32
|
-
case 'newline':
|
|
33
|
-
if (!hasComment)
|
|
34
|
-
return false;
|
|
35
|
-
break;
|
|
36
|
-
default:
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
if (hasComment) {
|
|
41
|
-
for (let i = start.length - 1; i >= 0; --i) {
|
|
42
|
-
switch (start[i].type) {
|
|
43
|
-
/* istanbul ignore next */
|
|
44
|
-
case 'space':
|
|
45
|
-
break;
|
|
46
|
-
case 'newline':
|
|
47
|
-
return true;
|
|
48
|
-
default:
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
23
|
function isFlowToken(token) {
|
|
56
24
|
switch (token === null || token === void 0 ? void 0 : token.type) {
|
|
57
25
|
case 'alias':
|
|
@@ -502,24 +470,38 @@ class Parser {
|
|
|
502
470
|
switch (this.type) {
|
|
503
471
|
case 'newline':
|
|
504
472
|
this.onKeyLine = false;
|
|
505
|
-
if (
|
|
506
|
-
const
|
|
507
|
-
const
|
|
508
|
-
if (
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
}
|
|
473
|
+
if (it.value) {
|
|
474
|
+
const end = 'end' in it.value ? it.value.end : undefined;
|
|
475
|
+
const last = Array.isArray(end) ? end[end.length - 1] : undefined;
|
|
476
|
+
if ((last === null || last === void 0 ? void 0 : last.type) === 'comment')
|
|
477
|
+
end === null || end === void 0 ? void 0 : end.push(this.sourceToken);
|
|
478
|
+
else
|
|
479
|
+
map.items.push({ start: [this.sourceToken] });
|
|
513
480
|
}
|
|
514
|
-
|
|
481
|
+
else if (it.sep)
|
|
482
|
+
it.sep.push(this.sourceToken);
|
|
483
|
+
else
|
|
484
|
+
it.start.push(this.sourceToken);
|
|
485
|
+
return;
|
|
515
486
|
case 'space':
|
|
516
487
|
case 'comment':
|
|
517
488
|
if (it.value)
|
|
518
489
|
map.items.push({ start: [this.sourceToken] });
|
|
519
490
|
else if (it.sep)
|
|
520
491
|
it.sep.push(this.sourceToken);
|
|
521
|
-
else
|
|
492
|
+
else {
|
|
493
|
+
if (this.atIndentedComment(it.start, map.indent)) {
|
|
494
|
+
const prev = map.items[map.items.length - 2];
|
|
495
|
+
const end = (_a = prev === null || prev === void 0 ? void 0 : prev.value) === null || _a === void 0 ? void 0 : _a.end;
|
|
496
|
+
if (Array.isArray(end)) {
|
|
497
|
+
Array.prototype.push.apply(end, it.start);
|
|
498
|
+
end.push(this.sourceToken);
|
|
499
|
+
map.items.pop();
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
522
503
|
it.start.push(this.sourceToken);
|
|
504
|
+
}
|
|
523
505
|
return;
|
|
524
506
|
}
|
|
525
507
|
if (this.indent >= map.indent) {
|
|
@@ -624,22 +606,34 @@ class Parser {
|
|
|
624
606
|
const it = seq.items[seq.items.length - 1];
|
|
625
607
|
switch (this.type) {
|
|
626
608
|
case 'newline':
|
|
627
|
-
if (
|
|
628
|
-
const
|
|
629
|
-
const
|
|
630
|
-
if (
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
}
|
|
609
|
+
if (it.value) {
|
|
610
|
+
const end = 'end' in it.value ? it.value.end : undefined;
|
|
611
|
+
const last = Array.isArray(end) ? end[end.length - 1] : undefined;
|
|
612
|
+
if ((last === null || last === void 0 ? void 0 : last.type) === 'comment')
|
|
613
|
+
end === null || end === void 0 ? void 0 : end.push(this.sourceToken);
|
|
614
|
+
else
|
|
615
|
+
seq.items.push({ start: [this.sourceToken] });
|
|
635
616
|
}
|
|
636
|
-
|
|
617
|
+
else
|
|
618
|
+
it.start.push(this.sourceToken);
|
|
619
|
+
return;
|
|
637
620
|
case 'space':
|
|
638
621
|
case 'comment':
|
|
639
622
|
if (it.value)
|
|
640
623
|
seq.items.push({ start: [this.sourceToken] });
|
|
641
|
-
else
|
|
624
|
+
else {
|
|
625
|
+
if (this.atIndentedComment(it.start, seq.indent)) {
|
|
626
|
+
const prev = seq.items[seq.items.length - 2];
|
|
627
|
+
const end = (_a = prev === null || prev === void 0 ? void 0 : prev.value) === null || _a === void 0 ? void 0 : _a.end;
|
|
628
|
+
if (Array.isArray(end)) {
|
|
629
|
+
Array.prototype.push.apply(end, it.start);
|
|
630
|
+
end.push(this.sourceToken);
|
|
631
|
+
seq.items.pop();
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
642
635
|
it.start.push(this.sourceToken);
|
|
636
|
+
}
|
|
643
637
|
return;
|
|
644
638
|
case 'anchor':
|
|
645
639
|
case 'tag':
|
|
@@ -834,6 +828,13 @@ class Parser {
|
|
|
834
828
|
}
|
|
835
829
|
return null;
|
|
836
830
|
}
|
|
831
|
+
atIndentedComment(start, indent) {
|
|
832
|
+
if (this.type !== 'comment')
|
|
833
|
+
return false;
|
|
834
|
+
if (this.indent <= indent)
|
|
835
|
+
return false;
|
|
836
|
+
return start.every(st => st.type === 'newline' || st.type === 'space');
|
|
837
|
+
}
|
|
837
838
|
*documentEnd(docEnd) {
|
|
838
839
|
if (this.type !== 'doc-mode') {
|
|
839
840
|
if (docEnd.end)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Collection } from '../nodes/Collection.js';
|
|
2
|
-
import { addComment } from './addComment.js';
|
|
3
|
-
import { stringify } from './stringify.js';
|
|
4
2
|
import { isNode, isPair } from '../nodes/Node.js';
|
|
3
|
+
import { stringify } from './stringify.js';
|
|
4
|
+
import { addComment, stringifyComment } from './stringifyComment.js';
|
|
5
5
|
|
|
6
6
|
function stringifyCollection({ comment, flow, items }, ctx, { blockItem, flowChars, itemIndent, onChompKeep, onComment }) {
|
|
7
7
|
const { indent, indentStep } = ctx;
|
|
@@ -16,10 +16,17 @@ function stringifyCollection({ comment, flow, items }, ctx, { blockItem, flowCha
|
|
|
16
16
|
if (isNode(item)) {
|
|
17
17
|
if (!chompKeep && item.spaceBefore)
|
|
18
18
|
nodes.push({ comment: true, str: '' });
|
|
19
|
-
|
|
19
|
+
let cb = item.commentBefore;
|
|
20
|
+
if (cb && chompKeep)
|
|
21
|
+
cb = cb.replace(/^\n+/, '');
|
|
22
|
+
if (cb) {
|
|
23
|
+
if (/^\n+$/.test(cb))
|
|
24
|
+
cb = cb.substring(1);
|
|
20
25
|
// This match will always succeed on a non-empty string
|
|
21
|
-
for (const line of
|
|
22
|
-
|
|
26
|
+
for (const line of cb.match(/^.*$/gm)) {
|
|
27
|
+
const str = line === ' ' ? '#' : line ? `#${line}` : '';
|
|
28
|
+
nodes.push({ comment: true, str });
|
|
29
|
+
}
|
|
23
30
|
}
|
|
24
31
|
if (item.comment) {
|
|
25
32
|
comment = item.comment;
|
|
@@ -31,10 +38,17 @@ function stringifyCollection({ comment, flow, items }, ctx, { blockItem, flowCha
|
|
|
31
38
|
if (ik) {
|
|
32
39
|
if (!chompKeep && ik.spaceBefore)
|
|
33
40
|
nodes.push({ comment: true, str: '' });
|
|
34
|
-
|
|
41
|
+
let cb = ik.commentBefore;
|
|
42
|
+
if (cb && chompKeep)
|
|
43
|
+
cb = cb.replace(/^\n+/, '');
|
|
44
|
+
if (cb) {
|
|
45
|
+
if (/^\n+$/.test(cb))
|
|
46
|
+
cb = cb.substring(1);
|
|
35
47
|
// This match will always succeed on a non-empty string
|
|
36
|
-
for (const line of
|
|
37
|
-
|
|
48
|
+
for (const line of cb.match(/^.*$/gm)) {
|
|
49
|
+
const str = line === ' ' ? '#' : line ? `#${line}` : '';
|
|
50
|
+
nodes.push({ comment: true, str });
|
|
51
|
+
}
|
|
38
52
|
}
|
|
39
53
|
if (ik.comment)
|
|
40
54
|
singleLineOutput = false;
|
|
@@ -96,7 +110,7 @@ function stringifyCollection({ comment, flow, items }, ctx, { blockItem, flowCha
|
|
|
96
110
|
str += s ? `\n${indent}${s}` : '\n';
|
|
97
111
|
}
|
|
98
112
|
if (comment) {
|
|
99
|
-
str += '\n' + comment
|
|
113
|
+
str += '\n' + stringifyComment(comment, indent);
|
|
100
114
|
if (onComment)
|
|
101
115
|
onComment();
|
|
102
116
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const stringifyComment = (comment, indent) => /^\n+$/.test(comment)
|
|
2
|
+
? comment.substring(1)
|
|
3
|
+
: comment.replace(/^(?!$)(?: $)?/gm, `${indent}#`);
|
|
4
|
+
function addComment(str, indent, comment) {
|
|
5
|
+
return !comment
|
|
6
|
+
? str
|
|
7
|
+
: comment.includes('\n')
|
|
8
|
+
? `${str}\n` + stringifyComment(comment, indent)
|
|
9
|
+
: str.endsWith(' ')
|
|
10
|
+
? `${str}#${comment}`
|
|
11
|
+
: `${str} #${comment}`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { addComment, stringifyComment };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isNode } from '../nodes/Node.js';
|
|
2
|
-
import { addComment } from './addComment.js';
|
|
3
2
|
import { createStringifyContext, stringify } from './stringify.js';
|
|
3
|
+
import { stringifyComment, addComment } from './stringifyComment.js';
|
|
4
4
|
|
|
5
5
|
function stringifyDocument(doc, options) {
|
|
6
6
|
const lines = [];
|
|
@@ -19,7 +19,7 @@ function stringifyDocument(doc, options) {
|
|
|
19
19
|
if (doc.commentBefore) {
|
|
20
20
|
if (lines.length !== 1)
|
|
21
21
|
lines.unshift('');
|
|
22
|
-
lines.unshift(doc.commentBefore
|
|
22
|
+
lines.unshift(stringifyComment(doc.commentBefore, ''));
|
|
23
23
|
}
|
|
24
24
|
const ctx = createStringifyContext(doc, options);
|
|
25
25
|
let chompKeep = false;
|
|
@@ -29,7 +29,7 @@ function stringifyDocument(doc, options) {
|
|
|
29
29
|
if (doc.contents.spaceBefore && hasDirectives)
|
|
30
30
|
lines.push('');
|
|
31
31
|
if (doc.contents.commentBefore)
|
|
32
|
-
lines.push(doc.contents.commentBefore
|
|
32
|
+
lines.push(stringifyComment(doc.contents.commentBefore, ''));
|
|
33
33
|
// top-level block scalars need to be indented if followed by a comment
|
|
34
34
|
ctx.forceBlockIndent = !!doc.comment;
|
|
35
35
|
contentComment = doc.contents.comment;
|
|
@@ -50,10 +50,13 @@ function stringifyDocument(doc, options) {
|
|
|
50
50
|
else {
|
|
51
51
|
lines.push(stringify(doc.contents, ctx));
|
|
52
52
|
}
|
|
53
|
-
|
|
53
|
+
let dc = doc.comment;
|
|
54
|
+
if (dc && chompKeep)
|
|
55
|
+
dc = dc.replace(/^\n+/, '');
|
|
56
|
+
if (dc) {
|
|
54
57
|
if ((!chompKeep || contentComment) && lines[lines.length - 1] !== '')
|
|
55
58
|
lines.push('');
|
|
56
|
-
lines.push(
|
|
59
|
+
lines.push(stringifyComment(dc, ''));
|
|
57
60
|
}
|
|
58
61
|
return lines.join('\n') + '\n';
|
|
59
62
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isCollection, isNode, isScalar, isSeq } from '../nodes/Node.js';
|
|
2
2
|
import { Scalar } from '../nodes/Scalar.js';
|
|
3
|
-
import { addComment } from './addComment.js';
|
|
4
3
|
import { stringify } from './stringify.js';
|
|
4
|
+
import { addComment, stringifyComment } from './stringifyComment.js';
|
|
5
5
|
|
|
6
6
|
function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
|
|
7
7
|
const { allNullValues, doc, indent, indentStep, options: { indentSeq, simpleKeys } } = ctx;
|
|
@@ -59,10 +59,8 @@ function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
|
|
|
59
59
|
if (isNode(value)) {
|
|
60
60
|
if (value.spaceBefore)
|
|
61
61
|
vcb = '\n';
|
|
62
|
-
if (value.commentBefore)
|
|
63
|
-
|
|
64
|
-
vcb += `\n${cs}`;
|
|
65
|
-
}
|
|
62
|
+
if (value.commentBefore)
|
|
63
|
+
vcb += `\n${stringifyComment(value.commentBefore, ctx.indent)}`;
|
|
66
64
|
valueComment = value.comment;
|
|
67
65
|
}
|
|
68
66
|
else if (value && typeof value === 'object') {
|
|
@@ -14,8 +14,8 @@ function composeDoc(options, directives, { offset, start, value, end }, onError)
|
|
|
14
14
|
schema: doc.schema
|
|
15
15
|
};
|
|
16
16
|
const props = resolveProps.resolveProps(start, {
|
|
17
|
-
ctx,
|
|
18
17
|
indicator: 'doc-start',
|
|
18
|
+
next: value || (end === null || end === void 0 ? void 0 : end[0]),
|
|
19
19
|
offset,
|
|
20
20
|
onError,
|
|
21
21
|
startOnNewline: true
|
package/dist/compose/composer.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { ParsedNode } from '../nodes/Node.js';
|
|
1
2
|
import { YAMLMap } from '../nodes/YAMLMap.js';
|
|
2
3
|
import type { BlockMap } from '../parse/cst.js';
|
|
3
4
|
import type { ComposeContext, ComposeNode } from './compose-node.js';
|
|
4
5
|
import type { ComposeErrorHandler } from './composer.js';
|
|
5
|
-
export declare function resolveBlockMap({ composeNode, composeEmptyNode }: ComposeNode, ctx: ComposeContext, bm: BlockMap, onError: ComposeErrorHandler): YAMLMap.Parsed<
|
|
6
|
+
export declare function resolveBlockMap({ composeNode, composeEmptyNode }: ComposeNode, ctx: ComposeContext, bm: BlockMap, onError: ComposeErrorHandler): YAMLMap.Parsed<ParsedNode, ParsedNode | null>;
|
|
@@ -4,6 +4,7 @@ var Pair = require('../nodes/Pair.js');
|
|
|
4
4
|
var YAMLMap = require('../nodes/YAMLMap.js');
|
|
5
5
|
var resolveProps = require('./resolve-props.js');
|
|
6
6
|
var utilContainsNewline = require('./util-contains-newline.js');
|
|
7
|
+
var utilMapIncludes = require('./util-map-includes.js');
|
|
7
8
|
|
|
8
9
|
const startColMsg = 'All mapping items must start at the same column';
|
|
9
10
|
function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
|
|
@@ -13,8 +14,8 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
|
|
|
13
14
|
for (const { start, key, sep, value } of bm.items) {
|
|
14
15
|
// key properties
|
|
15
16
|
const keyProps = resolveProps.resolveProps(start, {
|
|
16
|
-
ctx,
|
|
17
17
|
indicator: 'explicit-key-ind',
|
|
18
|
+
next: key || (sep === null || sep === void 0 ? void 0 : sep[0]),
|
|
18
19
|
offset,
|
|
19
20
|
onError,
|
|
20
21
|
startOnNewline: true
|
|
@@ -48,10 +49,12 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
|
|
|
48
49
|
const keyNode = key
|
|
49
50
|
? composeNode(ctx, key, keyProps, onError)
|
|
50
51
|
: composeEmptyNode(ctx, keyStart, start, null, keyProps, onError);
|
|
52
|
+
if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
|
|
53
|
+
onError(keyStart, 'DUPLICATE_KEY', 'Map keys must be unique');
|
|
51
54
|
// value properties
|
|
52
55
|
const valueProps = resolveProps.resolveProps(sep || [], {
|
|
53
|
-
ctx,
|
|
54
56
|
indicator: 'map-value-ind',
|
|
57
|
+
next: value,
|
|
55
58
|
offset: keyNode.range[2],
|
|
56
59
|
onError,
|
|
57
60
|
startOnNewline: !key || key.type === 'block-scalar'
|
|
@@ -151,7 +151,7 @@ function parseBlockScalarHeader({ offset, props }, strict, onError) {
|
|
|
151
151
|
case 'comment':
|
|
152
152
|
if (strict && !hasSpace) {
|
|
153
153
|
const message = 'Comments must be separated from other tokens by white space characters';
|
|
154
|
-
onError(token, '
|
|
154
|
+
onError(token, 'MISSING_CHAR', message);
|
|
155
155
|
}
|
|
156
156
|
length += token.source.length;
|
|
157
157
|
comment = token.source.substring(1);
|
|
@@ -8,8 +8,8 @@ function resolveBlockSeq({ composeNode, composeEmptyNode }, ctx, bs, onError) {
|
|
|
8
8
|
let offset = bs.offset;
|
|
9
9
|
for (const { start, value } of bs.items) {
|
|
10
10
|
const props = resolveProps.resolveProps(start, {
|
|
11
|
-
ctx,
|
|
12
11
|
indicator: 'seq-item-ind',
|
|
12
|
+
next: value,
|
|
13
13
|
offset,
|
|
14
14
|
onError,
|
|
15
15
|
startOnNewline: true
|
|
@@ -13,8 +13,8 @@ function resolveEnd(end, offset, reqSpace, onError) {
|
|
|
13
13
|
break;
|
|
14
14
|
case 'comment': {
|
|
15
15
|
if (reqSpace && !hasSpace)
|
|
16
|
-
onError(token, '
|
|
17
|
-
const cb = source.substring(1);
|
|
16
|
+
onError(token, 'MISSING_CHAR', 'Comments must be separated from other tokens by white space characters');
|
|
17
|
+
const cb = source.substring(1) || ' ';
|
|
18
18
|
if (!comment)
|
|
19
19
|
comment = cb;
|
|
20
20
|
else
|