272 lines
8.7 KiB
JavaScript
272 lines
8.7 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.default = void 0;
|
|
|
|
var _constants = require("../constants");
|
|
|
|
var _errors = require("../errors");
|
|
|
|
var _Alias = _interopRequireDefault(require("./Alias"));
|
|
|
|
var _BlockValue = _interopRequireDefault(require("./BlockValue"));
|
|
|
|
var _Collection = _interopRequireDefault(require("./Collection"));
|
|
|
|
var _CollectionItem = _interopRequireDefault(require("./CollectionItem"));
|
|
|
|
var _FlowCollection = _interopRequireDefault(require("./FlowCollection"));
|
|
|
|
var _Node = _interopRequireDefault(require("./Node"));
|
|
|
|
var _PlainValue = _interopRequireDefault(require("./PlainValue"));
|
|
|
|
var _QuoteDouble = _interopRequireDefault(require("./QuoteDouble"));
|
|
|
|
var _QuoteSingle = _interopRequireDefault(require("./QuoteSingle"));
|
|
|
|
var _Range = _interopRequireDefault(require("./Range"));
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
|
|
/**
|
|
* @param {boolean} atLineStart - Node starts at beginning of line
|
|
* @param {boolean} inFlow - true if currently in a flow context
|
|
* @param {boolean} inCollection - true if currently in a collection context
|
|
* @param {number} indent - Current level of indentation
|
|
* @param {number} lineStart - Start of the current line
|
|
* @param {Node} parent - The parent of the node
|
|
* @param {string} src - Source of the YAML document
|
|
*/
|
|
class ParseContext {
|
|
static parseType(src, offset, inFlow) {
|
|
switch (src[offset]) {
|
|
case '*':
|
|
return _constants.Type.ALIAS;
|
|
|
|
case '>':
|
|
return _constants.Type.BLOCK_FOLDED;
|
|
|
|
case '|':
|
|
return _constants.Type.BLOCK_LITERAL;
|
|
|
|
case '{':
|
|
return _constants.Type.FLOW_MAP;
|
|
|
|
case '[':
|
|
return _constants.Type.FLOW_SEQ;
|
|
|
|
case '?':
|
|
return !inFlow && _Node.default.atBlank(src, offset + 1, true) ? _constants.Type.MAP_KEY : _constants.Type.PLAIN;
|
|
|
|
case ':':
|
|
return !inFlow && _Node.default.atBlank(src, offset + 1, true) ? _constants.Type.MAP_VALUE : _constants.Type.PLAIN;
|
|
|
|
case '-':
|
|
return !inFlow && _Node.default.atBlank(src, offset + 1, true) ? _constants.Type.SEQ_ITEM : _constants.Type.PLAIN;
|
|
|
|
case '"':
|
|
return _constants.Type.QUOTE_DOUBLE;
|
|
|
|
case "'":
|
|
return _constants.Type.QUOTE_SINGLE;
|
|
|
|
default:
|
|
return _constants.Type.PLAIN;
|
|
}
|
|
}
|
|
|
|
constructor(orig = {}, {
|
|
atLineStart,
|
|
inCollection,
|
|
inFlow,
|
|
indent,
|
|
lineStart,
|
|
parent
|
|
} = {}) {
|
|
_defineProperty(this, "parseNode", (overlay, start) => {
|
|
if (_Node.default.atDocumentBoundary(this.src, start)) return null;
|
|
const context = new ParseContext(this, overlay);
|
|
const {
|
|
props,
|
|
type,
|
|
valueStart
|
|
} = context.parseProps(start);
|
|
let node;
|
|
|
|
switch (type) {
|
|
case _constants.Type.ALIAS:
|
|
node = new _Alias.default(type, props);
|
|
break;
|
|
|
|
case _constants.Type.BLOCK_FOLDED:
|
|
case _constants.Type.BLOCK_LITERAL:
|
|
node = new _BlockValue.default(type, props);
|
|
break;
|
|
|
|
case _constants.Type.FLOW_MAP:
|
|
case _constants.Type.FLOW_SEQ:
|
|
node = new _FlowCollection.default(type, props);
|
|
break;
|
|
|
|
case _constants.Type.MAP_KEY:
|
|
case _constants.Type.MAP_VALUE:
|
|
case _constants.Type.SEQ_ITEM:
|
|
node = new _CollectionItem.default(type, props);
|
|
break;
|
|
|
|
case _constants.Type.COMMENT:
|
|
case _constants.Type.PLAIN:
|
|
node = new _PlainValue.default(type, props);
|
|
break;
|
|
|
|
case _constants.Type.QUOTE_DOUBLE:
|
|
node = new _QuoteDouble.default(type, props);
|
|
break;
|
|
|
|
case _constants.Type.QUOTE_SINGLE:
|
|
node = new _QuoteSingle.default(type, props);
|
|
break;
|
|
|
|
default:
|
|
node.error = new _errors.YAMLSyntaxError(node, `Unknown node type: ${JSON.stringify(type)}`);
|
|
node.range = new _Range.default(start, start + 1);
|
|
return node;
|
|
}
|
|
|
|
let offset = node.parse(context, valueStart);
|
|
node.range = new _Range.default(start, offset);
|
|
|
|
if (offset <= start) {
|
|
node.error = new Error(`Node#parse consumed no characters`);
|
|
node.error.parseEnd = offset;
|
|
node.error.source = node;
|
|
node.range.end = start + 1;
|
|
}
|
|
|
|
if (context.nodeStartsCollection(node)) {
|
|
if (!node.error && !context.atLineStart && context.parent.type === _constants.Type.DOCUMENT) {
|
|
node.error = new _errors.YAMLSyntaxError(node, 'Block collection must not have preceding content here (e.g. directives-end indicator)');
|
|
}
|
|
|
|
const collection = new _Collection.default(node);
|
|
offset = collection.parse(new ParseContext(context), offset);
|
|
collection.range = new _Range.default(start, offset);
|
|
return collection;
|
|
}
|
|
|
|
return node;
|
|
});
|
|
|
|
this.atLineStart = atLineStart != null ? atLineStart : orig.atLineStart || false;
|
|
this.inCollection = inCollection != null ? inCollection : orig.inCollection || false;
|
|
this.inFlow = inFlow != null ? inFlow : orig.inFlow || false;
|
|
this.indent = indent != null ? indent : orig.indent;
|
|
this.lineStart = lineStart != null ? lineStart : orig.lineStart;
|
|
this.parent = parent != null ? parent : orig.parent || {};
|
|
this.root = orig.root;
|
|
this.src = orig.src;
|
|
} // for logging
|
|
|
|
|
|
get pretty() {
|
|
const obj = {
|
|
start: `${this.lineStart} + ${this.indent}`,
|
|
in: [],
|
|
parent: this.parent.type
|
|
};
|
|
if (!this.atLineStart) obj.start += ' + N';
|
|
if (this.inCollection) obj.in.push('collection');
|
|
if (this.inFlow) obj.in.push('flow');
|
|
return obj;
|
|
}
|
|
|
|
nodeStartsCollection(node) {
|
|
const {
|
|
inCollection,
|
|
inFlow,
|
|
src
|
|
} = this;
|
|
if (inCollection || inFlow) return false;
|
|
if (node instanceof _CollectionItem.default) return true; // check for implicit key
|
|
|
|
let offset = node.range.end;
|
|
if (src[offset] === '\n' || src[offset - 1] === '\n') return false;
|
|
offset = _Node.default.endOfWhiteSpace(src, offset);
|
|
return src[offset] === ':';
|
|
} // Anchor and tag are before type, which determines the node implementation
|
|
// class; hence this intermediate step.
|
|
|
|
|
|
parseProps(offset) {
|
|
const {
|
|
inFlow,
|
|
parent,
|
|
src
|
|
} = this;
|
|
const props = [];
|
|
let lineHasProps = false;
|
|
offset = _Node.default.endOfWhiteSpace(src, offset);
|
|
let ch = src[offset];
|
|
|
|
while (ch === _constants.Char.ANCHOR || ch === _constants.Char.COMMENT || ch === _constants.Char.TAG || ch === '\n') {
|
|
if (ch === '\n') {
|
|
const lineStart = offset + 1;
|
|
|
|
const inEnd = _Node.default.endOfIndent(src, lineStart);
|
|
|
|
const indentDiff = inEnd - (lineStart + this.indent);
|
|
const noIndicatorAsIndent = parent.type === _constants.Type.SEQ_ITEM && parent.context.atLineStart;
|
|
if (!_Node.default.nextNodeIsIndented(src[inEnd], indentDiff, !noIndicatorAsIndent)) break;
|
|
this.atLineStart = true;
|
|
this.lineStart = lineStart;
|
|
lineHasProps = false;
|
|
offset = inEnd;
|
|
} else if (ch === _constants.Char.COMMENT) {
|
|
const end = _Node.default.endOfLine(src, offset + 1);
|
|
|
|
props.push(new _Range.default(offset, end));
|
|
offset = end;
|
|
} else {
|
|
let end = _Node.default.endOfIdentifier(src, offset + 1);
|
|
|
|
if (ch === _constants.Char.TAG && src[end] === ',' && /^[a-zA-Z0-9-]+\.[a-zA-Z0-9-]+,\d\d\d\d(-\d\d){0,2}\/\S/.test(src.slice(offset + 1, end + 13))) {
|
|
// Let's presume we're dealing with a YAML 1.0 domain tag here, rather
|
|
// than an empty but 'foo.bar' private-tagged node in a flow collection
|
|
// followed without whitespace by a plain string starting with a year
|
|
// or date divided by something.
|
|
end = _Node.default.endOfIdentifier(src, end + 5);
|
|
}
|
|
|
|
props.push(new _Range.default(offset, end));
|
|
lineHasProps = true;
|
|
offset = _Node.default.endOfWhiteSpace(src, end);
|
|
}
|
|
|
|
ch = src[offset];
|
|
} // '- &a : b' has an anchor on an empty node
|
|
|
|
|
|
if (lineHasProps && ch === ':' && _Node.default.atBlank(src, offset + 1, true)) offset -= 1;
|
|
const type = ParseContext.parseType(src, offset, inFlow);
|
|
return {
|
|
props,
|
|
type,
|
|
valueStart: offset
|
|
};
|
|
}
|
|
/**
|
|
* Parses a node from the source
|
|
* @param {ParseContext} overlay
|
|
* @param {number} start - Index of first non-whitespace character for the node
|
|
* @returns {?Node} - null if at a document boundary
|
|
*/
|
|
|
|
|
|
}
|
|
|
|
exports.default = ParseContext; |