Skip to content

Commit

Permalink
refactor(yaml): inline readBlockScalar() (denoland#5841)
Browse files Browse the repository at this point in the history
  • Loading branch information
timreichen committed Aug 27, 2024
1 parent baa5086 commit cde346d
Showing 1 changed file with 157 additions and 156 deletions.
313 changes: 157 additions & 156 deletions yaml/_loader_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,162 @@ export class LoaderState {
"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() {
const documentStart = this.position;
Expand Down Expand Up @@ -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(
state: LoaderState,
nodeIndent: number,
Expand Down Expand Up @@ -1649,7 +1650,7 @@ function composeNode(
hasContent = true;
} else {
if (
(allowBlockScalars && readBlockScalar(state, flowIndent)) ||
(allowBlockScalars && state.readBlockScalar(flowIndent)) ||
state.readSingleQuotedScalar(flowIndent) ||
state.readDoubleQuotedScalar(flowIndent)
) {
Expand Down

0 comments on commit cde346d

Please sign in to comment.