import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; import _classCallCheck from "@babel/runtime/helpers/classCallCheck"; import _createClass from "@babel/runtime/helpers/createClass"; import { Char, Type } from '../constants'; import { getLinePos } from './source-utils'; import { Range } from './Range'; /** Root class of all nodes */ export var Node = /*#__PURE__*/function () { _createClass(Node, null, [{ key: "addStringTerminator", value: function addStringTerminator(src, offset, str) { if (str[str.length - 1] === '\n') return str; var next = Node.endOfWhiteSpace(src, offset); return next >= src.length || src[next] === '\n' ? str + '\n' : str; } // ^(---|...) }, { key: "atDocumentBoundary", value: function atDocumentBoundary(src, offset, sep) { var ch0 = src[offset]; if (!ch0) return true; var prev = src[offset - 1]; if (prev && prev !== '\n') return false; if (sep) { if (ch0 !== sep) return false; } else { if (ch0 !== Char.DIRECTIVES_END && ch0 !== Char.DOCUMENT_END) return false; } var ch1 = src[offset + 1]; var ch2 = src[offset + 2]; if (ch1 !== ch0 || ch2 !== ch0) return false; var ch3 = src[offset + 3]; return !ch3 || ch3 === '\n' || ch3 === '\t' || ch3 === ' '; } }, { key: "endOfIdentifier", value: function endOfIdentifier(src, offset) { var ch = src[offset]; var isVerbatim = ch === '<'; var notOk = isVerbatim ? ['\n', '\t', ' ', '>'] : ['\n', '\t', ' ', '[', ']', '{', '}', ',']; while (ch && notOk.indexOf(ch) === -1) { ch = src[offset += 1]; } if (isVerbatim && ch === '>') offset += 1; return offset; } }, { key: "endOfIndent", value: function endOfIndent(src, offset) { var ch = src[offset]; while (ch === ' ') { ch = src[offset += 1]; } return offset; } }, { key: "endOfLine", value: function endOfLine(src, offset) { var ch = src[offset]; while (ch && ch !== '\n') { ch = src[offset += 1]; } return offset; } }, { key: "endOfWhiteSpace", value: function endOfWhiteSpace(src, offset) { var ch = src[offset]; while (ch === '\t' || ch === ' ') { ch = src[offset += 1]; } return offset; } }, { key: "startOfLine", value: function startOfLine(src, offset) { var ch = src[offset - 1]; if (ch === '\n') return offset; while (ch && ch !== '\n') { ch = src[offset -= 1]; } return offset + 1; } /** * End of indentation, or null if the line's indent level is not more * than `indent` * * @param {string} src * @param {number} indent * @param {number} lineStart * @returns {?number} */ }, { key: "endOfBlockIndent", value: function endOfBlockIndent(src, indent, lineStart) { var inEnd = Node.endOfIndent(src, lineStart); if (inEnd > lineStart + indent) { return inEnd; } else { var wsEnd = Node.endOfWhiteSpace(src, inEnd); var ch = src[wsEnd]; if (!ch || ch === '\n') return wsEnd; } return null; } }, { key: "atBlank", value: function atBlank(src, offset, endAsBlank) { var ch = src[offset]; return ch === '\n' || ch === '\t' || ch === ' ' || endAsBlank && !ch; } }, { key: "nextNodeIsIndented", value: function nextNodeIsIndented(ch, indentDiff, indicatorAsIndent) { if (!ch || indentDiff < 0) return false; if (indentDiff > 0) return true; return indicatorAsIndent && ch === '-'; } // should be at line or string end, or at next non-whitespace char }, { key: "normalizeOffset", value: function normalizeOffset(src, offset) { var ch = src[offset]; return !ch ? offset : ch !== '\n' && src[offset - 1] === '\n' ? offset - 1 : Node.endOfWhiteSpace(src, offset); } // fold single newline into space, multiple newlines to N - 1 newlines // presumes src[offset] === '\n' }, { key: "foldNewline", value: function foldNewline(src, offset, indent) { var inCount = 0; var error = false; var fold = ''; var ch = src[offset + 1]; while (ch === ' ' || ch === '\t' || ch === '\n') { switch (ch) { case '\n': inCount = 0; offset += 1; fold += '\n'; break; case '\t': if (inCount <= indent) error = true; offset = Node.endOfWhiteSpace(src, offset + 2) - 1; break; case ' ': inCount += 1; offset += 1; break; } ch = src[offset + 1]; } if (!fold) fold = ' '; if (ch && inCount <= indent) error = true; return { fold: fold, offset: offset, error: error }; } }]); function Node(type, props, context) { _classCallCheck(this, Node); Object.defineProperty(this, 'context', { value: context || null, writable: true }); this.error = null; this.range = null; this.valueRange = null; this.props = props || []; this.type = type; this.value = null; } _createClass(Node, [{ key: "getPropValue", value: function getPropValue(idx, key, skipKey) { if (!this.context) return null; var src = this.context.src; var prop = this.props[idx]; return prop && src[prop.start] === key ? src.slice(prop.start + (skipKey ? 1 : 0), prop.end) : null; } }, { key: "commentHasRequiredWhitespace", value: function commentHasRequiredWhitespace(start) { var src = this.context.src; if (this.header && start === this.header.end) return false; if (!this.valueRange) return false; var end = this.valueRange.end; return start !== end || Node.atBlank(src, end - 1); } }, { key: "parseComment", value: function parseComment(start) { var src = this.context.src; if (src[start] === Char.COMMENT) { var end = Node.endOfLine(src, start + 1); var commentRange = new Range(start, end); this.props.push(commentRange); return end; } return start; } /** * Populates the `origStart` and `origEnd` values of all ranges for this * node. Extended by child classes to handle descendant nodes. * * @param {number[]} cr - Positions of dropped CR characters * @param {number} offset - Starting index of `cr` from the last call * @returns {number} - The next offset, matching the one found for `origStart` */ }, { key: "setOrigRanges", value: function setOrigRanges(cr, offset) { if (this.range) offset = this.range.setOrigRange(cr, offset); if (this.valueRange) this.valueRange.setOrigRange(cr, offset); this.props.forEach(function (prop) { return prop.setOrigRange(cr, offset); }); return offset; } }, { key: "toString", value: function toString() { var src = this.context.src, range = this.range, value = this.value; if (value != null) return value; var str = src.slice(range.start, range.end); return Node.addStringTerminator(src, range.end, str); } }, { key: "anchor", get: function get() { for (var i = 0; i < this.props.length; ++i) { var anchor = this.getPropValue(i, Char.ANCHOR, true); if (anchor != null) return anchor; } return null; } }, { key: "comment", get: function get() { var comments = []; for (var i = 0; i < this.props.length; ++i) { var comment = this.getPropValue(i, Char.COMMENT, true); if (comment != null) comments.push(comment); } return comments.length > 0 ? comments.join('\n') : null; } }, { key: "hasComment", get: function get() { if (this.context) { var src = this.context.src; for (var i = 0; i < this.props.length; ++i) { if (src[this.props[i].start] === Char.COMMENT) return true; } } return false; } }, { key: "hasProps", get: function get() { if (this.context) { var src = this.context.src; for (var i = 0; i < this.props.length; ++i) { if (src[this.props[i].start] !== Char.COMMENT) return true; } } return false; } }, { key: "includesTrailingLines", get: function get() { return false; } }, { key: "jsonLike", get: function get() { var jsonLikeTypes = [Type.FLOW_MAP, Type.FLOW_SEQ, Type.QUOTE_DOUBLE, Type.QUOTE_SINGLE]; return jsonLikeTypes.indexOf(this.type) !== -1; } }, { key: "rangeAsLinePos", get: function get() { if (!this.range || !this.context) return undefined; var start = getLinePos(this.range.start, this.context.root); if (!start) return undefined; var end = getLinePos(this.range.end, this.context.root); return { start: start, end: end }; } }, { key: "rawValue", get: function get() { if (!this.valueRange || !this.context) return null; var _this$valueRange = this.valueRange, start = _this$valueRange.start, end = _this$valueRange.end; return this.context.src.slice(start, end); } }, { key: "tag", get: function get() { for (var i = 0; i < this.props.length; ++i) { var tag = this.getPropValue(i, Char.TAG, false); if (tag != null) { if (tag[1] === '<') { return { verbatim: tag.slice(2, -1) }; } else { // eslint-disable-next-line no-unused-vars var _tag$match = tag.match(/^(.*!)([^!]*)$/), _tag$match2 = _slicedToArray(_tag$match, 3), _ = _tag$match2[0], handle = _tag$match2[1], suffix = _tag$match2[2]; return { handle: handle, suffix: suffix }; } } } return null; } }, { key: "valueRangeContainsNewline", get: function get() { if (!this.valueRange || !this.context) return false; var _this$valueRange2 = this.valueRange, start = _this$valueRange2.start, end = _this$valueRange2.end; var src = this.context.src; for (var i = start; i < end; ++i) { if (src[i] === '\n') return true; } return false; } }]); return Node; }();