import type { Content, Parent, Root, RootContent } from 'mdast' const escapeForRegExp = (s: string) => s.replace (/[.*+?^${}()|[\]\\]/g, '\\$&') export default (pageNames: string[], basePath = '/wiki'): ((tree: Root) => void) => { const names = [...pageNames].sort ((a, b) => b.length - a.length) if (names.length === 0) { return () => { ; } } const re = new RegExp (`(${ names.map (escapeForRegExp).join ('|') })`, 'g') return (tree: Root) => { const edits: { parent: Parent; index: number; parts: RootContent[] }[] = [] const walk = (node: Content | Root, ancestors: Parent[]) => { if (!(node) || (typeof node !== 'object')) return if (!(ancestors.some (ancestor => ['link', 'linkReference', 'image', 'imageReference', 'code', 'inlineCode'].includes (ancestor?.type))) && (node.type === 'text')) { const value = node.value ?? '' if (value) { re.lastIndex = 0 let m: RegExpExecArray | null let last = 0 const parts: RootContent[] = [] while (m = re.exec (value)) { const start = m.index const end = start + m[0].length if (start > last) parts.push ({ type: 'text', value: value.slice (last, start) }) const name = m[1] parts.push ({ type: 'link', url: `${ basePath }/${ encodeURIComponent (name) }`, title: null, children: [{ type: 'text', value: name }], data: { hProperties: { 'data-wiki': '1' } } }) last = end } if (parts.length) { if (last < value.length) parts.push ({ type: 'text', value: value.slice (last) }) const parent = ancestors[ancestors.length - 1] if (parent && Array.isArray (parent.children)) { const index = parent.children.indexOf (node) if (index >= 0) edits.push ({ parent, index, parts }) } } } } const maybeChidren = (node as any).children if (Array.isArray (maybeChidren)) { const parent = node as Parent for (let i = 0; i < maybeChidren.length; ++i) { const child: Content | undefined = maybeChidren[i] if (!(child)) continue walk (child, ancestors.concat (parent)) } } } walk (tree, []) for (let i = edits.length - 1; i >= 0; --i) { const { parent, index, parts } = edits[i] if (!(parent) || !(Array.isArray (parent.children))) continue if (0 <= index && index < parent.children.length) parent.children.splice (index, 1, ...parts) } } }