Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,32 @@ import { removeFakeNodes } from "./utils/remove-fake-nodes.js";
import { updatePositions } from "./utils/update-positions.js";

export function parse(text: string, options?: ParseOptions): Root {
const parser = new YAML.Parser();
const lineCounter = new YAML.LineCounter();
const parser = new YAML.Parser(lineCounter.addNewLine);
const composer = new YAML.Composer({
keepSourceTokens: true,
// Intentionally to not cast to boolean, so user can pass a function (undocumented)
// https://eemeli.org/yaml/#options
uniqueKeys: options?.uniqueKeys,
lineCounter,
});
const documentNodes: YAML.Document.Parsed[] = [];
const cstTokens: YAML.CST.Token[] = [];
const context = new Context(text);
const context = new Context(text, lineCounter);

for (const cst of parser.parse(text)) {
cstTokens.push(cst);
for (const doc of composer.next(cst)) {
documentNodes.push(doc);
documentNodes.push(throwParseError(doc, context));
}
}

for (const doc of composer.end()) {
documentNodes.push(doc);
}

for (const doc of documentNodes) {
for (const error of doc.errors) {
throw transformError(error, context);
}
documentNodes.push(throwParseError(doc, context));
}

const root = createRoot(
context.transformRange({ origStart: 0, origEnd: text.length }),
context.transformRange([0, text.length]),
context.transformDocuments(documentNodes, cstTokens),
context.comments,
);
Expand All @@ -48,3 +44,11 @@ export function parse(text: string, options?: ParseOptions): Root {

return root;
}

function throwParseError(document: YAML.Document.Parsed, context: Context) {
const { errors } = document;
if (errors.length > 0) {
throw transformError(errors[0], context);
}
return document;
}
5 changes: 1 addition & 4 deletions src/transforms/alias.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ export function transformAlias(
}

return createAlias(
context.transformRange({
origStart: alias.range[0],
origEnd: alias.range[1],
}),
context.transformRange(alias.range),
context.transformContentProperties(alias, props.tokens),
alias.source,
);
Expand Down
5 changes: 1 addition & 4 deletions src/transforms/block-value.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@ export function transformAstBlockValue(

const headerInfo = parseHeader(blockScalarHeaderToken.source);

const position = context.transformRange({
origStart: blockValue.range[0],
origEnd: blockValue.range[1],
});
const position = context.transformRange(blockValue.range);

return createBlockValue(
position,
Expand Down
8 changes: 4 additions & 4 deletions src/transforms/comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ export function transformComment(
context: Context,
): Comment {
return createComment(
context.transformRange({
origStart: comment.offset,
origEnd: comment.offset + comment.source.length,
}),
context.transformRange([
comment.offset,
comment.offset + comment.source.length,
]),
comment.source.slice(1),
);
}
16 changes: 8 additions & 8 deletions src/transforms/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ export function transformContentProperties(
let anchor: Anchor | null = null;

for (const token of tokens) {
const tokenRange: Range = {
origStart: token.offset,
origEnd: token.offset + token.source.length,
};
const tokenRange: Range = [
token.offset,
token.offset + token.source.length,
];
switch (token.type) {
case "tag":
{
firstTagOrAnchorRange = firstTagOrAnchorRange || tokenRange;
firstTagOrAnchorRange ??= tokenRange;
let resolvedTag =
node.tag ??
token.source.slice(token.source.startsWith("!!") ? 2 : 1);
Expand All @@ -41,15 +41,15 @@ export function transformContentProperties(
}
break;
case "anchor":
firstTagOrAnchorRange = firstTagOrAnchorRange || tokenRange;
firstTagOrAnchorRange ??= tokenRange;
anchor = createAnchor(context.transformRange(tokenRange), node.anchor!);
break;
case "comment": {
const comment = context.transformComment(token);
if (
firstTagOrAnchorRange &&
firstTagOrAnchorRange.origEnd <= tokenRange.origStart &&
tokenRange.origEnd <= node.range[0]
firstTagOrAnchorRange[0] <= tokenRange[0] &&
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mistake

tokenRange[1] <= node.range[0]
) {
middleComments.push(comment);
}
Expand Down
80 changes: 6 additions & 74 deletions src/transforms/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,33 +22,20 @@ import {
class Context {
text;
comments: Comment[] = [];
#linesAndColumns: LinesAndColumns;
#lineCounter: YAML.LineCounter;

constructor(text: string) {
constructor(text: string, lineCounter: YAML.LineCounter) {
this.text = text;
this.#linesAndColumns = new LinesAndColumns(text);
}

#getRangePosition(range: Range): { start: Point; end: Point } {
if (this.text === "" && range.origStart === 0 && range.origEnd === 0) {
return {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 0, line: 1, column: 1 },
};
}

return {
start: this.#linesAndColumns.getPoint(range.origStart),
end: this.#linesAndColumns.getPoint(range.origEnd),
};
this.#lineCounter = lineCounter;
}

transformOffset(offset: number): Point {
return this.#linesAndColumns.getPoint(offset);
const { line, col } = this.#lineCounter.linePos(offset);
return { line, column: col, offset };
}

transformRange(range: Range): Position {
const { start, end } = this.#getRangePosition(range);
const [start, end] = range.map(position => this.transformOffset(position));
return createPosition(start, end);
}

Expand Down Expand Up @@ -85,58 +72,3 @@ class Context {
}

export default Context;

class LinesAndColumns {
private lineBreakIndices: number[];

constructor(text: string) {
this.lineBreakIndices = [];
for (let i = 0; i < text.length; i++) {
const ch = text[i];
if (ch === "\n") {
this.lineBreakIndices.push(i);
} else if (ch === "\r") {
if (i + 1 < text.length && text[i + 1] === "\n") {
this.lineBreakIndices.push(i + 1);
i++;
} else {
this.lineBreakIndices.push(i);
}
}
}
}

/**
* Get line and column for the given offset.
* @param offset 0-based offset
* @returns 1-based line and 1-based column
*/
getPoint(offset: number): Point {
let low = 0;
let high = this.lineBreakIndices.length - 1;

while (low <= high) {
const mid = Math.floor((low + high) / 2);
const lineBreakIndex = this.lineBreakIndices[mid];

if (lineBreakIndex < offset) {
low = mid + 1;
} else if (lineBreakIndex > offset) {
high = mid - 1;
} else {
return {
line: mid + 1,
column:
mid === 0 ? offset + 1 : offset - this.lineBreakIndices[mid - 1],
offset,
};
}
}

const line = low + 1;
const lineStartIndex = low === 0 ? 0 : this.lineBreakIndices[low - 1] + 1;
const column = offset - lineStartIndex + 1;

return { line, column, offset };
}
}
8 changes: 4 additions & 4 deletions src/transforms/directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ export function transformDirective(
const parts = directive.source.trim().split(/[\t ]+/);
const name = parts.shift()!.replace(/^%/, "");
return createDirective(
context.transformRange({
origStart: directive.offset,
origEnd: directive.offset + directive.source.length,
}),
context.transformRange([
directive.offset,
directive.offset + directive.source.length,
]),
name,
parts,
);
Expand Down
5 changes: 1 addition & 4 deletions src/transforms/document-body.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,7 @@ function getPosition(
}
}

const position = context.transformRange({
origStart,
origEnd,
});
const position = context.transformRange([origStart, origEnd]);

const documentEndPoint = docEnd
? context.transformOffset(docEnd.offset + docEnd.source.length)
Expand Down
17 changes: 4 additions & 13 deletions src/transforms/document-head.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,22 +104,13 @@ function getPosition(
context: Context,
) {
const range: Range = docStart
? {
origStart: docStart.offset,
origEnd: docStart.offset + docStart.source.length,
}
? [docStart.offset, docStart.offset + docStart.source.length]
: document.contents
? {
origStart: document.contents.range[0],
origEnd: document.contents.range[0],
}
: {
origStart: document.range[0],
origEnd: document.range[0],
};
? [document.contents.range[0], document.contents.range[0]]
: [document.range[0], document.range[0]];

if (directives.length !== 0) {
range.origStart = directives[0].position.start.offset;
range[0] = directives[0].position.start.offset;
}

return context.transformRange(range);
Expand Down
5 changes: 1 addition & 4 deletions src/transforms/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ export function transformError(
return createError(
error.message,
context.text,
context.transformRange({
origStart: range[0],
origEnd: range[1],
}),
context.transformRange(range),
);
}
8 changes: 4 additions & 4 deletions src/transforms/flow-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ export function transformFlowMap(
}

return createFlowMapping(
context.transformRange({
origStart: srcToken.start.offset,
origEnd: flowMapEndToken.offset + flowMapEndToken.source.length,
}),
context.transformRange([
srcToken.start.offset,
flowMapEndToken.offset + flowMapEndToken.source.length,
]),
context.transformContentProperties(flowMap, props.tokens),
flowMappingItems,
);
Expand Down
8 changes: 4 additions & 4 deletions src/transforms/flow-seq.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,10 @@ export function transformFlowSeq(
}

return createFlowSequence(
context.transformRange({
origStart: srcToken.start.offset,
origEnd: flowSeqEndToken.offset + flowSeqEndToken.source.length,
}),
context.transformRange([
srcToken.start.offset,
flowSeqEndToken.offset + flowSeqEndToken.source.length,
]),
context.transformContentProperties(flowSeq, props.tokens),
flowSequenceItems,
);
Expand Down
34 changes: 13 additions & 21 deletions src/transforms/pair.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,7 @@ export function transformPair(
? explicitKeyIndToken.offset + explicitKeyIndToken.source.length
: // Fallback to start of key
keyStartOffset;
const keyRange = {
origStart: keyStartOffset,
origEnd: keyEndOffset,
};
const keyRange: Range = [keyStartOffset, keyEndOffset];

let valueRange: Range | null = null;
if (pair.value) {
Expand All @@ -117,10 +114,7 @@ export function transformPair(
? mapValueIndToken.offset + mapValueIndToken.source.length
: // Fallback to start of value
valueStartOffset;
valueRange = {
origStart: valueStartOffset,
origEnd: valueEndOffset,
};
valueRange = [valueStartOffset, valueEndOffset];
}

return transformAstPair(
Expand Down Expand Up @@ -154,29 +148,27 @@ function transformAstPair(
}

const mappingKey = createMappingKey(
context.transformRange({
origStart: additionalKeyData.range
? additionalKeyData.range.origStart
context.transformRange([
additionalKeyData.range
? additionalKeyData.range[0]
: keyContent!.position.start.offset,
origEnd: keyContent
? keyContent.position.end.offset
: additionalKeyData.range!.origEnd,
}),
keyContent ? keyContent.position.end.offset : additionalKeyData.range![1],
]),
keyContent as Exclude<typeof keyContent, Comment | Directive | Document>,
);

const mappingValue =
valueContent || additionalValueData.range
? createMappingValue(
context.transformRange({
origStart: additionalValueData.range
? additionalValueData.range.origStart
context.transformRange([
additionalValueData.range
? additionalValueData.range[0]
: // istanbul ignore next -- @preserve
valueContent!.position.start.offset,
origEnd: valueContent
valueContent
? valueContent.position.end.offset
: additionalValueData.range!.origStart + 1,
}),
: additionalValueData.range![0] + 1,
]),
valueContent as Exclude<
typeof valueContent,
Comment | Directive | Document
Expand Down
Loading
Loading