yaml 2.4.4 → 2.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/browser/dist/compose/compose-collection.js +15 -3
- package/browser/dist/compose/compose-doc.js +1 -0
- package/browser/dist/compose/compose-node.js +1 -1
- package/browser/dist/compose/compose-scalar.js +1 -1
- package/browser/dist/compose/resolve-block-map.js +3 -1
- package/browser/dist/compose/resolve-block-scalar.js +6 -2
- package/browser/dist/compose/resolve-block-seq.js +1 -0
- package/browser/dist/compose/resolve-flow-collection.js +2 -0
- package/browser/dist/compose/resolve-props.js +12 -9
- package/browser/dist/nodes/Collection.js +0 -1
- package/browser/dist/parse/cst-scalar.js +1 -1
- package/browser/dist/parse/lexer.js +15 -8
- package/browser/dist/stringify/foldFlowLines.js +2 -0
- package/dist/cli.d.ts +1 -2
- package/dist/cli.mjs +8 -4
- package/dist/compose/compose-collection.d.ts +7 -1
- package/dist/compose/compose-collection.js +15 -3
- package/dist/compose/compose-doc.js +1 -0
- package/dist/compose/compose-node.d.ts +1 -0
- package/dist/compose/compose-node.js +1 -1
- package/dist/compose/compose-scalar.js +1 -1
- package/dist/compose/resolve-block-map.d.ts +1 -2
- package/dist/compose/resolve-block-map.js +3 -1
- package/dist/compose/resolve-block-scalar.d.ts +2 -1
- package/dist/compose/resolve-block-scalar.js +6 -2
- package/dist/compose/resolve-block-seq.d.ts +1 -1
- package/dist/compose/resolve-block-seq.js +1 -0
- package/dist/compose/resolve-flow-collection.js +2 -0
- package/dist/compose/resolve-props.d.ts +3 -2
- package/dist/compose/resolve-props.js +12 -9
- package/dist/nodes/Collection.d.ts +0 -1
- package/dist/nodes/Collection.js +0 -1
- package/dist/nodes/identity.d.ts +1 -1
- package/dist/parse/cst-scalar.js +1 -1
- package/dist/parse/lexer.js +15 -8
- package/dist/schema/yaml-1.1/omap.d.ts +3 -3
- package/dist/stringify/foldFlowLines.js +2 -0
- package/package.json +1 -1
|
@@ -23,10 +23,23 @@ function resolveCollection(CN, ctx, token, onError, tagName, tag) {
|
|
|
23
23
|
coll.tag = tagName;
|
|
24
24
|
return coll;
|
|
25
25
|
}
|
|
26
|
-
function composeCollection(CN, ctx, token,
|
|
26
|
+
function composeCollection(CN, ctx, token, props, onError) {
|
|
27
|
+
const tagToken = props.tag;
|
|
27
28
|
const tagName = !tagToken
|
|
28
29
|
? null
|
|
29
30
|
: ctx.directives.tagName(tagToken.source, msg => onError(tagToken, 'TAG_RESOLVE_FAILED', msg));
|
|
31
|
+
if (token.type === 'block-seq') {
|
|
32
|
+
const { anchor, newlineAfterProp: nl } = props;
|
|
33
|
+
const lastProp = anchor && tagToken
|
|
34
|
+
? anchor.offset > tagToken.offset
|
|
35
|
+
? anchor
|
|
36
|
+
: tagToken
|
|
37
|
+
: (anchor ?? tagToken);
|
|
38
|
+
if (lastProp && (!nl || nl.offset < lastProp.offset)) {
|
|
39
|
+
const message = 'Missing newline after block sequence props';
|
|
40
|
+
onError(lastProp, 'MISSING_CHAR', message);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
30
43
|
const expType = token.type === 'block-map'
|
|
31
44
|
? 'map'
|
|
32
45
|
: token.type === 'block-seq'
|
|
@@ -40,8 +53,7 @@ function composeCollection(CN, ctx, token, tagToken, onError) {
|
|
|
40
53
|
!tagName ||
|
|
41
54
|
tagName === '!' ||
|
|
42
55
|
(tagName === YAMLMap.tagName && expType === 'map') ||
|
|
43
|
-
(tagName === YAMLSeq.tagName && expType === 'seq')
|
|
44
|
-
!expType) {
|
|
56
|
+
(tagName === YAMLSeq.tagName && expType === 'seq')) {
|
|
45
57
|
return resolveCollection(CN, ctx, token, onError, tagName);
|
|
46
58
|
}
|
|
47
59
|
let tag = ctx.schema.tags.find(t => t.tag === tagName && t.collection === expType);
|
|
@@ -26,7 +26,7 @@ function composeNode(ctx, token, props, onError) {
|
|
|
26
26
|
case 'block-map':
|
|
27
27
|
case 'block-seq':
|
|
28
28
|
case 'flow-collection':
|
|
29
|
-
node = composeCollection(CN, ctx, token,
|
|
29
|
+
node = composeCollection(CN, ctx, token, props, onError);
|
|
30
30
|
if (anchor)
|
|
31
31
|
node.anchor = anchor.source.substring(1);
|
|
32
32
|
break;
|
|
@@ -5,7 +5,7 @@ import { resolveFlowScalar } from './resolve-flow-scalar.js';
|
|
|
5
5
|
|
|
6
6
|
function composeScalar(ctx, token, tagToken, onError) {
|
|
7
7
|
const { value, type, comment, range } = token.type === 'block-scalar'
|
|
8
|
-
? resolveBlockScalar(
|
|
8
|
+
? resolveBlockScalar(ctx, token, onError)
|
|
9
9
|
: resolveFlowScalar(token, ctx.options.strict, onError);
|
|
10
10
|
const tagName = tagToken
|
|
11
11
|
? ctx.directives.tagName(tagToken.source, msg => onError(tagToken, 'TAG_RESOLVE_FAILED', msg))
|
|
@@ -21,6 +21,7 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError, ta
|
|
|
21
21
|
next: key ?? sep?.[0],
|
|
22
22
|
offset,
|
|
23
23
|
onError,
|
|
24
|
+
parentIndent: bm.indent,
|
|
24
25
|
startOnNewline: true
|
|
25
26
|
});
|
|
26
27
|
const implicitKey = !keyProps.found;
|
|
@@ -41,7 +42,7 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError, ta
|
|
|
41
42
|
}
|
|
42
43
|
continue;
|
|
43
44
|
}
|
|
44
|
-
if (keyProps.
|
|
45
|
+
if (keyProps.newlineAfterProp || containsNewline(key)) {
|
|
45
46
|
onError(key ?? start[start.length - 1], 'MULTILINE_IMPLICIT_KEY', 'Implicit keys need to be on a single line');
|
|
46
47
|
}
|
|
47
48
|
}
|
|
@@ -63,6 +64,7 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError, ta
|
|
|
63
64
|
next: value,
|
|
64
65
|
offset: keyNode.range[2],
|
|
65
66
|
onError,
|
|
67
|
+
parentIndent: bm.indent,
|
|
66
68
|
startOnNewline: !key || key.type === 'block-scalar'
|
|
67
69
|
});
|
|
68
70
|
offset = valueProps.end;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Scalar } from '../nodes/Scalar.js';
|
|
2
2
|
|
|
3
|
-
function resolveBlockScalar(
|
|
3
|
+
function resolveBlockScalar(ctx, scalar, onError) {
|
|
4
4
|
const start = scalar.offset;
|
|
5
|
-
const header = parseBlockScalarHeader(scalar, strict, onError);
|
|
5
|
+
const header = parseBlockScalarHeader(scalar, ctx.options.strict, onError);
|
|
6
6
|
if (!header)
|
|
7
7
|
return { value: '', type: null, comment: '', range: [start, start, start] };
|
|
8
8
|
const type = header.mode === '>' ? Scalar.BLOCK_FOLDED : Scalar.BLOCK_LITERAL;
|
|
@@ -44,6 +44,10 @@ function resolveBlockScalar(scalar, strict, onError) {
|
|
|
44
44
|
if (header.indent === 0)
|
|
45
45
|
trimIndent = indent.length;
|
|
46
46
|
contentStart = i;
|
|
47
|
+
if (trimIndent === 0 && !ctx.atRoot) {
|
|
48
|
+
const message = 'Block scalar values in collections must be indented';
|
|
49
|
+
onError(offset, 'BAD_INDENT', message);
|
|
50
|
+
}
|
|
47
51
|
break;
|
|
48
52
|
}
|
|
49
53
|
offset += indent.length + content.length + 1;
|
|
@@ -28,6 +28,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
28
28
|
next: key ?? sep?.[0],
|
|
29
29
|
offset,
|
|
30
30
|
onError,
|
|
31
|
+
parentIndent: fc.indent,
|
|
31
32
|
startOnNewline: false
|
|
32
33
|
});
|
|
33
34
|
if (!props.found) {
|
|
@@ -109,6 +110,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
109
110
|
next: value,
|
|
110
111
|
offset: keyNode.range[2],
|
|
111
112
|
onError,
|
|
113
|
+
parentIndent: fc.indent,
|
|
112
114
|
startOnNewline: false
|
|
113
115
|
});
|
|
114
116
|
if (valueProps.found) {
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnNewline }) {
|
|
1
|
+
function resolveProps(tokens, { flow, indicator, next, offset, onError, parentIndent, 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 hasNewlineAfterProp = false;
|
|
9
8
|
let reqSpace = false;
|
|
10
9
|
let tab = null;
|
|
11
10
|
let anchor = null;
|
|
12
11
|
let tag = null;
|
|
12
|
+
let newlineAfterProp = null;
|
|
13
13
|
let comma = null;
|
|
14
14
|
let found = null;
|
|
15
15
|
let start = null;
|
|
@@ -22,7 +22,7 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
|
|
|
22
22
|
reqSpace = false;
|
|
23
23
|
}
|
|
24
24
|
if (tab) {
|
|
25
|
-
if (token.type !== 'comment') {
|
|
25
|
+
if (atNewline && token.type !== 'comment' && token.type !== 'newline') {
|
|
26
26
|
onError(tab, 'TAB_AS_INDENT', 'Tabs are not allowed as indentation');
|
|
27
27
|
}
|
|
28
28
|
tab = null;
|
|
@@ -33,9 +33,8 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
|
|
|
33
33
|
// as leading white space rather than indentation.
|
|
34
34
|
// In a flow collection, only the parser handles indent.
|
|
35
35
|
if (!flow &&
|
|
36
|
-
atNewline &&
|
|
37
36
|
(indicator !== 'doc-start' || next?.type !== 'flow-collection') &&
|
|
38
|
-
token.source
|
|
37
|
+
token.source.includes('\t')) {
|
|
39
38
|
tab = token;
|
|
40
39
|
}
|
|
41
40
|
hasSpace = true;
|
|
@@ -64,7 +63,7 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
|
|
|
64
63
|
atNewline = true;
|
|
65
64
|
hasNewline = true;
|
|
66
65
|
if (anchor || tag)
|
|
67
|
-
|
|
66
|
+
newlineAfterProp = token;
|
|
68
67
|
hasSpace = true;
|
|
69
68
|
break;
|
|
70
69
|
case 'anchor':
|
|
@@ -97,7 +96,8 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
|
|
|
97
96
|
if (found)
|
|
98
97
|
onError(token, 'UNEXPECTED_TOKEN', `Unexpected ${token.source} in ${flow ?? 'collection'}`);
|
|
99
98
|
found = token;
|
|
100
|
-
atNewline =
|
|
99
|
+
atNewline =
|
|
100
|
+
indicator === 'seq-item-ind' || indicator === 'explicit-key-ind';
|
|
101
101
|
hasSpace = false;
|
|
102
102
|
break;
|
|
103
103
|
case 'comma':
|
|
@@ -126,7 +126,10 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
|
|
|
126
126
|
(next.type !== 'scalar' || next.source !== '')) {
|
|
127
127
|
onError(next.offset, 'MISSING_CHAR', 'Tags and anchors must be separated from the next token by white space');
|
|
128
128
|
}
|
|
129
|
-
if (tab
|
|
129
|
+
if (tab &&
|
|
130
|
+
((atNewline && tab.indent <= parentIndent) ||
|
|
131
|
+
next?.type === 'block-map' ||
|
|
132
|
+
next?.type === 'block-seq'))
|
|
130
133
|
onError(tab, 'TAB_AS_INDENT', 'Tabs are not allowed as indentation');
|
|
131
134
|
return {
|
|
132
135
|
comma,
|
|
@@ -134,9 +137,9 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
|
|
|
134
137
|
spaceBefore,
|
|
135
138
|
comment,
|
|
136
139
|
hasNewline,
|
|
137
|
-
hasNewlineAfterProp,
|
|
138
140
|
anchor,
|
|
139
141
|
tag,
|
|
142
|
+
newlineAfterProp,
|
|
140
143
|
end,
|
|
141
144
|
start: start ?? end
|
|
142
145
|
};
|
|
@@ -18,7 +18,7 @@ function resolveAsScalar(token, strict = true, onError) {
|
|
|
18
18
|
case 'double-quoted-scalar':
|
|
19
19
|
return resolveFlowScalar(token, strict, _onError);
|
|
20
20
|
case 'block-scalar':
|
|
21
|
-
return resolveBlockScalar(
|
|
21
|
+
return resolveBlockScalar({ options: { strict } }, token, _onError);
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
return null;
|
|
@@ -290,15 +290,11 @@ class Lexer {
|
|
|
290
290
|
if (!this.atEnd && !this.hasChars(4))
|
|
291
291
|
return this.setNext('line-start');
|
|
292
292
|
const s = this.peek(3);
|
|
293
|
-
if (s === '---' && isEmpty(this.charAt(3))) {
|
|
293
|
+
if ((s === '---' || s === '...') && isEmpty(this.charAt(3))) {
|
|
294
294
|
yield* this.pushCount(3);
|
|
295
295
|
this.indentValue = 0;
|
|
296
296
|
this.indentNext = 0;
|
|
297
|
-
return 'doc';
|
|
298
|
-
}
|
|
299
|
-
else if (s === '...' && isEmpty(this.charAt(3))) {
|
|
300
|
-
yield* this.pushCount(3);
|
|
301
|
-
return 'stream';
|
|
297
|
+
return s === '---' ? 'doc' : 'stream';
|
|
302
298
|
}
|
|
303
299
|
}
|
|
304
300
|
this.indentValue = yield* this.pushSpaces(false);
|
|
@@ -541,14 +537,25 @@ class Lexer {
|
|
|
541
537
|
nl = this.buffer.length;
|
|
542
538
|
}
|
|
543
539
|
}
|
|
544
|
-
|
|
540
|
+
// Trailing insufficiently indented tabs are invalid.
|
|
541
|
+
// To catch that during parsing, we include them in the block scalar value.
|
|
542
|
+
let i = nl + 1;
|
|
543
|
+
ch = this.buffer[i];
|
|
544
|
+
while (ch === ' ')
|
|
545
|
+
ch = this.buffer[++i];
|
|
546
|
+
if (ch === '\t') {
|
|
547
|
+
while (ch === '\t' || ch === ' ' || ch === '\r' || ch === '\n')
|
|
548
|
+
ch = this.buffer[++i];
|
|
549
|
+
nl = i - 1;
|
|
550
|
+
}
|
|
551
|
+
else if (!this.blockScalarKeep) {
|
|
545
552
|
do {
|
|
546
553
|
let i = nl - 1;
|
|
547
554
|
let ch = this.buffer[i];
|
|
548
555
|
if (ch === '\r')
|
|
549
556
|
ch = this.buffer[--i];
|
|
550
557
|
const lastChar = i; // Drop the line if last char not more indented
|
|
551
|
-
while (ch === ' '
|
|
558
|
+
while (ch === ' ')
|
|
552
559
|
ch = this.buffer[--i];
|
|
553
560
|
if (ch === '\n' && i >= this.pos && i + 1 + indent > lastChar)
|
|
554
561
|
nl = i;
|
|
@@ -9,6 +9,8 @@ const FOLD_QUOTED = 'quoted';
|
|
|
9
9
|
function foldFlowLines(text, indent, mode = 'flow', { indentAtStart, lineWidth = 80, minContentWidth = 20, onFold, onOverflow } = {}) {
|
|
10
10
|
if (!lineWidth || lineWidth < 0)
|
|
11
11
|
return text;
|
|
12
|
+
if (lineWidth < minContentWidth)
|
|
13
|
+
minContentWidth = 0;
|
|
12
14
|
const endStep = Math.max(1 + minContentWidth, 1 + lineWidth - indent.length);
|
|
13
15
|
if (text.length <= endStep)
|
|
14
16
|
return text;
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const help = "yaml: A command-line YAML processor and inspector\n\nReads stdin and writes output to stdout and errors & warnings to stderr.\n\nUsage:\n yaml Process a YAML stream, outputting it as YAML\n yaml cst Parse the CST of a YAML stream\n yaml lex Parse the lexical tokens of a YAML stream\n yaml valid Validate a YAML stream, returning 0 on success\n\nOptions:\n --help, -h Show this message.\n --json, -j Output JSON.\n\nAdditional options for bare \"yaml\" command:\n --doc, -d Output pretty-printed JS Document objects.\n --single, -1 Require the input to consist of a single YAML document.\n --strict, -s Stop on errors.\n --visit, -v Apply a visitor to each document (requires a path to import)\n --yaml 1.1 Set the YAML version. (default: 1.2)";
|
|
1
|
+
export declare const help = "yaml: A command-line YAML processor and inspector\n\nReads stdin and writes output to stdout and errors & warnings to stderr.\n\nUsage:\n yaml Process a YAML stream, outputting it as YAML\n yaml cst Parse the CST of a YAML stream\n yaml lex Parse the lexical tokens of a YAML stream\n yaml valid Validate a YAML stream, returning 0 on success\n\nOptions:\n --help, -h Show this message.\n --json, -j Output JSON.\n --indent 2 Output pretty-printed data, indented by the given number of spaces.\n\nAdditional options for bare \"yaml\" command:\n --doc, -d Output pretty-printed JS Document objects.\n --single, -1 Require the input to consist of a single YAML document.\n --strict, -s Stop on errors.\n --visit, -v Apply a visitor to each document (requires a path to import)\n --yaml 1.1 Set the YAML version. (default: 1.2)";
|
|
3
2
|
export declare class UserError extends Error {
|
|
4
3
|
static ARGS: number;
|
|
5
4
|
static SINGLE: number;
|
package/dist/cli.mjs
CHANGED
|
@@ -22,6 +22,7 @@ Usage:
|
|
|
22
22
|
Options:
|
|
23
23
|
--help, -h Show this message.
|
|
24
24
|
--json, -j Output JSON.
|
|
25
|
+
--indent 2 Output pretty-printed data, indented by the given number of spaces.
|
|
25
26
|
|
|
26
27
|
Additional options for bare "yaml" command:
|
|
27
28
|
--doc, -d Output pretty-printed JS Document objects.
|
|
@@ -46,6 +47,7 @@ async function cli(stdin, done, argv) {
|
|
|
46
47
|
options: {
|
|
47
48
|
doc: { type: 'boolean', short: 'd' },
|
|
48
49
|
help: { type: 'boolean', short: 'h' },
|
|
50
|
+
indent: { type: 'string', short: 'i' },
|
|
49
51
|
json: { type: 'boolean', short: 'j' },
|
|
50
52
|
single: { type: 'boolean', short: '1' },
|
|
51
53
|
strict: { type: 'boolean', short: 's' },
|
|
@@ -58,6 +60,7 @@ async function cli(stdin, done, argv) {
|
|
|
58
60
|
return done(new UserError(UserError.ARGS, error.message));
|
|
59
61
|
}
|
|
60
62
|
const { positionals: [mode], values: opt } = args;
|
|
63
|
+
let indent = Number(opt.indent);
|
|
61
64
|
stdin.setEncoding('utf-8');
|
|
62
65
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
63
66
|
switch (opt.help || mode) {
|
|
@@ -82,7 +85,7 @@ async function cli(stdin, done, argv) {
|
|
|
82
85
|
for (const tok of lexer.lex('', false))
|
|
83
86
|
add(tok);
|
|
84
87
|
if (opt.json)
|
|
85
|
-
console.log(JSON.stringify(data));
|
|
88
|
+
console.log(JSON.stringify(data, null, indent));
|
|
86
89
|
done();
|
|
87
90
|
});
|
|
88
91
|
break;
|
|
@@ -104,7 +107,7 @@ async function cli(stdin, done, argv) {
|
|
|
104
107
|
for (const tok of parser.parse('', false))
|
|
105
108
|
add(tok);
|
|
106
109
|
if (opt.json)
|
|
107
|
-
console.log(JSON.stringify(data));
|
|
110
|
+
console.log(JSON.stringify(data, null, indent));
|
|
108
111
|
done();
|
|
109
112
|
});
|
|
110
113
|
break;
|
|
@@ -153,7 +156,8 @@ async function cli(stdin, done, argv) {
|
|
|
153
156
|
if (reqDocEnd)
|
|
154
157
|
console.log('...');
|
|
155
158
|
try {
|
|
156
|
-
|
|
159
|
+
indent || (indent = 2);
|
|
160
|
+
const str = doc.toString({ indent });
|
|
157
161
|
console.log(str.endsWith('\n') ? str.slice(0, -1) : str);
|
|
158
162
|
}
|
|
159
163
|
catch (error) {
|
|
@@ -181,7 +185,7 @@ async function cli(stdin, done, argv) {
|
|
|
181
185
|
return done(new UserError(UserError.SINGLE, 'Input stream contained no documents'));
|
|
182
186
|
}
|
|
183
187
|
if (mode !== 'valid' && opt.json) {
|
|
184
|
-
console.log(JSON.stringify(opt.single ? data[0] : data));
|
|
188
|
+
console.log(JSON.stringify(opt.single ? data[0] : data, null, indent));
|
|
185
189
|
}
|
|
186
190
|
done();
|
|
187
191
|
});
|
|
@@ -2,4 +2,10 @@ import type { ParsedNode } from '../nodes/Node.js';
|
|
|
2
2
|
import type { BlockMap, BlockSequence, FlowCollection, SourceToken } from '../parse/cst.js';
|
|
3
3
|
import type { ComposeContext, ComposeNode } from './compose-node.js';
|
|
4
4
|
import type { ComposeErrorHandler } from './composer.js';
|
|
5
|
-
|
|
5
|
+
interface Props {
|
|
6
|
+
anchor: SourceToken | null;
|
|
7
|
+
tag: SourceToken | null;
|
|
8
|
+
newlineAfterProp: SourceToken | null;
|
|
9
|
+
}
|
|
10
|
+
export declare function composeCollection(CN: ComposeNode, ctx: ComposeContext, token: BlockMap | BlockSequence | FlowCollection, props: Props, onError: ComposeErrorHandler): ParsedNode;
|
|
11
|
+
export {};
|
|
@@ -25,10 +25,23 @@ function resolveCollection(CN, ctx, token, onError, tagName, tag) {
|
|
|
25
25
|
coll.tag = tagName;
|
|
26
26
|
return coll;
|
|
27
27
|
}
|
|
28
|
-
function composeCollection(CN, ctx, token,
|
|
28
|
+
function composeCollection(CN, ctx, token, props, onError) {
|
|
29
|
+
const tagToken = props.tag;
|
|
29
30
|
const tagName = !tagToken
|
|
30
31
|
? null
|
|
31
32
|
: ctx.directives.tagName(tagToken.source, msg => onError(tagToken, 'TAG_RESOLVE_FAILED', msg));
|
|
33
|
+
if (token.type === 'block-seq') {
|
|
34
|
+
const { anchor, newlineAfterProp: nl } = props;
|
|
35
|
+
const lastProp = anchor && tagToken
|
|
36
|
+
? anchor.offset > tagToken.offset
|
|
37
|
+
? anchor
|
|
38
|
+
: tagToken
|
|
39
|
+
: (anchor ?? tagToken);
|
|
40
|
+
if (lastProp && (!nl || nl.offset < lastProp.offset)) {
|
|
41
|
+
const message = 'Missing newline after block sequence props';
|
|
42
|
+
onError(lastProp, 'MISSING_CHAR', message);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
32
45
|
const expType = token.type === 'block-map'
|
|
33
46
|
? 'map'
|
|
34
47
|
: token.type === 'block-seq'
|
|
@@ -42,8 +55,7 @@ function composeCollection(CN, ctx, token, tagToken, onError) {
|
|
|
42
55
|
!tagName ||
|
|
43
56
|
tagName === '!' ||
|
|
44
57
|
(tagName === YAMLMap.YAMLMap.tagName && expType === 'map') ||
|
|
45
|
-
(tagName === YAMLSeq.YAMLSeq.tagName && expType === 'seq')
|
|
46
|
-
!expType) {
|
|
58
|
+
(tagName === YAMLSeq.YAMLSeq.tagName && expType === 'seq')) {
|
|
47
59
|
return resolveCollection(CN, ctx, token, onError, tagName);
|
|
48
60
|
}
|
|
49
61
|
let tag = ctx.schema.tags.find(t => t.tag === tagName && t.collection === expType);
|
|
@@ -28,7 +28,7 @@ function composeNode(ctx, token, props, onError) {
|
|
|
28
28
|
case 'block-map':
|
|
29
29
|
case 'block-seq':
|
|
30
30
|
case 'flow-collection':
|
|
31
|
-
node = composeCollection.composeCollection(CN, ctx, token,
|
|
31
|
+
node = composeCollection.composeCollection(CN, ctx, token, props, onError);
|
|
32
32
|
if (anchor)
|
|
33
33
|
node.anchor = anchor.source.substring(1);
|
|
34
34
|
break;
|
|
@@ -7,7 +7,7 @@ var resolveFlowScalar = require('./resolve-flow-scalar.js');
|
|
|
7
7
|
|
|
8
8
|
function composeScalar(ctx, token, tagToken, onError) {
|
|
9
9
|
const { value, type, comment, range } = token.type === 'block-scalar'
|
|
10
|
-
? resolveBlockScalar.resolveBlockScalar(
|
|
10
|
+
? resolveBlockScalar.resolveBlockScalar(ctx, token, onError)
|
|
11
11
|
: resolveFlowScalar.resolveFlowScalar(token, ctx.options.strict, onError);
|
|
12
12
|
const tagName = tagToken
|
|
13
13
|
? ctx.directives.tagName(tagToken.source, msg => onError(tagToken, 'TAG_RESOLVE_FAILED', msg))
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type { ParsedNode } from '../nodes/Node.js';
|
|
2
1
|
import { YAMLMap } from '../nodes/YAMLMap.js';
|
|
3
2
|
import type { BlockMap } from '../parse/cst.js';
|
|
4
3
|
import { CollectionTag } from '../schema/types.js';
|
|
5
4
|
import type { ComposeContext, ComposeNode } from './compose-node.js';
|
|
6
5
|
import type { ComposeErrorHandler } from './composer.js';
|
|
7
|
-
export declare function resolveBlockMap({ composeNode, composeEmptyNode }: ComposeNode, ctx: ComposeContext, bm: BlockMap, onError: ComposeErrorHandler, tag?: CollectionTag): YAMLMap.Parsed
|
|
6
|
+
export declare function resolveBlockMap({ composeNode, composeEmptyNode }: ComposeNode, ctx: ComposeContext, bm: BlockMap, onError: ComposeErrorHandler, tag?: CollectionTag): YAMLMap.Parsed;
|
|
@@ -23,6 +23,7 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError, ta
|
|
|
23
23
|
next: key ?? sep?.[0],
|
|
24
24
|
offset,
|
|
25
25
|
onError,
|
|
26
|
+
parentIndent: bm.indent,
|
|
26
27
|
startOnNewline: true
|
|
27
28
|
});
|
|
28
29
|
const implicitKey = !keyProps.found;
|
|
@@ -43,7 +44,7 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError, ta
|
|
|
43
44
|
}
|
|
44
45
|
continue;
|
|
45
46
|
}
|
|
46
|
-
if (keyProps.
|
|
47
|
+
if (keyProps.newlineAfterProp || utilContainsNewline.containsNewline(key)) {
|
|
47
48
|
onError(key ?? start[start.length - 1], 'MULTILINE_IMPLICIT_KEY', 'Implicit keys need to be on a single line');
|
|
48
49
|
}
|
|
49
50
|
}
|
|
@@ -65,6 +66,7 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError, ta
|
|
|
65
66
|
next: value,
|
|
66
67
|
offset: keyNode.range[2],
|
|
67
68
|
onError,
|
|
69
|
+
parentIndent: bm.indent,
|
|
68
70
|
startOnNewline: !key || key.type === 'block-scalar'
|
|
69
71
|
});
|
|
70
72
|
offset = valueProps.end;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Range } from '../nodes/Node.js';
|
|
2
2
|
import { Scalar } from '../nodes/Scalar.js';
|
|
3
3
|
import type { BlockScalar } from '../parse/cst.js';
|
|
4
|
+
import type { ComposeContext } from './compose-node.js';
|
|
4
5
|
import type { ComposeErrorHandler } from './composer.js';
|
|
5
|
-
export declare function resolveBlockScalar(
|
|
6
|
+
export declare function resolveBlockScalar(ctx: ComposeContext, scalar: BlockScalar, onError: ComposeErrorHandler): {
|
|
6
7
|
value: string;
|
|
7
8
|
type: Scalar.BLOCK_FOLDED | Scalar.BLOCK_LITERAL | null;
|
|
8
9
|
comment: string;
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
var Scalar = require('../nodes/Scalar.js');
|
|
4
4
|
|
|
5
|
-
function resolveBlockScalar(
|
|
5
|
+
function resolveBlockScalar(ctx, scalar, onError) {
|
|
6
6
|
const start = scalar.offset;
|
|
7
|
-
const header = parseBlockScalarHeader(scalar, strict, onError);
|
|
7
|
+
const header = parseBlockScalarHeader(scalar, ctx.options.strict, onError);
|
|
8
8
|
if (!header)
|
|
9
9
|
return { value: '', type: null, comment: '', range: [start, start, start] };
|
|
10
10
|
const type = header.mode === '>' ? Scalar.Scalar.BLOCK_FOLDED : Scalar.Scalar.BLOCK_LITERAL;
|
|
@@ -46,6 +46,10 @@ function resolveBlockScalar(scalar, strict, onError) {
|
|
|
46
46
|
if (header.indent === 0)
|
|
47
47
|
trimIndent = indent.length;
|
|
48
48
|
contentStart = i;
|
|
49
|
+
if (trimIndent === 0 && !ctx.atRoot) {
|
|
50
|
+
const message = 'Block scalar values in collections must be indented';
|
|
51
|
+
onError(offset, 'BAD_INDENT', message);
|
|
52
|
+
}
|
|
49
53
|
break;
|
|
50
54
|
}
|
|
51
55
|
offset += indent.length + content.length + 1;
|
|
@@ -3,4 +3,4 @@ import type { BlockSequence } from '../parse/cst.js';
|
|
|
3
3
|
import { CollectionTag } from '../schema/types.js';
|
|
4
4
|
import type { ComposeContext, ComposeNode } from './compose-node.js';
|
|
5
5
|
import type { ComposeErrorHandler } from './composer.js';
|
|
6
|
-
export declare function resolveBlockSeq({ composeNode, composeEmptyNode }: ComposeNode, ctx: ComposeContext, bs: BlockSequence, onError: ComposeErrorHandler, tag?: CollectionTag): YAMLSeq.Parsed
|
|
6
|
+
export declare function resolveBlockSeq({ composeNode, composeEmptyNode }: ComposeNode, ctx: ComposeContext, bs: BlockSequence, onError: ComposeErrorHandler, tag?: CollectionTag): YAMLSeq.Parsed;
|
|
@@ -30,6 +30,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
30
30
|
next: key ?? sep?.[0],
|
|
31
31
|
offset,
|
|
32
32
|
onError,
|
|
33
|
+
parentIndent: fc.indent,
|
|
33
34
|
startOnNewline: false
|
|
34
35
|
});
|
|
35
36
|
if (!props.found) {
|
|
@@ -111,6 +112,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
111
112
|
next: value,
|
|
112
113
|
offset: keyNode.range[2],
|
|
113
114
|
onError,
|
|
115
|
+
parentIndent: fc.indent,
|
|
114
116
|
startOnNewline: false
|
|
115
117
|
});
|
|
116
118
|
if (valueProps.found) {
|
|
@@ -6,17 +6,18 @@ export interface ResolvePropsArg {
|
|
|
6
6
|
next: Token | null | undefined;
|
|
7
7
|
offset: number;
|
|
8
8
|
onError: ComposeErrorHandler;
|
|
9
|
+
parentIndent: number;
|
|
9
10
|
startOnNewline: boolean;
|
|
10
11
|
}
|
|
11
|
-
export declare function resolveProps(tokens: SourceToken[], { flow, indicator, next, offset, onError, startOnNewline }: ResolvePropsArg): {
|
|
12
|
+
export declare function resolveProps(tokens: SourceToken[], { flow, indicator, next, offset, onError, parentIndent, startOnNewline }: ResolvePropsArg): {
|
|
12
13
|
comma: SourceToken | null;
|
|
13
14
|
found: SourceToken | null;
|
|
14
15
|
spaceBefore: boolean;
|
|
15
16
|
comment: string;
|
|
16
17
|
hasNewline: boolean;
|
|
17
|
-
hasNewlineAfterProp: boolean;
|
|
18
18
|
anchor: SourceToken | null;
|
|
19
19
|
tag: SourceToken | null;
|
|
20
|
+
newlineAfterProp: SourceToken | null;
|
|
20
21
|
end: number;
|
|
21
22
|
start: number;
|
|
22
23
|
};
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnNewline }) {
|
|
3
|
+
function resolveProps(tokens, { flow, indicator, next, offset, onError, parentIndent, startOnNewline }) {
|
|
4
4
|
let spaceBefore = false;
|
|
5
5
|
let atNewline = startOnNewline;
|
|
6
6
|
let hasSpace = startOnNewline;
|
|
7
7
|
let comment = '';
|
|
8
8
|
let commentSep = '';
|
|
9
9
|
let hasNewline = false;
|
|
10
|
-
let hasNewlineAfterProp = false;
|
|
11
10
|
let reqSpace = false;
|
|
12
11
|
let tab = null;
|
|
13
12
|
let anchor = null;
|
|
14
13
|
let tag = null;
|
|
14
|
+
let newlineAfterProp = null;
|
|
15
15
|
let comma = null;
|
|
16
16
|
let found = null;
|
|
17
17
|
let start = null;
|
|
@@ -24,7 +24,7 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
|
|
|
24
24
|
reqSpace = false;
|
|
25
25
|
}
|
|
26
26
|
if (tab) {
|
|
27
|
-
if (token.type !== 'comment') {
|
|
27
|
+
if (atNewline && token.type !== 'comment' && token.type !== 'newline') {
|
|
28
28
|
onError(tab, 'TAB_AS_INDENT', 'Tabs are not allowed as indentation');
|
|
29
29
|
}
|
|
30
30
|
tab = null;
|
|
@@ -35,9 +35,8 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
|
|
|
35
35
|
// as leading white space rather than indentation.
|
|
36
36
|
// In a flow collection, only the parser handles indent.
|
|
37
37
|
if (!flow &&
|
|
38
|
-
atNewline &&
|
|
39
38
|
(indicator !== 'doc-start' || next?.type !== 'flow-collection') &&
|
|
40
|
-
token.source
|
|
39
|
+
token.source.includes('\t')) {
|
|
41
40
|
tab = token;
|
|
42
41
|
}
|
|
43
42
|
hasSpace = true;
|
|
@@ -66,7 +65,7 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
|
|
|
66
65
|
atNewline = true;
|
|
67
66
|
hasNewline = true;
|
|
68
67
|
if (anchor || tag)
|
|
69
|
-
|
|
68
|
+
newlineAfterProp = token;
|
|
70
69
|
hasSpace = true;
|
|
71
70
|
break;
|
|
72
71
|
case 'anchor':
|
|
@@ -99,7 +98,8 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
|
|
|
99
98
|
if (found)
|
|
100
99
|
onError(token, 'UNEXPECTED_TOKEN', `Unexpected ${token.source} in ${flow ?? 'collection'}`);
|
|
101
100
|
found = token;
|
|
102
|
-
atNewline =
|
|
101
|
+
atNewline =
|
|
102
|
+
indicator === 'seq-item-ind' || indicator === 'explicit-key-ind';
|
|
103
103
|
hasSpace = false;
|
|
104
104
|
break;
|
|
105
105
|
case 'comma':
|
|
@@ -128,7 +128,10 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
|
|
|
128
128
|
(next.type !== 'scalar' || next.source !== '')) {
|
|
129
129
|
onError(next.offset, 'MISSING_CHAR', 'Tags and anchors must be separated from the next token by white space');
|
|
130
130
|
}
|
|
131
|
-
if (tab
|
|
131
|
+
if (tab &&
|
|
132
|
+
((atNewline && tab.indent <= parentIndent) ||
|
|
133
|
+
next?.type === 'block-map' ||
|
|
134
|
+
next?.type === 'block-seq'))
|
|
132
135
|
onError(tab, 'TAB_AS_INDENT', 'Tabs are not allowed as indentation');
|
|
133
136
|
return {
|
|
134
137
|
comma,
|
|
@@ -136,9 +139,9 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
|
|
|
136
139
|
spaceBefore,
|
|
137
140
|
comment,
|
|
138
141
|
hasNewline,
|
|
139
|
-
hasNewlineAfterProp,
|
|
140
142
|
anchor,
|
|
141
143
|
tag,
|
|
144
|
+
newlineAfterProp,
|
|
142
145
|
end,
|
|
143
146
|
start: start ?? end
|
|
144
147
|
};
|
|
@@ -4,7 +4,6 @@ import { NodeBase } from './Node.js';
|
|
|
4
4
|
export declare function collectionFromPath(schema: Schema, path: unknown[], value: unknown): import("./Node.js").Node;
|
|
5
5
|
export declare const isEmptyPath: (path: Iterable<unknown> | null | undefined) => path is null | undefined;
|
|
6
6
|
export declare abstract class Collection extends NodeBase {
|
|
7
|
-
static maxFlowStringSingleLineLength: number;
|
|
8
7
|
schema: Schema | undefined;
|
|
9
8
|
[NODE_TYPE]: symbol;
|
|
10
9
|
items: unknown[];
|
package/dist/nodes/Collection.js
CHANGED
package/dist/nodes/identity.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export declare const SCALAR: unique symbol;
|
|
|
13
13
|
export declare const SEQ: unique symbol;
|
|
14
14
|
export declare const NODE_TYPE: unique symbol;
|
|
15
15
|
export declare const isAlias: (node: any) => node is Alias;
|
|
16
|
-
export declare const isDocument: <T extends Node = Node>(node: any) => node is Document<T
|
|
16
|
+
export declare const isDocument: <T extends Node = Node>(node: any) => node is Document<T>;
|
|
17
17
|
export declare const isMap: <K = unknown, V = unknown>(node: any) => node is YAMLMap<K, V>;
|
|
18
18
|
export declare const isPair: <K = unknown, V = unknown>(node: any) => node is Pair<K, V>;
|
|
19
19
|
export declare const isScalar: <T = unknown>(node: any) => node is Scalar<T>;
|
package/dist/parse/cst-scalar.js
CHANGED
|
@@ -20,7 +20,7 @@ function resolveAsScalar(token, strict = true, onError) {
|
|
|
20
20
|
case 'double-quoted-scalar':
|
|
21
21
|
return resolveFlowScalar.resolveFlowScalar(token, strict, _onError);
|
|
22
22
|
case 'block-scalar':
|
|
23
|
-
return resolveBlockScalar.resolveBlockScalar(
|
|
23
|
+
return resolveBlockScalar.resolveBlockScalar({ options: { strict } }, token, _onError);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
return null;
|
package/dist/parse/lexer.js
CHANGED
|
@@ -292,15 +292,11 @@ class Lexer {
|
|
|
292
292
|
if (!this.atEnd && !this.hasChars(4))
|
|
293
293
|
return this.setNext('line-start');
|
|
294
294
|
const s = this.peek(3);
|
|
295
|
-
if (s === '---' && isEmpty(this.charAt(3))) {
|
|
295
|
+
if ((s === '---' || s === '...') && isEmpty(this.charAt(3))) {
|
|
296
296
|
yield* this.pushCount(3);
|
|
297
297
|
this.indentValue = 0;
|
|
298
298
|
this.indentNext = 0;
|
|
299
|
-
return 'doc';
|
|
300
|
-
}
|
|
301
|
-
else if (s === '...' && isEmpty(this.charAt(3))) {
|
|
302
|
-
yield* this.pushCount(3);
|
|
303
|
-
return 'stream';
|
|
299
|
+
return s === '---' ? 'doc' : 'stream';
|
|
304
300
|
}
|
|
305
301
|
}
|
|
306
302
|
this.indentValue = yield* this.pushSpaces(false);
|
|
@@ -543,14 +539,25 @@ class Lexer {
|
|
|
543
539
|
nl = this.buffer.length;
|
|
544
540
|
}
|
|
545
541
|
}
|
|
546
|
-
|
|
542
|
+
// Trailing insufficiently indented tabs are invalid.
|
|
543
|
+
// To catch that during parsing, we include them in the block scalar value.
|
|
544
|
+
let i = nl + 1;
|
|
545
|
+
ch = this.buffer[i];
|
|
546
|
+
while (ch === ' ')
|
|
547
|
+
ch = this.buffer[++i];
|
|
548
|
+
if (ch === '\t') {
|
|
549
|
+
while (ch === '\t' || ch === ' ' || ch === '\r' || ch === '\n')
|
|
550
|
+
ch = this.buffer[++i];
|
|
551
|
+
nl = i - 1;
|
|
552
|
+
}
|
|
553
|
+
else if (!this.blockScalarKeep) {
|
|
547
554
|
do {
|
|
548
555
|
let i = nl - 1;
|
|
549
556
|
let ch = this.buffer[i];
|
|
550
557
|
if (ch === '\r')
|
|
551
558
|
ch = this.buffer[--i];
|
|
552
559
|
const lastChar = i; // Drop the line if last char not more indented
|
|
553
|
-
while (ch === ' '
|
|
560
|
+
while (ch === ' ')
|
|
554
561
|
ch = this.buffer[--i];
|
|
555
562
|
if (ch === '\n' && i >= this.pos && i + 1 + indent > lastChar)
|
|
556
563
|
nl = i;
|
|
@@ -9,12 +9,12 @@ export declare class YAMLOMap extends YAMLSeq {
|
|
|
9
9
|
add: (pair: import("../../index.js").Pair<any, any> | {
|
|
10
10
|
key: any;
|
|
11
11
|
value: any;
|
|
12
|
-
}, overwrite?: boolean
|
|
12
|
+
}, overwrite?: boolean) => void;
|
|
13
13
|
delete: (key: unknown) => boolean;
|
|
14
14
|
get: {
|
|
15
15
|
(key: unknown, keepScalar: true): import("../../index.js").Scalar<any> | undefined;
|
|
16
|
-
(key: unknown, keepScalar?: false
|
|
17
|
-
(key: unknown, keepScalar?: boolean
|
|
16
|
+
(key: unknown, keepScalar?: false): any;
|
|
17
|
+
(key: unknown, keepScalar?: boolean): any;
|
|
18
18
|
};
|
|
19
19
|
has: (key: unknown) => boolean;
|
|
20
20
|
set: (key: any, value: any) => void;
|
|
@@ -11,6 +11,8 @@ const FOLD_QUOTED = 'quoted';
|
|
|
11
11
|
function foldFlowLines(text, indent, mode = 'flow', { indentAtStart, lineWidth = 80, minContentWidth = 20, onFold, onOverflow } = {}) {
|
|
12
12
|
if (!lineWidth || lineWidth < 0)
|
|
13
13
|
return text;
|
|
14
|
+
if (lineWidth < minContentWidth)
|
|
15
|
+
minContentWidth = 0;
|
|
14
16
|
const endStep = Math.max(1 + minContentWidth, 1 + lineWidth - indent.length);
|
|
15
17
|
if (text.length <= endStep)
|
|
16
18
|
return text;
|