yaml 2.8.2 → 3.0.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 +65 -85
- package/{bin.mjs → bin.js} +1 -1
- package/dist/chunk-BYypO7fO.js +18 -0
- package/dist/cli.d.ts +10 -7
- package/dist/cli.js +181 -0
- package/dist/directives-CG6n4xSM.js +2856 -0
- package/dist/index.d.ts +335 -25
- package/dist/index.js +4 -49
- package/dist/line-counter-TFl552k_.js +3098 -0
- package/dist/public-api-BE74JyVm.js +79 -0
- package/dist/stringifyString-S_ITVLTO.d.ts +1306 -0
- package/dist/test-events.d.ts +6 -3
- package/dist/test-events.js +98 -124
- package/dist/util.d.ts +2 -16
- package/dist/util.js +2 -27
- package/package.json +20 -44
- package/browser/dist/compose/compose-collection.js +0 -88
- package/browser/dist/compose/compose-doc.js +0 -43
- package/browser/dist/compose/compose-node.js +0 -102
- package/browser/dist/compose/compose-scalar.js +0 -86
- package/browser/dist/compose/composer.js +0 -217
- package/browser/dist/compose/resolve-block-map.js +0 -115
- package/browser/dist/compose/resolve-block-scalar.js +0 -198
- package/browser/dist/compose/resolve-block-seq.js +0 -49
- package/browser/dist/compose/resolve-end.js +0 -37
- package/browser/dist/compose/resolve-flow-collection.js +0 -207
- package/browser/dist/compose/resolve-flow-scalar.js +0 -223
- package/browser/dist/compose/resolve-props.js +0 -146
- package/browser/dist/compose/util-contains-newline.js +0 -34
- package/browser/dist/compose/util-empty-scalar-position.js +0 -26
- package/browser/dist/compose/util-flow-indent-check.js +0 -15
- package/browser/dist/compose/util-map-includes.js +0 -13
- package/browser/dist/doc/Document.js +0 -335
- package/browser/dist/doc/anchors.js +0 -71
- package/browser/dist/doc/applyReviver.js +0 -55
- package/browser/dist/doc/createNode.js +0 -88
- package/browser/dist/doc/directives.js +0 -176
- package/browser/dist/errors.js +0 -57
- package/browser/dist/index.js +0 -17
- package/browser/dist/log.js +0 -11
- package/browser/dist/nodes/Alias.js +0 -114
- package/browser/dist/nodes/Collection.js +0 -147
- package/browser/dist/nodes/Node.js +0 -38
- package/browser/dist/nodes/Pair.js +0 -36
- package/browser/dist/nodes/Scalar.js +0 -24
- package/browser/dist/nodes/YAMLMap.js +0 -144
- package/browser/dist/nodes/YAMLSeq.js +0 -113
- package/browser/dist/nodes/addPairToJSMap.js +0 -63
- package/browser/dist/nodes/identity.js +0 -36
- package/browser/dist/nodes/toJS.js +0 -37
- package/browser/dist/parse/cst-scalar.js +0 -214
- package/browser/dist/parse/cst-stringify.js +0 -61
- package/browser/dist/parse/cst-visit.js +0 -97
- package/browser/dist/parse/cst.js +0 -98
- package/browser/dist/parse/lexer.js +0 -717
- package/browser/dist/parse/line-counter.js +0 -39
- package/browser/dist/parse/parser.js +0 -967
- package/browser/dist/public-api.js +0 -102
- package/browser/dist/schema/Schema.js +0 -37
- package/browser/dist/schema/common/map.js +0 -17
- package/browser/dist/schema/common/null.js +0 -15
- package/browser/dist/schema/common/seq.js +0 -17
- package/browser/dist/schema/common/string.js +0 -14
- package/browser/dist/schema/core/bool.js +0 -19
- package/browser/dist/schema/core/float.js +0 -43
- package/browser/dist/schema/core/int.js +0 -38
- package/browser/dist/schema/core/schema.js +0 -23
- package/browser/dist/schema/json/schema.js +0 -62
- package/browser/dist/schema/tags.js +0 -96
- package/browser/dist/schema/yaml-1.1/binary.js +0 -58
- package/browser/dist/schema/yaml-1.1/bool.js +0 -26
- package/browser/dist/schema/yaml-1.1/float.js +0 -46
- package/browser/dist/schema/yaml-1.1/int.js +0 -71
- package/browser/dist/schema/yaml-1.1/merge.js +0 -64
- package/browser/dist/schema/yaml-1.1/omap.js +0 -74
- package/browser/dist/schema/yaml-1.1/pairs.js +0 -78
- package/browser/dist/schema/yaml-1.1/schema.js +0 -39
- package/browser/dist/schema/yaml-1.1/set.js +0 -93
- package/browser/dist/schema/yaml-1.1/timestamp.js +0 -101
- package/browser/dist/stringify/foldFlowLines.js +0 -146
- package/browser/dist/stringify/stringify.js +0 -128
- package/browser/dist/stringify/stringifyCollection.js +0 -143
- package/browser/dist/stringify/stringifyComment.js +0 -20
- package/browser/dist/stringify/stringifyDocument.js +0 -85
- package/browser/dist/stringify/stringifyNumber.js +0 -24
- package/browser/dist/stringify/stringifyPair.js +0 -150
- package/browser/dist/stringify/stringifyString.js +0 -336
- package/browser/dist/util.js +0 -11
- package/browser/dist/visit.js +0 -233
- package/browser/index.js +0 -5
- package/browser/package.json +0 -3
- package/dist/cli.mjs +0 -201
- package/dist/compose/compose-collection.d.ts +0 -11
- package/dist/compose/compose-collection.js +0 -90
- package/dist/compose/compose-doc.d.ts +0 -7
- package/dist/compose/compose-doc.js +0 -45
- package/dist/compose/compose-node.d.ts +0 -29
- package/dist/compose/compose-node.js +0 -105
- package/dist/compose/compose-scalar.d.ts +0 -5
- package/dist/compose/compose-scalar.js +0 -88
- package/dist/compose/composer.d.ts +0 -63
- package/dist/compose/composer.js +0 -222
- package/dist/compose/resolve-block-map.d.ts +0 -6
- package/dist/compose/resolve-block-map.js +0 -117
- package/dist/compose/resolve-block-scalar.d.ts +0 -11
- package/dist/compose/resolve-block-scalar.js +0 -200
- package/dist/compose/resolve-block-seq.d.ts +0 -6
- package/dist/compose/resolve-block-seq.js +0 -51
- package/dist/compose/resolve-end.d.ts +0 -6
- package/dist/compose/resolve-end.js +0 -39
- package/dist/compose/resolve-flow-collection.d.ts +0 -7
- package/dist/compose/resolve-flow-collection.js +0 -209
- package/dist/compose/resolve-flow-scalar.d.ts +0 -10
- package/dist/compose/resolve-flow-scalar.js +0 -225
- package/dist/compose/resolve-props.d.ts +0 -23
- package/dist/compose/resolve-props.js +0 -148
- package/dist/compose/util-contains-newline.d.ts +0 -2
- package/dist/compose/util-contains-newline.js +0 -36
- package/dist/compose/util-empty-scalar-position.d.ts +0 -2
- package/dist/compose/util-empty-scalar-position.js +0 -28
- package/dist/compose/util-flow-indent-check.d.ts +0 -3
- package/dist/compose/util-flow-indent-check.js +0 -17
- package/dist/compose/util-map-includes.d.ts +0 -4
- package/dist/compose/util-map-includes.js +0 -15
- package/dist/doc/Document.d.ts +0 -141
- package/dist/doc/Document.js +0 -337
- package/dist/doc/anchors.d.ts +0 -24
- package/dist/doc/anchors.js +0 -76
- package/dist/doc/applyReviver.d.ts +0 -9
- package/dist/doc/applyReviver.js +0 -57
- package/dist/doc/createNode.d.ts +0 -17
- package/dist/doc/createNode.js +0 -90
- package/dist/doc/directives.d.ts +0 -49
- package/dist/doc/directives.js +0 -178
- package/dist/errors.d.ts +0 -21
- package/dist/errors.js +0 -62
- package/dist/log.d.ts +0 -3
- package/dist/log.js +0 -19
- package/dist/nodes/Alias.d.ts +0 -29
- package/dist/nodes/Alias.js +0 -116
- package/dist/nodes/Collection.d.ts +0 -73
- package/dist/nodes/Collection.js +0 -151
- package/dist/nodes/Node.d.ts +0 -53
- package/dist/nodes/Node.js +0 -40
- package/dist/nodes/Pair.d.ts +0 -22
- package/dist/nodes/Pair.js +0 -39
- package/dist/nodes/Scalar.d.ts +0 -43
- package/dist/nodes/Scalar.js +0 -27
- package/dist/nodes/YAMLMap.d.ts +0 -53
- package/dist/nodes/YAMLMap.js +0 -147
- package/dist/nodes/YAMLSeq.d.ts +0 -60
- package/dist/nodes/YAMLSeq.js +0 -115
- package/dist/nodes/addPairToJSMap.d.ts +0 -4
- package/dist/nodes/addPairToJSMap.js +0 -65
- package/dist/nodes/identity.d.ts +0 -23
- package/dist/nodes/identity.js +0 -53
- package/dist/nodes/toJS.d.ts +0 -29
- package/dist/nodes/toJS.js +0 -39
- package/dist/options.d.ts +0 -344
- package/dist/parse/cst-scalar.d.ts +0 -64
- package/dist/parse/cst-scalar.js +0 -218
- package/dist/parse/cst-stringify.d.ts +0 -8
- package/dist/parse/cst-stringify.js +0 -63
- package/dist/parse/cst-visit.d.ts +0 -39
- package/dist/parse/cst-visit.js +0 -99
- package/dist/parse/cst.d.ts +0 -109
- package/dist/parse/cst.js +0 -112
- package/dist/parse/lexer.d.ts +0 -87
- package/dist/parse/lexer.js +0 -719
- package/dist/parse/line-counter.d.ts +0 -22
- package/dist/parse/line-counter.js +0 -41
- package/dist/parse/parser.d.ts +0 -84
- package/dist/parse/parser.js +0 -972
- package/dist/public-api.d.ts +0 -44
- package/dist/public-api.js +0 -107
- package/dist/schema/Schema.d.ts +0 -17
- package/dist/schema/Schema.js +0 -39
- package/dist/schema/common/map.d.ts +0 -2
- package/dist/schema/common/map.js +0 -19
- package/dist/schema/common/null.d.ts +0 -4
- package/dist/schema/common/null.js +0 -17
- package/dist/schema/common/seq.d.ts +0 -2
- package/dist/schema/common/seq.js +0 -19
- package/dist/schema/common/string.d.ts +0 -2
- package/dist/schema/common/string.js +0 -16
- package/dist/schema/core/bool.d.ts +0 -4
- package/dist/schema/core/bool.js +0 -21
- package/dist/schema/core/float.d.ts +0 -4
- package/dist/schema/core/float.js +0 -47
- package/dist/schema/core/int.d.ts +0 -4
- package/dist/schema/core/int.js +0 -42
- package/dist/schema/core/schema.d.ts +0 -1
- package/dist/schema/core/schema.js +0 -25
- package/dist/schema/json/schema.d.ts +0 -2
- package/dist/schema/json/schema.js +0 -64
- package/dist/schema/json-schema.d.ts +0 -69
- package/dist/schema/tags.d.ts +0 -48
- package/dist/schema/tags.js +0 -99
- package/dist/schema/types.d.ts +0 -92
- package/dist/schema/yaml-1.1/binary.d.ts +0 -2
- package/dist/schema/yaml-1.1/binary.js +0 -70
- package/dist/schema/yaml-1.1/bool.d.ts +0 -7
- package/dist/schema/yaml-1.1/bool.js +0 -29
- package/dist/schema/yaml-1.1/float.d.ts +0 -4
- package/dist/schema/yaml-1.1/float.js +0 -50
- package/dist/schema/yaml-1.1/int.d.ts +0 -5
- package/dist/schema/yaml-1.1/int.js +0 -76
- package/dist/schema/yaml-1.1/merge.d.ts +0 -9
- package/dist/schema/yaml-1.1/merge.js +0 -68
- package/dist/schema/yaml-1.1/omap.d.ts +0 -22
- package/dist/schema/yaml-1.1/omap.js +0 -77
- package/dist/schema/yaml-1.1/pairs.d.ts +0 -10
- package/dist/schema/yaml-1.1/pairs.js +0 -82
- package/dist/schema/yaml-1.1/schema.d.ts +0 -1
- package/dist/schema/yaml-1.1/schema.js +0 -41
- package/dist/schema/yaml-1.1/set.d.ts +0 -28
- package/dist/schema/yaml-1.1/set.js +0 -96
- package/dist/schema/yaml-1.1/timestamp.d.ts +0 -6
- package/dist/schema/yaml-1.1/timestamp.js +0 -105
- package/dist/stringify/foldFlowLines.d.ts +0 -34
- package/dist/stringify/foldFlowLines.js +0 -151
- package/dist/stringify/stringify.d.ts +0 -21
- package/dist/stringify/stringify.js +0 -131
- package/dist/stringify/stringifyCollection.d.ts +0 -17
- package/dist/stringify/stringifyCollection.js +0 -145
- package/dist/stringify/stringifyComment.d.ts +0 -10
- package/dist/stringify/stringifyComment.js +0 -24
- package/dist/stringify/stringifyDocument.d.ts +0 -4
- package/dist/stringify/stringifyDocument.js +0 -87
- package/dist/stringify/stringifyNumber.d.ts +0 -2
- package/dist/stringify/stringifyNumber.js +0 -26
- package/dist/stringify/stringifyPair.d.ts +0 -3
- package/dist/stringify/stringifyPair.js +0 -152
- package/dist/stringify/stringifyString.d.ts +0 -9
- package/dist/stringify/stringifyString.js +0 -338
- package/dist/visit.d.ts +0 -102
- package/dist/visit.js +0 -236
- package/util.js +0 -2
|
@@ -0,0 +1,2856 @@
|
|
|
1
|
+
//#region src/doc/applyReviver.ts
|
|
2
|
+
/**
|
|
3
|
+
* Applies the JSON.parse reviver algorithm as defined in the ECMA-262 spec,
|
|
4
|
+
* in section 24.5.1.1 "Runtime Semantics: InternalizeJSONProperty" of the
|
|
5
|
+
* 2021 edition: https://tc39.es/ecma262/#sec-json.parse
|
|
6
|
+
*
|
|
7
|
+
* Includes extensions for handling Map and Set objects.
|
|
8
|
+
*/
|
|
9
|
+
function applyReviver(reviver, obj, key, val) {
|
|
10
|
+
if (val && typeof val === "object") if (Array.isArray(val)) for (let i = 0, len = val.length; i < len; ++i) {
|
|
11
|
+
const v0 = val[i];
|
|
12
|
+
const v1 = applyReviver(reviver, val, String(i), v0);
|
|
13
|
+
if (v1 === void 0) delete val[i];
|
|
14
|
+
else if (v1 !== v0) val[i] = v1;
|
|
15
|
+
}
|
|
16
|
+
else if (val instanceof Map) for (const k of Array.from(val.keys())) {
|
|
17
|
+
const v0 = val.get(k);
|
|
18
|
+
const v1 = applyReviver(reviver, val, k, v0);
|
|
19
|
+
if (v1 === void 0) val.delete(k);
|
|
20
|
+
else if (v1 !== v0) val.set(k, v1);
|
|
21
|
+
}
|
|
22
|
+
else if (val instanceof Set) for (const v0 of Array.from(val)) {
|
|
23
|
+
const v1 = applyReviver(reviver, val, v0, v0);
|
|
24
|
+
if (v1 === void 0) val.delete(v0);
|
|
25
|
+
else if (v1 !== v0) {
|
|
26
|
+
val.delete(v0);
|
|
27
|
+
val.add(v1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else for (const [k, v0] of Object.entries(val)) {
|
|
31
|
+
const v1 = applyReviver(reviver, val, k, v0);
|
|
32
|
+
if (v1 === void 0) delete val[k];
|
|
33
|
+
else if (v1 !== v0) val[k] = v1;
|
|
34
|
+
}
|
|
35
|
+
return reviver.call(obj, key, val);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/nodes/toJS.ts
|
|
40
|
+
/**
|
|
41
|
+
* Recursively convert any node or its contents to native JavaScript
|
|
42
|
+
*
|
|
43
|
+
* @param value - The input value
|
|
44
|
+
* @param arg - If `value` defines a `toJSON()` method, use this
|
|
45
|
+
* as its first argument
|
|
46
|
+
* @param ctx - Conversion context, originally set in Document#toJS(). If
|
|
47
|
+
* `{ keep: true }` is not set, output should be suitable for JSON
|
|
48
|
+
* stringification.
|
|
49
|
+
*/
|
|
50
|
+
function toJS(value, arg, ctx) {
|
|
51
|
+
if (Array.isArray(value)) return value.map((v, i) => toJS(v, String(i), ctx));
|
|
52
|
+
if (value && typeof value.toJSON === "function") {
|
|
53
|
+
const node = value;
|
|
54
|
+
if (!ctx || !(node instanceof NodeBase) || !node.anchor) return value.toJSON(arg, ctx);
|
|
55
|
+
const data = {
|
|
56
|
+
aliasCount: 0,
|
|
57
|
+
count: 1,
|
|
58
|
+
res: void 0
|
|
59
|
+
};
|
|
60
|
+
ctx.anchors.set(node, data);
|
|
61
|
+
ctx.onCreate = (res) => {
|
|
62
|
+
data.res = res;
|
|
63
|
+
delete ctx.onCreate;
|
|
64
|
+
};
|
|
65
|
+
const res = node.toJSON(arg, ctx);
|
|
66
|
+
if (ctx.onCreate) ctx.onCreate(res);
|
|
67
|
+
return res;
|
|
68
|
+
}
|
|
69
|
+
if (typeof value === "bigint" && !ctx?.keep) return Number(value);
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/nodes/Node.ts
|
|
75
|
+
var NodeBase = class {
|
|
76
|
+
/** Create a copy of this node. */
|
|
77
|
+
clone(_schema) {
|
|
78
|
+
const copy = Object.create(Object.getPrototypeOf(this), Object.getOwnPropertyDescriptors(this));
|
|
79
|
+
if (this.range) copy.range = this.range.slice();
|
|
80
|
+
return copy;
|
|
81
|
+
}
|
|
82
|
+
/** A plain JavaScript representation of this node. */
|
|
83
|
+
toJS(doc, { mapAsMap, maxAliasCount, onAnchor, reviver } = {}) {
|
|
84
|
+
if (!doc?.schema) throw new TypeError("A document argument is required");
|
|
85
|
+
const ctx = {
|
|
86
|
+
anchors: /* @__PURE__ */ new Map(),
|
|
87
|
+
doc,
|
|
88
|
+
keep: true,
|
|
89
|
+
mapAsMap: mapAsMap === true,
|
|
90
|
+
mapKeyWarned: false,
|
|
91
|
+
maxAliasCount: typeof maxAliasCount === "number" ? maxAliasCount : 100
|
|
92
|
+
};
|
|
93
|
+
const res = toJS(this, "", ctx);
|
|
94
|
+
if (typeof onAnchor === "function") for (const { count, res } of ctx.anchors.values()) onAnchor(res, count);
|
|
95
|
+
return typeof reviver === "function" ? applyReviver(reviver, { "": res }, "", res) : res;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
//#endregion
|
|
100
|
+
//#region src/nodes/Scalar.ts
|
|
101
|
+
var Scalar = class extends NodeBase {
|
|
102
|
+
static BLOCK_FOLDED = "BLOCK_FOLDED";
|
|
103
|
+
static BLOCK_LITERAL = "BLOCK_LITERAL";
|
|
104
|
+
static PLAIN = "PLAIN";
|
|
105
|
+
static QUOTE_DOUBLE = "QUOTE_DOUBLE";
|
|
106
|
+
static QUOTE_SINGLE = "QUOTE_SINGLE";
|
|
107
|
+
value;
|
|
108
|
+
constructor(value) {
|
|
109
|
+
super();
|
|
110
|
+
this.value = value;
|
|
111
|
+
}
|
|
112
|
+
toJSON(arg, ctx) {
|
|
113
|
+
return ctx?.keep ? this.value : toJS(this.value, arg, ctx);
|
|
114
|
+
}
|
|
115
|
+
toString() {
|
|
116
|
+
return String(this.value);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region src/stringify/foldFlowLines.ts
|
|
122
|
+
const FOLD_FLOW = "flow";
|
|
123
|
+
const FOLD_BLOCK = "block";
|
|
124
|
+
const FOLD_QUOTED = "quoted";
|
|
125
|
+
/**
|
|
126
|
+
* Tries to keep input at up to `lineWidth` characters, splitting only on spaces
|
|
127
|
+
* not followed by newlines or spaces unless `mode` is `'quoted'`. Lines are
|
|
128
|
+
* terminated with `\n` and started with `indent`.
|
|
129
|
+
*/
|
|
130
|
+
function foldFlowLines(text, indent, mode = "flow", { indentAtStart, lineWidth = 80, minContentWidth = 20, onFold, onOverflow } = {}) {
|
|
131
|
+
if (!lineWidth || lineWidth < 0) return text;
|
|
132
|
+
if (lineWidth < minContentWidth) minContentWidth = 0;
|
|
133
|
+
const endStep = Math.max(1 + minContentWidth, 1 + lineWidth - indent.length);
|
|
134
|
+
if (text.length <= endStep) return text;
|
|
135
|
+
const folds = [];
|
|
136
|
+
const escapedFolds = {};
|
|
137
|
+
let end = lineWidth - indent.length;
|
|
138
|
+
if (typeof indentAtStart === "number") if (indentAtStart > lineWidth - Math.max(2, minContentWidth)) folds.push(0);
|
|
139
|
+
else end = lineWidth - indentAtStart;
|
|
140
|
+
let split = void 0;
|
|
141
|
+
let prev = void 0;
|
|
142
|
+
let overflow = false;
|
|
143
|
+
let i = -1;
|
|
144
|
+
let escStart = -1;
|
|
145
|
+
let escEnd = -1;
|
|
146
|
+
if (mode === FOLD_BLOCK) {
|
|
147
|
+
i = consumeMoreIndentedLines(text, i, indent.length);
|
|
148
|
+
if (i !== -1) end = i + endStep;
|
|
149
|
+
}
|
|
150
|
+
for (let ch; ch = text[i += 1];) {
|
|
151
|
+
if (mode === FOLD_QUOTED && ch === "\\") {
|
|
152
|
+
escStart = i;
|
|
153
|
+
switch (text[i + 1]) {
|
|
154
|
+
case "x":
|
|
155
|
+
i += 3;
|
|
156
|
+
break;
|
|
157
|
+
case "u":
|
|
158
|
+
i += 5;
|
|
159
|
+
break;
|
|
160
|
+
case "U":
|
|
161
|
+
i += 9;
|
|
162
|
+
break;
|
|
163
|
+
default: i += 1;
|
|
164
|
+
}
|
|
165
|
+
escEnd = i;
|
|
166
|
+
}
|
|
167
|
+
if (ch === "\n") {
|
|
168
|
+
if (mode === FOLD_BLOCK) i = consumeMoreIndentedLines(text, i, indent.length);
|
|
169
|
+
end = i + indent.length + endStep;
|
|
170
|
+
split = void 0;
|
|
171
|
+
} else {
|
|
172
|
+
if (ch === " " && prev && prev !== " " && prev !== "\n" && prev !== " ") {
|
|
173
|
+
const next = text[i + 1];
|
|
174
|
+
if (next && next !== " " && next !== "\n" && next !== " ") split = i;
|
|
175
|
+
}
|
|
176
|
+
if (i >= end) if (split) {
|
|
177
|
+
folds.push(split);
|
|
178
|
+
end = split + endStep;
|
|
179
|
+
split = void 0;
|
|
180
|
+
} else if (mode === FOLD_QUOTED) {
|
|
181
|
+
while (prev === " " || prev === " ") {
|
|
182
|
+
prev = ch;
|
|
183
|
+
ch = text[i += 1];
|
|
184
|
+
overflow = true;
|
|
185
|
+
}
|
|
186
|
+
const j = i > escEnd + 1 ? i - 2 : escStart - 1;
|
|
187
|
+
if (escapedFolds[j]) return text;
|
|
188
|
+
folds.push(j);
|
|
189
|
+
escapedFolds[j] = true;
|
|
190
|
+
end = j + endStep;
|
|
191
|
+
split = void 0;
|
|
192
|
+
} else overflow = true;
|
|
193
|
+
}
|
|
194
|
+
prev = ch;
|
|
195
|
+
}
|
|
196
|
+
if (overflow && onOverflow) onOverflow();
|
|
197
|
+
if (folds.length === 0) return text;
|
|
198
|
+
if (onFold) onFold();
|
|
199
|
+
let res = text.slice(0, folds[0]);
|
|
200
|
+
for (let i = 0; i < folds.length; ++i) {
|
|
201
|
+
const fold = folds[i];
|
|
202
|
+
const end = folds[i + 1] || text.length;
|
|
203
|
+
if (fold === 0) res = `\n${indent}${text.slice(0, end)}`;
|
|
204
|
+
else {
|
|
205
|
+
if (mode === FOLD_QUOTED && escapedFolds[fold]) res += `${text[fold]}\\`;
|
|
206
|
+
res += `\n${indent}${text.slice(fold + 1, end)}`;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return res;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Presumes `i + 1` is at the start of a line
|
|
213
|
+
* @returns index of last newline in more-indented block
|
|
214
|
+
*/
|
|
215
|
+
function consumeMoreIndentedLines(text, i, indent) {
|
|
216
|
+
let end = i;
|
|
217
|
+
let start = i + 1;
|
|
218
|
+
let ch = text[start];
|
|
219
|
+
while (ch === " " || ch === " ") if (i < start + indent) ch = text[++i];
|
|
220
|
+
else {
|
|
221
|
+
do
|
|
222
|
+
ch = text[++i];
|
|
223
|
+
while (ch && ch !== "\n");
|
|
224
|
+
end = i;
|
|
225
|
+
start = i + 1;
|
|
226
|
+
ch = text[start];
|
|
227
|
+
}
|
|
228
|
+
return end;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region src/stringify/stringifyString.ts
|
|
233
|
+
const getFoldOptions = (ctx, isBlock) => ({
|
|
234
|
+
indentAtStart: isBlock ? ctx.indent.length : ctx.indentAtStart,
|
|
235
|
+
lineWidth: ctx.options.lineWidth,
|
|
236
|
+
minContentWidth: ctx.options.minContentWidth
|
|
237
|
+
});
|
|
238
|
+
const containsDocumentMarker = (str) => /^(%|---|\.\.\.)/m.test(str);
|
|
239
|
+
function lineLengthOverLimit(str, lineWidth, indentLength) {
|
|
240
|
+
if (!lineWidth || lineWidth < 0) return false;
|
|
241
|
+
const limit = lineWidth - indentLength;
|
|
242
|
+
const strLen = str.length;
|
|
243
|
+
if (strLen <= limit) return false;
|
|
244
|
+
for (let i = 0, start = 0; i < strLen; ++i) if (str[i] === "\n") {
|
|
245
|
+
if (i - start > limit) return true;
|
|
246
|
+
start = i + 1;
|
|
247
|
+
if (strLen - start <= limit) return false;
|
|
248
|
+
}
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
function doubleQuotedString(value, ctx) {
|
|
252
|
+
const json = JSON.stringify(value);
|
|
253
|
+
if (ctx.options.doubleQuotedAsJSON) return json;
|
|
254
|
+
const { implicitKey } = ctx;
|
|
255
|
+
const minMultiLineLength = ctx.options.doubleQuotedMinMultiLineLength;
|
|
256
|
+
const indent = ctx.indent || (containsDocumentMarker(value) ? " " : "");
|
|
257
|
+
let str = "";
|
|
258
|
+
let start = 0;
|
|
259
|
+
for (let i = 0, ch = json[i]; ch; ch = json[++i]) {
|
|
260
|
+
if (ch === " " && json[i + 1] === "\\" && json[i + 2] === "n") {
|
|
261
|
+
str += json.slice(start, i) + "\\ ";
|
|
262
|
+
i += 1;
|
|
263
|
+
start = i;
|
|
264
|
+
ch = "\\";
|
|
265
|
+
}
|
|
266
|
+
if (ch === "\\") switch (json[i + 1]) {
|
|
267
|
+
case "u":
|
|
268
|
+
{
|
|
269
|
+
str += json.slice(start, i);
|
|
270
|
+
const code = json.substr(i + 2, 4);
|
|
271
|
+
switch (code) {
|
|
272
|
+
case "0000":
|
|
273
|
+
str += "\\0";
|
|
274
|
+
break;
|
|
275
|
+
case "0007":
|
|
276
|
+
str += "\\a";
|
|
277
|
+
break;
|
|
278
|
+
case "000b":
|
|
279
|
+
str += "\\v";
|
|
280
|
+
break;
|
|
281
|
+
case "001b":
|
|
282
|
+
str += "\\e";
|
|
283
|
+
break;
|
|
284
|
+
case "0085":
|
|
285
|
+
str += "\\N";
|
|
286
|
+
break;
|
|
287
|
+
case "00a0":
|
|
288
|
+
str += "\\_";
|
|
289
|
+
break;
|
|
290
|
+
case "2028":
|
|
291
|
+
str += "\\L";
|
|
292
|
+
break;
|
|
293
|
+
case "2029":
|
|
294
|
+
str += "\\P";
|
|
295
|
+
break;
|
|
296
|
+
default: if (code.substr(0, 2) === "00") str += "\\x" + code.substr(2);
|
|
297
|
+
else str += json.substr(i, 6);
|
|
298
|
+
}
|
|
299
|
+
i += 5;
|
|
300
|
+
start = i + 1;
|
|
301
|
+
}
|
|
302
|
+
break;
|
|
303
|
+
case "n":
|
|
304
|
+
if (implicitKey || json[i + 2] === "\"" || json.length < minMultiLineLength) i += 1;
|
|
305
|
+
else {
|
|
306
|
+
str += json.slice(start, i) + "\n\n";
|
|
307
|
+
while (json[i + 2] === "\\" && json[i + 3] === "n" && json[i + 4] !== "\"") {
|
|
308
|
+
str += "\n";
|
|
309
|
+
i += 2;
|
|
310
|
+
}
|
|
311
|
+
str += indent;
|
|
312
|
+
if (json[i + 2] === " ") str += "\\";
|
|
313
|
+
i += 1;
|
|
314
|
+
start = i + 1;
|
|
315
|
+
}
|
|
316
|
+
break;
|
|
317
|
+
default: i += 1;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
str = start ? str + json.slice(start) : json;
|
|
321
|
+
return implicitKey ? str : foldFlowLines(str, indent, FOLD_QUOTED, getFoldOptions(ctx, false));
|
|
322
|
+
}
|
|
323
|
+
function singleQuotedString(value, ctx) {
|
|
324
|
+
if (ctx.options.singleQuote === false || ctx.implicitKey && value.includes("\n") || /[ \t]\n|\n[ \t]/.test(value)) return doubleQuotedString(value, ctx);
|
|
325
|
+
const indent = ctx.indent || (containsDocumentMarker(value) ? " " : "");
|
|
326
|
+
const res = "'" + value.replace(/'/g, "''").replace(/\n+/g, `$&\n${indent}`) + "'";
|
|
327
|
+
return ctx.implicitKey ? res : foldFlowLines(res, indent, FOLD_FLOW, getFoldOptions(ctx, false));
|
|
328
|
+
}
|
|
329
|
+
function quotedString(value, ctx) {
|
|
330
|
+
const { singleQuote } = ctx.options;
|
|
331
|
+
let qs;
|
|
332
|
+
if (singleQuote === false) qs = doubleQuotedString;
|
|
333
|
+
else {
|
|
334
|
+
const hasDouble = value.includes("\"");
|
|
335
|
+
const hasSingle = value.includes("'");
|
|
336
|
+
if (hasDouble && !hasSingle) qs = singleQuotedString;
|
|
337
|
+
else if (hasSingle && !hasDouble) qs = doubleQuotedString;
|
|
338
|
+
else qs = singleQuote ? singleQuotedString : doubleQuotedString;
|
|
339
|
+
}
|
|
340
|
+
return qs(value, ctx);
|
|
341
|
+
}
|
|
342
|
+
let blockEndNewlines;
|
|
343
|
+
try {
|
|
344
|
+
blockEndNewlines = /* @__PURE__ */ new RegExp("(^|(?<!\n))\n+(?!\n|$)", "g");
|
|
345
|
+
} catch {
|
|
346
|
+
blockEndNewlines = /\n+(?!\n|$)/g;
|
|
347
|
+
}
|
|
348
|
+
function blockString({ comment, type, value }, ctx, onComment, onChompKeep) {
|
|
349
|
+
const { blockQuote, commentString, lineWidth } = ctx.options;
|
|
350
|
+
if (!blockQuote || /\n[\t ]+$/.test(value)) return quotedString(value, ctx);
|
|
351
|
+
const indent = ctx.indent || (ctx.forceBlockIndent || containsDocumentMarker(value) ? " " : "");
|
|
352
|
+
const literal = blockQuote === "literal" ? true : blockQuote === "folded" || type === Scalar.BLOCK_FOLDED ? false : type === Scalar.BLOCK_LITERAL ? true : !lineLengthOverLimit(value, lineWidth, indent.length);
|
|
353
|
+
if (!value) return literal ? "|\n" : ">\n";
|
|
354
|
+
let chomp;
|
|
355
|
+
let endStart;
|
|
356
|
+
for (endStart = value.length; endStart > 0; --endStart) {
|
|
357
|
+
const ch = value[endStart - 1];
|
|
358
|
+
if (ch !== "\n" && ch !== " " && ch !== " ") break;
|
|
359
|
+
}
|
|
360
|
+
let end = value.substring(endStart);
|
|
361
|
+
const endNlPos = end.indexOf("\n");
|
|
362
|
+
if (endNlPos === -1) chomp = "-";
|
|
363
|
+
else if (value === end || endNlPos !== end.length - 1) {
|
|
364
|
+
chomp = "+";
|
|
365
|
+
if (onChompKeep) onChompKeep();
|
|
366
|
+
} else chomp = "";
|
|
367
|
+
if (end) {
|
|
368
|
+
value = value.slice(0, -end.length);
|
|
369
|
+
if (end[end.length - 1] === "\n") end = end.slice(0, -1);
|
|
370
|
+
end = end.replace(blockEndNewlines, `$&${indent}`);
|
|
371
|
+
}
|
|
372
|
+
let startWithSpace = false;
|
|
373
|
+
let startEnd;
|
|
374
|
+
let startNlPos = -1;
|
|
375
|
+
for (startEnd = 0; startEnd < value.length; ++startEnd) {
|
|
376
|
+
const ch = value[startEnd];
|
|
377
|
+
if (ch === " ") startWithSpace = true;
|
|
378
|
+
else if (ch === "\n") startNlPos = startEnd;
|
|
379
|
+
else break;
|
|
380
|
+
}
|
|
381
|
+
let start = value.substring(0, startNlPos < startEnd ? startNlPos + 1 : startEnd);
|
|
382
|
+
if (start) {
|
|
383
|
+
value = value.substring(start.length);
|
|
384
|
+
start = start.replace(/\n+/g, `$&${indent}`);
|
|
385
|
+
}
|
|
386
|
+
let header = (startWithSpace ? indent ? "2" : "1" : "") + chomp;
|
|
387
|
+
if (comment) {
|
|
388
|
+
header += " " + commentString(comment.replace(/ ?[\r\n]+/g, " "));
|
|
389
|
+
if (onComment) onComment();
|
|
390
|
+
}
|
|
391
|
+
if (!literal) {
|
|
392
|
+
const foldedValue = value.replace(/\n+/g, "\n$&").replace(/(?:^|\n)([\t ].*)(?:([\n\t ]*)\n(?![\n\t ]))?/g, "$1$2").replace(/\n+/g, `$&${indent}`);
|
|
393
|
+
let literalFallback = false;
|
|
394
|
+
const foldOptions = getFoldOptions(ctx, true);
|
|
395
|
+
if (blockQuote !== "folded" && type !== Scalar.BLOCK_FOLDED) foldOptions.onOverflow = () => {
|
|
396
|
+
literalFallback = true;
|
|
397
|
+
};
|
|
398
|
+
const body = foldFlowLines(`${start}${foldedValue}${end}`, indent, FOLD_BLOCK, foldOptions);
|
|
399
|
+
if (!literalFallback) return `>${header}\n${indent}${body}`;
|
|
400
|
+
}
|
|
401
|
+
value = value.replace(/\n+/g, `$&${indent}`);
|
|
402
|
+
return `|${header}\n${indent}${start}${value}${end}`;
|
|
403
|
+
}
|
|
404
|
+
function plainString(item, ctx, onComment, onChompKeep) {
|
|
405
|
+
const { type, value } = item;
|
|
406
|
+
const { actualString, implicitKey, indent, indentStep, inFlow } = ctx;
|
|
407
|
+
if (implicitKey && value.includes("\n") || inFlow && /[[\]{},]/.test(value)) return quotedString(value, ctx);
|
|
408
|
+
if (/^[\n\t ,[\]{}#&*!|>'"%@`]|^[?-]$|^[?-][ \t]|[\n:][ \t]|[ \t]\n|[\n\t ]#|[\n\t :]$/.test(value)) return implicitKey || inFlow || !value.includes("\n") ? quotedString(value, ctx) : blockString(item, ctx, onComment, onChompKeep);
|
|
409
|
+
if (!implicitKey && !inFlow && type !== Scalar.PLAIN && value.includes("\n")) return blockString(item, ctx, onComment, onChompKeep);
|
|
410
|
+
if (containsDocumentMarker(value)) {
|
|
411
|
+
if (indent === "") {
|
|
412
|
+
ctx.forceBlockIndent = true;
|
|
413
|
+
return blockString(item, ctx, onComment, onChompKeep);
|
|
414
|
+
} else if (implicitKey && indent === indentStep) return quotedString(value, ctx);
|
|
415
|
+
}
|
|
416
|
+
const str = value.replace(/\n+/g, `$&\n${indent}`);
|
|
417
|
+
if (actualString) {
|
|
418
|
+
const test = (tag) => tag.default && tag.tag !== "tag:yaml.org,2002:str" && tag.test?.test(str);
|
|
419
|
+
const { compat, tags } = ctx.doc.schema;
|
|
420
|
+
if (tags.some(test) || compat?.some(test)) return quotedString(value, ctx);
|
|
421
|
+
}
|
|
422
|
+
return implicitKey ? str : foldFlowLines(str, indent, FOLD_FLOW, getFoldOptions(ctx, false));
|
|
423
|
+
}
|
|
424
|
+
function stringifyString(item, ctx, onComment, onChompKeep) {
|
|
425
|
+
const { implicitKey, inFlow } = ctx;
|
|
426
|
+
const ss = typeof item.value === "string" ? item : Object.assign({}, item, { value: String(item.value) });
|
|
427
|
+
let { type } = item;
|
|
428
|
+
if (type !== Scalar.QUOTE_DOUBLE) {
|
|
429
|
+
if (/[\x00-\x08\x0b-\x1f\x7f-\x9f\u{D800}-\u{DFFF}]/u.test(ss.value)) type = Scalar.QUOTE_DOUBLE;
|
|
430
|
+
}
|
|
431
|
+
const _stringify = (_type) => {
|
|
432
|
+
switch (_type) {
|
|
433
|
+
case Scalar.BLOCK_FOLDED:
|
|
434
|
+
case Scalar.BLOCK_LITERAL: return implicitKey || inFlow ? quotedString(ss.value, ctx) : blockString(ss, ctx, onComment, onChompKeep);
|
|
435
|
+
case Scalar.QUOTE_DOUBLE: return doubleQuotedString(ss.value, ctx);
|
|
436
|
+
case Scalar.QUOTE_SINGLE: return singleQuotedString(ss.value, ctx);
|
|
437
|
+
case Scalar.PLAIN: return plainString(ss, ctx, onComment, onChompKeep);
|
|
438
|
+
default: return null;
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
let res = _stringify(type);
|
|
442
|
+
if (res === null) {
|
|
443
|
+
const { defaultKeyType, defaultStringType } = ctx.options;
|
|
444
|
+
const t = implicitKey && defaultKeyType || defaultStringType;
|
|
445
|
+
res = _stringify(t);
|
|
446
|
+
if (res === null) throw new Error(`Unsupported default string type ${t}`);
|
|
447
|
+
}
|
|
448
|
+
return res;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
//#endregion
|
|
452
|
+
//#region src/doc/anchors.ts
|
|
453
|
+
/**
|
|
454
|
+
* Verify that the input string is a valid anchor.
|
|
455
|
+
*
|
|
456
|
+
* Will throw on errors.
|
|
457
|
+
*/
|
|
458
|
+
function anchorIsValid(anchor) {
|
|
459
|
+
if (/[\x00-\x19\s,[\]{}]/.test(anchor)) {
|
|
460
|
+
const msg = `Anchor must not contain whitespace or control characters: ${JSON.stringify(anchor)}`;
|
|
461
|
+
throw new Error(msg);
|
|
462
|
+
}
|
|
463
|
+
return true;
|
|
464
|
+
}
|
|
465
|
+
function anchorNames(root) {
|
|
466
|
+
const anchors = /* @__PURE__ */ new Set();
|
|
467
|
+
visit(root, { Value(_key, node) {
|
|
468
|
+
if (node.anchor) anchors.add(node.anchor);
|
|
469
|
+
} });
|
|
470
|
+
return anchors;
|
|
471
|
+
}
|
|
472
|
+
/** Find a new anchor name with the given `prefix` and a one-indexed suffix. */
|
|
473
|
+
function findNewAnchor(prefix, exclude) {
|
|
474
|
+
for (let i = 1;; ++i) {
|
|
475
|
+
const name = `${prefix}${i}`;
|
|
476
|
+
if (!exclude.has(name)) return name;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
//#endregion
|
|
481
|
+
//#region src/doc/NodeCreator.ts
|
|
482
|
+
const defaultTagPrefix = "tag:yaml.org,2002:";
|
|
483
|
+
var NodeCreator = class {
|
|
484
|
+
keepUndefined;
|
|
485
|
+
replacer;
|
|
486
|
+
schema;
|
|
487
|
+
#aliasDuplicateObjects;
|
|
488
|
+
#anchorPrefix;
|
|
489
|
+
#aliasObjects = [];
|
|
490
|
+
#doc;
|
|
491
|
+
#flow;
|
|
492
|
+
#onTagObj;
|
|
493
|
+
#prevAnchors = null;
|
|
494
|
+
#sourceObjects = /* @__PURE__ */ new Map();
|
|
495
|
+
constructor(docOrSchema, options = {}, replacer) {
|
|
496
|
+
this.keepUndefined = options.keepUndefined ?? false;
|
|
497
|
+
this.replacer = replacer;
|
|
498
|
+
this.#flow = options.flow ?? false;
|
|
499
|
+
this.#onTagObj = options.onTagObj;
|
|
500
|
+
this.#aliasDuplicateObjects = options.aliasDuplicateObjects ?? true;
|
|
501
|
+
this.#anchorPrefix = options.anchorPrefix || "a";
|
|
502
|
+
if (docOrSchema instanceof Document) {
|
|
503
|
+
this.#doc = docOrSchema;
|
|
504
|
+
this.schema = docOrSchema.schema;
|
|
505
|
+
} else this.schema = docOrSchema;
|
|
506
|
+
}
|
|
507
|
+
create(value, tagName) {
|
|
508
|
+
if (value instanceof Document) value = value.value;
|
|
509
|
+
if (value instanceof NodeBase) return value;
|
|
510
|
+
if (value instanceof Pair) {
|
|
511
|
+
const map = this.schema.map.nodeClass.from(this, null);
|
|
512
|
+
map.items.push(value);
|
|
513
|
+
return map;
|
|
514
|
+
}
|
|
515
|
+
if (value instanceof String || value instanceof Number || value instanceof Boolean || typeof BigInt !== "undefined" && value instanceof BigInt) value = value.valueOf();
|
|
516
|
+
let ref = void 0;
|
|
517
|
+
if (this.#aliasDuplicateObjects && value && typeof value === "object") {
|
|
518
|
+
ref = this.#sourceObjects.get(value);
|
|
519
|
+
if (ref) {
|
|
520
|
+
if (!ref.anchor) {
|
|
521
|
+
this.#aliasObjects.push(value);
|
|
522
|
+
this.#prevAnchors ??= anchorNames(this.#doc);
|
|
523
|
+
ref.anchor = findNewAnchor(this.#anchorPrefix, this.#prevAnchors);
|
|
524
|
+
this.#prevAnchors.add(ref.anchor);
|
|
525
|
+
}
|
|
526
|
+
return new Alias(ref.anchor);
|
|
527
|
+
} else {
|
|
528
|
+
ref = {
|
|
529
|
+
anchor: null,
|
|
530
|
+
node: null
|
|
531
|
+
};
|
|
532
|
+
this.#sourceObjects.set(value, ref);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
let tagObj;
|
|
536
|
+
if (tagName) {
|
|
537
|
+
if (tagName.startsWith("!!")) tagName = defaultTagPrefix + tagName.slice(2);
|
|
538
|
+
const match = this.schema.tags.filter((t) => t.tag === tagName);
|
|
539
|
+
tagObj = match.find((t) => !t.format) ?? match[0];
|
|
540
|
+
if (!tagObj) throw new Error(`Tag ${tagName} not found`);
|
|
541
|
+
} else tagObj = this.schema.tags.find((t) => t.identify?.(value) && !t.format);
|
|
542
|
+
if (!tagObj) {
|
|
543
|
+
if (value && typeof value.toJSON === "function") value = value.toJSON();
|
|
544
|
+
if (!value || typeof value !== "object") {
|
|
545
|
+
const node = new Scalar(value);
|
|
546
|
+
if (ref) ref.node = node;
|
|
547
|
+
return node;
|
|
548
|
+
}
|
|
549
|
+
tagObj = value instanceof Map ? this.schema.map : Symbol.iterator in Object(value) ? this.schema.seq : this.schema.map;
|
|
550
|
+
}
|
|
551
|
+
if (this.#onTagObj) {
|
|
552
|
+
this.#onTagObj(tagObj);
|
|
553
|
+
this.#onTagObj = void 0;
|
|
554
|
+
}
|
|
555
|
+
const node = tagObj?.createNode?.(this, value) ?? tagObj?.nodeClass?.from?.(this, value) ?? new Scalar(value);
|
|
556
|
+
if (tagName) node.tag = tagName;
|
|
557
|
+
else if (!tagObj.default) node.tag = tagObj.tag;
|
|
558
|
+
if (ref) ref.node = node;
|
|
559
|
+
if (this.#flow && node instanceof Collection) node.flow = true;
|
|
560
|
+
return node;
|
|
561
|
+
}
|
|
562
|
+
createPair(key, value) {
|
|
563
|
+
return new Pair(this.create(key), value == null ? null : this.create(value));
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* With circular references, the source node is only resolved after all
|
|
567
|
+
* of its child nodes are. This is why anchors are set only after all of
|
|
568
|
+
* the nodes have been created.
|
|
569
|
+
*/
|
|
570
|
+
setAnchors() {
|
|
571
|
+
for (const source of this.#aliasObjects) {
|
|
572
|
+
const ref = this.#sourceObjects.get(source);
|
|
573
|
+
if (typeof ref === "object" && ref.anchor && (ref.node instanceof Scalar || ref.node instanceof Collection)) ref.node.anchor = ref.anchor;
|
|
574
|
+
else throw Object.assign(new Error("Failed to resolve repeated object (this should not happen)"), { source });
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
//#endregion
|
|
580
|
+
//#region src/nodes/Collection.ts
|
|
581
|
+
function collectionFromPath(schema, path, value) {
|
|
582
|
+
let v = value;
|
|
583
|
+
for (let i = path.length - 1; i >= 0; --i) {
|
|
584
|
+
const k = path[i];
|
|
585
|
+
if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
|
|
586
|
+
const a = [];
|
|
587
|
+
a[k] = v;
|
|
588
|
+
v = a;
|
|
589
|
+
} else v = new Map([[k, v]]);
|
|
590
|
+
}
|
|
591
|
+
return new NodeCreator(schema, { aliasDuplicateObjects: false }).create(v);
|
|
592
|
+
}
|
|
593
|
+
var Collection = class Collection extends NodeBase {
|
|
594
|
+
schema;
|
|
595
|
+
constructor(schema) {
|
|
596
|
+
super();
|
|
597
|
+
Object.defineProperty(this, "schema", {
|
|
598
|
+
value: schema,
|
|
599
|
+
configurable: true,
|
|
600
|
+
enumerable: false,
|
|
601
|
+
writable: true
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Create a copy of this collection.
|
|
606
|
+
*
|
|
607
|
+
* @param schema - If defined, overwrites the original's schema
|
|
608
|
+
*/
|
|
609
|
+
clone(schema) {
|
|
610
|
+
const copy = Object.create(Object.getPrototypeOf(this), Object.getOwnPropertyDescriptors(this));
|
|
611
|
+
if (schema) copy.schema = schema;
|
|
612
|
+
copy.items = copy.items.map((it) => it.clone(schema));
|
|
613
|
+
if (this.range) copy.range = this.range.slice();
|
|
614
|
+
return copy;
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Adds a value to the collection.
|
|
618
|
+
*
|
|
619
|
+
* For `!!map` and `!!omap` the value must be a Pair instance.
|
|
620
|
+
*/
|
|
621
|
+
addIn(path, value) {
|
|
622
|
+
if (!path.length) this.add(value);
|
|
623
|
+
else {
|
|
624
|
+
const [key, ...rest] = path;
|
|
625
|
+
const node = this.get(key);
|
|
626
|
+
if (node instanceof Collection) node.addIn(rest, value);
|
|
627
|
+
else if (node === void 0 && this.schema) this.set(key, collectionFromPath(this.schema, rest, value));
|
|
628
|
+
else throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Removes a value from the collection.
|
|
633
|
+
*
|
|
634
|
+
* @returns `true` if the item was found and removed.
|
|
635
|
+
*/
|
|
636
|
+
deleteIn(path) {
|
|
637
|
+
const [key, ...rest] = path;
|
|
638
|
+
if (rest.length === 0) return this.delete(key);
|
|
639
|
+
const node = this.get(key);
|
|
640
|
+
if (node instanceof Collection) return node.deleteIn(rest);
|
|
641
|
+
else throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Returns item at `key`, or `undefined` if not found.
|
|
645
|
+
*/
|
|
646
|
+
getIn(path) {
|
|
647
|
+
const [key, ...rest] = path;
|
|
648
|
+
const node = this.get(key);
|
|
649
|
+
if (rest.length === 0) return node;
|
|
650
|
+
else return node instanceof Collection ? node.getIn(rest) : void 0;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Checks if the collection includes a value with the key `key`.
|
|
654
|
+
*/
|
|
655
|
+
hasIn(path) {
|
|
656
|
+
const [key, ...rest] = path;
|
|
657
|
+
if (rest.length === 0) return this.has(key);
|
|
658
|
+
const node = this.get(key);
|
|
659
|
+
return node instanceof Collection ? node.hasIn(rest) : false;
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Sets a value in this collection.
|
|
663
|
+
*/
|
|
664
|
+
setIn(path, value) {
|
|
665
|
+
const [key, ...rest] = path;
|
|
666
|
+
if (rest.length === 0) this.set(key, value);
|
|
667
|
+
else {
|
|
668
|
+
const node = this.get(key);
|
|
669
|
+
if (node instanceof Collection) node.setIn(rest, value);
|
|
670
|
+
else if (node === void 0 && this.schema) this.set(key, collectionFromPath(this.schema, rest, value));
|
|
671
|
+
else throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
//#endregion
|
|
677
|
+
//#region src/stringify/stringifyComment.ts
|
|
678
|
+
/**
|
|
679
|
+
* Stringifies a comment.
|
|
680
|
+
*
|
|
681
|
+
* Empty comment lines are left empty,
|
|
682
|
+
* lines consisting of a single space are replaced by `#`,
|
|
683
|
+
* and all other lines are prefixed with a `#`.
|
|
684
|
+
*/
|
|
685
|
+
const stringifyComment = (str) => str.replace(/^(?!$)(?: $)?/gm, "#");
|
|
686
|
+
function indentComment(comment, indent) {
|
|
687
|
+
if (/^\n+$/.test(comment)) return comment.substring(1);
|
|
688
|
+
return indent ? comment.replace(/^(?! *$)/gm, indent) : comment;
|
|
689
|
+
}
|
|
690
|
+
const lineComment = (str, indent, comment) => str.endsWith("\n") ? indentComment(comment, indent) : comment.includes("\n") ? "\n" + indentComment(comment, indent) : (str.endsWith(" ") ? "" : " ") + comment;
|
|
691
|
+
|
|
692
|
+
//#endregion
|
|
693
|
+
//#region src/stringify/stringify.ts
|
|
694
|
+
function createStringifyContext(doc, options) {
|
|
695
|
+
const opt = Object.assign({
|
|
696
|
+
blockQuote: true,
|
|
697
|
+
commentString: stringifyComment,
|
|
698
|
+
defaultKeyType: null,
|
|
699
|
+
defaultStringType: "PLAIN",
|
|
700
|
+
directives: null,
|
|
701
|
+
doubleQuotedAsJSON: false,
|
|
702
|
+
doubleQuotedMinMultiLineLength: 40,
|
|
703
|
+
falseStr: "false",
|
|
704
|
+
flowCollectionPadding: true,
|
|
705
|
+
indentSeq: true,
|
|
706
|
+
lineWidth: 80,
|
|
707
|
+
minContentWidth: 20,
|
|
708
|
+
nullStr: "null",
|
|
709
|
+
simpleKeys: false,
|
|
710
|
+
singleQuote: null,
|
|
711
|
+
trueStr: "true",
|
|
712
|
+
verifyAliasOrder: true
|
|
713
|
+
}, doc.schema.toStringOptions, options);
|
|
714
|
+
let inFlow;
|
|
715
|
+
switch (opt.collectionStyle) {
|
|
716
|
+
case "block":
|
|
717
|
+
inFlow = false;
|
|
718
|
+
break;
|
|
719
|
+
case "flow":
|
|
720
|
+
inFlow = true;
|
|
721
|
+
break;
|
|
722
|
+
default: inFlow = null;
|
|
723
|
+
}
|
|
724
|
+
return {
|
|
725
|
+
anchors: /* @__PURE__ */ new Set(),
|
|
726
|
+
doc,
|
|
727
|
+
flowCollectionPadding: opt.flowCollectionPadding ? " " : "",
|
|
728
|
+
indent: "",
|
|
729
|
+
indentStep: typeof opt.indent === "number" ? " ".repeat(opt.indent) : " ",
|
|
730
|
+
inFlow,
|
|
731
|
+
options: opt
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
function getTagObject(tags, item) {
|
|
735
|
+
if (item.tag) {
|
|
736
|
+
const match = tags.filter((t) => t.tag === item.tag);
|
|
737
|
+
if (match.length > 0) return match.find((t) => t.format === item.format) ?? match[0];
|
|
738
|
+
}
|
|
739
|
+
let tagObj = void 0;
|
|
740
|
+
let obj;
|
|
741
|
+
if (item instanceof Scalar) {
|
|
742
|
+
obj = item.value;
|
|
743
|
+
let match = tags.filter((t) => t.identify?.(obj));
|
|
744
|
+
if (match.length > 1) {
|
|
745
|
+
const testMatch = match.filter((t) => t.test);
|
|
746
|
+
if (testMatch.length > 0) match = testMatch;
|
|
747
|
+
}
|
|
748
|
+
tagObj = match.find((t) => t.format === item.format) ?? match.find((t) => !t.format);
|
|
749
|
+
} else {
|
|
750
|
+
obj = item;
|
|
751
|
+
tagObj = tags.find((t) => t.nodeClass && obj instanceof t.nodeClass);
|
|
752
|
+
}
|
|
753
|
+
if (!tagObj) {
|
|
754
|
+
const name = obj?.constructor?.name ?? (obj === null ? "null" : typeof obj);
|
|
755
|
+
throw new Error(`Tag not resolved for ${name} value`);
|
|
756
|
+
}
|
|
757
|
+
return tagObj;
|
|
758
|
+
}
|
|
759
|
+
function stringifyProps(node, tagObj, { anchors, doc }) {
|
|
760
|
+
if (!doc.directives) return "";
|
|
761
|
+
const props = [];
|
|
762
|
+
const anchor = (node instanceof Scalar || node instanceof Collection) && node.anchor;
|
|
763
|
+
if (anchor && anchorIsValid(anchor)) {
|
|
764
|
+
anchors.add(anchor);
|
|
765
|
+
props.push(`&${anchor}`);
|
|
766
|
+
}
|
|
767
|
+
const tag = node.tag ?? (tagObj.default ? null : tagObj.tag);
|
|
768
|
+
if (tag) props.push(doc.directives.tagString(tag));
|
|
769
|
+
return props.join(" ");
|
|
770
|
+
}
|
|
771
|
+
function stringify(item, ctx, onComment, onChompKeep) {
|
|
772
|
+
if (item instanceof Pair) return item.toString(ctx, onComment, onChompKeep);
|
|
773
|
+
if (item instanceof Alias) {
|
|
774
|
+
if (ctx.doc.directives) return item.toString(ctx);
|
|
775
|
+
if (ctx.resolvedAliases?.has(item)) throw new TypeError(`Cannot stringify circular structure without alias nodes`);
|
|
776
|
+
else {
|
|
777
|
+
if (ctx.resolvedAliases) ctx.resolvedAliases.add(item);
|
|
778
|
+
else ctx.resolvedAliases = new Set([item]);
|
|
779
|
+
item = item.resolve(ctx.doc);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
let tagObj = void 0;
|
|
783
|
+
const node = item instanceof NodeBase ? item : ctx.doc.createNode(item, { onTagObj: (o) => tagObj = o });
|
|
784
|
+
tagObj ??= getTagObject(ctx.doc.schema.tags, node);
|
|
785
|
+
const props = stringifyProps(node, tagObj, ctx);
|
|
786
|
+
if (props.length > 0) ctx.indentAtStart = (ctx.indentAtStart ?? 0) + props.length + 1;
|
|
787
|
+
const str = typeof tagObj.stringify === "function" ? tagObj.stringify(node, ctx, onComment, onChompKeep) : node instanceof Scalar ? stringifyString(node, ctx, onComment, onChompKeep) : node.toString(ctx, onComment, onChompKeep);
|
|
788
|
+
if (!props) return str;
|
|
789
|
+
return node instanceof Scalar || str[0] === "{" || str[0] === "[" ? `${props} ${str}` : `${props}\n${ctx.indent}${str}`;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
//#endregion
|
|
793
|
+
//#region src/stringify/stringifyCollection.ts
|
|
794
|
+
function stringifyCollection(collection, ctx, options) {
|
|
795
|
+
return (ctx.inFlow ?? collection.flow ? stringifyFlowCollection : stringifyBlockCollection)(collection, ctx, options);
|
|
796
|
+
}
|
|
797
|
+
function stringifyBlockCollection({ comment, items }, ctx, { blockItemPrefix, flowChars, itemIndent, onChompKeep, onComment }) {
|
|
798
|
+
const { indent, options: { commentString } } = ctx;
|
|
799
|
+
const itemCtx = Object.assign({}, ctx, {
|
|
800
|
+
indent: itemIndent,
|
|
801
|
+
type: null
|
|
802
|
+
});
|
|
803
|
+
let chompKeep = false;
|
|
804
|
+
const lines = [];
|
|
805
|
+
for (let i = 0; i < items.length; ++i) {
|
|
806
|
+
const item = items[i];
|
|
807
|
+
let comment = null;
|
|
808
|
+
if (item instanceof NodeBase) {
|
|
809
|
+
if (!chompKeep && item.spaceBefore) lines.push("");
|
|
810
|
+
addCommentBefore(ctx, lines, item.commentBefore, chompKeep);
|
|
811
|
+
if (item.comment) comment = item.comment;
|
|
812
|
+
} else if (item instanceof Pair) {
|
|
813
|
+
const ik = item.key instanceof NodeBase ? item.key : null;
|
|
814
|
+
if (ik) {
|
|
815
|
+
if (!chompKeep && ik.spaceBefore) lines.push("");
|
|
816
|
+
addCommentBefore(ctx, lines, ik.commentBefore, chompKeep);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
chompKeep = false;
|
|
820
|
+
let str = stringify(item, itemCtx, () => comment = null, () => chompKeep = true);
|
|
821
|
+
if (comment) str += lineComment(str, itemIndent, commentString(comment));
|
|
822
|
+
if (chompKeep && comment) chompKeep = false;
|
|
823
|
+
lines.push(blockItemPrefix + str);
|
|
824
|
+
}
|
|
825
|
+
let str;
|
|
826
|
+
if (lines.length === 0) str = flowChars.start + flowChars.end;
|
|
827
|
+
else {
|
|
828
|
+
str = lines[0];
|
|
829
|
+
for (let i = 1; i < lines.length; ++i) {
|
|
830
|
+
const line = lines[i];
|
|
831
|
+
str += line ? `\n${indent}${line}` : "\n";
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
if (comment) {
|
|
835
|
+
str += "\n" + indentComment(commentString(comment), indent);
|
|
836
|
+
if (onComment) onComment();
|
|
837
|
+
} else if (chompKeep && onChompKeep) onChompKeep();
|
|
838
|
+
return str;
|
|
839
|
+
}
|
|
840
|
+
function stringifyFlowCollection({ items }, ctx, { flowChars, itemIndent }) {
|
|
841
|
+
const { indent, indentStep, flowCollectionPadding: fcPadding, options: { commentString } } = ctx;
|
|
842
|
+
itemIndent += indentStep;
|
|
843
|
+
const itemCtx = Object.assign({}, ctx, {
|
|
844
|
+
indent: itemIndent,
|
|
845
|
+
inFlow: true,
|
|
846
|
+
type: null
|
|
847
|
+
});
|
|
848
|
+
let reqNewline = false;
|
|
849
|
+
let linesAtValue = 0;
|
|
850
|
+
const lines = [];
|
|
851
|
+
for (let i = 0; i < items.length; ++i) {
|
|
852
|
+
const item = items[i];
|
|
853
|
+
let comment = null;
|
|
854
|
+
if (item instanceof NodeBase) {
|
|
855
|
+
if (item.spaceBefore) lines.push("");
|
|
856
|
+
addCommentBefore(ctx, lines, item.commentBefore, false);
|
|
857
|
+
if (item.comment) comment = item.comment;
|
|
858
|
+
} else if (item instanceof Pair) {
|
|
859
|
+
const ik = item.key instanceof NodeBase ? item.key : null;
|
|
860
|
+
if (ik) {
|
|
861
|
+
if (ik.spaceBefore) lines.push("");
|
|
862
|
+
addCommentBefore(ctx, lines, ik.commentBefore, false);
|
|
863
|
+
if (ik.comment) reqNewline = true;
|
|
864
|
+
}
|
|
865
|
+
const iv = item.value instanceof NodeBase ? item.value : null;
|
|
866
|
+
if (iv) {
|
|
867
|
+
if (iv.comment) comment = iv.comment;
|
|
868
|
+
if (iv.commentBefore) reqNewline = true;
|
|
869
|
+
} else if (item.value == null && ik?.comment) comment = ik.comment;
|
|
870
|
+
}
|
|
871
|
+
if (comment) reqNewline = true;
|
|
872
|
+
let str = stringify(item, itemCtx, () => comment = null);
|
|
873
|
+
if (i < items.length - 1) str += ",";
|
|
874
|
+
if (comment) str += lineComment(str, itemIndent, commentString(comment));
|
|
875
|
+
if (!reqNewline && (lines.length > linesAtValue || str.includes("\n"))) reqNewline = true;
|
|
876
|
+
lines.push(str);
|
|
877
|
+
linesAtValue = lines.length;
|
|
878
|
+
}
|
|
879
|
+
const { start, end } = flowChars;
|
|
880
|
+
if (lines.length === 0) return start + end;
|
|
881
|
+
else {
|
|
882
|
+
if (!reqNewline) {
|
|
883
|
+
const len = lines.reduce((sum, line) => sum + line.length + 2, 2);
|
|
884
|
+
reqNewline = ctx.options.lineWidth > 0 && len > ctx.options.lineWidth;
|
|
885
|
+
}
|
|
886
|
+
if (reqNewline) {
|
|
887
|
+
let str = start;
|
|
888
|
+
for (const line of lines) str += line ? `\n${indentStep}${indent}${line}` : "\n";
|
|
889
|
+
return `${str}\n${indent}${end}`;
|
|
890
|
+
} else return `${start}${fcPadding}${lines.join(" ")}${fcPadding}${end}`;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
function addCommentBefore({ indent, options: { commentString } }, lines, comment, chompKeep) {
|
|
894
|
+
if (comment && chompKeep) comment = comment.replace(/^\n+/, "");
|
|
895
|
+
if (comment) {
|
|
896
|
+
const ic = indentComment(commentString(comment), indent);
|
|
897
|
+
lines.push(ic.trimStart());
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
//#endregion
|
|
902
|
+
//#region src/nodes/YAMLSeq.ts
|
|
903
|
+
const isScalarValue = (value) => !value || typeof value !== "function" && typeof value !== "object";
|
|
904
|
+
var YAMLSeq = class extends Collection {
|
|
905
|
+
static get tagName() {
|
|
906
|
+
return "tag:yaml.org,2002:seq";
|
|
907
|
+
}
|
|
908
|
+
items = [];
|
|
909
|
+
add(value, options) {
|
|
910
|
+
if (value instanceof NodeBase) this.items.push(value);
|
|
911
|
+
else if (!this.schema) throw new Error("Schema is required");
|
|
912
|
+
else {
|
|
913
|
+
const nc = new NodeCreator(this.schema, {
|
|
914
|
+
...options,
|
|
915
|
+
aliasDuplicateObjects: false
|
|
916
|
+
});
|
|
917
|
+
this.items.push(nc.create(value));
|
|
918
|
+
nc.setAnchors();
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Removes a value from the collection.
|
|
923
|
+
*
|
|
924
|
+
* Throws if `idx` is not a non-negative integer.
|
|
925
|
+
*
|
|
926
|
+
* @returns `true` if the item was found and removed.
|
|
927
|
+
*/
|
|
928
|
+
delete(idx) {
|
|
929
|
+
if (!Number.isInteger(idx)) throw new TypeError(`Expected an integer, not ${idx}.`);
|
|
930
|
+
if (idx < 0) throw new RangeError(`Invalid negative index ${idx}`);
|
|
931
|
+
return this.items.splice(idx, 1).length > 0;
|
|
932
|
+
}
|
|
933
|
+
/**
|
|
934
|
+
* Returns item at `key`, or `undefined` if not found.
|
|
935
|
+
*
|
|
936
|
+
* Throws if `idx` is not a non-negative integer.
|
|
937
|
+
*/
|
|
938
|
+
get(idx) {
|
|
939
|
+
if (!Number.isInteger(idx)) throw new TypeError(`Expected an integer, not ${JSON.stringify(idx)}.`);
|
|
940
|
+
if (idx < 0) throw new RangeError(`Invalid negative index ${idx}`);
|
|
941
|
+
return this.items[idx];
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Checks if the collection includes a value with the key `key`.
|
|
945
|
+
*
|
|
946
|
+
* Throws if `idx` is not a non-negative integer.
|
|
947
|
+
*/
|
|
948
|
+
has(idx) {
|
|
949
|
+
if (!Number.isInteger(idx)) throw new TypeError(`Expected an integer, not ${JSON.stringify(idx)}.`);
|
|
950
|
+
if (idx < 0) throw new RangeError(`Invalid negative index ${idx}`);
|
|
951
|
+
return idx < this.items.length;
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* Sets a value in this collection. For `!!set`, `value` needs to be a
|
|
955
|
+
* boolean to add/remove the item from the set.
|
|
956
|
+
*
|
|
957
|
+
* Throws if `idx` is not a non-negative integer.
|
|
958
|
+
*/
|
|
959
|
+
set(idx, value, options) {
|
|
960
|
+
if (!Number.isInteger(idx)) throw new TypeError(`Expected an integer, not ${JSON.stringify(idx)}.`);
|
|
961
|
+
if (idx < 0) throw new RangeError(`Invalid negative index ${idx}`);
|
|
962
|
+
const prev = this.items[idx];
|
|
963
|
+
if (prev instanceof Scalar && isScalarValue(value)) prev.value = value;
|
|
964
|
+
else if (value instanceof NodeBase) this.items[idx] = value;
|
|
965
|
+
else if (!this.schema) throw new Error("Schema is required");
|
|
966
|
+
else {
|
|
967
|
+
const nc = new NodeCreator(this.schema, {
|
|
968
|
+
...options,
|
|
969
|
+
aliasDuplicateObjects: false
|
|
970
|
+
});
|
|
971
|
+
this.items[idx] = nc.create(value);
|
|
972
|
+
nc.setAnchors();
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
toJSON(_, ctx) {
|
|
976
|
+
const seq = [];
|
|
977
|
+
if (ctx?.onCreate) ctx.onCreate(seq);
|
|
978
|
+
let i = 0;
|
|
979
|
+
for (const item of this.items) seq.push(toJS(item, String(i++), ctx));
|
|
980
|
+
return seq;
|
|
981
|
+
}
|
|
982
|
+
toString(ctx, onComment, onChompKeep) {
|
|
983
|
+
if (!ctx) return JSON.stringify(this);
|
|
984
|
+
return stringifyCollection(this, ctx, {
|
|
985
|
+
blockItemPrefix: "- ",
|
|
986
|
+
flowChars: {
|
|
987
|
+
start: "[",
|
|
988
|
+
end: "]"
|
|
989
|
+
},
|
|
990
|
+
itemIndent: (ctx.indent || "") + " ",
|
|
991
|
+
onChompKeep,
|
|
992
|
+
onComment
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
static from(nc, obj) {
|
|
996
|
+
const seq = new this(nc.schema);
|
|
997
|
+
if (obj && Symbol.iterator in Object(obj)) {
|
|
998
|
+
let i = 0;
|
|
999
|
+
for (let it of obj) {
|
|
1000
|
+
if (typeof nc.replacer === "function") {
|
|
1001
|
+
const key = obj instanceof Set ? it : String(i++);
|
|
1002
|
+
it = nc.replacer.call(obj, key, it);
|
|
1003
|
+
}
|
|
1004
|
+
seq.items.push(nc.create(it));
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
return seq;
|
|
1008
|
+
}
|
|
1009
|
+
};
|
|
1010
|
+
|
|
1011
|
+
//#endregion
|
|
1012
|
+
//#region src/stringify/stringifyPair.ts
|
|
1013
|
+
function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
|
|
1014
|
+
const { doc, indent, indentStep, noValues, options: { commentString, indentSeq, simpleKeys } } = ctx;
|
|
1015
|
+
let keyComment = key instanceof NodeBase && key.comment || null;
|
|
1016
|
+
if (simpleKeys) {
|
|
1017
|
+
if (keyComment) throw new Error("With simple keys, key nodes cannot have comments");
|
|
1018
|
+
if (key instanceof Collection || !(key instanceof NodeBase) && typeof key === "object") throw new Error("With simple keys, collection cannot be used as a key value");
|
|
1019
|
+
}
|
|
1020
|
+
let explicitKey = !simpleKeys && (!key || !(key instanceof Scalar) || key.type === Scalar.BLOCK_FOLDED || key.type === Scalar.BLOCK_LITERAL);
|
|
1021
|
+
ctx = {
|
|
1022
|
+
...ctx,
|
|
1023
|
+
implicitKey: !explicitKey && (simpleKeys || !noValues),
|
|
1024
|
+
indent: indent + indentStep,
|
|
1025
|
+
noValues: false
|
|
1026
|
+
};
|
|
1027
|
+
let keyCommentDone = false;
|
|
1028
|
+
let chompKeep = false;
|
|
1029
|
+
let str = stringify(key, ctx, () => keyCommentDone = true, () => chompKeep = true);
|
|
1030
|
+
if (!explicitKey && !ctx.inFlow && str.length > 1024) {
|
|
1031
|
+
if (simpleKeys) throw new Error("With simple keys, single line scalar must not span more than 1024 characters");
|
|
1032
|
+
explicitKey = true;
|
|
1033
|
+
}
|
|
1034
|
+
if (ctx.inFlow) {
|
|
1035
|
+
if (noValues || value == null) {
|
|
1036
|
+
if (keyCommentDone && onComment) onComment();
|
|
1037
|
+
return str === "" ? "?" : explicitKey ? `? ${str}` : noValues ? str : `${str}:`;
|
|
1038
|
+
}
|
|
1039
|
+
} else if (noValues && !simpleKeys || value == null && explicitKey) {
|
|
1040
|
+
str = `? ${str}`;
|
|
1041
|
+
if (keyComment && !keyCommentDone) str += lineComment(str, ctx.indent, commentString(keyComment));
|
|
1042
|
+
else if (chompKeep && onChompKeep) onChompKeep();
|
|
1043
|
+
return str;
|
|
1044
|
+
}
|
|
1045
|
+
if (keyCommentDone) keyComment = null;
|
|
1046
|
+
if (explicitKey) {
|
|
1047
|
+
if (keyComment) str += lineComment(str, ctx.indent, commentString(keyComment));
|
|
1048
|
+
str = `? ${str}\n${indent}:`;
|
|
1049
|
+
} else {
|
|
1050
|
+
str = `${str}:`;
|
|
1051
|
+
if (keyComment) str += lineComment(str, ctx.indent, commentString(keyComment));
|
|
1052
|
+
}
|
|
1053
|
+
let vsb, vcb, valueComment;
|
|
1054
|
+
if (value instanceof NodeBase) {
|
|
1055
|
+
vsb = !!value.spaceBefore;
|
|
1056
|
+
vcb = value.commentBefore;
|
|
1057
|
+
valueComment = value.comment;
|
|
1058
|
+
} else {
|
|
1059
|
+
vsb = false;
|
|
1060
|
+
vcb = null;
|
|
1061
|
+
valueComment = null;
|
|
1062
|
+
if (value && typeof value === "object") value = doc.createNode(value);
|
|
1063
|
+
}
|
|
1064
|
+
ctx.implicitKey = false;
|
|
1065
|
+
if (!explicitKey && !keyComment && value instanceof Scalar) ctx.indentAtStart = str.length + 1;
|
|
1066
|
+
chompKeep = false;
|
|
1067
|
+
if (!indentSeq && indentStep.length >= 2 && !ctx.inFlow && !explicitKey && value instanceof YAMLSeq && !value.flow && !value.tag && !value.anchor) ctx.indent = ctx.indent.substring(2);
|
|
1068
|
+
let valueCommentDone = false;
|
|
1069
|
+
const valueStr = stringify(value, ctx, () => valueCommentDone = true, () => chompKeep = true);
|
|
1070
|
+
let ws = " ";
|
|
1071
|
+
if (keyComment || vsb || vcb) {
|
|
1072
|
+
ws = vsb ? "\n" : "";
|
|
1073
|
+
if (vcb) {
|
|
1074
|
+
const cs = commentString(vcb);
|
|
1075
|
+
ws += `\n${indentComment(cs, ctx.indent)}`;
|
|
1076
|
+
}
|
|
1077
|
+
if (valueStr === "" && !ctx.inFlow) {
|
|
1078
|
+
if (ws === "\n" && valueComment) ws = "\n\n";
|
|
1079
|
+
} else ws += `\n${ctx.indent}`;
|
|
1080
|
+
} else if (!explicitKey && value instanceof Collection) {
|
|
1081
|
+
const vs0 = valueStr[0];
|
|
1082
|
+
const nl0 = valueStr.indexOf("\n");
|
|
1083
|
+
const hasNewline = nl0 !== -1;
|
|
1084
|
+
const flow = ctx.inFlow ?? value.flow ?? value.items.length === 0;
|
|
1085
|
+
if (hasNewline || !flow) {
|
|
1086
|
+
let hasPropsLine = false;
|
|
1087
|
+
if (hasNewline && (vs0 === "&" || vs0 === "!")) {
|
|
1088
|
+
let sp0 = valueStr.indexOf(" ");
|
|
1089
|
+
if (vs0 === "&" && sp0 !== -1 && sp0 < nl0 && valueStr[sp0 + 1] === "!") sp0 = valueStr.indexOf(" ", sp0 + 1);
|
|
1090
|
+
if (sp0 === -1 || nl0 < sp0) hasPropsLine = true;
|
|
1091
|
+
}
|
|
1092
|
+
if (!hasPropsLine) ws = `\n${ctx.indent}`;
|
|
1093
|
+
}
|
|
1094
|
+
} else if (valueStr === "" || valueStr[0] === "\n") ws = "";
|
|
1095
|
+
str += ws + valueStr;
|
|
1096
|
+
if (ctx.inFlow) {
|
|
1097
|
+
if (valueCommentDone && onComment) onComment();
|
|
1098
|
+
} else if (valueComment && !valueCommentDone) str += lineComment(str, ctx.indent, commentString(valueComment));
|
|
1099
|
+
else if (chompKeep && onChompKeep) onChompKeep();
|
|
1100
|
+
return str;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
//#endregion
|
|
1104
|
+
//#region src/log.ts
|
|
1105
|
+
function debug(logLevel, ...messages) {
|
|
1106
|
+
if (logLevel === "debug") console.log(...messages);
|
|
1107
|
+
}
|
|
1108
|
+
function warn(logLevel, warning) {
|
|
1109
|
+
if (logLevel === "debug" || logLevel === "warn") if (typeof process !== "undefined" && typeof process.emitWarning === "function") process.emitWarning(warning);
|
|
1110
|
+
else console.warn(warning);
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
//#endregion
|
|
1114
|
+
//#region src/schema/yaml-1.1/merge.ts
|
|
1115
|
+
const MERGE_KEY = "<<";
|
|
1116
|
+
const merge = {
|
|
1117
|
+
identify: (value) => value === MERGE_KEY || typeof value === "symbol" && value.description === MERGE_KEY,
|
|
1118
|
+
default: "key",
|
|
1119
|
+
tag: "tag:yaml.org,2002:merge",
|
|
1120
|
+
test: /^<<$/,
|
|
1121
|
+
resolve: () => Object.assign(new Scalar(Symbol(MERGE_KEY)), { addToJSMap: addMergeToJSMap }),
|
|
1122
|
+
stringify: () => MERGE_KEY
|
|
1123
|
+
};
|
|
1124
|
+
const isMergeKey = (ctx, key) => (merge.identify(key) || key instanceof Scalar && (!key.type || key.type === Scalar.PLAIN) && merge.identify(key.value)) && Boolean(ctx?.doc.schema.tags.some((tag) => tag.tag === merge.tag && tag.default));
|
|
1125
|
+
function addMergeToJSMap(ctx, map, value) {
|
|
1126
|
+
value = ctx && value instanceof Alias ? value.resolve(ctx.doc) : value;
|
|
1127
|
+
if (value instanceof YAMLSeq) for (const it of value.items) mergeValue(ctx, map, it);
|
|
1128
|
+
else if (Array.isArray(value)) for (const it of value) mergeValue(ctx, map, it);
|
|
1129
|
+
else mergeValue(ctx, map, value);
|
|
1130
|
+
}
|
|
1131
|
+
function mergeValue(ctx, map, value) {
|
|
1132
|
+
const srcMap = (ctx && value instanceof Alias ? value.resolve(ctx.doc) : value).toJSON(null, ctx, Map);
|
|
1133
|
+
if (!(srcMap instanceof Map)) throw new Error("Merge sources must be maps or map aliases");
|
|
1134
|
+
for (const [key, value] of srcMap) if (map instanceof Map) {
|
|
1135
|
+
if (!map.has(key)) map.set(key, value);
|
|
1136
|
+
} else if (map instanceof Set) map.add(key);
|
|
1137
|
+
else if (!Object.prototype.hasOwnProperty.call(map, key)) Object.defineProperty(map, key, {
|
|
1138
|
+
value,
|
|
1139
|
+
writable: true,
|
|
1140
|
+
enumerable: true,
|
|
1141
|
+
configurable: true
|
|
1142
|
+
});
|
|
1143
|
+
return map;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
//#endregion
|
|
1147
|
+
//#region src/nodes/addPairToJSMap.ts
|
|
1148
|
+
function addPairToJSMap(ctx, map, { key, value }) {
|
|
1149
|
+
if (key instanceof NodeBase && key.addToJSMap) key.addToJSMap(ctx, map, value);
|
|
1150
|
+
else if (isMergeKey(ctx, key)) addMergeToJSMap(ctx, map, value);
|
|
1151
|
+
else {
|
|
1152
|
+
const jsKey = toJS(key, "", ctx);
|
|
1153
|
+
if (map instanceof Map) map.set(jsKey, toJS(value, jsKey, ctx));
|
|
1154
|
+
else if (map instanceof Set) map.add(jsKey);
|
|
1155
|
+
else {
|
|
1156
|
+
const stringKey = stringifyKey(key, jsKey, ctx);
|
|
1157
|
+
const jsValue = toJS(value, stringKey, ctx);
|
|
1158
|
+
if (stringKey in map) Object.defineProperty(map, stringKey, {
|
|
1159
|
+
value: jsValue,
|
|
1160
|
+
writable: true,
|
|
1161
|
+
enumerable: true,
|
|
1162
|
+
configurable: true
|
|
1163
|
+
});
|
|
1164
|
+
else map[stringKey] = jsValue;
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
return map;
|
|
1168
|
+
}
|
|
1169
|
+
function stringifyKey(key, jsKey, ctx) {
|
|
1170
|
+
if (jsKey === null) return "";
|
|
1171
|
+
if (typeof jsKey !== "object") return String(jsKey);
|
|
1172
|
+
if (key instanceof NodeBase && ctx?.doc) {
|
|
1173
|
+
const strCtx = createStringifyContext(ctx.doc, {});
|
|
1174
|
+
strCtx.anchors = /* @__PURE__ */ new Set();
|
|
1175
|
+
for (const node of ctx.anchors.keys()) strCtx.anchors.add(node.anchor);
|
|
1176
|
+
strCtx.inFlow = true;
|
|
1177
|
+
strCtx.inStringifyKey = true;
|
|
1178
|
+
const strKey = key.toString(strCtx);
|
|
1179
|
+
if (!ctx.mapKeyWarned) {
|
|
1180
|
+
let jsonStr = JSON.stringify(strKey);
|
|
1181
|
+
if (jsonStr.length > 40) jsonStr = jsonStr.substring(0, 36) + "...\"";
|
|
1182
|
+
warn(ctx.doc.options.logLevel, `Keys with collection values will be stringified due to JS Object restrictions: ${jsonStr}. Set mapAsMap: true to use object keys.`);
|
|
1183
|
+
ctx.mapKeyWarned = true;
|
|
1184
|
+
}
|
|
1185
|
+
return strKey;
|
|
1186
|
+
}
|
|
1187
|
+
return JSON.stringify(jsKey);
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
//#endregion
|
|
1191
|
+
//#region src/nodes/Pair.ts
|
|
1192
|
+
var Pair = class Pair {
|
|
1193
|
+
key;
|
|
1194
|
+
value;
|
|
1195
|
+
constructor(key, value = null) {
|
|
1196
|
+
this.key = key;
|
|
1197
|
+
this.value = value;
|
|
1198
|
+
}
|
|
1199
|
+
clone(schema) {
|
|
1200
|
+
return new Pair(this.key.clone(schema), this.value?.clone(schema) ?? null);
|
|
1201
|
+
}
|
|
1202
|
+
toJSON(_, ctx) {
|
|
1203
|
+
return addPairToJSMap(ctx, ctx?.mapAsMap ? /* @__PURE__ */ new Map() : {}, this);
|
|
1204
|
+
}
|
|
1205
|
+
toString(ctx, onComment, onChompKeep) {
|
|
1206
|
+
return ctx?.doc ? stringifyPair(this, ctx, onComment, onChompKeep) : JSON.stringify(this);
|
|
1207
|
+
}
|
|
1208
|
+
};
|
|
1209
|
+
|
|
1210
|
+
//#endregion
|
|
1211
|
+
//#region src/nodes/Alias.ts
|
|
1212
|
+
var Alias = class Alias extends NodeBase {
|
|
1213
|
+
source;
|
|
1214
|
+
constructor(source) {
|
|
1215
|
+
super();
|
|
1216
|
+
this.source = source;
|
|
1217
|
+
Object.defineProperty(this, "tag", { set() {
|
|
1218
|
+
throw new Error("Alias nodes cannot have tags");
|
|
1219
|
+
} });
|
|
1220
|
+
}
|
|
1221
|
+
/**
|
|
1222
|
+
* Resolve the value of this alias within `doc`, finding the last
|
|
1223
|
+
* instance of the `source` anchor before this node.
|
|
1224
|
+
*/
|
|
1225
|
+
resolve(doc, ctx) {
|
|
1226
|
+
let nodes;
|
|
1227
|
+
if (ctx?.aliasResolveCache) nodes = ctx.aliasResolveCache;
|
|
1228
|
+
else {
|
|
1229
|
+
nodes = [];
|
|
1230
|
+
visit(doc, { Node: (_key, node) => {
|
|
1231
|
+
if (node instanceof Alias || node.anchor) nodes.push(node);
|
|
1232
|
+
} });
|
|
1233
|
+
if (ctx) ctx.aliasResolveCache = nodes;
|
|
1234
|
+
}
|
|
1235
|
+
let found = void 0;
|
|
1236
|
+
for (const node of nodes) {
|
|
1237
|
+
if (node === this) break;
|
|
1238
|
+
if (node.anchor === this.source) found = node;
|
|
1239
|
+
}
|
|
1240
|
+
return found;
|
|
1241
|
+
}
|
|
1242
|
+
toJSON(_arg, ctx) {
|
|
1243
|
+
if (!ctx) return { source: this.source };
|
|
1244
|
+
const { anchors, doc, maxAliasCount } = ctx;
|
|
1245
|
+
const source = this.resolve(doc, ctx);
|
|
1246
|
+
if (!source) {
|
|
1247
|
+
const msg = `Unresolved alias (the anchor must be set before the alias): ${this.source}`;
|
|
1248
|
+
throw new ReferenceError(msg);
|
|
1249
|
+
}
|
|
1250
|
+
let data = anchors.get(source);
|
|
1251
|
+
if (!data) {
|
|
1252
|
+
toJS(source, null, ctx);
|
|
1253
|
+
data = anchors.get(source);
|
|
1254
|
+
}
|
|
1255
|
+
/* istanbul ignore if */
|
|
1256
|
+
if (data?.res === void 0) throw new ReferenceError("This should not happen: Alias anchor was not resolved?");
|
|
1257
|
+
if (maxAliasCount >= 0) {
|
|
1258
|
+
data.count += 1;
|
|
1259
|
+
if (data.aliasCount === 0) data.aliasCount = getAliasCount(doc, source, anchors);
|
|
1260
|
+
if (data.count * data.aliasCount > maxAliasCount) throw new ReferenceError("Excessive alias count indicates a resource exhaustion attack");
|
|
1261
|
+
}
|
|
1262
|
+
return data.res;
|
|
1263
|
+
}
|
|
1264
|
+
toString(ctx, _onComment, _onChompKeep) {
|
|
1265
|
+
const src = `*${this.source}`;
|
|
1266
|
+
if (ctx) {
|
|
1267
|
+
anchorIsValid(this.source);
|
|
1268
|
+
if (ctx.options.verifyAliasOrder && !ctx.anchors.has(this.source)) {
|
|
1269
|
+
const msg = `Unresolved alias (the anchor must be set before the alias): ${this.source}`;
|
|
1270
|
+
throw new Error(msg);
|
|
1271
|
+
}
|
|
1272
|
+
if (ctx.implicitKey) return `${src} `;
|
|
1273
|
+
}
|
|
1274
|
+
return src;
|
|
1275
|
+
}
|
|
1276
|
+
};
|
|
1277
|
+
function getAliasCount(doc, node, anchors) {
|
|
1278
|
+
if (node instanceof Alias) {
|
|
1279
|
+
const source = node.resolve(doc);
|
|
1280
|
+
const anchor = anchors && source && anchors.get(source);
|
|
1281
|
+
return anchor ? anchor.count * anchor.aliasCount : 0;
|
|
1282
|
+
} else if (node instanceof NodeBase && "items" in node) {
|
|
1283
|
+
const coll = node;
|
|
1284
|
+
let count = 0;
|
|
1285
|
+
for (const item of coll.items) {
|
|
1286
|
+
const c = getAliasCount(doc, item, anchors);
|
|
1287
|
+
if (c > count) count = c;
|
|
1288
|
+
}
|
|
1289
|
+
return count;
|
|
1290
|
+
} else if (node instanceof Pair) {
|
|
1291
|
+
const kc = getAliasCount(doc, node.key, anchors);
|
|
1292
|
+
const vc = getAliasCount(doc, node.value, anchors);
|
|
1293
|
+
return Math.max(kc, vc);
|
|
1294
|
+
}
|
|
1295
|
+
return 1;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
//#endregion
|
|
1299
|
+
//#region src/nodes/YAMLMap.ts
|
|
1300
|
+
function findPair(items, key) {
|
|
1301
|
+
const k = key instanceof Scalar ? key.value : key;
|
|
1302
|
+
for (const it of items) {
|
|
1303
|
+
if (it.key === key || it.key === k) return it;
|
|
1304
|
+
if (it.key instanceof Scalar && it.key.value === k) return it;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
var YAMLMap = class extends Collection {
|
|
1308
|
+
static get tagName() {
|
|
1309
|
+
return "tag:yaml.org,2002:map";
|
|
1310
|
+
}
|
|
1311
|
+
items = [];
|
|
1312
|
+
/**
|
|
1313
|
+
* A generic collection parsing method that can be extended
|
|
1314
|
+
* to other node classes that inherit from YAMLMap
|
|
1315
|
+
*/
|
|
1316
|
+
static from(nc, obj) {
|
|
1317
|
+
const { replacer } = nc;
|
|
1318
|
+
const map = new this(nc.schema);
|
|
1319
|
+
const add = (key, value) => {
|
|
1320
|
+
if (typeof replacer === "function") value = replacer.call(obj, key, value);
|
|
1321
|
+
else if (Array.isArray(replacer) && !replacer.includes(key)) return;
|
|
1322
|
+
if (value !== void 0 || nc.keepUndefined) map.items.push(nc.createPair(key, value));
|
|
1323
|
+
};
|
|
1324
|
+
if (obj instanceof Map) for (const [key, value] of obj) add(key, value);
|
|
1325
|
+
else if (obj && typeof obj === "object") for (const key of Object.keys(obj)) add(key, obj[key]);
|
|
1326
|
+
if (typeof nc.schema.sortMapEntries === "function") map.items.sort(nc.schema.sortMapEntries);
|
|
1327
|
+
return map;
|
|
1328
|
+
}
|
|
1329
|
+
/**
|
|
1330
|
+
* Adds a key-value pair to the map.
|
|
1331
|
+
*
|
|
1332
|
+
* Using a key that is already in the collection overwrites the previous value.
|
|
1333
|
+
*/
|
|
1334
|
+
add(pair) {
|
|
1335
|
+
if (!(pair instanceof Pair)) throw new TypeError("Expected a Pair");
|
|
1336
|
+
const prev = findPair(this.items, pair.key);
|
|
1337
|
+
const sortEntries = this.schema?.sortMapEntries;
|
|
1338
|
+
if (prev) if (prev.value instanceof Scalar && pair.value instanceof Scalar) prev.value.value = pair.value.value;
|
|
1339
|
+
else prev.value = pair.value;
|
|
1340
|
+
else if (sortEntries) {
|
|
1341
|
+
const i = this.items.findIndex((item) => sortEntries(pair, item) < 0);
|
|
1342
|
+
if (i === -1) this.items.push(pair);
|
|
1343
|
+
else this.items.splice(i, 0, pair);
|
|
1344
|
+
} else this.items.push(pair);
|
|
1345
|
+
}
|
|
1346
|
+
delete(key) {
|
|
1347
|
+
const it = findPair(this.items, key);
|
|
1348
|
+
if (!it) return false;
|
|
1349
|
+
return this.items.splice(this.items.indexOf(it), 1).length > 0;
|
|
1350
|
+
}
|
|
1351
|
+
get(key) {
|
|
1352
|
+
return findPair(this.items, key)?.value ?? void 0;
|
|
1353
|
+
}
|
|
1354
|
+
has(key) {
|
|
1355
|
+
return !!findPair(this.items, key);
|
|
1356
|
+
}
|
|
1357
|
+
set(key, value, options) {
|
|
1358
|
+
let pair;
|
|
1359
|
+
if (key instanceof NodeBase && (value instanceof NodeBase || value === null)) pair = new Pair(key, value);
|
|
1360
|
+
else if (!this.schema) throw new Error("Schema is required");
|
|
1361
|
+
else {
|
|
1362
|
+
const nc = new NodeCreator(this.schema, {
|
|
1363
|
+
...options,
|
|
1364
|
+
aliasDuplicateObjects: false
|
|
1365
|
+
});
|
|
1366
|
+
pair = nc.createPair(key, value);
|
|
1367
|
+
nc.setAnchors();
|
|
1368
|
+
}
|
|
1369
|
+
this.add(pair);
|
|
1370
|
+
}
|
|
1371
|
+
toJSON(_, ctx, Type) {
|
|
1372
|
+
const map = Type ? new Type() : ctx?.mapAsMap ? /* @__PURE__ */ new Map() : {};
|
|
1373
|
+
if (ctx?.onCreate) ctx.onCreate(map);
|
|
1374
|
+
for (const item of this.items) addPairToJSMap(ctx, map, item);
|
|
1375
|
+
return map;
|
|
1376
|
+
}
|
|
1377
|
+
toString(ctx, onComment, onChompKeep) {
|
|
1378
|
+
if (!ctx) return JSON.stringify(this);
|
|
1379
|
+
for (const item of this.items) if (!(item instanceof Pair)) throw new Error(`Map items must all be pairs; found ${JSON.stringify(item)} instead`);
|
|
1380
|
+
return stringifyCollection(this, ctx, {
|
|
1381
|
+
blockItemPrefix: "",
|
|
1382
|
+
flowChars: {
|
|
1383
|
+
start: "{",
|
|
1384
|
+
end: "}"
|
|
1385
|
+
},
|
|
1386
|
+
itemIndent: ctx.indent || "",
|
|
1387
|
+
onChompKeep,
|
|
1388
|
+
onComment
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1391
|
+
};
|
|
1392
|
+
|
|
1393
|
+
//#endregion
|
|
1394
|
+
//#region src/schema/common/map.ts
|
|
1395
|
+
const map = {
|
|
1396
|
+
collection: "map",
|
|
1397
|
+
default: true,
|
|
1398
|
+
nodeClass: YAMLMap,
|
|
1399
|
+
tag: "tag:yaml.org,2002:map",
|
|
1400
|
+
resolve(map, onError) {
|
|
1401
|
+
if (!(map instanceof YAMLMap)) onError("Expected a mapping for this tag");
|
|
1402
|
+
return map;
|
|
1403
|
+
}
|
|
1404
|
+
};
|
|
1405
|
+
|
|
1406
|
+
//#endregion
|
|
1407
|
+
//#region src/schema/common/seq.ts
|
|
1408
|
+
const seq = {
|
|
1409
|
+
collection: "seq",
|
|
1410
|
+
default: true,
|
|
1411
|
+
nodeClass: YAMLSeq,
|
|
1412
|
+
tag: "tag:yaml.org,2002:seq",
|
|
1413
|
+
resolve(seq, onError) {
|
|
1414
|
+
if (!(seq instanceof YAMLSeq)) onError("Expected a sequence for this tag");
|
|
1415
|
+
return seq;
|
|
1416
|
+
}
|
|
1417
|
+
};
|
|
1418
|
+
|
|
1419
|
+
//#endregion
|
|
1420
|
+
//#region src/schema/common/string.ts
|
|
1421
|
+
const string = {
|
|
1422
|
+
identify: (value) => typeof value === "string",
|
|
1423
|
+
default: true,
|
|
1424
|
+
tag: "tag:yaml.org,2002:str",
|
|
1425
|
+
resolve: (str) => str,
|
|
1426
|
+
stringify(item, ctx, onComment, onChompKeep) {
|
|
1427
|
+
ctx = Object.assign({ actualString: true }, ctx);
|
|
1428
|
+
return stringifyString(item, ctx, onComment, onChompKeep);
|
|
1429
|
+
}
|
|
1430
|
+
};
|
|
1431
|
+
|
|
1432
|
+
//#endregion
|
|
1433
|
+
//#region src/schema/common/null.ts
|
|
1434
|
+
const nullTag = {
|
|
1435
|
+
identify: (value) => value == null,
|
|
1436
|
+
createNode: () => new Scalar(null),
|
|
1437
|
+
default: true,
|
|
1438
|
+
tag: "tag:yaml.org,2002:null",
|
|
1439
|
+
test: /^(?:~|[Nn]ull|NULL)?$/,
|
|
1440
|
+
resolve: () => new Scalar(null),
|
|
1441
|
+
stringify: ({ source }, ctx) => typeof source === "string" && nullTag.test.test(source) ? source : ctx.options.nullStr
|
|
1442
|
+
};
|
|
1443
|
+
|
|
1444
|
+
//#endregion
|
|
1445
|
+
//#region src/schema/core/bool.ts
|
|
1446
|
+
const boolTag = {
|
|
1447
|
+
identify: (value) => typeof value === "boolean",
|
|
1448
|
+
default: true,
|
|
1449
|
+
tag: "tag:yaml.org,2002:bool",
|
|
1450
|
+
test: /^(?:[Tt]rue|TRUE|[Ff]alse|FALSE)$/,
|
|
1451
|
+
resolve: (str) => new Scalar(str[0] === "t" || str[0] === "T"),
|
|
1452
|
+
stringify({ source, value }, ctx) {
|
|
1453
|
+
if (source && boolTag.test.test(source)) {
|
|
1454
|
+
if (value === (source[0] === "t" || source[0] === "T")) return source;
|
|
1455
|
+
}
|
|
1456
|
+
return value ? ctx.options.trueStr : ctx.options.falseStr;
|
|
1457
|
+
}
|
|
1458
|
+
};
|
|
1459
|
+
|
|
1460
|
+
//#endregion
|
|
1461
|
+
//#region src/stringify/stringifyNumber.ts
|
|
1462
|
+
function stringifyNumber({ format, minFractionDigits, tag, value }) {
|
|
1463
|
+
if (typeof value === "bigint") return String(value);
|
|
1464
|
+
const num = typeof value === "number" ? value : Number(value);
|
|
1465
|
+
if (!isFinite(num)) return isNaN(num) ? ".nan" : num < 0 ? "-.inf" : ".inf";
|
|
1466
|
+
let n = Object.is(value, -0) ? "-0" : JSON.stringify(value);
|
|
1467
|
+
if (!format && minFractionDigits && (!tag || tag === "tag:yaml.org,2002:float") && /^\d/.test(n)) {
|
|
1468
|
+
let i = n.indexOf(".");
|
|
1469
|
+
if (i < 0) {
|
|
1470
|
+
i = n.length;
|
|
1471
|
+
n += ".";
|
|
1472
|
+
}
|
|
1473
|
+
let d = minFractionDigits - (n.length - i - 1);
|
|
1474
|
+
while (d-- > 0) n += "0";
|
|
1475
|
+
}
|
|
1476
|
+
return n;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
//#endregion
|
|
1480
|
+
//#region src/schema/core/float.ts
|
|
1481
|
+
const floatNaN$1 = {
|
|
1482
|
+
identify: (value) => typeof value === "number",
|
|
1483
|
+
default: true,
|
|
1484
|
+
tag: "tag:yaml.org,2002:float",
|
|
1485
|
+
test: /^(?:[-+]?\.(?:inf|Inf|INF)|\.nan|\.NaN|\.NAN)$/,
|
|
1486
|
+
resolve: (str) => str.slice(-3).toLowerCase() === "nan" ? NaN : str[0] === "-" ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
|
|
1487
|
+
stringify: stringifyNumber
|
|
1488
|
+
};
|
|
1489
|
+
const floatExp$1 = {
|
|
1490
|
+
identify: (value) => typeof value === "number",
|
|
1491
|
+
default: true,
|
|
1492
|
+
tag: "tag:yaml.org,2002:float",
|
|
1493
|
+
format: "EXP",
|
|
1494
|
+
test: /^[-+]?(?:\.[0-9]+|[0-9]+(?:\.[0-9]*)?)[eE][-+]?[0-9]+$/,
|
|
1495
|
+
resolve: (str) => parseFloat(str),
|
|
1496
|
+
stringify(node) {
|
|
1497
|
+
const num = Number(node.value);
|
|
1498
|
+
return isFinite(num) ? num.toExponential() : stringifyNumber(node);
|
|
1499
|
+
}
|
|
1500
|
+
};
|
|
1501
|
+
const float$1 = {
|
|
1502
|
+
identify: (value) => typeof value === "number",
|
|
1503
|
+
default: true,
|
|
1504
|
+
tag: "tag:yaml.org,2002:float",
|
|
1505
|
+
test: /^[-+]?(?:\.[0-9]+|[0-9]+\.[0-9]*)$/,
|
|
1506
|
+
resolve(str) {
|
|
1507
|
+
const node = new Scalar(parseFloat(str));
|
|
1508
|
+
const dot = str.indexOf(".");
|
|
1509
|
+
if (dot !== -1 && str[str.length - 1] === "0") node.minFractionDigits = str.length - dot - 1;
|
|
1510
|
+
return node;
|
|
1511
|
+
},
|
|
1512
|
+
stringify: stringifyNumber
|
|
1513
|
+
};
|
|
1514
|
+
|
|
1515
|
+
//#endregion
|
|
1516
|
+
//#region src/schema/core/int.ts
|
|
1517
|
+
const intIdentify$2 = (value) => typeof value === "bigint" || Number.isInteger(value);
|
|
1518
|
+
const intResolve$1 = (str, offset, radix, { intAsBigInt }) => intAsBigInt ? BigInt(str) : parseInt(str.substring(offset), radix);
|
|
1519
|
+
function intStringify$1(node, radix, prefix) {
|
|
1520
|
+
const { value } = node;
|
|
1521
|
+
if (intIdentify$2(value) && value >= 0) return prefix + value.toString(radix);
|
|
1522
|
+
return stringifyNumber(node);
|
|
1523
|
+
}
|
|
1524
|
+
const intOct$1 = {
|
|
1525
|
+
identify: (value) => intIdentify$2(value) && value >= 0,
|
|
1526
|
+
default: true,
|
|
1527
|
+
tag: "tag:yaml.org,2002:int",
|
|
1528
|
+
format: "OCT",
|
|
1529
|
+
test: /^0o[0-7]+$/,
|
|
1530
|
+
resolve: (str, _onError, opt) => intResolve$1(str, 2, 8, opt),
|
|
1531
|
+
stringify: (node) => intStringify$1(node, 8, "0o")
|
|
1532
|
+
};
|
|
1533
|
+
const int$1 = {
|
|
1534
|
+
identify: intIdentify$2,
|
|
1535
|
+
default: true,
|
|
1536
|
+
tag: "tag:yaml.org,2002:int",
|
|
1537
|
+
test: /^[-+]?[0-9]+$/,
|
|
1538
|
+
resolve: (str, _onError, opt) => intResolve$1(str, 0, 10, opt),
|
|
1539
|
+
stringify: stringifyNumber
|
|
1540
|
+
};
|
|
1541
|
+
const intHex$1 = {
|
|
1542
|
+
identify: (value) => intIdentify$2(value) && value >= 0,
|
|
1543
|
+
default: true,
|
|
1544
|
+
tag: "tag:yaml.org,2002:int",
|
|
1545
|
+
format: "HEX",
|
|
1546
|
+
test: /^0x[0-9a-fA-F]+$/,
|
|
1547
|
+
resolve: (str, _onError, opt) => intResolve$1(str, 2, 16, opt),
|
|
1548
|
+
stringify: (node) => intStringify$1(node, 16, "0x")
|
|
1549
|
+
};
|
|
1550
|
+
|
|
1551
|
+
//#endregion
|
|
1552
|
+
//#region src/schema/core/schema.ts
|
|
1553
|
+
const schema$2 = [
|
|
1554
|
+
map,
|
|
1555
|
+
seq,
|
|
1556
|
+
string,
|
|
1557
|
+
nullTag,
|
|
1558
|
+
boolTag,
|
|
1559
|
+
intOct$1,
|
|
1560
|
+
int$1,
|
|
1561
|
+
intHex$1,
|
|
1562
|
+
floatNaN$1,
|
|
1563
|
+
floatExp$1,
|
|
1564
|
+
float$1
|
|
1565
|
+
];
|
|
1566
|
+
|
|
1567
|
+
//#endregion
|
|
1568
|
+
//#region src/schema/json/schema.ts
|
|
1569
|
+
function intIdentify$1(value) {
|
|
1570
|
+
return typeof value === "bigint" || Number.isInteger(value);
|
|
1571
|
+
}
|
|
1572
|
+
const stringifyJSON = ({ value }) => JSON.stringify(value);
|
|
1573
|
+
const jsonScalars = [
|
|
1574
|
+
{
|
|
1575
|
+
identify: (value) => typeof value === "string",
|
|
1576
|
+
default: true,
|
|
1577
|
+
tag: "tag:yaml.org,2002:str",
|
|
1578
|
+
resolve: (str) => str,
|
|
1579
|
+
stringify: stringifyJSON
|
|
1580
|
+
},
|
|
1581
|
+
{
|
|
1582
|
+
identify: (value) => value == null,
|
|
1583
|
+
createNode: () => new Scalar(null),
|
|
1584
|
+
default: true,
|
|
1585
|
+
tag: "tag:yaml.org,2002:null",
|
|
1586
|
+
test: /^null$/,
|
|
1587
|
+
resolve: () => null,
|
|
1588
|
+
stringify: stringifyJSON
|
|
1589
|
+
},
|
|
1590
|
+
{
|
|
1591
|
+
identify: (value) => typeof value === "boolean",
|
|
1592
|
+
default: true,
|
|
1593
|
+
tag: "tag:yaml.org,2002:bool",
|
|
1594
|
+
test: /^true$|^false$/,
|
|
1595
|
+
resolve: (str) => str === "true",
|
|
1596
|
+
stringify: stringifyJSON
|
|
1597
|
+
},
|
|
1598
|
+
{
|
|
1599
|
+
identify: intIdentify$1,
|
|
1600
|
+
default: true,
|
|
1601
|
+
tag: "tag:yaml.org,2002:int",
|
|
1602
|
+
test: /^-?(?:0|[1-9][0-9]*)$/,
|
|
1603
|
+
resolve: (str, _onError, { intAsBigInt }) => intAsBigInt ? BigInt(str) : parseInt(str, 10),
|
|
1604
|
+
stringify: ({ value }) => intIdentify$1(value) ? value.toString() : JSON.stringify(value)
|
|
1605
|
+
},
|
|
1606
|
+
{
|
|
1607
|
+
identify: (value) => typeof value === "number",
|
|
1608
|
+
default: true,
|
|
1609
|
+
tag: "tag:yaml.org,2002:float",
|
|
1610
|
+
test: /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]*)?(?:[eE][-+]?[0-9]+)?$/,
|
|
1611
|
+
resolve: (str) => parseFloat(str),
|
|
1612
|
+
stringify: stringifyJSON
|
|
1613
|
+
}
|
|
1614
|
+
];
|
|
1615
|
+
const jsonError = {
|
|
1616
|
+
default: true,
|
|
1617
|
+
tag: "",
|
|
1618
|
+
test: /^/,
|
|
1619
|
+
resolve(str, onError) {
|
|
1620
|
+
onError(`Unresolved plain scalar ${JSON.stringify(str)}`);
|
|
1621
|
+
return str;
|
|
1622
|
+
}
|
|
1623
|
+
};
|
|
1624
|
+
const schema$1 = [
|
|
1625
|
+
map,
|
|
1626
|
+
seq,
|
|
1627
|
+
...jsonScalars,
|
|
1628
|
+
jsonError
|
|
1629
|
+
];
|
|
1630
|
+
|
|
1631
|
+
//#endregion
|
|
1632
|
+
//#region src/schema/yaml-1.1/binary.ts
|
|
1633
|
+
const binary = {
|
|
1634
|
+
identify: (value) => value instanceof Uint8Array,
|
|
1635
|
+
default: false,
|
|
1636
|
+
tag: "tag:yaml.org,2002:binary",
|
|
1637
|
+
resolve(src, onError) {
|
|
1638
|
+
if (typeof Buffer === "function") return Buffer.from(src, "base64");
|
|
1639
|
+
else if (typeof Uint8Array.fromBase64 === "function") return Uint8Array.fromBase64(src);
|
|
1640
|
+
else if (typeof atob === "function") {
|
|
1641
|
+
const str = atob(src.replace(/[\n\r]/g, ""));
|
|
1642
|
+
const buffer = new Uint8Array(str.length);
|
|
1643
|
+
for (let i = 0; i < str.length; ++i) buffer[i] = str.charCodeAt(i);
|
|
1644
|
+
return buffer;
|
|
1645
|
+
} else {
|
|
1646
|
+
onError("This environment does not support reading binary tags; either Buffer or atob is required");
|
|
1647
|
+
return src;
|
|
1648
|
+
}
|
|
1649
|
+
},
|
|
1650
|
+
stringify({ comment, type, value }, ctx, onComment, onChompKeep) {
|
|
1651
|
+
if (!value) return "";
|
|
1652
|
+
const buf = value;
|
|
1653
|
+
let str;
|
|
1654
|
+
if (typeof buf.toBase64 === "function") str = buf.toBase64();
|
|
1655
|
+
else if (typeof Buffer === "function") str = buf instanceof Buffer ? buf.toString("base64") : Buffer.from(buf.buffer).toString("base64");
|
|
1656
|
+
else if (typeof btoa === "function") {
|
|
1657
|
+
let s = "";
|
|
1658
|
+
for (let i = 0; i < buf.length; ++i) s += String.fromCharCode(buf[i]);
|
|
1659
|
+
str = btoa(s);
|
|
1660
|
+
} else throw new Error("This environment does not support writing binary tags; either Buffer or btoa is required");
|
|
1661
|
+
type ??= Scalar.BLOCK_LITERAL;
|
|
1662
|
+
if (type !== Scalar.QUOTE_DOUBLE) {
|
|
1663
|
+
const lineWidth = Math.max(ctx.options.lineWidth - ctx.indent.length, ctx.options.minContentWidth);
|
|
1664
|
+
const n = Math.ceil(str.length / lineWidth);
|
|
1665
|
+
const lines = new Array(n);
|
|
1666
|
+
for (let i = 0, o = 0; i < n; ++i, o += lineWidth) lines[i] = str.substr(o, lineWidth);
|
|
1667
|
+
str = lines.join(type === Scalar.BLOCK_LITERAL ? "\n" : " ");
|
|
1668
|
+
}
|
|
1669
|
+
return stringifyString({
|
|
1670
|
+
comment,
|
|
1671
|
+
type,
|
|
1672
|
+
value: str
|
|
1673
|
+
}, ctx, onComment, onChompKeep);
|
|
1674
|
+
}
|
|
1675
|
+
};
|
|
1676
|
+
|
|
1677
|
+
//#endregion
|
|
1678
|
+
//#region src/schema/yaml-1.1/pairs.ts
|
|
1679
|
+
function resolvePairs(seq, onError) {
|
|
1680
|
+
if (seq instanceof YAMLSeq) for (let i = 0; i < seq.items.length; ++i) {
|
|
1681
|
+
const item = seq.items[i];
|
|
1682
|
+
if (item instanceof Pair) continue;
|
|
1683
|
+
else if (item instanceof YAMLMap) {
|
|
1684
|
+
if (item.items.length > 1) onError("Each pair must have its own sequence indicator");
|
|
1685
|
+
const pair = item.items[0] || new Pair(new Scalar(null));
|
|
1686
|
+
if (item.commentBefore) pair.key.commentBefore = pair.key.commentBefore ? `${item.commentBefore}\n${pair.key.commentBefore}` : item.commentBefore;
|
|
1687
|
+
if (item.comment) {
|
|
1688
|
+
const cn = pair.value ?? pair.key;
|
|
1689
|
+
cn.comment = cn.comment ? `${item.comment}\n${cn.comment}` : item.comment;
|
|
1690
|
+
}
|
|
1691
|
+
seq.items[i] = pair;
|
|
1692
|
+
} else seq.items[i] = new Pair(item, null);
|
|
1693
|
+
}
|
|
1694
|
+
else onError("Expected a sequence for this tag");
|
|
1695
|
+
return seq;
|
|
1696
|
+
}
|
|
1697
|
+
function createPairs(nc, iterable) {
|
|
1698
|
+
const pairs = new YAMLSeq(nc.schema);
|
|
1699
|
+
pairs.tag = "tag:yaml.org,2002:pairs";
|
|
1700
|
+
let i = 0;
|
|
1701
|
+
if (iterable && Symbol.iterator in Object(iterable)) for (let it of iterable) {
|
|
1702
|
+
if (typeof nc.replacer === "function") it = nc.replacer.call(iterable, String(i++), it);
|
|
1703
|
+
let key, value;
|
|
1704
|
+
if (Array.isArray(it)) if (it.length === 2) {
|
|
1705
|
+
key = it[0];
|
|
1706
|
+
value = it[1];
|
|
1707
|
+
} else throw new TypeError(`Expected [key, value] tuple: ${it}`);
|
|
1708
|
+
else if (it && it instanceof Object) {
|
|
1709
|
+
const keys = Object.keys(it);
|
|
1710
|
+
if (keys.length === 1) {
|
|
1711
|
+
key = keys[0];
|
|
1712
|
+
value = it[key];
|
|
1713
|
+
} else throw new TypeError(`Expected tuple with one key, not ${keys.length} keys`);
|
|
1714
|
+
} else key = it;
|
|
1715
|
+
pairs.items.push(nc.createPair(key, value));
|
|
1716
|
+
}
|
|
1717
|
+
return pairs;
|
|
1718
|
+
}
|
|
1719
|
+
const pairs = {
|
|
1720
|
+
collection: "seq",
|
|
1721
|
+
default: false,
|
|
1722
|
+
tag: "tag:yaml.org,2002:pairs",
|
|
1723
|
+
resolve: resolvePairs,
|
|
1724
|
+
createNode: createPairs
|
|
1725
|
+
};
|
|
1726
|
+
|
|
1727
|
+
//#endregion
|
|
1728
|
+
//#region src/schema/yaml-1.1/omap.ts
|
|
1729
|
+
var YAMLOMap = class YAMLOMap extends YAMLSeq {
|
|
1730
|
+
static tag = "tag:yaml.org,2002:omap";
|
|
1731
|
+
constructor(schema) {
|
|
1732
|
+
super(schema);
|
|
1733
|
+
this.tag = YAMLOMap.tag;
|
|
1734
|
+
}
|
|
1735
|
+
add = YAMLMap.prototype.add.bind(this);
|
|
1736
|
+
delete = YAMLMap.prototype.delete.bind(this);
|
|
1737
|
+
get = YAMLMap.prototype.get.bind(this);
|
|
1738
|
+
has = YAMLMap.prototype.has.bind(this);
|
|
1739
|
+
set = YAMLMap.prototype.set.bind(this);
|
|
1740
|
+
/**
|
|
1741
|
+
* If `ctx` is given, the return type is actually `Map<unknown, unknown>`,
|
|
1742
|
+
* but TypeScript won't allow widening the signature of a child method.
|
|
1743
|
+
*/
|
|
1744
|
+
toJSON(_, ctx) {
|
|
1745
|
+
if (!ctx) return super.toJSON(_);
|
|
1746
|
+
const map = /* @__PURE__ */ new Map();
|
|
1747
|
+
if (ctx?.onCreate) ctx.onCreate(map);
|
|
1748
|
+
for (const pair of this.items) {
|
|
1749
|
+
let key, value;
|
|
1750
|
+
if (pair instanceof Pair) {
|
|
1751
|
+
key = toJS(pair.key, "", ctx);
|
|
1752
|
+
value = toJS(pair.value, key, ctx);
|
|
1753
|
+
} else key = toJS(pair, "", ctx);
|
|
1754
|
+
if (map.has(key)) throw new Error("Ordered maps must not include duplicate keys");
|
|
1755
|
+
map.set(key, value);
|
|
1756
|
+
}
|
|
1757
|
+
return map;
|
|
1758
|
+
}
|
|
1759
|
+
static from(nc, iterable) {
|
|
1760
|
+
const pairs = createPairs(nc, iterable);
|
|
1761
|
+
const omap = new this(nc.schema);
|
|
1762
|
+
omap.items = pairs.items;
|
|
1763
|
+
return omap;
|
|
1764
|
+
}
|
|
1765
|
+
};
|
|
1766
|
+
const omap = {
|
|
1767
|
+
collection: "seq",
|
|
1768
|
+
identify: (value) => value instanceof Map,
|
|
1769
|
+
nodeClass: YAMLOMap,
|
|
1770
|
+
default: false,
|
|
1771
|
+
tag: "tag:yaml.org,2002:omap",
|
|
1772
|
+
resolve(seq, onError) {
|
|
1773
|
+
const pairs = resolvePairs(seq, onError);
|
|
1774
|
+
const seenKeys = [];
|
|
1775
|
+
for (const { key } of pairs.items) if (key instanceof Scalar) if (seenKeys.includes(key.value)) onError(`Ordered maps must not include duplicate keys: ${key.value}`);
|
|
1776
|
+
else seenKeys.push(key.value);
|
|
1777
|
+
return Object.assign(new YAMLOMap(), pairs);
|
|
1778
|
+
}
|
|
1779
|
+
};
|
|
1780
|
+
|
|
1781
|
+
//#endregion
|
|
1782
|
+
//#region src/schema/yaml-1.1/bool.ts
|
|
1783
|
+
function boolStringify({ value, source }, ctx) {
|
|
1784
|
+
if (source && (value ? trueTag : falseTag).test.test(source)) return source;
|
|
1785
|
+
return value ? ctx.options.trueStr : ctx.options.falseStr;
|
|
1786
|
+
}
|
|
1787
|
+
const trueTag = {
|
|
1788
|
+
identify: (value) => value === true,
|
|
1789
|
+
default: true,
|
|
1790
|
+
tag: "tag:yaml.org,2002:bool",
|
|
1791
|
+
test: /^(?:Y|y|[Yy]es|YES|[Tt]rue|TRUE|[Oo]n|ON)$/,
|
|
1792
|
+
resolve: () => new Scalar(true),
|
|
1793
|
+
stringify: boolStringify
|
|
1794
|
+
};
|
|
1795
|
+
const falseTag = {
|
|
1796
|
+
identify: (value) => value === false,
|
|
1797
|
+
default: true,
|
|
1798
|
+
tag: "tag:yaml.org,2002:bool",
|
|
1799
|
+
test: /^(?:N|n|[Nn]o|NO|[Ff]alse|FALSE|[Oo]ff|OFF)$/,
|
|
1800
|
+
resolve: () => new Scalar(false),
|
|
1801
|
+
stringify: boolStringify
|
|
1802
|
+
};
|
|
1803
|
+
|
|
1804
|
+
//#endregion
|
|
1805
|
+
//#region src/schema/yaml-1.1/float.ts
|
|
1806
|
+
const floatNaN = {
|
|
1807
|
+
identify: (value) => typeof value === "number",
|
|
1808
|
+
default: true,
|
|
1809
|
+
tag: "tag:yaml.org,2002:float",
|
|
1810
|
+
test: /^(?:[-+]?\.(?:inf|Inf|INF)|\.nan|\.NaN|\.NAN)$/,
|
|
1811
|
+
resolve: (str) => str.slice(-3).toLowerCase() === "nan" ? NaN : str[0] === "-" ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
|
|
1812
|
+
stringify: stringifyNumber
|
|
1813
|
+
};
|
|
1814
|
+
const floatExp = {
|
|
1815
|
+
identify: (value) => typeof value === "number",
|
|
1816
|
+
default: true,
|
|
1817
|
+
tag: "tag:yaml.org,2002:float",
|
|
1818
|
+
format: "EXP",
|
|
1819
|
+
test: /^[-+]?(?:[0-9][0-9_]*)?(?:\.[0-9_]*)?[eE][-+]?[0-9]+$/,
|
|
1820
|
+
resolve: (str) => parseFloat(str.replace(/_/g, "")),
|
|
1821
|
+
stringify(node) {
|
|
1822
|
+
const num = Number(node.value);
|
|
1823
|
+
return isFinite(num) ? num.toExponential() : stringifyNumber(node);
|
|
1824
|
+
}
|
|
1825
|
+
};
|
|
1826
|
+
const float = {
|
|
1827
|
+
identify: (value) => typeof value === "number",
|
|
1828
|
+
default: true,
|
|
1829
|
+
tag: "tag:yaml.org,2002:float",
|
|
1830
|
+
test: /^[-+]?(?:[0-9][0-9_]*)?\.[0-9_]*$/,
|
|
1831
|
+
resolve(str) {
|
|
1832
|
+
const node = new Scalar(parseFloat(str.replace(/_/g, "")));
|
|
1833
|
+
const dot = str.indexOf(".");
|
|
1834
|
+
if (dot !== -1) {
|
|
1835
|
+
const f = str.substring(dot + 1).replace(/_/g, "");
|
|
1836
|
+
if (f[f.length - 1] === "0") node.minFractionDigits = f.length;
|
|
1837
|
+
}
|
|
1838
|
+
return node;
|
|
1839
|
+
},
|
|
1840
|
+
stringify: stringifyNumber
|
|
1841
|
+
};
|
|
1842
|
+
|
|
1843
|
+
//#endregion
|
|
1844
|
+
//#region src/schema/yaml-1.1/int.ts
|
|
1845
|
+
const intIdentify = (value) => typeof value === "bigint" || Number.isInteger(value);
|
|
1846
|
+
function intResolve(str, offset, radix, { intAsBigInt }) {
|
|
1847
|
+
const sign = str[0];
|
|
1848
|
+
if (sign === "-" || sign === "+") offset += 1;
|
|
1849
|
+
str = str.substring(offset).replace(/_/g, "");
|
|
1850
|
+
if (intAsBigInt) {
|
|
1851
|
+
switch (radix) {
|
|
1852
|
+
case 2:
|
|
1853
|
+
str = `0b${str}`;
|
|
1854
|
+
break;
|
|
1855
|
+
case 8:
|
|
1856
|
+
str = `0o${str}`;
|
|
1857
|
+
break;
|
|
1858
|
+
case 16:
|
|
1859
|
+
str = `0x${str}`;
|
|
1860
|
+
break;
|
|
1861
|
+
}
|
|
1862
|
+
const n = BigInt(str);
|
|
1863
|
+
return sign === "-" ? BigInt(-1) * n : n;
|
|
1864
|
+
}
|
|
1865
|
+
const n = parseInt(str, radix);
|
|
1866
|
+
return sign === "-" ? -1 * n : n;
|
|
1867
|
+
}
|
|
1868
|
+
function intStringify(node, radix, prefix) {
|
|
1869
|
+
const { value } = node;
|
|
1870
|
+
if (intIdentify(value)) {
|
|
1871
|
+
const str = value.toString(radix);
|
|
1872
|
+
return value < 0 ? "-" + prefix + str.substr(1) : prefix + str;
|
|
1873
|
+
}
|
|
1874
|
+
return stringifyNumber(node);
|
|
1875
|
+
}
|
|
1876
|
+
const intBin = {
|
|
1877
|
+
identify: intIdentify,
|
|
1878
|
+
default: true,
|
|
1879
|
+
tag: "tag:yaml.org,2002:int",
|
|
1880
|
+
format: "BIN",
|
|
1881
|
+
test: /^[-+]?0b[0-1_]+$/,
|
|
1882
|
+
resolve: (str, _onError, opt) => intResolve(str, 2, 2, opt),
|
|
1883
|
+
stringify: (node) => intStringify(node, 2, "0b")
|
|
1884
|
+
};
|
|
1885
|
+
const intOct = {
|
|
1886
|
+
identify: intIdentify,
|
|
1887
|
+
default: true,
|
|
1888
|
+
tag: "tag:yaml.org,2002:int",
|
|
1889
|
+
format: "OCT",
|
|
1890
|
+
test: /^[-+]?0[0-7_]+$/,
|
|
1891
|
+
resolve: (str, _onError, opt) => intResolve(str, 1, 8, opt),
|
|
1892
|
+
stringify: (node) => intStringify(node, 8, "0")
|
|
1893
|
+
};
|
|
1894
|
+
const int = {
|
|
1895
|
+
identify: intIdentify,
|
|
1896
|
+
default: true,
|
|
1897
|
+
tag: "tag:yaml.org,2002:int",
|
|
1898
|
+
test: /^[-+]?[0-9][0-9_]*$/,
|
|
1899
|
+
resolve: (str, _onError, opt) => intResolve(str, 0, 10, opt),
|
|
1900
|
+
stringify: stringifyNumber
|
|
1901
|
+
};
|
|
1902
|
+
const intHex = {
|
|
1903
|
+
identify: intIdentify,
|
|
1904
|
+
default: true,
|
|
1905
|
+
tag: "tag:yaml.org,2002:int",
|
|
1906
|
+
format: "HEX",
|
|
1907
|
+
test: /^[-+]?0x[0-9a-fA-F_]+$/,
|
|
1908
|
+
resolve: (str, _onError, opt) => intResolve(str, 2, 16, opt),
|
|
1909
|
+
stringify: (node) => intStringify(node, 16, "0x")
|
|
1910
|
+
};
|
|
1911
|
+
|
|
1912
|
+
//#endregion
|
|
1913
|
+
//#region src/schema/yaml-1.1/set.ts
|
|
1914
|
+
var YAMLSet = class YAMLSet extends YAMLMap {
|
|
1915
|
+
static tag = "tag:yaml.org,2002:set";
|
|
1916
|
+
constructor(schema) {
|
|
1917
|
+
super(schema);
|
|
1918
|
+
this.tag = YAMLSet.tag;
|
|
1919
|
+
}
|
|
1920
|
+
/**
|
|
1921
|
+
* Add a value to the set.
|
|
1922
|
+
*
|
|
1923
|
+
* If `value` is a Pair, its `.value` must be null and `options` is ignored.
|
|
1924
|
+
*
|
|
1925
|
+
* If the set already includes a matching value, no value is added.
|
|
1926
|
+
*/
|
|
1927
|
+
add(value, options) {
|
|
1928
|
+
if (!(value instanceof Pair)) this.set(value, true, options);
|
|
1929
|
+
else if (value.value !== null) throw new TypeError("set pair values must be null");
|
|
1930
|
+
else if (!findPair(this.items, value.key)) this.items.push(value);
|
|
1931
|
+
}
|
|
1932
|
+
/**
|
|
1933
|
+
* Returns the value matching `key`.
|
|
1934
|
+
*/
|
|
1935
|
+
get(key) {
|
|
1936
|
+
return findPair(this.items, key)?.key;
|
|
1937
|
+
}
|
|
1938
|
+
/**
|
|
1939
|
+
* `value` needs to be true/false to add/remove the item from the set.
|
|
1940
|
+
*/
|
|
1941
|
+
set(key, value, options) {
|
|
1942
|
+
if (typeof value !== "boolean") throw new Error(`Expected a boolean value, not ${typeof value}`);
|
|
1943
|
+
const prev = findPair(this.items, key);
|
|
1944
|
+
if (prev && !value) this.items.splice(this.items.indexOf(prev), 1);
|
|
1945
|
+
else if (!prev && value) {
|
|
1946
|
+
let node;
|
|
1947
|
+
if (key instanceof NodeBase) node = key;
|
|
1948
|
+
else if (!this.schema) throw new Error("Schema is required");
|
|
1949
|
+
else {
|
|
1950
|
+
const nc = new NodeCreator(this.schema, {
|
|
1951
|
+
...options,
|
|
1952
|
+
aliasDuplicateObjects: false
|
|
1953
|
+
});
|
|
1954
|
+
node = nc.create(key);
|
|
1955
|
+
nc.setAnchors();
|
|
1956
|
+
}
|
|
1957
|
+
this.items.push(new Pair(node));
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
toJSON(_, ctx) {
|
|
1961
|
+
return super.toJSON(_, ctx, Set);
|
|
1962
|
+
}
|
|
1963
|
+
toString(ctx, onComment, onChompKeep) {
|
|
1964
|
+
if (!ctx) return JSON.stringify(this);
|
|
1965
|
+
return super.toString({
|
|
1966
|
+
...ctx,
|
|
1967
|
+
noValues: true
|
|
1968
|
+
}, onComment, onChompKeep);
|
|
1969
|
+
}
|
|
1970
|
+
static from(nc, iterable) {
|
|
1971
|
+
const set = new this(nc.schema);
|
|
1972
|
+
if (iterable && Symbol.iterator in Object(iterable)) for (let value of iterable) {
|
|
1973
|
+
if (typeof nc.replacer === "function") value = nc.replacer.call(iterable, value, value);
|
|
1974
|
+
set.items.push(nc.createPair(value, null));
|
|
1975
|
+
}
|
|
1976
|
+
return set;
|
|
1977
|
+
}
|
|
1978
|
+
};
|
|
1979
|
+
const hasAllNullValues = (map) => map.items.every(({ value }) => value == null || value instanceof Scalar && value.value == null && !value.commentBefore && !value.comment && !value.tag);
|
|
1980
|
+
const set = {
|
|
1981
|
+
collection: "map",
|
|
1982
|
+
identify: (value) => value instanceof Set,
|
|
1983
|
+
nodeClass: YAMLSet,
|
|
1984
|
+
default: false,
|
|
1985
|
+
tag: "tag:yaml.org,2002:set",
|
|
1986
|
+
resolve(map, onError) {
|
|
1987
|
+
if (!(map instanceof YAMLMap)) {
|
|
1988
|
+
onError("Expected a mapping for this tag");
|
|
1989
|
+
return map;
|
|
1990
|
+
} else if (!hasAllNullValues(map)) {
|
|
1991
|
+
onError("Set items must all have null values");
|
|
1992
|
+
return map;
|
|
1993
|
+
} else {
|
|
1994
|
+
const set = Object.assign(new YAMLSet(), map);
|
|
1995
|
+
for (const pair of map.items) pair.value &&= null;
|
|
1996
|
+
return set;
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
};
|
|
2000
|
+
|
|
2001
|
+
//#endregion
|
|
2002
|
+
//#region src/schema/yaml-1.1/timestamp.ts
|
|
2003
|
+
/** Internal types handle bigint as number, because TS can't figure it out. */
|
|
2004
|
+
function parseSexagesimal(str, asBigInt) {
|
|
2005
|
+
const sign = str[0];
|
|
2006
|
+
const parts = sign === "-" || sign === "+" ? str.substring(1) : str;
|
|
2007
|
+
const num = (n) => asBigInt ? BigInt(n) : Number(n);
|
|
2008
|
+
const res = parts.replace(/_/g, "").split(":").reduce((res, p) => res * num(60) + num(p), num(0));
|
|
2009
|
+
return sign === "-" ? num(-1) * res : res;
|
|
2010
|
+
}
|
|
2011
|
+
/**
|
|
2012
|
+
* hhhh:mm:ss.sss
|
|
2013
|
+
*
|
|
2014
|
+
* Internal types handle bigint as number, because TS can't figure it out.
|
|
2015
|
+
*/
|
|
2016
|
+
function stringifySexagesimal(node) {
|
|
2017
|
+
let { value } = node;
|
|
2018
|
+
let num = (n) => n;
|
|
2019
|
+
if (typeof value === "bigint") num = (n) => BigInt(n);
|
|
2020
|
+
else if (isNaN(value) || !isFinite(value)) return stringifyNumber(node);
|
|
2021
|
+
let sign = "";
|
|
2022
|
+
if (value < 0) {
|
|
2023
|
+
sign = "-";
|
|
2024
|
+
value *= num(-1);
|
|
2025
|
+
}
|
|
2026
|
+
const _60 = num(60);
|
|
2027
|
+
const parts = [value % _60];
|
|
2028
|
+
if (value < 60) parts.unshift(0);
|
|
2029
|
+
else {
|
|
2030
|
+
value = (value - parts[0]) / _60;
|
|
2031
|
+
parts.unshift(value % _60);
|
|
2032
|
+
if (value >= 60) {
|
|
2033
|
+
value = (value - parts[0]) / _60;
|
|
2034
|
+
parts.unshift(value);
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
return sign + parts.map((n) => String(n).padStart(2, "0")).join(":").replace(/000000\d*$/, "");
|
|
2038
|
+
}
|
|
2039
|
+
const intTime = {
|
|
2040
|
+
identify: (value) => typeof value === "bigint" || Number.isInteger(value),
|
|
2041
|
+
default: true,
|
|
2042
|
+
tag: "tag:yaml.org,2002:int",
|
|
2043
|
+
format: "TIME",
|
|
2044
|
+
test: /^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+$/,
|
|
2045
|
+
resolve: (str, _onError, { intAsBigInt }) => parseSexagesimal(str, intAsBigInt),
|
|
2046
|
+
stringify: stringifySexagesimal
|
|
2047
|
+
};
|
|
2048
|
+
const floatTime = {
|
|
2049
|
+
identify: (value) => typeof value === "number",
|
|
2050
|
+
default: true,
|
|
2051
|
+
tag: "tag:yaml.org,2002:float",
|
|
2052
|
+
format: "TIME",
|
|
2053
|
+
test: /^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\.[0-9_]*$/,
|
|
2054
|
+
resolve: (str) => parseSexagesimal(str, false),
|
|
2055
|
+
stringify: stringifySexagesimal
|
|
2056
|
+
};
|
|
2057
|
+
const timestamp = {
|
|
2058
|
+
identify: (value) => value instanceof Date,
|
|
2059
|
+
default: true,
|
|
2060
|
+
tag: "tag:yaml.org,2002:timestamp",
|
|
2061
|
+
test: RegExp("^([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})(?:(?:t|T|[ \\t]+)([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2}(\\.[0-9]+)?)(?:[ \\t]*(Z|[-+][012]?[0-9](?::[0-9]{2})?))?)?$"),
|
|
2062
|
+
resolve(str) {
|
|
2063
|
+
const match = str.match(timestamp.test);
|
|
2064
|
+
if (!match) throw new Error("!!timestamp expects a date, starting with yyyy-mm-dd");
|
|
2065
|
+
const [, year, month, day, hour, minute, second] = match.map(Number);
|
|
2066
|
+
const millisec = match[7] ? Number((match[7] + "00").substr(1, 3)) : 0;
|
|
2067
|
+
let date = Date.UTC(year, month - 1, day, hour || 0, minute || 0, second || 0, millisec);
|
|
2068
|
+
const tz = match[8];
|
|
2069
|
+
if (tz && tz !== "Z") {
|
|
2070
|
+
let d = parseSexagesimal(tz, false);
|
|
2071
|
+
if (Math.abs(d) < 30) d *= 60;
|
|
2072
|
+
date -= 6e4 * d;
|
|
2073
|
+
}
|
|
2074
|
+
return new Date(date);
|
|
2075
|
+
},
|
|
2076
|
+
stringify: ({ value }) => value?.toISOString().replace(/(T00:00:00)?\.000Z$/, "") ?? ""
|
|
2077
|
+
};
|
|
2078
|
+
|
|
2079
|
+
//#endregion
|
|
2080
|
+
//#region src/schema/yaml-1.1/schema.ts
|
|
2081
|
+
const schema = [
|
|
2082
|
+
map,
|
|
2083
|
+
seq,
|
|
2084
|
+
string,
|
|
2085
|
+
nullTag,
|
|
2086
|
+
trueTag,
|
|
2087
|
+
falseTag,
|
|
2088
|
+
intBin,
|
|
2089
|
+
intOct,
|
|
2090
|
+
int,
|
|
2091
|
+
intHex,
|
|
2092
|
+
floatNaN,
|
|
2093
|
+
floatExp,
|
|
2094
|
+
float,
|
|
2095
|
+
binary,
|
|
2096
|
+
merge,
|
|
2097
|
+
omap,
|
|
2098
|
+
pairs,
|
|
2099
|
+
set,
|
|
2100
|
+
intTime,
|
|
2101
|
+
floatTime,
|
|
2102
|
+
timestamp
|
|
2103
|
+
];
|
|
2104
|
+
|
|
2105
|
+
//#endregion
|
|
2106
|
+
//#region src/schema/tags.ts
|
|
2107
|
+
const schemas = new Map([
|
|
2108
|
+
["core", schema$2],
|
|
2109
|
+
["failsafe", [
|
|
2110
|
+
map,
|
|
2111
|
+
seq,
|
|
2112
|
+
string
|
|
2113
|
+
]],
|
|
2114
|
+
["json", schema$1],
|
|
2115
|
+
["yaml11", schema],
|
|
2116
|
+
["yaml-1.1", schema]
|
|
2117
|
+
]);
|
|
2118
|
+
const tagsByName = {
|
|
2119
|
+
binary,
|
|
2120
|
+
bool: boolTag,
|
|
2121
|
+
float: float$1,
|
|
2122
|
+
floatExp: floatExp$1,
|
|
2123
|
+
floatNaN: floatNaN$1,
|
|
2124
|
+
floatTime,
|
|
2125
|
+
int: int$1,
|
|
2126
|
+
intHex: intHex$1,
|
|
2127
|
+
intOct: intOct$1,
|
|
2128
|
+
intTime,
|
|
2129
|
+
map,
|
|
2130
|
+
merge,
|
|
2131
|
+
null: nullTag,
|
|
2132
|
+
omap,
|
|
2133
|
+
pairs,
|
|
2134
|
+
seq,
|
|
2135
|
+
set,
|
|
2136
|
+
timestamp
|
|
2137
|
+
};
|
|
2138
|
+
const coreKnownTags = {
|
|
2139
|
+
"tag:yaml.org,2002:binary": binary,
|
|
2140
|
+
"tag:yaml.org,2002:merge": merge,
|
|
2141
|
+
"tag:yaml.org,2002:omap": omap,
|
|
2142
|
+
"tag:yaml.org,2002:pairs": pairs,
|
|
2143
|
+
"tag:yaml.org,2002:set": set,
|
|
2144
|
+
"tag:yaml.org,2002:timestamp": timestamp
|
|
2145
|
+
};
|
|
2146
|
+
function getTags(customTags, schemaName, addMergeTag) {
|
|
2147
|
+
const schemaTags = schemas.get(schemaName);
|
|
2148
|
+
if (schemaTags && !customTags) return addMergeTag && !schemaTags.includes(merge) ? schemaTags.concat(merge) : schemaTags.slice();
|
|
2149
|
+
let tags = schemaTags;
|
|
2150
|
+
if (!tags) if (Array.isArray(customTags)) tags = [];
|
|
2151
|
+
else {
|
|
2152
|
+
const keys = Array.from(schemas.keys()).filter((key) => key !== "yaml11").map((key) => JSON.stringify(key)).join(", ");
|
|
2153
|
+
throw new Error(`Unknown schema "${schemaName}"; use one of ${keys} or define customTags array`);
|
|
2154
|
+
}
|
|
2155
|
+
if (Array.isArray(customTags)) for (const tag of customTags) tags = tags.concat(tag);
|
|
2156
|
+
else if (typeof customTags === "function") tags = customTags(tags.slice());
|
|
2157
|
+
if (addMergeTag) tags = tags.concat(merge);
|
|
2158
|
+
return tags.reduce((tags, tag) => {
|
|
2159
|
+
const tagObj = typeof tag === "string" ? tagsByName[tag] : tag;
|
|
2160
|
+
if (!tagObj) {
|
|
2161
|
+
const tagName = JSON.stringify(tag);
|
|
2162
|
+
const keys = Object.keys(tagsByName).map((key) => JSON.stringify(key)).join(", ");
|
|
2163
|
+
throw new Error(`Unknown custom tag ${tagName}; use one of ${keys}`);
|
|
2164
|
+
}
|
|
2165
|
+
if (!tags.includes(tagObj)) tags.push(tagObj);
|
|
2166
|
+
return tags;
|
|
2167
|
+
}, []);
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
//#endregion
|
|
2171
|
+
//#region src/schema/Schema.ts
|
|
2172
|
+
const sortMapEntriesByKey = (a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0;
|
|
2173
|
+
var Schema = class Schema {
|
|
2174
|
+
compat;
|
|
2175
|
+
knownTags;
|
|
2176
|
+
name;
|
|
2177
|
+
sortMapEntries;
|
|
2178
|
+
tags;
|
|
2179
|
+
toStringOptions;
|
|
2180
|
+
constructor({ compat, customTags, merge, resolveKnownTags, schema, sortMapEntries, toStringDefaults }) {
|
|
2181
|
+
this.compat = Array.isArray(compat) ? getTags(compat, "compat") : compat ? getTags(null, compat) : null;
|
|
2182
|
+
this.name = typeof schema === "string" && schema || "core";
|
|
2183
|
+
this.knownTags = resolveKnownTags ? coreKnownTags : {};
|
|
2184
|
+
this.tags = getTags(customTags, this.name, merge);
|
|
2185
|
+
this.toStringOptions = toStringDefaults ?? null;
|
|
2186
|
+
Object.defineProperty(this, "map", { value: map });
|
|
2187
|
+
Object.defineProperty(this, "scalar", { value: string });
|
|
2188
|
+
Object.defineProperty(this, "seq", { value: seq });
|
|
2189
|
+
this.sortMapEntries = typeof sortMapEntries === "function" ? sortMapEntries : sortMapEntries === true ? sortMapEntriesByKey : null;
|
|
2190
|
+
}
|
|
2191
|
+
clone() {
|
|
2192
|
+
const copy = Object.create(Schema.prototype, Object.getOwnPropertyDescriptors(this));
|
|
2193
|
+
copy.tags = this.tags.slice();
|
|
2194
|
+
return copy;
|
|
2195
|
+
}
|
|
2196
|
+
};
|
|
2197
|
+
|
|
2198
|
+
//#endregion
|
|
2199
|
+
//#region src/stringify/stringifyDocument.ts
|
|
2200
|
+
function stringifyDocument(doc, options) {
|
|
2201
|
+
const lines = [];
|
|
2202
|
+
let hasDirectives = options.directives === true;
|
|
2203
|
+
if (options.directives !== false && doc.directives) {
|
|
2204
|
+
const dir = doc.directives.toString(doc);
|
|
2205
|
+
if (dir) {
|
|
2206
|
+
lines.push(dir);
|
|
2207
|
+
hasDirectives = true;
|
|
2208
|
+
} else if (doc.directives.docStart) hasDirectives = true;
|
|
2209
|
+
}
|
|
2210
|
+
if (hasDirectives) lines.push("---");
|
|
2211
|
+
const ctx = createStringifyContext(doc, options);
|
|
2212
|
+
const { commentString } = ctx.options;
|
|
2213
|
+
if (doc.commentBefore) {
|
|
2214
|
+
if (lines.length !== 1) lines.unshift("");
|
|
2215
|
+
const cs = commentString(doc.commentBefore);
|
|
2216
|
+
lines.unshift(indentComment(cs, ""));
|
|
2217
|
+
}
|
|
2218
|
+
let chompKeep = false;
|
|
2219
|
+
let contentComment = null;
|
|
2220
|
+
if (doc.value.spaceBefore && hasDirectives) lines.push("");
|
|
2221
|
+
if (doc.value.commentBefore) {
|
|
2222
|
+
const cs = commentString(doc.value.commentBefore);
|
|
2223
|
+
lines.push(indentComment(cs, ""));
|
|
2224
|
+
}
|
|
2225
|
+
ctx.forceBlockIndent = !!doc.comment;
|
|
2226
|
+
contentComment = doc.value.comment;
|
|
2227
|
+
const onChompKeep = contentComment ? void 0 : () => chompKeep = true;
|
|
2228
|
+
let body = stringify(doc.value, ctx, () => contentComment = null, onChompKeep);
|
|
2229
|
+
if (contentComment) body += lineComment(body, "", commentString(contentComment));
|
|
2230
|
+
if ((body[0] === "|" || body[0] === ">") && lines[lines.length - 1] === "---") lines[lines.length - 1] = `--- ${body}`;
|
|
2231
|
+
else lines.push(body);
|
|
2232
|
+
if (doc.directives?.docEnd) if (doc.comment) {
|
|
2233
|
+
const cs = commentString(doc.comment);
|
|
2234
|
+
if (cs.includes("\n")) {
|
|
2235
|
+
lines.push("...");
|
|
2236
|
+
lines.push(indentComment(cs, ""));
|
|
2237
|
+
} else lines.push(`... ${cs}`);
|
|
2238
|
+
} else lines.push("...");
|
|
2239
|
+
else {
|
|
2240
|
+
let dc = doc.comment;
|
|
2241
|
+
if (dc && chompKeep) dc = dc.replace(/^\n+/, "");
|
|
2242
|
+
if (dc) {
|
|
2243
|
+
if ((!chompKeep || contentComment) && lines[lines.length - 1] !== "") lines.push("");
|
|
2244
|
+
lines.push(indentComment(commentString(dc), ""));
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
return lines.join("\n") + "\n";
|
|
2248
|
+
}
|
|
2249
|
+
|
|
2250
|
+
//#endregion
|
|
2251
|
+
//#region src/doc/Document.ts
|
|
2252
|
+
var Document = class Document {
|
|
2253
|
+
/** A comment before this Document */
|
|
2254
|
+
commentBefore = null;
|
|
2255
|
+
/** A comment immediately after this Document */
|
|
2256
|
+
comment = null;
|
|
2257
|
+
/** The document value. */
|
|
2258
|
+
value;
|
|
2259
|
+
directives;
|
|
2260
|
+
/** Errors encountered during parsing. */
|
|
2261
|
+
errors = [];
|
|
2262
|
+
options;
|
|
2263
|
+
/** Warnings encountered during parsing. */
|
|
2264
|
+
warnings = [];
|
|
2265
|
+
constructor(value, replacer, options) {
|
|
2266
|
+
let _replacer = null;
|
|
2267
|
+
if (typeof replacer === "function" || Array.isArray(replacer)) _replacer = replacer;
|
|
2268
|
+
else if (options === void 0 && replacer) {
|
|
2269
|
+
options = replacer;
|
|
2270
|
+
replacer = void 0;
|
|
2271
|
+
}
|
|
2272
|
+
const opt = Object.assign({
|
|
2273
|
+
intAsBigInt: false,
|
|
2274
|
+
keepSourceTokens: false,
|
|
2275
|
+
logLevel: "warn",
|
|
2276
|
+
prettyErrors: true,
|
|
2277
|
+
strict: true,
|
|
2278
|
+
stringKeys: false,
|
|
2279
|
+
uniqueKeys: true,
|
|
2280
|
+
version: "1.2"
|
|
2281
|
+
}, options);
|
|
2282
|
+
this.options = opt;
|
|
2283
|
+
let { version } = opt;
|
|
2284
|
+
if (options?._directives) {
|
|
2285
|
+
this.directives = options._directives.atDocument();
|
|
2286
|
+
if (this.directives.yaml.explicit) version = this.directives.yaml.version;
|
|
2287
|
+
} else this.directives = new Directives({ version });
|
|
2288
|
+
this.setSchema(version, options);
|
|
2289
|
+
this.value = this.createNode(value, _replacer, options);
|
|
2290
|
+
}
|
|
2291
|
+
/**
|
|
2292
|
+
* Create a deep copy of this Document and its value.
|
|
2293
|
+
*
|
|
2294
|
+
* Custom Node values that inherit from `Object` still refer to their original instances.
|
|
2295
|
+
*/
|
|
2296
|
+
clone() {
|
|
2297
|
+
const copy = Object.create(Document.prototype);
|
|
2298
|
+
copy.commentBefore = this.commentBefore;
|
|
2299
|
+
copy.comment = this.comment;
|
|
2300
|
+
copy.errors = this.errors.slice();
|
|
2301
|
+
copy.warnings = this.warnings.slice();
|
|
2302
|
+
copy.options = Object.assign({}, this.options);
|
|
2303
|
+
if (this.directives) copy.directives = this.directives.clone();
|
|
2304
|
+
copy.schema = this.schema.clone();
|
|
2305
|
+
copy.value = this.value.clone(copy.schema);
|
|
2306
|
+
if (this.range) copy.range = this.range.slice();
|
|
2307
|
+
return copy;
|
|
2308
|
+
}
|
|
2309
|
+
/** Adds a value to the document. */
|
|
2310
|
+
add(value) {
|
|
2311
|
+
assertCollection(this.value).add(value);
|
|
2312
|
+
}
|
|
2313
|
+
/** Adds a value to the document. */
|
|
2314
|
+
addIn(path, value) {
|
|
2315
|
+
assertCollection(this.value).addIn(path, value);
|
|
2316
|
+
}
|
|
2317
|
+
/**
|
|
2318
|
+
* Create a new `Alias` node, ensuring that the target `node` has the required anchor.
|
|
2319
|
+
*
|
|
2320
|
+
* If `node` already has an anchor, `name` is ignored.
|
|
2321
|
+
* Otherwise, the `node.anchor` value will be set to `name`,
|
|
2322
|
+
* or if an anchor with that name is already present in the document,
|
|
2323
|
+
* `name` will be used as a prefix for a new unique anchor.
|
|
2324
|
+
* If `name` is undefined, the generated anchor will use 'a' as a prefix.
|
|
2325
|
+
*/
|
|
2326
|
+
createAlias(node, name) {
|
|
2327
|
+
if (!node.anchor) {
|
|
2328
|
+
const prev = anchorNames(this);
|
|
2329
|
+
node.anchor = !name || prev.has(name) ? findNewAnchor(name || "a", prev) : name;
|
|
2330
|
+
}
|
|
2331
|
+
return new Alias(node.anchor);
|
|
2332
|
+
}
|
|
2333
|
+
createNode(value, replacer, options) {
|
|
2334
|
+
let nc;
|
|
2335
|
+
if (typeof replacer === "function") {
|
|
2336
|
+
value = replacer.call({ "": value }, "", value);
|
|
2337
|
+
nc = new NodeCreator(this, options, replacer);
|
|
2338
|
+
} else if (Array.isArray(replacer)) {
|
|
2339
|
+
const keyToStr = (v) => typeof v === "number" || v instanceof String || v instanceof Number;
|
|
2340
|
+
const asStr = replacer.filter(keyToStr).map(String);
|
|
2341
|
+
if (asStr.length > 0) replacer = replacer.concat(asStr);
|
|
2342
|
+
nc = new NodeCreator(this, options, replacer);
|
|
2343
|
+
} else {
|
|
2344
|
+
options ??= replacer ?? void 0;
|
|
2345
|
+
nc = new NodeCreator(this, options);
|
|
2346
|
+
}
|
|
2347
|
+
const node = nc.create(value, options?.tag);
|
|
2348
|
+
nc.setAnchors();
|
|
2349
|
+
return node;
|
|
2350
|
+
}
|
|
2351
|
+
/**
|
|
2352
|
+
* Convert a key and a value into a `Pair` using the current schema,
|
|
2353
|
+
* recursively wrapping all values as `Scalar` or `Collection` nodes.
|
|
2354
|
+
*/
|
|
2355
|
+
createPair(key, value, options = {}) {
|
|
2356
|
+
const nc = new NodeCreator(this, options);
|
|
2357
|
+
const pair = nc.createPair(key, value);
|
|
2358
|
+
nc.setAnchors();
|
|
2359
|
+
return pair;
|
|
2360
|
+
}
|
|
2361
|
+
/**
|
|
2362
|
+
* Removes a value from the document.
|
|
2363
|
+
* @returns `true` if the item was found and removed.
|
|
2364
|
+
*/
|
|
2365
|
+
delete(key) {
|
|
2366
|
+
return assertCollection(this.value).delete(key);
|
|
2367
|
+
}
|
|
2368
|
+
/**
|
|
2369
|
+
* Removes a value from the document.
|
|
2370
|
+
* @returns `true` if the item was found and removed.
|
|
2371
|
+
*/
|
|
2372
|
+
deleteIn(path) {
|
|
2373
|
+
if (!path.length) {
|
|
2374
|
+
this.value = new Scalar(null);
|
|
2375
|
+
return true;
|
|
2376
|
+
}
|
|
2377
|
+
return assertCollection(this.value).deleteIn(path);
|
|
2378
|
+
}
|
|
2379
|
+
/**
|
|
2380
|
+
* Returns item at `key`, or `undefined` if not found.
|
|
2381
|
+
*/
|
|
2382
|
+
get(key) {
|
|
2383
|
+
return this.value instanceof Collection ? this.value.get(key) : void 0;
|
|
2384
|
+
}
|
|
2385
|
+
/**
|
|
2386
|
+
* Returns item at `path`, or `undefined` if not found.
|
|
2387
|
+
*/
|
|
2388
|
+
getIn(path) {
|
|
2389
|
+
if (!path.length) return this.value;
|
|
2390
|
+
return this.value instanceof Collection ? this.value.getIn(path) : void 0;
|
|
2391
|
+
}
|
|
2392
|
+
/**
|
|
2393
|
+
* Checks if the document includes a value with the key `key`.
|
|
2394
|
+
*/
|
|
2395
|
+
has(key) {
|
|
2396
|
+
return this.value instanceof Collection ? this.value.has(key) : false;
|
|
2397
|
+
}
|
|
2398
|
+
/**
|
|
2399
|
+
* Checks if the document includes a value at `path`.
|
|
2400
|
+
*/
|
|
2401
|
+
hasIn(path) {
|
|
2402
|
+
if (!path.length) return true;
|
|
2403
|
+
return this.value instanceof Collection ? this.value.hasIn(path) : false;
|
|
2404
|
+
}
|
|
2405
|
+
/**
|
|
2406
|
+
* Sets a value in this document. For `!!set`, `value` needs to be a
|
|
2407
|
+
* boolean to add/remove the item from the set.
|
|
2408
|
+
*/
|
|
2409
|
+
set(key, value) {
|
|
2410
|
+
assertCollection(this.value).set(key, value);
|
|
2411
|
+
}
|
|
2412
|
+
/**
|
|
2413
|
+
* Sets a value in this document. For `!!set`, `value` needs to be a
|
|
2414
|
+
* boolean to add/remove the item from the set.
|
|
2415
|
+
*/
|
|
2416
|
+
setIn(path, value) {
|
|
2417
|
+
if (!path.length) this.value = value;
|
|
2418
|
+
else assertCollection(this.value).setIn(path, value);
|
|
2419
|
+
}
|
|
2420
|
+
/**
|
|
2421
|
+
* Change the YAML version and schema used by the document.
|
|
2422
|
+
* A `null` version disables support for directives, explicit tags, anchors, and aliases.
|
|
2423
|
+
* It also requires the `schema` option to be given as a `Schema` instance value.
|
|
2424
|
+
*
|
|
2425
|
+
* Overrides all previously set schema options.
|
|
2426
|
+
*/
|
|
2427
|
+
setSchema(version, options = {}) {
|
|
2428
|
+
if (typeof version === "number") version = String(version);
|
|
2429
|
+
let opt;
|
|
2430
|
+
switch (version) {
|
|
2431
|
+
case "1.1":
|
|
2432
|
+
if (this.directives) this.directives.yaml.version = "1.1";
|
|
2433
|
+
else this.directives = new Directives({ version: "1.1" });
|
|
2434
|
+
opt = {
|
|
2435
|
+
resolveKnownTags: false,
|
|
2436
|
+
schema: "yaml-1.1"
|
|
2437
|
+
};
|
|
2438
|
+
break;
|
|
2439
|
+
case "1.2":
|
|
2440
|
+
case "next":
|
|
2441
|
+
if (this.directives) this.directives.yaml.version = version;
|
|
2442
|
+
else this.directives = new Directives({ version });
|
|
2443
|
+
opt = {
|
|
2444
|
+
resolveKnownTags: true,
|
|
2445
|
+
schema: "core"
|
|
2446
|
+
};
|
|
2447
|
+
break;
|
|
2448
|
+
case null:
|
|
2449
|
+
if (this.directives) delete this.directives;
|
|
2450
|
+
opt = null;
|
|
2451
|
+
break;
|
|
2452
|
+
default: {
|
|
2453
|
+
const sv = JSON.stringify(version);
|
|
2454
|
+
throw new Error(`Expected '1.1', '1.2' or null as first argument, but found: ${sv}`);
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
if (options.schema instanceof Object) this.schema = options.schema;
|
|
2458
|
+
else if (opt) this.schema = new Schema(Object.assign(opt, options));
|
|
2459
|
+
else throw new Error(`With a null YAML version, the { schema: Schema } option is required`);
|
|
2460
|
+
}
|
|
2461
|
+
toJS({ json, jsonArg, mapAsMap, maxAliasCount, onAnchor, reviver } = {}) {
|
|
2462
|
+
const ctx = {
|
|
2463
|
+
anchors: /* @__PURE__ */ new Map(),
|
|
2464
|
+
doc: this,
|
|
2465
|
+
keep: !json,
|
|
2466
|
+
mapAsMap: mapAsMap === true,
|
|
2467
|
+
mapKeyWarned: false,
|
|
2468
|
+
maxAliasCount: typeof maxAliasCount === "number" ? maxAliasCount : 100
|
|
2469
|
+
};
|
|
2470
|
+
const res = toJS(this.value, jsonArg ?? "", ctx);
|
|
2471
|
+
if (typeof onAnchor === "function") for (const { count, res } of ctx.anchors.values()) onAnchor(res, count);
|
|
2472
|
+
return typeof reviver === "function" ? applyReviver(reviver, { "": res }, "", res) : res;
|
|
2473
|
+
}
|
|
2474
|
+
/**
|
|
2475
|
+
* A JSON representation of the document `value`.
|
|
2476
|
+
*
|
|
2477
|
+
* @param jsonArg Used by `JSON.stringify` to indicate the array index or
|
|
2478
|
+
* property name.
|
|
2479
|
+
*/
|
|
2480
|
+
toJSON(jsonArg, onAnchor) {
|
|
2481
|
+
return this.toJS({
|
|
2482
|
+
json: true,
|
|
2483
|
+
jsonArg,
|
|
2484
|
+
mapAsMap: false,
|
|
2485
|
+
onAnchor
|
|
2486
|
+
});
|
|
2487
|
+
}
|
|
2488
|
+
/** A YAML representation of the document. */
|
|
2489
|
+
toString(options = {}) {
|
|
2490
|
+
if (this.errors.length > 0) throw new Error("Document with errors cannot be stringified");
|
|
2491
|
+
if ("indent" in options && (!Number.isInteger(options.indent) || Number(options.indent) <= 0)) {
|
|
2492
|
+
const s = JSON.stringify(options.indent);
|
|
2493
|
+
throw new Error(`"indent" option must be a positive integer, not ${s}`);
|
|
2494
|
+
}
|
|
2495
|
+
return stringifyDocument(this, options);
|
|
2496
|
+
}
|
|
2497
|
+
};
|
|
2498
|
+
function assertCollection(value) {
|
|
2499
|
+
if (value instanceof Collection) return value;
|
|
2500
|
+
throw new Error("Expected a YAML collection as document value");
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2503
|
+
//#endregion
|
|
2504
|
+
//#region src/visit.ts
|
|
2505
|
+
const BREAK = Symbol("break visit");
|
|
2506
|
+
const SKIP = Symbol("skip children");
|
|
2507
|
+
const REMOVE = Symbol("remove node");
|
|
2508
|
+
/**
|
|
2509
|
+
* Apply a visitor to an AST node or document.
|
|
2510
|
+
*
|
|
2511
|
+
* Walks through the tree (depth-first) starting from `node`, calling a
|
|
2512
|
+
* `visitor` function with three arguments:
|
|
2513
|
+
* - `key`: For sequence values and map `Pair`, the node's index in the
|
|
2514
|
+
* collection. Within a `Pair`, `'key'` or `'value'`, correspondingly.
|
|
2515
|
+
* `null` for the root node.
|
|
2516
|
+
* - `node`: The current node.
|
|
2517
|
+
* - `path`: The ancestry of the current node.
|
|
2518
|
+
*
|
|
2519
|
+
* The return value of the visitor may be used to control the traversal:
|
|
2520
|
+
* - `undefined` (default): Do nothing and continue
|
|
2521
|
+
* - `visit.SKIP`: Do not visit the children of this node, continue with next
|
|
2522
|
+
* sibling
|
|
2523
|
+
* - `visit.BREAK`: Terminate traversal completely
|
|
2524
|
+
* - `visit.REMOVE`: Remove the current node, then continue with the next one
|
|
2525
|
+
* - `Node`: Replace the current node, then continue by visiting it
|
|
2526
|
+
* - `number`: While iterating the items of a sequence or map, set the index
|
|
2527
|
+
* of the next step. This is useful especially if the index of the current
|
|
2528
|
+
* node has changed.
|
|
2529
|
+
*
|
|
2530
|
+
* If `visitor` is a single function, it will be called with all values
|
|
2531
|
+
* encountered in the tree, including e.g. `null` values. Alternatively,
|
|
2532
|
+
* separate visitor functions may be defined for each `Map`, `Pair`, `Seq`,
|
|
2533
|
+
* `Alias` and `Scalar` node. To define the same visitor function for more than
|
|
2534
|
+
* one node type, use the `Collection` (map and seq), `Value` (map, seq & scalar)
|
|
2535
|
+
* and `Node` (alias, map, seq & scalar) targets. Of all these, only the most
|
|
2536
|
+
* specific defined one will be used for each node.
|
|
2537
|
+
*/
|
|
2538
|
+
const visit = function visit(node, visitor) {
|
|
2539
|
+
const visitor_ = initVisitor(visitor);
|
|
2540
|
+
if (node instanceof Document) {
|
|
2541
|
+
if (visit_(null, node.value, visitor_, Object.freeze([node])) === REMOVE) node.value = new Scalar(null);
|
|
2542
|
+
} else visit_(null, node, visitor_, Object.freeze([]));
|
|
2543
|
+
};
|
|
2544
|
+
visit.BREAK = BREAK;
|
|
2545
|
+
visit.SKIP = SKIP;
|
|
2546
|
+
visit.REMOVE = REMOVE;
|
|
2547
|
+
function visit_(key, node, visitor, path) {
|
|
2548
|
+
const ctrl = callVisitor(key, node, visitor, path);
|
|
2549
|
+
if (ctrl instanceof NodeBase || ctrl instanceof Pair) {
|
|
2550
|
+
replaceNode(key, path, ctrl);
|
|
2551
|
+
return visit_(key, ctrl, visitor, path);
|
|
2552
|
+
}
|
|
2553
|
+
if (typeof ctrl !== "symbol") {
|
|
2554
|
+
if (node instanceof YAMLMap || node instanceof YAMLSeq) {
|
|
2555
|
+
path = Object.freeze(path.concat(node));
|
|
2556
|
+
for (let i = 0; i < node.items.length; ++i) {
|
|
2557
|
+
const ci = visit_(i, node.items[i], visitor, path);
|
|
2558
|
+
if (typeof ci === "number") i = ci - 1;
|
|
2559
|
+
else if (ci === BREAK) return BREAK;
|
|
2560
|
+
else if (ci === REMOVE) {
|
|
2561
|
+
node.items.splice(i, 1);
|
|
2562
|
+
i -= 1;
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
} else if (node instanceof Pair) {
|
|
2566
|
+
path = Object.freeze(path.concat(node));
|
|
2567
|
+
const ck = visit_("key", node.key, visitor, path);
|
|
2568
|
+
if (ck === BREAK) return BREAK;
|
|
2569
|
+
else if (ck === REMOVE) node.key = new Scalar(null);
|
|
2570
|
+
const cv = visit_("value", node.value, visitor, path);
|
|
2571
|
+
if (cv === BREAK) return BREAK;
|
|
2572
|
+
else if (cv === REMOVE) node.value = null;
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
return ctrl;
|
|
2576
|
+
}
|
|
2577
|
+
/**
|
|
2578
|
+
* Apply an async visitor to an AST node or document.
|
|
2579
|
+
*
|
|
2580
|
+
* Walks through the tree (depth-first) starting from `node`, calling a
|
|
2581
|
+
* `visitor` function with three arguments:
|
|
2582
|
+
* - `key`: For sequence values and map `Pair`, the node's index in the
|
|
2583
|
+
* collection. Within a `Pair`, `'key'` or `'value'`, correspondingly.
|
|
2584
|
+
* `null` for the root node.
|
|
2585
|
+
* - `node`: The current node.
|
|
2586
|
+
* - `path`: The ancestry of the current node.
|
|
2587
|
+
*
|
|
2588
|
+
* The return value of the visitor may be used to control the traversal:
|
|
2589
|
+
* - `Promise`: Must resolve to one of the following values
|
|
2590
|
+
* - `undefined` (default): Do nothing and continue
|
|
2591
|
+
* - `visitAsync.SKIP`: Do not visit the children of this node,
|
|
2592
|
+
* continue with next sibling
|
|
2593
|
+
* - `visitAsync.BREAK`: Terminate traversal completely
|
|
2594
|
+
* - `visitAsync.REMOVE`: Remove the current node,
|
|
2595
|
+
* then continue with the next one
|
|
2596
|
+
* - `Node`: Replace the current node, then continue by visiting it
|
|
2597
|
+
* - `number`: While iterating the items of a sequence or map, set the index
|
|
2598
|
+
* of the next step. This is useful especially if the index of the current
|
|
2599
|
+
* node has changed.
|
|
2600
|
+
*
|
|
2601
|
+
* If `visitor` is a single function, it will be called with all values
|
|
2602
|
+
* encountered in the tree, including e.g. `null` values. Alternatively,
|
|
2603
|
+
* separate visitor functions may be defined for each `Map`, `Pair`, `Seq`,
|
|
2604
|
+
* `Alias` and `Scalar` node. To define the same visitor function for more than
|
|
2605
|
+
* one node type, use the `Collection` (map and seq), `Value` (map, seq & scalar)
|
|
2606
|
+
* and `Node` (alias, map, seq & scalar) targets. Of all these, only the most
|
|
2607
|
+
* specific defined one will be used for each node.
|
|
2608
|
+
*/
|
|
2609
|
+
const visitAsync = async function visitAsync(node, visitor) {
|
|
2610
|
+
const visitor_ = initVisitor(visitor);
|
|
2611
|
+
if (node instanceof Document) {
|
|
2612
|
+
if (await visitAsync_(null, node.value, visitor_, Object.freeze([node])) === REMOVE) node.value = new Scalar(null);
|
|
2613
|
+
} else await visitAsync_(null, node, visitor_, Object.freeze([]));
|
|
2614
|
+
};
|
|
2615
|
+
visitAsync.BREAK = BREAK;
|
|
2616
|
+
visitAsync.SKIP = SKIP;
|
|
2617
|
+
visitAsync.REMOVE = REMOVE;
|
|
2618
|
+
async function visitAsync_(key, node, visitor, path) {
|
|
2619
|
+
const ctrl = await callVisitor(key, node, visitor, path);
|
|
2620
|
+
if (ctrl instanceof NodeBase || ctrl instanceof Pair) {
|
|
2621
|
+
replaceNode(key, path, ctrl);
|
|
2622
|
+
return visitAsync_(key, ctrl, visitor, path);
|
|
2623
|
+
}
|
|
2624
|
+
if (typeof ctrl !== "symbol") {
|
|
2625
|
+
if (node instanceof YAMLMap || node instanceof YAMLSeq) {
|
|
2626
|
+
path = Object.freeze(path.concat(node));
|
|
2627
|
+
for (let i = 0; i < node.items.length; ++i) {
|
|
2628
|
+
const ci = await visitAsync_(i, node.items[i], visitor, path);
|
|
2629
|
+
if (typeof ci === "number") i = ci - 1;
|
|
2630
|
+
else if (ci === BREAK) return BREAK;
|
|
2631
|
+
else if (ci === REMOVE) {
|
|
2632
|
+
node.items.splice(i, 1);
|
|
2633
|
+
i -= 1;
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
} else if (node instanceof Pair) {
|
|
2637
|
+
path = Object.freeze(path.concat(node));
|
|
2638
|
+
const ck = await visitAsync_("key", node.key, visitor, path);
|
|
2639
|
+
if (ck === BREAK) return BREAK;
|
|
2640
|
+
else if (ck === REMOVE) node.key = new Scalar(null);
|
|
2641
|
+
const cv = await visitAsync_("value", node.value, visitor, path);
|
|
2642
|
+
if (cv === BREAK) return BREAK;
|
|
2643
|
+
else if (cv === REMOVE) node.value = null;
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
return ctrl;
|
|
2647
|
+
}
|
|
2648
|
+
function initVisitor(visitor) {
|
|
2649
|
+
if (typeof visitor === "object" && (visitor.Collection || visitor.Node || visitor.Value)) return Object.assign({
|
|
2650
|
+
Alias: visitor.Node,
|
|
2651
|
+
Map: visitor.Node,
|
|
2652
|
+
Scalar: visitor.Node,
|
|
2653
|
+
Seq: visitor.Node
|
|
2654
|
+
}, visitor.Value && {
|
|
2655
|
+
Map: visitor.Value,
|
|
2656
|
+
Scalar: visitor.Value,
|
|
2657
|
+
Seq: visitor.Value
|
|
2658
|
+
}, visitor.Collection && {
|
|
2659
|
+
Map: visitor.Collection,
|
|
2660
|
+
Seq: visitor.Collection
|
|
2661
|
+
}, visitor);
|
|
2662
|
+
return visitor;
|
|
2663
|
+
}
|
|
2664
|
+
function callVisitor(key, node, visitor, path) {
|
|
2665
|
+
if (typeof visitor === "function") return visitor(key, node, path);
|
|
2666
|
+
if (node instanceof YAMLMap) return visitor.Map?.(key, node, path);
|
|
2667
|
+
if (node instanceof YAMLSeq) return visitor.Seq?.(key, node, path);
|
|
2668
|
+
if (node instanceof Pair) return visitor.Pair?.(key, node, path);
|
|
2669
|
+
if (node instanceof Scalar) return visitor.Scalar?.(key, node, path);
|
|
2670
|
+
if (node instanceof Alias) return visitor.Alias?.(key, node, path);
|
|
2671
|
+
}
|
|
2672
|
+
function replaceNode(key, path, node) {
|
|
2673
|
+
const parent = path[path.length - 1];
|
|
2674
|
+
if (parent instanceof YAMLMap || parent instanceof YAMLSeq) parent.items[key] = node;
|
|
2675
|
+
else if (parent instanceof Pair) if (node instanceof NodeBase) if (key === "key") parent.key = node;
|
|
2676
|
+
else parent.value = node;
|
|
2677
|
+
else throw new Error(`Cannot replace pair ${key} with non-node value`);
|
|
2678
|
+
else if (parent instanceof Document) parent.value = node;
|
|
2679
|
+
else {
|
|
2680
|
+
const pt = parent instanceof Alias ? "alias" : "scalar";
|
|
2681
|
+
throw new Error(`Cannot replace node with ${pt} parent`);
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2685
|
+
//#endregion
|
|
2686
|
+
//#region src/doc/directives.ts
|
|
2687
|
+
const escapeChars = {
|
|
2688
|
+
"!": "%21",
|
|
2689
|
+
",": "%2C",
|
|
2690
|
+
"[": "%5B",
|
|
2691
|
+
"]": "%5D",
|
|
2692
|
+
"{": "%7B",
|
|
2693
|
+
"}": "%7D"
|
|
2694
|
+
};
|
|
2695
|
+
const escapeTagName = (tn) => tn.replace(/[!,[\]{}]/g, (ch) => escapeChars[ch]);
|
|
2696
|
+
var Directives = class Directives {
|
|
2697
|
+
static defaultYaml = {
|
|
2698
|
+
explicit: false,
|
|
2699
|
+
version: "1.2"
|
|
2700
|
+
};
|
|
2701
|
+
static defaultTags = { "!!": "tag:yaml.org,2002:" };
|
|
2702
|
+
yaml;
|
|
2703
|
+
tags;
|
|
2704
|
+
/**
|
|
2705
|
+
* The directives-end/doc-start marker `---`. If `null`, a marker may still be
|
|
2706
|
+
* included in the document's stringified representation.
|
|
2707
|
+
*/
|
|
2708
|
+
docStart = null;
|
|
2709
|
+
/** The doc-end marker `...`. */
|
|
2710
|
+
docEnd = false;
|
|
2711
|
+
/**
|
|
2712
|
+
* Used when parsing YAML 1.1, where:
|
|
2713
|
+
* > If the document specifies no directives, it is parsed using the same
|
|
2714
|
+
* > settings as the previous document. If the document does specify any
|
|
2715
|
+
* > directives, all directives of previous documents, if any, are ignored.
|
|
2716
|
+
*/
|
|
2717
|
+
atNextDocument;
|
|
2718
|
+
constructor(yaml, tags) {
|
|
2719
|
+
this.yaml = Object.assign({}, Directives.defaultYaml, yaml);
|
|
2720
|
+
this.tags = Object.assign({}, Directives.defaultTags, tags);
|
|
2721
|
+
}
|
|
2722
|
+
clone() {
|
|
2723
|
+
const copy = new Directives(this.yaml, this.tags);
|
|
2724
|
+
copy.docStart = this.docStart;
|
|
2725
|
+
return copy;
|
|
2726
|
+
}
|
|
2727
|
+
/**
|
|
2728
|
+
* During parsing, get a Directives instance for the current document and
|
|
2729
|
+
* update the stream state according to the current version's spec.
|
|
2730
|
+
*/
|
|
2731
|
+
atDocument() {
|
|
2732
|
+
const res = new Directives(this.yaml, this.tags);
|
|
2733
|
+
switch (this.yaml.version) {
|
|
2734
|
+
case "1.1":
|
|
2735
|
+
this.atNextDocument = true;
|
|
2736
|
+
break;
|
|
2737
|
+
case "1.2":
|
|
2738
|
+
this.atNextDocument = false;
|
|
2739
|
+
this.yaml = {
|
|
2740
|
+
explicit: Directives.defaultYaml.explicit,
|
|
2741
|
+
version: "1.2"
|
|
2742
|
+
};
|
|
2743
|
+
this.tags = Object.assign({}, Directives.defaultTags);
|
|
2744
|
+
break;
|
|
2745
|
+
}
|
|
2746
|
+
return res;
|
|
2747
|
+
}
|
|
2748
|
+
/**
|
|
2749
|
+
* @param onError - May be called even if the action was successful
|
|
2750
|
+
* @returns `true` on success
|
|
2751
|
+
*/
|
|
2752
|
+
add(line, onError) {
|
|
2753
|
+
if (this.atNextDocument) {
|
|
2754
|
+
this.yaml = {
|
|
2755
|
+
explicit: Directives.defaultYaml.explicit,
|
|
2756
|
+
version: "1.1"
|
|
2757
|
+
};
|
|
2758
|
+
this.tags = Object.assign({}, Directives.defaultTags);
|
|
2759
|
+
this.atNextDocument = false;
|
|
2760
|
+
}
|
|
2761
|
+
const parts = line.trim().split(/[ \t]+/);
|
|
2762
|
+
const name = parts.shift();
|
|
2763
|
+
switch (name) {
|
|
2764
|
+
case "%TAG": {
|
|
2765
|
+
if (parts.length !== 2) {
|
|
2766
|
+
onError(0, "%TAG directive should contain exactly two parts");
|
|
2767
|
+
if (parts.length < 2) return false;
|
|
2768
|
+
}
|
|
2769
|
+
const [handle, prefix] = parts;
|
|
2770
|
+
this.tags[handle] = prefix;
|
|
2771
|
+
return true;
|
|
2772
|
+
}
|
|
2773
|
+
case "%YAML": {
|
|
2774
|
+
this.yaml.explicit = true;
|
|
2775
|
+
if (parts.length !== 1) {
|
|
2776
|
+
onError(0, "%YAML directive should contain exactly one part");
|
|
2777
|
+
return false;
|
|
2778
|
+
}
|
|
2779
|
+
const [version] = parts;
|
|
2780
|
+
if (version === "1.1" || version === "1.2") {
|
|
2781
|
+
this.yaml.version = version;
|
|
2782
|
+
return true;
|
|
2783
|
+
} else {
|
|
2784
|
+
const isValid = /^\d+\.\d+$/.test(version);
|
|
2785
|
+
onError(6, `Unsupported YAML version ${version}`, isValid);
|
|
2786
|
+
return false;
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
default:
|
|
2790
|
+
onError(0, `Unknown directive ${name}`, true);
|
|
2791
|
+
return false;
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2794
|
+
/**
|
|
2795
|
+
* Resolves a tag, matching handles to those defined in %TAG directives.
|
|
2796
|
+
*
|
|
2797
|
+
* @returns Resolved tag, which may also be the non-specific tag `'!'` or a
|
|
2798
|
+
* `'!local'` tag, or `null` if unresolvable.
|
|
2799
|
+
*/
|
|
2800
|
+
tagName(source, onError) {
|
|
2801
|
+
if (source === "!") return "!";
|
|
2802
|
+
if (source[0] !== "!") {
|
|
2803
|
+
onError(`Not a valid tag: ${source}`);
|
|
2804
|
+
return null;
|
|
2805
|
+
}
|
|
2806
|
+
if (source[1] === "<") {
|
|
2807
|
+
const verbatim = source.slice(2, -1);
|
|
2808
|
+
if (verbatim === "!" || verbatim === "!!") {
|
|
2809
|
+
onError(`Verbatim tags aren't resolved, so ${source} is invalid.`);
|
|
2810
|
+
return null;
|
|
2811
|
+
}
|
|
2812
|
+
if (source[source.length - 1] !== ">") onError("Verbatim tags must end with a >");
|
|
2813
|
+
return verbatim;
|
|
2814
|
+
}
|
|
2815
|
+
const [, handle, suffix] = source.match(/^(.*!)([^!]*)$/s);
|
|
2816
|
+
if (!suffix) onError(`The ${source} tag has no suffix`);
|
|
2817
|
+
const prefix = this.tags[handle];
|
|
2818
|
+
if (prefix) try {
|
|
2819
|
+
return prefix + decodeURIComponent(suffix);
|
|
2820
|
+
} catch (error) {
|
|
2821
|
+
onError(String(error));
|
|
2822
|
+
return null;
|
|
2823
|
+
}
|
|
2824
|
+
if (handle === "!") return source;
|
|
2825
|
+
onError(`Could not resolve tag: ${source}`);
|
|
2826
|
+
return null;
|
|
2827
|
+
}
|
|
2828
|
+
/**
|
|
2829
|
+
* Given a fully resolved tag, returns its printable string form,
|
|
2830
|
+
* taking into account current tag prefixes and defaults.
|
|
2831
|
+
*/
|
|
2832
|
+
tagString(tag) {
|
|
2833
|
+
for (const [handle, prefix] of Object.entries(this.tags)) if (tag.startsWith(prefix)) return handle + escapeTagName(tag.substring(prefix.length));
|
|
2834
|
+
return tag[0] === "!" ? tag : `!<${tag}>`;
|
|
2835
|
+
}
|
|
2836
|
+
toString(doc) {
|
|
2837
|
+
const lines = this.yaml.explicit ? [`%YAML ${this.yaml.version || "1.2"}`] : [];
|
|
2838
|
+
const tagEntries = Object.entries(this.tags);
|
|
2839
|
+
let tagNames;
|
|
2840
|
+
if (doc && tagEntries.length > 0) {
|
|
2841
|
+
const tags = {};
|
|
2842
|
+
visit(doc.value, (_key, node) => {
|
|
2843
|
+
if (node instanceof NodeBase && node.tag) tags[node.tag] = true;
|
|
2844
|
+
});
|
|
2845
|
+
tagNames = Object.keys(tags);
|
|
2846
|
+
} else tagNames = [];
|
|
2847
|
+
for (const [handle, prefix] of tagEntries) {
|
|
2848
|
+
if (handle === "!!" && prefix === "tag:yaml.org,2002:") continue;
|
|
2849
|
+
if (!doc || tagNames.some((tn) => tn.startsWith(prefix))) lines.push(`%TAG ${handle} ${prefix}`);
|
|
2850
|
+
}
|
|
2851
|
+
return lines.join("\n");
|
|
2852
|
+
}
|
|
2853
|
+
};
|
|
2854
|
+
|
|
2855
|
+
//#endregion
|
|
2856
|
+
export { toJS as S, Collection as _, Schema as a, Scalar as b, seq as c, findPair as d, Alias as f, YAMLSeq as g, warn as h, Document as i, map as l, debug as m, visit as n, stringifyNumber as o, Pair as p, visitAsync as r, string as s, Directives as t, YAMLMap as u, stringifyString as v, NodeBase as x, foldFlowLines as y };
|