Added markdown rendering
This commit is contained in:
parent
26ca510785
commit
5a0340c226
172 changed files with 12198 additions and 8338 deletions
192
static/js/lib/node_modules/marked-token-position/src/index.ts
generated
vendored
Normal file
192
static/js/lib/node_modules/marked-token-position/src/index.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
/* node:coverage ignore next */
|
||||
import type { MarkedExtension, Token, Tokens } from 'marked';
|
||||
|
||||
export interface TokenWithPosition extends Tokens.Generic {
|
||||
position: Position;
|
||||
}
|
||||
interface Position {
|
||||
/**
|
||||
* Positions for each line of the token. LinePositions will not include the newline character for the line.
|
||||
*/
|
||||
lines: LinePosition[]
|
||||
/**
|
||||
* Position at the beginning of token
|
||||
*/
|
||||
start: PositionFields;
|
||||
/**
|
||||
* Position at the end of token
|
||||
*/
|
||||
end: PositionFields;
|
||||
}
|
||||
|
||||
interface LinePosition {
|
||||
/**
|
||||
* Position at the beginning of line
|
||||
*/
|
||||
start: PositionFields;
|
||||
/**
|
||||
* Position at the end of line. Will not include the newline character.
|
||||
*/
|
||||
end: PositionFields;
|
||||
}
|
||||
|
||||
interface PositionFields {
|
||||
/**
|
||||
* Number of characters from the beginning of the markdown string
|
||||
*/
|
||||
offset: number;
|
||||
/**
|
||||
* Line number of the token. Starts at line 0.
|
||||
*/
|
||||
line: number;
|
||||
/**
|
||||
* Column number of the token. Starts at column 0.
|
||||
*/
|
||||
column: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add position field to tokens
|
||||
*/
|
||||
export function addTokenPositions(tokens: Token[]) {
|
||||
const markdown = tokens.map(token => token.raw).join('');
|
||||
return addPosition(tokens, 0, 0, 0, markdown).tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marked extension to add position field to tokens
|
||||
*/
|
||||
export default function(options = {}): MarkedExtension {
|
||||
return {
|
||||
hooks: {
|
||||
processAllTokens(tokens) {
|
||||
return addTokenPositions(tokens);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function addPosition(tokens: Token[], offset: number, line: number, column: number, markdown: string) {
|
||||
for (const token of tokens) {
|
||||
const genericToken = token as Tokens.Generic;
|
||||
const position = getPosition(offset, line, column, markdown, genericToken.raw);
|
||||
genericToken.position = position;
|
||||
|
||||
if (genericToken.tokens) {
|
||||
addPosition(genericToken.tokens, offset, line, column, markdown);
|
||||
}
|
||||
|
||||
if (genericToken.childTokens) {
|
||||
let nextOffset = offset;
|
||||
let nextLine = line;
|
||||
let nextColumn = column;
|
||||
let nextMarkdown = markdown;
|
||||
for (const childToken of genericToken.childTokens) {
|
||||
const nextPosition = addPosition(genericToken[childToken], nextOffset, nextLine, nextColumn, nextMarkdown);
|
||||
nextOffset = nextPosition.offset;
|
||||
nextLine = nextPosition.line;
|
||||
nextColumn = nextPosition.column;
|
||||
nextMarkdown = nextPosition.markdown;
|
||||
}
|
||||
}
|
||||
|
||||
if (genericToken.type === 'list') {
|
||||
addPosition(genericToken.items, offset, line, column, markdown);
|
||||
}
|
||||
|
||||
if (genericToken.type === 'table') {
|
||||
let nextOffset = offset;
|
||||
let nextLine = line;
|
||||
let nextColumn = column;
|
||||
let nextMarkdown = markdown;
|
||||
for (const headerCell of genericToken.header) {
|
||||
const nextPosition = addPosition(headerCell.tokens, nextOffset, nextLine, nextColumn, nextMarkdown);
|
||||
nextOffset = nextPosition.offset;
|
||||
nextLine = nextPosition.line;
|
||||
nextColumn = nextPosition.column;
|
||||
nextMarkdown = nextPosition.markdown;
|
||||
}
|
||||
for (const row of genericToken.rows) {
|
||||
for (const rowCell of row) {
|
||||
const nextPosition = addPosition(rowCell.tokens, nextOffset, nextLine, nextColumn, nextMarkdown);
|
||||
nextOffset = nextPosition.offset;
|
||||
nextLine = nextPosition.line;
|
||||
nextColumn = nextPosition.column;
|
||||
nextMarkdown = nextPosition.markdown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const deltaOffset = position.end.offset - offset;
|
||||
offset = position.end.offset;
|
||||
line = position.end.line;
|
||||
column = position.end.column;
|
||||
markdown = markdown.slice(deltaOffset);
|
||||
}
|
||||
|
||||
return {
|
||||
tokens: tokens as TokenWithPosition[],
|
||||
offset,
|
||||
line,
|
||||
column,
|
||||
markdown,
|
||||
};
|
||||
}
|
||||
|
||||
function getPosition(offset: number, line: number, column: number, markdown: string, raw: string): Position {
|
||||
let lines: LinePosition[] = [];
|
||||
const rawLines = raw.split('\n');
|
||||
const markdownLines = markdown.split('\n');
|
||||
|
||||
// eslint-disable-next-line no-labels
|
||||
md: for (let i = 0; i <= markdownLines.length - rawLines.length; i++) {
|
||||
lines = [];
|
||||
for (let j = 0; j < rawLines.length; j++) {
|
||||
const markdownLine = markdownLines[i + j];
|
||||
const rawLine = rawLines[j];
|
||||
const lineStartOffset = markdownLine.indexOf(rawLine);
|
||||
|
||||
if (lineStartOffset === -1) {
|
||||
// eslint-disable-next-line no-labels
|
||||
continue md;
|
||||
}
|
||||
|
||||
const beforeMarkdownLines = markdownLines.slice(0, i + j).join('\n') + (i + j > 0 ? '\n' : '');
|
||||
const start = {
|
||||
offset: offset + beforeMarkdownLines.length + lineStartOffset,
|
||||
line: line + i + j,
|
||||
column: (i + j === 0 ? column : 0) + lineStartOffset,
|
||||
};
|
||||
const end = {
|
||||
offset: start.offset + rawLine.length,
|
||||
line: start.line,
|
||||
column: start.column + rawLine.length,
|
||||
};
|
||||
|
||||
lines.push({
|
||||
start,
|
||||
end,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* node:coverage ignore next 4 */
|
||||
if (lines.length === 0) {
|
||||
// This shouldn't ever happen but if it does it would be nice to have a good error message
|
||||
throw new Error(`Cannot find ${JSON.stringify(raw)} in ${JSON.stringify(markdown)}`);
|
||||
}
|
||||
|
||||
const start = lines[0].start;
|
||||
const end = lines.at(-1)!.end;
|
||||
|
||||
if (lines.length > 1 && lines.at(-1)!.start.offset === end.offset) {
|
||||
lines = lines.slice(0, -1);
|
||||
}
|
||||
|
||||
return {
|
||||
lines,
|
||||
start,
|
||||
end,
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue