feat: Wiki 自動リンクをテキスト領域のみに制限(#93) (#218)
Merge branch 'main' into #93 #93 Merge remote-tracking branch 'origin/main' into #93 #93 #93 Co-authored-by: miteruzo <miteruzo@naver.com> Reviewed-on: #218
This commit was merged in pull request #218.
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user