80 lines
1.9 KiB
TypeScript
80 lines
1.9 KiB
TypeScript
export type FenceSpan = {
|
|
start: number;
|
|
end: number;
|
|
openLine: string;
|
|
marker: string;
|
|
indent: string;
|
|
};
|
|
|
|
export function parseFenceSpans(buffer: string): FenceSpan[] {
|
|
const spans: FenceSpan[] = [];
|
|
let open:
|
|
| {
|
|
start: number;
|
|
markerChar: string;
|
|
markerLen: number;
|
|
openLine: string;
|
|
marker: string;
|
|
indent: string;
|
|
}
|
|
| undefined;
|
|
|
|
let offset = 0;
|
|
while (offset <= buffer.length) {
|
|
const nextNewline = buffer.indexOf("\n", offset);
|
|
const lineEnd = nextNewline === -1 ? buffer.length : nextNewline;
|
|
const line = buffer.slice(offset, lineEnd);
|
|
|
|
const match = line.match(/^( {0,3})(`{3,}|~{3,})(.*)$/);
|
|
if (match) {
|
|
const indent = match[1];
|
|
const marker = match[2];
|
|
const markerChar = marker[0];
|
|
const markerLen = marker.length;
|
|
if (!open) {
|
|
open = {
|
|
start: offset,
|
|
markerChar,
|
|
markerLen,
|
|
openLine: line,
|
|
marker,
|
|
indent,
|
|
};
|
|
} else if (open.markerChar === markerChar && markerLen >= open.markerLen) {
|
|
const end = lineEnd;
|
|
spans.push({
|
|
start: open.start,
|
|
end,
|
|
openLine: open.openLine,
|
|
marker: open.marker,
|
|
indent: open.indent,
|
|
});
|
|
open = undefined;
|
|
}
|
|
}
|
|
|
|
if (nextNewline === -1) break;
|
|
offset = nextNewline + 1;
|
|
}
|
|
|
|
if (open) {
|
|
spans.push({
|
|
start: open.start,
|
|
end: buffer.length,
|
|
openLine: open.openLine,
|
|
marker: open.marker,
|
|
indent: open.indent,
|
|
});
|
|
}
|
|
|
|
return spans;
|
|
}
|
|
|
|
export function findFenceSpanAt(spans: FenceSpan[], index: number): FenceSpan | undefined {
|
|
return spans.find((span) => index > span.start && index < span.end);
|
|
}
|
|
|
|
export function isSafeFenceBreak(spans: FenceSpan[], index: number): boolean {
|
|
return !findFenceSpanAt(spans, index);
|
|
}
|