| ; | |
| var Scalar = require('../nodes/Scalar.js'); | |
| function resolveBlockScalar(ctx, scalar, onError) { | |
| const start = scalar.offset; | |
| const header = parseBlockScalarHeader(scalar, ctx.options.strict, onError); | |
| if (!header) | |
| return { value: '', type: null, comment: '', range: [start, start, start] }; | |
| const type = header.mode === '>' ? Scalar.Scalar.BLOCK_FOLDED : Scalar.Scalar.BLOCK_LITERAL; | |
| const lines = scalar.source ? splitLines(scalar.source) : []; | |
| // determine the end of content & start of chomping | |
| let chompStart = lines.length; | |
| for (let i = lines.length - 1; i >= 0; --i) { | |
| const content = lines[i][1]; | |
| if (content === '' || content === '\r') | |
| chompStart = i; | |
| else | |
| break; | |
| } | |
| // shortcut for empty contents | |
| if (chompStart === 0) { | |
| const value = header.chomp === '+' && lines.length > 0 | |
| ? '\n'.repeat(Math.max(1, lines.length - 1)) | |
| : ''; | |
| let end = start + header.length; | |
| if (scalar.source) | |
| end += scalar.source.length; | |
| return { value, type, comment: header.comment, range: [start, end, end] }; | |
| } | |
| // find the indentation level to trim from start | |
| let trimIndent = scalar.indent + header.indent; | |
| let offset = scalar.offset + header.length; | |
| let contentStart = 0; | |
| for (let i = 0; i < chompStart; ++i) { | |
| const [indent, content] = lines[i]; | |
| if (content === '' || content === '\r') { | |
| if (header.indent === 0 && indent.length > trimIndent) | |
| trimIndent = indent.length; | |
| } | |
| else { | |
| if (indent.length < trimIndent) { | |
| const message = 'Block scalars with more-indented leading empty lines must use an explicit indentation indicator'; | |
| onError(offset + indent.length, 'MISSING_CHAR', message); | |
| } | |
| if (header.indent === 0) | |
| trimIndent = indent.length; | |
| contentStart = i; | |
| if (trimIndent === 0 && !ctx.atRoot) { | |
| const message = 'Block scalar values in collections must be indented'; | |
| onError(offset, 'BAD_INDENT', message); | |
| } | |
| break; | |
| } | |
| offset += indent.length + content.length + 1; | |
| } | |
| // include trailing more-indented empty lines in content | |
| for (let i = lines.length - 1; i >= chompStart; --i) { | |
| if (lines[i][0].length > trimIndent) | |
| chompStart = i + 1; | |
| } | |
| let value = ''; | |
| let sep = ''; | |
| let prevMoreIndented = false; | |
| // leading whitespace is kept intact | |
| for (let i = 0; i < contentStart; ++i) | |
| value += lines[i][0].slice(trimIndent) + '\n'; | |
| for (let i = contentStart; i < chompStart; ++i) { | |
| let [indent, content] = lines[i]; | |
| offset += indent.length + content.length + 1; | |
| const crlf = content[content.length - 1] === '\r'; | |
| if (crlf) | |
| content = content.slice(0, -1); | |
| /* istanbul ignore if already caught in lexer */ | |
| if (content && indent.length < trimIndent) { | |
| const src = header.indent | |
| ? 'explicit indentation indicator' | |
| : 'first line'; | |
| const message = `Block scalar lines must not be less indented than their ${src}`; | |
| onError(offset - content.length - (crlf ? 2 : 1), 'BAD_INDENT', message); | |
| indent = ''; | |
| } | |
| if (type === Scalar.Scalar.BLOCK_LITERAL) { | |
| value += sep + indent.slice(trimIndent) + content; | |
| sep = '\n'; | |
| } | |
| else if (indent.length > trimIndent || content[0] === '\t') { | |
| // more-indented content within a folded block | |
| if (sep === ' ') | |
| sep = '\n'; | |
| else if (!prevMoreIndented && sep === '\n') | |
| sep = '\n\n'; | |
| value += sep + indent.slice(trimIndent) + content; | |
| sep = '\n'; | |
| prevMoreIndented = true; | |
| } | |
| else if (content === '') { | |
| // empty line | |
| if (sep === '\n') | |
| value += '\n'; | |
| else | |
| sep = '\n'; | |
| } | |
| else { | |
| value += sep + content; | |
| sep = ' '; | |
| prevMoreIndented = false; | |
| } | |
| } | |
| switch (header.chomp) { | |
| case '-': | |
| break; | |
| case '+': | |
| for (let i = chompStart; i < lines.length; ++i) | |
| value += '\n' + lines[i][0].slice(trimIndent); | |
| if (value[value.length - 1] !== '\n') | |
| value += '\n'; | |
| break; | |
| default: | |
| value += '\n'; | |
| } | |
| const end = start + header.length + scalar.source.length; | |
| return { value, type, comment: header.comment, range: [start, end, end] }; | |
| } | |
| function parseBlockScalarHeader({ offset, props }, strict, onError) { | |
| /* istanbul ignore if should not happen */ | |
| if (props[0].type !== 'block-scalar-header') { | |
| onError(props[0], 'IMPOSSIBLE', 'Block scalar header not found'); | |
| return null; | |
| } | |
| const { source } = props[0]; | |
| const mode = source[0]; | |
| let indent = 0; | |
| let chomp = ''; | |
| let error = -1; | |
| for (let i = 1; i < source.length; ++i) { | |
| const ch = source[i]; | |
| if (!chomp && (ch === '-' || ch === '+')) | |
| chomp = ch; | |
| else { | |
| const n = Number(ch); | |
| if (!indent && n) | |
| indent = n; | |
| else if (error === -1) | |
| error = offset + i; | |
| } | |
| } | |
| if (error !== -1) | |
| onError(error, 'UNEXPECTED_TOKEN', `Block scalar header includes extra characters: ${source}`); | |
| let hasSpace = false; | |
| let comment = ''; | |
| let length = source.length; | |
| for (let i = 1; i < props.length; ++i) { | |
| const token = props[i]; | |
| switch (token.type) { | |
| case 'space': | |
| hasSpace = true; | |
| // fallthrough | |
| case 'newline': | |
| length += token.source.length; | |
| break; | |
| case 'comment': | |
| if (strict && !hasSpace) { | |
| const message = 'Comments must be separated from other tokens by white space characters'; | |
| onError(token, 'MISSING_CHAR', message); | |
| } | |
| length += token.source.length; | |
| comment = token.source.substring(1); | |
| break; | |
| case 'error': | |
| onError(token, 'UNEXPECTED_TOKEN', token.message); | |
| length += token.source.length; | |
| break; | |
| /* istanbul ignore next should not happen */ | |
| default: { | |
| const message = `Unexpected token in block scalar header: ${token.type}`; | |
| onError(token, 'UNEXPECTED_TOKEN', message); | |
| const ts = token.source; | |
| if (ts && typeof ts === 'string') | |
| length += ts.length; | |
| } | |
| } | |
| } | |
| return { mode, indent, chomp, comment, length }; | |
| } | |
| /** @returns Array of lines split up as `[indent, content]` */ | |
| function splitLines(source) { | |
| const split = source.split(/\n( *)/); | |
| const first = split[0]; | |
| const m = first.match(/^( *)/); | |
| const line0 = m?.[1] | |
| ? [m[1], first.slice(m[1].length)] | |
| : ['', first]; | |
| const lines = [line0]; | |
| for (let i = 1; i < split.length; i += 2) | |
| lines.push([split[i], split[i + 1]]); | |
| return lines; | |
| } | |
| exports.resolveBlockScalar = resolveBlockScalar; | |
Xet Storage Details
- Size:
- 7.5 kB
- Xet hash:
- 866b20d1b6c13070586740d220a2e24252f63dabcd0916e32ec871c5d4c4edc4
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.