more work on Markdown parsing, now with ordered lists
This commit is contained in:
parent
554c67229f
commit
d91bfeb527
|
@ -15,25 +15,21 @@ export default class MarkdownParser {
|
||||||
this.parseLinks = opt && opt.parseLinks || false;
|
this.parseLinks = opt && opt.parseLinks || false;
|
||||||
this.tabWidth = opt && opt.tabWidth || 4;
|
this.tabWidth = opt && opt.tabWidth || 4;
|
||||||
this.newlineBreaksArticles = opt && opt.newlineBreaksArticles || true;
|
this.newlineBreaksArticles = opt && opt.newlineBreaksArticles || true;
|
||||||
this.keepQuoteArrows = opt && opt.keepQuoteArrows || true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parse(text: string) {
|
parse(text: string) {
|
||||||
return this.parseText(text, 0, 0, '')[0];
|
return this.parseText(text, 0, 0)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
parseText(text, headingLevel, start, quoteLevel) {
|
parseText(text, headingLevel, start) {
|
||||||
let mdArray = [];
|
let mdArray = [];
|
||||||
let iter = start;
|
let iter = start;
|
||||||
while (iter < text.length) {
|
while (iter < text.length) {
|
||||||
const [aMdArray, newIter, breaking] = this.parseSection(
|
const [aMdArray, newIter] = this.parseSection(
|
||||||
text, iter, headingLevel, quoteLevel,
|
text, iter, headingLevel,
|
||||||
);
|
);
|
||||||
iter = newIter;
|
iter = newIter;
|
||||||
mdArray = mdArray.concat(aMdArray);
|
mdArray = mdArray.concat(aMdArray);
|
||||||
if (breaking) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// either heading hit or article end
|
// either heading hit or article end
|
||||||
const chr = text[iter];
|
const chr = text[iter];
|
||||||
if (chr === '#') {
|
if (chr === '#') {
|
||||||
|
@ -53,18 +49,11 @@ export default class MarkdownParser {
|
||||||
const title = text.slice(iter + subLvl, lineEnd).trimLeft();
|
const title = text.slice(iter + subLvl, lineEnd).trimLeft();
|
||||||
subLvl = Math.min(subLvl, 6);
|
subLvl = Math.min(subLvl, 6);
|
||||||
const [subMdArray, newIter] = this.parseText(
|
const [subMdArray, newIter] = this.parseText(
|
||||||
text, subLvl, lineEnd + 1, quoteLevel,
|
text, subLvl, lineEnd + 1,
|
||||||
);
|
);
|
||||||
mdArray.push(['a', subLvl, title, subMdArray]);
|
mdArray.push(['a', subLvl, title, subMdArray]);
|
||||||
iter = newIter;
|
iter = newIter;
|
||||||
}
|
}
|
||||||
} else if (chr === '>' || chr === '<') {
|
|
||||||
// child quote
|
|
||||||
const [subMdArray, newIter] = this.parseText(
|
|
||||||
text, 0, iter - quoteLevel.length, quoteLevel + chr,
|
|
||||||
);
|
|
||||||
mdArray.push([chr, subMdArray]);
|
|
||||||
iter = newIter;
|
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -97,26 +86,15 @@ export default class MarkdownParser {
|
||||||
text: string,
|
text: string,
|
||||||
start: number,
|
start: number,
|
||||||
headingLevel = 0,
|
headingLevel = 0,
|
||||||
quoteLevel = '',
|
|
||||||
indent = 0,
|
indent = 0,
|
||||||
) {
|
) {
|
||||||
let iter = start;
|
let iter = start;
|
||||||
/*
|
|
||||||
* breaking is currently only used when
|
|
||||||
* end of quote block is reached
|
|
||||||
*/
|
|
||||||
let breaking = false;
|
|
||||||
const mdArray = [];
|
const mdArray = [];
|
||||||
let paraStart = iter;
|
let paraStart = iter;
|
||||||
let lineNr = 0;
|
let lineNr = 0;
|
||||||
|
|
||||||
const addParagraph = (start, end) => {
|
const addParagraph = (start, end) => {
|
||||||
let paraText = text.slice(start, end);
|
let paraText = text.slice(start, end);
|
||||||
if (!this.keepQuoteArrows && quoteLevel) {
|
|
||||||
paraText = paraText.split('\n')
|
|
||||||
.map((t) => t.trim().slice(quoteLevel.length))
|
|
||||||
.join('\n');
|
|
||||||
}
|
|
||||||
mdArray.push(['p', paraText]);
|
mdArray.push(['p', paraText]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,32 +109,6 @@ export default class MarkdownParser {
|
||||||
const paraLineStart = iter;
|
const paraLineStart = iter;
|
||||||
lineNr += 1;
|
lineNr += 1;
|
||||||
|
|
||||||
/*
|
|
||||||
* break when in or out of quote levels
|
|
||||||
*/
|
|
||||||
if (!indent || lineNr > 1) {
|
|
||||||
if (text.startsWith(quoteLevel, iter)) {
|
|
||||||
iter += quoteLevel.length;
|
|
||||||
const chr = text[iter];
|
|
||||||
if (chr === '>' || chr === '<') {
|
|
||||||
if (iter - 1 > paraStart) {
|
|
||||||
addParagraph(paraStart, iter - quoteLevel.length - 1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// quote ended aka less deep quotelevel
|
|
||||||
if (iter - 1 > paraStart) {
|
|
||||||
addParagraph(paraStart, iter - 1);
|
|
||||||
}
|
|
||||||
breaking = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
iter += quoteLevel.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* act on indent
|
* act on indent
|
||||||
*/
|
*/
|
||||||
|
@ -172,29 +124,62 @@ export default class MarkdownParser {
|
||||||
|
|
||||||
const chr = text[iter];
|
const chr = text[iter];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* unordered list
|
||||||
|
*/
|
||||||
|
let isUnorderedList = false;
|
||||||
|
let isOrderedList = false;
|
||||||
if (chr === '-') {
|
if (chr === '-') {
|
||||||
|
isUnorderedList = true;
|
||||||
|
iter += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ordered list
|
||||||
|
*/
|
||||||
|
if (!Number.isNaN(parseInt(chr))) {
|
||||||
|
let itern = iter + 1;
|
||||||
|
for(;!Number.isNaN(parseInt(text[itern])); itern += 1){}
|
||||||
|
if (text[itern] === '.' || text[itern] === ')') {
|
||||||
|
isOrderedList = true;
|
||||||
|
iter = itern + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isUnorderedList || isOrderedList) {
|
||||||
if (paraLineStart - 1 > paraStart) {
|
if (paraLineStart - 1 > paraStart) {
|
||||||
addParagraph(paraStart, paraLineStart - 1);
|
addParagraph(paraStart, paraLineStart - 1);
|
||||||
}
|
}
|
||||||
let childMdArray;
|
let childMdArray;
|
||||||
[childMdArray, iter, breaking] = this.parseSection(
|
[childMdArray, iter] = this.parseSection(
|
||||||
text,
|
text,
|
||||||
iter + 1,
|
iter,
|
||||||
headingLevel,
|
headingLevel,
|
||||||
quoteLevel,
|
|
||||||
curIndent + 1,
|
curIndent + 1,
|
||||||
);
|
);
|
||||||
childMdArray = ['-', childMdArray];
|
childMdArray = ['-', childMdArray];
|
||||||
// lists are encapsuled by 'ul'
|
// lists are encapsuled
|
||||||
if (!mdArray.length || mdArray[mdArray.length - 1][0] !== 'ul') {
|
const capsule = (isUnorderedList) ? 'ul' : 'ol';
|
||||||
mdArray.push(['ul', [childMdArray]]);
|
if (!mdArray.length || mdArray[mdArray.length - 1][0] !== capsule) {
|
||||||
|
mdArray.push([capsule, [childMdArray]]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mdArray[mdArray.length - 1][1].push(childMdArray);
|
mdArray[mdArray.length - 1][1].push(childMdArray);
|
||||||
}
|
}
|
||||||
if (breaking) {
|
paraStart = iter;
|
||||||
return [mdArray, iter, breaking];
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* quotes
|
||||||
|
*/
|
||||||
|
if (chr === '>' || chr === '<') {
|
||||||
|
if (paraLineStart - 1 > paraStart) {
|
||||||
|
addParagraph(paraStart, paraLineStart - 1);
|
||||||
}
|
}
|
||||||
|
const [qArray, newIter] = this.parseQuote(text, iter);
|
||||||
|
mdArray.push(qArray);
|
||||||
|
iter = newIter;
|
||||||
paraStart = iter;
|
paraStart = iter;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -239,12 +224,7 @@ export default class MarkdownParser {
|
||||||
iter += 1;
|
iter += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [mdArray, iter, breaking];
|
return [mdArray, iter];
|
||||||
}
|
|
||||||
|
|
||||||
parseList(text: string, start: number) {
|
|
||||||
const iter = start;
|
|
||||||
const mdArray = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -276,8 +256,11 @@ export default class MarkdownParser {
|
||||||
* we just parse till the ending occures
|
* we just parse till the ending occures
|
||||||
*/
|
*/
|
||||||
parseCodeBlock(text, start) {
|
parseCodeBlock(text, start) {
|
||||||
const cbStart = this.skipSpaces(text, start, true);
|
let iter = this.skipSpaces(text, start, false);
|
||||||
let iter = cbStart;
|
if (text[iter] === '\n') {
|
||||||
|
iter += 1;
|
||||||
|
}
|
||||||
|
const cbStart = iter;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (iter >= text.length) {
|
if (iter >= text.length) {
|
||||||
return [['cb', text.slice(cbStart)], iter];
|
return [['cb', text.slice(cbStart)], iter];
|
||||||
|
@ -294,6 +277,27 @@ export default class MarkdownParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* parse quote
|
||||||
|
*/
|
||||||
|
parseQuote(text, start) {
|
||||||
|
// either '<' or '>'
|
||||||
|
const quoteChar = text[start];
|
||||||
|
let iter = start;
|
||||||
|
let quoteText = '';
|
||||||
|
while(true) {
|
||||||
|
if (iter >= text.length || text[iter] !== quoteChar) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iter += 1;
|
||||||
|
const startLine = iter;
|
||||||
|
for (;iter < text.length && text[iter] !== '\n'; iter += 1) {}
|
||||||
|
iter += 1;
|
||||||
|
quoteText += text.slice(startLine, iter);
|
||||||
|
}
|
||||||
|
return [[quoteChar, this.parseText(quoteText, 0, 0)[0]], iter];
|
||||||
|
}
|
||||||
|
|
||||||
skipSpaces(text: string, start: number, skipNewlines = false) {
|
skipSpaces(text: string, start: number, skipNewlines = false) {
|
||||||
let iter = start;
|
let iter = start;
|
||||||
for (;iter < text.length; iter += 1) {
|
for (;iter < text.length; iter += 1) {
|
||||||
|
@ -304,58 +308,4 @@ export default class MarkdownParser {
|
||||||
}
|
}
|
||||||
return iter;
|
return iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseIndents(text: string) {
|
|
||||||
const lines = text.split('\n');
|
|
||||||
const indents = [];
|
|
||||||
const { tabWidth } = this;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get indentation of lines
|
|
||||||
* @param text: string of text to parse
|
|
||||||
* @return [indents, lines]:
|
|
||||||
* indents: Array of normalized numerical indents
|
|
||||||
* lines: Array of trimmed lines
|
|
||||||
*/
|
|
||||||
for (let i = 0; i < lines.length; i += 1) {
|
|
||||||
const line = lines[i];
|
|
||||||
let indent = 0;
|
|
||||||
for (let c = 0; c < line.length; c += 1) {
|
|
||||||
const chr = line[c];
|
|
||||||
if (chr === '\t') {
|
|
||||||
indent += this.tabWidth;
|
|
||||||
} else if (chr === ' ') {
|
|
||||||
indent += 1;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lines[i] = line.trim();
|
|
||||||
indents.push(indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// normalize
|
|
||||||
let min = indents[0];
|
|
||||||
let max = indents[0];
|
|
||||||
for (let m = 0; m < indents.length; m += 1) {
|
|
||||||
const indent = indents[m];
|
|
||||||
if (indent < min) min = indent;
|
|
||||||
if (indent > max) max = indent;
|
|
||||||
}
|
|
||||||
let cnt = 0;
|
|
||||||
console.log(min, max);
|
|
||||||
for (let n = min; n <= max; n += 1) {
|
|
||||||
let available = false;
|
|
||||||
for (let c = 0; c < indents.length; c += 1) {
|
|
||||||
if (indents[c] === n) {
|
|
||||||
if (!available) available = true;
|
|
||||||
indents[c] = cnt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (available) cnt += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(lines);
|
|
||||||
console.log(indents);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,14 @@ const Markdown = ({ mdArray }) => {
|
||||||
</ul>
|
</ul>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
case 'ol': {
|
||||||
|
const children = part[1];
|
||||||
|
return (
|
||||||
|
<ol>
|
||||||
|
<Markdown mdArray={children} />
|
||||||
|
</ol>
|
||||||
|
);
|
||||||
|
}
|
||||||
case '-': {
|
case '-': {
|
||||||
const children = part[1];
|
const children = part[1];
|
||||||
return (
|
return (
|
||||||
|
|
Loading…
Reference in New Issue
Block a user