yaml 2.0.0-7 → 2.0.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 +1 -1
- package/browser/dist/compose/compose-doc.js +3 -2
- package/browser/dist/compose/compose-node.js +14 -3
- package/browser/dist/compose/compose-scalar.js +17 -10
- package/browser/dist/compose/composer.js +6 -7
- package/browser/dist/compose/resolve-block-map.js +19 -5
- package/browser/dist/compose/resolve-block-scalar.js +12 -3
- package/browser/dist/compose/resolve-block-seq.js +5 -0
- package/browser/dist/compose/resolve-flow-collection.js +18 -6
- package/browser/dist/compose/resolve-flow-scalar.js +9 -2
- package/browser/dist/compose/resolve-props.js +4 -0
- package/browser/dist/compose/util-flow-indent-check.js +15 -0
- package/browser/dist/doc/Document.js +73 -16
- package/browser/dist/doc/anchors.js +2 -2
- package/browser/dist/doc/createNode.js +12 -7
- package/browser/dist/doc/directives.js +11 -3
- package/browser/dist/index.js +1 -2
- 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 +11 -3
- package/browser/dist/nodes/Scalar.js +1 -1
- package/browser/dist/nodes/YAMLMap.js +6 -5
- package/browser/dist/nodes/YAMLSeq.js +2 -2
- package/browser/dist/nodes/addPairToJSMap.js +3 -2
- package/browser/dist/nodes/toJS.js +3 -1
- package/browser/dist/parse/cst-scalar.js +2 -6
- package/browser/dist/parse/cst-visit.js +2 -2
- package/browser/dist/parse/lexer.js +50 -22
- package/browser/dist/parse/parser.js +121 -45
- package/browser/dist/public-api.js +4 -5
- package/browser/dist/schema/Schema.js +19 -4
- package/browser/dist/schema/common/null.js +3 -1
- package/browser/dist/schema/core/float.js +4 -1
- package/browser/dist/schema/tags.js +17 -13
- package/browser/dist/schema/yaml-1.1/float.js +4 -1
- package/browser/dist/schema/yaml-1.1/omap.js +1 -1
- package/browser/dist/schema/yaml-1.1/pairs.js +2 -1
- package/browser/dist/stringify/stringify.js +53 -23
- package/browser/dist/stringify/stringifyCollection.js +115 -85
- package/browser/dist/stringify/stringifyComment.js +18 -12
- package/browser/dist/stringify/stringifyDocument.js +37 -15
- package/browser/dist/stringify/stringifyPair.js +35 -21
- package/browser/dist/stringify/stringifyString.js +41 -43
- package/browser/dist/util.js +3 -0
- package/browser/dist/visit.js +150 -62
- package/dist/compose/compose-doc.js +3 -2
- package/dist/compose/compose-node.d.ts +1 -0
- package/dist/compose/compose-node.js +14 -3
- package/dist/compose/compose-scalar.js +16 -9
- package/dist/compose/composer.d.ts +1 -1
- package/dist/compose/composer.js +8 -9
- package/dist/compose/resolve-block-map.js +19 -5
- package/dist/compose/resolve-block-scalar.js +12 -3
- package/dist/compose/resolve-block-seq.js +5 -0
- package/dist/compose/resolve-flow-collection.js +18 -6
- package/dist/compose/resolve-flow-scalar.js +9 -2
- package/dist/compose/resolve-props.d.ts +1 -1
- package/dist/compose/resolve-props.js +4 -0
- package/dist/compose/util-flow-indent-check.d.ts +3 -0
- package/dist/compose/util-flow-indent-check.js +17 -0
- package/dist/doc/Document.d.ts +13 -4
- package/dist/doc/Document.js +79 -22
- package/dist/doc/anchors.d.ts +2 -2
- package/dist/doc/anchors.js +2 -2
- package/dist/doc/createNode.d.ts +3 -2
- package/dist/doc/createNode.js +11 -6
- package/dist/doc/directives.d.ts +5 -2
- package/dist/doc/directives.js +11 -3
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -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 +6 -1
- package/dist/nodes/Node.js +7 -0
- package/dist/nodes/Pair.d.ts +7 -2
- package/dist/nodes/Pair.js +10 -2
- package/dist/nodes/Scalar.d.ts +2 -0
- package/dist/nodes/Scalar.js +1 -1
- package/dist/nodes/YAMLMap.d.ts +5 -1
- package/dist/nodes/YAMLMap.js +6 -5
- package/dist/nodes/YAMLSeq.d.ts +2 -0
- package/dist/nodes/YAMLSeq.js +2 -2
- package/dist/nodes/addPairToJSMap.js +2 -1
- package/dist/nodes/toJS.js +3 -1
- package/dist/options.d.ts +67 -15
- package/dist/parse/cst-scalar.d.ts +6 -0
- package/dist/parse/cst-scalar.js +2 -6
- package/dist/parse/cst-visit.js +2 -2
- package/dist/parse/lexer.d.ts +2 -0
- package/dist/parse/lexer.js +50 -22
- package/dist/parse/parser.js +121 -45
- package/dist/public-api.js +4 -5
- package/dist/schema/Schema.d.ts +6 -4
- package/dist/schema/Schema.js +18 -3
- package/dist/schema/common/null.js +3 -1
- package/dist/schema/core/float.js +4 -1
- package/dist/schema/tags.d.ts +1 -2
- package/dist/schema/tags.js +17 -13
- package/dist/schema/yaml-1.1/float.js +4 -1
- package/dist/schema/yaml-1.1/omap.js +1 -1
- package/dist/schema/yaml-1.1/pairs.js +2 -1
- package/dist/stringify/stringify.d.ts +5 -3
- package/dist/stringify/stringify.js +53 -23
- package/dist/stringify/stringifyCollection.d.ts +2 -6
- package/dist/stringify/stringifyCollection.js +114 -84
- package/dist/stringify/stringifyComment.d.ts +10 -2
- package/dist/stringify/stringifyComment.js +19 -12
- package/dist/stringify/stringifyDocument.js +36 -14
- package/dist/stringify/stringifyPair.js +34 -20
- package/dist/stringify/stringifyString.js +41 -43
- package/dist/test-events.d.ts +1 -1
- package/dist/test-events.js +13 -12
- package/dist/util.d.ts +3 -0
- package/dist/util.js +6 -0
- package/dist/visit.d.ts +49 -10
- package/dist/visit.js +149 -60
- package/package.json +12 -10
- package/util.d.ts +3 -0
- package/browser/dist/options.js +0 -17
- package/dist/options.js +0 -19
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ For more information, see the project's documentation site: [**eemeli.org/yaml**
|
|
|
19
19
|
To install:
|
|
20
20
|
|
|
21
21
|
```sh
|
|
22
|
-
npm install
|
|
22
|
+
npm install yaml
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
**Note:** These docs are for `yaml@2`. For v1, see the [v1.10.0 tag](https://github.com/eemeli/yaml/tree/v1.10.0) for the source and [eemeli.org/yaml/v1](https://eemeli.org/yaml/v1/) for the documentation.
|
|
@@ -7,19 +7,20 @@ function composeDoc(options, directives, { offset, start, value, end }, onError)
|
|
|
7
7
|
const opts = Object.assign({ directives }, options);
|
|
8
8
|
const doc = new Document(undefined, opts);
|
|
9
9
|
const ctx = {
|
|
10
|
+
atRoot: true,
|
|
10
11
|
directives: doc.directives,
|
|
11
12
|
options: doc.options,
|
|
12
13
|
schema: doc.schema
|
|
13
14
|
};
|
|
14
15
|
const props = resolveProps(start, {
|
|
15
16
|
indicator: 'doc-start',
|
|
16
|
-
next: value
|
|
17
|
+
next: value !== null && value !== void 0 ? value : end === null || end === void 0 ? void 0 : end[0],
|
|
17
18
|
offset,
|
|
18
19
|
onError,
|
|
19
20
|
startOnNewline: true
|
|
20
21
|
});
|
|
21
22
|
if (props.found) {
|
|
22
|
-
doc.directives.
|
|
23
|
+
doc.directives.docStart = true;
|
|
23
24
|
if (value &&
|
|
24
25
|
(value.type === 'block-map' || value.type === 'block-seq') &&
|
|
25
26
|
!props.hasNewline)
|
|
@@ -8,6 +8,7 @@ const CN = { composeNode, composeEmptyNode };
|
|
|
8
8
|
function composeNode(ctx, token, props, onError) {
|
|
9
9
|
const { spaceBefore, comment, anchor, tag } = props;
|
|
10
10
|
let node;
|
|
11
|
+
let isSrcToken = true;
|
|
11
12
|
switch (token.type) {
|
|
12
13
|
case 'alias':
|
|
13
14
|
node = composeAlias(ctx, token, onError);
|
|
@@ -29,9 +30,14 @@ function composeNode(ctx, token, props, onError) {
|
|
|
29
30
|
if (anchor)
|
|
30
31
|
node.anchor = anchor.source.substring(1);
|
|
31
32
|
break;
|
|
32
|
-
default:
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
default: {
|
|
34
|
+
const message = token.type === 'error'
|
|
35
|
+
? token.message
|
|
36
|
+
: `Unsupported token (type: ${token.type})`;
|
|
37
|
+
onError(token, 'UNEXPECTED_TOKEN', message);
|
|
38
|
+
node = composeEmptyNode(ctx, token.offset, undefined, null, props, onError);
|
|
39
|
+
isSrcToken = false;
|
|
40
|
+
}
|
|
35
41
|
}
|
|
36
42
|
if (anchor && node.anchor === '')
|
|
37
43
|
onError(anchor, 'BAD_ALIAS', 'Anchor cannot be an empty string');
|
|
@@ -43,6 +49,9 @@ function composeNode(ctx, token, props, onError) {
|
|
|
43
49
|
else
|
|
44
50
|
node.commentBefore = comment;
|
|
45
51
|
}
|
|
52
|
+
// @ts-expect-error Type checking misses meaning of isSrcToken
|
|
53
|
+
if (ctx.options.keepSourceTokens && isSrcToken)
|
|
54
|
+
node.srcToken = token;
|
|
46
55
|
return node;
|
|
47
56
|
}
|
|
48
57
|
function composeEmptyNode(ctx, offset, before, pos, { spaceBefore, comment, anchor, tag }, onError) {
|
|
@@ -68,6 +77,8 @@ function composeAlias({ options }, { offset, source, end }, onError) {
|
|
|
68
77
|
const alias = new Alias(source.substring(1));
|
|
69
78
|
if (alias.source === '')
|
|
70
79
|
onError(offset, 'BAD_ALIAS', 'Alias cannot be an empty string');
|
|
80
|
+
if (alias.source.endsWith(':'))
|
|
81
|
+
onError(offset + source.length - 1, 'BAD_ALIAS', 'Alias ending in : is ambiguous', true);
|
|
71
82
|
const valueEnd = offset + source.length;
|
|
72
83
|
const re = resolveEnd(end, valueEnd, options.strict, onError);
|
|
73
84
|
alias.range = [offset, valueEnd, re.offset];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SCALAR, isScalar } from '../nodes/Node.js';
|
|
2
2
|
import { Scalar } from '../nodes/Scalar.js';
|
|
3
3
|
import { resolveBlockScalar } from './resolve-block-scalar.js';
|
|
4
4
|
import { resolveFlowScalar } from './resolve-flow-scalar.js';
|
|
@@ -12,14 +12,17 @@ function composeScalar(ctx, token, tagToken, onError) {
|
|
|
12
12
|
: null;
|
|
13
13
|
const tag = tagToken && tagName
|
|
14
14
|
? findScalarTagByName(ctx.schema, value, tagName, tagToken, onError)
|
|
15
|
-
:
|
|
15
|
+
: token.type === 'scalar'
|
|
16
|
+
? findScalarTagByTest(ctx, value, token, onError)
|
|
17
|
+
: ctx.schema[SCALAR];
|
|
16
18
|
let scalar;
|
|
17
19
|
try {
|
|
18
|
-
const res = tag.resolve(value, msg => onError(tagToken
|
|
20
|
+
const res = tag.resolve(value, msg => onError(tagToken !== null && tagToken !== void 0 ? tagToken : token, 'TAG_RESOLVE_FAILED', msg), ctx.options);
|
|
19
21
|
scalar = isScalar(res) ? res : new Scalar(res);
|
|
20
22
|
}
|
|
21
23
|
catch (error) {
|
|
22
|
-
|
|
24
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
25
|
+
onError(tagToken !== null && tagToken !== void 0 ? tagToken : token, 'TAG_RESOLVE_FAILED', msg);
|
|
23
26
|
scalar = new Scalar(value);
|
|
24
27
|
}
|
|
25
28
|
scalar.range = range;
|
|
@@ -60,15 +63,19 @@ function findScalarTagByName(schema, value, tagName, tagToken, onError) {
|
|
|
60
63
|
onError(tagToken, 'TAG_RESOLVE_FAILED', `Unresolved tag: ${tagName}`, tagName !== 'tag:yaml.org,2002:str');
|
|
61
64
|
return schema[SCALAR];
|
|
62
65
|
}
|
|
63
|
-
function findScalarTagByTest(schema, value,
|
|
66
|
+
function findScalarTagByTest({ directives, schema }, value, token, onError) {
|
|
64
67
|
var _a;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
const tag = schema.tags.find(tag => { var _a; return tag.default && ((_a = tag.test) === null || _a === void 0 ? void 0 : _a.test(value)); }) || schema[SCALAR];
|
|
69
|
+
if (schema.compat) {
|
|
70
|
+
const compat = (_a = schema.compat.find(tag => { var _a; return tag.default && ((_a = tag.test) === null || _a === void 0 ? void 0 : _a.test(value)); })) !== null && _a !== void 0 ? _a : schema[SCALAR];
|
|
71
|
+
if (tag.tag !== compat.tag) {
|
|
72
|
+
const ts = directives.tagString(tag.tag);
|
|
73
|
+
const cs = directives.tagString(compat.tag);
|
|
74
|
+
const msg = `Value may be parsed as either ${ts} or ${cs}`;
|
|
75
|
+
onError(token, 'TAG_RESOLVE_FAILED', msg, true);
|
|
69
76
|
}
|
|
70
77
|
}
|
|
71
|
-
return
|
|
78
|
+
return tag;
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
export { composeScalar };
|
|
@@ -2,7 +2,6 @@ import { Directives } from '../doc/directives.js';
|
|
|
2
2
|
import { Document } from '../doc/Document.js';
|
|
3
3
|
import { YAMLWarning, YAMLParseError } from '../errors.js';
|
|
4
4
|
import { isCollection, isPair } from '../nodes/Node.js';
|
|
5
|
-
import { defaultOptions } from '../options.js';
|
|
6
5
|
import { composeDoc } from './compose-doc.js';
|
|
7
6
|
import { resolveEnd } from './resolve-end.js';
|
|
8
7
|
|
|
@@ -68,9 +67,8 @@ class Composer {
|
|
|
68
67
|
else
|
|
69
68
|
this.errors.push(new YAMLParseError(pos, code, message));
|
|
70
69
|
};
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
});
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
71
|
+
this.directives = new Directives({ version: options.version || '1.2' });
|
|
74
72
|
this.options = options;
|
|
75
73
|
}
|
|
76
74
|
decorate(doc, afterDoc) {
|
|
@@ -81,7 +79,7 @@ class Composer {
|
|
|
81
79
|
if (afterDoc) {
|
|
82
80
|
doc.comment = doc.comment ? `${doc.comment}\n${comment}` : comment;
|
|
83
81
|
}
|
|
84
|
-
else if (afterEmptyLine || doc.directives.
|
|
82
|
+
else if (afterEmptyLine || doc.directives.docStart || !dc) {
|
|
85
83
|
doc.commentBefore = comment;
|
|
86
84
|
}
|
|
87
85
|
else if (isCollection(dc) && !dc.flow && dc.items.length > 0) {
|
|
@@ -146,8 +144,8 @@ class Composer {
|
|
|
146
144
|
break;
|
|
147
145
|
case 'document': {
|
|
148
146
|
const doc = composeDoc(this.options, this.directives, token, this.onError);
|
|
149
|
-
if (this.atDirectives && !doc.directives.
|
|
150
|
-
this.onError(token, 'MISSING_CHAR', 'Missing directives-end indicator line');
|
|
147
|
+
if (this.atDirectives && !doc.directives.docStart)
|
|
148
|
+
this.onError(token, 'MISSING_CHAR', 'Missing directives-end/doc-start indicator line');
|
|
151
149
|
this.decorate(doc, false);
|
|
152
150
|
if (this.doc)
|
|
153
151
|
yield this.doc;
|
|
@@ -179,6 +177,7 @@ class Composer {
|
|
|
179
177
|
this.errors.push(new YAMLParseError(getErrorPos(token), 'UNEXPECTED_TOKEN', msg));
|
|
180
178
|
break;
|
|
181
179
|
}
|
|
180
|
+
this.doc.directives.docEnd = true;
|
|
182
181
|
const end = resolveEnd(token.end, token.offset + token.source.length, this.doc.options.strict, this.onError);
|
|
183
182
|
this.decorate(this.doc, true);
|
|
184
183
|
if (end.comment) {
|
|
@@ -2,18 +2,22 @@ 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 { flowIndentCheck } from './util-flow-indent-check.js';
|
|
5
6
|
import { mapIncludes } from './util-map-includes.js';
|
|
6
7
|
|
|
7
8
|
const startColMsg = 'All mapping items must start at the same column';
|
|
8
9
|
function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
|
|
9
10
|
var _a;
|
|
10
11
|
const map = new YAMLMap(ctx.schema);
|
|
12
|
+
if (ctx.atRoot)
|
|
13
|
+
ctx.atRoot = false;
|
|
11
14
|
let offset = bm.offset;
|
|
12
|
-
for (const
|
|
15
|
+
for (const collItem of bm.items) {
|
|
16
|
+
const { start, key, sep, value } = collItem;
|
|
13
17
|
// key properties
|
|
14
18
|
const keyProps = resolveProps(start, {
|
|
15
19
|
indicator: 'explicit-key-ind',
|
|
16
|
-
next: key
|
|
20
|
+
next: key !== null && key !== void 0 ? key : sep === null || sep === void 0 ? void 0 : sep[0],
|
|
17
21
|
offset,
|
|
18
22
|
onError,
|
|
19
23
|
startOnNewline: true
|
|
@@ -47,10 +51,12 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
|
|
|
47
51
|
const keyNode = key
|
|
48
52
|
? composeNode(ctx, key, keyProps, onError)
|
|
49
53
|
: composeEmptyNode(ctx, keyStart, start, null, keyProps, onError);
|
|
54
|
+
if (ctx.schema.compat)
|
|
55
|
+
flowIndentCheck(bm.indent, key, onError);
|
|
50
56
|
if (mapIncludes(ctx, map.items, keyNode))
|
|
51
57
|
onError(keyStart, 'DUPLICATE_KEY', 'Map keys must be unique');
|
|
52
58
|
// value properties
|
|
53
|
-
const valueProps = resolveProps(sep
|
|
59
|
+
const valueProps = resolveProps(sep !== null && sep !== void 0 ? sep : [], {
|
|
54
60
|
indicator: 'map-value-ind',
|
|
55
61
|
next: value,
|
|
56
62
|
offset: keyNode.range[2],
|
|
@@ -70,8 +76,13 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
|
|
|
70
76
|
const valueNode = value
|
|
71
77
|
? composeNode(ctx, value, valueProps, onError)
|
|
72
78
|
: composeEmptyNode(ctx, offset, sep, null, valueProps, onError);
|
|
79
|
+
if (ctx.schema.compat)
|
|
80
|
+
flowIndentCheck(bm.indent, value, onError);
|
|
73
81
|
offset = valueNode.range[2];
|
|
74
|
-
|
|
82
|
+
const pair = new Pair(keyNode, valueNode);
|
|
83
|
+
if (ctx.options.keepSourceTokens)
|
|
84
|
+
pair.srcToken = collItem;
|
|
85
|
+
map.items.push(pair);
|
|
75
86
|
}
|
|
76
87
|
else {
|
|
77
88
|
// key with no value
|
|
@@ -83,7 +94,10 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
|
|
|
83
94
|
else
|
|
84
95
|
keyNode.comment = valueProps.comment;
|
|
85
96
|
}
|
|
86
|
-
|
|
97
|
+
const pair = new Pair(keyNode);
|
|
98
|
+
if (ctx.options.keepSourceTokens)
|
|
99
|
+
pair.srcToken = collItem;
|
|
100
|
+
map.items.push(pair);
|
|
87
101
|
}
|
|
88
102
|
}
|
|
89
103
|
map.range = [bm.offset, offset, offset];
|
|
@@ -17,8 +17,10 @@ function resolveBlockScalar(scalar, strict, onError) {
|
|
|
17
17
|
break;
|
|
18
18
|
}
|
|
19
19
|
// shortcut for empty contents
|
|
20
|
-
if (
|
|
21
|
-
const value = header.chomp === '+'
|
|
20
|
+
if (chompStart === 0) {
|
|
21
|
+
const value = header.chomp === '+' && lines.length > 0
|
|
22
|
+
? '\n'.repeat(Math.max(1, lines.length - 1))
|
|
23
|
+
: '';
|
|
22
24
|
let end = start + header.length;
|
|
23
25
|
if (scalar.source)
|
|
24
26
|
end += scalar.source.length;
|
|
@@ -46,6 +48,11 @@ function resolveBlockScalar(scalar, strict, onError) {
|
|
|
46
48
|
}
|
|
47
49
|
offset += indent.length + content.length + 1;
|
|
48
50
|
}
|
|
51
|
+
// include trailing more-indented empty lines in content
|
|
52
|
+
for (let i = lines.length - 1; i >= chompStart; --i) {
|
|
53
|
+
if (lines[i][0].length > trimIndent)
|
|
54
|
+
chompStart = i + 1;
|
|
55
|
+
}
|
|
49
56
|
let value = '';
|
|
50
57
|
let sep = '';
|
|
51
58
|
let prevMoreIndented = false;
|
|
@@ -175,7 +182,9 @@ function splitLines(source) {
|
|
|
175
182
|
const split = source.split(/\n( *)/);
|
|
176
183
|
const first = split[0];
|
|
177
184
|
const m = first.match(/^( *)/);
|
|
178
|
-
const line0 = m
|
|
185
|
+
const line0 = (m === null || m === void 0 ? void 0 : m[1])
|
|
186
|
+
? [m[1], first.slice(m[1].length)]
|
|
187
|
+
: ['', first];
|
|
179
188
|
const lines = [line0];
|
|
180
189
|
for (let i = 1; i < split.length; i += 2)
|
|
181
190
|
lines.push([split[i], split[i + 1]]);
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { YAMLSeq } from '../nodes/YAMLSeq.js';
|
|
2
2
|
import { resolveProps } from './resolve-props.js';
|
|
3
|
+
import { flowIndentCheck } from './util-flow-indent-check.js';
|
|
3
4
|
|
|
4
5
|
function resolveBlockSeq({ composeNode, composeEmptyNode }, ctx, bs, onError) {
|
|
5
6
|
const seq = new YAMLSeq(ctx.schema);
|
|
7
|
+
if (ctx.atRoot)
|
|
8
|
+
ctx.atRoot = false;
|
|
6
9
|
let offset = bs.offset;
|
|
7
10
|
for (const { start, value } of bs.items) {
|
|
8
11
|
const props = resolveProps(start, {
|
|
@@ -30,6 +33,8 @@ function resolveBlockSeq({ composeNode, composeEmptyNode }, ctx, bs, onError) {
|
|
|
30
33
|
const node = value
|
|
31
34
|
? composeNode(ctx, value, props, onError)
|
|
32
35
|
: composeEmptyNode(ctx, offset, start, null, props, onError);
|
|
36
|
+
if (ctx.schema.compat)
|
|
37
|
+
flowIndentCheck(bs.indent, value, onError);
|
|
33
38
|
offset = node.range[2];
|
|
34
39
|
seq.items.push(node);
|
|
35
40
|
}
|
|
@@ -10,19 +10,24 @@ import { mapIncludes } from './util-map-includes.js';
|
|
|
10
10
|
const blockMsg = 'Block collections are not allowed within flow collections';
|
|
11
11
|
const isBlock = (token) => token && (token.type === 'block-map' || token.type === 'block-seq');
|
|
12
12
|
function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onError) {
|
|
13
|
+
var _a;
|
|
13
14
|
const isMap = fc.start.source === '{';
|
|
14
15
|
const fcName = isMap ? 'flow map' : 'flow sequence';
|
|
15
16
|
const coll = isMap
|
|
16
17
|
? new YAMLMap(ctx.schema)
|
|
17
18
|
: new YAMLSeq(ctx.schema);
|
|
18
19
|
coll.flow = true;
|
|
19
|
-
|
|
20
|
+
const atRoot = ctx.atRoot;
|
|
21
|
+
if (atRoot)
|
|
22
|
+
ctx.atRoot = false;
|
|
23
|
+
let offset = fc.offset + fc.start.source.length;
|
|
20
24
|
for (let i = 0; i < fc.items.length; ++i) {
|
|
21
|
-
const
|
|
25
|
+
const collItem = fc.items[i];
|
|
26
|
+
const { start, key, sep, value } = collItem;
|
|
22
27
|
const props = resolveProps(start, {
|
|
23
28
|
flow: fcName,
|
|
24
29
|
indicator: 'explicit-key-ind',
|
|
25
|
-
next: key
|
|
30
|
+
next: key !== null && key !== void 0 ? key : sep === null || sep === void 0 ? void 0 : sep[0],
|
|
26
31
|
offset,
|
|
27
32
|
onError,
|
|
28
33
|
startOnNewline: false
|
|
@@ -39,6 +44,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
39
44
|
else
|
|
40
45
|
coll.comment = props.comment;
|
|
41
46
|
}
|
|
47
|
+
offset = props.end;
|
|
42
48
|
continue;
|
|
43
49
|
}
|
|
44
50
|
if (!isMap && ctx.options.strict && containsNewline(key))
|
|
@@ -69,7 +75,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
69
75
|
if (prevItemComment) {
|
|
70
76
|
let prev = coll.items[coll.items.length - 1];
|
|
71
77
|
if (isPair(prev))
|
|
72
|
-
prev = prev.value
|
|
78
|
+
prev = (_a = prev.value) !== null && _a !== void 0 ? _a : prev.key;
|
|
73
79
|
if (prev.comment)
|
|
74
80
|
prev.comment += '\n' + prevItemComment;
|
|
75
81
|
else
|
|
@@ -99,7 +105,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
99
105
|
if (isBlock(key))
|
|
100
106
|
onError(keyNode.range, 'BLOCK_IN_FLOW', blockMsg);
|
|
101
107
|
// value properties
|
|
102
|
-
const valueProps = resolveProps(sep
|
|
108
|
+
const valueProps = resolveProps(sep !== null && sep !== void 0 ? sep : [], {
|
|
103
109
|
flow: fcName,
|
|
104
110
|
indicator: 'map-value-ind',
|
|
105
111
|
next: value,
|
|
@@ -145,6 +151,8 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
145
151
|
keyNode.comment = valueProps.comment;
|
|
146
152
|
}
|
|
147
153
|
const pair = new Pair(keyNode, valueNode);
|
|
154
|
+
if (ctx.options.keepSourceTokens)
|
|
155
|
+
pair.srcToken = collItem;
|
|
148
156
|
if (isMap) {
|
|
149
157
|
const map = coll;
|
|
150
158
|
if (mapIncludes(ctx, map.items, keyNode))
|
|
@@ -166,7 +174,11 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
|
|
|
166
174
|
if (ce && ce.source === expectedEnd)
|
|
167
175
|
cePos = ce.offset + ce.source.length;
|
|
168
176
|
else {
|
|
169
|
-
|
|
177
|
+
const name = fcName[0].toUpperCase() + fcName.substring(1);
|
|
178
|
+
const msg = atRoot
|
|
179
|
+
? `${name} must end with a ${expectedEnd}`
|
|
180
|
+
: `${name} in block collection must be sufficiently indented and end with a ${expectedEnd}`;
|
|
181
|
+
onError(offset, atRoot ? 'MISSING_CHAR' : 'BAD_INDENT', msg);
|
|
170
182
|
if (ce && ce.source.length !== 1)
|
|
171
183
|
ee.unshift(ce);
|
|
172
184
|
}
|
|
@@ -72,6 +72,7 @@ function singleQuotedValue(source, onError) {
|
|
|
72
72
|
return foldLines(source.slice(1, -1)).replace(/''/g, "'");
|
|
73
73
|
}
|
|
74
74
|
function foldLines(source) {
|
|
75
|
+
var _a;
|
|
75
76
|
/**
|
|
76
77
|
* The negative lookbehind here and in the `re` RegExp is to
|
|
77
78
|
* prevent causing a polynomial search time in certain cases.
|
|
@@ -111,7 +112,7 @@ function foldLines(source) {
|
|
|
111
112
|
const last = /[ \t]*(.*)/sy;
|
|
112
113
|
last.lastIndex = pos;
|
|
113
114
|
match = last.exec(source);
|
|
114
|
-
return res + sep + ((match
|
|
115
|
+
return res + sep + ((_a = match === null || match === void 0 ? void 0 : match[1]) !== null && _a !== void 0 ? _a : '');
|
|
115
116
|
}
|
|
116
117
|
function doubleQuotedValue(source, onError) {
|
|
117
118
|
let res = '';
|
|
@@ -135,6 +136,12 @@ function doubleQuotedValue(source, onError) {
|
|
|
135
136
|
while (next === ' ' || next === '\t')
|
|
136
137
|
next = source[++i + 1];
|
|
137
138
|
}
|
|
139
|
+
else if (next === '\r' && source[i + 1] === '\n') {
|
|
140
|
+
// skip escaped CRLF newlines, but still trim the following line
|
|
141
|
+
next = source[++i + 1];
|
|
142
|
+
while (next === ' ' || next === '\t')
|
|
143
|
+
next = source[++i + 1];
|
|
144
|
+
}
|
|
138
145
|
else if (next === 'x' || next === 'u' || next === 'U') {
|
|
139
146
|
const length = { x: 2, u: 4, U: 8 }[next];
|
|
140
147
|
res += parseCharCode(source, i + 1, length, onError);
|
|
@@ -152,7 +159,7 @@ function doubleQuotedValue(source, onError) {
|
|
|
152
159
|
let next = source[i + 1];
|
|
153
160
|
while (next === ' ' || next === '\t')
|
|
154
161
|
next = source[++i + 1];
|
|
155
|
-
if (next !== '\n')
|
|
162
|
+
if (next !== '\n' && !(next === '\r' && source[i + 2] === '\n'))
|
|
156
163
|
res += i > wsStart ? source.slice(wsStart, i + 1) : ch;
|
|
157
164
|
}
|
|
158
165
|
else {
|
|
@@ -59,6 +59,8 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
|
|
|
59
59
|
case 'anchor':
|
|
60
60
|
if (anchor)
|
|
61
61
|
onError(token, 'MULTIPLE_ANCHORS', 'A node can have at most one anchor');
|
|
62
|
+
if (token.source.endsWith(':'))
|
|
63
|
+
onError(token.offset + token.source.length - 1, 'BAD_ALIAS', 'Anchor ending in : is ambiguous', true);
|
|
62
64
|
anchor = token;
|
|
63
65
|
if (start === null)
|
|
64
66
|
start = token.offset;
|
|
@@ -81,6 +83,8 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
|
|
|
81
83
|
// Could here handle preceding comments differently
|
|
82
84
|
if (anchor || tag)
|
|
83
85
|
onError(token, 'BAD_PROP_ORDER', `Anchors and tags must be after the ${token.source} indicator`);
|
|
86
|
+
if (found)
|
|
87
|
+
onError(token, 'UNEXPECTED_TOKEN', `Unexpected ${token.source} in ${flow !== null && flow !== void 0 ? flow : 'collection'}`);
|
|
84
88
|
found = token;
|
|
85
89
|
atNewline = false;
|
|
86
90
|
hasSpace = false;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { containsNewline } from './util-contains-newline.js';
|
|
2
|
+
|
|
3
|
+
function flowIndentCheck(indent, fc, onError) {
|
|
4
|
+
if ((fc === null || fc === void 0 ? void 0 : fc.type) === 'flow-collection') {
|
|
5
|
+
const end = fc.end[0];
|
|
6
|
+
if (end.indent === indent &&
|
|
7
|
+
(end.source === ']' || end.source === '}') &&
|
|
8
|
+
containsNewline(fc)) {
|
|
9
|
+
const msg = 'Flow end indicator should be more indented than parent';
|
|
10
|
+
onError(end, 'BAD_INDENT', msg, true);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { flowIndentCheck };
|
|
@@ -1,9 +1,8 @@
|
|
|
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
|
-
import { defaultOptions } from '../options.js';
|
|
7
6
|
import { Schema } from '../schema/Schema.js';
|
|
8
7
|
import { stringify } from '../stringify/stringify.js';
|
|
9
8
|
import { stringifyDocument } from '../stringify/stringifyDocument.js';
|
|
@@ -31,7 +30,15 @@ class Document {
|
|
|
31
30
|
options = replacer;
|
|
32
31
|
replacer = undefined;
|
|
33
32
|
}
|
|
34
|
-
const opt = Object.assign({
|
|
33
|
+
const opt = Object.assign({
|
|
34
|
+
intAsBigInt: false,
|
|
35
|
+
keepSourceTokens: false,
|
|
36
|
+
logLevel: 'warn',
|
|
37
|
+
prettyErrors: true,
|
|
38
|
+
strict: true,
|
|
39
|
+
uniqueKeys: true,
|
|
40
|
+
version: '1.2'
|
|
41
|
+
}, options);
|
|
35
42
|
this.options = opt;
|
|
36
43
|
let { version } = opt;
|
|
37
44
|
if (options === null || options === void 0 ? void 0 : options.directives) {
|
|
@@ -48,6 +55,30 @@ class Document {
|
|
|
48
55
|
this.contents = this.createNode(value, _replacer, options);
|
|
49
56
|
}
|
|
50
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Create a deep copy of this Document and its contents.
|
|
60
|
+
*
|
|
61
|
+
* Custom Node values that inherit from `Object` still refer to their original instances.
|
|
62
|
+
*/
|
|
63
|
+
clone() {
|
|
64
|
+
const copy = Object.create(Document.prototype, {
|
|
65
|
+
[NODE_TYPE]: { value: DOC }
|
|
66
|
+
});
|
|
67
|
+
copy.commentBefore = this.commentBefore;
|
|
68
|
+
copy.comment = this.comment;
|
|
69
|
+
copy.errors = this.errors.slice();
|
|
70
|
+
copy.warnings = this.warnings.slice();
|
|
71
|
+
copy.options = Object.assign({}, this.options);
|
|
72
|
+
if (this.directives)
|
|
73
|
+
copy.directives = this.directives.clone();
|
|
74
|
+
copy.schema = this.schema.clone();
|
|
75
|
+
copy.contents = isNode(this.contents)
|
|
76
|
+
? this.contents.clone(copy.schema)
|
|
77
|
+
: this.contents;
|
|
78
|
+
if (this.range)
|
|
79
|
+
copy.range = this.range.slice();
|
|
80
|
+
return copy;
|
|
81
|
+
}
|
|
51
82
|
/** Adds a value to the document. */
|
|
52
83
|
add(value) {
|
|
53
84
|
if (assertCollection(this.contents))
|
|
@@ -71,6 +102,7 @@ class Document {
|
|
|
71
102
|
if (!node.anchor) {
|
|
72
103
|
const prev = anchorNames(this);
|
|
73
104
|
node.anchor =
|
|
105
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
74
106
|
!name || prev.has(name) ? findNewAnchor(name || 'a', prev) : name;
|
|
75
107
|
}
|
|
76
108
|
return new Alias(node.anchor);
|
|
@@ -92,9 +124,12 @@ class Document {
|
|
|
92
124
|
options = replacer;
|
|
93
125
|
replacer = undefined;
|
|
94
126
|
}
|
|
95
|
-
const { anchorPrefix, flow, keepUndefined, onTagObj, tag } = options
|
|
96
|
-
const { onAnchor, setAnchors, sourceObjects } = createNodeAnchors(this,
|
|
127
|
+
const { aliasDuplicateObjects, anchorPrefix, flow, keepUndefined, onTagObj, tag } = options !== null && options !== void 0 ? options : {};
|
|
128
|
+
const { onAnchor, setAnchors, sourceObjects } = createNodeAnchors(this,
|
|
129
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
130
|
+
anchorPrefix || 'a');
|
|
97
131
|
const ctx = {
|
|
132
|
+
aliasDuplicateObjects: aliasDuplicateObjects !== null && aliasDuplicateObjects !== void 0 ? aliasDuplicateObjects : true,
|
|
98
133
|
keepUndefined: keepUndefined !== null && keepUndefined !== void 0 ? keepUndefined : false,
|
|
99
134
|
onAnchor,
|
|
100
135
|
onTagObj,
|
|
@@ -205,26 +240,48 @@ class Document {
|
|
|
205
240
|
}
|
|
206
241
|
/**
|
|
207
242
|
* Change the YAML version and schema used by the document.
|
|
243
|
+
* A `null` version disables support for directives, explicit tags, anchors, and aliases.
|
|
244
|
+
* It also requires the `schema` option to be given as a `Schema` instance value.
|
|
208
245
|
*
|
|
209
|
-
* Overrides all previously set schema options
|
|
246
|
+
* Overrides all previously set schema options.
|
|
210
247
|
*/
|
|
211
|
-
setSchema(version, options) {
|
|
212
|
-
|
|
213
|
-
|
|
248
|
+
setSchema(version, options = {}) {
|
|
249
|
+
if (typeof version === 'number')
|
|
250
|
+
version = String(version);
|
|
251
|
+
let opt;
|
|
252
|
+
switch (version) {
|
|
214
253
|
case '1.1':
|
|
215
|
-
this.directives
|
|
216
|
-
|
|
254
|
+
if (this.directives)
|
|
255
|
+
this.directives.yaml.version = '1.1';
|
|
256
|
+
else
|
|
257
|
+
this.directives = new Directives({ version: '1.1' });
|
|
258
|
+
opt = { merge: true, resolveKnownTags: false, schema: 'yaml-1.1' };
|
|
217
259
|
break;
|
|
218
260
|
case '1.2':
|
|
219
|
-
|
|
220
|
-
|
|
261
|
+
case 'next':
|
|
262
|
+
if (this.directives)
|
|
263
|
+
this.directives.yaml.version = version;
|
|
264
|
+
else
|
|
265
|
+
this.directives = new Directives({ version });
|
|
266
|
+
opt = { merge: false, resolveKnownTags: true, schema: 'core' };
|
|
267
|
+
break;
|
|
268
|
+
case null:
|
|
269
|
+
if (this.directives)
|
|
270
|
+
delete this.directives;
|
|
271
|
+
opt = null;
|
|
221
272
|
break;
|
|
222
273
|
default: {
|
|
223
274
|
const sv = JSON.stringify(version);
|
|
224
|
-
throw new Error(`Expected '1.1'
|
|
275
|
+
throw new Error(`Expected '1.1', '1.2' or null as first argument, but found: ${sv}`);
|
|
225
276
|
}
|
|
226
277
|
}
|
|
227
|
-
|
|
278
|
+
// Not using `instanceof Schema` to allow for duck typing
|
|
279
|
+
if (options.schema instanceof Object)
|
|
280
|
+
this.schema = options.schema;
|
|
281
|
+
else if (opt)
|
|
282
|
+
this.schema = new Schema(Object.assign(opt, options));
|
|
283
|
+
else
|
|
284
|
+
throw new Error(`With a null YAML version, the { schema: Schema } option is required`);
|
|
228
285
|
}
|
|
229
286
|
// json & jsonArg are only used from toJSON()
|
|
230
287
|
toJS({ json, jsonArg, mapAsMap, maxAliasCount, onAnchor, reviver } = {}) {
|
|
@@ -237,7 +294,7 @@ class Document {
|
|
|
237
294
|
maxAliasCount: typeof maxAliasCount === 'number' ? maxAliasCount : 100,
|
|
238
295
|
stringify
|
|
239
296
|
};
|
|
240
|
-
const res = toJS(this.contents, jsonArg
|
|
297
|
+
const res = toJS(this.contents, jsonArg !== null && jsonArg !== void 0 ? jsonArg : '', ctx);
|
|
241
298
|
if (typeof onAnchor === 'function')
|
|
242
299
|
for (const { count, res } of ctx.anchors.values())
|
|
243
300
|
onAnchor(res, count);
|
|
@@ -37,7 +37,7 @@ function createNodeAnchors(doc, prefix) {
|
|
|
37
37
|
const sourceObjects = new Map();
|
|
38
38
|
let prevAnchors = null;
|
|
39
39
|
return {
|
|
40
|
-
onAnchor(source) {
|
|
40
|
+
onAnchor: (source) => {
|
|
41
41
|
aliasObjects.push(source);
|
|
42
42
|
if (!prevAnchors)
|
|
43
43
|
prevAnchors = anchorNames(doc);
|
|
@@ -50,7 +50,7 @@ function createNodeAnchors(doc, prefix) {
|
|
|
50
50
|
* of its child nodes are. This is why anchors are set only after all of
|
|
51
51
|
* the nodes have been created.
|
|
52
52
|
*/
|
|
53
|
-
setAnchors() {
|
|
53
|
+
setAnchors: () => {
|
|
54
54
|
for (const source of aliasObjects) {
|
|
55
55
|
const ref = sourceObjects.get(source);
|
|
56
56
|
if (typeof ref === 'object' &&
|