You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
876 lines
20 KiB
876 lines
20 KiB
'use strict'; |
|
|
|
const Char = { |
|
ANCHOR: '&', |
|
COMMENT: '#', |
|
TAG: '!', |
|
DIRECTIVES_END: '-', |
|
DOCUMENT_END: '.' |
|
}; |
|
const Type = { |
|
ALIAS: 'ALIAS', |
|
BLANK_LINE: 'BLANK_LINE', |
|
BLOCK_FOLDED: 'BLOCK_FOLDED', |
|
BLOCK_LITERAL: 'BLOCK_LITERAL', |
|
COMMENT: 'COMMENT', |
|
DIRECTIVE: 'DIRECTIVE', |
|
DOCUMENT: 'DOCUMENT', |
|
FLOW_MAP: 'FLOW_MAP', |
|
FLOW_SEQ: 'FLOW_SEQ', |
|
MAP: 'MAP', |
|
MAP_KEY: 'MAP_KEY', |
|
MAP_VALUE: 'MAP_VALUE', |
|
PLAIN: 'PLAIN', |
|
QUOTE_DOUBLE: 'QUOTE_DOUBLE', |
|
QUOTE_SINGLE: 'QUOTE_SINGLE', |
|
SEQ: 'SEQ', |
|
SEQ_ITEM: 'SEQ_ITEM' |
|
}; |
|
const defaultTagPrefix = 'tag:yaml.org,2002:'; |
|
const defaultTags = { |
|
MAP: 'tag:yaml.org,2002:map', |
|
SEQ: 'tag:yaml.org,2002:seq', |
|
STR: 'tag:yaml.org,2002:str' |
|
}; |
|
|
|
function findLineStarts(src) { |
|
const ls = [0]; |
|
let offset = src.indexOf('\n'); |
|
|
|
while (offset !== -1) { |
|
offset += 1; |
|
ls.push(offset); |
|
offset = src.indexOf('\n', offset); |
|
} |
|
|
|
return ls; |
|
} |
|
|
|
function getSrcInfo(cst) { |
|
let lineStarts, src; |
|
|
|
if (typeof cst === 'string') { |
|
lineStarts = findLineStarts(cst); |
|
src = cst; |
|
} else { |
|
if (Array.isArray(cst)) cst = cst[0]; |
|
|
|
if (cst && cst.context) { |
|
if (!cst.lineStarts) cst.lineStarts = findLineStarts(cst.context.src); |
|
lineStarts = cst.lineStarts; |
|
src = cst.context.src; |
|
} |
|
} |
|
|
|
return { |
|
lineStarts, |
|
src |
|
}; |
|
} |
|
/** |
|
* @typedef {Object} LinePos - One-indexed position in the source |
|
* @property {number} line |
|
* @property {number} col |
|
*/ |
|
|
|
/** |
|
* Determine the line/col position matching a character offset. |
|
* |
|
* Accepts a source string or a CST document as the second parameter. With |
|
* the latter, starting indices for lines are cached in the document as |
|
* `lineStarts: number[]`. |
|
* |
|
* Returns a one-indexed `{ line, col }` location if found, or |
|
* `undefined` otherwise. |
|
* |
|
* @param {number} offset |
|
* @param {string|Document|Document[]} cst |
|
* @returns {?LinePos} |
|
*/ |
|
|
|
|
|
function getLinePos(offset, cst) { |
|
if (typeof offset !== 'number' || offset < 0) return null; |
|
const { |
|
lineStarts, |
|
src |
|
} = getSrcInfo(cst); |
|
if (!lineStarts || !src || offset > src.length) return null; |
|
|
|
for (let i = 0; i < lineStarts.length; ++i) { |
|
const start = lineStarts[i]; |
|
|
|
if (offset < start) { |
|
return { |
|
line: i, |
|
col: offset - lineStarts[i - 1] + 1 |
|
}; |
|
} |
|
|
|
if (offset === start) return { |
|
line: i + 1, |
|
col: 1 |
|
}; |
|
} |
|
|
|
const line = lineStarts.length; |
|
return { |
|
line, |
|
col: offset - lineStarts[line - 1] + 1 |
|
}; |
|
} |
|
/** |
|
* Get a specified line from the source. |
|
* |
|
* Accepts a source string or a CST document as the second parameter. With |
|
* the latter, starting indices for lines are cached in the document as |
|
* `lineStarts: number[]`. |
|
* |
|
* Returns the line as a string if found, or `null` otherwise. |
|
* |
|
* @param {number} line One-indexed line number |
|
* @param {string|Document|Document[]} cst |
|
* @returns {?string} |
|
*/ |
|
|
|
function getLine(line, cst) { |
|
const { |
|
lineStarts, |
|
src |
|
} = getSrcInfo(cst); |
|
if (!lineStarts || !(line >= 1) || line > lineStarts.length) return null; |
|
const start = lineStarts[line - 1]; |
|
let end = lineStarts[line]; // undefined for last line; that's ok for slice() |
|
|
|
while (end && end > start && src[end - 1] === '\n') --end; |
|
|
|
return src.slice(start, end); |
|
} |
|
/** |
|
* Pretty-print the starting line from the source indicated by the range `pos` |
|
* |
|
* Trims output to `maxWidth` chars while keeping the starting column visible, |
|
* using `…` at either end to indicate dropped characters. |
|
* |
|
* Returns a two-line string (or `null`) with `\n` as separator; the second line |
|
* will hold appropriately indented `^` marks indicating the column range. |
|
* |
|
* @param {Object} pos |
|
* @param {LinePos} pos.start |
|
* @param {LinePos} [pos.end] |
|
* @param {string|Document|Document[]*} cst |
|
* @param {number} [maxWidth=80] |
|
* @returns {?string} |
|
*/ |
|
|
|
function getPrettyContext({ |
|
start, |
|
end |
|
}, cst, maxWidth = 80) { |
|
let src = getLine(start.line, cst); |
|
if (!src) return null; |
|
let { |
|
col |
|
} = start; |
|
|
|
if (src.length > maxWidth) { |
|
if (col <= maxWidth - 10) { |
|
src = src.substr(0, maxWidth - 1) + '…'; |
|
} else { |
|
const halfWidth = Math.round(maxWidth / 2); |
|
if (src.length > col + halfWidth) src = src.substr(0, col + halfWidth - 1) + '…'; |
|
col -= src.length - maxWidth; |
|
src = '…' + src.substr(1 - maxWidth); |
|
} |
|
} |
|
|
|
let errLen = 1; |
|
let errEnd = ''; |
|
|
|
if (end) { |
|
if (end.line === start.line && col + (end.col - start.col) <= maxWidth + 1) { |
|
errLen = end.col - start.col; |
|
} else { |
|
errLen = Math.min(src.length + 1, maxWidth) - col; |
|
errEnd = '…'; |
|
} |
|
} |
|
|
|
const offset = col > 1 ? ' '.repeat(col - 1) : ''; |
|
const err = '^'.repeat(errLen); |
|
return `${src}\n${offset}${err}${errEnd}`; |
|
} |
|
|
|
class Range { |
|
static copy(orig) { |
|
return new Range(orig.start, orig.end); |
|
} |
|
|
|
constructor(start, end) { |
|
this.start = start; |
|
this.end = end || start; |
|
} |
|
|
|
isEmpty() { |
|
return typeof this.start !== 'number' || !this.end || this.end <= this.start; |
|
} |
|
/** |
|
* Set `origStart` and `origEnd` to point to the original source range for |
|
* this node, which may differ due to dropped CR characters. |
|
* |
|
* @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` |
|
*/ |
|
|
|
|
|
setOrigRange(cr, offset) { |
|
const { |
|
start, |
|
end |
|
} = this; |
|
|
|
if (cr.length === 0 || end <= cr[0]) { |
|
this.origStart = start; |
|
this.origEnd = end; |
|
return offset; |
|
} |
|
|
|
let i = offset; |
|
|
|
while (i < cr.length) { |
|
if (cr[i] > start) break;else ++i; |
|
} |
|
|
|
this.origStart = start + i; |
|
const nextOffset = i; |
|
|
|
while (i < cr.length) { |
|
// if end was at \n, it should now be at \r |
|
if (cr[i] >= end) break;else ++i; |
|
} |
|
|
|
this.origEnd = end + i; |
|
return nextOffset; |
|
} |
|
|
|
} |
|
|
|
/** Root class of all nodes */ |
|
|
|
class Node { |
|
static addStringTerminator(src, offset, str) { |
|
if (str[str.length - 1] === '\n') return str; |
|
const next = Node.endOfWhiteSpace(src, offset); |
|
return next >= src.length || src[next] === '\n' ? str + '\n' : str; |
|
} // ^(---|...) |
|
|
|
|
|
static atDocumentBoundary(src, offset, sep) { |
|
const ch0 = src[offset]; |
|
if (!ch0) return true; |
|
const 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; |
|
} |
|
|
|
const ch1 = src[offset + 1]; |
|
const ch2 = src[offset + 2]; |
|
if (ch1 !== ch0 || ch2 !== ch0) return false; |
|
const ch3 = src[offset + 3]; |
|
return !ch3 || ch3 === '\n' || ch3 === '\t' || ch3 === ' '; |
|
} |
|
|
|
static endOfIdentifier(src, offset) { |
|
let ch = src[offset]; |
|
const isVerbatim = ch === '<'; |
|
const notOk = isVerbatim ? ['\n', '\t', ' ', '>'] : ['\n', '\t', ' ', '[', ']', '{', '}', ',']; |
|
|
|
while (ch && notOk.indexOf(ch) === -1) ch = src[offset += 1]; |
|
|
|
if (isVerbatim && ch === '>') offset += 1; |
|
return offset; |
|
} |
|
|
|
static endOfIndent(src, offset) { |
|
let ch = src[offset]; |
|
|
|
while (ch === ' ') ch = src[offset += 1]; |
|
|
|
return offset; |
|
} |
|
|
|
static endOfLine(src, offset) { |
|
let ch = src[offset]; |
|
|
|
while (ch && ch !== '\n') ch = src[offset += 1]; |
|
|
|
return offset; |
|
} |
|
|
|
static endOfWhiteSpace(src, offset) { |
|
let ch = src[offset]; |
|
|
|
while (ch === '\t' || ch === ' ') ch = src[offset += 1]; |
|
|
|
return offset; |
|
} |
|
|
|
static startOfLine(src, offset) { |
|
let 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} |
|
*/ |
|
|
|
|
|
static endOfBlockIndent(src, indent, lineStart) { |
|
const inEnd = Node.endOfIndent(src, lineStart); |
|
|
|
if (inEnd > lineStart + indent) { |
|
return inEnd; |
|
} else { |
|
const wsEnd = Node.endOfWhiteSpace(src, inEnd); |
|
const ch = src[wsEnd]; |
|
if (!ch || ch === '\n') return wsEnd; |
|
} |
|
|
|
return null; |
|
} |
|
|
|
static atBlank(src, offset, endAsBlank) { |
|
const ch = src[offset]; |
|
return ch === '\n' || ch === '\t' || ch === ' ' || endAsBlank && !ch; |
|
} |
|
|
|
static 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 |
|
|
|
|
|
static normalizeOffset(src, offset) { |
|
const 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' |
|
|
|
|
|
static foldNewline(src, offset, indent) { |
|
let inCount = 0; |
|
let error = false; |
|
let fold = ''; |
|
let 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, |
|
offset, |
|
error |
|
}; |
|
} |
|
|
|
constructor(type, props, context) { |
|
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; |
|
} |
|
|
|
getPropValue(idx, key, skipKey) { |
|
if (!this.context) return null; |
|
const { |
|
src |
|
} = this.context; |
|
const prop = this.props[idx]; |
|
return prop && src[prop.start] === key ? src.slice(prop.start + (skipKey ? 1 : 0), prop.end) : null; |
|
} |
|
|
|
get anchor() { |
|
for (let i = 0; i < this.props.length; ++i) { |
|
const anchor = this.getPropValue(i, Char.ANCHOR, true); |
|
if (anchor != null) return anchor; |
|
} |
|
|
|
return null; |
|
} |
|
|
|
get comment() { |
|
const comments = []; |
|
|
|
for (let i = 0; i < this.props.length; ++i) { |
|
const comment = this.getPropValue(i, Char.COMMENT, true); |
|
if (comment != null) comments.push(comment); |
|
} |
|
|
|
return comments.length > 0 ? comments.join('\n') : null; |
|
} |
|
|
|
commentHasRequiredWhitespace(start) { |
|
const { |
|
src |
|
} = this.context; |
|
if (this.header && start === this.header.end) return false; |
|
if (!this.valueRange) return false; |
|
const { |
|
end |
|
} = this.valueRange; |
|
return start !== end || Node.atBlank(src, end - 1); |
|
} |
|
|
|
get hasComment() { |
|
if (this.context) { |
|
const { |
|
src |
|
} = this.context; |
|
|
|
for (let i = 0; i < this.props.length; ++i) { |
|
if (src[this.props[i].start] === Char.COMMENT) return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
get hasProps() { |
|
if (this.context) { |
|
const { |
|
src |
|
} = this.context; |
|
|
|
for (let i = 0; i < this.props.length; ++i) { |
|
if (src[this.props[i].start] !== Char.COMMENT) return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
get includesTrailingLines() { |
|
return false; |
|
} |
|
|
|
get jsonLike() { |
|
const jsonLikeTypes = [Type.FLOW_MAP, Type.FLOW_SEQ, Type.QUOTE_DOUBLE, Type.QUOTE_SINGLE]; |
|
return jsonLikeTypes.indexOf(this.type) !== -1; |
|
} |
|
|
|
get rangeAsLinePos() { |
|
if (!this.range || !this.context) return undefined; |
|
const start = getLinePos(this.range.start, this.context.root); |
|
if (!start) return undefined; |
|
const end = getLinePos(this.range.end, this.context.root); |
|
return { |
|
start, |
|
end |
|
}; |
|
} |
|
|
|
get rawValue() { |
|
if (!this.valueRange || !this.context) return null; |
|
const { |
|
start, |
|
end |
|
} = this.valueRange; |
|
return this.context.src.slice(start, end); |
|
} |
|
|
|
get tag() { |
|
for (let i = 0; i < this.props.length; ++i) { |
|
const 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 |
|
const [_, handle, suffix] = tag.match(/^(.*!)([^!]*)$/); |
|
return { |
|
handle, |
|
suffix |
|
}; |
|
} |
|
} |
|
} |
|
|
|
return null; |
|
} |
|
|
|
get valueRangeContainsNewline() { |
|
if (!this.valueRange || !this.context) return false; |
|
const { |
|
start, |
|
end |
|
} = this.valueRange; |
|
const { |
|
src |
|
} = this.context; |
|
|
|
for (let i = start; i < end; ++i) { |
|
if (src[i] === '\n') return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
parseComment(start) { |
|
const { |
|
src |
|
} = this.context; |
|
|
|
if (src[start] === Char.COMMENT) { |
|
const end = Node.endOfLine(src, start + 1); |
|
const 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` |
|
*/ |
|
|
|
|
|
setOrigRanges(cr, offset) { |
|
if (this.range) offset = this.range.setOrigRange(cr, offset); |
|
if (this.valueRange) this.valueRange.setOrigRange(cr, offset); |
|
this.props.forEach(prop => prop.setOrigRange(cr, offset)); |
|
return offset; |
|
} |
|
|
|
toString() { |
|
const { |
|
context: { |
|
src |
|
}, |
|
range, |
|
value |
|
} = this; |
|
if (value != null) return value; |
|
const str = src.slice(range.start, range.end); |
|
return Node.addStringTerminator(src, range.end, str); |
|
} |
|
|
|
} |
|
|
|
class YAMLError extends Error { |
|
constructor(name, source, message) { |
|
if (!message || !(source instanceof Node)) throw new Error(`Invalid arguments for new ${name}`); |
|
super(); |
|
this.name = name; |
|
this.message = message; |
|
this.source = source; |
|
} |
|
|
|
makePretty() { |
|
if (!this.source) return; |
|
this.nodeType = this.source.type; |
|
const cst = this.source.context && this.source.context.root; |
|
|
|
if (typeof this.offset === 'number') { |
|
this.range = new Range(this.offset, this.offset + 1); |
|
const start = cst && getLinePos(this.offset, cst); |
|
|
|
if (start) { |
|
const end = { |
|
line: start.line, |
|
col: start.col + 1 |
|
}; |
|
this.linePos = { |
|
start, |
|
end |
|
}; |
|
} |
|
|
|
delete this.offset; |
|
} else { |
|
this.range = this.source.range; |
|
this.linePos = this.source.rangeAsLinePos; |
|
} |
|
|
|
if (this.linePos) { |
|
const { |
|
line, |
|
col |
|
} = this.linePos.start; |
|
this.message += ` at line ${line}, column ${col}`; |
|
const ctx = cst && getPrettyContext(this.linePos, cst); |
|
if (ctx) this.message += `:\n\n${ctx}\n`; |
|
} |
|
|
|
delete this.source; |
|
} |
|
|
|
} |
|
class YAMLReferenceError extends YAMLError { |
|
constructor(source, message) { |
|
super('YAMLReferenceError', source, message); |
|
} |
|
|
|
} |
|
class YAMLSemanticError extends YAMLError { |
|
constructor(source, message) { |
|
super('YAMLSemanticError', source, message); |
|
} |
|
|
|
} |
|
class YAMLSyntaxError extends YAMLError { |
|
constructor(source, message) { |
|
super('YAMLSyntaxError', source, message); |
|
} |
|
|
|
} |
|
class YAMLWarning extends YAMLError { |
|
constructor(source, message) { |
|
super('YAMLWarning', source, message); |
|
} |
|
|
|
} |
|
|
|
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; |
|
} |
|
|
|
class PlainValue extends Node { |
|
static endOfLine(src, start, inFlow) { |
|
let ch = src[start]; |
|
let offset = start; |
|
|
|
while (ch && ch !== '\n') { |
|
if (inFlow && (ch === '[' || ch === ']' || ch === '{' || ch === '}' || ch === ',')) break; |
|
const next = src[offset + 1]; |
|
if (ch === ':' && (!next || next === '\n' || next === '\t' || next === ' ' || inFlow && next === ',')) break; |
|
if ((ch === ' ' || ch === '\t') && next === '#') break; |
|
offset += 1; |
|
ch = next; |
|
} |
|
|
|
return offset; |
|
} |
|
|
|
get strValue() { |
|
if (!this.valueRange || !this.context) return null; |
|
let { |
|
start, |
|
end |
|
} = this.valueRange; |
|
const { |
|
src |
|
} = this.context; |
|
let ch = src[end - 1]; |
|
|
|
while (start < end && (ch === '\n' || ch === '\t' || ch === ' ')) ch = src[--end - 1]; |
|
|
|
let str = ''; |
|
|
|
for (let i = start; i < end; ++i) { |
|
const ch = src[i]; |
|
|
|
if (ch === '\n') { |
|
const { |
|
fold, |
|
offset |
|
} = Node.foldNewline(src, i, -1); |
|
str += fold; |
|
i = offset; |
|
} else if (ch === ' ' || ch === '\t') { |
|
// trim trailing whitespace |
|
const wsStart = i; |
|
let next = src[i + 1]; |
|
|
|
while (i < end && (next === ' ' || next === '\t')) { |
|
i += 1; |
|
next = src[i + 1]; |
|
} |
|
|
|
if (next !== '\n') str += i > wsStart ? src.slice(wsStart, i + 1) : ch; |
|
} else { |
|
str += ch; |
|
} |
|
} |
|
|
|
const ch0 = src[start]; |
|
|
|
switch (ch0) { |
|
case '\t': |
|
{ |
|
const msg = 'Plain value cannot start with a tab character'; |
|
const errors = [new YAMLSemanticError(this, msg)]; |
|
return { |
|
errors, |
|
str |
|
}; |
|
} |
|
|
|
case '@': |
|
case '`': |
|
{ |
|
const msg = `Plain value cannot start with reserved character ${ch0}`; |
|
const errors = [new YAMLSemanticError(this, msg)]; |
|
return { |
|
errors, |
|
str |
|
}; |
|
} |
|
|
|
default: |
|
return str; |
|
} |
|
} |
|
|
|
parseBlockValue(start) { |
|
const { |
|
indent, |
|
inFlow, |
|
src |
|
} = this.context; |
|
let offset = start; |
|
let valueEnd = start; |
|
|
|
for (let ch = src[offset]; ch === '\n'; ch = src[offset]) { |
|
if (Node.atDocumentBoundary(src, offset + 1)) break; |
|
const end = Node.endOfBlockIndent(src, indent, offset + 1); |
|
if (end === null || src[end] === '#') break; |
|
|
|
if (src[end] === '\n') { |
|
offset = end; |
|
} else { |
|
valueEnd = PlainValue.endOfLine(src, end, inFlow); |
|
offset = valueEnd; |
|
} |
|
} |
|
|
|
if (this.valueRange.isEmpty()) this.valueRange.start = start; |
|
this.valueRange.end = valueEnd; |
|
return valueEnd; |
|
} |
|
/** |
|
* Parses a plain value from the source |
|
* |
|
* Accepted forms are: |
|
* ``` |
|
* #comment |
|
* |
|
* first line |
|
* |
|
* first line #comment |
|
* |
|
* first line |
|
* block |
|
* lines |
|
* |
|
* #comment |
|
* block |
|
* lines |
|
* ``` |
|
* where block lines are empty or have an indent level greater than `indent`. |
|
* |
|
* @param {ParseContext} context |
|
* @param {number} start - Index of first character |
|
* @returns {number} - Index of the character after this scalar, may be `\n` |
|
*/ |
|
|
|
|
|
parse(context, start) { |
|
this.context = context; |
|
const { |
|
inFlow, |
|
src |
|
} = context; |
|
let offset = start; |
|
const ch = src[offset]; |
|
|
|
if (ch && ch !== '#' && ch !== '\n') { |
|
offset = PlainValue.endOfLine(src, start, inFlow); |
|
} |
|
|
|
this.valueRange = new Range(start, offset); |
|
offset = Node.endOfWhiteSpace(src, offset); |
|
offset = this.parseComment(offset); |
|
|
|
if (!this.hasComment || this.valueRange.isEmpty()) { |
|
offset = this.parseBlockValue(offset); |
|
} |
|
|
|
return offset; |
|
} |
|
|
|
} |
|
|
|
exports.Char = Char; |
|
exports.Node = Node; |
|
exports.PlainValue = PlainValue; |
|
exports.Range = Range; |
|
exports.Type = Type; |
|
exports.YAMLError = YAMLError; |
|
exports.YAMLReferenceError = YAMLReferenceError; |
|
exports.YAMLSemanticError = YAMLSemanticError; |
|
exports.YAMLSyntaxError = YAMLSyntaxError; |
|
exports.YAMLWarning = YAMLWarning; |
|
exports._defineProperty = _defineProperty; |
|
exports.defaultTagPrefix = defaultTagPrefix; |
|
exports.defaultTags = defaultTags;
|
|
|