refactor(yaml): inline readBlockScalar() (#5841)

This commit is contained in:
Tim Reichen 2024-08-27 22:35:05 +02:00 committed by GitHub
parent baa5086dff
commit cde346da13
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -943,6 +943,162 @@ export class LoaderState {
"Cannot read flow collection: unexpected end of the stream within a flow collection", "Cannot read flow collection: unexpected end of the stream within a flow collection",
); );
} }
// Handles block scaler styles: e.g. '|', '>', '|-' and '>-'.
// https://yaml.org/spec/1.2.2/#81-block-scalar-styles
readBlockScalar(nodeIndent: number): boolean {
let chomping = CHOMPING_CLIP;
let didReadContent = false;
let detectedIndent = false;
let textIndent = nodeIndent;
let emptyLines = 0;
let atMoreIndented = false;
let ch = this.peek();
let folding = false;
if (ch === VERTICAL_LINE) {
folding = false;
} else if (ch === GREATER_THAN) {
folding = true;
} else {
return false;
}
this.kind = "scalar";
this.result = "";
let tmp = 0;
while (ch !== 0) {
ch = this.next();
if (ch === PLUS || ch === MINUS) {
if (CHOMPING_CLIP === chomping) {
chomping = ch === PLUS ? CHOMPING_KEEP : CHOMPING_STRIP;
} else {
return this.throwError(
"Cannot read block: chomping mode identifier repeated",
);
}
} else if ((tmp = decimalCharCodeToNumber(ch)) >= 0) {
if (tmp === 0) {
return this.throwError(
"Cannot read block: indentation width must be greater than 0",
);
} else if (!detectedIndent) {
textIndent = nodeIndent + tmp - 1;
detectedIndent = true;
} else {
return this.throwError(
"Cannot read block: indentation width identifier repeated",
);
}
} else {
break;
}
}
if (isWhiteSpace(ch)) {
do {
ch = this.next();
} while (isWhiteSpace(ch));
if (ch === SHARP) {
do {
ch = this.next();
} while (!isEOL(ch) && ch !== 0);
}
}
while (ch !== 0) {
this.readLineBreak();
this.lineIndent = 0;
ch = this.peek();
while (
(!detectedIndent || this.lineIndent < textIndent) &&
ch === SPACE
) {
this.lineIndent++;
ch = this.next();
}
if (!detectedIndent && this.lineIndent > textIndent) {
textIndent = this.lineIndent;
}
if (isEOL(ch)) {
emptyLines++;
continue;
}
// End of the scalar.
if (this.lineIndent < textIndent) {
// Perform the chomping.
if (chomping === CHOMPING_KEEP) {
this.result += "\n".repeat(
didReadContent ? 1 + emptyLines : emptyLines,
);
} else if (chomping === CHOMPING_CLIP) {
if (didReadContent) {
// i.e. only if the scalar is not empty.
this.result += "\n";
}
}
// Break this `while` cycle and go to the function's epilogue.
break;
}
// Folded style: use fancy rules to handle line breaks.
if (folding) {
// Lines starting with white space characters (more-indented lines) are not folded.
if (isWhiteSpace(ch)) {
atMoreIndented = true;
// except for the first content line (cf. Example 8.1)
this.result += "\n".repeat(
didReadContent ? 1 + emptyLines : emptyLines,
);
// End of more-indented block.
} else if (atMoreIndented) {
atMoreIndented = false;
this.result += "\n".repeat(emptyLines + 1);
// Just one line break - perceive as the same line.
} else if (emptyLines === 0) {
if (didReadContent) {
// i.e. only if we have already read some scalar content.
this.result += " ";
}
// Several line breaks - perceive as different lines.
} else {
this.result += "\n".repeat(emptyLines);
}
// Literal style: just add exact number of line breaks between content lines.
} else {
// Keep all line breaks except the header line break.
this.result += "\n".repeat(
didReadContent ? 1 + emptyLines : emptyLines,
);
}
didReadContent = true;
detectedIndent = true;
emptyLines = 0;
const captureStart = this.position;
while (!isEOL(ch) && ch !== 0) {
ch = this.next();
}
this.captureSegment(captureStart, this.position, false);
}
return true;
}
readDocument() { readDocument() {
const documentStart = this.position; const documentStart = this.position;
@ -1072,161 +1228,6 @@ export class LoaderState {
} }
} }
// Handles block scaler styles: e.g. '|', '>', '|-' and '>-'.
// https://yaml.org/spec/1.2.2/#81-block-scalar-styles
function readBlockScalar(state: LoaderState, nodeIndent: number): boolean {
let chomping = CHOMPING_CLIP;
let didReadContent = false;
let detectedIndent = false;
let textIndent = nodeIndent;
let emptyLines = 0;
let atMoreIndented = false;
let ch = state.peek();
let folding = false;
if (ch === VERTICAL_LINE) {
folding = false;
} else if (ch === GREATER_THAN) {
folding = true;
} else {
return false;
}
state.kind = "scalar";
state.result = "";
let tmp = 0;
while (ch !== 0) {
ch = state.next();
if (ch === PLUS || ch === MINUS) {
if (CHOMPING_CLIP === chomping) {
chomping = ch === PLUS ? CHOMPING_KEEP : CHOMPING_STRIP;
} else {
return state.throwError(
"Cannot read block: chomping mode identifier repeated",
);
}
} else if ((tmp = decimalCharCodeToNumber(ch)) >= 0) {
if (tmp === 0) {
return state.throwError(
"Cannot read block: indentation width must be greater than 0",
);
} else if (!detectedIndent) {
textIndent = nodeIndent + tmp - 1;
detectedIndent = true;
} else {
return state.throwError(
"Cannot read block: indentation width identifier repeated",
);
}
} else {
break;
}
}
if (isWhiteSpace(ch)) {
do {
ch = state.next();
} while (isWhiteSpace(ch));
if (ch === SHARP) {
do {
ch = state.next();
} while (!isEOL(ch) && ch !== 0);
}
}
while (ch !== 0) {
state.readLineBreak();
state.lineIndent = 0;
ch = state.peek();
while (
(!detectedIndent || state.lineIndent < textIndent) &&
ch === SPACE
) {
state.lineIndent++;
ch = state.next();
}
if (!detectedIndent && state.lineIndent > textIndent) {
textIndent = state.lineIndent;
}
if (isEOL(ch)) {
emptyLines++;
continue;
}
// End of the scalar.
if (state.lineIndent < textIndent) {
// Perform the chomping.
if (chomping === CHOMPING_KEEP) {
state.result += "\n".repeat(
didReadContent ? 1 + emptyLines : emptyLines,
);
} else if (chomping === CHOMPING_CLIP) {
if (didReadContent) {
// i.e. only if the scalar is not empty.
state.result += "\n";
}
}
// Break this `while` cycle and go to the function's epilogue.
break;
}
// Folded style: use fancy rules to handle line breaks.
if (folding) {
// Lines starting with white space characters (more-indented lines) are not folded.
if (isWhiteSpace(ch)) {
atMoreIndented = true;
// except for the first content line (cf. Example 8.1)
state.result += "\n".repeat(
didReadContent ? 1 + emptyLines : emptyLines,
);
// End of more-indented block.
} else if (atMoreIndented) {
atMoreIndented = false;
state.result += "\n".repeat(emptyLines + 1);
// Just one line break - perceive as the same line.
} else if (emptyLines === 0) {
if (didReadContent) {
// i.e. only if we have already read some scalar content.
state.result += " ";
}
// Several line breaks - perceive as different lines.
} else {
state.result += "\n".repeat(emptyLines);
}
// Literal style: just add exact number of line breaks between content lines.
} else {
// Keep all line breaks except the header line break.
state.result += "\n".repeat(didReadContent ? 1 + emptyLines : emptyLines);
}
didReadContent = true;
detectedIndent = true;
emptyLines = 0;
const captureStart = state.position;
while (!isEOL(ch) && ch !== 0) {
ch = state.next();
}
state.captureSegment(captureStart, state.position, false);
}
return true;
}
function readBlockMapping( function readBlockMapping(
state: LoaderState, state: LoaderState,
nodeIndent: number, nodeIndent: number,
@ -1649,7 +1650,7 @@ function composeNode(
hasContent = true; hasContent = true;
} else { } else {
if ( if (
(allowBlockScalars && readBlockScalar(state, flowIndent)) || (allowBlockScalars && state.readBlockScalar(flowIndent)) ||
state.readSingleQuotedScalar(flowIndent) || state.readSingleQuotedScalar(flowIndent) ||
state.readDoubleQuotedScalar(flowIndent) state.readDoubleQuotedScalar(flowIndent)
) { ) {