You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
79 lines
2.2 KiB
79 lines
2.2 KiB
import {Tree} from "@lezer/common" |
|
import {MarkdownParser} from ".." |
|
|
|
const abbrev: {[abbr: string]: string} = { |
|
__proto__: null as any, |
|
CB: "CodeBlock", |
|
FC: "FencedCode", |
|
Q: "Blockquote", |
|
HR: "HorizontalRule", |
|
BL: "BulletList", |
|
OL: "OrderedList", |
|
LI: "ListItem", |
|
H1: "ATXHeading1", |
|
H2: "ATXHeading2", |
|
H3: "ATXHeading3", |
|
H4: "ATXHeading4", |
|
H5: "ATXHeading5", |
|
H6: "ATXHeading6", |
|
SH1: "SetextHeading1", |
|
SH2: "SetextHeading2", |
|
HB: "HTMLBlock", |
|
PI: "ProcessingInstructionBlock", |
|
CMB: "CommentBlock", |
|
LR: "LinkReference", |
|
P: "Paragraph", |
|
Esc: "Escape", |
|
Ent: "Entity", |
|
BR: "HardBreak", |
|
Em: "Emphasis", |
|
St: "StrongEmphasis", |
|
Ln: "Link", |
|
Al: "Autolink", |
|
Im: "Image", |
|
C: "InlineCode", |
|
HT: "HTMLTag", |
|
CM: "Comment", |
|
Pi: "ProcessingInstruction", |
|
h: "HeaderMark", |
|
q: "QuoteMark", |
|
l: "ListMark", |
|
L: "LinkMark", |
|
e: "EmphasisMark", |
|
c: "CodeMark", |
|
cI: "CodeInfo", |
|
cT: "CodeText", |
|
LT: "LinkTitle", |
|
LL: "LinkLabel" |
|
} |
|
|
|
export class SpecParser { |
|
constructor(readonly parser: MarkdownParser, readonly localAbbrev?: {[name: string]: string}) {} |
|
|
|
type(name: string) { |
|
name = (this.localAbbrev && this.localAbbrev[name]) || abbrev[name] || name |
|
return this.parser.nodeSet.types.find(t => t.name == name)?.id |
|
} |
|
|
|
parse(spec: string, specName: string) { |
|
let doc = "", buffer = [], stack: number[] = [] |
|
for (let pos = 0; pos < spec.length; pos++) { |
|
let ch = spec[pos] |
|
if (ch == "{") { |
|
let name = /^(\w+):/.exec(spec.slice(pos + 1)), tag = name && this.type(name[1]) |
|
if (tag == null) throw new Error(`Invalid node opening mark at ${pos} in ${specName}`) |
|
pos += name![0].length |
|
stack.push(tag, doc.length, buffer.length) |
|
} else if (ch == "}") { |
|
if (!stack.length) throw new Error(`Mismatched node close mark at ${pos} in ${specName}`) |
|
let bufStart = stack.pop()!, from = stack.pop()!, type = stack.pop()! |
|
buffer.push(type, from, doc.length, 4 + buffer.length - bufStart) |
|
} else { |
|
doc += ch |
|
} |
|
} |
|
if (stack.length) throw new Error(`Unclosed node in ${specName}`) |
|
return {tree: Tree.build({buffer, nodeSet: this.parser.nodeSet, topID: this.type("Document")!, length: doc.length}), doc} |
|
} |
|
} |
|
|
|
|