| [9af201e] | 1 | 'use strict';
|
|---|
| 2 |
|
|---|
| 3 | var PlainValue = require('./PlainValue-516d5bc2.js');
|
|---|
| 4 | var resolveSeq = require('./resolveSeq-95613e94.js');
|
|---|
| 5 | var Schema = require('./Schema-bcc6c2d7.js');
|
|---|
| 6 |
|
|---|
| 7 | const defaultOptions = {
|
|---|
| 8 | anchorPrefix: 'a',
|
|---|
| 9 | customTags: null,
|
|---|
| 10 | indent: 2,
|
|---|
| 11 | indentSeq: true,
|
|---|
| 12 | keepCstNodes: false,
|
|---|
| 13 | keepNodeTypes: true,
|
|---|
| 14 | keepBlobsInJSON: true,
|
|---|
| 15 | mapAsMap: false,
|
|---|
| 16 | maxAliasCount: 100,
|
|---|
| 17 | prettyErrors: false,
|
|---|
| 18 | // TODO Set true in v2
|
|---|
| 19 | simpleKeys: false,
|
|---|
| 20 | version: '1.2'
|
|---|
| 21 | };
|
|---|
| 22 | const scalarOptions = {
|
|---|
| 23 | get binary() {
|
|---|
| 24 | return resolveSeq.binaryOptions;
|
|---|
| 25 | },
|
|---|
| 26 | set binary(opt) {
|
|---|
| 27 | Object.assign(resolveSeq.binaryOptions, opt);
|
|---|
| 28 | },
|
|---|
| 29 | get bool() {
|
|---|
| 30 | return resolveSeq.boolOptions;
|
|---|
| 31 | },
|
|---|
| 32 | set bool(opt) {
|
|---|
| 33 | Object.assign(resolveSeq.boolOptions, opt);
|
|---|
| 34 | },
|
|---|
| 35 | get int() {
|
|---|
| 36 | return resolveSeq.intOptions;
|
|---|
| 37 | },
|
|---|
| 38 | set int(opt) {
|
|---|
| 39 | Object.assign(resolveSeq.intOptions, opt);
|
|---|
| 40 | },
|
|---|
| 41 | get null() {
|
|---|
| 42 | return resolveSeq.nullOptions;
|
|---|
| 43 | },
|
|---|
| 44 | set null(opt) {
|
|---|
| 45 | Object.assign(resolveSeq.nullOptions, opt);
|
|---|
| 46 | },
|
|---|
| 47 | get str() {
|
|---|
| 48 | return resolveSeq.strOptions;
|
|---|
| 49 | },
|
|---|
| 50 | set str(opt) {
|
|---|
| 51 | Object.assign(resolveSeq.strOptions, opt);
|
|---|
| 52 | }
|
|---|
| 53 | };
|
|---|
| 54 | const documentOptions = {
|
|---|
| 55 | '1.0': {
|
|---|
| 56 | schema: 'yaml-1.1',
|
|---|
| 57 | merge: true,
|
|---|
| 58 | tagPrefixes: [{
|
|---|
| 59 | handle: '!',
|
|---|
| 60 | prefix: PlainValue.defaultTagPrefix
|
|---|
| 61 | }, {
|
|---|
| 62 | handle: '!!',
|
|---|
| 63 | prefix: 'tag:private.yaml.org,2002:'
|
|---|
| 64 | }]
|
|---|
| 65 | },
|
|---|
| 66 | 1.1: {
|
|---|
| 67 | schema: 'yaml-1.1',
|
|---|
| 68 | merge: true,
|
|---|
| 69 | tagPrefixes: [{
|
|---|
| 70 | handle: '!',
|
|---|
| 71 | prefix: '!'
|
|---|
| 72 | }, {
|
|---|
| 73 | handle: '!!',
|
|---|
| 74 | prefix: PlainValue.defaultTagPrefix
|
|---|
| 75 | }]
|
|---|
| 76 | },
|
|---|
| 77 | 1.2: {
|
|---|
| 78 | schema: 'core',
|
|---|
| 79 | merge: false,
|
|---|
| 80 | tagPrefixes: [{
|
|---|
| 81 | handle: '!',
|
|---|
| 82 | prefix: '!'
|
|---|
| 83 | }, {
|
|---|
| 84 | handle: '!!',
|
|---|
| 85 | prefix: PlainValue.defaultTagPrefix
|
|---|
| 86 | }]
|
|---|
| 87 | }
|
|---|
| 88 | };
|
|---|
| 89 |
|
|---|
| 90 | function stringifyTag(doc, tag) {
|
|---|
| 91 | if ((doc.version || doc.options.version) === '1.0') {
|
|---|
| 92 | const priv = tag.match(/^tag:private\.yaml\.org,2002:([^:/]+)$/);
|
|---|
| 93 | if (priv) return '!' + priv[1];
|
|---|
| 94 | const vocab = tag.match(/^tag:([a-zA-Z0-9-]+)\.yaml\.org,2002:(.*)/);
|
|---|
| 95 | return vocab ? `!${vocab[1]}/${vocab[2]}` : `!${tag.replace(/^tag:/, '')}`;
|
|---|
| 96 | }
|
|---|
| 97 | let p = doc.tagPrefixes.find(p => tag.indexOf(p.prefix) === 0);
|
|---|
| 98 | if (!p) {
|
|---|
| 99 | const dtp = doc.getDefaults().tagPrefixes;
|
|---|
| 100 | p = dtp && dtp.find(p => tag.indexOf(p.prefix) === 0);
|
|---|
| 101 | }
|
|---|
| 102 | if (!p) return tag[0] === '!' ? tag : `!<${tag}>`;
|
|---|
| 103 | const suffix = tag.substr(p.prefix.length).replace(/[!,[\]{}]/g, ch => ({
|
|---|
| 104 | '!': '%21',
|
|---|
| 105 | ',': '%2C',
|
|---|
| 106 | '[': '%5B',
|
|---|
| 107 | ']': '%5D',
|
|---|
| 108 | '{': '%7B',
|
|---|
| 109 | '}': '%7D'
|
|---|
| 110 | })[ch]);
|
|---|
| 111 | return p.handle + suffix;
|
|---|
| 112 | }
|
|---|
| 113 |
|
|---|
| 114 | function getTagObject(tags, item) {
|
|---|
| 115 | if (item instanceof resolveSeq.Alias) return resolveSeq.Alias;
|
|---|
| 116 | if (item.tag) {
|
|---|
| 117 | const match = tags.filter(t => t.tag === item.tag);
|
|---|
| 118 | if (match.length > 0) return match.find(t => t.format === item.format) || match[0];
|
|---|
| 119 | }
|
|---|
| 120 | let tagObj, obj;
|
|---|
| 121 | if (item instanceof resolveSeq.Scalar) {
|
|---|
| 122 | obj = item.value;
|
|---|
| 123 | // TODO: deprecate/remove class check
|
|---|
| 124 | const match = tags.filter(t => t.identify && t.identify(obj) || t.class && obj instanceof t.class);
|
|---|
| 125 | tagObj = match.find(t => t.format === item.format) || match.find(t => !t.format);
|
|---|
| 126 | } else {
|
|---|
| 127 | obj = item;
|
|---|
| 128 | tagObj = tags.find(t => t.nodeClass && obj instanceof t.nodeClass);
|
|---|
| 129 | }
|
|---|
| 130 | if (!tagObj) {
|
|---|
| 131 | const name = obj && obj.constructor ? obj.constructor.name : typeof obj;
|
|---|
| 132 | throw new Error(`Tag not resolved for ${name} value`);
|
|---|
| 133 | }
|
|---|
| 134 | return tagObj;
|
|---|
| 135 | }
|
|---|
| 136 |
|
|---|
| 137 | // needs to be called before value stringifier to allow for circular anchor refs
|
|---|
| 138 | function stringifyProps(node, tagObj, {
|
|---|
| 139 | anchors,
|
|---|
| 140 | doc
|
|---|
| 141 | }) {
|
|---|
| 142 | const props = [];
|
|---|
| 143 | const anchor = doc.anchors.getName(node);
|
|---|
| 144 | if (anchor) {
|
|---|
| 145 | anchors[anchor] = node;
|
|---|
| 146 | props.push(`&${anchor}`);
|
|---|
| 147 | }
|
|---|
| 148 | if (node.tag) {
|
|---|
| 149 | props.push(stringifyTag(doc, node.tag));
|
|---|
| 150 | } else if (!tagObj.default) {
|
|---|
| 151 | props.push(stringifyTag(doc, tagObj.tag));
|
|---|
| 152 | }
|
|---|
| 153 | return props.join(' ');
|
|---|
| 154 | }
|
|---|
| 155 | function stringify(item, ctx, onComment, onChompKeep) {
|
|---|
| 156 | const {
|
|---|
| 157 | anchors,
|
|---|
| 158 | schema
|
|---|
| 159 | } = ctx.doc;
|
|---|
| 160 | let tagObj;
|
|---|
| 161 | if (!(item instanceof resolveSeq.Node)) {
|
|---|
| 162 | const createCtx = {
|
|---|
| 163 | aliasNodes: [],
|
|---|
| 164 | onTagObj: o => tagObj = o,
|
|---|
| 165 | prevObjects: new Map()
|
|---|
| 166 | };
|
|---|
| 167 | item = schema.createNode(item, true, null, createCtx);
|
|---|
| 168 | for (const alias of createCtx.aliasNodes) {
|
|---|
| 169 | alias.source = alias.source.node;
|
|---|
| 170 | let name = anchors.getName(alias.source);
|
|---|
| 171 | if (!name) {
|
|---|
| 172 | name = anchors.newName();
|
|---|
| 173 | anchors.map[name] = alias.source;
|
|---|
| 174 | }
|
|---|
| 175 | }
|
|---|
| 176 | }
|
|---|
| 177 | if (item instanceof resolveSeq.Pair) return item.toString(ctx, onComment, onChompKeep);
|
|---|
| 178 | if (!tagObj) tagObj = getTagObject(schema.tags, item);
|
|---|
| 179 | const props = stringifyProps(item, tagObj, ctx);
|
|---|
| 180 | if (props.length > 0) ctx.indentAtStart = (ctx.indentAtStart || 0) + props.length + 1;
|
|---|
| 181 | const str = typeof tagObj.stringify === 'function' ? tagObj.stringify(item, ctx, onComment, onChompKeep) : item instanceof resolveSeq.Scalar ? resolveSeq.stringifyString(item, ctx, onComment, onChompKeep) : item.toString(ctx, onComment, onChompKeep);
|
|---|
| 182 | if (!props) return str;
|
|---|
| 183 | return item instanceof resolveSeq.Scalar || str[0] === '{' || str[0] === '[' ? `${props} ${str}` : `${props}\n${ctx.indent}${str}`;
|
|---|
| 184 | }
|
|---|
| 185 |
|
|---|
| 186 | class Anchors {
|
|---|
| 187 | static validAnchorNode(node) {
|
|---|
| 188 | return node instanceof resolveSeq.Scalar || node instanceof resolveSeq.YAMLSeq || node instanceof resolveSeq.YAMLMap;
|
|---|
| 189 | }
|
|---|
| 190 | constructor(prefix) {
|
|---|
| 191 | PlainValue._defineProperty(this, "map", Object.create(null));
|
|---|
| 192 | this.prefix = prefix;
|
|---|
| 193 | }
|
|---|
| 194 | createAlias(node, name) {
|
|---|
| 195 | this.setAnchor(node, name);
|
|---|
| 196 | return new resolveSeq.Alias(node);
|
|---|
| 197 | }
|
|---|
| 198 | createMergePair(...sources) {
|
|---|
| 199 | const merge = new resolveSeq.Merge();
|
|---|
| 200 | merge.value.items = sources.map(s => {
|
|---|
| 201 | if (s instanceof resolveSeq.Alias) {
|
|---|
| 202 | if (s.source instanceof resolveSeq.YAMLMap) return s;
|
|---|
| 203 | } else if (s instanceof resolveSeq.YAMLMap) {
|
|---|
| 204 | return this.createAlias(s);
|
|---|
| 205 | }
|
|---|
| 206 | throw new Error('Merge sources must be Map nodes or their Aliases');
|
|---|
| 207 | });
|
|---|
| 208 | return merge;
|
|---|
| 209 | }
|
|---|
| 210 | getName(node) {
|
|---|
| 211 | const {
|
|---|
| 212 | map
|
|---|
| 213 | } = this;
|
|---|
| 214 | return Object.keys(map).find(a => map[a] === node);
|
|---|
| 215 | }
|
|---|
| 216 | getNames() {
|
|---|
| 217 | return Object.keys(this.map);
|
|---|
| 218 | }
|
|---|
| 219 | getNode(name) {
|
|---|
| 220 | return this.map[name];
|
|---|
| 221 | }
|
|---|
| 222 | newName(prefix) {
|
|---|
| 223 | if (!prefix) prefix = this.prefix;
|
|---|
| 224 | const names = Object.keys(this.map);
|
|---|
| 225 | for (let i = 1; true; ++i) {
|
|---|
| 226 | const name = `${prefix}${i}`;
|
|---|
| 227 | if (!names.includes(name)) return name;
|
|---|
| 228 | }
|
|---|
| 229 | }
|
|---|
| 230 |
|
|---|
| 231 | // During parsing, map & aliases contain CST nodes
|
|---|
| 232 | resolveNodes() {
|
|---|
| 233 | const {
|
|---|
| 234 | map,
|
|---|
| 235 | _cstAliases
|
|---|
| 236 | } = this;
|
|---|
| 237 | Object.keys(map).forEach(a => {
|
|---|
| 238 | map[a] = map[a].resolved;
|
|---|
| 239 | });
|
|---|
| 240 | _cstAliases.forEach(a => {
|
|---|
| 241 | a.source = a.source.resolved;
|
|---|
| 242 | });
|
|---|
| 243 | delete this._cstAliases;
|
|---|
| 244 | }
|
|---|
| 245 | setAnchor(node, name) {
|
|---|
| 246 | if (node != null && !Anchors.validAnchorNode(node)) {
|
|---|
| 247 | throw new Error('Anchors may only be set for Scalar, Seq and Map nodes');
|
|---|
| 248 | }
|
|---|
| 249 | if (name && /[\x00-\x19\s,[\]{}]/.test(name)) {
|
|---|
| 250 | throw new Error('Anchor names must not contain whitespace or control characters');
|
|---|
| 251 | }
|
|---|
| 252 | const {
|
|---|
| 253 | map
|
|---|
| 254 | } = this;
|
|---|
| 255 | const prev = node && Object.keys(map).find(a => map[a] === node);
|
|---|
| 256 | if (prev) {
|
|---|
| 257 | if (!name) {
|
|---|
| 258 | return prev;
|
|---|
| 259 | } else if (prev !== name) {
|
|---|
| 260 | delete map[prev];
|
|---|
| 261 | map[name] = node;
|
|---|
| 262 | }
|
|---|
| 263 | } else {
|
|---|
| 264 | if (!name) {
|
|---|
| 265 | if (!node) return null;
|
|---|
| 266 | name = this.newName();
|
|---|
| 267 | }
|
|---|
| 268 | map[name] = node;
|
|---|
| 269 | }
|
|---|
| 270 | return name;
|
|---|
| 271 | }
|
|---|
| 272 | }
|
|---|
| 273 |
|
|---|
| 274 | const visit = (node, tags) => {
|
|---|
| 275 | if (node && typeof node === 'object') {
|
|---|
| 276 | const {
|
|---|
| 277 | tag
|
|---|
| 278 | } = node;
|
|---|
| 279 | if (node instanceof resolveSeq.Collection) {
|
|---|
| 280 | if (tag) tags[tag] = true;
|
|---|
| 281 | node.items.forEach(n => visit(n, tags));
|
|---|
| 282 | } else if (node instanceof resolveSeq.Pair) {
|
|---|
| 283 | visit(node.key, tags);
|
|---|
| 284 | visit(node.value, tags);
|
|---|
| 285 | } else if (node instanceof resolveSeq.Scalar) {
|
|---|
| 286 | if (tag) tags[tag] = true;
|
|---|
| 287 | }
|
|---|
| 288 | }
|
|---|
| 289 | return tags;
|
|---|
| 290 | };
|
|---|
| 291 | const listTagNames = node => Object.keys(visit(node, {}));
|
|---|
| 292 |
|
|---|
| 293 | function parseContents(doc, contents) {
|
|---|
| 294 | const comments = {
|
|---|
| 295 | before: [],
|
|---|
| 296 | after: []
|
|---|
| 297 | };
|
|---|
| 298 | let body = undefined;
|
|---|
| 299 | let spaceBefore = false;
|
|---|
| 300 | for (const node of contents) {
|
|---|
| 301 | if (node.valueRange) {
|
|---|
| 302 | if (body !== undefined) {
|
|---|
| 303 | const msg = 'Document contains trailing content not separated by a ... or --- line';
|
|---|
| 304 | doc.errors.push(new PlainValue.YAMLSyntaxError(node, msg));
|
|---|
| 305 | break;
|
|---|
| 306 | }
|
|---|
| 307 | const res = resolveSeq.resolveNode(doc, node);
|
|---|
| 308 | if (spaceBefore) {
|
|---|
| 309 | res.spaceBefore = true;
|
|---|
| 310 | spaceBefore = false;
|
|---|
| 311 | }
|
|---|
| 312 | body = res;
|
|---|
| 313 | } else if (node.comment !== null) {
|
|---|
| 314 | const cc = body === undefined ? comments.before : comments.after;
|
|---|
| 315 | cc.push(node.comment);
|
|---|
| 316 | } else if (node.type === PlainValue.Type.BLANK_LINE) {
|
|---|
| 317 | spaceBefore = true;
|
|---|
| 318 | if (body === undefined && comments.before.length > 0 && !doc.commentBefore) {
|
|---|
| 319 | // space-separated comments at start are parsed as document comments
|
|---|
| 320 | doc.commentBefore = comments.before.join('\n');
|
|---|
| 321 | comments.before = [];
|
|---|
| 322 | }
|
|---|
| 323 | }
|
|---|
| 324 | }
|
|---|
| 325 | doc.contents = body || null;
|
|---|
| 326 | if (!body) {
|
|---|
| 327 | doc.comment = comments.before.concat(comments.after).join('\n') || null;
|
|---|
| 328 | } else {
|
|---|
| 329 | const cb = comments.before.join('\n');
|
|---|
| 330 | if (cb) {
|
|---|
| 331 | const cbNode = body instanceof resolveSeq.Collection && body.items[0] ? body.items[0] : body;
|
|---|
| 332 | cbNode.commentBefore = cbNode.commentBefore ? `${cb}\n${cbNode.commentBefore}` : cb;
|
|---|
| 333 | }
|
|---|
| 334 | doc.comment = comments.after.join('\n') || null;
|
|---|
| 335 | }
|
|---|
| 336 | }
|
|---|
| 337 |
|
|---|
| 338 | function resolveTagDirective({
|
|---|
| 339 | tagPrefixes
|
|---|
| 340 | }, directive) {
|
|---|
| 341 | const [handle, prefix] = directive.parameters;
|
|---|
| 342 | if (!handle || !prefix) {
|
|---|
| 343 | const msg = 'Insufficient parameters given for %TAG directive';
|
|---|
| 344 | throw new PlainValue.YAMLSemanticError(directive, msg);
|
|---|
| 345 | }
|
|---|
| 346 | if (tagPrefixes.some(p => p.handle === handle)) {
|
|---|
| 347 | const msg = 'The %TAG directive must only be given at most once per handle in the same document.';
|
|---|
| 348 | throw new PlainValue.YAMLSemanticError(directive, msg);
|
|---|
| 349 | }
|
|---|
| 350 | return {
|
|---|
| 351 | handle,
|
|---|
| 352 | prefix
|
|---|
| 353 | };
|
|---|
| 354 | }
|
|---|
| 355 | function resolveYamlDirective(doc, directive) {
|
|---|
| 356 | let [version] = directive.parameters;
|
|---|
| 357 | if (directive.name === 'YAML:1.0') version = '1.0';
|
|---|
| 358 | if (!version) {
|
|---|
| 359 | const msg = 'Insufficient parameters given for %YAML directive';
|
|---|
| 360 | throw new PlainValue.YAMLSemanticError(directive, msg);
|
|---|
| 361 | }
|
|---|
| 362 | if (!documentOptions[version]) {
|
|---|
| 363 | const v0 = doc.version || doc.options.version;
|
|---|
| 364 | const msg = `Document will be parsed as YAML ${v0} rather than YAML ${version}`;
|
|---|
| 365 | doc.warnings.push(new PlainValue.YAMLWarning(directive, msg));
|
|---|
| 366 | }
|
|---|
| 367 | return version;
|
|---|
| 368 | }
|
|---|
| 369 | function parseDirectives(doc, directives, prevDoc) {
|
|---|
| 370 | const directiveComments = [];
|
|---|
| 371 | let hasDirectives = false;
|
|---|
| 372 | for (const directive of directives) {
|
|---|
| 373 | const {
|
|---|
| 374 | comment,
|
|---|
| 375 | name
|
|---|
| 376 | } = directive;
|
|---|
| 377 | switch (name) {
|
|---|
| 378 | case 'TAG':
|
|---|
| 379 | try {
|
|---|
| 380 | doc.tagPrefixes.push(resolveTagDirective(doc, directive));
|
|---|
| 381 | } catch (error) {
|
|---|
| 382 | doc.errors.push(error);
|
|---|
| 383 | }
|
|---|
| 384 | hasDirectives = true;
|
|---|
| 385 | break;
|
|---|
| 386 | case 'YAML':
|
|---|
| 387 | case 'YAML:1.0':
|
|---|
| 388 | if (doc.version) {
|
|---|
| 389 | const msg = 'The %YAML directive must only be given at most once per document.';
|
|---|
| 390 | doc.errors.push(new PlainValue.YAMLSemanticError(directive, msg));
|
|---|
| 391 | }
|
|---|
| 392 | try {
|
|---|
| 393 | doc.version = resolveYamlDirective(doc, directive);
|
|---|
| 394 | } catch (error) {
|
|---|
| 395 | doc.errors.push(error);
|
|---|
| 396 | }
|
|---|
| 397 | hasDirectives = true;
|
|---|
| 398 | break;
|
|---|
| 399 | default:
|
|---|
| 400 | if (name) {
|
|---|
| 401 | const msg = `YAML only supports %TAG and %YAML directives, and not %${name}`;
|
|---|
| 402 | doc.warnings.push(new PlainValue.YAMLWarning(directive, msg));
|
|---|
| 403 | }
|
|---|
| 404 | }
|
|---|
| 405 | if (comment) directiveComments.push(comment);
|
|---|
| 406 | }
|
|---|
| 407 | if (prevDoc && !hasDirectives && '1.1' === (doc.version || prevDoc.version || doc.options.version)) {
|
|---|
| 408 | const copyTagPrefix = ({
|
|---|
| 409 | handle,
|
|---|
| 410 | prefix
|
|---|
| 411 | }) => ({
|
|---|
| 412 | handle,
|
|---|
| 413 | prefix
|
|---|
| 414 | });
|
|---|
| 415 | doc.tagPrefixes = prevDoc.tagPrefixes.map(copyTagPrefix);
|
|---|
| 416 | doc.version = prevDoc.version;
|
|---|
| 417 | }
|
|---|
| 418 | doc.commentBefore = directiveComments.join('\n') || null;
|
|---|
| 419 | }
|
|---|
| 420 |
|
|---|
| 421 | function assertCollection(contents) {
|
|---|
| 422 | if (contents instanceof resolveSeq.Collection) return true;
|
|---|
| 423 | throw new Error('Expected a YAML collection as document contents');
|
|---|
| 424 | }
|
|---|
| 425 | class Document {
|
|---|
| 426 | constructor(options) {
|
|---|
| 427 | this.anchors = new Anchors(options.anchorPrefix);
|
|---|
| 428 | this.commentBefore = null;
|
|---|
| 429 | this.comment = null;
|
|---|
| 430 | this.contents = null;
|
|---|
| 431 | this.directivesEndMarker = null;
|
|---|
| 432 | this.errors = [];
|
|---|
| 433 | this.options = options;
|
|---|
| 434 | this.schema = null;
|
|---|
| 435 | this.tagPrefixes = [];
|
|---|
| 436 | this.version = null;
|
|---|
| 437 | this.warnings = [];
|
|---|
| 438 | }
|
|---|
| 439 | add(value) {
|
|---|
| 440 | assertCollection(this.contents);
|
|---|
| 441 | return this.contents.add(value);
|
|---|
| 442 | }
|
|---|
| 443 | addIn(path, value) {
|
|---|
| 444 | assertCollection(this.contents);
|
|---|
| 445 | this.contents.addIn(path, value);
|
|---|
| 446 | }
|
|---|
| 447 | delete(key) {
|
|---|
| 448 | assertCollection(this.contents);
|
|---|
| 449 | return this.contents.delete(key);
|
|---|
| 450 | }
|
|---|
| 451 | deleteIn(path) {
|
|---|
| 452 | if (resolveSeq.isEmptyPath(path)) {
|
|---|
| 453 | if (this.contents == null) return false;
|
|---|
| 454 | this.contents = null;
|
|---|
| 455 | return true;
|
|---|
| 456 | }
|
|---|
| 457 | assertCollection(this.contents);
|
|---|
| 458 | return this.contents.deleteIn(path);
|
|---|
| 459 | }
|
|---|
| 460 | getDefaults() {
|
|---|
| 461 | return Document.defaults[this.version] || Document.defaults[this.options.version] || {};
|
|---|
| 462 | }
|
|---|
| 463 | get(key, keepScalar) {
|
|---|
| 464 | return this.contents instanceof resolveSeq.Collection ? this.contents.get(key, keepScalar) : undefined;
|
|---|
| 465 | }
|
|---|
| 466 | getIn(path, keepScalar) {
|
|---|
| 467 | if (resolveSeq.isEmptyPath(path)) return !keepScalar && this.contents instanceof resolveSeq.Scalar ? this.contents.value : this.contents;
|
|---|
| 468 | return this.contents instanceof resolveSeq.Collection ? this.contents.getIn(path, keepScalar) : undefined;
|
|---|
| 469 | }
|
|---|
| 470 | has(key) {
|
|---|
| 471 | return this.contents instanceof resolveSeq.Collection ? this.contents.has(key) : false;
|
|---|
| 472 | }
|
|---|
| 473 | hasIn(path) {
|
|---|
| 474 | if (resolveSeq.isEmptyPath(path)) return this.contents !== undefined;
|
|---|
| 475 | return this.contents instanceof resolveSeq.Collection ? this.contents.hasIn(path) : false;
|
|---|
| 476 | }
|
|---|
| 477 | set(key, value) {
|
|---|
| 478 | assertCollection(this.contents);
|
|---|
| 479 | this.contents.set(key, value);
|
|---|
| 480 | }
|
|---|
| 481 | setIn(path, value) {
|
|---|
| 482 | if (resolveSeq.isEmptyPath(path)) this.contents = value;else {
|
|---|
| 483 | assertCollection(this.contents);
|
|---|
| 484 | this.contents.setIn(path, value);
|
|---|
| 485 | }
|
|---|
| 486 | }
|
|---|
| 487 | setSchema(id, customTags) {
|
|---|
| 488 | if (!id && !customTags && this.schema) return;
|
|---|
| 489 | if (typeof id === 'number') id = id.toFixed(1);
|
|---|
| 490 | if (id === '1.0' || id === '1.1' || id === '1.2') {
|
|---|
| 491 | if (this.version) this.version = id;else this.options.version = id;
|
|---|
| 492 | delete this.options.schema;
|
|---|
| 493 | } else if (id && typeof id === 'string') {
|
|---|
| 494 | this.options.schema = id;
|
|---|
| 495 | }
|
|---|
| 496 | if (Array.isArray(customTags)) this.options.customTags = customTags;
|
|---|
| 497 | const opt = Object.assign({}, this.getDefaults(), this.options);
|
|---|
| 498 | this.schema = new Schema.Schema(opt);
|
|---|
| 499 | }
|
|---|
| 500 | parse(node, prevDoc) {
|
|---|
| 501 | if (this.options.keepCstNodes) this.cstNode = node;
|
|---|
| 502 | if (this.options.keepNodeTypes) this.type = 'DOCUMENT';
|
|---|
| 503 | const {
|
|---|
| 504 | directives = [],
|
|---|
| 505 | contents = [],
|
|---|
| 506 | directivesEndMarker,
|
|---|
| 507 | error,
|
|---|
| 508 | valueRange
|
|---|
| 509 | } = node;
|
|---|
| 510 | if (error) {
|
|---|
| 511 | if (!error.source) error.source = this;
|
|---|
| 512 | this.errors.push(error);
|
|---|
| 513 | }
|
|---|
| 514 | parseDirectives(this, directives, prevDoc);
|
|---|
| 515 | if (directivesEndMarker) this.directivesEndMarker = true;
|
|---|
| 516 | this.range = valueRange ? [valueRange.start, valueRange.end] : null;
|
|---|
| 517 | this.setSchema();
|
|---|
| 518 | this.anchors._cstAliases = [];
|
|---|
| 519 | parseContents(this, contents);
|
|---|
| 520 | this.anchors.resolveNodes();
|
|---|
| 521 | if (this.options.prettyErrors) {
|
|---|
| 522 | for (const error of this.errors) if (error instanceof PlainValue.YAMLError) error.makePretty();
|
|---|
| 523 | for (const warn of this.warnings) if (warn instanceof PlainValue.YAMLError) warn.makePretty();
|
|---|
| 524 | }
|
|---|
| 525 | return this;
|
|---|
| 526 | }
|
|---|
| 527 | listNonDefaultTags() {
|
|---|
| 528 | return listTagNames(this.contents).filter(t => t.indexOf(Schema.Schema.defaultPrefix) !== 0);
|
|---|
| 529 | }
|
|---|
| 530 | setTagPrefix(handle, prefix) {
|
|---|
| 531 | if (handle[0] !== '!' || handle[handle.length - 1] !== '!') throw new Error('Handle must start and end with !');
|
|---|
| 532 | if (prefix) {
|
|---|
| 533 | const prev = this.tagPrefixes.find(p => p.handle === handle);
|
|---|
| 534 | if (prev) prev.prefix = prefix;else this.tagPrefixes.push({
|
|---|
| 535 | handle,
|
|---|
| 536 | prefix
|
|---|
| 537 | });
|
|---|
| 538 | } else {
|
|---|
| 539 | this.tagPrefixes = this.tagPrefixes.filter(p => p.handle !== handle);
|
|---|
| 540 | }
|
|---|
| 541 | }
|
|---|
| 542 | toJSON(arg, onAnchor) {
|
|---|
| 543 | const {
|
|---|
| 544 | keepBlobsInJSON,
|
|---|
| 545 | mapAsMap,
|
|---|
| 546 | maxAliasCount
|
|---|
| 547 | } = this.options;
|
|---|
| 548 | const keep = keepBlobsInJSON && (typeof arg !== 'string' || !(this.contents instanceof resolveSeq.Scalar));
|
|---|
| 549 | const ctx = {
|
|---|
| 550 | doc: this,
|
|---|
| 551 | indentStep: ' ',
|
|---|
| 552 | keep,
|
|---|
| 553 | mapAsMap: keep && !!mapAsMap,
|
|---|
| 554 | maxAliasCount,
|
|---|
| 555 | stringify // Requiring directly in Pair would create circular dependencies
|
|---|
| 556 | };
|
|---|
| 557 | const anchorNames = Object.keys(this.anchors.map);
|
|---|
| 558 | if (anchorNames.length > 0) ctx.anchors = new Map(anchorNames.map(name => [this.anchors.map[name], {
|
|---|
| 559 | alias: [],
|
|---|
| 560 | aliasCount: 0,
|
|---|
| 561 | count: 1
|
|---|
| 562 | }]));
|
|---|
| 563 | const res = resolveSeq.toJSON(this.contents, arg, ctx);
|
|---|
| 564 | if (typeof onAnchor === 'function' && ctx.anchors) for (const {
|
|---|
| 565 | count,
|
|---|
| 566 | res
|
|---|
| 567 | } of ctx.anchors.values()) onAnchor(res, count);
|
|---|
| 568 | return res;
|
|---|
| 569 | }
|
|---|
| 570 | toString() {
|
|---|
| 571 | if (this.errors.length > 0) throw new Error('Document with errors cannot be stringified');
|
|---|
| 572 | const indentSize = this.options.indent;
|
|---|
| 573 | if (!Number.isInteger(indentSize) || indentSize <= 0) {
|
|---|
| 574 | const s = JSON.stringify(indentSize);
|
|---|
| 575 | throw new Error(`"indent" option must be a positive integer, not ${s}`);
|
|---|
| 576 | }
|
|---|
| 577 | this.setSchema();
|
|---|
| 578 | const lines = [];
|
|---|
| 579 | let hasDirectives = false;
|
|---|
| 580 | if (this.version) {
|
|---|
| 581 | let vd = '%YAML 1.2';
|
|---|
| 582 | if (this.schema.name === 'yaml-1.1') {
|
|---|
| 583 | if (this.version === '1.0') vd = '%YAML:1.0';else if (this.version === '1.1') vd = '%YAML 1.1';
|
|---|
| 584 | }
|
|---|
| 585 | lines.push(vd);
|
|---|
| 586 | hasDirectives = true;
|
|---|
| 587 | }
|
|---|
| 588 | const tagNames = this.listNonDefaultTags();
|
|---|
| 589 | this.tagPrefixes.forEach(({
|
|---|
| 590 | handle,
|
|---|
| 591 | prefix
|
|---|
| 592 | }) => {
|
|---|
| 593 | if (tagNames.some(t => t.indexOf(prefix) === 0)) {
|
|---|
| 594 | lines.push(`%TAG ${handle} ${prefix}`);
|
|---|
| 595 | hasDirectives = true;
|
|---|
| 596 | }
|
|---|
| 597 | });
|
|---|
| 598 | if (hasDirectives || this.directivesEndMarker) lines.push('---');
|
|---|
| 599 | if (this.commentBefore) {
|
|---|
| 600 | if (hasDirectives || !this.directivesEndMarker) lines.unshift('');
|
|---|
| 601 | lines.unshift(this.commentBefore.replace(/^/gm, '#'));
|
|---|
| 602 | }
|
|---|
| 603 | const ctx = {
|
|---|
| 604 | anchors: Object.create(null),
|
|---|
| 605 | doc: this,
|
|---|
| 606 | indent: '',
|
|---|
| 607 | indentStep: ' '.repeat(indentSize),
|
|---|
| 608 | stringify // Requiring directly in nodes would create circular dependencies
|
|---|
| 609 | };
|
|---|
| 610 | let chompKeep = false;
|
|---|
| 611 | let contentComment = null;
|
|---|
| 612 | if (this.contents) {
|
|---|
| 613 | if (this.contents instanceof resolveSeq.Node) {
|
|---|
| 614 | if (this.contents.spaceBefore && (hasDirectives || this.directivesEndMarker)) lines.push('');
|
|---|
| 615 | if (this.contents.commentBefore) lines.push(this.contents.commentBefore.replace(/^/gm, '#'));
|
|---|
| 616 | // top-level block scalars need to be indented if followed by a comment
|
|---|
| 617 | ctx.forceBlockIndent = !!this.comment;
|
|---|
| 618 | contentComment = this.contents.comment;
|
|---|
| 619 | }
|
|---|
| 620 | const onChompKeep = contentComment ? null : () => chompKeep = true;
|
|---|
| 621 | const body = stringify(this.contents, ctx, () => contentComment = null, onChompKeep);
|
|---|
| 622 | lines.push(resolveSeq.addComment(body, '', contentComment));
|
|---|
| 623 | } else if (this.contents !== undefined) {
|
|---|
| 624 | lines.push(stringify(this.contents, ctx));
|
|---|
| 625 | }
|
|---|
| 626 | if (this.comment) {
|
|---|
| 627 | if ((!chompKeep || contentComment) && lines[lines.length - 1] !== '') lines.push('');
|
|---|
| 628 | lines.push(this.comment.replace(/^/gm, '#'));
|
|---|
| 629 | }
|
|---|
| 630 | return lines.join('\n') + '\n';
|
|---|
| 631 | }
|
|---|
| 632 | }
|
|---|
| 633 | PlainValue._defineProperty(Document, "defaults", documentOptions);
|
|---|
| 634 |
|
|---|
| 635 | exports.Document = Document;
|
|---|
| 636 | exports.defaultOptions = defaultOptions;
|
|---|
| 637 | exports.scalarOptions = scalarOptions;
|
|---|