yaml 2.0.0-5 → 2.0.0-9
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/compose-node.js +10 -1
- package/browser/dist/compose/compose-scalar.js +2 -1
- package/browser/dist/compose/composer.js +3 -2
- package/browser/dist/compose/resolve-block-map.js +15 -5
- package/browser/dist/compose/resolve-block-scalar.js +2 -2
- 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 +14 -6
- package/browser/dist/compose/resolve-flow-scalar.js +19 -7
- package/browser/dist/compose/resolve-props.js +30 -7
- package/browser/dist/compose/util-map-includes.js +17 -0
- package/browser/dist/doc/Document.js +26 -2
- package/browser/dist/doc/createNode.js +11 -5
- package/browser/dist/doc/directives.js +5 -0
- package/browser/dist/node_modules/tslib/tslib.es6.js +164 -0
- package/browser/dist/nodes/Collection.js +28 -15
- package/browser/dist/nodes/Node.js +7 -0
- package/browser/dist/nodes/Pair.js +9 -1
- package/browser/dist/nodes/addPairToJSMap.js +4 -3
- package/browser/dist/options.js +2 -0
- package/browser/dist/parse/cst-scalar.js +2 -6
- package/browser/dist/parse/lexer.js +64 -31
- package/browser/dist/parse/parser.js +53 -52
- package/browser/dist/schema/Schema.js +5 -0
- package/browser/dist/schema/tags.js +9 -5
- package/browser/dist/stringify/stringify.js +2 -1
- 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 +5 -7
- package/browser/dist/stringify/stringifyString.js +35 -34
- package/browser/dist/util.js +3 -0
- package/dist/compose/compose-doc.js +1 -1
- package/dist/compose/compose-node.js +10 -1
- package/dist/compose/compose-scalar.js +2 -1
- package/dist/compose/composer.js +3 -2
- package/dist/compose/resolve-block-map.d.ts +2 -1
- package/dist/compose/resolve-block-map.js +15 -5
- package/dist/compose/resolve-block-scalar.js +2 -2
- package/dist/compose/resolve-block-seq.js +1 -1
- package/dist/compose/resolve-end.js +2 -2
- package/dist/compose/resolve-flow-collection.js +14 -6
- package/dist/compose/resolve-flow-scalar.js +19 -7
- 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 +10 -2
- package/dist/doc/Document.js +25 -1
- package/dist/doc/createNode.d.ts +2 -1
- package/dist/doc/createNode.js +10 -4
- package/dist/doc/directives.d.ts +1 -0
- package/dist/doc/directives.js +5 -0
- package/dist/errors.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/node_modules/tslib/tslib.es6.js +76 -0
- package/dist/nodes/Alias.d.ts +7 -3
- package/dist/nodes/Collection.d.ts +10 -4
- package/dist/nodes/Collection.js +27 -14
- package/dist/nodes/Node.d.ts +10 -3
- package/dist/nodes/Node.js +7 -0
- package/dist/nodes/Pair.d.ts +7 -2
- package/dist/nodes/Pair.js +8 -0
- package/dist/nodes/Scalar.d.ts +2 -0
- package/dist/nodes/YAMLMap.d.ts +2 -0
- package/dist/nodes/YAMLSeq.d.ts +2 -0
- package/dist/nodes/addPairToJSMap.js +3 -2
- package/dist/options.d.ts +40 -3
- package/dist/options.js +2 -0
- package/dist/parse/cst-scalar.d.ts +6 -0
- package/dist/parse/cst-scalar.js +2 -6
- package/dist/parse/lexer.d.ts +3 -1
- package/dist/parse/lexer.js +64 -31
- package/dist/parse/parser.d.ts +1 -0
- package/dist/parse/parser.js +53 -52
- package/dist/schema/Schema.d.ts +1 -0
- package/dist/schema/Schema.js +5 -0
- package/dist/schema/tags.js +9 -5
- package/dist/stringify/stringify.js +2 -1
- 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 +9 -11
- package/dist/stringify/stringifyString.js +35 -34
- package/dist/test-events.d.ts +1 -1
- package/dist/util.d.ts +3 -0
- package/dist/util.js +6 -0
- package/package.json +9 -8
- package/util.d.ts +3 -0
- 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
|
|
@@ -33,6 +33,8 @@ function composeNode(ctx, token, props, onError) {
|
|
|
33
33
|
console.log(token);
|
|
34
34
|
throw new Error(`Unsupporten token type: ${token.type}`);
|
|
35
35
|
}
|
|
36
|
+
if (anchor && node.anchor === '')
|
|
37
|
+
onError(anchor, 'BAD_ALIAS', 'Anchor cannot be an empty string');
|
|
36
38
|
if (spaceBefore)
|
|
37
39
|
node.spaceBefore = true;
|
|
38
40
|
if (comment) {
|
|
@@ -41,6 +43,8 @@ function composeNode(ctx, token, props, onError) {
|
|
|
41
43
|
else
|
|
42
44
|
node.commentBefore = comment;
|
|
43
45
|
}
|
|
46
|
+
if (ctx.options.keepSourceTokens)
|
|
47
|
+
node.srcToken = token;
|
|
44
48
|
return node;
|
|
45
49
|
}
|
|
46
50
|
function composeEmptyNode(ctx, offset, before, pos, { spaceBefore, comment, anchor, tag }, onError) {
|
|
@@ -51,8 +55,11 @@ function composeEmptyNode(ctx, offset, before, pos, { spaceBefore, comment, anch
|
|
|
51
55
|
source: ''
|
|
52
56
|
};
|
|
53
57
|
const node = composeScalar(ctx, token, tag, onError);
|
|
54
|
-
if (anchor)
|
|
58
|
+
if (anchor) {
|
|
55
59
|
node.anchor = anchor.source.substring(1);
|
|
60
|
+
if (node.anchor === '')
|
|
61
|
+
onError(anchor, 'BAD_ALIAS', 'Anchor cannot be an empty string');
|
|
62
|
+
}
|
|
56
63
|
if (spaceBefore)
|
|
57
64
|
node.spaceBefore = true;
|
|
58
65
|
if (comment)
|
|
@@ -61,6 +68,8 @@ function composeEmptyNode(ctx, offset, before, pos, { spaceBefore, comment, anch
|
|
|
61
68
|
}
|
|
62
69
|
function composeAlias({ options }, { offset, source, end }, onError) {
|
|
63
70
|
const alias = new Alias(source.substring(1));
|
|
71
|
+
if (alias.source === '')
|
|
72
|
+
onError(offset, 'BAD_ALIAS', 'Alias cannot be an empty string');
|
|
64
73
|
const valueEnd = offset + source.length;
|
|
65
74
|
const re = resolveEnd(end, valueEnd, options.strict, onError);
|
|
66
75
|
alias.range = [offset, valueEnd, re.offset];
|
|
@@ -19,7 +19,8 @@ function composeScalar(ctx, token, tagToken, onError) {
|
|
|
19
19
|
scalar = isScalar(res) ? res : new Scalar(res);
|
|
20
20
|
}
|
|
21
21
|
catch (error) {
|
|
22
|
-
|
|
22
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
23
|
+
onError(tagToken || token, 'TAG_RESOLVE_FAILED', msg);
|
|
23
24
|
scalar = new Scalar(value);
|
|
24
25
|
}
|
|
25
26
|
scalar.range = range;
|
|
@@ -15,6 +15,7 @@ function getErrorPos(src) {
|
|
|
15
15
|
return [offset, offset + (typeof source === 'string' ? source.length : 1)];
|
|
16
16
|
}
|
|
17
17
|
function parsePrelude(prelude) {
|
|
18
|
+
var _a;
|
|
18
19
|
let comment = '';
|
|
19
20
|
let atComment = false;
|
|
20
21
|
let afterEmptyLine = false;
|
|
@@ -24,12 +25,12 @@ function parsePrelude(prelude) {
|
|
|
24
25
|
case '#':
|
|
25
26
|
comment +=
|
|
26
27
|
(comment === '' ? '' : afterEmptyLine ? '\n\n' : '\n') +
|
|
27
|
-
source.substring(1);
|
|
28
|
+
(source.substring(1) || ' ');
|
|
28
29
|
atComment = true;
|
|
29
30
|
afterEmptyLine = false;
|
|
30
31
|
break;
|
|
31
32
|
case '%':
|
|
32
|
-
if (prelude[i + 1][0] !== '#')
|
|
33
|
+
if (((_a = prelude[i + 1]) === null || _a === void 0 ? void 0 : _a[0]) !== '#')
|
|
33
34
|
i += 1;
|
|
34
35
|
atComment = false;
|
|
35
36
|
break;
|
|
@@ -2,17 +2,19 @@ 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) {
|
|
8
9
|
var _a;
|
|
9
10
|
const map = new YAMLMap(ctx.schema);
|
|
10
11
|
let offset = bm.offset;
|
|
11
|
-
for (const
|
|
12
|
+
for (const collItem of bm.items) {
|
|
13
|
+
const { start, key, sep, value } = collItem;
|
|
12
14
|
// key properties
|
|
13
15
|
const keyProps = resolveProps(start, {
|
|
14
|
-
ctx,
|
|
15
16
|
indicator: 'explicit-key-ind',
|
|
17
|
+
next: key || (sep === null || sep === void 0 ? void 0 : sep[0]),
|
|
16
18
|
offset,
|
|
17
19
|
onError,
|
|
18
20
|
startOnNewline: true
|
|
@@ -46,10 +48,12 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
|
|
|
46
48
|
const keyNode = key
|
|
47
49
|
? composeNode(ctx, key, keyProps, onError)
|
|
48
50
|
: composeEmptyNode(ctx, keyStart, start, null, keyProps, onError);
|
|
51
|
+
if (mapIncludes(ctx, map.items, keyNode))
|
|
52
|
+
onError(keyStart, 'DUPLICATE_KEY', 'Map keys must be unique');
|
|
49
53
|
// value properties
|
|
50
54
|
const valueProps = resolveProps(sep || [], {
|
|
51
|
-
ctx,
|
|
52
55
|
indicator: 'map-value-ind',
|
|
56
|
+
next: value,
|
|
53
57
|
offset: keyNode.range[2],
|
|
54
58
|
onError,
|
|
55
59
|
startOnNewline: !key || key.type === 'block-scalar'
|
|
@@ -68,7 +72,10 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
|
|
|
68
72
|
? composeNode(ctx, value, valueProps, onError)
|
|
69
73
|
: composeEmptyNode(ctx, offset, sep, null, valueProps, onError);
|
|
70
74
|
offset = valueNode.range[2];
|
|
71
|
-
|
|
75
|
+
const pair = new Pair(keyNode, valueNode);
|
|
76
|
+
if (ctx.options.keepSourceTokens)
|
|
77
|
+
pair.srcToken = collItem;
|
|
78
|
+
map.items.push(pair);
|
|
72
79
|
}
|
|
73
80
|
else {
|
|
74
81
|
// key with no value
|
|
@@ -80,7 +87,10 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
|
|
|
80
87
|
else
|
|
81
88
|
keyNode.comment = valueProps.comment;
|
|
82
89
|
}
|
|
83
|
-
|
|
90
|
+
const pair = new Pair(keyNode);
|
|
91
|
+
if (ctx.options.keepSourceTokens)
|
|
92
|
+
pair.srcToken = collItem;
|
|
93
|
+
map.items.push(pair);
|
|
84
94
|
}
|
|
85
95
|
}
|
|
86
96
|
map.range = [bm.offset, offset, offset];
|
|
@@ -18,7 +18,7 @@ function resolveBlockScalar(scalar, strict, onError) {
|
|
|
18
18
|
}
|
|
19
19
|
// shortcut for empty contents
|
|
20
20
|
if (!scalar.source || chompStart === 0) {
|
|
21
|
-
const value = header.chomp === '+' ?
|
|
21
|
+
const value = header.chomp === '+' ? '\n'.repeat(Math.max(0, lines.length - 1)) : '';
|
|
22
22
|
let end = start + header.length;
|
|
23
23
|
if (scalar.source)
|
|
24
24
|
end += scalar.source.length;
|
|
@@ -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');
|
|
@@ -17,11 +18,12 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
17
18
|
coll.flow = true;
|
|
18
19
|
let offset = fc.offset;
|
|
19
20
|
for (let i = 0; i < fc.items.length; ++i) {
|
|
20
|
-
const
|
|
21
|
+
const collItem = fc.items[i];
|
|
22
|
+
const { start, key, sep, value } = collItem;
|
|
21
23
|
const props = resolveProps(start, {
|
|
22
|
-
ctx,
|
|
23
24
|
flow: fcName,
|
|
24
25
|
indicator: 'explicit-key-ind',
|
|
26
|
+
next: key || (sep === null || sep === void 0 ? void 0 : sep[0]),
|
|
25
27
|
offset,
|
|
26
28
|
onError,
|
|
27
29
|
startOnNewline: false
|
|
@@ -99,9 +101,9 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
99
101
|
onError(keyNode.range, 'BLOCK_IN_FLOW', blockMsg);
|
|
100
102
|
// value properties
|
|
101
103
|
const valueProps = resolveProps(sep || [], {
|
|
102
|
-
ctx,
|
|
103
104
|
flow: fcName,
|
|
104
105
|
indicator: 'map-value-ind',
|
|
106
|
+
next: value,
|
|
105
107
|
offset: keyNode.range[2],
|
|
106
108
|
onError,
|
|
107
109
|
startOnNewline: false
|
|
@@ -144,8 +146,14 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
144
146
|
keyNode.comment = valueProps.comment;
|
|
145
147
|
}
|
|
146
148
|
const pair = new Pair(keyNode, valueNode);
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
+
if (ctx.options.keepSourceTokens)
|
|
150
|
+
pair.srcToken = collItem;
|
|
151
|
+
if (isMap) {
|
|
152
|
+
const map = coll;
|
|
153
|
+
if (mapIncludes(ctx, map.items, keyNode))
|
|
154
|
+
onError(keyStart, 'DUPLICATE_KEY', 'Map keys must be unique');
|
|
155
|
+
map.items.push(pair);
|
|
156
|
+
}
|
|
149
157
|
else {
|
|
150
158
|
const map = new YAMLMap(ctx.schema);
|
|
151
159
|
map.flow = true;
|
|
@@ -159,7 +167,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
159
167
|
const [ce, ...ee] = fc.end;
|
|
160
168
|
let cePos = offset;
|
|
161
169
|
if (ce && ce.source === expectedEnd)
|
|
162
|
-
cePos
|
|
170
|
+
cePos = ce.offset + ce.source.length;
|
|
163
171
|
else {
|
|
164
172
|
onError(offset + 1, 'MISSING_CHAR', `Expected ${fcName} to end with ${expectedEnd}`);
|
|
165
173
|
if (ce && ce.source.length !== 1)
|
|
@@ -39,25 +39,31 @@ function resolveFlowScalar(scalar, strict, onError) {
|
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
function plainValue(source, onError) {
|
|
42
|
-
let
|
|
42
|
+
let badChar = '';
|
|
43
43
|
switch (source[0]) {
|
|
44
44
|
/* istanbul ignore next should not happen */
|
|
45
45
|
case '\t':
|
|
46
|
-
|
|
46
|
+
badChar = 'a tab character';
|
|
47
|
+
break;
|
|
48
|
+
case ',':
|
|
49
|
+
badChar = 'flow indicator character ,';
|
|
50
|
+
break;
|
|
51
|
+
case '%':
|
|
52
|
+
badChar = 'directive indicator character %';
|
|
47
53
|
break;
|
|
48
54
|
case '|':
|
|
49
55
|
case '>': {
|
|
50
|
-
|
|
56
|
+
badChar = `block scalar indicator ${source[0]}`;
|
|
51
57
|
break;
|
|
52
58
|
}
|
|
53
59
|
case '@':
|
|
54
60
|
case '`': {
|
|
55
|
-
|
|
61
|
+
badChar = `reserved character ${source[0]}`;
|
|
56
62
|
break;
|
|
57
63
|
}
|
|
58
64
|
}
|
|
59
|
-
if (
|
|
60
|
-
onError(0, 'BAD_SCALAR_START',
|
|
65
|
+
if (badChar)
|
|
66
|
+
onError(0, 'BAD_SCALAR_START', `Plain value cannot start with ${badChar}`);
|
|
61
67
|
return foldLines(source);
|
|
62
68
|
}
|
|
63
69
|
function singleQuotedValue(source, onError) {
|
|
@@ -129,6 +135,12 @@ function doubleQuotedValue(source, onError) {
|
|
|
129
135
|
while (next === ' ' || next === '\t')
|
|
130
136
|
next = source[++i + 1];
|
|
131
137
|
}
|
|
138
|
+
else if (next === '\r' && source[i + 1] === '\n') {
|
|
139
|
+
// skip escaped CRLF newlines, but still trim the following line
|
|
140
|
+
next = source[++i + 1];
|
|
141
|
+
while (next === ' ' || next === '\t')
|
|
142
|
+
next = source[++i + 1];
|
|
143
|
+
}
|
|
132
144
|
else if (next === 'x' || next === 'u' || next === 'U') {
|
|
133
145
|
const length = { x: 2, u: 4, U: 8 }[next];
|
|
134
146
|
res += parseCharCode(source, i + 1, length, onError);
|
|
@@ -146,7 +158,7 @@ function doubleQuotedValue(source, onError) {
|
|
|
146
158
|
let next = source[i + 1];
|
|
147
159
|
while (next === ' ' || next === '\t')
|
|
148
160
|
next = source[++i + 1];
|
|
149
|
-
if (next !== '\n')
|
|
161
|
+
if (next !== '\n' && !(next === '\r' && source[i + 2] === '\n'))
|
|
150
162
|
res += i > wsStart ? source.slice(wsStart, i + 1) : ch;
|
|
151
163
|
}
|
|
152
164
|
else {
|
|
@@ -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 };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Alias } from '../nodes/Alias.js';
|
|
2
2
|
import { isEmptyPath, collectionFromPath } from '../nodes/Collection.js';
|
|
3
|
-
import { NODE_TYPE, DOC, isCollection, isScalar } from '../nodes/Node.js';
|
|
3
|
+
import { NODE_TYPE, DOC, isNode, isCollection, isScalar } from '../nodes/Node.js';
|
|
4
4
|
import { Pair } from '../nodes/Pair.js';
|
|
5
5
|
import { toJS } from '../nodes/toJS.js';
|
|
6
6
|
import { defaultOptions } from '../options.js';
|
|
@@ -48,6 +48,29 @@ class Document {
|
|
|
48
48
|
this.contents = this.createNode(value, _replacer, options);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Create a deep copy of this Document and its contents.
|
|
53
|
+
*
|
|
54
|
+
* Custom Node values that inherit from `Object` still refer to their original instances.
|
|
55
|
+
*/
|
|
56
|
+
clone() {
|
|
57
|
+
const copy = Object.create(Document.prototype, {
|
|
58
|
+
[NODE_TYPE]: { value: DOC }
|
|
59
|
+
});
|
|
60
|
+
copy.commentBefore = this.commentBefore;
|
|
61
|
+
copy.comment = this.comment;
|
|
62
|
+
copy.errors = this.errors.slice();
|
|
63
|
+
copy.warnings = this.warnings.slice();
|
|
64
|
+
copy.options = Object.assign({}, this.options);
|
|
65
|
+
copy.directives = this.directives.clone();
|
|
66
|
+
copy.schema = this.schema.clone();
|
|
67
|
+
copy.contents = isNode(this.contents)
|
|
68
|
+
? this.contents.clone(copy.schema)
|
|
69
|
+
: this.contents;
|
|
70
|
+
if (this.range)
|
|
71
|
+
copy.range = this.range.slice();
|
|
72
|
+
return copy;
|
|
73
|
+
}
|
|
51
74
|
/** Adds a value to the document. */
|
|
52
75
|
add(value) {
|
|
53
76
|
if (assertCollection(this.contents))
|
|
@@ -92,9 +115,10 @@ class Document {
|
|
|
92
115
|
options = replacer;
|
|
93
116
|
replacer = undefined;
|
|
94
117
|
}
|
|
95
|
-
const { anchorPrefix, flow, keepUndefined, onTagObj, tag } = options || {};
|
|
118
|
+
const { aliasDuplicateObjects, anchorPrefix, flow, keepUndefined, onTagObj, tag } = options || {};
|
|
96
119
|
const { onAnchor, setAnchors, sourceObjects } = createNodeAnchors(this, anchorPrefix || 'a');
|
|
97
120
|
const ctx = {
|
|
121
|
+
aliasDuplicateObjects: aliasDuplicateObjects !== null && aliasDuplicateObjects !== void 0 ? aliasDuplicateObjects : true,
|
|
98
122
|
keepUndefined: keepUndefined !== null && keepUndefined !== void 0 ? keepUndefined : false,
|
|
99
123
|
onAnchor,
|
|
100
124
|
onTagObj,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Alias } from '../nodes/Alias.js';
|
|
2
|
-
import { isNode, isPair, MAP, SEQ } from '../nodes/Node.js';
|
|
2
|
+
import { isNode, isPair, MAP, SEQ, isDocument } from '../nodes/Node.js';
|
|
3
3
|
import { Scalar } from '../nodes/Scalar.js';
|
|
4
4
|
|
|
5
5
|
const defaultTagPrefix = 'tag:yaml.org,2002:';
|
|
@@ -15,6 +15,8 @@ function findTagObject(value, tagName, tags) {
|
|
|
15
15
|
}
|
|
16
16
|
function createNode(value, tagName, ctx) {
|
|
17
17
|
var _a, _b;
|
|
18
|
+
if (isDocument(value))
|
|
19
|
+
value = value.contents;
|
|
18
20
|
if (isNode(value))
|
|
19
21
|
return value;
|
|
20
22
|
if (isPair(value)) {
|
|
@@ -30,11 +32,11 @@ function createNode(value, tagName, ctx) {
|
|
|
30
32
|
// https://tc39.es/ecma262/#sec-serializejsonproperty
|
|
31
33
|
value = value.valueOf();
|
|
32
34
|
}
|
|
33
|
-
const { onAnchor, onTagObj, schema, sourceObjects } = ctx;
|
|
35
|
+
const { aliasDuplicateObjects, onAnchor, onTagObj, schema, sourceObjects } = ctx;
|
|
34
36
|
// Detect duplicate references to the same object & use Alias nodes for all
|
|
35
37
|
// after first. The `ref` wrapper allows for circular references to resolve.
|
|
36
38
|
let ref = undefined;
|
|
37
|
-
if (value && typeof value === 'object') {
|
|
39
|
+
if (aliasDuplicateObjects && value && typeof value === 'object') {
|
|
38
40
|
ref = sourceObjects.get(value);
|
|
39
41
|
if (ref) {
|
|
40
42
|
if (!ref.anchor)
|
|
@@ -52,8 +54,12 @@ function createNode(value, tagName, ctx) {
|
|
|
52
54
|
if (!tagObj) {
|
|
53
55
|
if (value && typeof value.toJSON === 'function')
|
|
54
56
|
value = value.toJSON();
|
|
55
|
-
if (!value || typeof value !== 'object')
|
|
56
|
-
|
|
57
|
+
if (!value || typeof value !== 'object') {
|
|
58
|
+
const node = new Scalar(value);
|
|
59
|
+
if (ref)
|
|
60
|
+
ref.node = node;
|
|
61
|
+
return node;
|
|
62
|
+
}
|
|
57
63
|
tagObj =
|
|
58
64
|
value instanceof Map
|
|
59
65
|
? schema[MAP]
|
|
@@ -20,6 +20,11 @@ class Directives {
|
|
|
20
20
|
this.yaml = Object.assign({}, Directives.defaultYaml, yaml);
|
|
21
21
|
this.tags = Object.assign({}, Directives.defaultTags, tags);
|
|
22
22
|
}
|
|
23
|
+
clone() {
|
|
24
|
+
const copy = new Directives(this.yaml, this.tags);
|
|
25
|
+
copy.marker = this.marker;
|
|
26
|
+
return copy;
|
|
27
|
+
}
|
|
23
28
|
/**
|
|
24
29
|
* During parsing, get a Directives instance for the current document and
|
|
25
30
|
* update the stream state according to the current version's spec.
|