UNPKG

@mieweb/wikigdrive

Version:

Google Drive to MarkDown synchronization

192 lines (154 loc) 5.72 kB
import {MarkdownNodes, TagPayload} from '../MarkdownNodes.ts'; import {walkRecursiveSync} from '../markdownNodesUtils.ts'; export function processListsAndNumbering(markdownChunks: MarkdownNodes) { const body = markdownChunks.body; const counters: { [id: string]: number } = {}; let preserveMinLevel = 999; function fetchListNo(styleName: string) { if (counters[styleName]) { return counters[styleName]; } return 0; } function storeListNo(styleName: string, val: number) { if (!styleName) { return; } counters[styleName] = val; } function clearListsNo(styleNamePrefix: string, minLevel: number) { for (const k in counters) { if (!k.startsWith(styleNamePrefix)) { continue; } const level = parseInt(k.substring(styleNamePrefix.length)); if (level < minLevel) { continue; } if (level > minLevel + 1) { // continue; } counters[k] = 0; } } function getTopListStyleName(): string { for (let i = stack.length - 1; i >=0; i--) { const leaf = stack[i]; if (leaf?.payload?.listStyle?.name) { return leaf.payload.listStyle.name; } } return null; } function topElement<A>(stack: A[]): A { if (stack.length === 0) { return null; } return stack[stack.length - 1]; } const stack: Array<{ tag: string, payload: TagPayload }> = []; stack.push({ tag: 'BODY', payload: {} }); const margins = {}; // let lastItem = null; walkRecursiveSync(body, (chunk, ctx: { level: number }) => { if (!chunk.isTag) { return; } const tag = chunk.tag; const parentLevel = topElement(stack); if (['TOC', 'UL', 'LI', 'P'].includes(tag)) { stack.push({ tag, payload: chunk.payload }); } else { return ; } const listLevel = stack.filter(item => item.tag === 'UL').length; const currentElement = topElement(stack); if ('UL' === currentElement.tag) { currentElement.payload.listLevel = listLevel; if (currentElement.payload.continueNumbering || currentElement.payload.continueList) { preserveMinLevel = listLevel; } const listStyleName = (currentElement.payload.listStyle?.name || getTopListStyleName()) + '_' + listLevel; if (!(preserveMinLevel <= listLevel)) { clearListsNo((currentElement.payload.listStyle?.name || getTopListStyleName()) + '_', listLevel); } else { currentElement.payload.number = fetchListNo(listStyleName) + 1; currentElement.payload.continueNumbering = true; } const firstChild = chunk.children[0]; if (firstChild && firstChild.isTag && firstChild.tag === 'LI') { const firstGrandChild = firstChild.children[0]; if (firstGrandChild && firstGrandChild.isTag && firstGrandChild.tag !== 'P') { currentElement.payload.continueNumbering = true; } } } if ('LI' === currentElement.tag) { if (parentLevel?.tag === 'UL') { currentElement.payload.listLevel = parentLevel.payload.listLevel; const listStyleName = (currentElement.payload.listStyle?.name || getTopListStyleName()) + '_' + currentElement.payload.listLevel; if (!(chunk.children.length > 0 && chunk.children[0].isTag && chunk.children[0].tag === 'UL')) { // Has para, increase number currentElement.payload.number = currentElement.payload.number || fetchListNo(listStyleName); currentElement.payload.number++; storeListNo(listStyleName, currentElement.payload.number); } } } if ('P' === currentElement.tag) { if (parentLevel?.tag === 'LI') { if (!margins[currentElement.payload.marginLeft]) { margins[currentElement.payload.marginLeft] = listLevel; } let level = parentLevel.payload.listLevel; if (margins[currentElement.payload.marginLeft]) { level = margins[currentElement.payload.marginLeft]; } const listStyle = parentLevel.payload.listStyle || currentElement.payload.listStyle; const listLevelStyleNumber = listStyle?.listLevelStyleNumber.find(i => i.level == listLevel); currentElement.payload.listLevel = level; parentLevel.payload.listLevel = level; const firstLevelStyleNumber = listStyle?.listLevelStyleNumber ? listStyle?.listLevelStyleNumber[0] : undefined; currentElement.payload.numFormat = listLevelStyleNumber?.numFormat; parentLevel.payload.numFormat = listLevelStyleNumber?.numFormat; if (listLevelStyleNumber?.numFormat) { currentElement.payload.number = parentLevel.payload.number; if (firstLevelStyleNumber?.startValue) { currentElement.payload.number = +firstLevelStyleNumber.startValue; parentLevel.payload.number = +firstLevelStyleNumber.startValue; } } else { currentElement.payload.bullet = true; parentLevel.payload.bullet = true; } } } return { ...ctx, level: ctx.level + 1 }; }, { level: 0 }, (chunk) => { if (!chunk.isTag) { return; } const tag = chunk.tag; if ('LI' === tag) { const parentElement = chunk.parent; if (parentElement?.tag === 'UL') { // parentElement.payload.listLevel = chunk.payload.listLevel; } } if (['TOC', 'UL', 'LI', 'P'].includes(tag)) { const currentLevel = topElement(stack); chunk.payload.listLevel = currentLevel.payload.listLevel; stack.pop(); if (tag === 'UL') { // this.listLevel--; preserveMinLevel = 999; } return ; } }); }