vitepress-allyouneed 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/index.cjs +14 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +14 -8
- package/dist/index.js.map +1 -1
- package/dist/markdown-it.d.cts +1 -1
- package/dist/markdown-it.d.ts +1 -1
- package/dist/{types-Nx7d15xb.d.cts → types-BLbN9Pg6.d.cts} +9 -0
- package/dist/{types-Nx7d15xb.d.ts → types-BLbN9Pg6.d.ts} +9 -0
- package/dist/vite.d.cts +1 -1
- package/dist/vite.d.ts +1 -1
- package/dist/vitepress.cjs +14 -8
- package/dist/vitepress.cjs.map +1 -1
- package/dist/vitepress.d.cts +1 -1
- package/dist/vitepress.d.ts +1 -1
- package/dist/vitepress.js +14 -8
- package/dist/vitepress.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/core/slugify.ts","../src/core/config-bridge.ts","../src/core/vault/index.ts","../src/utils/path.ts","../src/utils/url.ts","../src/core/vault/scan.ts","../src/core/vault/ignore.ts","../src/core/vault/frontmatter.ts","../src/core/vault/headings.ts","../src/core/resolver.ts","../src/modules/wikilinks/render.ts","../src/utils/escape.ts","../src/core/asset-pipeline/build-emit.ts","../src/modules/embeds/image.ts","../src/modules/embeds/transclusion.ts","../src/modules/embeds/media.ts","../src/modules/wikilinks/rule.ts","../src/modules/wikilinks/index.ts","../src/modules/embeds/block-rule.ts","../src/modules/embeds/index.ts","../src/modules/callouts/types.ts","../src/modules/callouts/rule.ts","../src/modules/callouts/index.ts","../src/modules/highlight/rule.ts","../src/modules/highlight/index.ts","../src/modules/comments/rule.ts","../src/modules/comments/index.ts","../src/modules/footnotes/rule.ts","../src/modules/block-refs/rule.ts","../src/markdown-it.ts","../src/vite.ts","../src/core/asset-pipeline/dev-middleware.ts","../src/core/views/generate-md.ts","../src/core/views/generate-data.ts","../src/modules/tags/rule.ts","../src/core/views/sidebar-inject.ts","../src/core/sidebar-auto/parse-sidebar-md.ts","../src/core/sidebar-auto/generate.ts","../src/core/sidebar-auto/generate-folder-index.ts","../src/core/scan-wikilinks.ts","../src/vitepress.ts"],"sourcesContent":["/**\n * 默认入口 —— 主要导出 markdown-it 插件函数,并把其它常用 API re-export\n * 出来,方便高级用户从同一个包名取所有东西。\n */\n\nexport { default } from './markdown-it.js'\nexport { allYouNeedMarkdownIt } from './markdown-it.js'\n\nexport { viteAllYouNeed } from './vite.js'\nexport { defineConfigWithAllYouNeed } from './vitepress.js'\n\nexport { resolveOptions } from './core/config-bridge.js'\nexport {\n scanVault,\n createEmptyIndex,\n updateFile,\n removeFile,\n} from './core/vault/index.js'\nexport { resolveWikilink, resolveAsset } from './core/resolver.js'\nexport { defaultSlugify, extractCustomId } from './core/slugify.js'\n\nexport type {\n AllYouNeedOptions,\n ResolvedOptions,\n VaultIndex,\n FileEntry,\n AssetEntry,\n HeadingEntry,\n BacklinkEntry,\n ScanWarning,\n AllYouNeedEnv,\n ResolveResult,\n WikilinksModuleOptions,\n EmbedsModuleOptions,\n ScanOptions,\n AssetsOptions,\n PageLinkAttrs,\n PageLinkAttrsContext,\n ImageEmbedAttrs,\n ImageEmbedAttrsContext,\n} from './core/types.js'\n","/**\n * 锚点 slugifier。\n *\n * 默认用 @mdit-vue/shared 的 slugify —— 这是 VitePress 内部 markdown-it-anchor\n * 默认使用的实现,保证我们算出的 slug 和 anchor ID 100% 对得上(包括中文)。\n *\n * 用户在 VitePress 里覆写了 markdown.anchor.slugify 时,ConfigBridge 会把\n * 用户的函数读出来传给 ResolvedOptions.slugify,Resolver 直接用,无需走这里。\n */\n\nimport { slugify as mditVueSlugify } from '@mdit-vue/shared'\n\n/**\n * 默认 slugifier。\n */\nexport function defaultSlugify(text: string): string {\n return mditVueSlugify(text)\n}\n\n/**\n * 处理 `## 标题 {#custom-id}` 这种自定义 anchor 语法,\n * 返回 `{ text: '标题', slug: 'custom-id' | undefined }`。\n *\n * markdown-it-anchor 默认启用此扩展(`permalink.linkInsideHeader` 等无关),\n * 我们的 heading 收集器要做相同识别,否则 [[Page#标题]] 会按 slugify('标题')\n * 算,而 markdown-it-anchor 实际用了 'custom-id',结果不匹配。\n */\nconst CUSTOM_ID_RE = /\\s*\\{#([^}\\s]+)\\}\\s*$/\n\nexport function extractCustomId(headingText: string): {\n text: string\n customId: string | undefined\n} {\n const m = headingText.match(CUSTOM_ID_RE)\n if (!m) return { text: headingText, customId: undefined }\n return {\n text: headingText.replace(CUSTOM_ID_RE, ''),\n customId: m[1],\n }\n}\n","/**\n * VitePress / Vite 配置桥接。\n *\n * 负责把外部配置(VitePress site config、Vite 的 ResolvedConfig)和用户传入\n * 的插件选项合并,产出一份 ResolvedOptions —— 所有字段都填值,后续模块只看这份。\n */\n\nimport type {\n AllYouNeedOptions,\n ResolvedOptions,\n PageLinkAttrs,\n ImageEmbedAttrs,\n} from './types.js'\nimport { defaultSlugify } from './slugify.js'\n\nconst DEFAULT_ASSET_EXTENSIONS = [\n // 位图\n 'bmp',\n 'gif',\n 'jpeg',\n 'jpg',\n 'png',\n 'svg',\n 'webp',\n 'avif',\n 'ico',\n // 视频\n 'mp4',\n 'webm',\n 'mov',\n 'm4v',\n // 音频\n 'mp3',\n 'wav',\n 'ogg',\n 'm4a',\n 'flac',\n // 文档\n 'pdf',\n // Obsidian 专属\n 'canvas',\n 'excalidraw',\n]\n\nconst DEFAULT_IMAGE_EXTENSIONS = [\n 'bmp',\n 'gif',\n 'jpeg',\n 'jpg',\n 'png',\n 'svg',\n 'webp',\n 'avif',\n 'ico',\n]\n\n/**\n * 合并默认值与用户配置,产出 ResolvedOptions。\n *\n * @param user 用户传入(可能为空对象)\n * @param ctx 外部上下文(VitePress / Vite 决议出的值)\n */\nexport function resolveOptions(\n user: AllYouNeedOptions = {},\n ctx: {\n srcDir?: string\n base?: string\n cleanUrls?: boolean\n /** VitePress markdown.anchor.slugify 若被用户覆写 */\n externalSlugify?: (text: string) => string\n } = {},\n): ResolvedOptions {\n const srcDir = user.srcDir ?? ctx.srcDir ?? process.cwd()\n let base = user.base ?? ctx.base ?? '/'\n if (!base.startsWith('/')) base = '/' + base\n if (!base.endsWith('/')) base = base + '/'\n\n const cleanUrls = user.cleanUrls ?? ctx.cleanUrls ?? false\n const slugify = user.slugify ?? ctx.externalSlugify ?? defaultSlugify\n\n const wikilinksUser = user.wikilinks ?? {}\n const embedsUser = user.embeds ?? {}\n const scanUser = user.scan ?? {}\n const assetsUser = user.assets ?? {}\n const modulesUser = user.modules ?? {}\n const viewsUser = user.views ?? {}\n\n const wikilinksHtmlAttrs: PageLinkAttrs = wikilinksUser.htmlAttributes ?? {}\n const embedsHtmlAttrs: ImageEmbedAttrs = embedsUser.htmlAttributes ?? {}\n\n return {\n srcDir,\n base,\n cleanUrls,\n caseSensitive: user.caseSensitive ?? false,\n deadLink: user.deadLink ?? 'warn',\n onConflict: user.onConflict ?? 'shortest',\n onAliasConflict: user.onAliasConflict ?? 'first',\n\n scan: {\n include: scanUser.include ?? ['**/*.md', '**/*.markdown'],\n exclude: scanUser.exclude ?? [],\n followSymlinks: scanUser.followSymlinks ?? false,\n respectGitignore: scanUser.respectGitignore ?? true,\n assetExtensions: scanUser.assetExtensions ?? DEFAULT_ASSET_EXTENSIONS,\n },\n\n assets: {\n mode: assetsUser.mode ?? 'auto',\n preserveAssetPaths: assetsUser.preserveAssetPaths ?? false,\n outputDir: assetsUser.outputDir ?? '_assets',\n },\n\n wikilinks: {\n postProcessLinkTarget:\n wikilinksUser.postProcessLinkTarget ?? ((t: string) => t.trim()),\n postProcessLinkLabel:\n wikilinksUser.postProcessLinkLabel ?? ((l: string) => l.trim()),\n allowLinkLabelFormatting:\n wikilinksUser.allowLinkLabelFormatting ?? false,\n linkText: wikilinksUser.linkText ?? 'basename',\n htmlAttributes: wikilinksHtmlAttrs,\n },\n\n embeds: {\n imageFileExt: embedsUser.imageFileExt ?? DEFAULT_IMAGE_EXTENSIONS,\n defaultAltText: embedsUser.defaultAltText ?? false,\n postProcessImageTarget:\n embedsUser.postProcessImageTarget ?? ((t: string) => t.trim()),\n postProcessAltText:\n embedsUser.postProcessAltText ?? ((a: string) => a.trim()),\n uriSuffix: embedsUser.uriSuffix ?? '',\n transclusionMaxDepth: embedsUser.transclusionMaxDepth ?? 8,\n htmlAttributes: embedsHtmlAttrs,\n },\n\n views: {\n enabled: {\n graph: viewsUser.enabled?.graph ?? true,\n stats: viewsUser.enabled?.stats ?? true,\n tags: viewsUser.enabled?.tags ?? true,\n },\n urlPrefix: viewsUser.urlPrefix ?? '_perspectives_',\n names: {\n graph: viewsUser.names?.graph ?? 'graph',\n stats: viewsUser.names?.stats ?? 'stats',\n tags: viewsUser.names?.tags ?? 'tags',\n },\n // 'injectInto' 优先(v0.3+);否则从老的 'sidebar' 字段推断;再否则默认 'nav'\n injectInto:\n viewsUser.injectInto ??\n (viewsUser.sidebar === false\n ? 'off'\n : viewsUser.sidebar === 'auto'\n ? 'sidebar'\n : 'nav'),\n sidebar: viewsUser.sidebar ?? 'auto',\n sidebarText: {\n group: viewsUser.sidebarText?.group ?? 'Perspectives',\n graph: viewsUser.sidebarText?.graph ?? 'Graph',\n stats: viewsUser.sidebarText?.stats ?? 'Stats',\n tags: viewsUser.sidebarText?.tags ?? 'Tags',\n },\n graphMaxNodes: viewsUser.graphMaxNodes ?? 500,\n dataFileName: viewsUser.dataFileName ?? 'vault-data.json',\n parseInlineTags: viewsUser.parseInlineTags ?? true,\n },\n\n modules: {\n wikilinks: modulesUser.wikilinks ?? true,\n embeds: modulesUser.embeds ?? true,\n views: modulesUser.views ?? true,\n callouts: modulesUser.callouts ?? true,\n highlight: modulesUser.highlight ?? true,\n comments: modulesUser.comments ?? true,\n footnotes: modulesUser.footnotes ?? true,\n blockRefs: modulesUser.blockRefs ?? true,\n },\n\n sidebarAuto: user.sidebarAuto ?? {},\n\n slugify,\n }\n}\n","/**\n * VaultScanner —— 把 srcDir 扫成一份完整的 VaultIndex。\n *\n * 设计目标:\n * - 一次扫描产出所有衍生索引,后续模块只查不扫;\n * - 同步实现(简单可靠,性能足够);\n * - 增量更新(updateFile / removeFile)供 dev 模式 HMR 用。\n */\n\nimport fs from 'node:fs'\nimport nodePath from 'node:path'\nimport type {\n VaultIndex,\n FileEntry,\n AssetEntry,\n ResolvedOptions,\n ScanWarning,\n} from '../types.js'\nimport {\n toPosix,\n basename,\n extname,\n relative as relativePath,\n pathDepth,\n} from '../../utils/path.js'\nimport { buildUrl, applyCleanUrls } from '../../utils/url.js'\nimport { walk } from './scan.js'\nimport { buildIgnorer } from './ignore.js'\nimport {\n parseFrontmatter,\n normalizeAliases,\n normalizeTags,\n} from './frontmatter.js'\nimport { collectHeadings } from './headings.js'\n\nconst MD_EXTENSIONS = new Set(['md', 'markdown'])\n\n/**\n * 创建一份空 VaultIndex(供测试或没有 srcDir 时使用)。\n */\nexport function createEmptyIndex(\n srcDir = '',\n base = '/',\n cleanUrls = false,\n): VaultIndex {\n return {\n files: new Map(),\n assets: new Map(),\n byBasename: new Map(),\n byBasenameLower: new Map(),\n byAlias: new Map(),\n byRelativePath: new Map(),\n byUrl: new Map(),\n assetsByBasename: new Map(),\n assetsByBasenameLower: new Map(),\n assetsByRelativePath: new Map(),\n tags: new Map(),\n backlinks: new Map(),\n headings: new Map(),\n srcDir,\n base,\n cleanUrls,\n scannedAt: Date.now(),\n warnings: [],\n }\n}\n\n/**\n * 扫描 srcDir 并构建 VaultIndex。\n */\nexport function scanVault(options: ResolvedOptions): VaultIndex {\n const srcDir = toPosix(nodePath.resolve(options.srcDir))\n const index = createEmptyIndex(srcDir, options.base, options.cleanUrls)\n\n const isIgnored = buildIgnorer(\n srcDir,\n options.scan.exclude,\n options.scan.respectGitignore,\n )\n\n const assetExtSet = new Set(\n options.scan.assetExtensions.map((e) => e.toLowerCase()),\n )\n\n const entries = walk(srcDir, isIgnored, options.scan.followSymlinks)\n\n for (const ent of entries) {\n const ext = ent.extension\n if (MD_EXTENSIONS.has(ext)) {\n ingestMarkdown(index, ent.absolutePath, ent.size, ent.mtime, options)\n } else if (assetExtSet.has(ext)) {\n ingestAsset(index, ent.absolutePath, ent.size, ent.mtime, ext)\n }\n // 其它扩展静默跳过(.json、.ts 等)\n }\n\n index.scannedAt = Date.now()\n return index\n}\n\n/**\n * 把一个 .md 文件读入索引。\n */\nfunction ingestMarkdown(\n index: VaultIndex,\n absPath: string,\n size: number,\n mtime: number,\n options: ResolvedOptions,\n): void {\n let raw: string\n try {\n raw = fs.readFileSync(absPath, 'utf8')\n } catch (err) {\n index.warnings.push({\n kind: 'unreadable-file',\n message: `无法读取文件: ${absPath} (${\n err instanceof Error ? err.message : String(err)\n })`,\n affected: [absPath],\n })\n return\n }\n\n const { data, content, error } = parseFrontmatter(raw)\n if (error) {\n index.warnings.push({\n kind: 'invalid-frontmatter',\n message: `frontmatter 解析失败 (${absPath}): ${error}`,\n affected: [absPath],\n })\n }\n\n const aliases = normalizeAliases(data.aliases)\n const tags = normalizeTags(data.tags)\n const headings = collectHeadings(content, options.slugify)\n const rel = relativePath(index.srcDir, absPath)\n const base = basename(absPath, true)\n const ext = extname(absPath)\n const url = computeUrl(rel, options)\n\n const entry: FileEntry = {\n absolutePath: absPath,\n relativePath: rel,\n basename: base,\n extension: ext,\n url,\n frontmatter: data,\n aliases,\n tags,\n headings,\n mtime,\n size,\n content,\n }\n\n registerFileEntry(index, entry, options)\n}\n\n/**\n * 把一个 asset 文件加入索引。\n */\nfunction ingestAsset(\n index: VaultIndex,\n absPath: string,\n size: number,\n mtime: number,\n ext: string,\n): void {\n const rel = relativePath(index.srcDir, absPath)\n const base = basename(absPath)\n\n const entry: AssetEntry = {\n absolutePath: absPath,\n relativePath: rel,\n basename: base,\n extension: ext,\n mtime,\n size,\n referencedBy: new Set(),\n }\n\n index.assets.set(absPath, entry)\n index.assetsByRelativePath.set(rel, entry)\n pushToArrayMap(index.assetsByBasename, base, entry)\n pushToArrayMap(index.assetsByBasenameLower, base.toLowerCase(), entry)\n}\n\n/**\n * 把 FileEntry 写进所有查找索引。\n */\nfunction registerFileEntry(\n index: VaultIndex,\n entry: FileEntry,\n options: ResolvedOptions,\n): void {\n index.files.set(entry.absolutePath, entry)\n index.byRelativePath.set(entry.relativePath, entry)\n\n // URL 冲突:多文件指向同一 URL(常见原因:index.md 和 README.md 并存,\n // 它们都路由到 '/'。VitePress 会让其中一个 404)\n const existingAtUrl = index.byUrl.get(entry.url)\n if (existingAtUrl && existingAtUrl.absolutePath !== entry.absolutePath) {\n index.warnings.push({\n kind: 'unknown',\n message:\n `URL 冲突:文件 \"${entry.relativePath}\" 和 \"${existingAtUrl.relativePath}\" ` +\n `都路由到 \"${entry.url}\"。VitePress 会让其中一个 404。` +\n `建议在 .vitepress/config 加 srcExclude: ['${entry.relativePath}'](或另一个)。`,\n affected: [existingAtUrl.absolutePath, entry.absolutePath],\n })\n }\n index.byUrl.set(entry.url, entry)\n index.headings.set(entry.absolutePath, entry.headings)\n\n pushToArrayMap(index.byBasename, entry.basename, entry)\n pushToArrayMap(index.byBasenameLower, entry.basename.toLowerCase(), entry)\n\n for (const alias of entry.aliases) {\n const key = options.caseSensitive ? alias : alias.toLowerCase()\n if (index.byAlias.has(key)) {\n index.warnings.push({\n kind: 'duplicate-alias',\n message: `alias \"${alias}\" 同时被多个文件声明,按 onAliasConflict='${options.onAliasConflict}' 处理`,\n affected: [index.byAlias.get(key)!.absolutePath, entry.absolutePath],\n })\n if (options.onAliasConflict === 'first') continue\n // 'error' 由调用方在 build 时检查 warnings 决定是否抛\n }\n index.byAlias.set(key, entry)\n }\n\n for (const tag of entry.tags) {\n pushToArrayMap(index.tags, tag, entry)\n }\n}\n\n/**\n * 从 relativePath 计算 VitePress URL。\n *\n * - index.md / README.md → 目录根(`/` 或 `/dir/`)\n * (VitePress 默认把这两个文件都路由到目录根,所以同一目录下若两者并存\n * 会冲突,scanVault 末尾会有 URL 冲突告警)\n * - foo.md → /dir/foo (或 /dir/foo.html when !cleanUrls)\n */\nfunction computeUrl(rel: string, options: ResolvedOptions): string {\n const noExt = rel.replace(/\\.(md|markdown)$/i, '')\n // index.md / README.md 特殊处理:URL 为父目录\n const isIndex = /(^|\\/)(index|README)$/i.test(noExt)\n const pathPart = isIndex ? noExt.replace(/(^|\\/)(index|README)$/i, '$1') : noExt\n\n // 路径段切片,各段 buildUrl 时再编码\n const segments = pathPart.split('/').filter(Boolean)\n if (segments.length === 0) {\n // 根 index.md —— **不带 base**(VitePress 会自动 prepend)\n return '/'\n }\n\n // 应用 cleanUrls(若 false,末尾加 .html)\n const last = segments[segments.length - 1]!\n if (!isIndex) {\n segments[segments.length - 1] = applyCleanUrls(last, options.cleanUrls)\n } else if (!options.cleanUrls) {\n segments.push('index.html')\n }\n\n // ⚠ 关键:始终不带 base(用 '/' 做 site-root 相对 URL)。\n // VitePress 在 render 阶段对所有 sidebar/nav link + markdown link 自动\n // prepend base —— 带了会双重 prefix(GitHub Pages 等子路径部署 404)。\n return buildUrl('/', segments)\n}\n\n/** Map<K, V[]> push 工具 */\nfunction pushToArrayMap<K, V>(m: Map<K, V[]>, k: K, v: V): void {\n const arr = m.get(k)\n if (arr) arr.push(v)\n else m.set(k, [v])\n}\n\n/**\n * 增量更新:单个文件改了。\n * 把旧 entry 从所有索引清掉,再走 ingest。\n */\nexport function updateFile(\n index: VaultIndex,\n absPath: string,\n options: ResolvedOptions,\n): void {\n const posix = toPosix(absPath)\n removeFile(index, posix, options)\n let stat: fs.Stats\n try {\n stat = fs.statSync(posix)\n } catch {\n return\n }\n const ext = extname(posix)\n if (MD_EXTENSIONS.has(ext)) {\n ingestMarkdown(index, posix, stat.size, stat.mtimeMs, options)\n } else if (\n new Set(options.scan.assetExtensions.map((e) => e.toLowerCase())).has(ext)\n ) {\n ingestAsset(index, posix, stat.size, stat.mtimeMs, ext)\n }\n}\n\n/**\n * 增量更新:单个文件被删。\n */\nexport function removeFile(\n index: VaultIndex,\n absPath: string,\n options: ResolvedOptions,\n): void {\n const posix = toPosix(absPath)\n\n // 试 file\n const file = index.files.get(posix)\n if (file) {\n index.files.delete(posix)\n index.byRelativePath.delete(file.relativePath)\n index.byUrl.delete(file.url)\n index.headings.delete(posix)\n removeFromArrayMap(index.byBasename, file.basename, file)\n removeFromArrayMap(\n index.byBasenameLower,\n file.basename.toLowerCase(),\n file,\n )\n for (const alias of file.aliases) {\n const key = options.caseSensitive ? alias : alias.toLowerCase()\n if (index.byAlias.get(key) === file) index.byAlias.delete(key)\n }\n for (const tag of file.tags) {\n removeFromArrayMap(index.tags, tag, file)\n }\n return\n }\n\n // 试 asset\n const asset = index.assets.get(posix)\n if (asset) {\n index.assets.delete(posix)\n index.assetsByRelativePath.delete(asset.relativePath)\n removeFromArrayMap(index.assetsByBasename, asset.basename, asset)\n removeFromArrayMap(\n index.assetsByBasenameLower,\n asset.basename.toLowerCase(),\n asset,\n )\n }\n}\n\nfunction removeFromArrayMap<K, V>(m: Map<K, V[]>, k: K, v: V): void {\n const arr = m.get(k)\n if (!arr) return\n const idx = arr.indexOf(v)\n if (idx >= 0) arr.splice(idx, 1)\n if (arr.length === 0) m.delete(k)\n}\n\n/**\n * 多条目按\"路径深度浅 → 路径字典序\"排序的 helper,供 Resolver 'shortest' 用。\n */\nexport function sortByShortestPath<T extends { relativePath: string }>(\n items: T[],\n): T[] {\n return [...items].sort((a, b) => {\n const da = pathDepth(a.relativePath)\n const db = pathDepth(b.relativePath)\n if (da !== db) return da - db\n return a.relativePath.localeCompare(b.relativePath)\n })\n}\n\n","/**\n * 跨平台 POSIX 路径工具。\n *\n * 设计原则:\n * - 内部所有路径都用 POSIX 风格(正斜杠);进出 OS 边界才转换。\n * - 我们的索引 key 永远是 POSIX,不依赖运行平台。\n */\n\nimport nodePath from 'node:path'\n\n/** 把任意路径转成 POSIX 风格(替换 \\\\ 为 /)*/\nexport function toPosix(p: string): string {\n return p.replace(/\\\\/g, '/')\n}\n\n/** 计算相对路径,POSIX 风格 */\nexport function relative(from: string, to: string): string {\n return toPosix(nodePath.relative(from, to))\n}\n\n/** POSIX join */\nexport function posixJoin(...parts: string[]): string {\n return parts\n .filter((p) => p && p.length > 0)\n .map((p, i) => {\n let s = toPosix(p)\n if (i > 0) s = s.replace(/^\\/+/, '')\n if (i < parts.length - 1) s = s.replace(/\\/+$/, '')\n return s\n })\n .join('/')\n}\n\n/** 去掉尾部 .md / .markdown(若有);其它扩展名保留 */\nexport function stripMarkdownExt(target: string): string {\n return target.replace(/\\.(md|markdown)$/i, '')\n}\n\n/** 取 POSIX 风格 basename,可选去扩展 */\nexport function basename(p: string, stripExt = false): string {\n const idx = p.lastIndexOf('/')\n const file = idx === -1 ? p : p.slice(idx + 1)\n if (!stripExt) return file\n const dot = file.lastIndexOf('.')\n return dot <= 0 ? file : file.slice(0, dot)\n}\n\n/** 取扩展名(不含点,小写);无扩展返回 '' */\nexport function extname(p: string): string {\n const file = basename(p)\n const dot = file.lastIndexOf('.')\n if (dot <= 0) return ''\n return file.slice(dot + 1).toLowerCase()\n}\n\n/** 把 path 用 / 拆开,过滤空段 */\nexport function splitPath(p: string): string[] {\n return toPosix(p).split('/').filter(Boolean)\n}\n\n/** 路径深度(段数),用于 onConflict: 'shortest' */\nexport function pathDepth(relPath: string): number {\n return splitPath(relPath).length\n}\n\n/** 把绝对路径正规化为 POSIX */\nexport function normalizeAbs(p: string): string {\n return toPosix(nodePath.resolve(p))\n}\n","/**\n * URL 拼接 / 编码工具。\n *\n * 关键设计:\n * - 站内 URL 永远是绝对路径 + base 前缀;\n * - 路径段做 URI 编码(空格、中文 → %xx),但保留 '/' 和 '#';\n * - 输出的 URL 仍是字符串,attr 写入时再做 HTML escape(escape.ts 负责)。\n */\n\n/**\n * 给一段路径做 URL 编码,但保留 '/' 和 '#'。\n *\n * `encodeURI` 默认就保留 '/'、'#'、'?' 等,但会保留 '%' —— 我们假设传入的是\n * 原始路径(未编码),所以直接 encodeURI 就行。\n */\nexport function encodePath(s: string): string {\n return encodeURI(s)\n}\n\n/**\n * 拼接 base + 路径段(单个或多个)+ 可选锚点,产出最终 URL。\n *\n * - 多余的 '/' 会被折叠;\n * - 空段被跳过;\n * - 始终以 base 开头(若 base 提供);\n * - cleanUrls=false 时调用方负责加 '.html' 后缀(我们这里不管)。\n */\nexport function buildUrl(\n base: string,\n pathSegments: string[],\n anchor?: string,\n): string {\n // 归一化 base:确保以 / 开头并以 / 结尾\n let normBase = base || '/'\n if (!normBase.startsWith('/')) normBase = '/' + normBase\n if (!normBase.endsWith('/')) normBase = normBase + '/'\n\n // 拼接路径段(过滤空、去段头尾的 /)\n const joined = pathSegments\n .map((s) => s.replace(/^\\/+|\\/+$/g, ''))\n .filter(Boolean)\n .join('/')\n\n let url = normBase + joined\n // 折叠相邻多 /\n url = url.replace(/\\/{2,}/g, '/')\n // URI 编码(空格、中文)\n url = encodePath(url)\n\n if (anchor) {\n // anchor 也要编码,但不再处理 /\n url += '#' + encodeURIComponent(anchor).replace(/%2F/g, '/')\n }\n return url\n}\n\n/**\n * 给路径加上 cleanUrls 决定的扩展名。\n *\n * cleanUrls=true:不加任何后缀(VitePress 生成 .html 但路由用无扩展)。\n * cleanUrls=false:加 '.html'。\n *\n * 调用方应该在 buildUrl 之前对 path 段调用本函数(或之后再追加 .html)。\n */\nexport function applyCleanUrls(path: string, cleanUrls: boolean): string {\n if (cleanUrls) return path\n if (/\\.html$/i.test(path)) return path\n // 末尾的 / 表示目录路由,index.html\n if (path.endsWith('/')) return path + 'index.html'\n return path + '.html'\n}\n","/**\n * 文件系统遍历。\n *\n * 同步遍历 srcDir,产出绝对路径列表。性能预算:\n * - 10k 文件 / 千级目录,< 1s。\n * - 同步 fs(我们就一份索引,build/dev 启动时一次性建,简单可靠)。\n */\n\nimport fs from 'node:fs'\nimport nodePath from 'node:path'\nimport { toPosix, extname } from '../../utils/path.js'\n\nexport interface WalkEntry {\n absolutePath: string // POSIX 风格\n size: number\n mtime: number\n extension: string\n}\n\n/**\n * 递归遍历 srcDir,返回所有非忽略的文件条目。\n *\n * @param srcDir 绝对路径\n * @param isIgnored 判定函数\n * @param followSymlinks 是否跟随符号链接(默认 false)\n */\nexport function walk(\n srcDir: string,\n isIgnored: (absPath: string) => boolean,\n followSymlinks: boolean,\n): WalkEntry[] {\n const out: WalkEntry[] = []\n const seenInodes = new Set<string>() // 防符号链接环\n\n function visit(dir: string): void {\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true })\n } catch {\n return\n }\n\n for (const ent of entries) {\n const full = nodePath.join(dir, ent.name)\n const posix = toPosix(full)\n if (isIgnored(posix)) continue\n\n let isDir = ent.isDirectory()\n let isFile = ent.isFile()\n\n if (ent.isSymbolicLink()) {\n if (!followSymlinks) continue\n try {\n const stat = fs.statSync(full)\n isDir = stat.isDirectory()\n isFile = stat.isFile()\n } catch {\n continue\n }\n }\n\n if (isDir) {\n if (followSymlinks) {\n try {\n const stat = fs.statSync(full)\n const key = `${stat.dev}:${stat.ino}`\n if (seenInodes.has(key)) continue\n seenInodes.add(key)\n } catch {\n // 取不到 stat 就跳过\n continue\n }\n }\n visit(full)\n } else if (isFile) {\n try {\n const stat = fs.statSync(full)\n out.push({\n absolutePath: posix,\n size: stat.size,\n mtime: stat.mtimeMs,\n extension: extname(posix),\n })\n } catch {\n // 读不到 stat 就跳过\n }\n }\n }\n }\n\n visit(srcDir)\n return out\n}\n","/**\n * 文件忽略规则。\n *\n * 默认忽略列表针对\"VitePress 文档站 + Obsidian vault\"的典型布局,\n * 用户可通过 ResolvedOptions.scan.exclude 追加。\n */\n\nimport fs from 'node:fs'\nimport nodePath from 'node:path'\nimport picomatch from 'picomatch'\nimport { relative, toPosix } from '../../utils/path.js'\n\n/** 始终忽略,不可关闭 */\nexport const HARD_IGNORE_DIRS = new Set([\n 'node_modules',\n '.git',\n '.svn',\n '.hg',\n '.obsidian',\n '.trash',\n '.vitepress',\n '.next',\n '.nuxt',\n '.cache',\n '.idea',\n '.vscode',\n 'dist',\n 'build',\n])\n\n/**\n * 构造一个 (absolutePath) => boolean 的\"是否忽略\"判定函数。\n *\n * @param srcDir 扫描根目录(绝对路径)\n * @param userExclude 用户额外的 glob 列表\n * @param respectGitignore 是否读 srcDir/.gitignore\n */\nexport function buildIgnorer(\n srcDir: string,\n userExclude: string[],\n respectGitignore: boolean,\n): (absPath: string) => boolean {\n const patterns: string[] = [...userExclude]\n if (respectGitignore) {\n const gitignore = nodePath.join(srcDir, '.gitignore')\n try {\n const content = fs.readFileSync(gitignore, 'utf8')\n for (const line of content.split(/\\r?\\n/)) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith('#')) continue\n // .gitignore 规则不完全等价于 picomatch 的 glob,\n // 但对常见 'dist/'、'*.log' 这类够用了。\n patterns.push(trimmed.endsWith('/') ? trimmed + '**' : trimmed)\n }\n } catch {\n // .gitignore 不存在或不可读 —— 静默跳过\n }\n }\n\n const matchers = patterns.map((p) =>\n picomatch(p, { dot: true, nocase: false }),\n )\n\n return (absPath: string): boolean => {\n const rel = toPosix(relative(srcDir, absPath))\n if (!rel || rel.startsWith('..')) return true\n\n // 硬忽略:任意路径段命中即忽略\n for (const seg of rel.split('/')) {\n if (HARD_IGNORE_DIRS.has(seg)) return true\n }\n\n // 用户/gitignore 规则\n for (const m of matchers) {\n if (m(rel)) return true\n }\n return false\n }\n}\n","/**\n * frontmatter 解析。\n *\n * 用 gray-matter,Obsidian 和 Astro 都用它,YAML 兼容性好。\n * 解析失败时返回空 frontmatter + 原文,落 warning。\n */\n\nimport matter from 'gray-matter'\n\nexport interface ParsedFrontmatter {\n /** 解析后的 frontmatter 对象,失败时为空对象 */\n data: Record<string, unknown>\n /** 去掉 frontmatter 之后的正文 */\n content: string\n /** 解析错误信息,成功为 undefined */\n error?: string\n}\n\nexport function parseFrontmatter(raw: string): ParsedFrontmatter {\n try {\n const { data, content } = matter(raw)\n return { data: (data ?? {}) as Record<string, unknown>, content }\n } catch (err) {\n return {\n data: {},\n content: raw,\n error: err instanceof Error ? err.message : String(err),\n }\n }\n}\n\n/**\n * 把 frontmatter.aliases 归一化为字符串数组。支持:\n * - undefined / null → []\n * - string → [string]\n * - string[] → 原样过滤空字符串\n * - 其它 → []\n */\nexport function normalizeAliases(raw: unknown): string[] {\n if (raw == null) return []\n if (typeof raw === 'string') return raw.trim() ? [raw.trim()] : []\n if (Array.isArray(raw)) {\n return raw\n .filter((v): v is string => typeof v === 'string')\n .map((s) => s.trim())\n .filter(Boolean)\n }\n return []\n}\n\n/**\n * 把 frontmatter.tags 归一化为字符串数组(同上规则)。\n */\nexport function normalizeTags(raw: unknown): string[] {\n if (raw == null) return []\n if (typeof raw === 'string') {\n return raw\n .split(/[,\\s]+/)\n .map((s) => s.trim().replace(/^#/, ''))\n .filter(Boolean)\n }\n if (Array.isArray(raw)) {\n return raw\n .filter((v): v is string => typeof v === 'string')\n .map((s) => s.trim().replace(/^#/, ''))\n .filter(Boolean)\n }\n return []\n}\n","/**\n * Heading 收集。\n *\n * 不引入完整 markdown-it 单纯为了收 heading —— 自己用正则扫,够快、零依赖。\n * 处理 ATX 风格(# / ## / ###),不处理 Setext(`===` / `---` 下划线风格,\n * Obsidian / VitePress 实际都极少用)。\n *\n * 识别 `{#custom-id}` 自定义 anchor 语法。\n */\n\nimport type { HeadingEntry } from '../types.js'\nimport { extractCustomId } from '../slugify.js'\n\nconst HEADING_RE = /^(#{1,6})\\s+(.+?)\\s*$/\nconst FENCE_RE = /^(`{3,}|~{3,})/\n\n/**\n * 从源文件正文(去掉 frontmatter 之后)收集 heading。\n *\n * @param content 正文\n * @param slugify 与 VitePress 一致的 slug 函数\n */\nexport function collectHeadings(\n content: string,\n slugify: (text: string) => string,\n): HeadingEntry[] {\n const lines = content.split(/\\r?\\n/)\n const out: HeadingEntry[] = []\n\n let inFence = false\n let fenceMarker = ''\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!\n\n // 跳过代码块内部\n const fenceMatch = line.match(FENCE_RE)\n if (fenceMatch) {\n if (!inFence) {\n inFence = true\n fenceMarker = fenceMatch[1]!\n } else if (line.startsWith(fenceMarker)) {\n inFence = false\n fenceMarker = ''\n }\n continue\n }\n if (inFence) continue\n\n const m = line.match(HEADING_RE)\n if (!m) continue\n\n const level = m[1]!.length\n const rawText = m[2]!\n const { text, customId } = extractCustomId(rawText)\n const slug = customId ?? slugify(text)\n\n out.push({ level, text, slug, line: i })\n }\n\n return out\n}\n","/**\n * Resolver —— 把 wikilink target 解析成最终 URL。\n *\n * 解析顺序(对应 PLAN §5):\n * 1. trim、剥 .md/.markdown\n * 2. 拆 #heading\n * 3. 含 '/' → 按 byRelativePath 查\n * 4. 不含 '/' → byAlias → byBasename(冲突按 onConflict)\n * 5. heading 匹配 → 加 anchor;否则标记半死链\n */\n\nimport type {\n VaultIndex,\n ResolvedOptions,\n ResolveResult,\n FileEntry,\n} from './types.js'\nimport { sortByShortestPath } from './vault/index.js'\nimport { stripMarkdownExt, toPosix, basename } from '../utils/path.js'\n\n/**\n * 解析一个 wikilink target(已经从 [[]] / ![[]] 中取出的 raw 字符串,不含 pipe 部分)。\n *\n * @param rawTarget 例如 \"notes/a\" / \"a\" / \"a#heading\" / \"中文笔记\"\n * @param index vault 索引\n * @param options 已解析配置\n * @param kind 'page' | 'image' | 'transclusion';v0.1 image 走单独路径,这里\n * 只处理 'page' / 'transclusion'\n */\nexport function resolveWikilink(\n rawTarget: string,\n index: VaultIndex,\n options: ResolvedOptions,\n kind: 'page' | 'transclusion' = 'page',\n /** 写这个 wikilink 的源文件绝对路径(用于相对路径 fallback) */\n currentSourcePath?: string,\n): ResolveResult {\n // 1. 归一化:反斜杠 → 正斜杠、剥 markdown 扩展、trim\n let target = toPosix(rawTarget).trim()\n // 2. 拆 #heading\n const hashIdx = target.indexOf('#')\n let headingPart = ''\n if (hashIdx >= 0) {\n headingPart = target.slice(hashIdx + 1).trim()\n target = target.slice(0, hashIdx).trim()\n }\n // 剥 .md / .markdown\n target = stripMarkdownExt(target)\n\n // 3-4. 查 entry\n const entry = lookupEntry(target, index, options, currentSourcePath)\n\n if (!entry) {\n return {\n url: buildDeadUrl(rawTarget, options),\n defaultLabel: defaultLabel(target, headingPart, undefined, options),\n isDead: true,\n hasUnmatchedAnchor: false,\n kind,\n }\n }\n\n // 5. heading 匹配\n let url = entry.url\n let hasUnmatchedAnchor = false\n if (headingPart) {\n const heading = entry.headings.find(\n (h) =>\n h.text === headingPart ||\n h.slug === headingPart ||\n h.slug === options.slugify(headingPart),\n )\n if (heading) {\n url = entry.url + '#' + heading.slug\n } else {\n hasUnmatchedAnchor = true\n url = entry.url + '#' + encodeURIComponent(headingPart)\n }\n }\n\n return {\n url,\n defaultLabel: defaultLabel(target, headingPart, entry, options),\n isDead: false,\n hasUnmatchedAnchor,\n target: entry,\n kind,\n }\n}\n\n/**\n * 查目标 entry:含 '/' 按 byRelativePath,否则 byAlias → byBasename(冲突按策略)。\n */\nfunction lookupEntry(\n target: string,\n index: VaultIndex,\n options: ResolvedOptions,\n currentSourcePath?: string,\n): FileEntry | undefined {\n if (!target) return undefined\n\n // 含 '/':按路径查\n if (target.includes('/')) {\n // 用户写 'notes/a' → 找 'notes/a.md' 或 'notes/a.markdown'\n const variants = [\n target,\n target + '.md',\n target + '.markdown',\n target + '/index.md',\n target + '/index.markdown',\n ]\n for (const v of variants) {\n const e = index.byRelativePath.get(v)\n if (e) return e\n }\n // Fallback:相对当前 source 文件目录(模仿 Obsidian 行为)\n if (currentSourcePath) {\n // currentSourcePath 是绝对路径,先转 vault 相对再拼\n const srcDirAbs = index.srcDir\n const rel = toPosix(currentSourcePath).startsWith(srcDirAbs + '/')\n ? toPosix(currentSourcePath).slice(srcDirAbs.length + 1)\n : ''\n if (rel) {\n const curDir = rel.split('/').slice(0, -1).join('/')\n if (curDir) {\n const relVariants = [\n `${curDir}/${target}`,\n `${curDir}/${target}.md`,\n `${curDir}/${target}.markdown`,\n `${curDir}/${target}/index.md`,\n `${curDir}/${target}/index.markdown`,\n ]\n for (const v of relVariants) {\n const e = index.byRelativePath.get(v)\n if (e) return e\n }\n }\n }\n }\n return undefined\n }\n\n // 不含 '/':先 alias\n const aliasKey = options.caseSensitive ? target : target.toLowerCase()\n const aliased = index.byAlias.get(aliasKey)\n if (aliased) return aliased\n\n // 再 basename\n const bnMap = options.caseSensitive\n ? index.byBasename\n : index.byBasenameLower\n const bnKey = options.caseSensitive ? target : target.toLowerCase()\n const candidates = bnMap.get(bnKey)\n if (!candidates || candidates.length === 0) return undefined\n if (candidates.length === 1) return candidates[0]!\n\n // 多个 → onConflict\n switch (options.onConflict) {\n case 'shortest': {\n const sorted = sortByShortestPath(candidates)\n return sorted[0]!\n }\n case 'first':\n return candidates[0]!\n case 'error':\n // build 时由调用方根据 deadLink 决定;这里返回 undefined → 当作死链\n return undefined\n }\n}\n\n/**\n * 死链 URL —— 给一个尽量接近用户意图的 href,便于用户点开诊断。\n * 不抛错,渲染时附 wikilink--dead class。\n */\nfunction buildDeadUrl(rawTarget: string, options: ResolvedOptions): string {\n // 把 raw 字符串原样编码进 URL,带个 sentinel hash 让用户一眼能看出\n const safe = encodeURIComponent(stripMarkdownExt(rawTarget).split('#')[0]!)\n return options.base + safe\n}\n\n/**\n * 计算默认 label。\n * - 用户传了 alias 优先,这里只算\"没有 alias 时\" fallback。\n * - linkText='basename' / 'fullPath' / 自定义函数\n * - 带 heading 时:basename > heading\n */\nfunction defaultLabel(\n target: string,\n headingPart: string,\n entry: FileEntry | undefined,\n options: ResolvedOptions,\n): string {\n const lt = options.wikilinks.linkText\n let base: string\n if (typeof lt === 'function') {\n if (entry) {\n base = lt(entry, target)\n } else {\n // 死链时拿不到 entry,降级到 raw target 的 basename\n base = basename(target)\n }\n } else if (lt === 'fullPath') {\n base = entry ? entry.relativePath.replace(/\\.(md|markdown)$/i, '') : target\n } else {\n // 'basename'\n base = entry ? entry.basename : basename(target)\n }\n if (headingPart) {\n // Obsidian 风格 \"basename > 章节\"\n return `${base} > ${headingPart}`\n }\n return base\n}\n\n/**\n * 解析 image embed target → AssetEntry。\n * 与 resolveWikilink 类似,但走 assets 索引。\n */\nexport function resolveAsset(\n rawTarget: string,\n index: VaultIndex,\n options: ResolvedOptions,\n): {\n asset: import('./types.js').AssetEntry | undefined\n rawBasename: string\n} {\n const target = toPosix(rawTarget).trim()\n // 含 '/':按 assetsByRelativePath 查\n if (target.includes('/')) {\n return {\n asset: index.assetsByRelativePath.get(target),\n rawBasename: basename(target),\n }\n }\n const bn = options.caseSensitive ? target : target.toLowerCase()\n const map = options.caseSensitive\n ? index.assetsByBasename\n : index.assetsByBasenameLower\n const candidates = map.get(bn)\n if (!candidates || candidates.length === 0) {\n return { asset: undefined, rawBasename: target }\n }\n if (candidates.length === 1) {\n return { asset: candidates[0], rawBasename: target }\n }\n // 多个 asset 同名 → 也走 onConflict\n switch (options.onConflict) {\n case 'shortest': {\n const sorted = sortByShortestPath(candidates)\n return { asset: sorted[0], rawBasename: target }\n }\n case 'first':\n return { asset: candidates[0], rawBasename: target }\n case 'error':\n return { asset: undefined, rawBasename: target }\n }\n}\n","/**\n * wikilinks 渲染辅助 —— 把解析结果落成 markdown-it tokens。\n */\n\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type {\n ResolveResult,\n AllYouNeedEnv,\n PageLinkAttrs,\n PageLinkAttrsContext,\n} from '../../core/types.js'\n\n/**\n * 渲染正常 wikilink(`[[Page]]`、`[[Page|alias]]`、`[[Page#heading]]`)。\n */\nexport function renderPageLink(\n state: StateInline,\n result: ResolveResult,\n label: string,\n env: AllYouNeedEnv,\n): boolean {\n const open = state.push('link_open', 'a', 1)\n const classes = ['wikilink']\n if (result.hasUnmatchedAnchor) classes.push('wikilink--unmatched-anchor')\n\n const baseAttrs: Record<string, string> = {\n href: result.url,\n class: classes.join(' '),\n 'data-wikilink-target': result.target\n ? result.target.relativePath\n : '',\n }\n\n const extra = resolveExtraAttrs(env.options.wikilinks.htmlAttributes, {\n originalHref: result.url,\n label,\n target: result.target,\n isDead: result.isDead,\n hasUnmatchedAnchor: result.hasUnmatchedAnchor,\n })\n\n applyAttrs(open, baseAttrs, extra)\n\n // label 渲染:默认走 text token(安全);allowLinkLabelFormatting=true 时\n // 走 inline 解析,但带递归保护。\n emitLabel(state, label, env)\n\n state.push('link_close', 'a', -1)\n return true\n}\n\n/**\n * 渲染死链:**不输出 href**,避免点击跳转到不存在的页面误导用户。\n * 用 <a class=\"wikilink wikilink--dead\"> 不带 href → 视觉是链接、CSS 标红删除线、\n * 鼠标 cursor: not-allowed 提示;**不可点**。\n *\n * 仍把 raw target 写到 data-attr 上方便用户自查;title 是 hover 提示。\n */\nexport function renderDeadLink(\n state: StateInline,\n url: string,\n label: string,\n rawTarget: string,\n env: AllYouNeedEnv,\n): boolean {\n const open = state.push('link_open', 'a', 1)\n const baseAttrs: Record<string, string> = {\n // ⚠ 不写 href:点击不会跳转\n class: 'wikilink wikilink--dead',\n 'data-wikilink-target': rawTarget,\n title: `死链:找不到 [[${rawTarget}]]`,\n }\n const extra = resolveExtraAttrs(env.options.wikilinks.htmlAttributes, {\n originalHref: url,\n label,\n target: undefined,\n isDead: true,\n hasUnmatchedAnchor: false,\n })\n applyAttrs(open, baseAttrs, extra)\n\n emitLabel(state, label, env)\n\n state.push('link_close', 'a', -1)\n return true\n}\n\n/**\n * 推 label 文本 token(或 inline 解析的结果)。\n */\nfunction emitLabel(\n state: StateInline,\n label: string,\n env: AllYouNeedEnv,\n): void {\n if (env.options.wikilinks.allowLinkLabelFormatting) {\n // 递归保护:env 上挂一个深度计数,超过 3 直接回退到 text\n const depth = (env as unknown as { _labelDepth?: number })._labelDepth ?? 0\n if (depth < 3) {\n ;(env as unknown as { _labelDepth?: number })._labelDepth = depth + 1\n const md = state.md\n const html = md.renderInline(label, env)\n const token = state.push('html_inline', '', 0)\n token.content = html\n ;(env as unknown as { _labelDepth?: number })._labelDepth = depth\n return\n }\n }\n const t = state.push('text', '', 0)\n t.content = label\n}\n\n/**\n * 合并用户 htmlAttributes(函数或对象)。\n */\nfunction resolveExtraAttrs(\n htmlAttrs: PageLinkAttrs,\n ctx: PageLinkAttrsContext,\n): Record<string, string> {\n if (typeof htmlAttrs === 'function') return htmlAttrs(ctx)\n return htmlAttrs ?? {}\n}\n\n/**\n * 把 base + extra 应用到 token,extra 中重复的 key 覆盖 base\n * (例外:class 做合并而非覆盖)。\n */\nfunction applyAttrs(\n token: { attrSet(k: string, v: string): void },\n base: Record<string, string>,\n extra: Record<string, string>,\n): void {\n const merged: Record<string, string> = { ...base }\n for (const [k, v] of Object.entries(extra)) {\n if (k === 'class' && merged.class) {\n merged.class = merged.class + ' ' + v\n } else {\n merged[k] = v\n }\n }\n for (const [k, v] of Object.entries(merged)) {\n token.attrSet(k, v)\n }\n}\n","/**\n * HTML escape。\n *\n * 这里不依赖 markdown-it 的 md.utils.escapeHtml,因为我们的工具可能\n * 在 markdown-it 之外被调用(例如 build-emit 写 HTML 占位符)。\n */\nconst HTML_ESCAPE_MAP: Record<string, string> = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n}\n\nconst HTML_ESCAPE_RE = /[&<>\"']/g\n\nexport function escapeHtml(s: string): string {\n return s.replace(HTML_ESCAPE_RE, (c) => HTML_ESCAPE_MAP[c]!)\n}\n","/**\n * Asset 占位符 URL + dev 公开 URL helpers。\n *\n * 工作流(v0.1):\n * 1. markdown-it 渲染 ![[image.png]] 时,image.ts 调 buildPlaceholderUrl 出\n * `<img src=\"/__ayn_asset__/<encoded-relPath>\">`,并把 AssetEntry 登记。\n * 2. Vite 编译 .md→.vue 时 Vue compiler 把 `<img src>` 转成 import;Vite 的\n * import-analysis 走 resolveId → 我们插件在 src/vite.ts 拦截这个 URL。\n * 3. dev:resolveId 返回虚拟模块,load 导出 `buildPublicUrl(asset)` —— URL\n * 点回 vault asset(由 dev-middleware 流式响应)。\n * 4. build:load 调 `this.emitFile` 把文件丢给 Rollup,导出\n * `import.meta.ROLLUP_FILE_URL_<id>` —— Rollup 自动算 hash 并替换。\n *\n * 没有 transformIndexHtml/后期字符串替换的路径 —— 全部走标准 Vite 资源管线。\n */\n\nimport type { AssetEntry, ResolvedOptions } from '../types.js'\nimport { basename } from '../../utils/path.js'\n\n/** 占位符 URL 前缀,不会出现在合法 URL 里 */\nexport const ASSET_PLACEHOLDER_PREFIX = '/__ayn_asset__/'\n\n/**\n * 给 asset 构造占位符 URL,markdown-it 渲染阶段使用。\n * 形如 `/__ayn_asset__/<encoded relativePath>`(base 前置)。\n *\n * **用 encodeURI 而不是 encodeURIComponent** —— 我们希望保留 `/` 不被编码成 `%2F`。\n * 原因:Vite 在内部把 URL 路径中的 `%2F` 解码回 `/`,导致 resolveId/load 收到的 id\n * 时而带 `%2F` 时而带 `/`,匹配 byRelativePath 不稳定。统一用 encodeURI 让路径段\n * 保留 `/`,resolveId/load 拿到的 id 总是 `/` 形式,行为稳定。\n */\nexport function buildPlaceholderUrl(\n asset: AssetEntry,\n options: ResolvedOptions,\n): string {\n const id = encodeURI(asset.relativePath)\n return options.base + ASSET_PLACEHOLDER_PREFIX.slice(1) + id\n}\n\n/**\n * dev 模式下 asset 的最终公开 URL。\n *\n * - preserveAssetPaths=false(默认):URL = base + basename\n * - preserveAssetPaths=true:URL = base + relativePath\n *\n * 这俩 dev-middleware 都能服务(basename + relativePath 双查找)。\n */\nexport function buildPublicUrl(\n asset: AssetEntry,\n options: ResolvedOptions,\n): string {\n const path = options.assets.preserveAssetPaths\n ? asset.relativePath\n : basename(asset.absolutePath)\n return options.base + encodeURI(path)\n}\n","/**\n * image embed:`![[image.png]]`、`![[image.png|alt]]`、\n * `![[image.png|300]]`、`![[image.png|x200]]`、`![[image.png|300x200]]`、\n * `![[image.png|alt|300x200]]`。\n *\n * 实现说明:\n * - 渲染为 `<img>` HTML 字符串(`renderImageHtml`)。\n * - inline 场景:外层用 `html_inline` token 包(图片本身是 inline 元素,\n * 和段落文本混排 OK)。\n * - block 场景:外层用 `html_block` token 包(整行只有 ![[image]] 时,\n * 避免被多余 `<p>` 包裹)。\n * - **不用 markdown-it 的 'image' token**:默认渲染器假设 attrs 数组里一定\n * 有 'alt' 项,若没设会 `attrs[-1] = ...` 崩溃。\n */\n\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type {\n AllYouNeedEnv,\n ImageEmbedAttrs,\n ImageEmbedAttrsContext,\n} from '../../core/types.js'\nimport { resolveAsset } from '../../core/resolver.js'\nimport { basename } from '../../utils/path.js'\nimport { escapeHtml } from '../../utils/escape.js'\nimport {\n buildPlaceholderUrl,\n buildPublicUrl,\n} from '../../core/asset-pipeline/build-emit.js'\n\n// ── 公共渲染:返回 <img> 标签字符串 ───────────────────────────────\n\n/**\n * 把 ![[image|...]] 渲染为完整的 `<img>` HTML 字符串。\n * 不向 markdown-it state 推 token;调用方决定用 html_inline 还是 html_block。\n */\nexport function renderImageHtml(\n rawTarget: string,\n aliasParts: string[],\n env: AllYouNeedEnv,\n): string {\n const { index, options } = env\n\n const { altText, dim } = parseAltAndDim(aliasParts)\n\n const processedTarget = options.embeds.postProcessImageTarget(rawTarget)\n const { asset } = resolveAsset(processedTarget, index, options)\n\n let src: string\n if (asset) {\n asset.referencedBy.add(env.currentPath ?? '<unknown>')\n env.referencedAssets?.add(asset)\n src = buildPlaceholderUrl(asset, options) + options.embeds.uriSuffix\n } else {\n src =\n options.base +\n encodeURIComponent(basename(processedTarget)) +\n options.embeds.uriSuffix\n }\n\n const finalAlt = determineAlt(altText, processedTarget, options)\n\n const attrs: Record<string, string> = {\n src,\n alt: finalAlt ?? '',\n }\n if (dim.width !== undefined) attrs.width = String(dim.width)\n if (dim.height !== undefined) attrs.height = String(dim.height)\n\n const extra = resolveExtra(options.embeds.htmlAttributes, {\n originalHref: src,\n altText: finalAlt,\n dimensions: dim.raw,\n embedType: 'image',\n })\n for (const [k, v] of Object.entries(extra)) {\n if (k === 'class' && attrs.class) {\n attrs.class = attrs.class + ' ' + v\n } else {\n attrs[k] = v\n }\n }\n\n return (\n '<img ' +\n Object.entries(attrs)\n .map(([k, v]) => `${escapeAttrName(k)}=\"${escapeHtml(v)}\"`)\n .join(' ') +\n ' />'\n )\n}\n\n// ── inline 入口(从 wikilinks rule 调用)──────────────────────────\n\n/**\n * 处理 inline 上下文中的 ![[image|...]]:推 html_inline。\n */\nexport function handleImageEmbed(\n state: StateInline,\n rawTarget: string,\n aliasParts: string[],\n env: AllYouNeedEnv,\n): boolean {\n const html = renderImageHtml(rawTarget, aliasParts, env)\n const token = state.push('html_inline', '', 0)\n token.content = html\n return true\n}\n\n// ── 解析尺寸 + alt ───────────────────────────────────────────────\n\ninterface ParsedDim {\n width?: number\n height?: number\n raw: string\n}\n\nfunction parseAltAndDim(parts: string[]): {\n altText: string\n dim: ParsedDim\n} {\n if (parts.length === 0) return { altText: '', dim: { raw: '' } }\n const last = parts[parts.length - 1]!\n const parsedLast = tryParseDimension(last)\n if (parsedLast) {\n const alt = parts.slice(0, -1).join('|').trim()\n return { altText: alt, dim: { ...parsedLast, raw: last } }\n }\n return { altText: parts.join('|').trim(), dim: { raw: '' } }\n}\n\nfunction tryParseDimension(\n s: string,\n): { width?: number; height?: number } | undefined {\n const trimmed = s.trim().toLowerCase()\n if (!trimmed) return undefined\n\n if (trimmed.includes('x')) {\n const [w, h] = trimmed.split('x')\n const wOk = w === '' || /^\\d+$/.test(w!)\n const hOk = h === '' || /^\\d+$/.test(h!)\n if (!wOk || !hOk) return undefined\n if (w === '' && h === '') return undefined\n return {\n width: w === '' ? undefined : Number(w),\n height: h === '' ? undefined : Number(h),\n }\n }\n if (/^\\d+$/.test(trimmed)) {\n return { width: Number(trimmed) }\n }\n return undefined\n}\n\nfunction determineAlt(\n rawAlt: string,\n target: string,\n options: AllYouNeedEnv['options'],\n): string | undefined {\n if (rawAlt && rawAlt !== '') {\n return options.embeds.postProcessAltText(rawAlt)\n }\n const def = options.embeds.defaultAltText\n if (def === false) return undefined\n if (def === true) {\n const bn = basename(target)\n const dot = bn.lastIndexOf('.')\n const noExt = dot > 0 ? bn.slice(0, dot) : bn\n return options.embeds.postProcessAltText(noExt)\n }\n if (typeof def === 'string') {\n return def === '' ? '' : options.embeds.postProcessAltText(def)\n }\n return options.embeds.postProcessAltText(basename(target))\n}\n\nfunction resolveExtra(\n attrs: ImageEmbedAttrs,\n ctx: ImageEmbedAttrsContext,\n): Record<string, string> {\n if (typeof attrs === 'function') return attrs(ctx)\n return attrs ?? {}\n}\n\nfunction escapeAttrName(k: string): string {\n return k.replace(/[^a-zA-Z0-9_-]/g, '_')\n}\n\n// 防 unused\nexport { buildPublicUrl }\n","/**\n * 笔记 transclusion:`![[note]]`、`![[note#heading]]`。\n *\n * **transclusion 始终是 block-level**:它内部会含 `<h1>` / `<div>` / `<pre>`\n * 等 block 元素,放进 `<p>` 里会产生不合法 HTML。\n *\n * 两种入口:\n * - block 入口(从 embed block-rule 调用)→ 推 html_block,无 <p> 包裹。\n * - inline 入口(从 wikilinks rule 调用)→ 不真做 transclusion,降级为\n * 带告警的 `<a>` 链接 + warn 日志(原因同上)。\n *\n * 内部 helper renderTransclusionHtml 返回完整 `<div class=\"transclusion\">...</div>`\n * 字符串,供 block 入口使用。\n */\n\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type MarkdownIt from 'markdown-it'\nimport type { AllYouNeedEnv, FileEntry } from '../../core/types.js'\nimport { resolveWikilink } from '../../core/resolver.js'\nimport { escapeHtml } from '../../utils/escape.js'\n\ninterface TransclusionCacheEntry {\n html: string\n}\n\n/**\n * 公共渲染:返回完整 `<div class=\"transclusion\">…</div>` HTML 字符串。\n * 失败/循环/超深时返回带告警 class 的 div。\n */\nexport function renderTransclusionHtml(\n md: MarkdownIt,\n rawTarget: string,\n aliasParts: string[],\n env: AllYouNeedEnv,\n): string {\n const { index, options } = env\n const result = resolveWikilink(rawTarget, index, options, 'transclusion')\n\n if (result.isDead || !result.target) {\n return `<div class=\"transclusion transclusion--dead\" data-target=\"${escapeHtml(\n rawTarget,\n )}\">⚠️ 找不到笔记 <code>${escapeHtml(rawTarget)}</code></div>`\n }\n\n const target = result.target\n\n // 注册 backlink\n const arr = index.backlinks.get(target.absolutePath) ?? []\n if (env.currentPath) {\n arr.push({\n fromPath: env.currentPath,\n fromUrl: index.files.get(env.currentPath)?.url ?? '',\n context: '',\n isEmbed: true,\n line: -1,\n })\n }\n index.backlinks.set(target.absolutePath, arr)\n\n const stack = env.transclusionStack ?? []\n if (stack.includes(target.absolutePath)) {\n return `<div class=\"transclusion transclusion--cycle\" data-target=\"${escapeHtml(\n rawTarget,\n )}\">⚠️ 循环引用:<code>${escapeHtml(\n rawTarget,\n )}</code> 已在 transclusion 链上</div>`\n }\n\n const depth = env.transclusionDepth ?? 0\n if (depth >= options.embeds.transclusionMaxDepth) {\n return `<div class=\"transclusion transclusion--too-deep\" data-target=\"${escapeHtml(\n rawTarget,\n )}\">⚠️ transclusion 嵌套过深(> ${options.embeds.transclusionMaxDepth})</div>`\n }\n\n const headingPart = extractHeading(rawTarget)\n const fragment = headingPart\n ? sliceByHeading(target, headingPart, options.slugify)\n : target.content\n\n if (fragment == null) {\n return `<div class=\"transclusion transclusion--unmatched-anchor\" data-target=\"${escapeHtml(\n rawTarget,\n )}\">⚠️ 找不到章节 <code>#${escapeHtml(\n headingPart,\n )}</code></div>`\n }\n\n const cacheKey = `${target.absolutePath}::${headingPart ?? ''}`\n const cache = getCache(env)\n let inner: string\n const cached = cache.get(cacheKey)\n if (cached) {\n inner = cached.html\n } else {\n // ⚠️ 关键:childEnv **只显式继承**我们这个插件需要共享的字段。\n // 不能用 { ...env, ... } 浅拷贝,否则 env.frontmatter / env.__data /\n // env.headers / env.excerpt 等 VitePress per-page 字段会被引用共享。\n // 递归 md.render 时,@mdit-vue/plugin-frontmatter 等插件会就地重置\n // 这些字段(因为内联的 fragment 没有自己的 frontmatter),从而 **覆盖\n // 掉外层页面的 frontmatter** —— VitePress 后续读不到 pageData → 路由\n // 数据缺失 → 首页 404。这是 v0.1 收尾期最坑的一个 bug,见 transclusion 测试。\n const childEnv: AllYouNeedEnv = {\n index: env.index,\n options: env.options,\n currentPath: target.absolutePath,\n transclusionStack: [...stack, target.absolutePath],\n transclusionDepth: depth + 1,\n // 跨递归共享:asset 引用集合(build 时要 emit 所有被引用 asset)\n referencedAssets: env.referencedAssets,\n }\n // 跨递归共享:transclusion 渲染缓存(同一笔记被多处 embed 时复用)\n ;(childEnv as unknown as Record<string, unknown>)._transclusionCache = (\n env as unknown as Record<string, unknown>\n )._transclusionCache\n\n inner = md.render(fragment, childEnv)\n cache.set(cacheKey, { html: inner })\n }\n\n const sourceUrl = headingPart\n ? `${target.url}#${options.slugify(headingPart)}`\n : target.url\n\n const aliasData = aliasParts.length\n ? ` data-caption=\"${escapeHtml(aliasParts.join('|'))}\"`\n : ''\n\n // v0.2 美化:右上角\"前往源文件\"按钮 —— 极简箭头图标,不带 basename 文字\n // (basename 已经通过 data-source attr 可以读取;鼠标 hover title 也能看)\n const sourceLink =\n `<a class=\"transclusion-source-link\" ` +\n `href=\"${escapeHtml(sourceUrl)}\" ` +\n `aria-label=\"Go to source: ${escapeHtml(target.relativePath)}\" ` +\n `title=\"${escapeHtml(target.relativePath)}\">↗</a>`\n\n return (\n `<div class=\"transclusion\" data-source=\"${escapeHtml(target.relativePath)}\"` +\n ` data-source-url=\"${escapeHtml(sourceUrl)}\"${aliasData}>` +\n sourceLink +\n inner +\n `</div>`\n )\n}\n\n/**\n * inline 上下文中的 ![[note]] —— 不做真 transclusion,降级为带告警的链接。\n * 原因:transclusion 内含 block 元素(<h1>/<div> 等),嵌进 <p> 会产生不合法 HTML。\n */\nexport function handleTransclusion(\n state: StateInline,\n rawTarget: string,\n aliasParts: string[],\n env: AllYouNeedEnv,\n): boolean {\n if (env.options.deadLink !== 'silent') {\n console.warn(\n `vitepress-allyouneed: ![[${rawTarget}]] 在段落中无法 transclude(会产生不合法 HTML),已降级为链接。请单独放一行。`,\n )\n }\n const { index, options } = env\n const result = resolveWikilink(rawTarget, index, options, 'page')\n const url = result.url\n const label = aliasParts.length\n ? aliasParts.join('|').trim()\n : result.defaultLabel\n\n const html =\n `<a class=\"wikilink wikilink--inline-transclusion-degraded\" ` +\n `href=\"${escapeHtml(url)}\" ` +\n `data-wikilink-target=\"${escapeHtml(rawTarget)}\" ` +\n `title=\"行内 transclusion 已降级,见控制台\">` +\n `${escapeHtml(label)}</a>`\n\n const token = state.push('html_inline', '', 0)\n token.content = html\n return true\n}\n\nfunction extractHeading(raw: string): string {\n const hashIdx = raw.indexOf('#')\n if (hashIdx < 0) return ''\n return raw.slice(hashIdx + 1).trim()\n}\n\nfunction sliceByHeading(\n target: FileEntry,\n headingPart: string,\n slugify: (s: string) => string,\n): string | undefined {\n const matched = target.headings.find(\n (h) =>\n h.text === headingPart ||\n h.slug === headingPart ||\n h.slug === slugify(headingPart),\n )\n if (!matched) return undefined\n\n const lines = target.content.split(/\\r?\\n/)\n const startLine = matched.line + 1\n let endLine = lines.length\n for (let i = startLine; i < lines.length; i++) {\n const l = lines[i]!\n const m = l.match(/^(#{1,6})\\s+/)\n if (m && m[1]!.length <= matched.level) {\n endLine = i\n break\n }\n }\n return lines.slice(startLine, endLine).join('\\n').trim()\n}\n\nfunction getCache(env: AllYouNeedEnv): Map<string, TransclusionCacheEntry> {\n const e = env as unknown as {\n _transclusionCache?: Map<string, TransclusionCacheEntry>\n }\n if (!e._transclusionCache) e._transclusionCache = new Map()\n return e._transclusionCache\n}\n","/**\n * v0.3 — audio / video / pdf embed 渲染。\n *\n * 复用 image.ts 同款 asset 解析路径(走 resolveAsset + buildPlaceholderUrl),\n * 唯一差别是输出 `<audio>` / `<video>` / `<iframe>` 标签。\n *\n * 调用约定:\n * - block 上下文:返回 HTML 字符串,调用方包成 html_block token\n * - inline 上下文:由 wikilinks/rule.ts 通过 handleMediaEmbed 推 html_inline\n *\n * 尺寸语法继承 image:\n * - audio:忽略尺寸(audio 没有视觉尺寸)\n * - video:支持 width/height\n * - pdf:支持 width/height(iframe 直接吃)\n */\n\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type { AllYouNeedEnv } from '../../core/types.js'\nimport { resolveAsset } from '../../core/resolver.js'\nimport { basename } from '../../utils/path.js'\nimport { escapeHtml } from '../../utils/escape.js'\nimport { buildPlaceholderUrl } from '../../core/asset-pipeline/build-emit.js'\n\nconst AUDIO_EXTS = ['mp3', 'wav', 'ogg', 'm4a', 'flac', 'aac', 'webm']\nconst VIDEO_EXTS = ['mp4', 'webm', 'mov', 'm4v', 'avi', 'mkv']\nconst PDF_EXTS = ['pdf']\n\nexport function isAudioExt(ext: string): boolean {\n return AUDIO_EXTS.includes(ext.toLowerCase())\n}\nexport function isVideoExt(ext: string): boolean {\n return VIDEO_EXTS.includes(ext.toLowerCase())\n}\nexport function isPdfExt(ext: string): boolean {\n return PDF_EXTS.includes(ext.toLowerCase())\n}\n\n/** 把 ext 归到 media 类型;不是 media 时返回 null */\nexport function classifyMediaExt(\n ext: string,\n): 'audio' | 'video' | 'pdf' | null {\n if (isVideoExt(ext)) return 'video'\n if (isAudioExt(ext)) return 'audio'\n if (isPdfExt(ext)) return 'pdf'\n return null\n}\n\ninterface ParsedDim {\n width?: number\n height?: number\n}\n\n/** 取最后一段 alias 当尺寸 token(逻辑和 image.ts 一致,但这里精简一份) */\nfunction parseAliasDim(parts: string[]): ParsedDim {\n if (parts.length === 0) return {}\n const last = parts[parts.length - 1]!.trim().toLowerCase()\n if (!last) return {}\n if (last.includes('x')) {\n const [w, h] = last.split('x')\n const wOk = w === '' || /^\\d+$/.test(w!)\n const hOk = h === '' || /^\\d+$/.test(h!)\n if (!wOk || !hOk) return {}\n return {\n width: w === '' ? undefined : Number(w),\n height: h === '' ? undefined : Number(h),\n }\n }\n if (/^\\d+$/.test(last)) return { width: Number(last) }\n return {}\n}\n\n/** 解析 asset 路径 → 最终 src URL(沿用 image 同款 placeholder URL)*/\nfunction resolveSrc(rawTarget: string, env: AllYouNeedEnv): string {\n const { index, options } = env\n const processedTarget = options.embeds.postProcessImageTarget(rawTarget)\n const { asset } = resolveAsset(processedTarget, index, options)\n if (asset) {\n asset.referencedBy.add(env.currentPath ?? '<unknown>')\n env.referencedAssets?.add(asset)\n return buildPlaceholderUrl(asset, options) + options.embeds.uriSuffix\n }\n return (\n options.base +\n encodeURIComponent(basename(processedTarget)) +\n options.embeds.uriSuffix\n )\n}\n\n// ── 渲染:audio / video / pdf ─────────────────────────────────────\n\nexport function renderAudioHtml(\n rawTarget: string,\n _aliasParts: string[],\n env: AllYouNeedEnv,\n): string {\n const src = resolveSrc(rawTarget, env)\n return (\n `<audio class=\"ayn-embed ayn-embed--audio\" controls preload=\"metadata\" ` +\n `src=\"${escapeHtml(src)}\">` +\n `Your browser does not support the audio element.` +\n `</audio>`\n )\n}\n\nexport function renderVideoHtml(\n rawTarget: string,\n aliasParts: string[],\n env: AllYouNeedEnv,\n): string {\n const src = resolveSrc(rawTarget, env)\n const dim = parseAliasDim(aliasParts)\n const attrs: string[] = [\n `class=\"ayn-embed ayn-embed--video\"`,\n `controls`,\n `preload=\"metadata\"`,\n `src=\"${escapeHtml(src)}\"`,\n ]\n if (dim.width !== undefined) attrs.push(`width=\"${dim.width}\"`)\n if (dim.height !== undefined) attrs.push(`height=\"${dim.height}\"`)\n return (\n `<video ${attrs.join(' ')}>` +\n `Your browser does not support the video element.` +\n `</video>`\n )\n}\n\nexport function renderPdfHtml(\n rawTarget: string,\n aliasParts: string[],\n env: AllYouNeedEnv,\n): string {\n const src = resolveSrc(rawTarget, env)\n const dim = parseAliasDim(aliasParts)\n // 默认尺寸:全宽 + 600px 高(给 iframe 一个起码可读的视口)\n const width = dim.width !== undefined ? `${dim.width}px` : '100%'\n const height = dim.height !== undefined ? `${dim.height}px` : '600px'\n return (\n `<iframe class=\"ayn-embed ayn-embed--pdf\" ` +\n `src=\"${escapeHtml(src)}\" ` +\n `style=\"width:${escapeHtml(width)};height:${escapeHtml(height)};border:0\" ` +\n `loading=\"lazy\" title=\"${escapeHtml(basename(rawTarget))}\">` +\n `</iframe>`\n )\n}\n\n/**\n * inline 上下文入口:由 wikilinks/rule.ts 在判断 isMedia 后调用。\n * 推一个 html_inline token,内含适配的播放器/iframe HTML。\n */\nexport function handleMediaEmbed(\n state: StateInline,\n kind: 'audio' | 'video' | 'pdf',\n rawTarget: string,\n aliasParts: string[],\n env: AllYouNeedEnv,\n): boolean {\n let html: string\n if (kind === 'audio') html = renderAudioHtml(rawTarget, aliasParts, env)\n else if (kind === 'video') html = renderVideoHtml(rawTarget, aliasParts, env)\n else html = renderPdfHtml(rawTarget, aliasParts, env)\n const token = state.push('html_inline', '', 0)\n token.content = html\n return true\n}\n","/**\n * wikilinks inline rule:识别 [[...]] 与 ![[...]]。\n *\n * 这条规则在 wikilinks/embeds 都启用时被共用,内部按 isEmbed 分派。\n * 注册顺序:`md.inline.ruler.before('link', 'allyouneed_wikilinks', rule)`。\n */\n\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type {\n AllYouNeedEnv,\n ResolvedOptions,\n VaultIndex,\n} from '../../core/types.js'\nimport { resolveWikilink } from '../../core/resolver.js'\nimport {\n renderPageLink,\n renderDeadLink,\n} from './render.js'\nimport { handleImageEmbed } from '../embeds/image.js'\nimport { handleTransclusion } from '../embeds/transclusion.js'\nimport { classifyMediaExt, handleMediaEmbed } from '../embeds/media.js'\n\n/**\n * 构造 inline rule。\n *\n * @param md markdown-it 实例,仅用于把 env 取出来\n * @param scope 控制此规则处理哪些前缀:'both' / 'wikilinks-only' / 'embeds-only'\n */\nexport function makeWikilinkRule(\n scope: 'both' | 'wikilinks-only' | 'embeds-only',\n): (state: StateInline, silent: boolean) => boolean {\n return function wikilinkRule(state, silent) {\n const src = state.src\n const start = state.pos\n const max = state.posMax\n\n let isEmbed = false\n let inner: string\n\n // 探测 ![[ 或 [[\n if (\n src.charCodeAt(start) === 0x21 /* ! */ &&\n src.charCodeAt(start + 1) === 0x5b /* [ */ &&\n src.charCodeAt(start + 2) === 0x5b /* [ */\n ) {\n if (scope === 'wikilinks-only') return false\n isEmbed = true\n } else if (\n src.charCodeAt(start) === 0x5b /* [ */ &&\n src.charCodeAt(start + 1) === 0x5b /* [ */\n ) {\n if (scope === 'embeds-only') return false\n } else {\n return false\n }\n\n const innerStart = start + (isEmbed ? 3 : 2)\n const closeIdx = src.indexOf(']]', innerStart)\n if (closeIdx < 0 || closeIdx >= max) return false\n\n inner = src.slice(innerStart, closeIdx)\n if (inner.includes('\\n')) return false // 不跨行\n if (!inner.trim()) return false\n\n // 按 markdown-it 约定:silent 模式找到匹配返回 true\n if (silent) return true\n\n // 提取 env\n const env = state.env as AllYouNeedEnv\n if (!env || !env.index || !env.options) {\n // 没注入索引 → 视为不识别,把控制权交回 markdown-it 默认链\n return false\n }\n\n state.pos = closeIdx + 2 // 推进游标\n\n const parts = inner.split('|').map((p) => p.trim())\n const rawTarget = parts[0]!\n const aliasParts = parts.slice(1)\n\n if (isEmbed) {\n // 路由顺序:image → audio/video/pdf → transclusion(.md)\n const ext = extractExt(rawTarget)\n const isImage =\n ext && env.options.embeds.imageFileExt.includes(ext.toLowerCase())\n if (isImage) {\n return handleImageEmbed(state, rawTarget, aliasParts, env)\n }\n const mediaKind = ext ? classifyMediaExt(ext) : null\n if (mediaKind) {\n return handleMediaEmbed(state, mediaKind, rawTarget, aliasParts, env)\n }\n return handleTransclusion(state, rawTarget, aliasParts, env)\n }\n\n // 普通 [[wikilink]]\n return emitPageLink(state, rawTarget, aliasParts, env)\n }\n}\n\n/**\n * 取一个 path 的扩展名(小写,无点),无扩展名返回 ''。\n */\nfunction extractExt(target: string): string {\n // 拆 #heading 之前先剥\n const cleaned = target.split('#')[0]!\n const dot = cleaned.lastIndexOf('.')\n if (dot <= 0) return ''\n return cleaned.slice(dot + 1).toLowerCase()\n}\n\n/**\n * 渲染一个 [[wikilink]]:解析 target → URL → push tokens。\n */\nfunction emitPageLink(\n state: StateInline,\n rawTarget: string,\n aliasParts: string[],\n env: AllYouNeedEnv,\n): boolean {\n const { index, options } = env\n const userAlias = aliasParts.length > 0 ? aliasParts.join('|').trim() : ''\n const processed = options.wikilinks.postProcessLinkTarget(rawTarget)\n const result = resolveWikilink(processed, index, options, 'page', env.currentPath)\n\n const label = userAlias\n ? options.wikilinks.postProcessLinkLabel(userAlias)\n : result.defaultLabel\n\n // 登记 backlink(用于 graph 模块)\n registerBacklink(env, result.target?.absolutePath, false)\n\n if (result.isDead) {\n handleDeadLink(env, rawTarget)\n return renderDeadLink(state, result.url, label, rawTarget, env)\n }\n return renderPageLink(state, result, label, env)\n}\n\n/** 登记反向链接(target 是被链接的页面)*/\nfunction registerBacklink(\n env: AllYouNeedEnv,\n targetPath: string | undefined,\n isEmbed: boolean,\n): void {\n if (!targetPath || !env.currentPath) return\n const arr = env.index.backlinks.get(targetPath) ?? []\n arr.push({\n fromPath: env.currentPath,\n fromUrl: env.index.files.get(env.currentPath)?.url ?? '',\n context: '',\n isEmbed,\n line: -1,\n })\n env.index.backlinks.set(targetPath, arr)\n}\n\n/** 死链 → 按 deadLink 策略输出告警 */\nfunction handleDeadLink(env: AllYouNeedEnv, rawTarget: string): void {\n const { options } = env\n const msg = `vitepress-allyouneed: 死链 [[${rawTarget}]]${\n env.currentPath ? ` (in ${env.currentPath})` : ''\n }`\n if (options.deadLink === 'silent') return\n if (options.deadLink === 'warn') {\n console.warn(msg)\n return\n }\n // 'error':仍然渲染,但把错误推到 index.warnings 让 build 失败\n env.index.warnings.push({\n kind: 'unknown',\n message: msg,\n affected: env.currentPath ? [env.currentPath] : [],\n })\n}\n\n// 抑制 unused 警告\nexport type { VaultIndex, ResolvedOptions }\n","/**\n * wikilinks 模块入口。\n *\n * register(md, scope) 把规则装进 markdown-it 实例。scope 决定本规则\n * 同时还要不要处理 ![[]];当 wikilinks 模块单独启用、embeds 模块关闭时\n * 走 'wikilinks-only',反之亦然。两者都开就 'both'(同一个规则,内部分派)。\n */\n\nimport type MarkdownIt from 'markdown-it'\nimport { makeWikilinkRule } from './rule.js'\n\nexport function registerWikilinks(\n md: MarkdownIt,\n scope: 'both' | 'wikilinks-only' | 'embeds-only',\n): void {\n md.inline.ruler.before(\n 'link',\n 'allyouneed_wikilinks',\n makeWikilinkRule(scope),\n )\n}\n","/**\n * Block rule:整行只有 `![[...]]` 时按 block-level 处理,推 `html_block` token。\n *\n * 这条规则**必须**存在,否则 markdown-it 会把 `![[note]]` 当成段落里的 inline\n * 内容,渲染出 `<p><div class=\"transclusion\">...</div></p>` —— 不合法 HTML\n * (`<div>` 不能在 `<p>` 里),Vue/VitePress 会爆 hydration 警告。\n *\n * 配合 wikilinks/rule.ts 的 inline 规则:\n * - 单独一行的 ![[...]] → 本规则吃掉,html_block\n * - 段落中混合的 ![[...]] → inline 规则处理,image 走 html_inline,\n * transclusion 降级为链接\n */\n\nimport type StateBlock from 'markdown-it/lib/rules_block/state_block.mjs'\nimport type MarkdownIt from 'markdown-it'\nimport type { AllYouNeedEnv } from '../../core/types.js'\nimport { renderImageHtml } from './image.js'\nimport { renderTransclusionHtml } from './transclusion.js'\nimport {\n classifyMediaExt,\n renderAudioHtml,\n renderVideoHtml,\n renderPdfHtml,\n} from './media.js'\n\nconst LINE_RE = /^!\\[\\[([^\\n\\]]+)\\]\\]\\s*$/\n\nexport function registerEmbedBlockRule(md: MarkdownIt): void {\n md.block.ruler.before(\n 'paragraph',\n 'allyouneed_embed_block',\n makeRule(md),\n { alt: ['paragraph'] },\n )\n}\n\nfunction makeRule(md: MarkdownIt) {\n return function embedBlockRule(\n state: StateBlock,\n startLine: number,\n _endLine: number,\n silent: boolean,\n ): boolean {\n const start = state.bMarks[startLine]! + state.tShift[startLine]!\n const max = state.eMarks[startLine]!\n const lineText = state.src.slice(start, max)\n\n const m = lineText.match(LINE_RE)\n if (!m) return false\n if (silent) return true\n\n const env = state.env as AllYouNeedEnv\n if (!env || !env.index || !env.options) return false\n\n const inner = m[1]!\n const parts = inner.split('|').map((p) => p.trim())\n const rawTarget = parts[0]!\n const aliasParts = parts.slice(1)\n\n const ext = extractExt(rawTarget)\n const isImage =\n !!ext && env.options.embeds.imageFileExt.includes(ext.toLowerCase())\n const mediaKind = ext ? classifyMediaExt(ext) : null\n\n let html: string\n if (isImage) {\n html = renderImageHtml(rawTarget, aliasParts, env)\n } else if (mediaKind === 'audio') {\n html = renderAudioHtml(rawTarget, aliasParts, env)\n } else if (mediaKind === 'video') {\n html = renderVideoHtml(rawTarget, aliasParts, env)\n } else if (mediaKind === 'pdf') {\n html = renderPdfHtml(rawTarget, aliasParts, env)\n } else {\n html = renderTransclusionHtml(md, rawTarget, aliasParts, env)\n }\n\n const token = state.push('html_block', '', 0)\n token.content = html + '\\n'\n token.map = [startLine, startLine + 1]\n\n state.line = startLine + 1\n return true\n }\n}\n\nfunction extractExt(target: string): string {\n const cleaned = target.split('#')[0]!\n const dot = cleaned.lastIndexOf('.')\n if (dot <= 0) return ''\n return cleaned.slice(dot + 1).toLowerCase()\n}\n","/**\n * embeds 模块入口。\n *\n * embeds 模块有两条规则:\n * 1. **block rule**(`registerEmbedBlockRule`):整行只有 ![[...]] 时按 block-level\n * 处理,推 `html_block`。**必须有,否则 transclusion 会产生 `<div>` in `<p>` 不合法 HTML**。\n * 2. **inline rule**(共用 wikilinks 模块的 makeWikilinkRule):处理段落内混合的\n * ![[...]]。image 走 inline image,transclusion 降级为告警链接。\n *\n * markdown-it.ts 在两种情况下分别调用:\n * - wikilinks + embeds 都开:wikilinks/index.ts 注册 inline 'both';本文件注册 block。\n * - 只开 embeds:本文件 registerEmbedsOnly 注册 inline 'embeds-only';同时注册 block。\n */\n\nimport type MarkdownIt from 'markdown-it'\nimport { makeWikilinkRule } from '../wikilinks/rule.js'\nimport { registerEmbedBlockRule } from './block-rule.js'\n\nexport function registerEmbedsOnly(md: MarkdownIt): void {\n md.inline.ruler.before(\n 'link',\n 'allyouneed_embeds',\n makeWikilinkRule('embeds-only'),\n )\n registerEmbedBlockRule(md)\n}\n\nexport { registerEmbedBlockRule }\n","/**\n * Obsidian 13 种原生 callout 类型 + 别名映射。\n * 别名 → 规范名(用于 CSS class / 图标)\n */\n\nexport const CALLOUT_TYPES = {\n // Standard\n note: 'note',\n info: 'info',\n tip: 'tip',\n success: 'success',\n question: 'question',\n warning: 'warning',\n failure: 'failure',\n danger: 'danger',\n bug: 'bug',\n example: 'example',\n quote: 'quote',\n abstract: 'abstract',\n todo: 'todo',\n\n // Aliases (Obsidian 官方文档列出的别名)\n hint: 'tip',\n important: 'tip',\n check: 'success',\n done: 'success',\n help: 'question',\n faq: 'question',\n caution: 'warning',\n attention: 'warning',\n fail: 'failure',\n missing: 'failure',\n error: 'danger',\n cite: 'quote',\n summary: 'abstract',\n tldr: 'abstract',\n} as const\n\nexport type CalloutCanonical =\n | 'note' | 'info' | 'tip' | 'success' | 'question' | 'warning'\n | 'failure' | 'danger' | 'bug' | 'example' | 'quote' | 'abstract' | 'todo'\n\n/**\n * 把任意 raw type(可能是别名)归一化为 canonical。未知 type 退化到 'note'。\n */\nexport function normalizeCalloutType(raw: string): CalloutCanonical {\n const key = raw.trim().toLowerCase()\n const mapped = (CALLOUT_TYPES as Record<string, string>)[key]\n return (mapped ?? 'note') as CalloutCanonical\n}\n\n/** foldable 标记:`[!info]+` 默认开,`[!info]-` 默认关,无标记不可折叠 */\nexport type CalloutFoldable = 'open' | 'closed' | null\n\n/** 解析一行 `[!type][+-]? <title>` 的结果 */\nexport interface CalloutHeader {\n type: CalloutCanonical\n foldable: CalloutFoldable\n /** 用户写的 title;为空时调用方应用 DEFAULT_TITLES[type] */\n title: string\n}\n\n/** 每种 type 的默认标题(用户没写自定义 title 时用)*/\nexport const DEFAULT_TITLES: Record<CalloutCanonical, string> = {\n note: 'Note',\n info: 'Info',\n tip: 'Tip',\n success: 'Success',\n question: 'Question',\n warning: 'Warning',\n failure: 'Failure',\n danger: 'Danger',\n bug: 'Bug',\n example: 'Example',\n quote: 'Quote',\n abstract: 'Abstract',\n todo: 'Todo',\n}\n\n/** 每种 type 的 SVG icon path(用 lucide 风,inline 渲染)*/\nexport const CALLOUT_ICONS: Record<CalloutCanonical, string> = {\n note:\n '<path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>',\n info:\n '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M12 16v-4\"/><path d=\"M12 8h.01\"/>',\n tip:\n '<path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/>',\n success:\n '<path d=\"M21.801 10A10 10 0 1 1 17 3.335\"/><path d=\"m9 11 3 3L22 4\"/>',\n question:\n '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3\"/><path d=\"M12 17h.01\"/>',\n warning:\n '<path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/>',\n failure:\n '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"m15 9-6 6\"/><path d=\"m9 9 6 6\"/>',\n danger:\n '<path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/>',\n bug:\n '<path d=\"m8 2 1.88 1.88\"/><path d=\"M14.12 3.88 16 2\"/><path d=\"M9 7.13v-1a3.003 3.003 0 1 1 6 0v1\"/><path d=\"M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6\"/><path d=\"M12 20v-9\"/><path d=\"M6.53 9C4.6 8.8 3 7.1 3 5\"/><path d=\"M6 13H2\"/><path d=\"M3 21c0-2.1 1.7-3.9 3.8-4\"/><path d=\"M20.97 5c0 2.1-1.6 3.8-3.5 4\"/><path d=\"M22 13h-4\"/><path d=\"M17.2 17c2.1.1 3.8 1.9 3.8 4\"/>',\n example:\n '<path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><polyline points=\"14 2 14 8 20 8\"/><path d=\"M10 9H8\"/><path d=\"M16 13H8\"/><path d=\"M16 17H8\"/>',\n quote:\n '<path d=\"M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V20c0 1 0 1 1 1z\"/><path d=\"M15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 .25 0 .5 0 .75.031V14c0 1-1 2-2 2s-1.5.5-1.5 1V20c0 1 .5 1 1.75 1z\"/>',\n abstract:\n '<path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><polyline points=\"14 2 14 8 20 8\"/><line x1=\"16\" x2=\"8\" y1=\"13\" y2=\"13\"/><line x1=\"16\" x2=\"8\" y1=\"17\" y2=\"17\"/><line x1=\"10\" x2=\"8\" y1=\"9\" y2=\"9\"/>',\n todo:\n '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"m9 12 2 2 4-4\"/>',\n}\n","/**\n * Obsidian callouts —— `> [!type][+-]? <title>` 块语法。\n *\n * 实现思路:\n * - 注册一条 markdown-it **core** rule(在 'block' 之后跑),扫所有 token\n * 找到 blockquote_open ... paragraph_open ... 第一段首行是 `[!type] ...` 的,\n * 把整块 blockquote 改写成 html_block 包 `<div class=\"callout\">…</div>`\n * - 嵌套:Obsidian 嵌套 callout 用 `> > [!info]`,markdown-it blockquote\n * 本身递归,我们 core rule 也递归扫所有 blockquote_open\n * - 渲染 body:用 md.render(bodyMarkdown, env) 把内层 markdown 递归渲染\n * 成 HTML,贴到 .callout-content\n *\n * 不写 markdown-it 的 block ruler 自定义 —— blockquote 的解析已经稳,\n * 我们后置改写 token 流更安全。\n */\n\nimport type MarkdownIt from 'markdown-it'\nimport type Token from 'markdown-it/lib/token.mjs'\nimport type StateCore from 'markdown-it/lib/rules_core/state_core.mjs'\nimport type { AllYouNeedEnv } from '../../core/types.js'\nimport { escapeHtml } from '../../utils/escape.js'\nimport {\n normalizeCalloutType,\n DEFAULT_TITLES,\n CALLOUT_ICONS,\n type CalloutCanonical,\n type CalloutFoldable,\n type CalloutHeader,\n} from './types.js'\n\nconst HEADER_RE = /^\\[!([a-zA-Z]+)\\]([+-]?)\\s*(.*)$/\n\n/**\n * 解析 callout 头(第一段第一行)。返回 null 表示不是 callout。\n */\nexport function parseCalloutHeader(line: string): CalloutHeader | null {\n const m = HEADER_RE.exec(line.trim())\n if (!m) return null\n const type = normalizeCalloutType(m[1]!)\n const foldChar = m[2]!\n const foldable: CalloutFoldable =\n foldChar === '+' ? 'open' : foldChar === '-' ? 'closed' : null\n return { type, foldable, title: (m[3] ?? '').trim() }\n}\n\n/**\n * core 规则:扫 state.tokens,把 callout-blockquote 改写为 html_block。\n *\n * Token 结构:\n * blockquote_open\n * paragraph_open\n * inline { children: [text \"[!type] ...\", softbreak, text \"rest\"] }\n * paragraph_close\n * (可能有更多 children)\n * blockquote_close\n */\nexport function registerCalloutsCore(md: MarkdownIt): void {\n md.core.ruler.after(\n 'block',\n 'allyouneed_callouts',\n function calloutsRule(state: StateCore): boolean {\n const tokens = state.tokens\n // 从后往前扫,改写时 splice 不影响前面 index\n for (let i = tokens.length - 1; i >= 0; i--) {\n const t = tokens[i]!\n if (t.type !== 'blockquote_open') continue\n // 找配对的 blockquote_close\n const closeIdx = findMatchingClose(tokens, i)\n if (closeIdx < 0) continue\n // 检查首段第一行\n const inner = tokens.slice(i + 1, closeIdx)\n const header = extractHeader(inner)\n if (!header) continue\n // 提取剩余内容(去掉 header 行后的所有内容)\n const bodyHtml = renderBody(inner, header.firstLineRest, md, state.env)\n const html = renderCallout(header.parsed, bodyHtml)\n // 用 html_block 替换 blockquote_open...blockquote_close\n const newToken = new state.Token('html_block', '', 0)\n newToken.content = html + '\\n'\n newToken.map = t.map\n tokens.splice(i, closeIdx - i + 1, newToken)\n }\n return false\n },\n )\n}\n\n/** 找配对 blockquote_close,考虑嵌套 */\nfunction findMatchingClose(tokens: Token[], openIdx: number): number {\n let depth = 0\n for (let i = openIdx; i < tokens.length; i++) {\n const t = tokens[i]!\n if (t.type === 'blockquote_open') depth++\n else if (t.type === 'blockquote_close') {\n depth--\n if (depth === 0) return i\n }\n }\n return -1\n}\n\ninterface ExtractedHeader {\n parsed: CalloutHeader\n /** header 之后同一段的剩余文本(softbreak 之后的部分)*/\n firstLineRest: string\n}\n\n/**\n * 从 blockquote 内部 token 序列中提取 callout header。\n * Header 必须是首个 paragraph 的第一行。返回 null 表示不是 callout。\n */\nfunction extractHeader(inner: Token[]): ExtractedHeader | null {\n // 找第一个 paragraph_open\n if (inner.length === 0) return null\n const first = inner[0]!\n if (first.type !== 'paragraph_open') return null\n const inlineToken = inner[1]\n if (!inlineToken || inlineToken.type !== 'inline') return null\n\n const content = inlineToken.content\n // 取首行\n const newlineIdx = content.indexOf('\\n')\n const firstLine = newlineIdx >= 0 ? content.slice(0, newlineIdx) : content\n const rest = newlineIdx >= 0 ? content.slice(newlineIdx + 1) : ''\n\n const parsed = parseCalloutHeader(firstLine)\n if (!parsed) return null\n\n return { parsed, firstLineRest: rest }\n}\n\n/**\n * 渲染 callout body:把 header 之后的 markdown 内容用 md.render 递归渲染。\n */\nfunction renderBody(\n inner: Token[],\n firstLineRest: string,\n md: MarkdownIt,\n env: unknown,\n): string {\n // 重建 body markdown:首段去掉 header 行后的内容,加上 inner 后续 block\n // 简化策略:把 inner 渲染回 markdown 不容易,改成直接 render 剩余 tokens\n // 但 markdown-it 的 renderer 是 token → html,我们已经有 inner tokens 了。\n // 不过首段的 inline token 还含 header 行,需要替换 content。\n\n if (inner.length < 3) {\n // 只有空段,body 为空\n return ''\n }\n\n // Clone inner tokens,替换首段 inline.content 为 firstLineRest\n const cloned: Token[] = inner.map((t) => {\n const c = new (t.constructor as new (\n type: string,\n tag: string,\n nesting: number,\n ) => Token)(t.type, t.tag, t.nesting)\n Object.assign(c, t)\n // 注意 children 是数组,需要重新做 clone(避免共享)\n if (t.children) c.children = [...t.children]\n return c\n })\n\n // 替换首段 inline 的 content;若 rest 为空,把首段三个 token(open/inline/close)\n // 整段移除\n if (firstLineRest.trim() === '') {\n cloned.splice(0, 3)\n } else {\n const inlineToken = cloned[1]!\n inlineToken.content = firstLineRest\n // markdown-it 渲染 inline token 看的是 children 而不是 content;\n // 我们改了 content 必须重新 parse 一次,把新 children 填回去\n const newChildren: Token[] = []\n inlineToken.children = newChildren\n md.inline.parse(firstLineRest, md, env as object, newChildren)\n }\n\n return md.renderer.render(cloned, md.options, env)\n}\n\n/**\n * 渲染 callout 最终 HTML。\n */\nfunction renderCallout(header: CalloutHeader, bodyHtml: string): string {\n const { type, foldable, title } = header\n const displayTitle = title || DEFAULT_TITLES[type]\n const iconSvg =\n `<svg class=\"callout-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" ` +\n `stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">` +\n CALLOUT_ICONS[type] +\n `</svg>`\n\n const cls = `callout callout--${type}` + (foldable ? ' callout--foldable' : '')\n\n if (foldable) {\n const isOpen = foldable === 'open'\n return (\n `<details class=\"${cls}\" data-callout=\"${type}\"${isOpen ? ' open' : ''}>` +\n `<summary class=\"callout-title\">${iconSvg}<span class=\"callout-title-text\">${escapeHtml(displayTitle)}</span></summary>` +\n `<div class=\"callout-content\">${bodyHtml}</div>` +\n `</details>`\n )\n }\n\n return (\n `<div class=\"${cls}\" data-callout=\"${type}\">` +\n `<div class=\"callout-title\">${iconSvg}<span class=\"callout-title-text\">${escapeHtml(displayTitle)}</span></div>` +\n `<div class=\"callout-content\">${bodyHtml}</div>` +\n `</div>`\n )\n}\n\n// 防 unused\nexport type { CalloutCanonical, AllYouNeedEnv }\n","/**\n * v0.3 callouts 模块入口。\n *\n * Obsidian 13 种 callout 语法:\n * > [!type][+-]? <title>\n * > body lines...\n *\n * 实现在 rule.ts 里用 markdown-it 的 core ruler 后置改写 blockquote token 流。\n */\nimport type MarkdownIt from 'markdown-it'\nimport { registerCalloutsCore, parseCalloutHeader } from './rule.js'\n\nexport { registerCalloutsCore, parseCalloutHeader }\nexport * from './types.js'\n\nexport function registerCallouts(md: MarkdownIt): void {\n registerCalloutsCore(md)\n}\n","/**\n * v0.3 — Obsidian `==text==` 高亮 inline rule。\n *\n * 渲染为 `<mark>text</mark>`,内部 markdown 继续解析(支持 `==**bold**==`)。\n *\n * 直接照搬 markdown-it-mark 的 tokenize + postProcess 双阶段方案:\n * - tokenize:遇 `=`,统计连续个数 N;每 2 个 `=` 推一个 text token 进\n * state.tokens,并往 state.delimiters 注一项 {marker: 0x3D, ...}\n * - 中间内容由 markdown-it 后续 inline rule 继续 tokenize\n * - balance_pairs 自动配对所有 delimiter(对 marker 不挑剔)\n * - postProcess:扫 delimiters 找到 marker===0x3D 且 end!==-1 的,把\n * 对应 text token 改写为 mark_open / mark_close\n */\n\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type Token from 'markdown-it/lib/token.mjs'\nimport type MarkdownIt from 'markdown-it'\n\nconst EQ = 0x3d /* = */\n\nfunction tokenize(state: StateInline, silent: boolean): boolean {\n if (silent) return false\n const start = state.pos\n const marker = state.src.charCodeAt(start)\n if (marker !== EQ) return false\n\n const scanned = state.scanDelims(state.pos, true)\n let len = scanned.length\n const ch = String.fromCharCode(marker)\n\n if (len < 2) return false\n\n // 奇数个 `=`:把第一个当普通文本\n let token: Token\n if (len % 2) {\n token = state.push('text', '', 0)\n token.content = ch\n len -= 1\n }\n\n for (let i = 0; i < len; i += 2) {\n token = state.push('text', '', 0)\n token.content = ch + ch\n\n // state.delimiters 的类型 markdown-it 内部用,这里 cast 进去\n const delims = (state as unknown as { delimiters: unknown[] }).delimiters\n delims.push({\n marker,\n length: 0, // 关掉 emphasis 用的 \"rule of 3\"\n jump: i / 2, // 1 delimiter = 2 chars\n token: state.tokens.length - 1,\n end: -1,\n open: scanned.can_open,\n close: scanned.can_close,\n })\n }\n\n state.pos += scanned.length\n return true\n}\n\ninterface DelimEntry {\n marker: number\n end: number\n token: number\n}\n\nfunction postProcess(state: StateInline): void {\n const delimiters = (state as unknown as { delimiters: DelimEntry[] })\n .delimiters\n const loneMarkers: number[] = []\n const max = delimiters.length\n\n for (let i = 0; i < max; i++) {\n const startDelim = delimiters[i]!\n if (startDelim.marker !== EQ) continue\n if (startDelim.end === -1) continue\n\n const endDelim = delimiters[startDelim.end]!\n\n let token: Token = state.tokens[startDelim.token]!\n token.type = 'mark_open'\n token.tag = 'mark'\n token.nesting = 1\n token.markup = '=='\n token.content = ''\n\n token = state.tokens[endDelim.token]!\n token.type = 'mark_close'\n token.tag = 'mark'\n token.nesting = -1\n token.markup = '=='\n token.content = ''\n\n const prev = state.tokens[endDelim.token - 1]\n if (prev && prev.type === 'text' && prev.content === '=') {\n loneMarkers.push(endDelim.token - 1)\n }\n }\n\n // 奇数残留 `=` 移到 close 后面,避免出现 `<mark>=</mark>x`\n while (loneMarkers.length > 0) {\n const i = loneMarkers.pop()!\n let j = i + 1\n while (\n j < state.tokens.length &&\n state.tokens[j]!.type === 'mark_close'\n ) {\n j += 1\n }\n j -= 1\n if (i !== j) {\n const tmp = state.tokens[j]!\n state.tokens[j] = state.tokens[i]!\n state.tokens[i] = tmp\n }\n }\n}\n\nexport function registerHighlightInline(md: MarkdownIt): void {\n // 放在 emphasis 之前,确保 `==**x**==` 中 `==` 比 `*` 先被识别\n // 如果用户开了 markdown.math(`markdown-it-mathjax3` 注册了 math_inline),\n // 我们要排在它之后 —— 不然 `$...==...$` 公式里的 `==` 会被误吃。\n try {\n // 先尝试 'after math_inline';失败说明 math 没注册,退到 emphasis 之前\n md.inline.ruler.after('math_inline', 'allyouneed_highlight', tokenize)\n } catch {\n md.inline.ruler.before('emphasis', 'allyouneed_highlight', tokenize)\n }\n // postProcess 与 emphasis 同阶段 (ruler2),按 inline / sub-inline 两层都处理\n md.inline.ruler2.before(\n 'emphasis',\n 'allyouneed_highlight',\n function highlightPostProcess(state) {\n const tokens_meta = (\n state as unknown as { tokens_meta?: Array<{ delimiters?: DelimEntry[] } | null> }\n ).tokens_meta\n const curr = (state as unknown as { delimiters?: DelimEntry[] })\n .delimiters\n if (curr) postProcess(state)\n if (tokens_meta) {\n for (const m of tokens_meta) {\n if (m && m.delimiters) {\n const proxy = {\n ...state,\n delimiters: m.delimiters,\n } as unknown as StateInline\n postProcess(proxy)\n }\n }\n }\n return false\n },\n )\n}\n","/** v0.3 highlight (`==text==`) 模块入口 */\nimport type MarkdownIt from 'markdown-it'\nimport { registerHighlightInline } from './rule.js'\n\nexport { registerHighlightInline }\n\nexport function registerHighlight(md: MarkdownIt): void {\n registerHighlightInline(md)\n}\n","/**\n * v0.3 — Obsidian 注释 `%%comment%%` 语法。\n *\n * 行为:\n * - inline `%%...%%`:静默吃掉,不渲染任何内容\n * - block 形式:整段都被 `%%` 包起来(可能跨多行)\n * ```\n * %%\n * multi-line comment\n * %%\n * ```\n * 整块从 token 流移除\n *\n * 实现:\n * - inline rule:碰到 `%%` 找到下一个 `%%`(可跨行?Obsidian 实际只在同段内匹配),\n * 吃掉,不 push token\n * - block rule:行首是 `%%`,扫到下一行的 `%%`(独占一行),整段当注释吃掉\n */\n\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type StateBlock from 'markdown-it/lib/rules_block/state_block.mjs'\nimport type MarkdownIt from 'markdown-it'\n\nconst PCT = 0x25 // '%'\n\nexport function makeCommentInlineRule(): (\n state: StateInline,\n silent: boolean,\n) => boolean {\n return function commentInline(state, silent): boolean {\n const start = state.pos\n const max = state.posMax\n if (start + 4 > max) return false\n if (state.src.charCodeAt(start) !== PCT) return false\n if (state.src.charCodeAt(start + 1) !== PCT) return false\n\n // 找下一个 `%%`,允许换行(Obsidian 行内注释可跨行)\n let pos = start + 2\n let found = -1\n while (pos < max - 1) {\n if (\n state.src.charCodeAt(pos) === PCT &&\n state.src.charCodeAt(pos + 1) === PCT\n ) {\n found = pos\n break\n }\n pos += 1\n }\n\n if (found < 0) return false\n if (silent) return true\n\n // 吃掉,不 push 任何 token\n state.pos = found + 2\n return true\n }\n}\n\n/**\n * block-level comment:`%%` 单独成行(允许尾随空格)起,\n * 下一个 `%%` 单独成行止,整段吃掉。\n *\n * 注意:markdown-it 的 block rule 接口要返回 true 表示\"消耗了若干行\"。\n */\nexport function makeCommentBlockRule(): (\n state: StateBlock,\n startLine: number,\n endLine: number,\n silent: boolean,\n) => boolean {\n return function commentBlock(state, startLine, endLine, silent): boolean {\n const pos = state.bMarks[startLine]! + state.tShift[startLine]!\n const max = state.eMarks[startLine]!\n // 必须以 `%%` 开头\n if (pos + 2 > max) return false\n if (state.src.charCodeAt(pos) !== PCT) return false\n if (state.src.charCodeAt(pos + 1) !== PCT) return false\n // 这一行 `%%` 之后必须只剩空白(才算独占一行 fence)\n const restStart = pos + 2\n const rest = state.src.slice(restStart, max)\n if (rest.trim() !== '') return false\n\n if (silent) return true\n\n // 找闭合:下一行起,寻找以 `%%` 独占的一行\n let next = startLine + 1\n let closed = false\n while (next < endLine) {\n const lpos = state.bMarks[next]! + state.tShift[next]!\n const lmax = state.eMarks[next]!\n if (\n lpos + 2 <= lmax &&\n state.src.charCodeAt(lpos) === PCT &&\n state.src.charCodeAt(lpos + 1) === PCT &&\n state.src.slice(lpos + 2, lmax).trim() === ''\n ) {\n closed = true\n break\n }\n next += 1\n }\n\n // 没找到闭合就吃到 endLine\n const lastLine = closed ? next + 1 : next\n state.line = lastLine\n return true\n }\n}\n\nexport function registerCommentsInline(md: MarkdownIt): void {\n // 放在 highlight 之前,避免 `%%` 被高亮规则误判(highlight 看 `==` 不会冲突,\n // 但越早跑越简单)\n md.inline.ruler.before(\n 'emphasis',\n 'allyouneed_comment_inline',\n makeCommentInlineRule(),\n )\n}\n\nexport function registerCommentsBlock(md: MarkdownIt): void {\n md.block.ruler.before(\n 'fence',\n 'allyouneed_comment_block',\n makeCommentBlockRule(),\n { alt: [] },\n )\n}\n","/** v0.3 comments (`%%...%%`) 模块入口 */\nimport type MarkdownIt from 'markdown-it'\nimport {\n registerCommentsInline,\n registerCommentsBlock,\n} from './rule.js'\n\nexport { registerCommentsInline, registerCommentsBlock }\n\nexport function registerComments(md: MarkdownIt): void {\n registerCommentsBlock(md)\n registerCommentsInline(md)\n}\n","/**\n * v0.3 — Pandoc 风格脚注。\n *\n * 支持的子集:\n * - 引用:`text[^id]` → 上标 `<sup><a>1</a></sup>`,自增编号\n * - 定义:行首 `[^id]: text...`(单行,**不支持**多段缩进续行 —— 留到 v0.4)\n * - 渲染:文末追加 `<section class=\"footnotes\">`,每个 def 一个 `<li>`,\n * 带反向链接箭头 ↩ 回到引用处\n *\n * 实现:\n * - block rule:扫到 `[^id]:` 起,把整行剩余文本当 def content,推一个\n * 私有 token 'footnote_def'(content=md inline 源),不影响主流\n * - inline rule:扫到 `[^id]` 推 'footnote_ref' token,记 id + 占位 number\n * - core rule(post 'inline'):收集所有 def + ref,按出现顺序编号,\n * 渲染 ref 用最终 number;在 tokens 末尾追加 footnotes section html_block\n *\n * 安全:\n * - id 只允许 `[\\w-]+`\n * - 同 id 多次引用 → 共用编号,反链多个箭头\n * - 引用了不存在的 id → 渲染成普通文本,不崩\n */\n\nimport type StateBlock from 'markdown-it/lib/rules_block/state_block.mjs'\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type StateCore from 'markdown-it/lib/rules_core/state_core.mjs'\nimport type MarkdownIt from 'markdown-it'\nimport { escapeHtml } from '../../utils/escape.js'\n\n/** 定义行:行首(允许 indent ≤3) `[^id]: rest`\n * 注:为简单起见 indent 必须 ≤3(markdown-it 默认 paragraph 阈值) */\nconst DEF_RE = /^\\[\\^([\\w-]+)\\]:\\s*(.*)$/\n/** 引用:`[^id]`,id 只允许 \\w 和 - */\nconst REF_RE = /^\\[\\^([\\w-]+)\\]/\n\n// ── block rule:抓 def ────────────────────────────────────────────\n\nfunction defBlockRule(\n state: StateBlock,\n startLine: number,\n endLine: number,\n silent: boolean,\n): boolean {\n const start = state.bMarks[startLine]! + state.tShift[startLine]!\n const max = state.eMarks[startLine]!\n const tShift = state.tShift[startLine]!\n if (tShift > 3) return false\n const line = state.src.slice(start, max)\n const m = DEF_RE.exec(line)\n if (!m) return false\n if (silent) return true\n\n const id = m[1]!\n const content = (m[2] ?? '').trim()\n\n const token = state.push('footnote_def', '', 0)\n token.meta = { id, content }\n token.map = [startLine, startLine + 1]\n token.hidden = true // 不直接渲染,等 core rule 收集\n\n state.line = startLine + 1\n // 防 endLine unused\n void endLine\n return true\n}\n\n// ── inline rule:抓 ref ──────────────────────────────────────────\n\nfunction refInlineRule(state: StateInline, silent: boolean): boolean {\n const start = state.pos\n if (state.src.charCodeAt(start) !== 0x5b /* [ */) return false\n if (state.src.charCodeAt(start + 1) !== 0x5e /* ^ */) return false\n const slice = state.src.slice(start)\n const m = REF_RE.exec(slice)\n if (!m) return false\n if (silent) return true\n\n const id = m[1]!\n const token = state.push('footnote_ref', '', 0)\n token.meta = { id }\n state.pos = start + m[0].length\n return true\n}\n\n// ── core rule:收集 + 编号 + 渲染 section ────────────────────────\n\ninterface DefRecord {\n id: string\n content: string\n number: number\n /** 这条 def 被哪几个 ref 引用,ref index → ref-token-anchor-id */\n refAnchors: string[]\n}\n\nfunction collectAndRender(state: StateCore): boolean {\n const tokens = state.tokens\n // 收集所有 def\n const defs = new Map<string, DefRecord>()\n // 把 ref 按出现顺序编号(只在 def 存在时分配编号;不存在保留 token,后面 render 兜底)\n let refSeq = 0\n let nextNumber = 1\n\n // pass 1:收集 def(不渲染顺序无关,只需要 content)\n for (let i = 0; i < tokens.length; i++) {\n const t = tokens[i]!\n if (t.type !== 'footnote_def') continue\n const meta = t.meta as { id: string; content: string }\n if (!defs.has(meta.id)) {\n defs.set(meta.id, {\n id: meta.id,\n content: meta.content,\n number: -1, // 在 ref 第一次遇到时分配\n refAnchors: [],\n })\n }\n // 把这个 def token 标记为完全空(等 core 渲染替换)\n t.type = 'html_block'\n t.content = ''\n t.hidden = true\n }\n\n // pass 2:扫所有 inline children,把 footnote_ref 改写为 html_inline\n for (const t of tokens) {\n if (t.type !== 'inline' || !t.children) continue\n for (let j = 0; j < t.children.length; j++) {\n const c = t.children[j]!\n if (c.type !== 'footnote_ref') continue\n const meta = c.meta as { id: string }\n const rec = defs.get(meta.id)\n if (!rec) {\n // 没找到 def:降级成原始文本 `[^id]`\n c.type = 'text'\n c.content = `[^${meta.id}]`\n c.meta = null\n continue\n }\n if (rec.number === -1) rec.number = nextNumber++\n const anchorId = `fnref-${escapeHtmlAttr(rec.id)}-${++refSeq}`\n rec.refAnchors.push(anchorId)\n\n c.type = 'html_inline'\n c.content =\n `<sup class=\"ayn-footnote-ref\" id=\"${anchorId}\">` +\n `<a href=\"#fn-${escapeHtmlAttr(rec.id)}\" data-footnote-ref>` +\n `[${rec.number}]` +\n `</a></sup>`\n c.meta = null\n }\n }\n\n // pass 3:把所有用到的 def(rec.number !== -1)按 number 排序后追加 section\n const used = Array.from(defs.values())\n .filter((d) => d.number !== -1)\n .sort((a, b) => a.number - b.number)\n\n if (used.length === 0) return false\n\n let html = '<section class=\"ayn-footnotes\"><hr><ol class=\"ayn-footnotes-list\">'\n for (const rec of used) {\n const renderedContent = state.md.renderInline(rec.content, state.env)\n const backlinks = rec.refAnchors\n .map(\n (anchor, idx) =>\n `<a class=\"ayn-footnote-backref\" href=\"#${anchor}\" ` +\n `data-footnote-backref aria-label=\"Back to reference ${rec.number}-${idx + 1}\">` +\n // U+2191 ↑ (UPWARDS ARROW),不是 emoji 字符;CSS font-family 强制\n // 非 emoji 字体保证显示一致(见 shared.css)\n `↑` +\n `</a>`,\n )\n .join(' ')\n html +=\n `<li id=\"fn-${escapeHtmlAttr(rec.id)}\" class=\"ayn-footnote-item\">` +\n `<span class=\"ayn-footnote-content\">${renderedContent}</span> ` +\n backlinks +\n `</li>`\n }\n html += '</ol></section>'\n\n const tail = new state.Token('html_block', '', 0)\n tail.content = html + '\\n'\n tokens.push(tail)\n\n return false\n}\n\nfunction escapeHtmlAttr(s: string): string {\n // id 只允许 \\w-,但还是过一次 escapeHtml 防意外\n return escapeHtml(s)\n}\n\n// ── 注册 ────────────────────────────────────────────────────────\n\nexport function registerFootnotes(md: MarkdownIt): void {\n md.block.ruler.before('reference', 'allyouneed_footnote_def', defBlockRule, {\n alt: ['paragraph', 'reference'],\n })\n md.inline.ruler.after('emphasis', 'allyouneed_footnote_ref', refInlineRule)\n md.core.ruler.after('inline', 'allyouneed_footnote_collect', collectAndRender)\n}\n","/**\n * v0.3 — Obsidian block-ref marker `^block-id`。\n *\n * 行为(渲染层简化版):\n * - 段落中或独立行末尾的 `^id` 被识别,从渲染文本中**剥除**\n * - 在所在 block(paragraph / heading / li / blockquote 等)的 open token 上\n * 附 `id=\"^block-id\"` 属性,作 DOM 锚点\n * - 用户可以通过 `<page>#^block-id` 直接跳转(浏览器原生 anchor scroll)\n *\n * 不在此版本做:\n * - VaultIndex 层登记 block-id(让 `[[note#^id]]` 走 resolver 跳转)\n * 这块需要碰 vault scanner,留到 v0.4\n *\n * 实现:\n * - core ruler(after 'inline'):扫所有 inline token,找 `^id`(末尾或前空白),\n * 从 content / children 中剥掉,把 id 写到前一个 open token 的 attrs\n */\n\nimport type StateCore from 'markdown-it/lib/rules_core/state_core.mjs'\nimport type Token from 'markdown-it/lib/token.mjs'\nimport type MarkdownIt from 'markdown-it'\n\n/** 末尾形式:`...\\s^id` 或 `^id`(独占)*/\nconst BLOCK_ID_TAIL_RE = /(?:^|\\s)\\^([A-Za-z0-9_-]+)\\s*$/\n\nfunction blockRefsRule(state: StateCore): boolean {\n const tokens = state.tokens\n for (let i = 0; i < tokens.length; i++) {\n const t = tokens[i]!\n if (t.type !== 'inline' || !t.children || t.children.length === 0) continue\n\n // 拼 inline 末尾文本(只看最后一个 text token,够覆盖 95% 用例)\n const lastIdx = findLastTextIdx(t.children)\n if (lastIdx < 0) continue\n const lastText = t.children[lastIdx]!\n const m = BLOCK_ID_TAIL_RE.exec(lastText.content)\n if (!m) continue\n\n const id = m[1]!\n // 从 text 末尾剥掉(留下前置空白也一起去掉)\n const matchedAt = lastText.content.length - m[0].length\n lastText.content = lastText.content.slice(0, matchedAt).replace(/\\s+$/, '')\n\n // 同步 inline.content(否则后续渲染可能误用旧 content)\n t.content = t.content.replace(BLOCK_ID_TAIL_RE, '').replace(/\\s+$/, '')\n\n // 把 id 加到上一个 *_open token(paragraph_open / heading_open / li_open ...)\n const opener = findPreviousOpen(tokens, i)\n if (opener) {\n addAttr(opener, 'id', `^${id}`)\n addClass(opener, 'ayn-block-anchor')\n }\n\n // 若剥完之后 last text 空了,把它移除(避免空 text 影响布局)\n if (lastText.content === '') {\n t.children.splice(lastIdx, 1)\n }\n }\n return false\n}\n\nfunction findLastTextIdx(children: Token[]): number {\n for (let i = children.length - 1; i >= 0; i--) {\n if (children[i]!.type === 'text') return i\n }\n return -1\n}\n\nfunction findPreviousOpen(tokens: Token[], inlineIdx: number): Token | null {\n for (let i = inlineIdx - 1; i >= 0; i--) {\n const t = tokens[i]!\n if (t.nesting === 1) return t\n }\n return null\n}\n\nfunction addAttr(token: Token, name: string, value: string): void {\n const existing = token.attrIndex(name)\n if (existing >= 0) {\n token.attrs![existing]![1] = value\n } else {\n token.attrPush([name, value])\n }\n}\n\nfunction addClass(token: Token, cls: string): void {\n const idx = token.attrIndex('class')\n if (idx >= 0) {\n const cur = token.attrs![idx]![1] ?? ''\n if (!cur.split(/\\s+/).includes(cls)) {\n token.attrs![idx]![1] = (cur + ' ' + cls).trim()\n }\n } else {\n token.attrPush(['class', cls])\n }\n}\n\nexport function registerBlockRefs(md: MarkdownIt): void {\n md.core.ruler.after('inline', 'allyouneed_block_refs', blockRefsRule)\n}\n","/**\n * markdown-it 入口。\n *\n * 高级用法:用户自己创建 markdown-it 实例,然后 md.use(allYouNeed, options)。\n * 此模式下需要由调用方负责提供 VaultIndex(通过 markdown-it env)。\n *\n * 用法示例:\n *\n * ```ts\n * import allYouNeed from 'vitepress-allyouneed/markdown-it'\n * import { scanVault, resolveOptions } from 'vitepress-allyouneed'\n *\n * const options = resolveOptions({ srcDir: '/path/to/vault' })\n * const index = scanVault(options)\n *\n * md.use(allYouNeed, options)\n *\n * // render 时把 index 注入 env\n * const html = md.render(markdown, { index, options })\n * ```\n */\n\nimport type MarkdownIt from 'markdown-it'\nimport type { ResolvedOptions, AllYouNeedOptions } from './core/types.js'\nimport { resolveOptions } from './core/config-bridge.js'\nimport { registerWikilinks } from './modules/wikilinks/index.js'\nimport {\n registerEmbedsOnly,\n registerEmbedBlockRule,\n} from './modules/embeds/index.js'\nimport { registerCallouts } from './modules/callouts/index.js'\nimport { registerHighlight } from './modules/highlight/index.js'\nimport { registerComments } from './modules/comments/index.js'\nimport { registerFootnotes } from './modules/footnotes/index.js'\nimport { registerBlockRefs } from './modules/block-refs/index.js'\n\n/**\n * markdown-it 插件函数。\n *\n * @param md markdown-it 实例\n * @param options AllYouNeedOptions 或已 resolve 过的 ResolvedOptions\n */\nfunction allYouNeedMarkdownIt(\n md: MarkdownIt,\n options?: AllYouNeedOptions | ResolvedOptions,\n): void {\n const resolved: ResolvedOptions =\n options && isResolved(options)\n ? options\n : resolveOptions(options as AllYouNeedOptions | undefined)\n\n const {\n wikilinks: wlOn,\n embeds: emOn,\n callouts: coOn,\n highlight: hlOn,\n comments: cmOn,\n footnotes: fnOn,\n blockRefs: brOn,\n } = resolved.modules\n\n if (wlOn && emOn) {\n registerWikilinks(md, 'both')\n registerEmbedBlockRule(md)\n } else if (wlOn) {\n registerWikilinks(md, 'wikilinks-only')\n // embeds 关掉时不注册 block rule\n } else if (emOn) {\n registerEmbedsOnly(md) // 内含 inline + block\n }\n\n // v0.3:Obsidian callouts(独立 core ruler,与 wikilinks/embeds 解耦)\n if (coOn) {\n registerCallouts(md)\n }\n\n // v0.3:`==text==` 高亮\n if (hlOn) {\n registerHighlight(md)\n }\n\n // v0.3:`%%comment%%` 注释(整段隐藏)\n if (cmOn) {\n registerComments(md)\n }\n\n // v0.3:Pandoc 风格 footnotes\n if (fnOn) {\n registerFootnotes(md)\n }\n\n // v0.3:block-ref `^id` 锚点(渲染层)\n if (brOn) {\n registerBlockRefs(md)\n }\n}\n\nfunction isResolved(\n o: AllYouNeedOptions | ResolvedOptions,\n): o is ResolvedOptions {\n // ResolvedOptions 有 'slugify' + 'modules' + 'srcDir'(都是必填)\n return (\n typeof (o as ResolvedOptions).slugify === 'function' &&\n typeof (o as ResolvedOptions).srcDir === 'string' &&\n typeof (o as ResolvedOptions).modules === 'object' &&\n (o as ResolvedOptions).modules !== null\n )\n}\n\nexport default allYouNeedMarkdownIt\nexport { allYouNeedMarkdownIt }\n","/**\n * Vite 插件入口。\n *\n * 职责:\n * - configResolved 时扫描 vault 建立 VaultIndex\n * - configureServer 注册 dev middleware(asset 流式响应,作为兜底)\n * - **resolveId**:拦截 markdown-it 渲染时产出的 /__ayn_asset__/ 占位 URL,\n * **直接返回 asset 的绝对文件路径**,后续交给 Vite 自带的资源管线处理:\n * - dev:Vite 自动按文件路径服务,URL 形如 /<srcDir 相对>/<asset 路径>\n * - build:Vite 自动 emit + 加 hash,URL 形如 /<assetsDir>/<name>-<hash>.<ext>\n * 这样我们就完全不用维护虚拟模块、不用写 load()、不会再撞 ?import 之类的边界\n * - handleHotUpdate:dev 增量更新\n * - config 钩子扩 server.fs.allow:用户的 vault 可能在项目根外,Vite 默认拒绝\n *\n * 设计:**完全不用 `\\0` 虚拟模块**。虚拟模块需要 Vite 在 URL 里把 id 编码成\n * `__x00__...`,加上 ?import 之类的 query,加上 URL 里 `/` 的歧义,导致 load()\n * 的 id 形态不稳定,要么找不到 asset 要么返回 HTML 把页面崩了(实测 v0.1\n * 收尾时撞过)。让 Vite 处理真实文件路径就完全没这一摊烦心事。\n */\n\nimport fs from 'node:fs'\nimport nodePath from 'node:path'\nimport type { Plugin, ResolvedConfig } from 'vite'\nimport type {\n AllYouNeedOptions,\n ResolvedOptions,\n VaultIndex,\n} from './core/types.js'\nimport { resolveOptions } from './core/config-bridge.js'\nimport { scanVault, updateFile, removeFile } from './core/vault/index.js'\nimport { createDevMiddleware } from './core/asset-pipeline/dev-middleware.js'\nimport { ASSET_PLACEHOLDER_PREFIX } from './core/asset-pipeline/build-emit.js'\nimport { toPosix } from './utils/path.js'\nimport { generateViewMarkdown } from './core/views/generate-md.js'\nimport { writeVaultData } from './core/views/generate-data.js'\n\nexport interface VitePluginAllYouNeedReturn extends Plugin {\n __getOptions(): ResolvedOptions\n __getIndex(): VaultIndex | undefined\n}\n\n/** 剥掉 ?query 和 #hash —— Vite 会带各种后缀来 */\nfunction stripQueryAndHash(id: string): string {\n return id.split('?')[0]!.split('#')[0]!\n}\n\nexport function viteAllYouNeed(\n userOptions: AllYouNeedOptions = {},\n): VitePluginAllYouNeedReturn {\n let resolved: ResolvedOptions\n let index: VaultIndex | undefined\n let viteConfig: ResolvedConfig | undefined\n\n const plugin: VitePluginAllYouNeedReturn = {\n name: 'vitepress-allyouneed',\n\n /**\n * 在 Vite 配置定型前扩 server.fs.allow,让我们的 vault srcDir 可被 Vite\n * 服务(即便 srcDir 不在项目根下)。\n */\n config(_userViteConfig, _envCtx) {\n const srcDirOpt = userOptions.srcDir\n if (!srcDirOpt) return undefined\n const abs = toPosix(nodePath.resolve(srcDirOpt))\n return {\n server: {\n fs: {\n allow: [abs],\n },\n },\n }\n },\n\n configResolved(cfg) {\n viteConfig = cfg\n resolved = resolveOptions(userOptions, {\n srcDir: userOptions.srcDir ?? cfg.root,\n base: userOptions.base ?? cfg.base,\n cleanUrls: userOptions.cleanUrls,\n })\n try {\n index = scanVault(resolved)\n\n // v0.2:生成虚拟视图 .md(若 views 模块开)\n if (resolved.modules.views) {\n const mdReport = generateViewMarkdown(resolved, index)\n for (const written of mdReport.written) {\n cfg.logger.info(`[vitepress-allyouneed] 生成视图 ${written}`)\n }\n for (const skipped of mdReport.skipped) {\n cfg.logger.warn(\n `[vitepress-allyouneed] 跳过 ${skipped.path}: ${skipped.reason}`,\n )\n }\n if (mdReport.written.length > 0) {\n index = scanVault(resolved)\n }\n try {\n const dataReport = writeVaultData(index, resolved)\n cfg.logger.info(\n `[vitepress-allyouneed] 写 ${dataReport.path} (${dataReport.bytes}B)`,\n )\n } catch (err) {\n cfg.logger.warn(\n `[vitepress-allyouneed] vault-data.json 写入失败: ${\n err instanceof Error ? err.message : String(err)\n }`,\n )\n }\n }\n\n if (index.warnings.length > 0) {\n const top = index.warnings.slice(0, 10)\n for (const w of top) {\n cfg.logger.warn(`[vitepress-allyouneed] ${w.message}`)\n }\n if (index.warnings.length > top.length) {\n cfg.logger.warn(\n `[vitepress-allyouneed] (...还有 ${\n index.warnings.length - top.length\n } 条告警)`,\n )\n }\n }\n } catch (err) {\n cfg.logger.error(\n `[vitepress-allyouneed] vault 扫描失败: ${\n err instanceof Error ? err.message : String(err)\n }`,\n )\n index = undefined\n }\n },\n\n configureServer(server) {\n if (!index) return\n const mw = createDevMiddleware(index, resolved)\n return () => {\n server.middlewares.use(mw)\n }\n },\n\n handleHotUpdate(ctx) {\n if (!index) return\n try {\n const stat = fs.statSync(ctx.file)\n if (stat.isFile()) {\n updateFile(index, ctx.file, resolved)\n } else if (!fs.existsSync(ctx.file)) {\n removeFile(index, ctx.file, resolved)\n }\n } catch {\n removeFile(index, ctx.file, resolved)\n }\n // v0.2:数据变了 → 重新生成 vault-data.json\n if (resolved.modules.views) {\n try {\n writeVaultData(index, resolved)\n } catch {\n /* */\n }\n }\n },\n\n /**\n * 拦截占位符 URL,**返回真实绝对文件路径**(POSIX 风格)。\n *\n * Vite 拿到文件路径会:\n * - dev:按文件系统服务,id 经 transform 后变成 `export default '<url>'`\n * - build:emit asset、Rollup 自动加 hash,导出最终 URL\n */\n resolveId(id) {\n if (!index) return null\n const stripped = stripQueryAndHash(id)\n const ph = ASSET_PLACEHOLDER_PREFIX // '/__ayn_asset__/'\n const phIdx = stripped.indexOf(ph)\n if (phIdx < 0) return null\n const encoded = stripped.slice(phIdx + ph.length)\n let relPath: string\n try {\n relPath = decodeURI(encoded)\n } catch {\n return null\n }\n const asset = index.assetsByRelativePath.get(relPath)\n if (!asset) return null\n // 把原 query(?import / ?inline / ?url 等)透传给下游,否则 Vite 会\n // 用错误的 transform 来处理\n const query = id.slice(stripped.length)\n return asset.absolutePath + query\n },\n\n /**\n * 给 vitepress.ts wrapper 用。\n */\n __getOptions() {\n return resolved\n },\n __getIndex() {\n return index\n },\n }\n\n // 防 unused\n void viteConfig\n\n return plugin\n}\n\nexport default viteAllYouNeed\n","/**\n * Dev 模式中间件 —— 拦截未知 URL,从 vault asset 索引里找文件流式响应。\n *\n * 查找顺序:\n * 1. **按相对路径**(`/<base>/<relativePath>`)—— resolveId/load 路径下,\n * Vue 编译后的 `<img src>` 解析出来的 URL 走这条\n * 2. **按 basename** —— 用户直接在 markdown 用绝对 URL `/foo.png` 时兜底\n * 3. 都没命中 → next() 给 Vite 默认 404\n *\n * 零拷贝、零配置。改图片直接刷新就能看到。\n */\n\nimport fs from 'node:fs'\nimport nodePath from 'node:path'\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport type {\n VaultIndex,\n ResolvedOptions,\n AssetEntry,\n} from '../types.js'\nimport { basename } from '../../utils/path.js'\n\nexport type DevMiddleware = (\n req: IncomingMessage,\n res: ServerResponse,\n next: () => void,\n) => void\n\nexport function createDevMiddleware(\n index: VaultIndex,\n options: ResolvedOptions,\n): DevMiddleware {\n return (req, res, next) => {\n if (!req.url) return next()\n\n const cleanPath = req.url.split('?')[0]!.split('#')[0]!\n\n // 把 base 前缀剥掉,得到站内绝对路径\n let inSiteUrl = cleanPath\n if (options.base !== '/' && cleanPath.startsWith(options.base)) {\n inSiteUrl = '/' + cleanPath.slice(options.base.length)\n }\n\n let decoded: string\n try {\n decoded = decodeURIComponent(inSiteUrl)\n } catch {\n return next()\n }\n\n // 必须含扩展名才尝试解析(避免误吞 /about 这种页面路由)\n if (!/\\.[a-zA-Z0-9]+$/.test(decoded)) return next()\n\n // 1) 先按相对路径查\n const relCandidate = decoded.replace(/^\\/+/, '')\n let asset: AssetEntry | undefined =\n index.assetsByRelativePath.get(relCandidate)\n\n // 2) 再按 basename 查\n if (!asset) {\n const bn = basename(decoded)\n const map = options.caseSensitive\n ? index.assetsByBasename\n : index.assetsByBasenameLower\n const key = options.caseSensitive ? bn : bn.toLowerCase()\n const candidates = map.get(key)\n if (candidates && candidates.length > 0) asset = candidates[0]\n }\n\n if (!asset) return next()\n\n let stat: fs.Stats\n try {\n stat = fs.statSync(asset.absolutePath)\n } catch {\n return next()\n }\n\n res.statusCode = 200\n res.setHeader('Content-Type', guessMime(asset.extension))\n res.setHeader('Content-Length', String(stat.size))\n res.setHeader('Cache-Control', 'no-cache')\n\n fs.createReadStream(asset.absolutePath)\n .on('error', () => next())\n .pipe(res)\n }\n}\n\n// 极简 MIME 映射,够 vault 里常见 asset 用。\nconst MIME: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n bmp: 'image/bmp',\n avif: 'image/avif',\n ico: 'image/x-icon',\n mp4: 'video/mp4',\n webm: 'video/webm',\n mov: 'video/quicktime',\n m4v: 'video/x-m4v',\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n ogg: 'audio/ogg',\n m4a: 'audio/mp4',\n flac: 'audio/flac',\n pdf: 'application/pdf',\n canvas: 'application/json',\n excalidraw: 'application/json',\n}\n\nfunction guessMime(ext: string): string {\n return MIME[ext.toLowerCase()] ?? 'application/octet-stream'\n}\n\n// 防 unused\nexport { nodePath }\n","/**\n * v0.2 — 在 srcDir 根目录生成 3 个虚拟视图 .md 文件。\n *\n * - 不覆盖用户文件:已存在且没我们的 sentinel,跳过 + 告警\n * - 可重新生成:存在但带 sentinel(说明上次是我们生成的),允许覆盖升级模板\n */\n\nimport fs from 'node:fs'\nimport nodePath from 'node:path'\nimport type { ResolvedOptions, VaultIndex } from '../types.js'\n\nexport const VIEW_SENTINEL =\n '<!-- generated by vitepress-allyouneed (do not edit; will be regenerated) -->'\n\ntype ViewKind = 'graph' | 'stats' | 'tags'\n\ninterface ViewTemplate {\n kind: ViewKind\n fileName: string\n title: string\n component: string\n}\n\nexport interface GenerateMdReport {\n written: string[]\n skipped: { path: string; reason: string }[]\n}\n\nexport function generateViewMarkdown(\n options: ResolvedOptions,\n index: VaultIndex,\n): GenerateMdReport {\n const report: GenerateMdReport = { written: [], skipped: [] }\n if (!options.modules.views) return report\n\n const srcDir = nodePath.resolve(options.srcDir)\n const prefix = options.views.urlPrefix\n const viewDir = prefix ? nodePath.join(srcDir, prefix) : srcDir\n\n // 子目录方式时,先建目录\n if (prefix) {\n try {\n fs.mkdirSync(viewDir, { recursive: true })\n } catch {\n /* mkdir 失败下面 write 也会失败,统一在那里报 */\n }\n }\n\n const views = buildViewList(options)\n\n for (const v of views) {\n const target = nodePath.join(viewDir, v.fileName)\n\n if (fs.existsSync(target)) {\n let existing: string\n try {\n existing = fs.readFileSync(target, 'utf8')\n } catch {\n report.skipped.push({ path: target, reason: '文件不可读,跳过' })\n continue\n }\n if (!existing.includes(VIEW_SENTINEL)) {\n report.skipped.push({\n path: target,\n reason:\n `用户已有同名文件,不覆盖。要启用此视图请:` +\n `(a) 删除该文件 / (b) views.names.${v.kind} 改名 / (c) views.enabled.${v.kind}: false 关掉`,\n })\n continue\n }\n }\n\n try {\n fs.writeFileSync(target, renderTemplate(v), 'utf8')\n report.written.push(target)\n void index\n } catch (err) {\n report.skipped.push({\n path: target,\n reason: `写入失败: ${err instanceof Error ? err.message : String(err)}`,\n })\n }\n }\n\n return report\n}\n\nfunction buildViewList(options: ResolvedOptions): ViewTemplate[] {\n const { enabled, names, sidebarText, graphMaxNodes } = options.views\n const list: ViewTemplate[] = []\n if (enabled.graph) {\n list.push({\n kind: 'graph',\n fileName: `${names.graph}.md`,\n title: sidebarText.graph,\n // 把配置里的 graphMaxNodes 直接注入到组件 prop\n component: `<VaultGraph :max-nodes=\"${graphMaxNodes}\" />`,\n })\n }\n if (enabled.stats) {\n list.push({\n kind: 'stats',\n fileName: `${names.stats}.md`,\n title: sidebarText.stats,\n component: '<VaultStats />',\n })\n }\n if (enabled.tags) {\n list.push({\n kind: 'tags',\n fileName: `${names.tags}.md`,\n title: sidebarText.tags,\n component: '<Tags />',\n })\n }\n return list\n}\n\nfunction renderTemplate(v: ViewTemplate): string {\n // 关键:frontmatter `---` 必须是文件**第一行**,否则 VitePress / gray-matter\n // 不识别。sentinel HTML 注释放到 frontmatter 之后。\n // 视图页全屏展示 — sidebar/aside/outline 都隐藏,只剩中间 graph/stats/tags 组件\n return [\n '---',\n `title: ${v.title}`,\n 'layout: doc',\n 'sidebar: false',\n 'aside: false',\n 'outline: false',\n '---',\n '',\n VIEW_SENTINEL,\n '',\n `# ${v.title}`,\n '',\n v.component,\n '',\n ].join('\\n')\n}\n","/**\n * v0.2 — 把 VaultIndex 序列化为前端 JSON,放 srcDir/public/。\n *\n * 边(edges)和正文 #tag 在 markdown-it 渲染阶段才能被填进 VaultIndex.backlinks /\n * tags。我们这个函数在 vite plugin configResolved 阶段(渲染之前)就跑,\n * 所以**自己从 file.content 用正则提取** wikilink 和 #tag 写进 JSON,不依赖\n * 运行时 backlinks。否则 Graph 永远空 / Tags 不含正文标签。\n */\n\nimport fs from 'node:fs'\nimport nodePath from 'node:path'\nimport type {\n ResolvedOptions,\n VaultIndex,\n FileEntry,\n} from '../types.js'\nimport { stripMarkdownExt, toPosix, basename } from '../../utils/path.js'\n\nexport interface VaultData {\n nodes: VaultDataNode[]\n edges: VaultDataEdge[]\n tags: Record<string, VaultDataTagInfo>\n stats: VaultDataStats\n meta: { generatedAt: number; pluginVersion: string }\n}\nexport interface VaultDataNode {\n id: string\n title: string\n url: string\n tags: string[]\n mtime: number\n}\nexport interface VaultDataEdge {\n source: string\n target: string\n type: 'wikilink' | 'transclusion'\n}\nexport interface VaultDataTagInfo {\n count: number\n files: {\n id: string\n url: string\n title: string\n mtime: number\n path: string\n /** 该文件除了\"当前 tag\"之外的其它 tag */\n otherTags: string[]\n }[]\n}\nexport interface VaultDataStats {\n totalFiles: number\n totalAssets: number\n totalWikilinks: number\n totalTags: number\n totalWarnings: number\n mostRecent: { id: string; url: string; title: string; mtime: number }[]\n}\n\nconst PLUGIN_VERSION = '0.2.0-beta.0'\n\n// `[[...]]` 或 `![[...]]`,不跨行,允许 |alias 和 #heading\nconst WIKILINK_RE = /(!?)\\[\\[([^\\]\\n|#]+)(?:#[^\\]\\n|]*)?(?:\\|[^\\]\\n]*)?\\]\\]/g\n\n// 正文 #tag(和 src/modules/tags/rule.ts 的语义保持一致,但允许更宽前置字符)\nconst BODY_TAG_RE =\n /(?:^|[\\s([{,;。,;])#([\\p{L}_][\\p{L}\\p{N}_/-]*)/gu\n\nexport function buildVaultData(\n index: VaultIndex,\n options: ResolvedOptions,\n): VaultData {\n // 排除插件自动生成的视图文件(_perspectives_/graph.md 等),它们是系统\n // 生成的工具页,不应该出现在 stats / graph / tags 统计里\n const viewsPrefix = options.views.urlPrefix\n ? options.views.urlPrefix.replace(/^\\/+|\\/+$/g, '') + '/'\n : ''\n const isPerspective = (f: FileEntry): boolean => {\n if (!viewsPrefix) return false\n return f.relativePath.startsWith(viewsPrefix)\n }\n const userFiles: FileEntry[] = []\n for (const f of index.files.values()) {\n if (!isPerspective(f)) userFiles.push(f)\n }\n\n // 节点\n const nodes: VaultDataNode[] = []\n for (const f of userFiles) {\n nodes.push({\n id: f.relativePath,\n title: pickTitle(f),\n url: f.url,\n tags: [...f.tags],\n mtime: f.mtime,\n })\n }\n\n // 边:从每个文件的 content 用正则提取 wikilink\n // 同一 source→target 去重:若同时有 wikilink + transclusion,保留 transclusion\n // (transclusion 是更\"强\"的关系,渲染出来视觉上也更重)\n const edgeMap = new Map<string, VaultDataEdge>()\n for (const f of userFiles) {\n const matches = f.content.matchAll(WIKILINK_RE)\n for (const m of matches) {\n const isEmbed = m[1] === '!'\n const rawTarget = m[2]!.trim()\n const target = resolveTargetSimple(rawTarget, index, options)\n if (!target) continue\n if (isPerspective(target)) continue\n if (target.relativePath === f.relativePath) continue\n const key = `${f.relativePath}\u0000${target.relativePath}`\n const existing = edgeMap.get(key)\n // 已有 edge,且新的不是 embed(更强类型)→ 跳过\n if (existing && existing.type === 'transclusion' && !isEmbed) continue\n edgeMap.set(key, {\n source: f.relativePath,\n target: target.relativePath,\n type: isEmbed ? 'transclusion' : 'wikilink',\n })\n }\n }\n const edges: VaultDataEdge[] = [...edgeMap.values()]\n\n // 标签:frontmatter tags + 正文 #tag(若开 parseInlineTags)\n const tagsMap = new Map<string, FileEntry[]>()\n for (const f of userFiles) {\n const allTags = new Set(f.tags)\n if (options.views.parseInlineTags) {\n for (const tm of f.content.matchAll(BODY_TAG_RE)) {\n allTags.add(tm[1]!)\n }\n }\n for (const tag of allTags) {\n const arr = tagsMap.get(tag) ?? []\n arr.push(f)\n tagsMap.set(tag, arr)\n }\n }\n // 每个 file 完整 tag set(用于\"该文件除了当前 tag 之外的其它 tag\")\n const allTagsByFile = new Map<string, string[]>()\n for (const f of userFiles) {\n const set = new Set(f.tags)\n if (options.views.parseInlineTags) {\n for (const tm of f.content.matchAll(BODY_TAG_RE)) set.add(tm[1]!)\n }\n allTagsByFile.set(f.relativePath, [...set])\n }\n\n const tags: Record<string, VaultDataTagInfo> = {}\n for (const [tag, files] of tagsMap) {\n // 按 mtime 倒序(最近修改在上)\n const sorted = [...files].sort((a, b) => b.mtime - a.mtime)\n tags[tag] = {\n count: files.length,\n files: sorted.map((f) => ({\n id: f.relativePath,\n url: f.url,\n title: pickTitle(f),\n mtime: f.mtime,\n path: f.relativePath,\n otherTags: (allTagsByFile.get(f.relativePath) ?? []).filter(\n (t) => t !== tag,\n ),\n })),\n }\n }\n\n // 最近修改 10\n const mostRecent = [...userFiles]\n .sort((a, b) => b.mtime - a.mtime)\n .slice(0, 10)\n .map((f) => ({\n id: f.relativePath,\n url: f.url,\n title: pickTitle(f),\n mtime: f.mtime,\n }))\n\n return {\n nodes,\n edges,\n tags,\n stats: {\n totalFiles: userFiles.length,\n totalAssets: index.assets.size,\n totalWikilinks: edges.length,\n totalTags: Object.keys(tags).length,\n totalWarnings: index.warnings.length,\n mostRecent,\n },\n meta: { generatedAt: Date.now(), pluginVersion: PLUGIN_VERSION },\n }\n}\n\nexport function writeVaultData(\n index: VaultIndex,\n options: ResolvedOptions,\n): { path: string; bytes: number } {\n const data = buildVaultData(index, options)\n const json = JSON.stringify(data)\n const publicDir = nodePath.join(nodePath.resolve(options.srcDir), 'public')\n fs.mkdirSync(publicDir, { recursive: true })\n const out = nodePath.join(publicDir, options.views.dataFileName)\n fs.writeFileSync(out, json, 'utf8')\n return { path: out, bytes: json.length }\n}\n\nfunction pickTitle(f: FileEntry): string {\n const fm = f.frontmatter as { title?: unknown } | undefined\n if (fm && typeof fm.title === 'string' && fm.title.trim()) {\n return fm.title.trim()\n }\n return f.basename\n}\n\n/**\n * 简化版 target → FileEntry 查找,与 Resolver 行为基本一致但不导出 URL。\n */\nfunction resolveTargetSimple(\n rawTarget: string,\n index: VaultIndex,\n options: ResolvedOptions,\n): FileEntry | undefined {\n const target = stripMarkdownExt(toPosix(rawTarget))\n if (!target) return undefined\n\n // 路径形式\n if (target.includes('/')) {\n return (\n index.byRelativePath.get(target) ??\n index.byRelativePath.get(target + '.md') ??\n index.byRelativePath.get(target + '.markdown')\n )\n }\n\n // alias\n const aliasKey = options.caseSensitive ? target : target.toLowerCase()\n const aliased = index.byAlias.get(aliasKey)\n if (aliased) return aliased\n\n // basename\n const map = options.caseSensitive\n ? index.byBasename\n : index.byBasenameLower\n const candidates = map.get(\n options.caseSensitive ? target : target.toLowerCase(),\n )\n if (!candidates || candidates.length === 0) return undefined\n if (candidates.length === 1) return candidates[0]\n\n // 多个 → 取最短路径\n return [...candidates].sort(\n (a, b) =>\n a.relativePath.split('/').length - b.relativePath.split('/').length,\n )[0]\n}\n\n// 防 unused warn\nexport { basename }\n","/**\n * v0.2 — 正文 #tag inline rule(Unicode 友好,带边界过滤)。\n */\n\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type MarkdownIt from 'markdown-it'\nimport type { AllYouNeedEnv } from '../../core/types.js'\nimport { escapeHtml } from '../../utils/escape.js'\n\nconst TAG_RE = /^#([\\p{L}_][\\p{L}\\p{N}_/-]*)/u\n\nfunction isValidPrecedingChar(c: string | undefined): boolean {\n if (c === undefined) return true\n if (/\\s/.test(c)) return true\n if ('([{,;。,;'.includes(c)) return true\n return false\n}\n\nexport function makeTagRule(): (state: StateInline, silent: boolean) => boolean {\n return function tagRule(state, silent) {\n const start = state.pos\n const src = state.src\n if (src.charCodeAt(start) !== 0x23 /* # */) return false\n\n const prev = start === 0 ? undefined : src[start - 1]\n if (!isValidPrecedingChar(prev)) return false\n\n const slice = src.slice(start)\n const m = TAG_RE.exec(slice)\n if (!m) return false\n\n const tag = m[1]!\n if (silent) return true\n\n const env = state.env as AllYouNeedEnv & { referencedTags?: Set<string> }\n if (!env.referencedTags) env.referencedTags = new Set()\n env.referencedTags.add(tag)\n\n const tagsViewName = env.options?.views?.names?.tags ?? 'tags'\n const urlPrefix = env.options?.views?.urlPrefix ?? '_perspectives_'\n const base = env.options?.base ?? '/'\n const prefixSeg = urlPrefix ? `${urlPrefix}/` : ''\n const href = `${base}${prefixSeg}${tagsViewName}#${encodeURIComponent(tag)}`\n const html =\n `<a class=\"ayn-tag\" data-tag=\"${escapeHtml(tag)}\" ` +\n `href=\"${escapeHtml(href)}\">#${escapeHtml(tag)}</a>`\n\n const token = state.push('html_inline', '', 0)\n token.content = html\n\n state.pos = start + m[0].length\n return true\n }\n}\n\nexport function registerTagsInline(md: MarkdownIt): void {\n md.inline.ruler.before('link', 'allyouneed_tags', makeTagRule())\n}\n","/**\n * v0.2 — 把 3 个视图条目自动追加到 VitePress sidebar 末尾。\n *\n * 支持 array / object(per-path)/ undefined 三种 sidebar 形态。\n */\n\nimport type { ResolvedOptions } from '../types.js'\n\ninterface SidebarItem {\n text?: string\n link?: string\n items?: SidebarItem[]\n collapsed?: boolean\n base?: string\n}\n\ntype SidebarConfig =\n | SidebarItem[]\n | Record<string, SidebarItem[]>\n | undefined\n\nexport function injectViewsSidebar(\n sidebar: SidebarConfig,\n options: ResolvedOptions,\n): SidebarConfig {\n if (!options.modules.views) return sidebar\n const inject = options.views.injectInto\n const group = buildViewsGroup(options)\n if (!group) return sidebar\n\n // 即使 injectInto='nav' 或 'off',也要给 /_perspectives_/ URL 配 fallback\n // sidebar(per-folder 模式)。否则点 nav 下拉进 graph,左侧 sidebar 找不到\n // key 而显示空。\n const wantSidebar = inject === 'sidebar' || inject === 'both'\n\n if (Array.isArray(sidebar)) {\n if (wantSidebar && !sidebar.some((it) => it.text === group.text)) {\n sidebar.push(group)\n }\n return sidebar\n }\n\n if (sidebar && typeof sidebar === 'object') {\n if (wantSidebar) {\n // 每个 per-path sidebar 末尾追加 Perspectives 组\n for (const path of Object.keys(sidebar)) {\n const arr = sidebar[path]\n if (Array.isArray(arr) && !arr.some((it) => it.text === group.text)) {\n arr.push(group)\n }\n }\n }\n // _perspectives_/ 自身的 fallback sidebar(无论哪种 injectInto 都加)。\n // **key 不带 base**(VitePress sidebar 用 site-root 相对前缀做 URL 匹配)\n const prefix = options.views.urlPrefix\n ? options.views.urlPrefix.replace(/^\\/+|\\/+$/g, '')\n : ''\n if (prefix) {\n const persPath = `/${prefix}/`\n if (!sidebar[persPath]) {\n sidebar[persPath] = buildPerspectivesFallbackSidebar(\n sidebar,\n group,\n options.base.endsWith('/') ? options.base : options.base + '/',\n )\n }\n }\n return sidebar\n }\n\n return [group]\n}\n\n/**\n * 给 _perspectives_/ URL 单独生成一份 sidebar:\n * - 第一项总是\"返回首页\"\n * - 然后每个**其它顶层 path**(/guide/, /tour/, /test/ 等)做成一个简单 link 项,\n * 让用户从视图页能跳回任何 tab(VitePress 不会保留\"之前在哪\",这是 URL 决定的)\n * - 最后是 perspectives 组本身\n */\nfunction buildPerspectivesFallbackSidebar(\n allSidebars: Record<string, SidebarItem[]>,\n group: SidebarItem,\n base: string,\n): SidebarItem[] {\n // link 都 strip base(VitePress 会自动 prepend)\n const out: SidebarItem[] = [{ text: 'Home', link: '/' }]\n const topPaths = Object.keys(allSidebars).filter(\n (p) => p !== base && !p.endsWith('/_perspectives_/'),\n )\n for (const p of topPaths) {\n const seg =\n p.replace(/^\\/|\\/$/g, '').split('/').filter(Boolean).pop() ?? p\n const text = seg.charAt(0).toUpperCase() + seg.slice(1)\n // p 形如 '/vitepress-allyouneed/guide/' → strip base 后 '/guide/'\n const b = base.endsWith('/') ? base : base + '/'\n const stripped = b !== '/' && p.startsWith(b) ? '/' + p.slice(b.length) : p\n out.push({ text, link: stripped })\n }\n out.push(group)\n return out\n}\n\nfunction buildViewsGroup(options: ResolvedOptions): SidebarItem | null {\n const { enabled, names, sidebarText, urlPrefix } = options.views\n // ⚠ link **不带 base** —— VitePress sidebar/nav 约定:配置里 link 用 site-root\n // 相对路径,渲染时 VitePress 自动 prepend base。带了会双重 prefix 404(build 后)。\n const prefixSeg = urlPrefix ? `/${urlPrefix}` : ''\n const items: SidebarItem[] = []\n if (enabled.graph) {\n items.push({ text: sidebarText.graph, link: `${prefixSeg}/${names.graph}` })\n }\n if (enabled.stats) {\n items.push({ text: sidebarText.stats, link: `${prefixSeg}/${names.stats}` })\n }\n if (enabled.tags) {\n items.push({ text: sidebarText.tags, link: `${prefixSeg}/${names.tags}` })\n }\n if (items.length === 0) return null\n return {\n text: sidebarText.group,\n collapsed: true,\n items,\n }\n}\n\n// ── v0.3:把 Perspectives 放到 nav 下拉里(per-folder 模式推荐)─────\n\ninterface NavItem {\n text: string\n link?: string\n items?: NavItem[]\n activeMatch?: string\n}\n\ntype NavConfig = NavItem[] | undefined\n\n/**\n * 在 themeConfig.nav 末尾追加一个 Perspectives 下拉。\n * 仅当 views.injectInto ∈ {'nav','both'} 时调用。\n * 如果 nav 里已有同名(views.sidebarText.group)项,跳过避免重复。\n */\nexport function injectViewsNav(\n nav: NavConfig,\n options: ResolvedOptions,\n): NavConfig {\n if (!options.modules.views) return nav\n const inject = options.views.injectInto\n if (inject !== 'nav' && inject !== 'both') return nav\n\n const group = buildViewsGroup(options)\n if (!group || !group.items || group.items.length === 0) return nav\n\n const navItem: NavItem = {\n text: group.text!,\n items: group.items.map((it) => ({\n text: it.text!,\n link: it.link!,\n })),\n }\n\n const arr = Array.isArray(nav) ? [...nav] : []\n if (!arr.some((it) => it.text === navItem.text)) {\n arr.push(navItem)\n }\n return arr\n}\n","/**\n * v0.3 — 解析用户手写的 `_sidebar.md` 文件,作为该目录的 sidebar override。\n *\n * 两种写法都支持(混用也行,frontmatter.sidebar 优先):\n *\n * 1) frontmatter.sidebar 数组(VitePress 原生 sidebar shape)\n * ```yaml\n * ---\n * sidebar:\n * - text: Overview\n * link: /guide/overview\n * - text: Docs\n * collapsed: false\n * items:\n * - text: Install\n * link: /guide/docs/install\n * ---\n * ```\n *\n * 2) markdown 列表(更 Obsidian 友好,支持嵌套)\n * ```markdown\n * - [[overview|Overview]]\n * - Docs\n * - [[docs/install|Install]]\n * - [[docs/configure|Configure]]\n * - Advanced\n * - [[advanced/custom-theme|Custom theme]]\n * ```\n * - 每行 `-` 起,2 空格缩进表示子级(也支持 tab)\n * - 含 `[[wikilink|text]]` → SidebarItem { text, link }\n * - 含 `[text](link)` → 同\n * - 纯文字 → group title(无 link,可有 items)\n */\n\nimport type { FileEntry, VaultIndex, ResolvedOptions } from '../types.js'\nimport type { SidebarItem } from './types.js'\nimport { stripMarkdownExt, toPosix } from '../../utils/path.js'\n\n/** 检查一个 FileEntry 是不是 _sidebar.md(大小写不敏感) */\nexport function isSidebarOverrideFile(entry: FileEntry): boolean {\n return entry.basename.toLowerCase() === '_sidebar'\n}\n\n/**\n * 解析 _sidebar.md → SidebarItem[]。\n * 失败返回 null(调用方降级到自动生成)。\n */\nexport function parseSidebarOverride(\n entry: FileEntry,\n index: VaultIndex,\n options: ResolvedOptions,\n): SidebarItem[] | null {\n // 1) frontmatter.sidebar 优先\n const fmSidebar = (entry.frontmatter as { sidebar?: unknown }).sidebar\n if (Array.isArray(fmSidebar)) {\n return normalizeItems(fmSidebar as SidebarItem[])\n }\n\n // 2) markdown list 解析\n const items = parseList(entry.content, entry, index, options)\n if (items.length === 0) return null\n return items\n}\n\n/** 把用户写的 SidebarItem(可能字段不全)归一化 */\nfunction normalizeItems(items: SidebarItem[]): SidebarItem[] {\n return items.map((it) => {\n const out: SidebarItem = {}\n if (typeof it.text === 'string') out.text = it.text\n if (typeof it.link === 'string') out.link = it.link\n if (typeof it.base === 'string') out.base = it.base\n if (typeof it.collapsed === 'boolean') out.collapsed = it.collapsed\n if (Array.isArray(it.items)) out.items = normalizeItems(it.items)\n return out\n })\n}\n\n// ── markdown list 解析 ──────────────────────────────────────────\n\ninterface ParsedLine {\n indent: number\n text: string | null\n link: string | null\n collapsed?: boolean\n}\n\nconst LINE_RE = /^(\\s*)-\\s+(.*)$/\nconst WIKILINK_RE = /^\\[\\[([^\\]\\n|#]+)(?:#[^\\]\\n|]*)?(?:\\|([^\\]\\n]+))?\\]\\]/\nconst MD_LINK_RE = /^\\[([^\\]]+)\\]\\(([^)]+)\\)/\n\nfunction parseList(\n src: string,\n entry: FileEntry,\n index: VaultIndex,\n options: ResolvedOptions,\n): SidebarItem[] {\n const lines = src.split(/\\r?\\n/)\n const parsed: ParsedLine[] = []\n let inFence = false\n for (const raw of lines) {\n if (/^```|^~~~/.test(raw.trim())) {\n inFence = !inFence\n continue\n }\n if (inFence) continue\n const m = LINE_RE.exec(raw)\n if (!m) continue\n const indent = m[1]!.replace(/\\t/g, ' ').length\n const body = m[2]!.trim()\n parsed.push(parseLineBody(indent, body, entry, index, options))\n }\n return buildTree(parsed)\n}\n\nfunction parseLineBody(\n indent: number,\n body: string,\n entry: FileEntry,\n index: VaultIndex,\n options: ResolvedOptions,\n): ParsedLine {\n // [[wikilink|text]] / [[wikilink]]\n const wl = WIKILINK_RE.exec(body)\n if (wl) {\n const target = wl[1]!.trim()\n const customText = wl[2]?.trim()\n const resolved = resolveTarget(target, index, options, entry)\n return {\n indent,\n text: customText ?? defaultTextForTarget(target, resolved),\n link: resolved?.url ?? null,\n }\n }\n // [text](link)\n const ml = MD_LINK_RE.exec(body)\n if (ml) {\n return { indent, text: ml[1]!.trim(), link: ml[2]!.trim() }\n }\n // 纯文字 group title:支持 `Title -` 结尾控制 collapsed\n let text = body\n let collapsed: boolean | undefined\n if (text.endsWith(' +')) {\n collapsed = false\n text = text.slice(0, -2).trim()\n } else if (text.endsWith(' -')) {\n collapsed = true\n text = text.slice(0, -2).trim()\n }\n return { indent, text, link: null, collapsed }\n}\n\nfunction defaultTextForTarget(target: string, entry: FileEntry | undefined): string {\n if (entry) {\n const fm = entry.frontmatter as { sidebarTitle?: string; title?: string }\n if (typeof fm.sidebarTitle === 'string' && fm.sidebarTitle.trim()) {\n return fm.sidebarTitle.trim()\n }\n if (typeof fm.title === 'string' && fm.title.trim()) {\n return fm.title.trim()\n }\n return entry.basename\n }\n return target\n}\n\nfunction resolveTarget(\n raw: string,\n index: VaultIndex,\n options: ResolvedOptions,\n contextEntry: FileEntry,\n): FileEntry | undefined {\n const target = stripMarkdownExt(toPosix(raw))\n if (!target) return undefined\n // 路径(相对当前 _sidebar.md 所在目录,或绝对)\n if (target.includes('/')) {\n // 相对路径试一次\n const ctxDir = contextEntry.relativePath.split('/').slice(0, -1).join('/')\n const candidates = [\n target,\n target + '.md',\n ctxDir ? `${ctxDir}/${target}` : '',\n ctxDir ? `${ctxDir}/${target}.md` : '',\n ].filter(Boolean)\n for (const c of candidates) {\n const found = index.byRelativePath.get(c)\n if (found) return found\n }\n }\n // alias\n const aliasKey = options.caseSensitive ? target : target.toLowerCase()\n const aliased = index.byAlias.get(aliasKey)\n if (aliased) return aliased\n // basename\n const map = options.caseSensitive ? index.byBasename : index.byBasenameLower\n const key = options.caseSensitive ? target : target.toLowerCase()\n const arr = map.get(key)\n if (arr && arr.length > 0) return arr[0]\n return undefined\n}\n\n/** 把扁平的 ParsedLine[](带 indent)折成 SidebarItem 树 */\nfunction buildTree(lines: ParsedLine[]): SidebarItem[] {\n if (lines.length === 0) return []\n // 把所有 indent 归一化到 level(0、1、2 ...)\n const indents = [...new Set(lines.map((l) => l.indent))].sort((a, b) => a - b)\n const indentToLevel = new Map<number, number>()\n indents.forEach((i, idx) => indentToLevel.set(i, idx))\n\n const root: SidebarItem[] = []\n // 栈:[{ level, items }]\n const stack: Array<{ level: number; items: SidebarItem[] }> = [\n { level: -1, items: root },\n ]\n for (const l of lines) {\n const level = indentToLevel.get(l.indent) ?? 0\n while (stack.length > 0 && stack[stack.length - 1]!.level >= level) {\n stack.pop()\n }\n const parent = stack[stack.length - 1]!\n const item: SidebarItem = {}\n if (l.text) item.text = l.text\n if (l.link) item.link = l.link\n if (l.collapsed !== undefined) item.collapsed = l.collapsed\n parent.items.push(item)\n // 这个 item 可能成为后续行的 parent → 给它一个 items 数组\n item.items = []\n stack.push({ level, items: item.items })\n }\n // 清掉空的 items 数组(纯叶子)\n pruneEmptyItems(root)\n // 顶层根据\"items 非空但 collapsed 未设\"补默认 collapsed:true\n return root\n}\n\nfunction pruneEmptyItems(arr: SidebarItem[]): void {\n for (const it of arr) {\n if (it.items) {\n if (it.items.length === 0) delete it.items\n else pruneEmptyItems(it.items)\n }\n }\n}\n","/**\n * v0.3 — 从 VaultIndex 自动生成 VitePress sidebar。\n *\n * 支持:\n * - 任意嵌套深度(子目录递归变成 collapsible 子 group)\n * - 三种 mode:\n * 'tree' (默认)单一全局 array,顶层每个目录嵌套子项\n * 'flat' 顶层目录扁平化(老 v0.3 行为,保留兼容)\n * 'per-folder' Record<string, items[]>,VitePress 按 URL 前缀切换 sidebar\n * - frontmatter 控制:\n * sidebarTitle 覆盖标题\n * sidebarHidden 整篇隐藏(等价 sidebar: false)\n * order 排序权重(数字小在前)\n * sidebarCollapsed 作用在目录的 index.md 上,控制该 group 默认展开/折叠\n * sidebarGroup 把文件挂到\"虚拟 group\"(跨目录归类,常用于 docs / tour 等)\n * - 隐藏:\n * _-前缀目录(_drafts / _perspectives_ 等自动跳)\n * options.views.urlPrefix 目录(插件视图)\n * index.md / README.md 不作为 sibling 文件出现(已用作 group 入口)\n */\n\nimport type { FileEntry, VaultIndex, ResolvedOptions } from '../types.js'\nimport type {\n SidebarItem,\n ResolvedSidebarAutoOptions,\n SidebarAutoOptions,\n NavItem,\n} from './types.js'\nimport {\n isSidebarOverrideFile,\n parseSidebarOverride,\n} from './parse-sidebar-md.js'\n\nexport type { NavItem }\n\n// ── option resolver ──────────────────────────────────────────────\n\nexport function resolveSidebarAutoOptions(\n user: SidebarAutoOptions = {},\n): ResolvedSidebarAutoOptions {\n const strip = user.stripNumericPrefix ?? true\n return {\n mode: user.mode ?? 'fill-if-empty',\n exclude: user.exclude ?? [],\n collapsed: user.collapsed ?? true,\n sortBy: user.sortBy ?? 'order-then-title',\n // **闭包**绑定 stripNumericPrefix,让 user 设 false 时 default formatter 也尊重\n formatGroupTitle:\n user.formatGroupTitle ?? ((d: string) => humanize(d, strip)),\n formatItemTitle:\n user.formatItemTitle ?? ((e: FileEntry) => defaultItemTitle(e, strip)),\n hiddenKey: user.hiddenKey ?? 'sidebarHidden',\n titleKey: user.titleKey ?? 'sidebarTitle',\n orderKey: user.orderKey ?? 'order',\n autoNav: user.autoNav ?? false,\n homeNavText: user.homeNavText ?? 'Home',\n stripNumericPrefix: strip,\n groupOrder: user.groupOrder ?? [],\n maxDepth: user.maxDepth,\n groupLink: user.groupLink ?? 'all',\n includePrefix: user.includePrefix,\n excludePrefixes: user.excludePrefixes ?? [],\n }\n}\n\n/** item 标题计算(接收 stripNumericPrefix,在 resolveSidebarAutoOptions 阶段绑定) */\nfunction defaultItemTitle(entry: FileEntry, strip: boolean): string {\n const fm = entry.frontmatter\n const sidebarTitle = typeof fm.sidebarTitle === 'string' ? fm.sidebarTitle : ''\n if (sidebarTitle.trim()) return sidebarTitle.trim()\n const title = typeof fm.title === 'string' ? fm.title : ''\n if (title.trim()) return title.trim()\n const firstH1 = entry.headings.find((h) => h.level === 1)\n if (firstH1) return firstH1.text\n return humanize(entry.basename, strip)\n}\n\n/** 共用 humanize:剥可选前缀数字 → 替换 -/_ → Title Case */\nfunction humanize(name: string, strip: boolean): string {\n let s = name\n if (strip) s = s.replace(/^\\d+[-_.\\s]+/, '')\n return s\n .replace(/[-_]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/\\b\\w/g, (m) => m.toUpperCase())\n}\n\n// ── tree 数据结构 ───────────────────────────────────────────────\n\ninterface DirNode {\n /** 'folder1/sub' 形式;根节点为 '' */\n path: string\n /** 这层目录下的\"普通\"文件(不含 index/README/_sidebar) */\n files: FileEntry[]\n /** 子目录(map key = 段名,如 'sub') */\n children: Map<string, DirNode>\n /** 这层目录的 dirIndex 文件(同名 > index > README,大小写不敏感) */\n dirIndex?: FileEntry\n /** dirIndex 文件**正文为空**(只有 frontmatter)→ 不当 link,仅取 frontmatter */\n dirIndexEmpty?: boolean\n /** 这层目录的 _sidebar.md (手动 override 文件) */\n sidebarOverride?: FileEntry\n}\n\nfunction newNode(path: string): DirNode {\n return { path, files: [], children: new Map() }\n}\n\n// ── 主入口 ──────────────────────────────────────────────────────\n\nexport function generateSidebar(\n index: VaultIndex,\n options: ResolvedOptions,\n autoOptions: SidebarAutoOptions = {},\n): SidebarItem[] | Record<string, SidebarItem[]> {\n const opts = resolveSidebarAutoOptions(autoOptions)\n const viewsPrefix = options.views.urlPrefix\n ? options.views.urlPrefix.replace(/^\\/+|\\/+$/g, '')\n : ''\n\n // 1. 过滤可见文件\n const visible: FileEntry[] = []\n for (const entry of index.files.values()) {\n if (shouldExclude(entry, opts, viewsPrefix)) continue\n visible.push(entry)\n }\n\n // 2. 建 tree\n const root = buildTree(visible)\n\n // 3. 根据 mode 输出\n const layout = autoOptions.layout ?? 'tree'\n let result: SidebarItem[] | Record<string, SidebarItem[]>\n if (layout === 'per-folder') {\n result = toPerFolderSidebar(root, opts, options, index)\n } else if (layout === 'flat') {\n result = toFlatSidebar(root, opts)\n } else {\n result = toTreeSidebar(root, opts, index, options)\n }\n // 4. **关键**:strip 掉 link 里的 base prefix。\n // VitePress sidebar/nav 配置约定:link 不带 base,VitePress 渲染时自己 prepend。\n // 我们 entry.url 已经含 base(为了让 wikilink <a href> 直接可用),\n // sidebar 出口必须 strip,否则 build 后 (base !== '/') 会双重 prefix → 404。\n stripBaseFromConfig(result, options.base)\n return result\n}\n\n/** strip base prefix from all link fields, recursively */\nfunction stripBaseFromConfig(\n cfg: SidebarItem[] | Record<string, SidebarItem[]>,\n base: string,\n): void {\n if (Array.isArray(cfg)) {\n stripBaseFromItems(cfg, base)\n } else {\n for (const k of Object.keys(cfg)) {\n stripBaseFromItems(cfg[k]!, base)\n }\n }\n}\nfunction stripBaseFromItems(items: SidebarItem[], base: string): void {\n const b = base.endsWith('/') ? base : base + '/'\n for (const it of items) {\n if (it.link && b !== '/' && it.link.startsWith(b)) {\n it.link = '/' + it.link.slice(b.length)\n }\n if (it.items) stripBaseFromItems(it.items, base)\n }\n}\n\n// ── 建 tree ─────────────────────────────────────────────────────\n\nfunction buildTree(files: FileEntry[]): DirNode {\n const root = newNode('')\n for (const f of files) {\n const segs = f.relativePath.split('/')\n const dirSegs = segs.slice(0, -1)\n let node = root\n for (const seg of dirSegs) {\n let child = node.children.get(seg)\n if (!child) {\n child = newNode(node.path ? node.path + '/' + seg : seg)\n node.children.set(seg, child)\n }\n node = child\n }\n // _sidebar.md 单拎出来当 override(不出现在 sidebar item)\n if (isSidebarOverrideFile(f)) {\n node.sidebarOverride = f\n continue\n }\n // 先全部塞进 files,稍后 pickDirIndexes 挑出最优先级的当 dirIndex\n node.files.push(f)\n }\n pickDirIndexes(root)\n return root\n}\n\n/**\n * 在 tree 建好后,为每个非根 DirNode 选出\"文件夹索引页\"。\n *\n * 优先级(大小写不敏感):\n * 1. 与文件夹同名的 .md —— 例 `tour/tour.md` 给 tour/\n * 2. index.md\n * 3. README.md\n *\n * 选中的从 files 移到 node.dirIndex,作为 group 的 link 来源。\n * 用户文件不会被覆盖(这里只是\"找出来当 link\",不写文件)。\n *\n * 额外:若该 dirIndex 文件**只有 frontmatter、无正文内容**,记 dirIndexEmpty,\n * 渲染时不当 link(但 frontmatter 的 sidebarTitle / sidebarCollapsed 仍读)。\n */\nfunction pickDirIndexes(node: DirNode): void {\n const folderName = node.path.split('/').pop() ?? ''\n if (folderName) {\n const folderLc = folderName.toLowerCase()\n let best: { entry: FileEntry; priority: number } | null = null\n for (const f of node.files) {\n const bnLc = f.basename.toLowerCase()\n let p = 0\n if (bnLc === folderLc) p = 1\n else if (bnLc === 'index') p = 2\n else if (bnLc === 'readme') p = 3\n if (p > 0 && (best === null || p < best.priority)) {\n best = { entry: f, priority: p }\n }\n }\n if (best) {\n node.dirIndex = best.entry\n node.dirIndexEmpty = best.entry.content.trim() === ''\n node.files = node.files.filter((f) => f !== best!.entry)\n }\n }\n for (const child of node.children.values()) pickDirIndexes(child)\n}\n\n// ── tree 模式:嵌套 group ───────────────────────────────────────\n\nfunction toTreeSidebar(\n root: DirNode,\n opts: ResolvedSidebarAutoOptions,\n index: VaultIndex,\n options: ResolvedOptions,\n): SidebarItem[] {\n return renderNode(root, opts, /* depth */ 0, /* isRoot */ true, index, options)\n}\n\n/**\n * 渲染一个 DirNode 的内容(files + 子 groups)。\n * isRoot=true 时返回顶层 array;否则用于子 group 的 items。\n *\n * \"虚拟 group\" sidebarGroup:文件 frontmatter 里 sidebarGroup: 'X' 的会被\n * 抽出来挂到一个名为 X 的虚拟 group 下,跨目录归类。\n */\nfunction renderNode(\n node: DirNode,\n opts: ResolvedSidebarAutoOptions,\n depth: number,\n isRoot: boolean,\n index: VaultIndex,\n options: ResolvedOptions,\n): SidebarItem[] {\n // 嵌套深度限制\n if (opts.maxDepth !== undefined && depth > opts.maxDepth) return []\n\n // _sidebar.md 手动 override:解析成功就直接用,跳过自动生成\n if (node.sidebarOverride) {\n const override = parseSidebarOverride(node.sidebarOverride, index, options)\n if (override) return override\n }\n\n const out: SidebarItem[] = []\n\n // 抽出 sidebarGroup 标记的文件(虚拟 group)\n const virtualGroups = new Map<string, FileEntry[]>()\n const normalFiles: FileEntry[] = []\n for (const f of node.files) {\n const g = readVirtualGroup(f)\n if (g) {\n const arr = virtualGroups.get(g) ?? []\n arr.push(f)\n virtualGroups.set(g, arr)\n } else {\n normalFiles.push(f)\n }\n }\n\n // 排序普通文件\n normalFiles.sort((a, b) => compareEntries(a, b, opts))\n for (const f of normalFiles) {\n out.push({ text: opts.formatItemTitle(f), link: f.url })\n }\n\n // 虚拟 groups(按名字字母序)\n const virtualKeys = [...virtualGroups.keys()].sort()\n for (const name of virtualKeys) {\n const items = virtualGroups.get(name)!.sort((a, b) => compareEntries(a, b, opts))\n out.push({\n text: name,\n collapsed: opts.collapsed,\n items: items.map((f) => ({ text: opts.formatItemTitle(f), link: f.url })),\n })\n }\n\n // 子目录:按 groupOrder(仅顶级生效)然后字母序\n const childKeys = sortChildKeys(node, opts, isRoot)\n for (const key of childKeys) {\n const child = node.children.get(key)!\n const childItems = renderNode(child, opts, depth + 1, false, index, options)\n if (childItems.length === 0 && !child.dirIndex) continue\n\n const group: SidebarItem = {\n text: computeGroupText(child.path, child.dirIndex, opts),\n collapsed: resolveGroupCollapsed(child.dirIndex, opts),\n items: childItems,\n }\n if (\n child.dirIndex &&\n !child.dirIndexEmpty &&\n shouldLinkGroup(opts, isRoot)\n ) {\n group.link = child.dirIndex.url\n }\n out.push(group)\n }\n\n return out\n}\n\n/**\n * 递归找 DirNode 子树的\"第一个可访问 page\"的 url,作为 fallback link。\n * 顺序:本节点 dirIndex(若非空) → 本节点 files 排序后第一个 → 各子目录递归。\n */\nfunction findFirstPageUrl(\n node: DirNode,\n opts: ResolvedSidebarAutoOptions,\n): string | null {\n if (node.dirIndex && !node.dirIndexEmpty) return node.dirIndex.url\n if (node.files.length > 0) {\n const sorted = [...node.files].sort((a, b) => compareEntries(a, b, opts))\n return sorted[0]!.url\n }\n const childKeys = [...node.children.keys()].sort()\n for (const k of childKeys) {\n const u = findFirstPageUrl(node.children.get(k)!, opts)\n if (u) return u\n }\n return null\n}\n\n/** 根据 groupLink 决定本层 group 是否可点(顶级 isRoot=true) */\nfunction shouldLinkGroup(opts: ResolvedSidebarAutoOptions, isTopLevel: boolean): boolean {\n if (opts.groupLink === 'off') return false\n if (opts.groupLink === 'top-level') return isTopLevel\n return true // 'all'\n}\n\n/** 子目录排序:顶级用 groupOrder + 字母序 fallback,非顶级直接字母序 */\nfunction sortChildKeys(\n node: DirNode,\n opts: ResolvedSidebarAutoOptions,\n isTopLevel: boolean,\n): string[] {\n const keys = [...node.children.keys()]\n if (!isTopLevel || opts.groupOrder.length === 0) {\n return keys.sort()\n }\n // 顶级:把 groupOrder 命中的项按指定顺序;其余按字母在后\n const orderMap = new Map<string, number>()\n opts.groupOrder.forEach((name, i) => {\n // groupOrder 名字应该是 group title 或 dirname,匹配 dirname 段\n orderMap.set(name, i)\n orderMap.set(name.toLowerCase(), i)\n })\n const indexed: string[] = []\n const rest: string[] = []\n for (const k of keys) {\n const title = computeGroupText(\n node.children.get(k)!.path,\n node.children.get(k)!.dirIndex,\n opts,\n )\n if (orderMap.has(k) || orderMap.has(title)) {\n indexed.push(k)\n } else {\n rest.push(k)\n }\n }\n indexed.sort((a, b) => {\n const ta = computeGroupText(\n node.children.get(a)!.path,\n node.children.get(a)!.dirIndex,\n opts,\n )\n const tb = computeGroupText(\n node.children.get(b)!.path,\n node.children.get(b)!.dirIndex,\n opts,\n )\n const oa = orderMap.has(a) ? orderMap.get(a)! : orderMap.get(ta)!\n const ob = orderMap.has(b) ? orderMap.get(b)! : orderMap.get(tb)!\n return oa - ob\n })\n rest.sort()\n return [...indexed, ...rest]\n}\n\n// ── flat 模式(老版兼容):所有目录摊到顶层 ───────────────────\n\nfunction toFlatSidebar(root: DirNode, opts: ResolvedSidebarAutoOptions): SidebarItem[] {\n // 遍历整 tree,把每个非根节点都做成顶层 group(items 只含直系文件)\n const out: SidebarItem[] = []\n // 先根\n const rootFiles = [...root.files].sort((a, b) => compareEntries(a, b, opts))\n for (const f of rootFiles) out.push({ text: opts.formatItemTitle(f), link: f.url })\n\n const allDirs: DirNode[] = []\n walkDirs(root, allDirs)\n for (const d of allDirs) {\n const files = [...d.files].sort((a, b) => compareEntries(a, b, opts))\n const items = files.map((f) => ({ text: opts.formatItemTitle(f), link: f.url }))\n if (items.length === 0 && !d.dirIndex) continue\n const group: SidebarItem = {\n text: computeGroupText(d.path, d.dirIndex, opts),\n collapsed: resolveGroupCollapsed(d.dirIndex, opts),\n items,\n }\n // flat 模式所有 group 都在\"顶层\" — 用 isTopLevel=true\n if (d.dirIndex && !d.dirIndexEmpty && shouldLinkGroup(opts, true)) {\n group.link = d.dirIndex.url\n }\n out.push(group)\n }\n return out\n}\n\nfunction walkDirs(node: DirNode, out: DirNode[]): void {\n const keys = [...node.children.keys()].sort()\n for (const k of keys) {\n const child = node.children.get(k)!\n out.push(child)\n walkDirs(child, out)\n }\n}\n\n// ── per-folder 模式:每个顶层目录一个独立 sidebar ────────────────\n\nfunction toPerFolderSidebar(\n root: DirNode,\n opts: ResolvedSidebarAutoOptions,\n options: ResolvedOptions,\n index: VaultIndex,\n): Record<string, SidebarItem[]> {\n // ⚠ Record 的 **key**(VitePress 用来匹配 URL 前缀)和**每个 item 的 link**\n // 都用**不带 base 的形式**。VitePress 内部用 currentPath(已 strip base)\n // 做匹配,且会自动给 link prepend base。带 base 会双重 prefix。\n\n const out: Record<string, SidebarItem[]> = {}\n\n const rootItems: SidebarItem[] = []\n const sortedRootFiles = [...root.files].sort((a, b) => compareEntries(a, b, opts))\n for (const f of sortedRootFiles) {\n rootItems.push({ text: opts.formatItemTitle(f), link: f.url })\n }\n const topKeys = [...root.children.keys()].sort()\n for (const key of topKeys) {\n const child = root.children.get(key)!\n if (child.files.length === 0 && child.children.size === 0 && !child.dirIndex) {\n continue\n }\n const labelText = computeGroupText(child.path, child.dirIndex, opts)\n if (shouldLinkGroup(opts, /* isTopLevel */ true)) {\n const firstUrl =\n child.dirIndex && !child.dirIndexEmpty\n ? child.dirIndex.url\n : findFirstPageUrl(child, opts)\n // ⚠ 没有真实页面就**不加 link**(避免点击 → 假 URL → 404 → router 报模块加载失败)\n if (firstUrl) {\n rootItems.push({ text: labelText, link: firstUrl })\n } else {\n rootItems.push({ text: labelText })\n }\n } else {\n rootItems.push({ text: labelText })\n }\n }\n if (rootItems.length > 0) out['/'] = rootItems // 根 key 用 '/'\n\n for (const key of topKeys) {\n const child = root.children.get(key)!\n const items = renderNode(child, opts, /* depth */ 1, /* isRoot */ false, index, options)\n if (items.length === 0 && !child.dirIndex) continue\n\n const sidebar: SidebarItem[] = []\n const canLink =\n child.dirIndex &&\n !child.dirIndexEmpty &&\n shouldLinkGroup(opts, /* isTopLevel */ true)\n if (canLink) {\n sidebar.push({\n text: computeGroupText(child.path, child.dirIndex, opts),\n link: child.dirIndex!.url,\n })\n }\n sidebar.push(...items)\n\n out[`/${key}/`] = sidebar // key 不带 base\n }\n return out\n}\n\n// ── generateNav:从 vault 顶层目录生成 nav tabs ─────────────────\n\nexport function generateNav(\n index: VaultIndex,\n options: ResolvedOptions,\n autoOptions: SidebarAutoOptions = {},\n): NavItem[] {\n const opts = resolveSidebarAutoOptions(autoOptions)\n const viewsPrefix = options.views.urlPrefix\n ? options.views.urlPrefix.replace(/^\\/+|\\/+$/g, '')\n : ''\n\n const visible: FileEntry[] = []\n for (const entry of index.files.values()) {\n if (shouldExclude(entry, opts, viewsPrefix)) continue\n visible.push(entry)\n }\n const root = buildTree(visible)\n\n const base = options.base.endsWith('/') ? options.base : options.base + '/'\n // nav link 不带 base(VitePress 渲染时自动 prepend);activeMatch 是正则,**也不带** base\n const out: NavItem[] = [{ text: opts.homeNavText, link: '/' }]\n\n const topKeys = [...root.children.keys()].sort()\n for (const key of topKeys) {\n const child = root.children.get(key)!\n if (child.files.length === 0 && child.children.size === 0 && !child.dirIndex) {\n continue\n }\n const text = computeGroupText(child.path, child.dirIndex, opts)\n // 链接选取(dirIndex.url 在 v0.3+ 已经不带 base,直接用即可):\n // 1. 非空 dirIndex → dirIndex.url\n // 2. 否则递归找第一个有效 page\n // 3. 都没有 → **跳过这个 tab**(nav tab 必须可点,否则点不动反而困惑;\n // 不像 sidebar 里没 link 还能展开/折叠)\n let link: string\n if (child.dirIndex && !child.dirIndexEmpty) {\n link = stripBase(child.dirIndex.url, base)\n } else {\n const first = findFirstPageUrl(child, opts)\n if (!first) continue // skip whole tab\n link = first\n }\n const escapedPrefix = `/${key}/`.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n out.push({ text, link, activeMatch: '^' + escapedPrefix })\n }\n return out\n}\n\nfunction stripBase(url: string, base: string): string {\n const b = base.endsWith('/') ? base : base + '/'\n if (b === '/' || !url.startsWith(b)) return url\n return '/' + url.slice(b.length)\n}\n\n// ── helpers ───────────────────────────────────────────────────────\n\nfunction compareEntries(\n a: FileEntry,\n b: FileEntry,\n opts: ResolvedSidebarAutoOptions,\n): number {\n if (opts.sortBy === 'title') {\n return opts.formatItemTitle(a).localeCompare(opts.formatItemTitle(b))\n }\n if (opts.sortBy === 'mtime-desc') {\n return b.mtime - a.mtime\n }\n const oa = readOrder(a, opts.orderKey)\n const ob = readOrder(b, opts.orderKey)\n if (oa !== ob) return oa - ob\n return opts.formatItemTitle(a).localeCompare(opts.formatItemTitle(b))\n}\n\nfunction readOrder(entry: FileEntry, key: string): number {\n const v = entry.frontmatter[key]\n if (typeof v === 'number' && Number.isFinite(v)) return v\n return Number.POSITIVE_INFINITY\n}\n\nfunction readVirtualGroup(entry: FileEntry): string | null {\n const v = entry.frontmatter.sidebarGroup\n if (typeof v === 'string' && v.trim()) return v.trim()\n return null\n}\n\nfunction resolveGroupCollapsed(\n dirIndex: FileEntry | undefined,\n opts: ResolvedSidebarAutoOptions,\n): boolean {\n if (dirIndex) {\n const v = dirIndex.frontmatter.sidebarCollapsed\n if (typeof v === 'boolean') return v\n }\n return opts.collapsed\n}\n\nfunction shouldExclude(\n entry: FileEntry,\n opts: ResolvedSidebarAutoOptions,\n viewsPrefix: string,\n): boolean {\n if (entry.frontmatter[opts.hiddenKey] === true) return true\n if (viewsPrefix && entry.relativePath.startsWith(viewsPrefix + '/')) return true\n\n // i18n:includePrefix(只看子树) / excludePrefixes(屏蔽 locale 子树)\n if (opts.includePrefix) {\n const ip = opts.includePrefix.replace(/^\\/+|\\/+$/g, '')\n if (!entry.relativePath.startsWith(ip + '/') && entry.relativePath !== ip) {\n return true\n }\n }\n for (const ex of opts.excludePrefixes) {\n const xp = ex.replace(/^\\/+|\\/+$/g, '')\n if (entry.relativePath.startsWith(xp + '/') || entry.relativePath === xp) {\n return true\n }\n }\n\n // _ 前缀目录\n const segs = entry.relativePath.split('/')\n for (const seg of segs.slice(0, -1)) {\n if (seg.startsWith('_')) return true\n }\n for (const pat of opts.exclude) {\n if (matchSimpleGlob(entry.relativePath, pat)) return true\n }\n return false\n}\n\nfunction matchSimpleGlob(path: string, pat: string): boolean {\n const ESCAPE_RE = /[.+?^${}()|[\\]\\\\]/g\n const escaped = pat.replace(ESCAPE_RE, '\\\\$&')\n const expanded = escaped\n .replace(/\\*\\*/g, '__DOUBLESTAR__')\n .replace(/\\*/g, '[^/]*')\n .replace(/__DOUBLESTAR__/g, '.*')\n return new RegExp('^' + expanded + '$').test(path)\n}\n\n// isDirIndex 之前的判断被 pickDirIndexes 取代(支持同名优先)\n\nfunction computeGroupText(\n dir: string,\n dirIndex: FileEntry | undefined,\n opts: ResolvedSidebarAutoOptions,\n): string {\n if (dirIndex) {\n const fmTitle = dirIndex.frontmatter[opts.titleKey]\n if (typeof fmTitle === 'string' && fmTitle.trim()) return fmTitle.trim()\n const title = dirIndex.frontmatter.title\n if (typeof title === 'string' && title.trim()) return title.trim()\n const h1 = dirIndex.headings.find((h) => h.level === 1)\n if (h1) return h1.text\n }\n const last = dir.split('/').pop() ?? dir\n return opts.formatGroupTitle(last)\n}\n","/**\n * v0.3 — 给缺 index.md / README.md 的文件夹自动生成 index 页。\n *\n * 行为:\n * - 扫 srcDir 下所有目录,对**已有 .md 文件**但**无 index.md/README.md**的\n * 目录,生成一个简单的 index.md\n * - 内容:H1 = 目录名 humanized;然后列出直接子文件 + 子目录链接(用 wikilink)\n * - 用 sentinel 标记,下次升级时允许覆盖\n * - 不生成:`_` 前缀目录、views.urlPrefix 目录、根目录(根用户自己写 index)\n *\n * 时机:在 vault scan 之前调用(views generate-md 同期),让 scanVault 看到这些\n * 生成的 index,sidebar 自动识别为 group link。\n */\n\nimport fs from 'node:fs'\nimport nodePath from 'node:path'\nimport type { ResolvedOptions } from '../types.js'\n\nexport const FOLDER_INDEX_SENTINEL =\n '<!-- generated by vitepress-allyouneed/folder-index (do not edit; will be regenerated) -->'\n\nexport interface FolderIndexReport {\n written: string[]\n skipped: { path: string; reason: string }[]\n}\n\nexport type FolderIndexMode = 'off' | 'top-level' | 'all'\n\nexport interface FolderIndexOptions {\n /**\n * 三种模式:\n * - 'off' 完全不生成\n * - 'top-level' 只为**顶级目录**生成(即作为 nav tab 入口的那批),\n * 侧边栏内的子目录保持原版\"点击展开\"(不跳转)行为\n * - 'all' 所有非空目录都生成\n *\n * 默认 'top-level' —— 既保证 nav tab 能正确跳转,又不在所有子目录里写文件。\n */\n mode?: FolderIndexMode\n /** 排除的 dir(相对 srcDir,glob)。默认 [] */\n exclude?: string[]\n /** 模板生成函数,可覆盖 */\n template?: (ctx: TemplateContext) => string\n /** humanize 时剥 `01-foo` 等数字前缀,默认 true */\n stripNumericPrefix?: boolean\n\n /** @deprecated 老 v0.3 字段,等价 mode: enabled?'top-level':'off' */\n enabled?: boolean\n}\n\nexport interface TemplateContext {\n dirAbsPath: string\n dirRelPath: string\n /** 目录名(已 humanize) */\n title: string\n /** 直接子 .md 文件(相对该目录) */\n files: Array<{ name: string; relPath: string; title: string }>\n /** 直接子目录(已有内容的) */\n subDirs: Array<{ name: string; title: string }>\n}\n\nconst MD_RE = /\\.(md|markdown)$/i\nconst INDEX_RE = /^(index|README)\\.(md|markdown)$/i\n\nexport function generateFolderIndexes(\n options: ResolvedOptions,\n folderOpts: FolderIndexOptions = {},\n): FolderIndexReport {\n const report: FolderIndexReport = { written: [], skipped: [] }\n\n // 兼容 enabled / 推断 mode\n const mode: FolderIndexMode =\n folderOpts.mode ??\n (folderOpts.enabled === true\n ? 'top-level'\n : folderOpts.enabled === false\n ? 'off'\n : 'top-level')\n if (mode === 'off') return report\n\n const srcDir = nodePath.resolve(options.srcDir)\n const viewsPrefix = options.views.urlPrefix\n ? options.views.urlPrefix.replace(/^\\/+|\\/+$/g, '')\n : ''\n const strip = folderOpts.stripNumericPrefix ?? true\n const exclude = folderOpts.exclude ?? []\n const template = folderOpts.template ?? defaultTemplate\n\n // 收集要处理的目录;0.3.2:把 srcDir 根**也加进去**,\n // 避免用户没写 index.md 时 / 直接 404\n const dirsToProcess = [srcDir, ...collectDirs(srcDir, srcDir, viewsPrefix, exclude, mode)]\n\n for (const dirAbs of dirsToProcess) {\n const dirRel = nodePath.relative(srcDir, dirAbs).split(nodePath.sep).join('/')\n // 0.3.2:**根目录也生成**(模板会用 srcDir name 当标题)\n\n const entries = safeReaddir(dirAbs)\n if (entries.length === 0) continue\n\n // 检测候选 dirIndex 文件:\n // 1. 与文件夹同名的 .md(优先级最高,优先于 index/README)\n // 2. index.md\n // 3. README.md\n // 任一存在且**不是我们之前生成的**(没 sentinel)→ 跳过,把现成的当索引页\n const dirName = nodePath.basename(dirAbs).toLowerCase()\n const target = nodePath.join(dirAbs, 'index.md')\n\n let userHasOwnIndex = false\n let userIndexName = ''\n for (const e of entries) {\n if (!e.isFile()) continue\n const lower = e.name.toLowerCase()\n const isCandidate =\n lower === `${dirName}.md` ||\n lower === `${dirName}.markdown` ||\n INDEX_RE.test(e.name)\n if (!isCandidate) continue\n const content = safeRead(nodePath.join(dirAbs, e.name))\n if (content === null) continue\n // 用户文件(包括空 frontmatter-only 文件)都不覆盖。\n // 只有带 sentinel 的我们自己生成的旧文件才允许覆盖更新。\n if (!content.includes(FOLDER_INDEX_SENTINEL)) {\n userHasOwnIndex = true\n userIndexName = e.name\n break\n }\n }\n if (userHasOwnIndex) {\n // 用户自己加了 dirIndex(同名或 index/README)。若我们之前曾生成过\n // index.md / README.md(带 sentinel),清理掉,避免 sidebar 同时出现\n // \"用户文件\" + \"我们的旧生成\"两条 stale item。\n for (const candName of ['index.md', 'README.md']) {\n if (candName.toLowerCase() === userIndexName.toLowerCase()) continue\n const candPath = nodePath.join(dirAbs, candName)\n const candContent = safeRead(candPath)\n if (candContent && candContent.includes(FOLDER_INDEX_SENTINEL)) {\n try {\n fs.unlinkSync(candPath)\n report.skipped.push({\n path: candPath,\n reason: `被用户的 ${userIndexName} 取代,自动清理`,\n })\n } catch {\n /* 删失败就保留,不影响主流程 */\n }\n }\n }\n report.skipped.push({\n path: target,\n reason: `用户已有 ${userIndexName},不生成`,\n })\n continue\n }\n\n // 收集子文件 + 子目录\n const files: TemplateContext['files'] = []\n const subDirs: TemplateContext['subDirs'] = []\n for (const e of entries) {\n if (e.isFile() && MD_RE.test(e.name) && !INDEX_RE.test(e.name)) {\n const name = e.name.replace(MD_RE, '')\n files.push({\n name,\n relPath: name,\n title: humanize(name, strip),\n })\n } else if (e.isDirectory() && !e.name.startsWith('_')) {\n // 排除空子目录\n if (hasMdContent(nodePath.join(dirAbs, e.name))) {\n subDirs.push({ name: e.name, title: humanize(e.name, strip) })\n }\n }\n }\n\n // 空目录(子文件 + 子目录都为 0)→ 不生成\n if (files.length === 0 && subDirs.length === 0) {\n continue\n }\n\n files.sort((a, b) => a.title.localeCompare(b.title))\n subDirs.sort((a, b) => a.title.localeCompare(b.title))\n\n // 根目录(dirRel === '')用 srcDir basename 当 title;否则用最后一段\n const lastSeg =\n dirRel === ''\n ? nodePath.basename(srcDir)\n : dirRel.split('/').pop() ?? ''\n const ctx: TemplateContext = {\n dirAbsPath: dirAbs,\n dirRelPath: dirRel,\n title: humanize(lastSeg, strip) || 'Home',\n files,\n subDirs,\n }\n\n try {\n fs.writeFileSync(target, template(ctx), 'utf8')\n report.written.push(target)\n } catch (err) {\n report.skipped.push({\n path: target,\n reason: `写入失败: ${err instanceof Error ? err.message : String(err)}`,\n })\n }\n }\n\n return report\n}\n\nfunction collectDirs(\n root: string,\n cur: string,\n viewsPrefix: string,\n exclude: string[],\n mode: FolderIndexMode,\n): string[] {\n const out: string[] = []\n walk(cur, 0)\n return out\n\n function walk(dir: string, depth: number): void {\n // top-level 模式只收 depth 0 的直接子目录\n if (mode === 'top-level' && depth > 1) return\n\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true })\n } catch {\n return\n }\n for (const e of entries) {\n if (!e.isDirectory()) continue\n if (e.name.startsWith('.')) continue\n if (e.name.startsWith('_')) continue\n if (e.name === 'node_modules' || e.name === 'public') continue\n const full = nodePath.join(dir, e.name)\n const rel = nodePath.relative(root, full).split(nodePath.sep).join('/')\n if (viewsPrefix && (rel === viewsPrefix || rel.startsWith(viewsPrefix + '/'))) continue\n if (exclude.some((pat) => matchGlob(rel, pat))) continue\n out.push(full)\n if (mode === 'all') walk(full, depth + 1)\n }\n }\n}\n\nfunction hasMdContent(dir: string): boolean {\n try {\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n for (const e of entries) {\n if (e.isFile() && MD_RE.test(e.name)) return true\n if (e.isDirectory() && !e.name.startsWith('_') && !e.name.startsWith('.')) {\n if (hasMdContent(nodePath.join(dir, e.name))) return true\n }\n }\n } catch {\n /* ignore */\n }\n return false\n}\n\nfunction safeReaddir(dir: string): fs.Dirent[] {\n try {\n return fs.readdirSync(dir, { withFileTypes: true })\n } catch {\n return []\n }\n}\n\nfunction safeRead(p: string): string | null {\n try {\n return fs.readFileSync(p, 'utf8')\n } catch {\n return null\n }\n}\n\nfunction matchGlob(path: string, pat: string): boolean {\n const ESC = /[.+?^${}()|[\\]\\\\]/g\n const re = pat\n .replace(ESC, '\\\\$&')\n .replace(/\\*\\*/g, '__DS__')\n .replace(/\\*/g, '[^/]*')\n .replace(/__DS__/g, '.*')\n return new RegExp('^' + re + '$').test(path)\n}\n\n/** 文件夹名 humanize:`my-dir` / `01-foo_bar` → `My Dir` / `Foo Bar`(开 strip 时) */\nexport function humanize(name: string, stripNumeric: boolean): string {\n let s = name\n if (stripNumeric) {\n s = s.replace(/^\\d+[-_.\\s]+/, '')\n }\n return s\n .replace(/[-_]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/\\b\\w/g, (m) => m.toUpperCase())\n}\n\nfunction defaultTemplate(ctx: TemplateContext): string {\n const lines: string[] = []\n lines.push('---')\n lines.push(`title: ${ctx.title}`)\n lines.push(`sidebarTitle: ${ctx.title}`)\n lines.push('---')\n lines.push(FOLDER_INDEX_SENTINEL)\n lines.push('')\n lines.push(`# ${ctx.title}`)\n lines.push('')\n if (ctx.subDirs.length > 0) {\n lines.push('## Sections')\n lines.push('')\n for (const d of ctx.subDirs) {\n lines.push(`- [[${ctx.dirRelPath}/${d.name}/|${d.title}]]`)\n }\n lines.push('')\n }\n if (ctx.files.length > 0) {\n lines.push('## Pages')\n lines.push('')\n for (const f of ctx.files) {\n lines.push(`- [[${ctx.dirRelPath}/${f.relPath}|${f.title}]]`)\n }\n lines.push('')\n }\n return lines.join('\\n')\n}\n","/**\n * v0.3 — 启动时预扫所有 .md,找出死 wikilink,集中 console.warn 一次。\n *\n * 不影响渲染管线(渲染时 wikilink rule 自己也有 dead-link 检测+报警)。\n * 这个函数只是给开发者一个\"启动总览\",避免要 dev-server 打开每页才看到死链。\n */\n\nimport type { ResolvedOptions, VaultIndex } from './types.js'\nimport { stripMarkdownExt, toPosix } from '../utils/path.js'\n\nconst WIKILINK_RE = /(!?)\\[\\[([^\\]\\n|#]+)(?:#[^\\]\\n|]*)?(?:\\|[^\\]\\n]*)?\\]\\]/g\n\nexport interface DeadLinkReport {\n /** 总扫描的 wikilink 数 */\n total: number\n /** 死链(target 解析不到的)*/\n dead: Array<{ source: string; target: string; raw: string }>\n}\n\n/**\n * 把 fenced code block / inline code 全部抹掉成空白(保留长度,不破坏行号),\n * 这样后续 wikilink regex 不会扫到代码示例里的 `[[note]]`(它们渲染时也不会\n * 被 markdown-it 当 wikilink,因此不该报死链)。\n */\nfunction stripCodeForScan(src: string): string {\n // ``` fenced ```\n let r = src.replace(/```[\\s\\S]*?```/g, (m) => ' '.repeat(m.length))\n // ~~~ fenced ~~~\n r = r.replace(/~~~[\\s\\S]*?~~~/g, (m) => ' '.repeat(m.length))\n // 行内 code(支持多个反引号,简化:同数量反引号配对)\n r = r.replace(/(`+)(?:(?!\\1)[\\s\\S])*?\\1/g, (m) => ' '.repeat(m.length))\n return r\n}\n\nexport function scanWikilinks(\n index: VaultIndex,\n options: ResolvedOptions,\n): DeadLinkReport {\n const dead: DeadLinkReport['dead'] = []\n let total = 0\n\n for (const f of index.files.values()) {\n const cleaned = stripCodeForScan(f.content)\n const matches = cleaned.matchAll(WIKILINK_RE)\n for (const m of matches) {\n total += 1\n const isEmbed = m[1] === '!'\n const rawTarget = m[2]!.trim()\n // image/audio/video/pdf/transclusion 走 embed 通道,不参与 wikilink 死链检测\n if (isEmbed) {\n const ext = extractExt(rawTarget)\n if (ext) {\n const isAsset =\n options.scan.assetExtensions.includes(ext.toLowerCase()) ||\n ['md', 'markdown'].includes(ext.toLowerCase())\n if (isAsset) continue\n }\n }\n const found = resolveSimple(rawTarget, index, options, f.relativePath)\n if (!found) {\n dead.push({\n source: f.relativePath,\n target: rawTarget,\n raw: `${isEmbed ? '!' : ''}[[${rawTarget}]]`,\n })\n }\n }\n }\n return { total, dead }\n}\n\n/** vitepress.ts wrapper 用:扫完打印汇总 */\nexport function logDeadLinks(report: DeadLinkReport, deadLink: 'silent' | 'warn' | 'error'): void {\n if (report.dead.length === 0) return\n if (deadLink === 'silent') return\n const head = `vitepress-allyouneed: 共扫描 ${report.total} 个 wikilink, ` +\n `发现 ${report.dead.length} 个死链:`\n if (deadLink === 'error') {\n console.error(head)\n } else {\n console.warn(head)\n }\n // 按 source 分组打印,便于人眼看\n const bySource = new Map<string, typeof report.dead>()\n for (const d of report.dead) {\n const arr = bySource.get(d.source) ?? []\n arr.push(d)\n bySource.set(d.source, arr)\n }\n for (const [src, items] of [...bySource.entries()].sort()) {\n console.warn(` ${src}`)\n for (const it of items) {\n console.warn(` ${it.raw}`)\n }\n }\n}\n\nfunction extractExt(target: string): string {\n const cleaned = target.split('#')[0]!\n const dot = cleaned.lastIndexOf('.')\n if (dot <= 0) return ''\n return cleaned.slice(dot + 1).toLowerCase()\n}\n\nfunction resolveSimple(\n raw: string,\n index: VaultIndex,\n options: ResolvedOptions,\n currentSourceRel?: string,\n): boolean {\n const target = stripMarkdownExt(toPosix(raw))\n if (!target) return false\n // 路径形式\n if (target.includes('/')) {\n if (\n index.byRelativePath.has(target) ||\n index.byRelativePath.has(target + '.md') ||\n index.byRelativePath.has(target + '.markdown')\n ) {\n return true\n }\n // Fallback:相对当前源文件目录\n if (currentSourceRel) {\n const curDir = currentSourceRel.split('/').slice(0, -1).join('/')\n if (curDir) {\n return (\n index.byRelativePath.has(`${curDir}/${target}`) ||\n index.byRelativePath.has(`${curDir}/${target}.md`) ||\n index.byRelativePath.has(`${curDir}/${target}.markdown`)\n )\n }\n }\n return false\n }\n // alias\n const aliasKey = options.caseSensitive ? target : target.toLowerCase()\n if (index.byAlias.has(aliasKey)) return true\n // basename\n const map = options.caseSensitive ? index.byBasename : index.byBasenameLower\n const key = options.caseSensitive ? target : target.toLowerCase()\n return (map.get(key)?.length ?? 0) > 0\n}\n","/**\n * VitePress 接入入口 —— defineConfigWithAllYouNeed 零配置 wrapper。\n *\n * 用法:\n *\n * ```ts\n * // .vitepress/config.ts\n * import { defineConfigWithAllYouNeed } from 'vitepress-allyouneed/vitepress'\n *\n * export default defineConfigWithAllYouNeed({\n * title: 'My Vault',\n * srcDir: '../my-vault',\n * cleanUrls: true,\n * // ⚠️ index.md 和 README.md 同目录会冲突(都路由到 '/')。建议二选一:\n * srcExclude: ['README.md'],\n * }, {\n * onConflict: 'shortest',\n * })\n * ```\n *\n * 这个 wrapper 做的事:\n * 1. 创建 Vite 插件实例并注入 vite.plugins\n * 2. 在 markdown.config 中注册我们的 inline/block 规则\n * 3. 注册一条 markdown-it core 规则,在 'normalize' 阶段把 vault index/options\n * 就地注入 state.env(详见 makeEnvInjector 内的注释 —— 这一步**必须就地修改**,\n * 不能新建 env 对象,否则会让 VitePress 读不到 @mdit-vue/plugin-frontmatter\n * 写回的 frontmatter,从而导致首页 404)\n * 4. 把 srcDir/base/cleanUrls/srcExclude 等从 VitePress 配置同步给插件\n */\n\nimport type { UserConfig } from 'vitepress'\nimport type MarkdownIt from 'markdown-it'\nimport type { AllYouNeedOptions, AllYouNeedEnv } from './core/types.js'\nimport { viteAllYouNeed } from './vite.js'\nimport allYouNeedMarkdownIt from './markdown-it.js'\nimport { resolveOptions } from './core/config-bridge.js'\nimport { registerTagsInline } from './modules/tags/index.js'\nimport { injectViewsSidebar, injectViewsNav } from './core/views/sidebar-inject.js'\nimport { generateSidebar, generateNav } from './core/sidebar-auto/index.js'\nimport { generateFolderIndexes } from './core/sidebar-auto/generate-folder-index.js'\nimport { scanVault } from './core/vault/index.js'\nimport { scanWikilinks, logDeadLinks } from './core/scan-wikilinks.js'\n\nexport function defineConfigWithAllYouNeed(\n config: UserConfig,\n pluginOptions: AllYouNeedOptions = {},\n): UserConfig {\n // VitePress 的 srcExclude 也合并进我们扫描器,两边对同一份文件集合\n const vpExclude = Array.isArray(config.srcExclude) ? config.srcExclude : []\n\n const mergedOptions: AllYouNeedOptions = {\n ...pluginOptions,\n srcDir: pluginOptions.srcDir ?? config.srcDir,\n base: pluginOptions.base ?? config.base,\n cleanUrls: pluginOptions.cleanUrls ?? config.cleanUrls,\n scan: {\n ...pluginOptions.scan,\n exclude: [\n ...(pluginOptions.scan?.exclude ?? []),\n ...vpExclude,\n ],\n },\n }\n\n // Vite 插件(扫描 vault、暴露 __getIndex/__getOptions、装 resolveId/load)\n const vitePlugin = viteAllYouNeed(mergedOptions)\n\n // 合并 vite 配置 —— 详见 src/vite.ts 注释,这里用 any 化处理 plugins,\n // 因为 vite 的 PluginOption 类型递归很深,精确类型会让 wrapper 越写越脆\n const existingVite = (\n typeof config.vite === 'object' && config.vite !== null\n ? config.vite\n : {}\n ) as Record<string, unknown>\n const existingPlugins: unknown[] = Array.isArray(existingVite.plugins)\n ? (existingVite.plugins as unknown[])\n : []\n const newVite = {\n ...existingVite,\n plugins: [...existingPlugins, vitePlugin] as never[],\n } as UserConfig['vite']\n\n // 合并 markdown 配置\n const existingMarkdown = config.markdown ?? {}\n const existingConfig = (existingMarkdown as { config?: unknown }).config\n\n // v0.2:wrapper 内解析一次选项,供 sidebar 注入和 tags 开关判断\n const resolvedForWrapper = resolveOptions(mergedOptions, {\n srcDir: mergedOptions.srcDir ?? config.srcDir,\n base: mergedOptions.base ?? config.base,\n cleanUrls: mergedOptions.cleanUrls ?? config.cleanUrls,\n })\n\n const newMarkdownConfig = (md: MarkdownIt) => {\n // 1. 装我们的 inline/block 规则\n allYouNeedMarkdownIt(md, mergedOptions)\n\n // 2. v0.2:正文 #tag 规则\n if (\n resolvedForWrapper.modules.views &&\n resolvedForWrapper.views.parseInlineTags\n ) {\n registerTagsInline(md)\n }\n\n // 3. 装一条 core 规则,在 'normalize' 之前把 vault index/options 注入 state.env\n md.core.ruler.before(\n 'normalize',\n 'allyouneed_env_inject',\n makeEnvInjector(vitePlugin),\n )\n\n // 4. 让用户原 markdown.config 继续生效\n if (typeof existingConfig === 'function') {\n existingConfig(md)\n }\n }\n\n // v0.2/v0.3:自动注入视图条目 + sidebar 自动生成\n const themeConfig = (config.themeConfig ?? {}) as Record<string, unknown>\n\n // v0.3:sidebar 自动生成\n // - mode='off' 不动\n // - mode='fill-if-empty' 仅当用户没提供 sidebar 时填(默认)\n // - mode='force' 覆盖\n // 依赖 viteplugin.__getIndex(),但 index 在 Vite buildStart 才填好,所以这里\n // 用懒解析:把 themeConfig.sidebar 设为一个 getter,首次访问时再扫\n const sidebarAuto = resolvedForWrapper.sidebarAuto\n const sidebarMode = sidebarAuto.mode ?? 'fill-if-empty'\n if (sidebarMode !== 'off') {\n const userProvided = themeConfig.sidebar !== undefined\n const shouldFill = sidebarMode === 'force' || !userProvided\n if (shouldFill) {\n // 同步路径:scanVault 已在 Vite buildStart 跑过(若 dev/build);\n // 但 defineConfigWithAllYouNeed 时 buildStart 还没到 —— 此时 index 为空。\n // 解决:这里立即跑一次 scanVault(成本约 100ms,可接受),用结果生成 sidebar。\n // Vite buildStart 时 viteplugin 会再扫一次,index 实例不同但内容一致。\n try {\n // v0.3:autoFolderIndex —— 在 scan 前给缺 index 的目录建一份 index.md。\n // 支持三种模式:'off' / 'top-level'(默认) / 'all'。\n // 兼容旧写法:true → 'top-level',false → 'off'。\n const folderOpts = normalizeAutoFolderIndex(\n sidebarAuto.autoFolderIndex,\n sidebarAuto.stripNumericPrefix,\n )\n if (folderOpts.mode !== 'off') {\n try {\n generateFolderIndexes(resolvedForWrapper, folderOpts)\n } catch (e) {\n console.warn(\n 'vitepress-allyouneed: autoFolderIndex 生成失败,跳过。',\n e instanceof Error ? e.message : String(e),\n )\n }\n }\n const index = scanVault(resolvedForWrapper)\n // 启动时把所有死 wikilink 集中 warn 一次,免得只能 dev 打开每页才能看到\n try {\n const report = scanWikilinks(index, resolvedForWrapper)\n logDeadLinks(report, resolvedForWrapper.deadLink)\n } catch {\n /* 不阻塞 */\n }\n // v0.3:i18n 支持 — 用户配了 themeConfig.locales(VitePress 原生 i18n),\n // 对每个 non-root locale 自动用 includePrefix 生成对应 sidebar,\n // root sidebar 用 excludePrefixes 排掉这些 locale 子树。\n const localesObj = (config as { locales?: Record<string, { link?: string; themeConfig?: Record<string, unknown> }> }).locales\n const localeKeys = localesObj\n ? Object.keys(localesObj).filter((k) => k !== 'root')\n : []\n\n themeConfig.sidebar = generateSidebar(index, resolvedForWrapper, {\n ...sidebarAuto,\n excludePrefixes: [\n ...(sidebarAuto.excludePrefixes ?? []),\n ...localeKeys, // 根 sidebar 排除掉所有 locale 子树\n ],\n })\n\n // 每个 non-root locale 各自生成 sidebar(在它自己的 themeConfig 里)\n if (localesObj) {\n for (const lang of localeKeys) {\n const localeCfg = localesObj[lang]!\n if (!localeCfg.themeConfig) localeCfg.themeConfig = {}\n if (localeCfg.themeConfig.sidebar === undefined) {\n localeCfg.themeConfig.sidebar = generateSidebar(\n index,\n resolvedForWrapper,\n { ...sidebarAuto, includePrefix: lang },\n )\n }\n }\n }\n\n // v0.3:autoNav 开启时,nav 没写就自动填(每个顶层目录一个 tab)\n if (sidebarAuto.autoNav && themeConfig.nav === undefined) {\n themeConfig.nav = generateNav(\n index,\n resolvedForWrapper,\n sidebarAuto,\n )\n }\n } catch (e) {\n console.warn(\n 'vitepress-allyouneed: sidebar 自动生成失败,跳过。',\n e instanceof Error ? e.message : String(e),\n )\n }\n }\n }\n\n if (resolvedForWrapper.modules.views) {\n themeConfig.sidebar = injectViewsSidebar(\n themeConfig.sidebar as Parameters<typeof injectViewsSidebar>[0],\n resolvedForWrapper,\n )\n // v0.3:也可注入到 nav(views.injectInto: 'nav' | 'both')\n themeConfig.nav = injectViewsNav(\n themeConfig.nav as Parameters<typeof injectViewsNav>[0],\n resolvedForWrapper,\n )\n // v0.3 i18n:每个 locale 的 themeConfig.nav 也注入(否则 i18n 下顶层 nav 被覆盖,\n // 下拉就消失了)\n const localesForNav = (config as { locales?: Record<string, { themeConfig?: { nav?: unknown } }> }).locales\n if (localesForNav) {\n for (const lang of Object.keys(localesForNav)) {\n const lc = localesForNav[lang]!\n if (!lc.themeConfig) continue\n if (lc.themeConfig.nav !== undefined) {\n lc.themeConfig.nav = injectViewsNav(\n lc.themeConfig.nav as Parameters<typeof injectViewsNav>[0],\n resolvedForWrapper,\n )\n }\n }\n }\n }\n\n return {\n ...config,\n vite: newVite,\n themeConfig,\n markdown: {\n ...existingMarkdown,\n config: newMarkdownConfig,\n },\n }\n}\n\n/**\n * 把 sidebarAuto.autoFolderIndex(union 类型)归一化成 generateFolderIndexes\n * 接受的对象形式。**默认 mode = 'top-level'**(用户没显式传时)。\n */\nfunction normalizeAutoFolderIndex(\n v: unknown,\n globalStripNumericPrefix: boolean | undefined,\n): {\n mode: 'off' | 'top-level' | 'all'\n exclude?: string[]\n stripNumericPrefix?: boolean\n template?: import('./core/sidebar-auto/generate-folder-index.js').FolderIndexOptions['template']\n} {\n let mode: 'off' | 'top-level' | 'all' = 'top-level'\n let exclude: string[] | undefined\n let strip: boolean | undefined = globalStripNumericPrefix\n let template:\n | import('./core/sidebar-auto/generate-folder-index.js').FolderIndexOptions['template']\n | undefined\n\n if (v === undefined || v === null) {\n // 用默认 'top-level'\n } else if (v === false || v === 'off') {\n mode = 'off'\n } else if (v === true || v === 'top-level') {\n mode = 'top-level'\n } else if (v === 'all') {\n mode = 'all'\n } else if (typeof v === 'object') {\n const obj = v as {\n mode?: 'off' | 'top-level' | 'all'\n enabled?: boolean\n exclude?: string[]\n stripNumericPrefix?: boolean\n template?: import('./core/sidebar-auto/generate-folder-index.js').FolderIndexOptions['template']\n }\n if (obj.mode) {\n mode = obj.mode\n } else if (obj.enabled === false) {\n mode = 'off'\n } else if (obj.enabled === true) {\n mode = 'top-level'\n }\n exclude = obj.exclude\n if (obj.stripNumericPrefix !== undefined) strip = obj.stripNumericPrefix\n template = obj.template\n }\n\n return { mode, exclude, stripNumericPrefix: strip, template }\n}\n\n/**\n * 构造 markdown-it core 规则,职责:**就地** mutate state.env 注入 vault 数据。\n *\n * ─ 为什么必须就地 mutate,不能新建 env ─\n *\n * VitePress 的 markdown 渲染流程大致是:\n *\n * ```ts\n * const env = { relativePath, realPath, ... }\n * const html = md.render(src, env)\n * const { __data, frontmatter, headers, ... } = env // 读回!\n * ```\n *\n * `@mdit-vue/plugin-frontmatter` 等 markdown-it 插件会通过 mutate `state.env`\n * 把 frontmatter 写到 `env.__data` 上;VitePress 之后从同一个 env 引用读取。\n *\n * 如果我们在中间 wrap 一层,把 env 换成新对象传给 md.render,新对象上的 mutation\n * 不会反映到 VitePress 的原 env → frontmatter / pageData 丢失 → 路由空 → 404。\n *\n * 用 core ruler 在 markdown-it 内部插入一步处理,直接 mutate state.env(就是\n * VitePress 传进来的同一个对象),既能注入我们的数据又不破坏 VitePress 的链路。\n */\nfunction makeEnvInjector(\n vitePlugin: ReturnType<typeof viteAllYouNeed>,\n): (state: { env?: unknown }) => void {\n return (state) => {\n const env = state.env as\n | (Record<string, unknown> & Partial<AllYouNeedEnv>)\n | undefined\n if (!env) return\n if (env.index && env.options) return // 已注入\n\n const index = vitePlugin.__getIndex()\n const options = vitePlugin.__getOptions()\n if (!index || !options) return\n\n env.index = index\n env.options = options\n if (!env.currentPath) {\n env.currentPath =\n typeof env.realPath === 'string'\n ? env.realPath\n : typeof env.path === 'string'\n ? env.path\n : undefined\n }\n if (!env.referencedAssets) env.referencedAssets = new Set()\n }\n}\n\nexport default defineConfigWithAllYouNeed\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACUA,oBAA0C;AAKnC,SAAS,eAAe,MAAsB;AACnD,aAAO,cAAAA,SAAe,IAAI;AAC5B;AAUA,IAAM,eAAe;AAEd,SAAS,gBAAgB,aAG9B;AACA,QAAM,IAAI,YAAY,MAAM,YAAY;AACxC,MAAI,CAAC,EAAG,QAAO,EAAE,MAAM,aAAa,UAAU,OAAU;AACxD,SAAO;AAAA,IACL,MAAM,YAAY,QAAQ,cAAc,EAAE;AAAA,IAC1C,UAAU,EAAE,CAAC;AAAA,EACf;AACF;;;ACxBA,IAAM,2BAA2B;AAAA;AAAA,EAE/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EACA;AACF;AAEA,IAAM,2BAA2B;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAQO,SAAS,eACd,OAA0B,CAAC,GAC3B,MAMI,CAAC,GACY;AACjB,QAAM,SAAS,KAAK,UAAU,IAAI,UAAU,QAAQ,IAAI;AACxD,MAAI,OAAO,KAAK,QAAQ,IAAI,QAAQ;AACpC,MAAI,CAAC,KAAK,WAAW,GAAG,EAAG,QAAO,MAAM;AACxC,MAAI,CAAC,KAAK,SAAS,GAAG,EAAG,QAAO,OAAO;AAEvC,QAAM,YAAY,KAAK,aAAa,IAAI,aAAa;AACrD,QAAM,UAAU,KAAK,WAAW,IAAI,mBAAmB;AAEvD,QAAM,gBAAgB,KAAK,aAAa,CAAC;AACzC,QAAM,aAAa,KAAK,UAAU,CAAC;AACnC,QAAM,WAAW,KAAK,QAAQ,CAAC;AAC/B,QAAM,aAAa,KAAK,UAAU,CAAC;AACnC,QAAM,cAAc,KAAK,WAAW,CAAC;AACrC,QAAM,YAAY,KAAK,SAAS,CAAC;AAEjC,QAAM,qBAAoC,cAAc,kBAAkB,CAAC;AAC3E,QAAM,kBAAmC,WAAW,kBAAkB,CAAC;AAEvE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe,KAAK,iBAAiB;AAAA,IACrC,UAAU,KAAK,YAAY;AAAA,IAC3B,YAAY,KAAK,cAAc;AAAA,IAC/B,iBAAiB,KAAK,mBAAmB;AAAA,IAEzC,MAAM;AAAA,MACJ,SAAS,SAAS,WAAW,CAAC,WAAW,eAAe;AAAA,MACxD,SAAS,SAAS,WAAW,CAAC;AAAA,MAC9B,gBAAgB,SAAS,kBAAkB;AAAA,MAC3C,kBAAkB,SAAS,oBAAoB;AAAA,MAC/C,iBAAiB,SAAS,mBAAmB;AAAA,IAC/C;AAAA,IAEA,QAAQ;AAAA,MACN,MAAM,WAAW,QAAQ;AAAA,MACzB,oBAAoB,WAAW,sBAAsB;AAAA,MACrD,WAAW,WAAW,aAAa;AAAA,IACrC;AAAA,IAEA,WAAW;AAAA,MACT,uBACE,cAAc,0BAA0B,CAAC,MAAc,EAAE,KAAK;AAAA,MAChE,sBACE,cAAc,yBAAyB,CAAC,MAAc,EAAE,KAAK;AAAA,MAC/D,0BACE,cAAc,4BAA4B;AAAA,MAC5C,UAAU,cAAc,YAAY;AAAA,MACpC,gBAAgB;AAAA,IAClB;AAAA,IAEA,QAAQ;AAAA,MACN,cAAc,WAAW,gBAAgB;AAAA,MACzC,gBAAgB,WAAW,kBAAkB;AAAA,MAC7C,wBACE,WAAW,2BAA2B,CAAC,MAAc,EAAE,KAAK;AAAA,MAC9D,oBACE,WAAW,uBAAuB,CAAC,MAAc,EAAE,KAAK;AAAA,MAC1D,WAAW,WAAW,aAAa;AAAA,MACnC,sBAAsB,WAAW,wBAAwB;AAAA,MACzD,gBAAgB;AAAA,IAClB;AAAA,IAEA,OAAO;AAAA,MACL,SAAS;AAAA,QACP,OAAO,UAAU,SAAS,SAAS;AAAA,QACnC,OAAO,UAAU,SAAS,SAAS;AAAA,QACnC,MAAM,UAAU,SAAS,QAAQ;AAAA,MACnC;AAAA,MACA,WAAW,UAAU,aAAa;AAAA,MAClC,OAAO;AAAA,QACL,OAAO,UAAU,OAAO,SAAS;AAAA,QACjC,OAAO,UAAU,OAAO,SAAS;AAAA,QACjC,MAAM,UAAU,OAAO,QAAQ;AAAA,MACjC;AAAA;AAAA,MAEA,YACE,UAAU,eACT,UAAU,YAAY,QACnB,QACA,UAAU,YAAY,SACpB,YACA;AAAA,MACR,SAAS,UAAU,WAAW;AAAA,MAC9B,aAAa;AAAA,QACX,OAAO,UAAU,aAAa,SAAS;AAAA,QACvC,OAAO,UAAU,aAAa,SAAS;AAAA,QACvC,OAAO,UAAU,aAAa,SAAS;AAAA,QACvC,MAAM,UAAU,aAAa,QAAQ;AAAA,MACvC;AAAA,MACA,eAAe,UAAU,iBAAiB;AAAA,MAC1C,cAAc,UAAU,gBAAgB;AAAA,MACxC,iBAAiB,UAAU,mBAAmB;AAAA,IAChD;AAAA,IAEA,SAAS;AAAA,MACP,WAAW,YAAY,aAAa;AAAA,MACpC,QAAQ,YAAY,UAAU;AAAA,MAC9B,OAAO,YAAY,SAAS;AAAA,MAC5B,UAAU,YAAY,YAAY;AAAA,MAClC,WAAW,YAAY,aAAa;AAAA,MACpC,UAAU,YAAY,YAAY;AAAA,MAClC,WAAW,YAAY,aAAa;AAAA,MACpC,WAAW,YAAY,aAAa;AAAA,IACtC;AAAA,IAEA,aAAa,KAAK,eAAe,CAAC;AAAA,IAElC;AAAA,EACF;AACF;;;AC9KA,IAAAC,kBAAe;AACf,IAAAC,oBAAqB;;;ACFrB,uBAAqB;AAGd,SAAS,QAAQ,GAAmB;AACzC,SAAO,EAAE,QAAQ,OAAO,GAAG;AAC7B;AAGO,SAAS,SAAS,MAAc,IAAoB;AACzD,SAAO,QAAQ,iBAAAC,QAAS,SAAS,MAAM,EAAE,CAAC;AAC5C;AAgBO,SAAS,iBAAiB,QAAwB;AACvD,SAAO,OAAO,QAAQ,qBAAqB,EAAE;AAC/C;AAGO,SAAS,SAAS,GAAW,WAAW,OAAe;AAC5D,QAAM,MAAM,EAAE,YAAY,GAAG;AAC7B,QAAM,OAAO,QAAQ,KAAK,IAAI,EAAE,MAAM,MAAM,CAAC;AAC7C,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,MAAM,KAAK,YAAY,GAAG;AAChC,SAAO,OAAO,IAAI,OAAO,KAAK,MAAM,GAAG,GAAG;AAC5C;AAGO,SAAS,QAAQ,GAAmB;AACzC,QAAM,OAAO,SAAS,CAAC;AACvB,QAAM,MAAM,KAAK,YAAY,GAAG;AAChC,MAAI,OAAO,EAAG,QAAO;AACrB,SAAO,KAAK,MAAM,MAAM,CAAC,EAAE,YAAY;AACzC;AAGO,SAAS,UAAU,GAAqB;AAC7C,SAAO,QAAQ,CAAC,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO;AAC7C;AAGO,SAAS,UAAU,SAAyB;AACjD,SAAO,UAAU,OAAO,EAAE;AAC5B;;;AChDO,SAAS,WAAW,GAAmB;AAC5C,SAAO,UAAU,CAAC;AACpB;AAUO,SAAS,SACd,MACA,cACA,QACQ;AAER,MAAI,WAAW,QAAQ;AACvB,MAAI,CAAC,SAAS,WAAW,GAAG,EAAG,YAAW,MAAM;AAChD,MAAI,CAAC,SAAS,SAAS,GAAG,EAAG,YAAW,WAAW;AAGnD,QAAM,SAAS,aACZ,IAAI,CAAC,MAAM,EAAE,QAAQ,cAAc,EAAE,CAAC,EACtC,OAAO,OAAO,EACd,KAAK,GAAG;AAEX,MAAI,MAAM,WAAW;AAErB,QAAM,IAAI,QAAQ,WAAW,GAAG;AAEhC,QAAM,WAAW,GAAG;AAEpB,MAAI,QAAQ;AAEV,WAAO,MAAM,mBAAmB,MAAM,EAAE,QAAQ,QAAQ,GAAG;AAAA,EAC7D;AACA,SAAO;AACT;AAUO,SAAS,eAAe,MAAc,WAA4B;AACvE,MAAI,UAAW,QAAO;AACtB,MAAI,WAAW,KAAK,IAAI,EAAG,QAAO;AAElC,MAAI,KAAK,SAAS,GAAG,EAAG,QAAO,OAAO;AACtC,SAAO,OAAO;AAChB;;;AC9DA,qBAAe;AACf,IAAAC,oBAAqB;AAiBd,SAAS,KACd,QACA,WACA,gBACa;AACb,QAAM,MAAmB,CAAC;AAC1B,QAAM,aAAa,oBAAI,IAAY;AAEnC,WAAS,MAAM,KAAmB;AAChC,QAAI;AACJ,QAAI;AACF,gBAAU,eAAAC,QAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,IACvD,QAAQ;AACN;AAAA,IACF;AAEA,eAAW,OAAO,SAAS;AACzB,YAAM,OAAO,kBAAAC,QAAS,KAAK,KAAK,IAAI,IAAI;AACxC,YAAM,QAAQ,QAAQ,IAAI;AAC1B,UAAI,UAAU,KAAK,EAAG;AAEtB,UAAI,QAAQ,IAAI,YAAY;AAC5B,UAAI,SAAS,IAAI,OAAO;AAExB,UAAI,IAAI,eAAe,GAAG;AACxB,YAAI,CAAC,eAAgB;AACrB,YAAI;AACF,gBAAM,OAAO,eAAAD,QAAG,SAAS,IAAI;AAC7B,kBAAQ,KAAK,YAAY;AACzB,mBAAS,KAAK,OAAO;AAAA,QACvB,QAAQ;AACN;AAAA,QACF;AAAA,MACF;AAEA,UAAI,OAAO;AACT,YAAI,gBAAgB;AAClB,cAAI;AACF,kBAAM,OAAO,eAAAA,QAAG,SAAS,IAAI;AAC7B,kBAAM,MAAM,GAAG,KAAK,GAAG,IAAI,KAAK,GAAG;AACnC,gBAAI,WAAW,IAAI,GAAG,EAAG;AACzB,uBAAW,IAAI,GAAG;AAAA,UACpB,QAAQ;AAEN;AAAA,UACF;AAAA,QACF;AACA,cAAM,IAAI;AAAA,MACZ,WAAW,QAAQ;AACjB,YAAI;AACF,gBAAM,OAAO,eAAAA,QAAG,SAAS,IAAI;AAC7B,cAAI,KAAK;AAAA,YACP,cAAc;AAAA,YACd,MAAM,KAAK;AAAA,YACX,OAAO,KAAK;AAAA,YACZ,WAAW,QAAQ,KAAK;AAAA,UAC1B,CAAC;AAAA,QACH,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,MAAM;AACZ,SAAO;AACT;;;ACrFA,IAAAE,kBAAe;AACf,IAAAC,oBAAqB;AACrB,uBAAsB;AAIf,IAAM,mBAAmB,oBAAI,IAAI;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AASM,SAAS,aACd,QACA,aACA,kBAC8B;AAC9B,QAAM,WAAqB,CAAC,GAAG,WAAW;AAC1C,MAAI,kBAAkB;AACpB,UAAM,YAAY,kBAAAC,QAAS,KAAK,QAAQ,YAAY;AACpD,QAAI;AACF,YAAM,UAAU,gBAAAC,QAAG,aAAa,WAAW,MAAM;AACjD,iBAAW,QAAQ,QAAQ,MAAM,OAAO,GAAG;AACzC,cAAM,UAAU,KAAK,KAAK;AAC1B,YAAI,CAAC,WAAW,QAAQ,WAAW,GAAG,EAAG;AAGzC,iBAAS,KAAK,QAAQ,SAAS,GAAG,IAAI,UAAU,OAAO,OAAO;AAAA,MAChE;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,WAAW,SAAS;AAAA,IAAI,CAAC,UAC7B,iBAAAC,SAAU,GAAG,EAAE,KAAK,MAAM,QAAQ,MAAM,CAAC;AAAA,EAC3C;AAEA,SAAO,CAAC,YAA6B;AACnC,UAAM,MAAM,QAAQ,SAAS,QAAQ,OAAO,CAAC;AAC7C,QAAI,CAAC,OAAO,IAAI,WAAW,IAAI,EAAG,QAAO;AAGzC,eAAW,OAAO,IAAI,MAAM,GAAG,GAAG;AAChC,UAAI,iBAAiB,IAAI,GAAG,EAAG,QAAO;AAAA,IACxC;AAGA,eAAW,KAAK,UAAU;AACxB,UAAI,EAAE,GAAG,EAAG,QAAO;AAAA,IACrB;AACA,WAAO;AAAA,EACT;AACF;;;ACvEA,yBAAmB;AAWZ,SAAS,iBAAiB,KAAgC;AAC/D,MAAI;AACF,UAAM,EAAE,MAAM,QAAQ,QAAI,mBAAAC,SAAO,GAAG;AACpC,WAAO,EAAE,MAAO,QAAQ,CAAC,GAA+B,QAAQ;AAAA,EAClE,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,MAAM,CAAC;AAAA,MACP,SAAS;AAAA,MACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IACxD;AAAA,EACF;AACF;AASO,SAAS,iBAAiB,KAAwB;AACvD,MAAI,OAAO,KAAM,QAAO,CAAC;AACzB,MAAI,OAAO,QAAQ,SAAU,QAAO,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC;AACjE,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO,IACJ,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,EAChD,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,OAAO;AAAA,EACnB;AACA,SAAO,CAAC;AACV;AAKO,SAAS,cAAc,KAAwB;AACpD,MAAI,OAAO,KAAM,QAAO,CAAC;AACzB,MAAI,OAAO,QAAQ,UAAU;AAC3B,WAAO,IACJ,MAAM,QAAQ,EACd,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,MAAM,EAAE,CAAC,EACrC,OAAO,OAAO;AAAA,EACnB;AACA,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO,IACJ,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,EAChD,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,MAAM,EAAE,CAAC,EACrC,OAAO,OAAO;AAAA,EACnB;AACA,SAAO,CAAC;AACV;;;ACvDA,IAAM,aAAa;AACnB,IAAM,WAAW;AAQV,SAAS,gBACd,SACA,SACgB;AAChB,QAAM,QAAQ,QAAQ,MAAM,OAAO;AACnC,QAAM,MAAsB,CAAC;AAE7B,MAAI,UAAU;AACd,MAAI,cAAc;AAElB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC;AAGpB,UAAM,aAAa,KAAK,MAAM,QAAQ;AACtC,QAAI,YAAY;AACd,UAAI,CAAC,SAAS;AACZ,kBAAU;AACV,sBAAc,WAAW,CAAC;AAAA,MAC5B,WAAW,KAAK,WAAW,WAAW,GAAG;AACvC,kBAAU;AACV,sBAAc;AAAA,MAChB;AACA;AAAA,IACF;AACA,QAAI,QAAS;AAEb,UAAM,IAAI,KAAK,MAAM,UAAU;AAC/B,QAAI,CAAC,EAAG;AAER,UAAM,QAAQ,EAAE,CAAC,EAAG;AACpB,UAAM,UAAU,EAAE,CAAC;AACnB,UAAM,EAAE,MAAM,SAAS,IAAI,gBAAgB,OAAO;AAClD,UAAM,OAAO,YAAY,QAAQ,IAAI;AAErC,QAAI,KAAK,EAAE,OAAO,MAAM,MAAM,MAAM,EAAE,CAAC;AAAA,EACzC;AAEA,SAAO;AACT;;;AN1BA,IAAM,gBAAgB,oBAAI,IAAI,CAAC,MAAM,UAAU,CAAC;AAKzC,SAAS,iBACd,SAAS,IACT,OAAO,KACP,YAAY,OACA;AACZ,SAAO;AAAA,IACL,OAAO,oBAAI,IAAI;AAAA,IACf,QAAQ,oBAAI,IAAI;AAAA,IAChB,YAAY,oBAAI,IAAI;AAAA,IACpB,iBAAiB,oBAAI,IAAI;AAAA,IACzB,SAAS,oBAAI,IAAI;AAAA,IACjB,gBAAgB,oBAAI,IAAI;AAAA,IACxB,OAAO,oBAAI,IAAI;AAAA,IACf,kBAAkB,oBAAI,IAAI;AAAA,IAC1B,uBAAuB,oBAAI,IAAI;AAAA,IAC/B,sBAAsB,oBAAI,IAAI;AAAA,IAC9B,MAAM,oBAAI,IAAI;AAAA,IACd,WAAW,oBAAI,IAAI;AAAA,IACnB,UAAU,oBAAI,IAAI;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,KAAK,IAAI;AAAA,IACpB,UAAU,CAAC;AAAA,EACb;AACF;AAKO,SAAS,UAAU,SAAsC;AAC9D,QAAM,SAAS,QAAQ,kBAAAC,QAAS,QAAQ,QAAQ,MAAM,CAAC;AACvD,QAAM,QAAQ,iBAAiB,QAAQ,QAAQ,MAAM,QAAQ,SAAS;AAEtE,QAAM,YAAY;AAAA,IAChB;AAAA,IACA,QAAQ,KAAK;AAAA,IACb,QAAQ,KAAK;AAAA,EACf;AAEA,QAAM,cAAc,IAAI;AAAA,IACtB,QAAQ,KAAK,gBAAgB,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC;AAAA,EACzD;AAEA,QAAM,UAAU,KAAK,QAAQ,WAAW,QAAQ,KAAK,cAAc;AAEnE,aAAW,OAAO,SAAS;AACzB,UAAM,MAAM,IAAI;AAChB,QAAI,cAAc,IAAI,GAAG,GAAG;AAC1B,qBAAe,OAAO,IAAI,cAAc,IAAI,MAAM,IAAI,OAAO,OAAO;AAAA,IACtE,WAAW,YAAY,IAAI,GAAG,GAAG;AAC/B,kBAAY,OAAO,IAAI,cAAc,IAAI,MAAM,IAAI,OAAO,GAAG;AAAA,IAC/D;AAAA,EAEF;AAEA,QAAM,YAAY,KAAK,IAAI;AAC3B,SAAO;AACT;AAKA,SAAS,eACP,OACA,SACA,MACA,OACA,SACM;AACN,MAAI;AACJ,MAAI;AACF,UAAM,gBAAAC,QAAG,aAAa,SAAS,MAAM;AAAA,EACvC,SAAS,KAAK;AACZ,UAAM,SAAS,KAAK;AAAA,MAClB,MAAM;AAAA,MACN,SAAS,yCAAW,OAAO,KACzB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CACjD;AAAA,MACA,UAAU,CAAC,OAAO;AAAA,IACpB,CAAC;AACD;AAAA,EACF;AAEA,QAAM,EAAE,MAAM,SAAS,MAAM,IAAI,iBAAiB,GAAG;AACrD,MAAI,OAAO;AACT,UAAM,SAAS,KAAK;AAAA,MAClB,MAAM;AAAA,MACN,SAAS,yCAAqB,OAAO,MAAM,KAAK;AAAA,MAChD,UAAU,CAAC,OAAO;AAAA,IACpB,CAAC;AAAA,EACH;AAEA,QAAM,UAAU,iBAAiB,KAAK,OAAO;AAC7C,QAAM,OAAO,cAAc,KAAK,IAAI;AACpC,QAAM,WAAW,gBAAgB,SAAS,QAAQ,OAAO;AACzD,QAAM,MAAM,SAAa,MAAM,QAAQ,OAAO;AAC9C,QAAM,OAAO,SAAS,SAAS,IAAI;AACnC,QAAM,MAAM,QAAQ,OAAO;AAC3B,QAAM,MAAM,WAAW,KAAK,OAAO;AAEnC,QAAM,QAAmB;AAAA,IACvB,cAAc;AAAA,IACd,cAAc;AAAA,IACd,UAAU;AAAA,IACV,WAAW;AAAA,IACX;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,oBAAkB,OAAO,OAAO,OAAO;AACzC;AAKA,SAAS,YACP,OACA,SACA,MACA,OACA,KACM;AACN,QAAM,MAAM,SAAa,MAAM,QAAQ,OAAO;AAC9C,QAAM,OAAO,SAAS,OAAO;AAE7B,QAAM,QAAoB;AAAA,IACxB,cAAc;AAAA,IACd,cAAc;AAAA,IACd,UAAU;AAAA,IACV,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA,cAAc,oBAAI,IAAI;AAAA,EACxB;AAEA,QAAM,OAAO,IAAI,SAAS,KAAK;AAC/B,QAAM,qBAAqB,IAAI,KAAK,KAAK;AACzC,iBAAe,MAAM,kBAAkB,MAAM,KAAK;AAClD,iBAAe,MAAM,uBAAuB,KAAK,YAAY,GAAG,KAAK;AACvE;AAKA,SAAS,kBACP,OACA,OACA,SACM;AACN,QAAM,MAAM,IAAI,MAAM,cAAc,KAAK;AACzC,QAAM,eAAe,IAAI,MAAM,cAAc,KAAK;AAIlD,QAAM,gBAAgB,MAAM,MAAM,IAAI,MAAM,GAAG;AAC/C,MAAI,iBAAiB,cAAc,iBAAiB,MAAM,cAAc;AACtE,UAAM,SAAS,KAAK;AAAA,MAClB,MAAM;AAAA,MACN,SACE,kCAAc,MAAM,YAAY,aAAQ,cAAc,YAAY,+BACzD,MAAM,GAAG,4HACuB,MAAM,YAAY;AAAA,MAC7D,UAAU,CAAC,cAAc,cAAc,MAAM,YAAY;AAAA,IAC3D,CAAC;AAAA,EACH;AACA,QAAM,MAAM,IAAI,MAAM,KAAK,KAAK;AAChC,QAAM,SAAS,IAAI,MAAM,cAAc,MAAM,QAAQ;AAErD,iBAAe,MAAM,YAAY,MAAM,UAAU,KAAK;AACtD,iBAAe,MAAM,iBAAiB,MAAM,SAAS,YAAY,GAAG,KAAK;AAEzE,aAAW,SAAS,MAAM,SAAS;AACjC,UAAM,MAAM,QAAQ,gBAAgB,QAAQ,MAAM,YAAY;AAC9D,QAAI,MAAM,QAAQ,IAAI,GAAG,GAAG;AAC1B,YAAM,SAAS,KAAK;AAAA,QAClB,MAAM;AAAA,QACN,SAAS,UAAU,KAAK,oFAAkC,QAAQ,eAAe;AAAA,QACjF,UAAU,CAAC,MAAM,QAAQ,IAAI,GAAG,EAAG,cAAc,MAAM,YAAY;AAAA,MACrE,CAAC;AACD,UAAI,QAAQ,oBAAoB,QAAS;AAAA,IAE3C;AACA,UAAM,QAAQ,IAAI,KAAK,KAAK;AAAA,EAC9B;AAEA,aAAW,OAAO,MAAM,MAAM;AAC5B,mBAAe,MAAM,MAAM,KAAK,KAAK;AAAA,EACvC;AACF;AAUA,SAAS,WAAW,KAAa,SAAkC;AACjE,QAAM,QAAQ,IAAI,QAAQ,qBAAqB,EAAE;AAEjD,QAAM,UAAU,yBAAyB,KAAK,KAAK;AACnD,QAAM,WAAW,UAAU,MAAM,QAAQ,0BAA0B,IAAI,IAAI;AAG3E,QAAM,WAAW,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AACnD,MAAI,SAAS,WAAW,GAAG;AAEzB,WAAO;AAAA,EACT;AAGA,QAAM,OAAO,SAAS,SAAS,SAAS,CAAC;AACzC,MAAI,CAAC,SAAS;AACZ,aAAS,SAAS,SAAS,CAAC,IAAI,eAAe,MAAM,QAAQ,SAAS;AAAA,EACxE,WAAW,CAAC,QAAQ,WAAW;AAC7B,aAAS,KAAK,YAAY;AAAA,EAC5B;AAKA,SAAO,SAAS,KAAK,QAAQ;AAC/B;AAGA,SAAS,eAAqB,GAAgB,GAAM,GAAY;AAC9D,QAAM,MAAM,EAAE,IAAI,CAAC;AACnB,MAAI,IAAK,KAAI,KAAK,CAAC;AAAA,MACd,GAAE,IAAI,GAAG,CAAC,CAAC,CAAC;AACnB;AAMO,SAAS,WACd,OACA,SACA,SACM;AACN,QAAM,QAAQ,QAAQ,OAAO;AAC7B,aAAW,OAAO,OAAO,OAAO;AAChC,MAAI;AACJ,MAAI;AACF,WAAO,gBAAAA,QAAG,SAAS,KAAK;AAAA,EAC1B,QAAQ;AACN;AAAA,EACF;AACA,QAAM,MAAM,QAAQ,KAAK;AACzB,MAAI,cAAc,IAAI,GAAG,GAAG;AAC1B,mBAAe,OAAO,OAAO,KAAK,MAAM,KAAK,SAAS,OAAO;AAAA,EAC/D,WACE,IAAI,IAAI,QAAQ,KAAK,gBAAgB,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,EAAE,IAAI,GAAG,GACzE;AACA,gBAAY,OAAO,OAAO,KAAK,MAAM,KAAK,SAAS,GAAG;AAAA,EACxD;AACF;AAKO,SAAS,WACd,OACA,SACA,SACM;AACN,QAAM,QAAQ,QAAQ,OAAO;AAG7B,QAAM,OAAO,MAAM,MAAM,IAAI,KAAK;AAClC,MAAI,MAAM;AACR,UAAM,MAAM,OAAO,KAAK;AACxB,UAAM,eAAe,OAAO,KAAK,YAAY;AAC7C,UAAM,MAAM,OAAO,KAAK,GAAG;AAC3B,UAAM,SAAS,OAAO,KAAK;AAC3B,uBAAmB,MAAM,YAAY,KAAK,UAAU,IAAI;AACxD;AAAA,MACE,MAAM;AAAA,MACN,KAAK,SAAS,YAAY;AAAA,MAC1B;AAAA,IACF;AACA,eAAW,SAAS,KAAK,SAAS;AAChC,YAAM,MAAM,QAAQ,gBAAgB,QAAQ,MAAM,YAAY;AAC9D,UAAI,MAAM,QAAQ,IAAI,GAAG,MAAM,KAAM,OAAM,QAAQ,OAAO,GAAG;AAAA,IAC/D;AACA,eAAW,OAAO,KAAK,MAAM;AAC3B,yBAAmB,MAAM,MAAM,KAAK,IAAI;AAAA,IAC1C;AACA;AAAA,EACF;AAGA,QAAM,QAAQ,MAAM,OAAO,IAAI,KAAK;AACpC,MAAI,OAAO;AACT,UAAM,OAAO,OAAO,KAAK;AACzB,UAAM,qBAAqB,OAAO,MAAM,YAAY;AACpD,uBAAmB,MAAM,kBAAkB,MAAM,UAAU,KAAK;AAChE;AAAA,MACE,MAAM;AAAA,MACN,MAAM,SAAS,YAAY;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,mBAAyB,GAAgB,GAAM,GAAY;AAClE,QAAM,MAAM,EAAE,IAAI,CAAC;AACnB,MAAI,CAAC,IAAK;AACV,QAAM,MAAM,IAAI,QAAQ,CAAC;AACzB,MAAI,OAAO,EAAG,KAAI,OAAO,KAAK,CAAC;AAC/B,MAAI,IAAI,WAAW,EAAG,GAAE,OAAO,CAAC;AAClC;AAKO,SAAS,mBACd,OACK;AACL,SAAO,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM;AAC/B,UAAM,KAAK,UAAU,EAAE,YAAY;AACnC,UAAM,KAAK,UAAU,EAAE,YAAY;AACnC,QAAI,OAAO,GAAI,QAAO,KAAK;AAC3B,WAAO,EAAE,aAAa,cAAc,EAAE,YAAY;AAAA,EACpD,CAAC;AACH;;;AOxVO,SAAS,gBACd,WACA,OACA,SACA,OAAgC,QAEhC,mBACe;AAEf,MAAI,SAAS,QAAQ,SAAS,EAAE,KAAK;AAErC,QAAM,UAAU,OAAO,QAAQ,GAAG;AAClC,MAAI,cAAc;AAClB,MAAI,WAAW,GAAG;AAChB,kBAAc,OAAO,MAAM,UAAU,CAAC,EAAE,KAAK;AAC7C,aAAS,OAAO,MAAM,GAAG,OAAO,EAAE,KAAK;AAAA,EACzC;AAEA,WAAS,iBAAiB,MAAM;AAGhC,QAAM,QAAQ,YAAY,QAAQ,OAAO,SAAS,iBAAiB;AAEnE,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,MACL,KAAK,aAAa,WAAW,OAAO;AAAA,MACpC,cAAc,aAAa,QAAQ,aAAa,QAAW,OAAO;AAAA,MAClE,QAAQ;AAAA,MACR,oBAAoB;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAGA,MAAI,MAAM,MAAM;AAChB,MAAI,qBAAqB;AACzB,MAAI,aAAa;AACf,UAAM,UAAU,MAAM,SAAS;AAAA,MAC7B,CAAC,MACC,EAAE,SAAS,eACX,EAAE,SAAS,eACX,EAAE,SAAS,QAAQ,QAAQ,WAAW;AAAA,IAC1C;AACA,QAAI,SAAS;AACX,YAAM,MAAM,MAAM,MAAM,QAAQ;AAAA,IAClC,OAAO;AACL,2BAAqB;AACrB,YAAM,MAAM,MAAM,MAAM,mBAAmB,WAAW;AAAA,IACxD;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,cAAc,aAAa,QAAQ,aAAa,OAAO,OAAO;AAAA,IAC9D,QAAQ;AAAA,IACR;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,EACF;AACF;AAKA,SAAS,YACP,QACA,OACA,SACA,mBACuB;AACvB,MAAI,CAAC,OAAQ,QAAO;AAGpB,MAAI,OAAO,SAAS,GAAG,GAAG;AAExB,UAAM,WAAW;AAAA,MACf;AAAA,MACA,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AACA,eAAW,KAAK,UAAU;AACxB,YAAM,IAAI,MAAM,eAAe,IAAI,CAAC;AACpC,UAAI,EAAG,QAAO;AAAA,IAChB;AAEA,QAAI,mBAAmB;AAErB,YAAM,YAAY,MAAM;AACxB,YAAM,MAAM,QAAQ,iBAAiB,EAAE,WAAW,YAAY,GAAG,IAC7D,QAAQ,iBAAiB,EAAE,MAAM,UAAU,SAAS,CAAC,IACrD;AACJ,UAAI,KAAK;AACP,cAAM,SAAS,IAAI,MAAM,GAAG,EAAE,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG;AACnD,YAAI,QAAQ;AACV,gBAAM,cAAc;AAAA,YAClB,GAAG,MAAM,IAAI,MAAM;AAAA,YACnB,GAAG,MAAM,IAAI,MAAM;AAAA,YACnB,GAAG,MAAM,IAAI,MAAM;AAAA,YACnB,GAAG,MAAM,IAAI,MAAM;AAAA,YACnB,GAAG,MAAM,IAAI,MAAM;AAAA,UACrB;AACA,qBAAW,KAAK,aAAa;AAC3B,kBAAM,IAAI,MAAM,eAAe,IAAI,CAAC;AACpC,gBAAI,EAAG,QAAO;AAAA,UAChB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAGA,QAAM,WAAW,QAAQ,gBAAgB,SAAS,OAAO,YAAY;AACrE,QAAM,UAAU,MAAM,QAAQ,IAAI,QAAQ;AAC1C,MAAI,QAAS,QAAO;AAGpB,QAAM,QAAQ,QAAQ,gBAClB,MAAM,aACN,MAAM;AACV,QAAM,QAAQ,QAAQ,gBAAgB,SAAS,OAAO,YAAY;AAClE,QAAM,aAAa,MAAM,IAAI,KAAK;AAClC,MAAI,CAAC,cAAc,WAAW,WAAW,EAAG,QAAO;AACnD,MAAI,WAAW,WAAW,EAAG,QAAO,WAAW,CAAC;AAGhD,UAAQ,QAAQ,YAAY;AAAA,IAC1B,KAAK,YAAY;AACf,YAAM,SAAS,mBAAmB,UAAU;AAC5C,aAAO,OAAO,CAAC;AAAA,IACjB;AAAA,IACA,KAAK;AACH,aAAO,WAAW,CAAC;AAAA,IACrB,KAAK;AAEH,aAAO;AAAA,EACX;AACF;AAMA,SAAS,aAAa,WAAmB,SAAkC;AAEzE,QAAM,OAAO,mBAAmB,iBAAiB,SAAS,EAAE,MAAM,GAAG,EAAE,CAAC,CAAE;AAC1E,SAAO,QAAQ,OAAO;AACxB;AAQA,SAAS,aACP,QACA,aACA,OACA,SACQ;AACR,QAAM,KAAK,QAAQ,UAAU;AAC7B,MAAI;AACJ,MAAI,OAAO,OAAO,YAAY;AAC5B,QAAI,OAAO;AACT,aAAO,GAAG,OAAO,MAAM;AAAA,IACzB,OAAO;AAEL,aAAO,SAAS,MAAM;AAAA,IACxB;AAAA,EACF,WAAW,OAAO,YAAY;AAC5B,WAAO,QAAQ,MAAM,aAAa,QAAQ,qBAAqB,EAAE,IAAI;AAAA,EACvE,OAAO;AAEL,WAAO,QAAQ,MAAM,WAAW,SAAS,MAAM;AAAA,EACjD;AACA,MAAI,aAAa;AAEf,WAAO,GAAG,IAAI,MAAM,WAAW;AAAA,EACjC;AACA,SAAO;AACT;AAMO,SAAS,aACd,WACA,OACA,SAIA;AACA,QAAM,SAAS,QAAQ,SAAS,EAAE,KAAK;AAEvC,MAAI,OAAO,SAAS,GAAG,GAAG;AACxB,WAAO;AAAA,MACL,OAAO,MAAM,qBAAqB,IAAI,MAAM;AAAA,MAC5C,aAAa,SAAS,MAAM;AAAA,IAC9B;AAAA,EACF;AACA,QAAM,KAAK,QAAQ,gBAAgB,SAAS,OAAO,YAAY;AAC/D,QAAM,MAAM,QAAQ,gBAChB,MAAM,mBACN,MAAM;AACV,QAAM,aAAa,IAAI,IAAI,EAAE;AAC7B,MAAI,CAAC,cAAc,WAAW,WAAW,GAAG;AAC1C,WAAO,EAAE,OAAO,QAAW,aAAa,OAAO;AAAA,EACjD;AACA,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO,EAAE,OAAO,WAAW,CAAC,GAAG,aAAa,OAAO;AAAA,EACrD;AAEA,UAAQ,QAAQ,YAAY;AAAA,IAC1B,KAAK,YAAY;AACf,YAAM,SAAS,mBAAmB,UAAU;AAC5C,aAAO,EAAE,OAAO,OAAO,CAAC,GAAG,aAAa,OAAO;AAAA,IACjD;AAAA,IACA,KAAK;AACH,aAAO,EAAE,OAAO,WAAW,CAAC,GAAG,aAAa,OAAO;AAAA,IACrD,KAAK;AACH,aAAO,EAAE,OAAO,QAAW,aAAa,OAAO;AAAA,EACnD;AACF;;;ACjPO,SAAS,eACd,OACA,QACA,OACA,KACS;AACT,QAAM,OAAO,MAAM,KAAK,aAAa,KAAK,CAAC;AAC3C,QAAM,UAAU,CAAC,UAAU;AAC3B,MAAI,OAAO,mBAAoB,SAAQ,KAAK,4BAA4B;AAExE,QAAM,YAAoC;AAAA,IACxC,MAAM,OAAO;AAAA,IACb,OAAO,QAAQ,KAAK,GAAG;AAAA,IACvB,wBAAwB,OAAO,SAC3B,OAAO,OAAO,eACd;AAAA,EACN;AAEA,QAAM,QAAQ,kBAAkB,IAAI,QAAQ,UAAU,gBAAgB;AAAA,IACpE,cAAc,OAAO;AAAA,IACrB;AAAA,IACA,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,IACf,oBAAoB,OAAO;AAAA,EAC7B,CAAC;AAED,aAAW,MAAM,WAAW,KAAK;AAIjC,YAAU,OAAO,OAAO,GAAG;AAE3B,QAAM,KAAK,cAAc,KAAK,EAAE;AAChC,SAAO;AACT;AASO,SAAS,eACd,OACA,KACA,OACA,WACA,KACS;AACT,QAAM,OAAO,MAAM,KAAK,aAAa,KAAK,CAAC;AAC3C,QAAM,YAAoC;AAAA;AAAA,IAExC,OAAO;AAAA,IACP,wBAAwB;AAAA,IACxB,OAAO,qCAAY,SAAS;AAAA,EAC9B;AACA,QAAM,QAAQ,kBAAkB,IAAI,QAAQ,UAAU,gBAAgB;AAAA,IACpE,cAAc;AAAA,IACd;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,oBAAoB;AAAA,EACtB,CAAC;AACD,aAAW,MAAM,WAAW,KAAK;AAEjC,YAAU,OAAO,OAAO,GAAG;AAE3B,QAAM,KAAK,cAAc,KAAK,EAAE;AAChC,SAAO;AACT;AAKA,SAAS,UACP,OACA,OACA,KACM;AACN,MAAI,IAAI,QAAQ,UAAU,0BAA0B;AAElD,UAAM,QAAS,IAA4C,eAAe;AAC1E,QAAI,QAAQ,GAAG;AACb;AAAC,MAAC,IAA4C,cAAc,QAAQ;AACpE,YAAM,KAAK,MAAM;AACjB,YAAM,OAAO,GAAG,aAAa,OAAO,GAAG;AACvC,YAAM,QAAQ,MAAM,KAAK,eAAe,IAAI,CAAC;AAC7C,YAAM,UAAU;AACf,MAAC,IAA4C,cAAc;AAC5D;AAAA,IACF;AAAA,EACF;AACA,QAAM,IAAI,MAAM,KAAK,QAAQ,IAAI,CAAC;AAClC,IAAE,UAAU;AACd;AAKA,SAAS,kBACP,WACA,KACwB;AACxB,MAAI,OAAO,cAAc,WAAY,QAAO,UAAU,GAAG;AACzD,SAAO,aAAa,CAAC;AACvB;AAMA,SAAS,WACP,OACA,MACA,OACM;AACN,QAAM,SAAiC,EAAE,GAAG,KAAK;AACjD,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC1C,QAAI,MAAM,WAAW,OAAO,OAAO;AACjC,aAAO,QAAQ,OAAO,QAAQ,MAAM;AAAA,IACtC,OAAO;AACL,aAAO,CAAC,IAAI;AAAA,IACd;AAAA,EACF;AACA,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC3C,UAAM,QAAQ,GAAG,CAAC;AAAA,EACpB;AACF;;;ACzIA,IAAM,kBAA0C;AAAA,EAC9C,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACP;AAEA,IAAM,iBAAiB;AAEhB,SAAS,WAAW,GAAmB;AAC5C,SAAO,EAAE,QAAQ,gBAAgB,CAAC,MAAM,gBAAgB,CAAC,CAAE;AAC7D;;;ACEO,IAAM,2BAA2B;AAWjC,SAAS,oBACd,OACA,SACQ;AACR,QAAM,KAAK,UAAU,MAAM,YAAY;AACvC,SAAO,QAAQ,OAAO,yBAAyB,MAAM,CAAC,IAAI;AAC5D;;;ACFO,SAAS,gBACd,WACA,YACA,KACQ;AACR,QAAM,EAAE,OAAO,QAAQ,IAAI;AAE3B,QAAM,EAAE,SAAS,IAAI,IAAI,eAAe,UAAU;AAElD,QAAM,kBAAkB,QAAQ,OAAO,uBAAuB,SAAS;AACvE,QAAM,EAAE,MAAM,IAAI,aAAa,iBAAiB,OAAO,OAAO;AAE9D,MAAI;AACJ,MAAI,OAAO;AACT,UAAM,aAAa,IAAI,IAAI,eAAe,WAAW;AACrD,QAAI,kBAAkB,IAAI,KAAK;AAC/B,UAAM,oBAAoB,OAAO,OAAO,IAAI,QAAQ,OAAO;AAAA,EAC7D,OAAO;AACL,UACE,QAAQ,OACR,mBAAmB,SAAS,eAAe,CAAC,IAC5C,QAAQ,OAAO;AAAA,EACnB;AAEA,QAAM,WAAW,aAAa,SAAS,iBAAiB,OAAO;AAE/D,QAAM,QAAgC;AAAA,IACpC;AAAA,IACA,KAAK,YAAY;AAAA,EACnB;AACA,MAAI,IAAI,UAAU,OAAW,OAAM,QAAQ,OAAO,IAAI,KAAK;AAC3D,MAAI,IAAI,WAAW,OAAW,OAAM,SAAS,OAAO,IAAI,MAAM;AAE9D,QAAM,QAAQ,aAAa,QAAQ,OAAO,gBAAgB;AAAA,IACxD,cAAc;AAAA,IACd,SAAS;AAAA,IACT,YAAY,IAAI;AAAA,IAChB,WAAW;AAAA,EACb,CAAC;AACD,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC1C,QAAI,MAAM,WAAW,MAAM,OAAO;AAChC,YAAM,QAAQ,MAAM,QAAQ,MAAM;AAAA,IACpC,OAAO;AACL,YAAM,CAAC,IAAI;AAAA,IACb;AAAA,EACF;AAEA,SACE,UACA,OAAO,QAAQ,KAAK,EACjB,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,eAAe,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,GAAG,EACzD,KAAK,GAAG,IACX;AAEJ;AAOO,SAAS,iBACd,OACA,WACA,YACA,KACS;AACT,QAAM,OAAO,gBAAgB,WAAW,YAAY,GAAG;AACvD,QAAM,QAAQ,MAAM,KAAK,eAAe,IAAI,CAAC;AAC7C,QAAM,UAAU;AAChB,SAAO;AACT;AAUA,SAAS,eAAe,OAGtB;AACA,MAAI,MAAM,WAAW,EAAG,QAAO,EAAE,SAAS,IAAI,KAAK,EAAE,KAAK,GAAG,EAAE;AAC/D,QAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,QAAM,aAAa,kBAAkB,IAAI;AACzC,MAAI,YAAY;AACd,UAAM,MAAM,MAAM,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,EAAE,KAAK;AAC9C,WAAO,EAAE,SAAS,KAAK,KAAK,EAAE,GAAG,YAAY,KAAK,KAAK,EAAE;AAAA,EAC3D;AACA,SAAO,EAAE,SAAS,MAAM,KAAK,GAAG,EAAE,KAAK,GAAG,KAAK,EAAE,KAAK,GAAG,EAAE;AAC7D;AAEA,SAAS,kBACP,GACiD;AACjD,QAAM,UAAU,EAAE,KAAK,EAAE,YAAY;AACrC,MAAI,CAAC,QAAS,QAAO;AAErB,MAAI,QAAQ,SAAS,GAAG,GAAG;AACzB,UAAM,CAAC,GAAG,CAAC,IAAI,QAAQ,MAAM,GAAG;AAChC,UAAM,MAAM,MAAM,MAAM,QAAQ,KAAK,CAAE;AACvC,UAAM,MAAM,MAAM,MAAM,QAAQ,KAAK,CAAE;AACvC,QAAI,CAAC,OAAO,CAAC,IAAK,QAAO;AACzB,QAAI,MAAM,MAAM,MAAM,GAAI,QAAO;AACjC,WAAO;AAAA,MACL,OAAO,MAAM,KAAK,SAAY,OAAO,CAAC;AAAA,MACtC,QAAQ,MAAM,KAAK,SAAY,OAAO,CAAC;AAAA,IACzC;AAAA,EACF;AACA,MAAI,QAAQ,KAAK,OAAO,GAAG;AACzB,WAAO,EAAE,OAAO,OAAO,OAAO,EAAE;AAAA,EAClC;AACA,SAAO;AACT;AAEA,SAAS,aACP,QACA,QACA,SACoB;AACpB,MAAI,UAAU,WAAW,IAAI;AAC3B,WAAO,QAAQ,OAAO,mBAAmB,MAAM;AAAA,EACjD;AACA,QAAM,MAAM,QAAQ,OAAO;AAC3B,MAAI,QAAQ,MAAO,QAAO;AAC1B,MAAI,QAAQ,MAAM;AAChB,UAAM,KAAK,SAAS,MAAM;AAC1B,UAAM,MAAM,GAAG,YAAY,GAAG;AAC9B,UAAM,QAAQ,MAAM,IAAI,GAAG,MAAM,GAAG,GAAG,IAAI;AAC3C,WAAO,QAAQ,OAAO,mBAAmB,KAAK;AAAA,EAChD;AACA,MAAI,OAAO,QAAQ,UAAU;AAC3B,WAAO,QAAQ,KAAK,KAAK,QAAQ,OAAO,mBAAmB,GAAG;AAAA,EAChE;AACA,SAAO,QAAQ,OAAO,mBAAmB,SAAS,MAAM,CAAC;AAC3D;AAEA,SAAS,aACP,OACA,KACwB;AACxB,MAAI,OAAO,UAAU,WAAY,QAAO,MAAM,GAAG;AACjD,SAAO,SAAS,CAAC;AACnB;AAEA,SAAS,eAAe,GAAmB;AACzC,SAAO,EAAE,QAAQ,mBAAmB,GAAG;AACzC;;;AC5JO,SAAS,uBACd,IACA,WACA,YACA,KACQ;AACR,QAAM,EAAE,OAAO,QAAQ,IAAI;AAC3B,QAAM,SAAS,gBAAgB,WAAW,OAAO,SAAS,cAAc;AAExE,MAAI,OAAO,UAAU,CAAC,OAAO,QAAQ;AACnC,WAAO,6DAA6D;AAAA,MAClE;AAAA,IACF,CAAC,uDAAoB,WAAW,SAAS,CAAC;AAAA,EAC5C;AAEA,QAAM,SAAS,OAAO;AAGtB,QAAM,MAAM,MAAM,UAAU,IAAI,OAAO,YAAY,KAAK,CAAC;AACzD,MAAI,IAAI,aAAa;AACnB,QAAI,KAAK;AAAA,MACP,UAAU,IAAI;AAAA,MACd,SAAS,MAAM,MAAM,IAAI,IAAI,WAAW,GAAG,OAAO;AAAA,MAClD,SAAS;AAAA,MACT,SAAS;AAAA,MACT,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AACA,QAAM,UAAU,IAAI,OAAO,cAAc,GAAG;AAE5C,QAAM,QAAQ,IAAI,qBAAqB,CAAC;AACxC,MAAI,MAAM,SAAS,OAAO,YAAY,GAAG;AACvC,WAAO,8DAA8D;AAAA,MACnE;AAAA,IACF,CAAC,iDAAmB;AAAA,MAClB;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,QAAQ,IAAI,qBAAqB;AACvC,MAAI,SAAS,QAAQ,OAAO,sBAAsB;AAChD,WAAO,iEAAiE;AAAA,MACtE;AAAA,IACF,CAAC,6DAA+B,QAAQ,OAAO,oBAAoB;AAAA,EACrE;AAEA,QAAM,cAAc,eAAe,SAAS;AAC5C,QAAM,WAAW,cACb,eAAe,QAAQ,aAAa,QAAQ,OAAO,IACnD,OAAO;AAEX,MAAI,YAAY,MAAM;AACpB,WAAO,yEAAyE;AAAA,MAC9E;AAAA,IACF,CAAC,wDAAqB;AAAA,MACpB;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,WAAW,GAAG,OAAO,YAAY,KAAK,eAAe,EAAE;AAC7D,QAAM,QAAQ,SAAS,GAAG;AAC1B,MAAI;AACJ,QAAM,SAAS,MAAM,IAAI,QAAQ;AACjC,MAAI,QAAQ;AACV,YAAQ,OAAO;AAAA,EACjB,OAAO;AAQL,UAAM,WAA0B;AAAA,MAC9B,OAAO,IAAI;AAAA,MACX,SAAS,IAAI;AAAA,MACb,aAAa,OAAO;AAAA,MACpB,mBAAmB,CAAC,GAAG,OAAO,OAAO,YAAY;AAAA,MACjD,mBAAmB,QAAQ;AAAA;AAAA,MAE3B,kBAAkB,IAAI;AAAA,IACxB;AAEC,IAAC,SAAgD,qBAChD,IACA;AAEF,YAAQ,GAAG,OAAO,UAAU,QAAQ;AACpC,UAAM,IAAI,UAAU,EAAE,MAAM,MAAM,CAAC;AAAA,EACrC;AAEA,QAAM,YAAY,cACd,GAAG,OAAO,GAAG,IAAI,QAAQ,QAAQ,WAAW,CAAC,KAC7C,OAAO;AAEX,QAAM,YAAY,WAAW,SACzB,kBAAkB,WAAW,WAAW,KAAK,GAAG,CAAC,CAAC,MAClD;AAIJ,QAAM,aACJ,6CACS,WAAW,SAAS,CAAC,+BACD,WAAW,OAAO,YAAY,CAAC,YAClD,WAAW,OAAO,YAAY,CAAC;AAE3C,SACE,0CAA0C,WAAW,OAAO,YAAY,CAAC,sBACpD,WAAW,SAAS,CAAC,IAAI,SAAS,MACvD,aACA,QACA;AAEJ;AAMO,SAAS,mBACd,OACA,WACA,YACA,KACS;AACT,MAAI,IAAI,QAAQ,aAAa,UAAU;AACrC,YAAQ;AAAA,MACN,4BAA4B,SAAS;AAAA,IACvC;AAAA,EACF;AACA,QAAM,EAAE,OAAO,QAAQ,IAAI;AAC3B,QAAM,SAAS,gBAAgB,WAAW,OAAO,SAAS,MAAM;AAChE,QAAM,MAAM,OAAO;AACnB,QAAM,QAAQ,WAAW,SACrB,WAAW,KAAK,GAAG,EAAE,KAAK,IAC1B,OAAO;AAEX,QAAM,OACJ,oEACS,WAAW,GAAG,CAAC,2BACC,WAAW,SAAS,CAAC,mFAE3C,WAAW,KAAK,CAAC;AAEtB,QAAM,QAAQ,MAAM,KAAK,eAAe,IAAI,CAAC;AAC7C,QAAM,UAAU;AAChB,SAAO;AACT;AAEA,SAAS,eAAe,KAAqB;AAC3C,QAAM,UAAU,IAAI,QAAQ,GAAG;AAC/B,MAAI,UAAU,EAAG,QAAO;AACxB,SAAO,IAAI,MAAM,UAAU,CAAC,EAAE,KAAK;AACrC;AAEA,SAAS,eACP,QACA,aACA,SACoB;AACpB,QAAM,UAAU,OAAO,SAAS;AAAA,IAC9B,CAAC,MACC,EAAE,SAAS,eACX,EAAE,SAAS,eACX,EAAE,SAAS,QAAQ,WAAW;AAAA,EAClC;AACA,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,QAAQ,OAAO,QAAQ,MAAM,OAAO;AAC1C,QAAM,YAAY,QAAQ,OAAO;AACjC,MAAI,UAAU,MAAM;AACpB,WAAS,IAAI,WAAW,IAAI,MAAM,QAAQ,KAAK;AAC7C,UAAM,IAAI,MAAM,CAAC;AACjB,UAAM,IAAI,EAAE,MAAM,cAAc;AAChC,QAAI,KAAK,EAAE,CAAC,EAAG,UAAU,QAAQ,OAAO;AACtC,gBAAU;AACV;AAAA,IACF;AAAA,EACF;AACA,SAAO,MAAM,MAAM,WAAW,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK;AACzD;AAEA,SAAS,SAAS,KAAyD;AACzE,QAAM,IAAI;AAGV,MAAI,CAAC,EAAE,mBAAoB,GAAE,qBAAqB,oBAAI,IAAI;AAC1D,SAAO,EAAE;AACX;;;ACnMA,IAAM,aAAa,CAAC,OAAO,OAAO,OAAO,OAAO,QAAQ,OAAO,MAAM;AACrE,IAAM,aAAa,CAAC,OAAO,QAAQ,OAAO,OAAO,OAAO,KAAK;AAC7D,IAAM,WAAW,CAAC,KAAK;AAEhB,SAAS,WAAW,KAAsB;AAC/C,SAAO,WAAW,SAAS,IAAI,YAAY,CAAC;AAC9C;AACO,SAAS,WAAW,KAAsB;AAC/C,SAAO,WAAW,SAAS,IAAI,YAAY,CAAC;AAC9C;AACO,SAAS,SAAS,KAAsB;AAC7C,SAAO,SAAS,SAAS,IAAI,YAAY,CAAC;AAC5C;AAGO,SAAS,iBACd,KACkC;AAClC,MAAI,WAAW,GAAG,EAAG,QAAO;AAC5B,MAAI,WAAW,GAAG,EAAG,QAAO;AAC5B,MAAI,SAAS,GAAG,EAAG,QAAO;AAC1B,SAAO;AACT;AAQA,SAAS,cAAc,OAA4B;AACjD,MAAI,MAAM,WAAW,EAAG,QAAO,CAAC;AAChC,QAAM,OAAO,MAAM,MAAM,SAAS,CAAC,EAAG,KAAK,EAAE,YAAY;AACzD,MAAI,CAAC,KAAM,QAAO,CAAC;AACnB,MAAI,KAAK,SAAS,GAAG,GAAG;AACtB,UAAM,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM,GAAG;AAC7B,UAAM,MAAM,MAAM,MAAM,QAAQ,KAAK,CAAE;AACvC,UAAM,MAAM,MAAM,MAAM,QAAQ,KAAK,CAAE;AACvC,QAAI,CAAC,OAAO,CAAC,IAAK,QAAO,CAAC;AAC1B,WAAO;AAAA,MACL,OAAO,MAAM,KAAK,SAAY,OAAO,CAAC;AAAA,MACtC,QAAQ,MAAM,KAAK,SAAY,OAAO,CAAC;AAAA,IACzC;AAAA,EACF;AACA,MAAI,QAAQ,KAAK,IAAI,EAAG,QAAO,EAAE,OAAO,OAAO,IAAI,EAAE;AACrD,SAAO,CAAC;AACV;AAGA,SAAS,WAAW,WAAmB,KAA4B;AACjE,QAAM,EAAE,OAAO,QAAQ,IAAI;AAC3B,QAAM,kBAAkB,QAAQ,OAAO,uBAAuB,SAAS;AACvE,QAAM,EAAE,MAAM,IAAI,aAAa,iBAAiB,OAAO,OAAO;AAC9D,MAAI,OAAO;AACT,UAAM,aAAa,IAAI,IAAI,eAAe,WAAW;AACrD,QAAI,kBAAkB,IAAI,KAAK;AAC/B,WAAO,oBAAoB,OAAO,OAAO,IAAI,QAAQ,OAAO;AAAA,EAC9D;AACA,SACE,QAAQ,OACR,mBAAmB,SAAS,eAAe,CAAC,IAC5C,QAAQ,OAAO;AAEnB;AAIO,SAAS,gBACd,WACA,aACA,KACQ;AACR,QAAM,MAAM,WAAW,WAAW,GAAG;AACrC,SACE,8EACQ,WAAW,GAAG,CAAC;AAI3B;AAEO,SAAS,gBACd,WACA,YACA,KACQ;AACR,QAAM,MAAM,WAAW,WAAW,GAAG;AACrC,QAAM,MAAM,cAAc,UAAU;AACpC,QAAM,QAAkB;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,WAAW,GAAG,CAAC;AAAA,EACzB;AACA,MAAI,IAAI,UAAU,OAAW,OAAM,KAAK,UAAU,IAAI,KAAK,GAAG;AAC9D,MAAI,IAAI,WAAW,OAAW,OAAM,KAAK,WAAW,IAAI,MAAM,GAAG;AACjE,SACE,UAAU,MAAM,KAAK,GAAG,CAAC;AAI7B;AAEO,SAAS,cACd,WACA,YACA,KACQ;AACR,QAAM,MAAM,WAAW,WAAW,GAAG;AACrC,QAAM,MAAM,cAAc,UAAU;AAEpC,QAAM,QAAQ,IAAI,UAAU,SAAY,GAAG,IAAI,KAAK,OAAO;AAC3D,QAAM,SAAS,IAAI,WAAW,SAAY,GAAG,IAAI,MAAM,OAAO;AAC9D,SACE,iDACQ,WAAW,GAAG,CAAC,kBACP,WAAW,KAAK,CAAC,WAAW,WAAW,MAAM,CAAC,oCACrC,WAAW,SAAS,SAAS,CAAC,CAAC;AAG5D;AAMO,SAAS,iBACd,OACA,MACA,WACA,YACA,KACS;AACT,MAAI;AACJ,MAAI,SAAS,QAAS,QAAO,gBAAgB,WAAW,YAAY,GAAG;AAAA,WAC9D,SAAS,QAAS,QAAO,gBAAgB,WAAW,YAAY,GAAG;AAAA,MACvE,QAAO,cAAc,WAAW,YAAY,GAAG;AACpD,QAAM,QAAQ,MAAM,KAAK,eAAe,IAAI,CAAC;AAC7C,QAAM,UAAU;AAChB,SAAO;AACT;;;ACvIO,SAAS,iBACd,OACkD;AAClD,SAAO,SAAS,aAAa,OAAO,QAAQ;AAC1C,UAAM,MAAM,MAAM;AAClB,UAAM,QAAQ,MAAM;AACpB,UAAM,MAAM,MAAM;AAElB,QAAI,UAAU;AACd,QAAI;AAGJ,QACE,IAAI,WAAW,KAAK,MAAM,MAC1B,IAAI,WAAW,QAAQ,CAAC,MAAM,MAC9B,IAAI,WAAW,QAAQ,CAAC,MAAM,IAC9B;AACA,UAAI,UAAU,iBAAkB,QAAO;AACvC,gBAAU;AAAA,IACZ,WACE,IAAI,WAAW,KAAK,MAAM,MAC1B,IAAI,WAAW,QAAQ,CAAC,MAAM,IAC9B;AACA,UAAI,UAAU,cAAe,QAAO;AAAA,IACtC,OAAO;AACL,aAAO;AAAA,IACT;AAEA,UAAM,aAAa,SAAS,UAAU,IAAI;AAC1C,UAAM,WAAW,IAAI,QAAQ,MAAM,UAAU;AAC7C,QAAI,WAAW,KAAK,YAAY,IAAK,QAAO;AAE5C,YAAQ,IAAI,MAAM,YAAY,QAAQ;AACtC,QAAI,MAAM,SAAS,IAAI,EAAG,QAAO;AACjC,QAAI,CAAC,MAAM,KAAK,EAAG,QAAO;AAG1B,QAAI,OAAQ,QAAO;AAGnB,UAAM,MAAM,MAAM;AAClB,QAAI,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC,IAAI,SAAS;AAEtC,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,WAAW;AAEvB,UAAM,QAAQ,MAAM,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAClD,UAAM,YAAY,MAAM,CAAC;AACzB,UAAM,aAAa,MAAM,MAAM,CAAC;AAEhC,QAAI,SAAS;AAEX,YAAM,MAAM,WAAW,SAAS;AAChC,YAAM,UACJ,OAAO,IAAI,QAAQ,OAAO,aAAa,SAAS,IAAI,YAAY,CAAC;AACnE,UAAI,SAAS;AACX,eAAO,iBAAiB,OAAO,WAAW,YAAY,GAAG;AAAA,MAC3D;AACA,YAAM,YAAY,MAAM,iBAAiB,GAAG,IAAI;AAChD,UAAI,WAAW;AACb,eAAO,iBAAiB,OAAO,WAAW,WAAW,YAAY,GAAG;AAAA,MACtE;AACA,aAAO,mBAAmB,OAAO,WAAW,YAAY,GAAG;AAAA,IAC7D;AAGA,WAAO,aAAa,OAAO,WAAW,YAAY,GAAG;AAAA,EACvD;AACF;AAKA,SAAS,WAAW,QAAwB;AAE1C,QAAM,UAAU,OAAO,MAAM,GAAG,EAAE,CAAC;AACnC,QAAM,MAAM,QAAQ,YAAY,GAAG;AACnC,MAAI,OAAO,EAAG,QAAO;AACrB,SAAO,QAAQ,MAAM,MAAM,CAAC,EAAE,YAAY;AAC5C;AAKA,SAAS,aACP,OACA,WACA,YACA,KACS;AACT,QAAM,EAAE,OAAO,QAAQ,IAAI;AAC3B,QAAM,YAAY,WAAW,SAAS,IAAI,WAAW,KAAK,GAAG,EAAE,KAAK,IAAI;AACxE,QAAM,YAAY,QAAQ,UAAU,sBAAsB,SAAS;AACnE,QAAM,SAAS,gBAAgB,WAAW,OAAO,SAAS,QAAQ,IAAI,WAAW;AAEjF,QAAM,QAAQ,YACV,QAAQ,UAAU,qBAAqB,SAAS,IAChD,OAAO;AAGX,mBAAiB,KAAK,OAAO,QAAQ,cAAc,KAAK;AAExD,MAAI,OAAO,QAAQ;AACjB,mBAAe,KAAK,SAAS;AAC7B,WAAO,eAAe,OAAO,OAAO,KAAK,OAAO,WAAW,GAAG;AAAA,EAChE;AACA,SAAO,eAAe,OAAO,QAAQ,OAAO,GAAG;AACjD;AAGA,SAAS,iBACP,KACA,YACA,SACM;AACN,MAAI,CAAC,cAAc,CAAC,IAAI,YAAa;AACrC,QAAM,MAAM,IAAI,MAAM,UAAU,IAAI,UAAU,KAAK,CAAC;AACpD,MAAI,KAAK;AAAA,IACP,UAAU,IAAI;AAAA,IACd,SAAS,IAAI,MAAM,MAAM,IAAI,IAAI,WAAW,GAAG,OAAO;AAAA,IACtD,SAAS;AAAA,IACT;AAAA,IACA,MAAM;AAAA,EACR,CAAC;AACD,MAAI,MAAM,UAAU,IAAI,YAAY,GAAG;AACzC;AAGA,SAAS,eAAe,KAAoB,WAAyB;AACnE,QAAM,EAAE,QAAQ,IAAI;AACpB,QAAM,MAAM,wCAA8B,SAAS,KACjD,IAAI,cAAc,QAAQ,IAAI,WAAW,MAAM,EACjD;AACA,MAAI,QAAQ,aAAa,SAAU;AACnC,MAAI,QAAQ,aAAa,QAAQ;AAC/B,YAAQ,KAAK,GAAG;AAChB;AAAA,EACF;AAEA,MAAI,MAAM,SAAS,KAAK;AAAA,IACtB,MAAM;AAAA,IACN,SAAS;AAAA,IACT,UAAU,IAAI,cAAc,CAAC,IAAI,WAAW,IAAI,CAAC;AAAA,EACnD,CAAC;AACH;;;ACnKO,SAAS,kBACd,IACA,OACM;AACN,KAAG,OAAO,MAAM;AAAA,IACd;AAAA,IACA;AAAA,IACA,iBAAiB,KAAK;AAAA,EACxB;AACF;;;ACKA,IAAM,UAAU;AAET,SAAS,uBAAuB,IAAsB;AAC3D,KAAG,MAAM,MAAM;AAAA,IACb;AAAA,IACA;AAAA,IACA,SAAS,EAAE;AAAA,IACX,EAAE,KAAK,CAAC,WAAW,EAAE;AAAA,EACvB;AACF;AAEA,SAAS,SAAS,IAAgB;AAChC,SAAO,SAAS,eACd,OACA,WACA,UACA,QACS;AACT,UAAM,QAAQ,MAAM,OAAO,SAAS,IAAK,MAAM,OAAO,SAAS;AAC/D,UAAM,MAAM,MAAM,OAAO,SAAS;AAClC,UAAM,WAAW,MAAM,IAAI,MAAM,OAAO,GAAG;AAE3C,UAAM,IAAI,SAAS,MAAM,OAAO;AAChC,QAAI,CAAC,EAAG,QAAO;AACf,QAAI,OAAQ,QAAO;AAEnB,UAAM,MAAM,MAAM;AAClB,QAAI,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC,IAAI,QAAS,QAAO;AAE/C,UAAM,QAAQ,EAAE,CAAC;AACjB,UAAM,QAAQ,MAAM,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAClD,UAAM,YAAY,MAAM,CAAC;AACzB,UAAM,aAAa,MAAM,MAAM,CAAC;AAEhC,UAAM,MAAMC,YAAW,SAAS;AAChC,UAAM,UACJ,CAAC,CAAC,OAAO,IAAI,QAAQ,OAAO,aAAa,SAAS,IAAI,YAAY,CAAC;AACrE,UAAM,YAAY,MAAM,iBAAiB,GAAG,IAAI;AAEhD,QAAI;AACJ,QAAI,SAAS;AACX,aAAO,gBAAgB,WAAW,YAAY,GAAG;AAAA,IACnD,WAAW,cAAc,SAAS;AAChC,aAAO,gBAAgB,WAAW,YAAY,GAAG;AAAA,IACnD,WAAW,cAAc,SAAS;AAChC,aAAO,gBAAgB,WAAW,YAAY,GAAG;AAAA,IACnD,WAAW,cAAc,OAAO;AAC9B,aAAO,cAAc,WAAW,YAAY,GAAG;AAAA,IACjD,OAAO;AACL,aAAO,uBAAuB,IAAI,WAAW,YAAY,GAAG;AAAA,IAC9D;AAEA,UAAM,QAAQ,MAAM,KAAK,cAAc,IAAI,CAAC;AAC5C,UAAM,UAAU,OAAO;AACvB,UAAM,MAAM,CAAC,WAAW,YAAY,CAAC;AAErC,UAAM,OAAO,YAAY;AACzB,WAAO;AAAA,EACT;AACF;AAEA,SAASA,YAAW,QAAwB;AAC1C,QAAM,UAAU,OAAO,MAAM,GAAG,EAAE,CAAC;AACnC,QAAM,MAAM,QAAQ,YAAY,GAAG;AACnC,MAAI,OAAO,EAAG,QAAO;AACrB,SAAO,QAAQ,MAAM,MAAM,CAAC,EAAE,YAAY;AAC5C;;;ACzEO,SAAS,mBAAmB,IAAsB;AACvD,KAAG,OAAO,MAAM;AAAA,IACd;AAAA,IACA;AAAA,IACA,iBAAiB,aAAa;AAAA,EAChC;AACA,yBAAuB,EAAE;AAC3B;;;ACpBO,IAAM,gBAAgB;AAAA;AAAA,EAE3B,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,SAAS;AAAA,EACT,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,SAAS;AAAA,EACT,OAAO;AAAA,EACP,UAAU;AAAA,EACV,MAAM;AAAA;AAAA,EAGN,MAAM;AAAA,EACN,WAAW;AAAA,EACX,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,SAAS;AAAA,EACT,WAAW;AAAA,EACX,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,EACP,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AACR;AASO,SAAS,qBAAqB,KAA+B;AAClE,QAAM,MAAM,IAAI,KAAK,EAAE,YAAY;AACnC,QAAM,SAAU,cAAyC,GAAG;AAC5D,SAAQ,UAAU;AACpB;AAcO,IAAM,iBAAmD;AAAA,EAC9D,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,SAAS;AAAA,EACT,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,SAAS;AAAA,EACT,OAAO;AAAA,EACP,UAAU;AAAA,EACV,MAAM;AACR;AAGO,IAAM,gBAAkD;AAAA,EAC7D,MACE;AAAA,EACF,MACE;AAAA,EACF,KACE;AAAA,EACF,SACE;AAAA,EACF,UACE;AAAA,EACF,SACE;AAAA,EACF,SACE;AAAA,EACF,QACE;AAAA,EACF,KACE;AAAA,EACF,SACE;AAAA,EACF,OACE;AAAA,EACF,UACE;AAAA,EACF,MACE;AACJ;;;AC7EA,IAAM,YAAY;AAKX,SAAS,mBAAmB,MAAoC;AACrE,QAAM,IAAI,UAAU,KAAK,KAAK,KAAK,CAAC;AACpC,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,OAAO,qBAAqB,EAAE,CAAC,CAAE;AACvC,QAAM,WAAW,EAAE,CAAC;AACpB,QAAM,WACJ,aAAa,MAAM,SAAS,aAAa,MAAM,WAAW;AAC5D,SAAO,EAAE,MAAM,UAAU,QAAQ,EAAE,CAAC,KAAK,IAAI,KAAK,EAAE;AACtD;AAaO,SAAS,qBAAqB,IAAsB;AACzD,KAAG,KAAK,MAAM;AAAA,IACZ;AAAA,IACA;AAAA,IACA,SAAS,aAAa,OAA2B;AAC/C,YAAM,SAAS,MAAM;AAErB,eAAS,IAAI,OAAO,SAAS,GAAG,KAAK,GAAG,KAAK;AAC3C,cAAM,IAAI,OAAO,CAAC;AAClB,YAAI,EAAE,SAAS,kBAAmB;AAElC,cAAM,WAAW,kBAAkB,QAAQ,CAAC;AAC5C,YAAI,WAAW,EAAG;AAElB,cAAM,QAAQ,OAAO,MAAM,IAAI,GAAG,QAAQ;AAC1C,cAAM,SAAS,cAAc,KAAK;AAClC,YAAI,CAAC,OAAQ;AAEb,cAAM,WAAW,WAAW,OAAO,OAAO,eAAe,IAAI,MAAM,GAAG;AACtE,cAAM,OAAO,cAAc,OAAO,QAAQ,QAAQ;AAElD,cAAM,WAAW,IAAI,MAAM,MAAM,cAAc,IAAI,CAAC;AACpD,iBAAS,UAAU,OAAO;AAC1B,iBAAS,MAAM,EAAE;AACjB,eAAO,OAAO,GAAG,WAAW,IAAI,GAAG,QAAQ;AAAA,MAC7C;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAGA,SAAS,kBAAkB,QAAiB,SAAyB;AACnE,MAAI,QAAQ;AACZ,WAAS,IAAI,SAAS,IAAI,OAAO,QAAQ,KAAK;AAC5C,UAAM,IAAI,OAAO,CAAC;AAClB,QAAI,EAAE,SAAS,kBAAmB;AAAA,aACzB,EAAE,SAAS,oBAAoB;AACtC;AACA,UAAI,UAAU,EAAG,QAAO;AAAA,IAC1B;AAAA,EACF;AACA,SAAO;AACT;AAYA,SAAS,cAAc,OAAwC;AAE7D,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,QAAQ,MAAM,CAAC;AACrB,MAAI,MAAM,SAAS,iBAAkB,QAAO;AAC5C,QAAM,cAAc,MAAM,CAAC;AAC3B,MAAI,CAAC,eAAe,YAAY,SAAS,SAAU,QAAO;AAE1D,QAAM,UAAU,YAAY;AAE5B,QAAM,aAAa,QAAQ,QAAQ,IAAI;AACvC,QAAM,YAAY,cAAc,IAAI,QAAQ,MAAM,GAAG,UAAU,IAAI;AACnE,QAAM,OAAO,cAAc,IAAI,QAAQ,MAAM,aAAa,CAAC,IAAI;AAE/D,QAAM,SAAS,mBAAmB,SAAS;AAC3C,MAAI,CAAC,OAAQ,QAAO;AAEpB,SAAO,EAAE,QAAQ,eAAe,KAAK;AACvC;AAKA,SAAS,WACP,OACA,eACA,IACA,KACQ;AAMR,MAAI,MAAM,SAAS,GAAG;AAEpB,WAAO;AAAA,EACT;AAGA,QAAM,SAAkB,MAAM,IAAI,CAAC,MAAM;AACvC,UAAM,IAAI,IAAK,EAAE,YAIL,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;AACpC,WAAO,OAAO,GAAG,CAAC;AAElB,QAAI,EAAE,SAAU,GAAE,WAAW,CAAC,GAAG,EAAE,QAAQ;AAC3C,WAAO;AAAA,EACT,CAAC;AAID,MAAI,cAAc,KAAK,MAAM,IAAI;AAC/B,WAAO,OAAO,GAAG,CAAC;AAAA,EACpB,OAAO;AACL,UAAM,cAAc,OAAO,CAAC;AAC5B,gBAAY,UAAU;AAGtB,UAAM,cAAuB,CAAC;AAC9B,gBAAY,WAAW;AACvB,OAAG,OAAO,MAAM,eAAe,IAAI,KAAe,WAAW;AAAA,EAC/D;AAEA,SAAO,GAAG,SAAS,OAAO,QAAQ,GAAG,SAAS,GAAG;AACnD;AAKA,SAAS,cAAc,QAAuB,UAA0B;AACtE,QAAM,EAAE,MAAM,UAAU,MAAM,IAAI;AAClC,QAAM,eAAe,SAAS,eAAe,IAAI;AACjD,QAAM,UACJ,wKAEA,cAAc,IAAI,IAClB;AAEF,QAAM,MAAM,oBAAoB,IAAI,MAAM,WAAW,uBAAuB;AAE5E,MAAI,UAAU;AACZ,UAAM,SAAS,aAAa;AAC5B,WACE,mBAAmB,GAAG,mBAAmB,IAAI,IAAI,SAAS,UAAU,EAAE,mCACpC,OAAO,oCAAoC,WAAW,YAAY,CAAC,iDACrE,QAAQ;AAAA,EAG5C;AAEA,SACE,eAAe,GAAG,mBAAmB,IAAI,gCACX,OAAO,oCAAoC,WAAW,YAAY,CAAC,6CACjE,QAAQ;AAG5C;;;ACnMO,SAAS,iBAAiB,IAAsB;AACrD,uBAAqB,EAAE;AACzB;;;ACCA,IAAM,KAAK;AAEX,SAAS,SAAS,OAAoB,QAA0B;AAC9D,MAAI,OAAQ,QAAO;AACnB,QAAM,QAAQ,MAAM;AACpB,QAAM,SAAS,MAAM,IAAI,WAAW,KAAK;AACzC,MAAI,WAAW,GAAI,QAAO;AAE1B,QAAM,UAAU,MAAM,WAAW,MAAM,KAAK,IAAI;AAChD,MAAI,MAAM,QAAQ;AAClB,QAAM,KAAK,OAAO,aAAa,MAAM;AAErC,MAAI,MAAM,EAAG,QAAO;AAGpB,MAAI;AACJ,MAAI,MAAM,GAAG;AACX,YAAQ,MAAM,KAAK,QAAQ,IAAI,CAAC;AAChC,UAAM,UAAU;AAChB,WAAO;AAAA,EACT;AAEA,WAAS,IAAI,GAAG,IAAI,KAAK,KAAK,GAAG;AAC/B,YAAQ,MAAM,KAAK,QAAQ,IAAI,CAAC;AAChC,UAAM,UAAU,KAAK;AAGrB,UAAM,SAAU,MAA+C;AAC/D,WAAO,KAAK;AAAA,MACV;AAAA,MACA,QAAQ;AAAA;AAAA,MACR,MAAM,IAAI;AAAA;AAAA,MACV,OAAO,MAAM,OAAO,SAAS;AAAA,MAC7B,KAAK;AAAA,MACL,MAAM,QAAQ;AAAA,MACd,OAAO,QAAQ;AAAA,IACjB,CAAC;AAAA,EACH;AAEA,QAAM,OAAO,QAAQ;AACrB,SAAO;AACT;AAQA,SAAS,YAAY,OAA0B;AAC7C,QAAM,aAAc,MACjB;AACH,QAAM,cAAwB,CAAC;AAC/B,QAAM,MAAM,WAAW;AAEvB,WAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,UAAM,aAAa,WAAW,CAAC;AAC/B,QAAI,WAAW,WAAW,GAAI;AAC9B,QAAI,WAAW,QAAQ,GAAI;AAE3B,UAAM,WAAW,WAAW,WAAW,GAAG;AAE1C,QAAI,QAAe,MAAM,OAAO,WAAW,KAAK;AAChD,UAAM,OAAO;AACb,UAAM,MAAM;AACZ,UAAM,UAAU;AAChB,UAAM,SAAS;AACf,UAAM,UAAU;AAEhB,YAAQ,MAAM,OAAO,SAAS,KAAK;AACnC,UAAM,OAAO;AACb,UAAM,MAAM;AACZ,UAAM,UAAU;AAChB,UAAM,SAAS;AACf,UAAM,UAAU;AAEhB,UAAM,OAAO,MAAM,OAAO,SAAS,QAAQ,CAAC;AAC5C,QAAI,QAAQ,KAAK,SAAS,UAAU,KAAK,YAAY,KAAK;AACxD,kBAAY,KAAK,SAAS,QAAQ,CAAC;AAAA,IACrC;AAAA,EACF;AAGA,SAAO,YAAY,SAAS,GAAG;AAC7B,UAAM,IAAI,YAAY,IAAI;AAC1B,QAAI,IAAI,IAAI;AACZ,WACE,IAAI,MAAM,OAAO,UACjB,MAAM,OAAO,CAAC,EAAG,SAAS,cAC1B;AACA,WAAK;AAAA,IACP;AACA,SAAK;AACL,QAAI,MAAM,GAAG;AACX,YAAM,MAAM,MAAM,OAAO,CAAC;AAC1B,YAAM,OAAO,CAAC,IAAI,MAAM,OAAO,CAAC;AAChC,YAAM,OAAO,CAAC,IAAI;AAAA,IACpB;AAAA,EACF;AACF;AAEO,SAAS,wBAAwB,IAAsB;AAI5D,MAAI;AAEF,OAAG,OAAO,MAAM,MAAM,eAAe,wBAAwB,QAAQ;AAAA,EACvE,QAAQ;AACN,OAAG,OAAO,MAAM,OAAO,YAAY,wBAAwB,QAAQ;AAAA,EACrE;AAEA,KAAG,OAAO,OAAO;AAAA,IACf;AAAA,IACA;AAAA,IACA,SAAS,qBAAqB,OAAO;AACnC,YAAM,cACJ,MACA;AACF,YAAM,OAAQ,MACX;AACH,UAAI,KAAM,aAAY,KAAK;AAC3B,UAAI,aAAa;AACf,mBAAW,KAAK,aAAa;AAC3B,cAAI,KAAK,EAAE,YAAY;AACrB,kBAAM,QAAQ;AAAA,cACZ,GAAG;AAAA,cACH,YAAY,EAAE;AAAA,YAChB;AACA,wBAAY,KAAK;AAAA,UACnB;AAAA,QACF;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;ACpJO,SAAS,kBAAkB,IAAsB;AACtD,0BAAwB,EAAE;AAC5B;;;ACeA,IAAM,MAAM;AAEL,SAAS,wBAGH;AACX,SAAO,SAAS,cAAc,OAAO,QAAiB;AACpD,UAAM,QAAQ,MAAM;AACpB,UAAM,MAAM,MAAM;AAClB,QAAI,QAAQ,IAAI,IAAK,QAAO;AAC5B,QAAI,MAAM,IAAI,WAAW,KAAK,MAAM,IAAK,QAAO;AAChD,QAAI,MAAM,IAAI,WAAW,QAAQ,CAAC,MAAM,IAAK,QAAO;AAGpD,QAAI,MAAM,QAAQ;AAClB,QAAI,QAAQ;AACZ,WAAO,MAAM,MAAM,GAAG;AACpB,UACE,MAAM,IAAI,WAAW,GAAG,MAAM,OAC9B,MAAM,IAAI,WAAW,MAAM,CAAC,MAAM,KAClC;AACA,gBAAQ;AACR;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAEA,QAAI,QAAQ,EAAG,QAAO;AACtB,QAAI,OAAQ,QAAO;AAGnB,UAAM,MAAM,QAAQ;AACpB,WAAO;AAAA,EACT;AACF;AAQO,SAAS,uBAKH;AACX,SAAO,SAAS,aAAa,OAAO,WAAW,SAAS,QAAiB;AACvE,UAAM,MAAM,MAAM,OAAO,SAAS,IAAK,MAAM,OAAO,SAAS;AAC7D,UAAM,MAAM,MAAM,OAAO,SAAS;AAElC,QAAI,MAAM,IAAI,IAAK,QAAO;AAC1B,QAAI,MAAM,IAAI,WAAW,GAAG,MAAM,IAAK,QAAO;AAC9C,QAAI,MAAM,IAAI,WAAW,MAAM,CAAC,MAAM,IAAK,QAAO;AAElD,UAAM,YAAY,MAAM;AACxB,UAAM,OAAO,MAAM,IAAI,MAAM,WAAW,GAAG;AAC3C,QAAI,KAAK,KAAK,MAAM,GAAI,QAAO;AAE/B,QAAI,OAAQ,QAAO;AAGnB,QAAI,OAAO,YAAY;AACvB,QAAI,SAAS;AACb,WAAO,OAAO,SAAS;AACrB,YAAM,OAAO,MAAM,OAAO,IAAI,IAAK,MAAM,OAAO,IAAI;AACpD,YAAM,OAAO,MAAM,OAAO,IAAI;AAC9B,UACE,OAAO,KAAK,QACZ,MAAM,IAAI,WAAW,IAAI,MAAM,OAC/B,MAAM,IAAI,WAAW,OAAO,CAAC,MAAM,OACnC,MAAM,IAAI,MAAM,OAAO,GAAG,IAAI,EAAE,KAAK,MAAM,IAC3C;AACA,iBAAS;AACT;AAAA,MACF;AACA,cAAQ;AAAA,IACV;AAGA,UAAM,WAAW,SAAS,OAAO,IAAI;AACrC,UAAM,OAAO;AACb,WAAO;AAAA,EACT;AACF;AAEO,SAAS,uBAAuB,IAAsB;AAG3D,KAAG,OAAO,MAAM;AAAA,IACd;AAAA,IACA;AAAA,IACA,sBAAsB;AAAA,EACxB;AACF;AAEO,SAAS,sBAAsB,IAAsB;AAC1D,KAAG,MAAM,MAAM;AAAA,IACb;AAAA,IACA;AAAA,IACA,qBAAqB;AAAA,IACrB,EAAE,KAAK,CAAC,EAAE;AAAA,EACZ;AACF;;;ACtHO,SAAS,iBAAiB,IAAsB;AACrD,wBAAsB,EAAE;AACxB,yBAAuB,EAAE;AAC3B;;;ACkBA,IAAM,SAAS;AAEf,IAAM,SAAS;AAIf,SAAS,aACP,OACA,WACA,SACA,QACS;AACT,QAAM,QAAQ,MAAM,OAAO,SAAS,IAAK,MAAM,OAAO,SAAS;AAC/D,QAAM,MAAM,MAAM,OAAO,SAAS;AAClC,QAAM,SAAS,MAAM,OAAO,SAAS;AACrC,MAAI,SAAS,EAAG,QAAO;AACvB,QAAM,OAAO,MAAM,IAAI,MAAM,OAAO,GAAG;AACvC,QAAM,IAAI,OAAO,KAAK,IAAI;AAC1B,MAAI,CAAC,EAAG,QAAO;AACf,MAAI,OAAQ,QAAO;AAEnB,QAAM,KAAK,EAAE,CAAC;AACd,QAAM,WAAW,EAAE,CAAC,KAAK,IAAI,KAAK;AAElC,QAAM,QAAQ,MAAM,KAAK,gBAAgB,IAAI,CAAC;AAC9C,QAAM,OAAO,EAAE,IAAI,QAAQ;AAC3B,QAAM,MAAM,CAAC,WAAW,YAAY,CAAC;AACrC,QAAM,SAAS;AAEf,QAAM,OAAO,YAAY;AAEzB,OAAK;AACL,SAAO;AACT;AAIA,SAAS,cAAc,OAAoB,QAA0B;AACnE,QAAM,QAAQ,MAAM;AACpB,MAAI,MAAM,IAAI,WAAW,KAAK,MAAM,GAAc,QAAO;AACzD,MAAI,MAAM,IAAI,WAAW,QAAQ,CAAC,MAAM,GAAc,QAAO;AAC7D,QAAM,QAAQ,MAAM,IAAI,MAAM,KAAK;AACnC,QAAM,IAAI,OAAO,KAAK,KAAK;AAC3B,MAAI,CAAC,EAAG,QAAO;AACf,MAAI,OAAQ,QAAO;AAEnB,QAAM,KAAK,EAAE,CAAC;AACd,QAAM,QAAQ,MAAM,KAAK,gBAAgB,IAAI,CAAC;AAC9C,QAAM,OAAO,EAAE,GAAG;AAClB,QAAM,MAAM,QAAQ,EAAE,CAAC,EAAE;AACzB,SAAO;AACT;AAYA,SAAS,iBAAiB,OAA2B;AACnD,QAAM,SAAS,MAAM;AAErB,QAAM,OAAO,oBAAI,IAAuB;AAExC,MAAI,SAAS;AACb,MAAI,aAAa;AAGjB,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,IAAI,OAAO,CAAC;AAClB,QAAI,EAAE,SAAS,eAAgB;AAC/B,UAAM,OAAO,EAAE;AACf,QAAI,CAAC,KAAK,IAAI,KAAK,EAAE,GAAG;AACtB,WAAK,IAAI,KAAK,IAAI;AAAA,QAChB,IAAI,KAAK;AAAA,QACT,SAAS,KAAK;AAAA,QACd,QAAQ;AAAA;AAAA,QACR,YAAY,CAAC;AAAA,MACf,CAAC;AAAA,IACH;AAEA,MAAE,OAAO;AACT,MAAE,UAAU;AACZ,MAAE,SAAS;AAAA,EACb;AAGA,aAAW,KAAK,QAAQ;AACtB,QAAI,EAAE,SAAS,YAAY,CAAC,EAAE,SAAU;AACxC,aAAS,IAAI,GAAG,IAAI,EAAE,SAAS,QAAQ,KAAK;AAC1C,YAAM,IAAI,EAAE,SAAS,CAAC;AACtB,UAAI,EAAE,SAAS,eAAgB;AAC/B,YAAM,OAAO,EAAE;AACf,YAAM,MAAM,KAAK,IAAI,KAAK,EAAE;AAC5B,UAAI,CAAC,KAAK;AAER,UAAE,OAAO;AACT,UAAE,UAAU,KAAK,KAAK,EAAE;AACxB,UAAE,OAAO;AACT;AAAA,MACF;AACA,UAAI,IAAI,WAAW,GAAI,KAAI,SAAS;AACpC,YAAM,WAAW,SAAS,eAAe,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM;AAC5D,UAAI,WAAW,KAAK,QAAQ;AAE5B,QAAE,OAAO;AACT,QAAE,UACA,qCAAqC,QAAQ,kBAC7B,eAAe,IAAI,EAAE,CAAC,wBAClC,IAAI,MAAM;AAEhB,QAAE,OAAO;AAAA,IACX;AAAA,EACF;AAGA,QAAM,OAAO,MAAM,KAAK,KAAK,OAAO,CAAC,EAClC,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,EAC7B,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AAErC,MAAI,KAAK,WAAW,EAAG,QAAO;AAE9B,MAAI,OAAO;AACX,aAAW,OAAO,MAAM;AACtB,UAAM,kBAAkB,MAAM,GAAG,aAAa,IAAI,SAAS,MAAM,GAAG;AACpE,UAAM,YAAY,IAAI,WACnB;AAAA,MACC,CAAC,QAAQ,QACP,0CAA0C,MAAM,yDACO,IAAI,MAAM,IAAI,MAAM,CAAC;AAAA,IAKhF,EACC,KAAK,GAAG;AACX,YACE,cAAc,eAAe,IAAI,EAAE,CAAC,kEACE,eAAe,aACrD,YACA;AAAA,EACJ;AACA,UAAQ;AAER,QAAM,OAAO,IAAI,MAAM,MAAM,cAAc,IAAI,CAAC;AAChD,OAAK,UAAU,OAAO;AACtB,SAAO,KAAK,IAAI;AAEhB,SAAO;AACT;AAEA,SAAS,eAAe,GAAmB;AAEzC,SAAO,WAAW,CAAC;AACrB;AAIO,SAAS,kBAAkB,IAAsB;AACtD,KAAG,MAAM,MAAM,OAAO,aAAa,2BAA2B,cAAc;AAAA,IAC1E,KAAK,CAAC,aAAa,WAAW;AAAA,EAChC,CAAC;AACD,KAAG,OAAO,MAAM,MAAM,YAAY,2BAA2B,aAAa;AAC1E,KAAG,KAAK,MAAM,MAAM,UAAU,+BAA+B,gBAAgB;AAC/E;;;AC/KA,IAAM,mBAAmB;AAEzB,SAAS,cAAc,OAA2B;AAChD,QAAM,SAAS,MAAM;AACrB,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,IAAI,OAAO,CAAC;AAClB,QAAI,EAAE,SAAS,YAAY,CAAC,EAAE,YAAY,EAAE,SAAS,WAAW,EAAG;AAGnE,UAAM,UAAU,gBAAgB,EAAE,QAAQ;AAC1C,QAAI,UAAU,EAAG;AACjB,UAAM,WAAW,EAAE,SAAS,OAAO;AACnC,UAAM,IAAI,iBAAiB,KAAK,SAAS,OAAO;AAChD,QAAI,CAAC,EAAG;AAER,UAAM,KAAK,EAAE,CAAC;AAEd,UAAM,YAAY,SAAS,QAAQ,SAAS,EAAE,CAAC,EAAE;AACjD,aAAS,UAAU,SAAS,QAAQ,MAAM,GAAG,SAAS,EAAE,QAAQ,QAAQ,EAAE;AAG1E,MAAE,UAAU,EAAE,QAAQ,QAAQ,kBAAkB,EAAE,EAAE,QAAQ,QAAQ,EAAE;AAGtE,UAAM,SAAS,iBAAiB,QAAQ,CAAC;AACzC,QAAI,QAAQ;AACV,cAAQ,QAAQ,MAAM,IAAI,EAAE,EAAE;AAC9B,eAAS,QAAQ,kBAAkB;AAAA,IACrC;AAGA,QAAI,SAAS,YAAY,IAAI;AAC3B,QAAE,SAAS,OAAO,SAAS,CAAC;AAAA,IAC9B;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,UAA2B;AAClD,WAAS,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;AAC7C,QAAI,SAAS,CAAC,EAAG,SAAS,OAAQ,QAAO;AAAA,EAC3C;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,QAAiB,WAAiC;AAC1E,WAAS,IAAI,YAAY,GAAG,KAAK,GAAG,KAAK;AACvC,UAAM,IAAI,OAAO,CAAC;AAClB,QAAI,EAAE,YAAY,EAAG,QAAO;AAAA,EAC9B;AACA,SAAO;AACT;AAEA,SAAS,QAAQ,OAAc,MAAc,OAAqB;AAChE,QAAM,WAAW,MAAM,UAAU,IAAI;AACrC,MAAI,YAAY,GAAG;AACjB,UAAM,MAAO,QAAQ,EAAG,CAAC,IAAI;AAAA,EAC/B,OAAO;AACL,UAAM,SAAS,CAAC,MAAM,KAAK,CAAC;AAAA,EAC9B;AACF;AAEA,SAAS,SAAS,OAAc,KAAmB;AACjD,QAAM,MAAM,MAAM,UAAU,OAAO;AACnC,MAAI,OAAO,GAAG;AACZ,UAAM,MAAM,MAAM,MAAO,GAAG,EAAG,CAAC,KAAK;AACrC,QAAI,CAAC,IAAI,MAAM,KAAK,EAAE,SAAS,GAAG,GAAG;AACnC,YAAM,MAAO,GAAG,EAAG,CAAC,KAAK,MAAM,MAAM,KAAK,KAAK;AAAA,IACjD;AAAA,EACF,OAAO;AACL,UAAM,SAAS,CAAC,SAAS,GAAG,CAAC;AAAA,EAC/B;AACF;AAEO,SAAS,kBAAkB,IAAsB;AACtD,KAAG,KAAK,MAAM,MAAM,UAAU,yBAAyB,aAAa;AACtE;;;ACzDA,SAAS,qBACP,IACA,SACM;AACN,QAAM,WACJ,WAAW,WAAW,OAAO,IACzB,UACA,eAAe,OAAwC;AAE7D,QAAM;AAAA,IACJ,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,WAAW;AAAA,IACX,UAAU;AAAA,IACV,WAAW;AAAA,IACX,WAAW;AAAA,EACb,IAAI,SAAS;AAEb,MAAI,QAAQ,MAAM;AAChB,sBAAkB,IAAI,MAAM;AAC5B,2BAAuB,EAAE;AAAA,EAC3B,WAAW,MAAM;AACf,sBAAkB,IAAI,gBAAgB;AAAA,EAExC,WAAW,MAAM;AACf,uBAAmB,EAAE;AAAA,EACvB;AAGA,MAAI,MAAM;AACR,qBAAiB,EAAE;AAAA,EACrB;AAGA,MAAI,MAAM;AACR,sBAAkB,EAAE;AAAA,EACtB;AAGA,MAAI,MAAM;AACR,qBAAiB,EAAE;AAAA,EACrB;AAGA,MAAI,MAAM;AACR,sBAAkB,EAAE;AAAA,EACtB;AAGA,MAAI,MAAM;AACR,sBAAkB,EAAE;AAAA,EACtB;AACF;AAEA,SAAS,WACP,GACsB;AAEtB,SACE,OAAQ,EAAsB,YAAY,cAC1C,OAAQ,EAAsB,WAAW,YACzC,OAAQ,EAAsB,YAAY,YACzC,EAAsB,YAAY;AAEvC;AAEA,IAAO,sBAAQ;;;ACzFf,IAAAC,kBAAe;AACf,IAAAC,oBAAqB;;;ACTrB,IAAAC,kBAAe;AACf,IAAAC,oBAAqB;AAed,SAAS,oBACd,OACA,SACe;AACf,SAAO,CAAC,KAAK,KAAK,SAAS;AACzB,QAAI,CAAC,IAAI,IAAK,QAAO,KAAK;AAE1B,UAAM,YAAY,IAAI,IAAI,MAAM,GAAG,EAAE,CAAC,EAAG,MAAM,GAAG,EAAE,CAAC;AAGrD,QAAI,YAAY;AAChB,QAAI,QAAQ,SAAS,OAAO,UAAU,WAAW,QAAQ,IAAI,GAAG;AAC9D,kBAAY,MAAM,UAAU,MAAM,QAAQ,KAAK,MAAM;AAAA,IACvD;AAEA,QAAI;AACJ,QAAI;AACF,gBAAU,mBAAmB,SAAS;AAAA,IACxC,QAAQ;AACN,aAAO,KAAK;AAAA,IACd;AAGA,QAAI,CAAC,kBAAkB,KAAK,OAAO,EAAG,QAAO,KAAK;AAGlD,UAAM,eAAe,QAAQ,QAAQ,QAAQ,EAAE;AAC/C,QAAI,QACF,MAAM,qBAAqB,IAAI,YAAY;AAG7C,QAAI,CAAC,OAAO;AACV,YAAM,KAAK,SAAS,OAAO;AAC3B,YAAM,MAAM,QAAQ,gBAChB,MAAM,mBACN,MAAM;AACV,YAAM,MAAM,QAAQ,gBAAgB,KAAK,GAAG,YAAY;AACxD,YAAM,aAAa,IAAI,IAAI,GAAG;AAC9B,UAAI,cAAc,WAAW,SAAS,EAAG,SAAQ,WAAW,CAAC;AAAA,IAC/D;AAEA,QAAI,CAAC,MAAO,QAAO,KAAK;AAExB,QAAI;AACJ,QAAI;AACF,aAAO,gBAAAC,QAAG,SAAS,MAAM,YAAY;AAAA,IACvC,QAAQ;AACN,aAAO,KAAK;AAAA,IACd;AAEA,QAAI,aAAa;AACjB,QAAI,UAAU,gBAAgB,UAAU,MAAM,SAAS,CAAC;AACxD,QAAI,UAAU,kBAAkB,OAAO,KAAK,IAAI,CAAC;AACjD,QAAI,UAAU,iBAAiB,UAAU;AAEzC,oBAAAA,QAAG,iBAAiB,MAAM,YAAY,EACnC,GAAG,SAAS,MAAM,KAAK,CAAC,EACxB,KAAK,GAAG;AAAA,EACb;AACF;AAGA,IAAM,OAA+B;AAAA,EACnC,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,YAAY;AACd;AAEA,SAAS,UAAU,KAAqB;AACtC,SAAO,KAAK,IAAI,YAAY,CAAC,KAAK;AACpC;;;AC7GA,IAAAC,kBAAe;AACf,IAAAC,oBAAqB;AAGd,IAAM,gBACX;AAgBK,SAAS,qBACd,SACA,OACkB;AAClB,QAAM,SAA2B,EAAE,SAAS,CAAC,GAAG,SAAS,CAAC,EAAE;AAC5D,MAAI,CAAC,QAAQ,QAAQ,MAAO,QAAO;AAEnC,QAAM,SAAS,kBAAAC,QAAS,QAAQ,QAAQ,MAAM;AAC9C,QAAM,SAAS,QAAQ,MAAM;AAC7B,QAAM,UAAU,SAAS,kBAAAA,QAAS,KAAK,QAAQ,MAAM,IAAI;AAGzD,MAAI,QAAQ;AACV,QAAI;AACF,sBAAAC,QAAG,UAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAAA,IAC3C,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,QAAQ,cAAc,OAAO;AAEnC,aAAW,KAAK,OAAO;AACrB,UAAM,SAAS,kBAAAD,QAAS,KAAK,SAAS,EAAE,QAAQ;AAEhD,QAAI,gBAAAC,QAAG,WAAW,MAAM,GAAG;AACzB,UAAI;AACJ,UAAI;AACF,mBAAW,gBAAAA,QAAG,aAAa,QAAQ,MAAM;AAAA,MAC3C,QAAQ;AACN,eAAO,QAAQ,KAAK,EAAE,MAAM,QAAQ,QAAQ,8CAAW,CAAC;AACxD;AAAA,MACF;AACA,UAAI,CAAC,SAAS,SAAS,aAAa,GAAG;AACrC,eAAO,QAAQ,KAAK;AAAA,UAClB,MAAM;AAAA,UACN,QACE,4KAC+B,EAAE,IAAI,qCAA2B,EAAE,IAAI;AAAA,QAC1E,CAAC;AACD;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,sBAAAA,QAAG,cAAc,QAAQ,eAAe,CAAC,GAAG,MAAM;AAClD,aAAO,QAAQ,KAAK,MAAM;AAC1B,WAAK;AAAA,IACP,SAAS,KAAK;AACZ,aAAO,QAAQ,KAAK;AAAA,QAClB,MAAM;AAAA,QACN,QAAQ,6BAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACnE,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,cAAc,SAA0C;AAC/D,QAAM,EAAE,SAAS,OAAO,aAAa,cAAc,IAAI,QAAQ;AAC/D,QAAM,OAAuB,CAAC;AAC9B,MAAI,QAAQ,OAAO;AACjB,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,UAAU,GAAG,MAAM,KAAK;AAAA,MACxB,OAAO,YAAY;AAAA;AAAA,MAEnB,WAAW,2BAA2B,aAAa;AAAA,IACrD,CAAC;AAAA,EACH;AACA,MAAI,QAAQ,OAAO;AACjB,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,UAAU,GAAG,MAAM,KAAK;AAAA,MACxB,OAAO,YAAY;AAAA,MACnB,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,MAAI,QAAQ,MAAM;AAChB,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,UAAU,GAAG,MAAM,IAAI;AAAA,MACvB,OAAO,YAAY;AAAA,MACnB,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,SAAS,eAAe,GAAyB;AAI/C,SAAO;AAAA,IACL;AAAA,IACA,UAAU,EAAE,KAAK;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,KAAK,EAAE,KAAK;AAAA,IACZ;AAAA,IACA,EAAE;AAAA,IACF;AAAA,EACF,EAAE,KAAK,IAAI;AACb;;;ACjIA,IAAAC,kBAAe;AACf,IAAAC,oBAAqB;AAgDrB,IAAM,iBAAiB;AAGvB,IAAM,cAAc;AAGpB,IAAM,cACJ;AAEK,SAAS,eACd,OACA,SACW;AAGX,QAAM,cAAc,QAAQ,MAAM,YAC9B,QAAQ,MAAM,UAAU,QAAQ,cAAc,EAAE,IAAI,MACpD;AACJ,QAAM,gBAAgB,CAAC,MAA0B;AAC/C,QAAI,CAAC,YAAa,QAAO;AACzB,WAAO,EAAE,aAAa,WAAW,WAAW;AAAA,EAC9C;AACA,QAAM,YAAyB,CAAC;AAChC,aAAW,KAAK,MAAM,MAAM,OAAO,GAAG;AACpC,QAAI,CAAC,cAAc,CAAC,EAAG,WAAU,KAAK,CAAC;AAAA,EACzC;AAGA,QAAM,QAAyB,CAAC;AAChC,aAAW,KAAK,WAAW;AACzB,UAAM,KAAK;AAAA,MACT,IAAI,EAAE;AAAA,MACN,OAAO,UAAU,CAAC;AAAA,MAClB,KAAK,EAAE;AAAA,MACP,MAAM,CAAC,GAAG,EAAE,IAAI;AAAA,MAChB,OAAO,EAAE;AAAA,IACX,CAAC;AAAA,EACH;AAKA,QAAM,UAAU,oBAAI,IAA2B;AAC/C,aAAW,KAAK,WAAW;AACzB,UAAM,UAAU,EAAE,QAAQ,SAAS,WAAW;AAC9C,eAAW,KAAK,SAAS;AACvB,YAAM,UAAU,EAAE,CAAC,MAAM;AACzB,YAAM,YAAY,EAAE,CAAC,EAAG,KAAK;AAC7B,YAAM,SAAS,oBAAoB,WAAW,OAAO,OAAO;AAC5D,UAAI,CAAC,OAAQ;AACb,UAAI,cAAc,MAAM,EAAG;AAC3B,UAAI,OAAO,iBAAiB,EAAE,aAAc;AAC5C,YAAM,MAAM,GAAG,EAAE,YAAY,KAAI,OAAO,YAAY;AACpD,YAAM,WAAW,QAAQ,IAAI,GAAG;AAEhC,UAAI,YAAY,SAAS,SAAS,kBAAkB,CAAC,QAAS;AAC9D,cAAQ,IAAI,KAAK;AAAA,QACf,QAAQ,EAAE;AAAA,QACV,QAAQ,OAAO;AAAA,QACf,MAAM,UAAU,iBAAiB;AAAA,MACnC,CAAC;AAAA,IACH;AAAA,EACF;AACA,QAAM,QAAyB,CAAC,GAAG,QAAQ,OAAO,CAAC;AAGnD,QAAM,UAAU,oBAAI,IAAyB;AAC7C,aAAW,KAAK,WAAW;AACzB,UAAM,UAAU,IAAI,IAAI,EAAE,IAAI;AAC9B,QAAI,QAAQ,MAAM,iBAAiB;AACjC,iBAAW,MAAM,EAAE,QAAQ,SAAS,WAAW,GAAG;AAChD,gBAAQ,IAAI,GAAG,CAAC,CAAE;AAAA,MACpB;AAAA,IACF;AACA,eAAW,OAAO,SAAS;AACzB,YAAM,MAAM,QAAQ,IAAI,GAAG,KAAK,CAAC;AACjC,UAAI,KAAK,CAAC;AACV,cAAQ,IAAI,KAAK,GAAG;AAAA,IACtB;AAAA,EACF;AAEA,QAAM,gBAAgB,oBAAI,IAAsB;AAChD,aAAW,KAAK,WAAW;AACzB,UAAM,MAAM,IAAI,IAAI,EAAE,IAAI;AAC1B,QAAI,QAAQ,MAAM,iBAAiB;AACjC,iBAAW,MAAM,EAAE,QAAQ,SAAS,WAAW,EAAG,KAAI,IAAI,GAAG,CAAC,CAAE;AAAA,IAClE;AACA,kBAAc,IAAI,EAAE,cAAc,CAAC,GAAG,GAAG,CAAC;AAAA,EAC5C;AAEA,QAAM,OAAyC,CAAC;AAChD,aAAW,CAAC,KAAK,KAAK,KAAK,SAAS;AAElC,UAAM,SAAS,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAC1D,SAAK,GAAG,IAAI;AAAA,MACV,OAAO,MAAM;AAAA,MACb,OAAO,OAAO,IAAI,CAAC,OAAO;AAAA,QACxB,IAAI,EAAE;AAAA,QACN,KAAK,EAAE;AAAA,QACP,OAAO,UAAU,CAAC;AAAA,QAClB,OAAO,EAAE;AAAA,QACT,MAAM,EAAE;AAAA,QACR,YAAY,cAAc,IAAI,EAAE,YAAY,KAAK,CAAC,GAAG;AAAA,UACnD,CAAC,MAAM,MAAM;AAAA,QACf;AAAA,MACF,EAAE;AAAA,IACJ;AAAA,EACF;AAGA,QAAM,aAAa,CAAC,GAAG,SAAS,EAC7B,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAChC,MAAM,GAAG,EAAE,EACX,IAAI,CAAC,OAAO;AAAA,IACX,IAAI,EAAE;AAAA,IACN,KAAK,EAAE;AAAA,IACP,OAAO,UAAU,CAAC;AAAA,IAClB,OAAO,EAAE;AAAA,EACX,EAAE;AAEJ,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,MACL,YAAY,UAAU;AAAA,MACtB,aAAa,MAAM,OAAO;AAAA,MAC1B,gBAAgB,MAAM;AAAA,MACtB,WAAW,OAAO,KAAK,IAAI,EAAE;AAAA,MAC7B,eAAe,MAAM,SAAS;AAAA,MAC9B;AAAA,IACF;AAAA,IACA,MAAM,EAAE,aAAa,KAAK,IAAI,GAAG,eAAe,eAAe;AAAA,EACjE;AACF;AAEO,SAAS,eACd,OACA,SACiC;AACjC,QAAM,OAAO,eAAe,OAAO,OAAO;AAC1C,QAAM,OAAO,KAAK,UAAU,IAAI;AAChC,QAAM,YAAY,kBAAAC,QAAS,KAAK,kBAAAA,QAAS,QAAQ,QAAQ,MAAM,GAAG,QAAQ;AAC1E,kBAAAC,QAAG,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAC3C,QAAM,MAAM,kBAAAD,QAAS,KAAK,WAAW,QAAQ,MAAM,YAAY;AAC/D,kBAAAC,QAAG,cAAc,KAAK,MAAM,MAAM;AAClC,SAAO,EAAE,MAAM,KAAK,OAAO,KAAK,OAAO;AACzC;AAEA,SAAS,UAAU,GAAsB;AACvC,QAAM,KAAK,EAAE;AACb,MAAI,MAAM,OAAO,GAAG,UAAU,YAAY,GAAG,MAAM,KAAK,GAAG;AACzD,WAAO,GAAG,MAAM,KAAK;AAAA,EACvB;AACA,SAAO,EAAE;AACX;AAKA,SAAS,oBACP,WACA,OACA,SACuB;AACvB,QAAM,SAAS,iBAAiB,QAAQ,SAAS,CAAC;AAClD,MAAI,CAAC,OAAQ,QAAO;AAGpB,MAAI,OAAO,SAAS,GAAG,GAAG;AACxB,WACE,MAAM,eAAe,IAAI,MAAM,KAC/B,MAAM,eAAe,IAAI,SAAS,KAAK,KACvC,MAAM,eAAe,IAAI,SAAS,WAAW;AAAA,EAEjD;AAGA,QAAM,WAAW,QAAQ,gBAAgB,SAAS,OAAO,YAAY;AACrE,QAAM,UAAU,MAAM,QAAQ,IAAI,QAAQ;AAC1C,MAAI,QAAS,QAAO;AAGpB,QAAM,MAAM,QAAQ,gBAChB,MAAM,aACN,MAAM;AACV,QAAM,aAAa,IAAI;AAAA,IACrB,QAAQ,gBAAgB,SAAS,OAAO,YAAY;AAAA,EACtD;AACA,MAAI,CAAC,cAAc,WAAW,WAAW,EAAG,QAAO;AACnD,MAAI,WAAW,WAAW,EAAG,QAAO,WAAW,CAAC;AAGhD,SAAO,CAAC,GAAG,UAAU,EAAE;AAAA,IACrB,CAAC,GAAG,MACF,EAAE,aAAa,MAAM,GAAG,EAAE,SAAS,EAAE,aAAa,MAAM,GAAG,EAAE;AAAA,EACjE,EAAE,CAAC;AACL;;;AHrNA,SAAS,kBAAkB,IAAoB;AAC7C,SAAO,GAAG,MAAM,GAAG,EAAE,CAAC,EAAG,MAAM,GAAG,EAAE,CAAC;AACvC;AAEO,SAAS,eACd,cAAiC,CAAC,GACN;AAC5B,MAAI;AACJ,MAAI;AACJ,MAAI;AAEJ,QAAM,SAAqC;AAAA,IACzC,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,IAMN,OAAO,iBAAiB,SAAS;AAC/B,YAAM,YAAY,YAAY;AAC9B,UAAI,CAAC,UAAW,QAAO;AACvB,YAAM,MAAM,QAAQ,kBAAAC,QAAS,QAAQ,SAAS,CAAC;AAC/C,aAAO;AAAA,QACL,QAAQ;AAAA,UACN,IAAI;AAAA,YACF,OAAO,CAAC,GAAG;AAAA,UACb;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,eAAe,KAAK;AAClB,mBAAa;AACb,iBAAW,eAAe,aAAa;AAAA,QACrC,QAAQ,YAAY,UAAU,IAAI;AAAA,QAClC,MAAM,YAAY,QAAQ,IAAI;AAAA,QAC9B,WAAW,YAAY;AAAA,MACzB,CAAC;AACD,UAAI;AACF,gBAAQ,UAAU,QAAQ;AAG1B,YAAI,SAAS,QAAQ,OAAO;AAC1B,gBAAM,WAAW,qBAAqB,UAAU,KAAK;AACrD,qBAAW,WAAW,SAAS,SAAS;AACtC,gBAAI,OAAO,KAAK,mDAA+B,OAAO,EAAE;AAAA,UAC1D;AACA,qBAAW,WAAW,SAAS,SAAS;AACtC,gBAAI,OAAO;AAAA,cACT,uCAA6B,QAAQ,IAAI,KAAK,QAAQ,MAAM;AAAA,YAC9D;AAAA,UACF;AACA,cAAI,SAAS,QAAQ,SAAS,GAAG;AAC/B,oBAAQ,UAAU,QAAQ;AAAA,UAC5B;AACA,cAAI;AACF,kBAAM,aAAa,eAAe,OAAO,QAAQ;AACjD,gBAAI,OAAO;AAAA,cACT,iCAA4B,WAAW,IAAI,KAAK,WAAW,KAAK;AAAA,YAClE;AAAA,UACF,SAAS,KAAK;AACZ,gBAAI,OAAO;AAAA,cACT,oEACE,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CACjD;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAEA,YAAI,MAAM,SAAS,SAAS,GAAG;AAC7B,gBAAM,MAAM,MAAM,SAAS,MAAM,GAAG,EAAE;AACtC,qBAAW,KAAK,KAAK;AACnB,gBAAI,OAAO,KAAK,0BAA0B,EAAE,OAAO,EAAE;AAAA,UACvD;AACA,cAAI,MAAM,SAAS,SAAS,IAAI,QAAQ;AACtC,gBAAI,OAAO;AAAA,cACT,2CACE,MAAM,SAAS,SAAS,IAAI,MAC9B;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF,SAAS,KAAK;AACZ,YAAI,OAAO;AAAA,UACT,0DACE,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CACjD;AAAA,QACF;AACA,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,IAEA,gBAAgB,QAAQ;AACtB,UAAI,CAAC,MAAO;AACZ,YAAM,KAAK,oBAAoB,OAAO,QAAQ;AAC9C,aAAO,MAAM;AACX,eAAO,YAAY,IAAI,EAAE;AAAA,MAC3B;AAAA,IACF;AAAA,IAEA,gBAAgB,KAAK;AACnB,UAAI,CAAC,MAAO;AACZ,UAAI;AACF,cAAM,OAAO,gBAAAC,QAAG,SAAS,IAAI,IAAI;AACjC,YAAI,KAAK,OAAO,GAAG;AACjB,qBAAW,OAAO,IAAI,MAAM,QAAQ;AAAA,QACtC,WAAW,CAAC,gBAAAA,QAAG,WAAW,IAAI,IAAI,GAAG;AACnC,qBAAW,OAAO,IAAI,MAAM,QAAQ;AAAA,QACtC;AAAA,MACF,QAAQ;AACN,mBAAW,OAAO,IAAI,MAAM,QAAQ;AAAA,MACtC;AAEA,UAAI,SAAS,QAAQ,OAAO;AAC1B,YAAI;AACF,yBAAe,OAAO,QAAQ;AAAA,QAChC,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASA,UAAU,IAAI;AACZ,UAAI,CAAC,MAAO,QAAO;AACnB,YAAM,WAAW,kBAAkB,EAAE;AACrC,YAAM,KAAK;AACX,YAAM,QAAQ,SAAS,QAAQ,EAAE;AACjC,UAAI,QAAQ,EAAG,QAAO;AACtB,YAAM,UAAU,SAAS,MAAM,QAAQ,GAAG,MAAM;AAChD,UAAI;AACJ,UAAI;AACF,kBAAU,UAAU,OAAO;AAAA,MAC7B,QAAQ;AACN,eAAO;AAAA,MACT;AACA,YAAM,QAAQ,MAAM,qBAAqB,IAAI,OAAO;AACpD,UAAI,CAAC,MAAO,QAAO;AAGnB,YAAM,QAAQ,GAAG,MAAM,SAAS,MAAM;AACtC,aAAO,MAAM,eAAe;AAAA,IAC9B;AAAA;AAAA;AAAA;AAAA,IAKA,eAAe;AACb,aAAO;AAAA,IACT;AAAA,IACA,aAAa;AACX,aAAO;AAAA,IACT;AAAA,EACF;AAGA,OAAK;AAEL,SAAO;AACT;;;AItMA,IAAM,SAAS;AAEf,SAAS,qBAAqB,GAAgC;AAC5D,MAAI,MAAM,OAAW,QAAO;AAC5B,MAAI,KAAK,KAAK,CAAC,EAAG,QAAO;AACzB,MAAI,gBAAW,SAAS,CAAC,EAAG,QAAO;AACnC,SAAO;AACT;AAEO,SAAS,cAAgE;AAC9E,SAAO,SAAS,QAAQ,OAAO,QAAQ;AACrC,UAAM,QAAQ,MAAM;AACpB,UAAM,MAAM,MAAM;AAClB,QAAI,IAAI,WAAW,KAAK,MAAM,GAAc,QAAO;AAEnD,UAAM,OAAO,UAAU,IAAI,SAAY,IAAI,QAAQ,CAAC;AACpD,QAAI,CAAC,qBAAqB,IAAI,EAAG,QAAO;AAExC,UAAM,QAAQ,IAAI,MAAM,KAAK;AAC7B,UAAM,IAAI,OAAO,KAAK,KAAK;AAC3B,QAAI,CAAC,EAAG,QAAO;AAEf,UAAM,MAAM,EAAE,CAAC;AACf,QAAI,OAAQ,QAAO;AAEnB,UAAM,MAAM,MAAM;AAClB,QAAI,CAAC,IAAI,eAAgB,KAAI,iBAAiB,oBAAI,IAAI;AACtD,QAAI,eAAe,IAAI,GAAG;AAE1B,UAAM,eAAe,IAAI,SAAS,OAAO,OAAO,QAAQ;AACxD,UAAM,YAAY,IAAI,SAAS,OAAO,aAAa;AACnD,UAAM,OAAO,IAAI,SAAS,QAAQ;AAClC,UAAM,YAAY,YAAY,GAAG,SAAS,MAAM;AAChD,UAAM,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,YAAY,IAAI,mBAAmB,GAAG,CAAC;AAC1E,UAAM,OACJ,gCAAgC,WAAW,GAAG,CAAC,WACtC,WAAW,IAAI,CAAC,MAAM,WAAW,GAAG,CAAC;AAEhD,UAAM,QAAQ,MAAM,KAAK,eAAe,IAAI,CAAC;AAC7C,UAAM,UAAU;AAEhB,UAAM,MAAM,QAAQ,EAAE,CAAC,EAAE;AACzB,WAAO;AAAA,EACT;AACF;AAEO,SAAS,mBAAmB,IAAsB;AACvD,KAAG,OAAO,MAAM,OAAO,QAAQ,mBAAmB,YAAY,CAAC;AACjE;;;ACpCO,SAAS,mBACd,SACA,SACe;AACf,MAAI,CAAC,QAAQ,QAAQ,MAAO,QAAO;AACnC,QAAM,SAAS,QAAQ,MAAM;AAC7B,QAAM,QAAQ,gBAAgB,OAAO;AACrC,MAAI,CAAC,MAAO,QAAO;AAKnB,QAAM,cAAc,WAAW,aAAa,WAAW;AAEvD,MAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,QAAI,eAAe,CAAC,QAAQ,KAAK,CAAC,OAAO,GAAG,SAAS,MAAM,IAAI,GAAG;AAChE,cAAQ,KAAK,KAAK;AAAA,IACpB;AACA,WAAO;AAAA,EACT;AAEA,MAAI,WAAW,OAAO,YAAY,UAAU;AAC1C,QAAI,aAAa;AAEf,iBAAW,QAAQ,OAAO,KAAK,OAAO,GAAG;AACvC,cAAM,MAAM,QAAQ,IAAI;AACxB,YAAI,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,GAAG,SAAS,MAAM,IAAI,GAAG;AACnE,cAAI,KAAK,KAAK;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAGA,UAAM,SAAS,QAAQ,MAAM,YACzB,QAAQ,MAAM,UAAU,QAAQ,cAAc,EAAE,IAChD;AACJ,QAAI,QAAQ;AACV,YAAM,WAAW,IAAI,MAAM;AAC3B,UAAI,CAAC,QAAQ,QAAQ,GAAG;AACtB,gBAAQ,QAAQ,IAAI;AAAA,UAClB;AAAA,UACA;AAAA,UACA,QAAQ,KAAK,SAAS,GAAG,IAAI,QAAQ,OAAO,QAAQ,OAAO;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,SAAO,CAAC,KAAK;AACf;AASA,SAAS,iCACP,aACA,OACA,MACe;AAEf,QAAM,MAAqB,CAAC,EAAE,MAAM,QAAQ,MAAM,IAAI,CAAC;AACvD,QAAM,WAAW,OAAO,KAAK,WAAW,EAAE;AAAA,IACxC,CAAC,MAAM,MAAM,QAAQ,CAAC,EAAE,SAAS,kBAAkB;AAAA,EACrD;AACA,aAAW,KAAK,UAAU;AACxB,UAAM,MACJ,EAAE,QAAQ,YAAY,EAAE,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,IAAI,KAAK;AAChE,UAAM,OAAO,IAAI,OAAO,CAAC,EAAE,YAAY,IAAI,IAAI,MAAM,CAAC;AAEtD,UAAM,IAAI,KAAK,SAAS,GAAG,IAAI,OAAO,OAAO;AAC7C,UAAM,WAAW,MAAM,OAAO,EAAE,WAAW,CAAC,IAAI,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI;AAC1E,QAAI,KAAK,EAAE,MAAM,MAAM,SAAS,CAAC;AAAA,EACnC;AACA,MAAI,KAAK,KAAK;AACd,SAAO;AACT;AAEA,SAAS,gBAAgB,SAA8C;AACrE,QAAM,EAAE,SAAS,OAAO,aAAa,UAAU,IAAI,QAAQ;AAG3D,QAAM,YAAY,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,QAAuB,CAAC;AAC9B,MAAI,QAAQ,OAAO;AACjB,UAAM,KAAK,EAAE,MAAM,YAAY,OAAO,MAAM,GAAG,SAAS,IAAI,MAAM,KAAK,GAAG,CAAC;AAAA,EAC7E;AACA,MAAI,QAAQ,OAAO;AACjB,UAAM,KAAK,EAAE,MAAM,YAAY,OAAO,MAAM,GAAG,SAAS,IAAI,MAAM,KAAK,GAAG,CAAC;AAAA,EAC7E;AACA,MAAI,QAAQ,MAAM;AAChB,UAAM,KAAK,EAAE,MAAM,YAAY,MAAM,MAAM,GAAG,SAAS,IAAI,MAAM,IAAI,GAAG,CAAC;AAAA,EAC3E;AACA,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SAAO;AAAA,IACL,MAAM,YAAY;AAAA,IAClB,WAAW;AAAA,IACX;AAAA,EACF;AACF;AAkBO,SAAS,eACd,KACA,SACW;AACX,MAAI,CAAC,QAAQ,QAAQ,MAAO,QAAO;AACnC,QAAM,SAAS,QAAQ,MAAM;AAC7B,MAAI,WAAW,SAAS,WAAW,OAAQ,QAAO;AAElD,QAAM,QAAQ,gBAAgB,OAAO;AACrC,MAAI,CAAC,SAAS,CAAC,MAAM,SAAS,MAAM,MAAM,WAAW,EAAG,QAAO;AAE/D,QAAM,UAAmB;AAAA,IACvB,MAAM,MAAM;AAAA,IACZ,OAAO,MAAM,MAAM,IAAI,CAAC,QAAQ;AAAA,MAC9B,MAAM,GAAG;AAAA,MACT,MAAM,GAAG;AAAA,IACX,EAAE;AAAA,EACJ;AAEA,QAAM,MAAM,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;AAC7C,MAAI,CAAC,IAAI,KAAK,CAAC,OAAO,GAAG,SAAS,QAAQ,IAAI,GAAG;AAC/C,QAAI,KAAK,OAAO;AAAA,EAClB;AACA,SAAO;AACT;;;AC/HO,SAAS,sBAAsB,OAA2B;AAC/D,SAAO,MAAM,SAAS,YAAY,MAAM;AAC1C;AAMO,SAAS,qBACd,OACA,OACA,SACsB;AAEtB,QAAM,YAAa,MAAM,YAAsC;AAC/D,MAAI,MAAM,QAAQ,SAAS,GAAG;AAC5B,WAAO,eAAe,SAA0B;AAAA,EAClD;AAGA,QAAM,QAAQ,UAAU,MAAM,SAAS,OAAO,OAAO,OAAO;AAC5D,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SAAO;AACT;AAGA,SAAS,eAAe,OAAqC;AAC3D,SAAO,MAAM,IAAI,CAAC,OAAO;AACvB,UAAM,MAAmB,CAAC;AAC1B,QAAI,OAAO,GAAG,SAAS,SAAU,KAAI,OAAO,GAAG;AAC/C,QAAI,OAAO,GAAG,SAAS,SAAU,KAAI,OAAO,GAAG;AAC/C,QAAI,OAAO,GAAG,SAAS,SAAU,KAAI,OAAO,GAAG;AAC/C,QAAI,OAAO,GAAG,cAAc,UAAW,KAAI,YAAY,GAAG;AAC1D,QAAI,MAAM,QAAQ,GAAG,KAAK,EAAG,KAAI,QAAQ,eAAe,GAAG,KAAK;AAChE,WAAO;AAAA,EACT,CAAC;AACH;AAWA,IAAMC,WAAU;AAChB,IAAMC,eAAc;AACpB,IAAM,aAAa;AAEnB,SAAS,UACP,KACA,OACA,OACA,SACe;AACf,QAAM,QAAQ,IAAI,MAAM,OAAO;AAC/B,QAAM,SAAuB,CAAC;AAC9B,MAAI,UAAU;AACd,aAAW,OAAO,OAAO;AACvB,QAAI,YAAY,KAAK,IAAI,KAAK,CAAC,GAAG;AAChC,gBAAU,CAAC;AACX;AAAA,IACF;AACA,QAAI,QAAS;AACb,UAAM,IAAID,SAAQ,KAAK,GAAG;AAC1B,QAAI,CAAC,EAAG;AACR,UAAM,SAAS,EAAE,CAAC,EAAG,QAAQ,OAAO,IAAI,EAAE;AAC1C,UAAM,OAAO,EAAE,CAAC,EAAG,KAAK;AACxB,WAAO,KAAK,cAAc,QAAQ,MAAM,OAAO,OAAO,OAAO,CAAC;AAAA,EAChE;AACA,SAAO,UAAU,MAAM;AACzB;AAEA,SAAS,cACP,QACA,MACA,OACA,OACA,SACY;AAEZ,QAAM,KAAKC,aAAY,KAAK,IAAI;AAChC,MAAI,IAAI;AACN,UAAM,SAAS,GAAG,CAAC,EAAG,KAAK;AAC3B,UAAM,aAAa,GAAG,CAAC,GAAG,KAAK;AAC/B,UAAM,WAAW,cAAc,QAAQ,OAAO,SAAS,KAAK;AAC5D,WAAO;AAAA,MACL;AAAA,MACA,MAAM,cAAc,qBAAqB,QAAQ,QAAQ;AAAA,MACzD,MAAM,UAAU,OAAO;AAAA,IACzB;AAAA,EACF;AAEA,QAAM,KAAK,WAAW,KAAK,IAAI;AAC/B,MAAI,IAAI;AACN,WAAO,EAAE,QAAQ,MAAM,GAAG,CAAC,EAAG,KAAK,GAAG,MAAM,GAAG,CAAC,EAAG,KAAK,EAAE;AAAA,EAC5D;AAEA,MAAI,OAAO;AACX,MAAI;AACJ,MAAI,KAAK,SAAS,IAAI,GAAG;AACvB,gBAAY;AACZ,WAAO,KAAK,MAAM,GAAG,EAAE,EAAE,KAAK;AAAA,EAChC,WAAW,KAAK,SAAS,IAAI,GAAG;AAC9B,gBAAY;AACZ,WAAO,KAAK,MAAM,GAAG,EAAE,EAAE,KAAK;AAAA,EAChC;AACA,SAAO,EAAE,QAAQ,MAAM,MAAM,MAAM,UAAU;AAC/C;AAEA,SAAS,qBAAqB,QAAgB,OAAsC;AAClF,MAAI,OAAO;AACT,UAAM,KAAK,MAAM;AACjB,QAAI,OAAO,GAAG,iBAAiB,YAAY,GAAG,aAAa,KAAK,GAAG;AACjE,aAAO,GAAG,aAAa,KAAK;AAAA,IAC9B;AACA,QAAI,OAAO,GAAG,UAAU,YAAY,GAAG,MAAM,KAAK,GAAG;AACnD,aAAO,GAAG,MAAM,KAAK;AAAA,IACvB;AACA,WAAO,MAAM;AAAA,EACf;AACA,SAAO;AACT;AAEA,SAAS,cACP,KACA,OACA,SACA,cACuB;AACvB,QAAM,SAAS,iBAAiB,QAAQ,GAAG,CAAC;AAC5C,MAAI,CAAC,OAAQ,QAAO;AAEpB,MAAI,OAAO,SAAS,GAAG,GAAG;AAExB,UAAM,SAAS,aAAa,aAAa,MAAM,GAAG,EAAE,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG;AACzE,UAAM,aAAa;AAAA,MACjB;AAAA,MACA,SAAS;AAAA,MACT,SAAS,GAAG,MAAM,IAAI,MAAM,KAAK;AAAA,MACjC,SAAS,GAAG,MAAM,IAAI,MAAM,QAAQ;AAAA,IACtC,EAAE,OAAO,OAAO;AAChB,eAAW,KAAK,YAAY;AAC1B,YAAM,QAAQ,MAAM,eAAe,IAAI,CAAC;AACxC,UAAI,MAAO,QAAO;AAAA,IACpB;AAAA,EACF;AAEA,QAAM,WAAW,QAAQ,gBAAgB,SAAS,OAAO,YAAY;AACrE,QAAM,UAAU,MAAM,QAAQ,IAAI,QAAQ;AAC1C,MAAI,QAAS,QAAO;AAEpB,QAAM,MAAM,QAAQ,gBAAgB,MAAM,aAAa,MAAM;AAC7D,QAAM,MAAM,QAAQ,gBAAgB,SAAS,OAAO,YAAY;AAChE,QAAM,MAAM,IAAI,IAAI,GAAG;AACvB,MAAI,OAAO,IAAI,SAAS,EAAG,QAAO,IAAI,CAAC;AACvC,SAAO;AACT;AAGA,SAAS,UAAU,OAAoC;AACrD,MAAI,MAAM,WAAW,EAAG,QAAO,CAAC;AAEhC,QAAM,UAAU,CAAC,GAAG,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAC7E,QAAM,gBAAgB,oBAAI,IAAoB;AAC9C,UAAQ,QAAQ,CAAC,GAAG,QAAQ,cAAc,IAAI,GAAG,GAAG,CAAC;AAErD,QAAM,OAAsB,CAAC;AAE7B,QAAM,QAAwD;AAAA,IAC5D,EAAE,OAAO,IAAI,OAAO,KAAK;AAAA,EAC3B;AACA,aAAW,KAAK,OAAO;AACrB,UAAM,QAAQ,cAAc,IAAI,EAAE,MAAM,KAAK;AAC7C,WAAO,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,CAAC,EAAG,SAAS,OAAO;AAClE,YAAM,IAAI;AAAA,IACZ;AACA,UAAM,SAAS,MAAM,MAAM,SAAS,CAAC;AACrC,UAAM,OAAoB,CAAC;AAC3B,QAAI,EAAE,KAAM,MAAK,OAAO,EAAE;AAC1B,QAAI,EAAE,KAAM,MAAK,OAAO,EAAE;AAC1B,QAAI,EAAE,cAAc,OAAW,MAAK,YAAY,EAAE;AAClD,WAAO,MAAM,KAAK,IAAI;AAEtB,SAAK,QAAQ,CAAC;AACd,UAAM,KAAK,EAAE,OAAO,OAAO,KAAK,MAAM,CAAC;AAAA,EACzC;AAEA,kBAAgB,IAAI;AAEpB,SAAO;AACT;AAEA,SAAS,gBAAgB,KAA0B;AACjD,aAAW,MAAM,KAAK;AACpB,QAAI,GAAG,OAAO;AACZ,UAAI,GAAG,MAAM,WAAW,EAAG,QAAO,GAAG;AAAA,UAChC,iBAAgB,GAAG,KAAK;AAAA,IAC/B;AAAA,EACF;AACF;;;AC5MO,SAAS,0BACd,OAA2B,CAAC,GACA;AAC5B,QAAM,QAAQ,KAAK,sBAAsB;AACzC,SAAO;AAAA,IACL,MAAM,KAAK,QAAQ;AAAA,IACnB,SAAS,KAAK,WAAW,CAAC;AAAA,IAC1B,WAAW,KAAK,aAAa;AAAA,IAC7B,QAAQ,KAAK,UAAU;AAAA;AAAA,IAEvB,kBACE,KAAK,qBAAqB,CAAC,MAAc,SAAS,GAAG,KAAK;AAAA,IAC5D,iBACE,KAAK,oBAAoB,CAAC,MAAiB,iBAAiB,GAAG,KAAK;AAAA,IACtE,WAAW,KAAK,aAAa;AAAA,IAC7B,UAAU,KAAK,YAAY;AAAA,IAC3B,UAAU,KAAK,YAAY;AAAA,IAC3B,SAAS,KAAK,WAAW;AAAA,IACzB,aAAa,KAAK,eAAe;AAAA,IACjC,oBAAoB;AAAA,IACpB,YAAY,KAAK,cAAc,CAAC;AAAA,IAChC,UAAU,KAAK;AAAA,IACf,WAAW,KAAK,aAAa;AAAA,IAC7B,eAAe,KAAK;AAAA,IACpB,iBAAiB,KAAK,mBAAmB,CAAC;AAAA,EAC5C;AACF;AAGA,SAAS,iBAAiB,OAAkB,OAAwB;AAClE,QAAM,KAAK,MAAM;AACjB,QAAM,eAAe,OAAO,GAAG,iBAAiB,WAAW,GAAG,eAAe;AAC7E,MAAI,aAAa,KAAK,EAAG,QAAO,aAAa,KAAK;AAClD,QAAM,QAAQ,OAAO,GAAG,UAAU,WAAW,GAAG,QAAQ;AACxD,MAAI,MAAM,KAAK,EAAG,QAAO,MAAM,KAAK;AACpC,QAAM,UAAU,MAAM,SAAS,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC;AACxD,MAAI,QAAS,QAAO,QAAQ;AAC5B,SAAO,SAAS,MAAM,UAAU,KAAK;AACvC;AAGA,SAAS,SAAS,MAAc,OAAwB;AACtD,MAAI,IAAI;AACR,MAAI,MAAO,KAAI,EAAE,QAAQ,gBAAgB,EAAE;AAC3C,SAAO,EACJ,QAAQ,UAAU,GAAG,EACrB,QAAQ,QAAQ,GAAG,EACnB,KAAK,EACL,QAAQ,SAAS,CAAC,MAAM,EAAE,YAAY,CAAC;AAC5C;AAmBA,SAAS,QAAQ,MAAuB;AACtC,SAAO,EAAE,MAAM,OAAO,CAAC,GAAG,UAAU,oBAAI,IAAI,EAAE;AAChD;AAIO,SAAS,gBACd,OACA,SACA,cAAkC,CAAC,GACY;AAC/C,QAAM,OAAO,0BAA0B,WAAW;AAClD,QAAM,cAAc,QAAQ,MAAM,YAC9B,QAAQ,MAAM,UAAU,QAAQ,cAAc,EAAE,IAChD;AAGJ,QAAM,UAAuB,CAAC;AAC9B,aAAW,SAAS,MAAM,MAAM,OAAO,GAAG;AACxC,QAAI,cAAc,OAAO,MAAM,WAAW,EAAG;AAC7C,YAAQ,KAAK,KAAK;AAAA,EACpB;AAGA,QAAM,OAAOC,WAAU,OAAO;AAG9B,QAAM,SAAS,YAAY,UAAU;AACrC,MAAI;AACJ,MAAI,WAAW,cAAc;AAC3B,aAAS,mBAAmB,MAAM,MAAM,SAAS,KAAK;AAAA,EACxD,WAAW,WAAW,QAAQ;AAC5B,aAAS,cAAc,MAAM,IAAI;AAAA,EACnC,OAAO;AACL,aAAS,cAAc,MAAM,MAAM,OAAO,OAAO;AAAA,EACnD;AAKA,sBAAoB,QAAQ,QAAQ,IAAI;AACxC,SAAO;AACT;AAGA,SAAS,oBACP,KACA,MACM;AACN,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,uBAAmB,KAAK,IAAI;AAAA,EAC9B,OAAO;AACL,eAAW,KAAK,OAAO,KAAK,GAAG,GAAG;AAChC,yBAAmB,IAAI,CAAC,GAAI,IAAI;AAAA,IAClC;AAAA,EACF;AACF;AACA,SAAS,mBAAmB,OAAsB,MAAoB;AACpE,QAAM,IAAI,KAAK,SAAS,GAAG,IAAI,OAAO,OAAO;AAC7C,aAAW,MAAM,OAAO;AACtB,QAAI,GAAG,QAAQ,MAAM,OAAO,GAAG,KAAK,WAAW,CAAC,GAAG;AACjD,SAAG,OAAO,MAAM,GAAG,KAAK,MAAM,EAAE,MAAM;AAAA,IACxC;AACA,QAAI,GAAG,MAAO,oBAAmB,GAAG,OAAO,IAAI;AAAA,EACjD;AACF;AAIA,SAASA,WAAU,OAA6B;AAC9C,QAAM,OAAO,QAAQ,EAAE;AACvB,aAAW,KAAK,OAAO;AACrB,UAAM,OAAO,EAAE,aAAa,MAAM,GAAG;AACrC,UAAM,UAAU,KAAK,MAAM,GAAG,EAAE;AAChC,QAAI,OAAO;AACX,eAAW,OAAO,SAAS;AACzB,UAAI,QAAQ,KAAK,SAAS,IAAI,GAAG;AACjC,UAAI,CAAC,OAAO;AACV,gBAAQ,QAAQ,KAAK,OAAO,KAAK,OAAO,MAAM,MAAM,GAAG;AACvD,aAAK,SAAS,IAAI,KAAK,KAAK;AAAA,MAC9B;AACA,aAAO;AAAA,IACT;AAEA,QAAI,sBAAsB,CAAC,GAAG;AAC5B,WAAK,kBAAkB;AACvB;AAAA,IACF;AAEA,SAAK,MAAM,KAAK,CAAC;AAAA,EACnB;AACA,iBAAe,IAAI;AACnB,SAAO;AACT;AAgBA,SAAS,eAAe,MAAqB;AAC3C,QAAM,aAAa,KAAK,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK;AACjD,MAAI,YAAY;AACd,UAAM,WAAW,WAAW,YAAY;AACxC,QAAI,OAAsD;AAC1D,eAAW,KAAK,KAAK,OAAO;AAC1B,YAAM,OAAO,EAAE,SAAS,YAAY;AACpC,UAAI,IAAI;AACR,UAAI,SAAS,SAAU,KAAI;AAAA,eAClB,SAAS,QAAS,KAAI;AAAA,eACtB,SAAS,SAAU,KAAI;AAChC,UAAI,IAAI,MAAM,SAAS,QAAQ,IAAI,KAAK,WAAW;AACjD,eAAO,EAAE,OAAO,GAAG,UAAU,EAAE;AAAA,MACjC;AAAA,IACF;AACA,QAAI,MAAM;AACR,WAAK,WAAW,KAAK;AACrB,WAAK,gBAAgB,KAAK,MAAM,QAAQ,KAAK,MAAM;AACnD,WAAK,QAAQ,KAAK,MAAM,OAAO,CAAC,MAAM,MAAM,KAAM,KAAK;AAAA,IACzD;AAAA,EACF;AACA,aAAW,SAAS,KAAK,SAAS,OAAO,EAAG,gBAAe,KAAK;AAClE;AAIA,SAAS,cACP,MACA,MACA,OACA,SACe;AACf,SAAO;AAAA,IAAW;AAAA,IAAM;AAAA;AAAA,IAAkB;AAAA;AAAA,IAAgB;AAAA,IAAM;AAAA,IAAO;AAAA,EAAO;AAChF;AASA,SAAS,WACP,MACA,MACA,OACA,QACA,OACA,SACe;AAEf,MAAI,KAAK,aAAa,UAAa,QAAQ,KAAK,SAAU,QAAO,CAAC;AAGlE,MAAI,KAAK,iBAAiB;AACxB,UAAM,WAAW,qBAAqB,KAAK,iBAAiB,OAAO,OAAO;AAC1E,QAAI,SAAU,QAAO;AAAA,EACvB;AAEA,QAAM,MAAqB,CAAC;AAG5B,QAAM,gBAAgB,oBAAI,IAAyB;AACnD,QAAM,cAA2B,CAAC;AAClC,aAAW,KAAK,KAAK,OAAO;AAC1B,UAAM,IAAI,iBAAiB,CAAC;AAC5B,QAAI,GAAG;AACL,YAAM,MAAM,cAAc,IAAI,CAAC,KAAK,CAAC;AACrC,UAAI,KAAK,CAAC;AACV,oBAAc,IAAI,GAAG,GAAG;AAAA,IAC1B,OAAO;AACL,kBAAY,KAAK,CAAC;AAAA,IACpB;AAAA,EACF;AAGA,cAAY,KAAK,CAAC,GAAG,MAAM,eAAe,GAAG,GAAG,IAAI,CAAC;AACrD,aAAW,KAAK,aAAa;AAC3B,QAAI,KAAK,EAAE,MAAM,KAAK,gBAAgB,CAAC,GAAG,MAAM,EAAE,IAAI,CAAC;AAAA,EACzD;AAGA,QAAM,cAAc,CAAC,GAAG,cAAc,KAAK,CAAC,EAAE,KAAK;AACnD,aAAW,QAAQ,aAAa;AAC9B,UAAM,QAAQ,cAAc,IAAI,IAAI,EAAG,KAAK,CAAC,GAAG,MAAM,eAAe,GAAG,GAAG,IAAI,CAAC;AAChF,QAAI,KAAK;AAAA,MACP,MAAM;AAAA,MACN,WAAW,KAAK;AAAA,MAChB,OAAO,MAAM,IAAI,CAAC,OAAO,EAAE,MAAM,KAAK,gBAAgB,CAAC,GAAG,MAAM,EAAE,IAAI,EAAE;AAAA,IAC1E,CAAC;AAAA,EACH;AAGA,QAAM,YAAY,cAAc,MAAM,MAAM,MAAM;AAClD,aAAW,OAAO,WAAW;AAC3B,UAAM,QAAQ,KAAK,SAAS,IAAI,GAAG;AACnC,UAAM,aAAa,WAAW,OAAO,MAAM,QAAQ,GAAG,OAAO,OAAO,OAAO;AAC3E,QAAI,WAAW,WAAW,KAAK,CAAC,MAAM,SAAU;AAEhD,UAAM,QAAqB;AAAA,MACzB,MAAM,iBAAiB,MAAM,MAAM,MAAM,UAAU,IAAI;AAAA,MACvD,WAAW,sBAAsB,MAAM,UAAU,IAAI;AAAA,MACrD,OAAO;AAAA,IACT;AACA,QACE,MAAM,YACN,CAAC,MAAM,iBACP,gBAAgB,MAAM,MAAM,GAC5B;AACA,YAAM,OAAO,MAAM,SAAS;AAAA,IAC9B;AACA,QAAI,KAAK,KAAK;AAAA,EAChB;AAEA,SAAO;AACT;AAMA,SAAS,iBACP,MACA,MACe;AACf,MAAI,KAAK,YAAY,CAAC,KAAK,cAAe,QAAO,KAAK,SAAS;AAC/D,MAAI,KAAK,MAAM,SAAS,GAAG;AACzB,UAAM,SAAS,CAAC,GAAG,KAAK,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,eAAe,GAAG,GAAG,IAAI,CAAC;AACxE,WAAO,OAAO,CAAC,EAAG;AAAA,EACpB;AACA,QAAM,YAAY,CAAC,GAAG,KAAK,SAAS,KAAK,CAAC,EAAE,KAAK;AACjD,aAAW,KAAK,WAAW;AACzB,UAAM,IAAI,iBAAiB,KAAK,SAAS,IAAI,CAAC,GAAI,IAAI;AACtD,QAAI,EAAG,QAAO;AAAA,EAChB;AACA,SAAO;AACT;AAGA,SAAS,gBAAgB,MAAkC,YAA8B;AACvF,MAAI,KAAK,cAAc,MAAO,QAAO;AACrC,MAAI,KAAK,cAAc,YAAa,QAAO;AAC3C,SAAO;AACT;AAGA,SAAS,cACP,MACA,MACA,YACU;AACV,QAAM,OAAO,CAAC,GAAG,KAAK,SAAS,KAAK,CAAC;AACrC,MAAI,CAAC,cAAc,KAAK,WAAW,WAAW,GAAG;AAC/C,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,QAAM,WAAW,oBAAI,IAAoB;AACzC,OAAK,WAAW,QAAQ,CAAC,MAAM,MAAM;AAEnC,aAAS,IAAI,MAAM,CAAC;AACpB,aAAS,IAAI,KAAK,YAAY,GAAG,CAAC;AAAA,EACpC,CAAC;AACD,QAAM,UAAoB,CAAC;AAC3B,QAAM,OAAiB,CAAC;AACxB,aAAW,KAAK,MAAM;AACpB,UAAM,QAAQ;AAAA,MACZ,KAAK,SAAS,IAAI,CAAC,EAAG;AAAA,MACtB,KAAK,SAAS,IAAI,CAAC,EAAG;AAAA,MACtB;AAAA,IACF;AACA,QAAI,SAAS,IAAI,CAAC,KAAK,SAAS,IAAI,KAAK,GAAG;AAC1C,cAAQ,KAAK,CAAC;AAAA,IAChB,OAAO;AACL,WAAK,KAAK,CAAC;AAAA,IACb;AAAA,EACF;AACA,UAAQ,KAAK,CAAC,GAAG,MAAM;AACrB,UAAM,KAAK;AAAA,MACT,KAAK,SAAS,IAAI,CAAC,EAAG;AAAA,MACtB,KAAK,SAAS,IAAI,CAAC,EAAG;AAAA,MACtB;AAAA,IACF;AACA,UAAM,KAAK;AAAA,MACT,KAAK,SAAS,IAAI,CAAC,EAAG;AAAA,MACtB,KAAK,SAAS,IAAI,CAAC,EAAG;AAAA,MACtB;AAAA,IACF;AACA,UAAM,KAAK,SAAS,IAAI,CAAC,IAAI,SAAS,IAAI,CAAC,IAAK,SAAS,IAAI,EAAE;AAC/D,UAAM,KAAK,SAAS,IAAI,CAAC,IAAI,SAAS,IAAI,CAAC,IAAK,SAAS,IAAI,EAAE;AAC/D,WAAO,KAAK;AAAA,EACd,CAAC;AACD,OAAK,KAAK;AACV,SAAO,CAAC,GAAG,SAAS,GAAG,IAAI;AAC7B;AAIA,SAAS,cAAc,MAAe,MAAiD;AAErF,QAAM,MAAqB,CAAC;AAE5B,QAAM,YAAY,CAAC,GAAG,KAAK,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,eAAe,GAAG,GAAG,IAAI,CAAC;AAC3E,aAAW,KAAK,UAAW,KAAI,KAAK,EAAE,MAAM,KAAK,gBAAgB,CAAC,GAAG,MAAM,EAAE,IAAI,CAAC;AAElF,QAAM,UAAqB,CAAC;AAC5B,WAAS,MAAM,OAAO;AACtB,aAAW,KAAK,SAAS;AACvB,UAAM,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,eAAe,GAAG,GAAG,IAAI,CAAC;AACpE,UAAM,QAAQ,MAAM,IAAI,CAAC,OAAO,EAAE,MAAM,KAAK,gBAAgB,CAAC,GAAG,MAAM,EAAE,IAAI,EAAE;AAC/E,QAAI,MAAM,WAAW,KAAK,CAAC,EAAE,SAAU;AACvC,UAAM,QAAqB;AAAA,MACzB,MAAM,iBAAiB,EAAE,MAAM,EAAE,UAAU,IAAI;AAAA,MAC/C,WAAW,sBAAsB,EAAE,UAAU,IAAI;AAAA,MACjD;AAAA,IACF;AAEA,QAAI,EAAE,YAAY,CAAC,EAAE,iBAAiB,gBAAgB,MAAM,IAAI,GAAG;AACjE,YAAM,OAAO,EAAE,SAAS;AAAA,IAC1B;AACA,QAAI,KAAK,KAAK;AAAA,EAChB;AACA,SAAO;AACT;AAEA,SAAS,SAAS,MAAe,KAAsB;AACrD,QAAM,OAAO,CAAC,GAAG,KAAK,SAAS,KAAK,CAAC,EAAE,KAAK;AAC5C,aAAW,KAAK,MAAM;AACpB,UAAM,QAAQ,KAAK,SAAS,IAAI,CAAC;AACjC,QAAI,KAAK,KAAK;AACd,aAAS,OAAO,GAAG;AAAA,EACrB;AACF;AAIA,SAAS,mBACP,MACA,MACA,SACA,OAC+B;AAK/B,QAAM,MAAqC,CAAC;AAE5C,QAAM,YAA2B,CAAC;AAClC,QAAM,kBAAkB,CAAC,GAAG,KAAK,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,eAAe,GAAG,GAAG,IAAI,CAAC;AACjF,aAAW,KAAK,iBAAiB;AAC/B,cAAU,KAAK,EAAE,MAAM,KAAK,gBAAgB,CAAC,GAAG,MAAM,EAAE,IAAI,CAAC;AAAA,EAC/D;AACA,QAAM,UAAU,CAAC,GAAG,KAAK,SAAS,KAAK,CAAC,EAAE,KAAK;AAC/C,aAAW,OAAO,SAAS;AACzB,UAAM,QAAQ,KAAK,SAAS,IAAI,GAAG;AACnC,QAAI,MAAM,MAAM,WAAW,KAAK,MAAM,SAAS,SAAS,KAAK,CAAC,MAAM,UAAU;AAC5E;AAAA,IACF;AACA,UAAM,YAAY,iBAAiB,MAAM,MAAM,MAAM,UAAU,IAAI;AACnE,QAAI;AAAA,MAAgB;AAAA;AAAA,MAAuB;AAAA,IAAI,GAAG;AAChD,YAAM,WACJ,MAAM,YAAY,CAAC,MAAM,gBACrB,MAAM,SAAS,MACf,iBAAiB,OAAO,IAAI;AAElC,UAAI,UAAU;AACZ,kBAAU,KAAK,EAAE,MAAM,WAAW,MAAM,SAAS,CAAC;AAAA,MACpD,OAAO;AACL,kBAAU,KAAK,EAAE,MAAM,UAAU,CAAC;AAAA,MACpC;AAAA,IACF,OAAO;AACL,gBAAU,KAAK,EAAE,MAAM,UAAU,CAAC;AAAA,IACpC;AAAA,EACF;AACA,MAAI,UAAU,SAAS,EAAG,KAAI,GAAG,IAAI;AAErC,aAAW,OAAO,SAAS;AACzB,UAAM,QAAQ,KAAK,SAAS,IAAI,GAAG;AACnC,UAAM,QAAQ;AAAA,MAAW;AAAA,MAAO;AAAA;AAAA,MAAkB;AAAA;AAAA,MAAgB;AAAA,MAAO;AAAA,MAAO;AAAA,IAAO;AACvF,QAAI,MAAM,WAAW,KAAK,CAAC,MAAM,SAAU;AAE3C,UAAM,UAAyB,CAAC;AAChC,UAAM,UACJ,MAAM,YACN,CAAC,MAAM,iBACP;AAAA,MAAgB;AAAA;AAAA,MAAuB;AAAA,IAAI;AAC7C,QAAI,SAAS;AACX,cAAQ,KAAK;AAAA,QACX,MAAM,iBAAiB,MAAM,MAAM,MAAM,UAAU,IAAI;AAAA,QACvD,MAAM,MAAM,SAAU;AAAA,MACxB,CAAC;AAAA,IACH;AACA,YAAQ,KAAK,GAAG,KAAK;AAErB,QAAI,IAAI,GAAG,GAAG,IAAI;AAAA,EACpB;AACA,SAAO;AACT;AAIO,SAAS,YACd,OACA,SACA,cAAkC,CAAC,GACxB;AACX,QAAM,OAAO,0BAA0B,WAAW;AAClD,QAAM,cAAc,QAAQ,MAAM,YAC9B,QAAQ,MAAM,UAAU,QAAQ,cAAc,EAAE,IAChD;AAEJ,QAAM,UAAuB,CAAC;AAC9B,aAAW,SAAS,MAAM,MAAM,OAAO,GAAG;AACxC,QAAI,cAAc,OAAO,MAAM,WAAW,EAAG;AAC7C,YAAQ,KAAK,KAAK;AAAA,EACpB;AACA,QAAM,OAAOA,WAAU,OAAO;AAE9B,QAAM,OAAO,QAAQ,KAAK,SAAS,GAAG,IAAI,QAAQ,OAAO,QAAQ,OAAO;AAExE,QAAM,MAAiB,CAAC,EAAE,MAAM,KAAK,aAAa,MAAM,IAAI,CAAC;AAE7D,QAAM,UAAU,CAAC,GAAG,KAAK,SAAS,KAAK,CAAC,EAAE,KAAK;AAC/C,aAAW,OAAO,SAAS;AACzB,UAAM,QAAQ,KAAK,SAAS,IAAI,GAAG;AACnC,QAAI,MAAM,MAAM,WAAW,KAAK,MAAM,SAAS,SAAS,KAAK,CAAC,MAAM,UAAU;AAC5E;AAAA,IACF;AACA,UAAM,OAAO,iBAAiB,MAAM,MAAM,MAAM,UAAU,IAAI;AAM9D,QAAI;AACJ,QAAI,MAAM,YAAY,CAAC,MAAM,eAAe;AAC1C,aAAO,UAAU,MAAM,SAAS,KAAK,IAAI;AAAA,IAC3C,OAAO;AACL,YAAM,QAAQ,iBAAiB,OAAO,IAAI;AAC1C,UAAI,CAAC,MAAO;AACZ,aAAO;AAAA,IACT;AACA,UAAM,gBAAgB,IAAI,GAAG,IAAI,QAAQ,uBAAuB,MAAM;AACtE,QAAI,KAAK,EAAE,MAAM,MAAM,aAAa,MAAM,cAAc,CAAC;AAAA,EAC3D;AACA,SAAO;AACT;AAEA,SAAS,UAAU,KAAa,MAAsB;AACpD,QAAM,IAAI,KAAK,SAAS,GAAG,IAAI,OAAO,OAAO;AAC7C,MAAI,MAAM,OAAO,CAAC,IAAI,WAAW,CAAC,EAAG,QAAO;AAC5C,SAAO,MAAM,IAAI,MAAM,EAAE,MAAM;AACjC;AAIA,SAAS,eACP,GACA,GACA,MACQ;AACR,MAAI,KAAK,WAAW,SAAS;AAC3B,WAAO,KAAK,gBAAgB,CAAC,EAAE,cAAc,KAAK,gBAAgB,CAAC,CAAC;AAAA,EACtE;AACA,MAAI,KAAK,WAAW,cAAc;AAChC,WAAO,EAAE,QAAQ,EAAE;AAAA,EACrB;AACA,QAAM,KAAK,UAAU,GAAG,KAAK,QAAQ;AACrC,QAAM,KAAK,UAAU,GAAG,KAAK,QAAQ;AACrC,MAAI,OAAO,GAAI,QAAO,KAAK;AAC3B,SAAO,KAAK,gBAAgB,CAAC,EAAE,cAAc,KAAK,gBAAgB,CAAC,CAAC;AACtE;AAEA,SAAS,UAAU,OAAkB,KAAqB;AACxD,QAAM,IAAI,MAAM,YAAY,GAAG;AAC/B,MAAI,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,EAAG,QAAO;AACxD,SAAO,OAAO;AAChB;AAEA,SAAS,iBAAiB,OAAiC;AACzD,QAAM,IAAI,MAAM,YAAY;AAC5B,MAAI,OAAO,MAAM,YAAY,EAAE,KAAK,EAAG,QAAO,EAAE,KAAK;AACrD,SAAO;AACT;AAEA,SAAS,sBACP,UACA,MACS;AACT,MAAI,UAAU;AACZ,UAAM,IAAI,SAAS,YAAY;AAC/B,QAAI,OAAO,MAAM,UAAW,QAAO;AAAA,EACrC;AACA,SAAO,KAAK;AACd;AAEA,SAAS,cACP,OACA,MACA,aACS;AACT,MAAI,MAAM,YAAY,KAAK,SAAS,MAAM,KAAM,QAAO;AACvD,MAAI,eAAe,MAAM,aAAa,WAAW,cAAc,GAAG,EAAG,QAAO;AAG5E,MAAI,KAAK,eAAe;AACtB,UAAM,KAAK,KAAK,cAAc,QAAQ,cAAc,EAAE;AACtD,QAAI,CAAC,MAAM,aAAa,WAAW,KAAK,GAAG,KAAK,MAAM,iBAAiB,IAAI;AACzE,aAAO;AAAA,IACT;AAAA,EACF;AACA,aAAW,MAAM,KAAK,iBAAiB;AACrC,UAAM,KAAK,GAAG,QAAQ,cAAc,EAAE;AACtC,QAAI,MAAM,aAAa,WAAW,KAAK,GAAG,KAAK,MAAM,iBAAiB,IAAI;AACxE,aAAO;AAAA,IACT;AAAA,EACF;AAGA,QAAM,OAAO,MAAM,aAAa,MAAM,GAAG;AACzC,aAAW,OAAO,KAAK,MAAM,GAAG,EAAE,GAAG;AACnC,QAAI,IAAI,WAAW,GAAG,EAAG,QAAO;AAAA,EAClC;AACA,aAAW,OAAO,KAAK,SAAS;AAC9B,QAAI,gBAAgB,MAAM,cAAc,GAAG,EAAG,QAAO;AAAA,EACvD;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,MAAc,KAAsB;AAC3D,QAAM,YAAY;AAClB,QAAM,UAAU,IAAI,QAAQ,WAAW,MAAM;AAC7C,QAAM,WAAW,QACd,QAAQ,SAAS,gBAAgB,EACjC,QAAQ,OAAO,OAAO,EACtB,QAAQ,mBAAmB,IAAI;AAClC,SAAO,IAAI,OAAO,MAAM,WAAW,GAAG,EAAE,KAAK,IAAI;AACnD;AAIA,SAAS,iBACP,KACA,UACA,MACQ;AACR,MAAI,UAAU;AACZ,UAAM,UAAU,SAAS,YAAY,KAAK,QAAQ;AAClD,QAAI,OAAO,YAAY,YAAY,QAAQ,KAAK,EAAG,QAAO,QAAQ,KAAK;AACvE,UAAM,QAAQ,SAAS,YAAY;AACnC,QAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAG,QAAO,MAAM,KAAK;AACjE,UAAM,KAAK,SAAS,SAAS,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC;AACtD,QAAI,GAAI,QAAO,GAAG;AAAA,EACpB;AACA,QAAM,OAAO,IAAI,MAAM,GAAG,EAAE,IAAI,KAAK;AACrC,SAAO,KAAK,iBAAiB,IAAI;AACnC;;;AChpBA,IAAAC,kBAAe;AACf,IAAAC,oBAAqB;AAGd,IAAM,wBACX;AA0CF,IAAM,QAAQ;AACd,IAAM,WAAW;AAEV,SAAS,sBACd,SACA,aAAiC,CAAC,GACf;AACnB,QAAM,SAA4B,EAAE,SAAS,CAAC,GAAG,SAAS,CAAC,EAAE;AAG7D,QAAM,OACJ,WAAW,SACV,WAAW,YAAY,OACpB,cACA,WAAW,YAAY,QACrB,QACA;AACR,MAAI,SAAS,MAAO,QAAO;AAE3B,QAAM,SAAS,kBAAAC,QAAS,QAAQ,QAAQ,MAAM;AAC9C,QAAM,cAAc,QAAQ,MAAM,YAC9B,QAAQ,MAAM,UAAU,QAAQ,cAAc,EAAE,IAChD;AACJ,QAAM,QAAQ,WAAW,sBAAsB;AAC/C,QAAM,UAAU,WAAW,WAAW,CAAC;AACvC,QAAM,WAAW,WAAW,YAAY;AAIxC,QAAM,gBAAgB,CAAC,QAAQ,GAAG,YAAY,QAAQ,QAAQ,aAAa,SAAS,IAAI,CAAC;AAEzF,aAAW,UAAU,eAAe;AAClC,UAAM,SAAS,kBAAAA,QAAS,SAAS,QAAQ,MAAM,EAAE,MAAM,kBAAAA,QAAS,GAAG,EAAE,KAAK,GAAG;AAG7E,UAAM,UAAU,YAAY,MAAM;AAClC,QAAI,QAAQ,WAAW,EAAG;AAO1B,UAAM,UAAU,kBAAAA,QAAS,SAAS,MAAM,EAAE,YAAY;AACtD,UAAM,SAAS,kBAAAA,QAAS,KAAK,QAAQ,UAAU;AAE/C,QAAI,kBAAkB;AACtB,QAAI,gBAAgB;AACpB,eAAW,KAAK,SAAS;AACvB,UAAI,CAAC,EAAE,OAAO,EAAG;AACjB,YAAM,QAAQ,EAAE,KAAK,YAAY;AACjC,YAAM,cACJ,UAAU,GAAG,OAAO,SACpB,UAAU,GAAG,OAAO,eACpB,SAAS,KAAK,EAAE,IAAI;AACtB,UAAI,CAAC,YAAa;AAClB,YAAM,UAAU,SAAS,kBAAAA,QAAS,KAAK,QAAQ,EAAE,IAAI,CAAC;AACtD,UAAI,YAAY,KAAM;AAGtB,UAAI,CAAC,QAAQ,SAAS,qBAAqB,GAAG;AAC5C,0BAAkB;AAClB,wBAAgB,EAAE;AAClB;AAAA,MACF;AAAA,IACF;AACA,QAAI,iBAAiB;AAInB,iBAAW,YAAY,CAAC,YAAY,WAAW,GAAG;AAChD,YAAI,SAAS,YAAY,MAAM,cAAc,YAAY,EAAG;AAC5D,cAAM,WAAW,kBAAAA,QAAS,KAAK,QAAQ,QAAQ;AAC/C,cAAM,cAAc,SAAS,QAAQ;AACrC,YAAI,eAAe,YAAY,SAAS,qBAAqB,GAAG;AAC9D,cAAI;AACF,4BAAAC,QAAG,WAAW,QAAQ;AACtB,mBAAO,QAAQ,KAAK;AAAA,cAClB,MAAM;AAAA,cACN,QAAQ,4BAAQ,aAAa;AAAA,YAC/B,CAAC;AAAA,UACH,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AACA,aAAO,QAAQ,KAAK;AAAA,QAClB,MAAM;AAAA,QACN,QAAQ,4BAAQ,aAAa;AAAA,MAC/B,CAAC;AACD;AAAA,IACF;AAGA,UAAM,QAAkC,CAAC;AACzC,UAAM,UAAsC,CAAC;AAC7C,eAAW,KAAK,SAAS;AACvB,UAAI,EAAE,OAAO,KAAK,MAAM,KAAK,EAAE,IAAI,KAAK,CAAC,SAAS,KAAK,EAAE,IAAI,GAAG;AAC9D,cAAM,OAAO,EAAE,KAAK,QAAQ,OAAO,EAAE;AACrC,cAAM,KAAK;AAAA,UACT;AAAA,UACA,SAAS;AAAA,UACT,OAAOC,UAAS,MAAM,KAAK;AAAA,QAC7B,CAAC;AAAA,MACH,WAAW,EAAE,YAAY,KAAK,CAAC,EAAE,KAAK,WAAW,GAAG,GAAG;AAErD,YAAI,aAAa,kBAAAF,QAAS,KAAK,QAAQ,EAAE,IAAI,CAAC,GAAG;AAC/C,kBAAQ,KAAK,EAAE,MAAM,EAAE,MAAM,OAAOE,UAAS,EAAE,MAAM,KAAK,EAAE,CAAC;AAAA,QAC/D;AAAA,MACF;AAAA,IACF;AAGA,QAAI,MAAM,WAAW,KAAK,QAAQ,WAAW,GAAG;AAC9C;AAAA,IACF;AAEA,UAAM,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AACnD,YAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AAGrD,UAAM,UACJ,WAAW,KACP,kBAAAF,QAAS,SAAS,MAAM,IACxB,OAAO,MAAM,GAAG,EAAE,IAAI,KAAK;AACjC,UAAM,MAAuB;AAAA,MAC3B,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ,OAAOE,UAAS,SAAS,KAAK,KAAK;AAAA,MACnC;AAAA,MACA;AAAA,IACF;AAEA,QAAI;AACF,sBAAAD,QAAG,cAAc,QAAQ,SAAS,GAAG,GAAG,MAAM;AAC9C,aAAO,QAAQ,KAAK,MAAM;AAAA,IAC5B,SAAS,KAAK;AACZ,aAAO,QAAQ,KAAK;AAAA,QAClB,MAAM;AAAA,QACN,QAAQ,6BAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACnE,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,YACP,MACA,KACA,aACA,SACA,MACU;AACV,QAAM,MAAgB,CAAC;AACvB,EAAAE,MAAK,KAAK,CAAC;AACX,SAAO;AAEP,WAASA,MAAK,KAAa,OAAqB;AAE9C,QAAI,SAAS,eAAe,QAAQ,EAAG;AAEvC,QAAI;AACJ,QAAI;AACF,gBAAU,gBAAAF,QAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,IACvD,QAAQ;AACN;AAAA,IACF;AACA,eAAW,KAAK,SAAS;AACvB,UAAI,CAAC,EAAE,YAAY,EAAG;AACtB,UAAI,EAAE,KAAK,WAAW,GAAG,EAAG;AAC5B,UAAI,EAAE,KAAK,WAAW,GAAG,EAAG;AAC5B,UAAI,EAAE,SAAS,kBAAkB,EAAE,SAAS,SAAU;AACtD,YAAM,OAAO,kBAAAD,QAAS,KAAK,KAAK,EAAE,IAAI;AACtC,YAAM,MAAM,kBAAAA,QAAS,SAAS,MAAM,IAAI,EAAE,MAAM,kBAAAA,QAAS,GAAG,EAAE,KAAK,GAAG;AACtE,UAAI,gBAAgB,QAAQ,eAAe,IAAI,WAAW,cAAc,GAAG,GAAI;AAC/E,UAAI,QAAQ,KAAK,CAAC,QAAQ,UAAU,KAAK,GAAG,CAAC,EAAG;AAChD,UAAI,KAAK,IAAI;AACb,UAAI,SAAS,MAAO,CAAAG,MAAK,MAAM,QAAQ,CAAC;AAAA,IAC1C;AAAA,EACF;AACF;AAEA,SAAS,aAAa,KAAsB;AAC1C,MAAI;AACF,UAAM,UAAU,gBAAAF,QAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAC3D,eAAW,KAAK,SAAS;AACvB,UAAI,EAAE,OAAO,KAAK,MAAM,KAAK,EAAE,IAAI,EAAG,QAAO;AAC7C,UAAI,EAAE,YAAY,KAAK,CAAC,EAAE,KAAK,WAAW,GAAG,KAAK,CAAC,EAAE,KAAK,WAAW,GAAG,GAAG;AACzE,YAAI,aAAa,kBAAAD,QAAS,KAAK,KAAK,EAAE,IAAI,CAAC,EAAG,QAAO;AAAA,MACvD;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,SAAS,YAAY,KAA0B;AAC7C,MAAI;AACF,WAAO,gBAAAC,QAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,EACpD,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,SAAS,GAA0B;AAC1C,MAAI;AACF,WAAO,gBAAAA,QAAG,aAAa,GAAG,MAAM;AAAA,EAClC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,UAAU,MAAc,KAAsB;AACrD,QAAM,MAAM;AACZ,QAAM,KAAK,IACR,QAAQ,KAAK,MAAM,EACnB,QAAQ,SAAS,QAAQ,EACzB,QAAQ,OAAO,OAAO,EACtB,QAAQ,WAAW,IAAI;AAC1B,SAAO,IAAI,OAAO,MAAM,KAAK,GAAG,EAAE,KAAK,IAAI;AAC7C;AAGO,SAASC,UAAS,MAAc,cAA+B;AACpE,MAAI,IAAI;AACR,MAAI,cAAc;AAChB,QAAI,EAAE,QAAQ,gBAAgB,EAAE;AAAA,EAClC;AACA,SAAO,EACJ,QAAQ,UAAU,GAAG,EACrB,QAAQ,QAAQ,GAAG,EACnB,KAAK,EACL,QAAQ,SAAS,CAAC,MAAM,EAAE,YAAY,CAAC;AAC5C;AAEA,SAAS,gBAAgB,KAA8B;AACrD,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,UAAU,IAAI,KAAK,EAAE;AAChC,QAAM,KAAK,iBAAiB,IAAI,KAAK,EAAE;AACvC,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,qBAAqB;AAChC,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,KAAK,IAAI,KAAK,EAAE;AAC3B,QAAM,KAAK,EAAE;AACb,MAAI,IAAI,QAAQ,SAAS,GAAG;AAC1B,UAAM,KAAK,aAAa;AACxB,UAAM,KAAK,EAAE;AACb,eAAW,KAAK,IAAI,SAAS;AAC3B,YAAM,KAAK,OAAO,IAAI,UAAU,IAAI,EAAE,IAAI,KAAK,EAAE,KAAK,IAAI;AAAA,IAC5D;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AACA,MAAI,IAAI,MAAM,SAAS,GAAG;AACxB,UAAM,KAAK,UAAU;AACrB,UAAM,KAAK,EAAE;AACb,eAAW,KAAK,IAAI,OAAO;AACzB,YAAM,KAAK,OAAO,IAAI,UAAU,IAAI,EAAE,OAAO,IAAI,EAAE,KAAK,IAAI;AAAA,IAC9D;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;;;AC3TA,IAAME,eAAc;AAcpB,SAAS,iBAAiB,KAAqB;AAE7C,MAAI,IAAI,IAAI,QAAQ,mBAAmB,CAAC,MAAM,IAAI,OAAO,EAAE,MAAM,CAAC;AAElE,MAAI,EAAE,QAAQ,mBAAmB,CAAC,MAAM,IAAI,OAAO,EAAE,MAAM,CAAC;AAE5D,MAAI,EAAE,QAAQ,6BAA6B,CAAC,MAAM,IAAI,OAAO,EAAE,MAAM,CAAC;AACtE,SAAO;AACT;AAEO,SAAS,cACd,OACA,SACgB;AAChB,QAAM,OAA+B,CAAC;AACtC,MAAI,QAAQ;AAEZ,aAAW,KAAK,MAAM,MAAM,OAAO,GAAG;AACpC,UAAM,UAAU,iBAAiB,EAAE,OAAO;AAC1C,UAAM,UAAU,QAAQ,SAASA,YAAW;AAC5C,eAAW,KAAK,SAAS;AACvB,eAAS;AACT,YAAM,UAAU,EAAE,CAAC,MAAM;AACzB,YAAM,YAAY,EAAE,CAAC,EAAG,KAAK;AAE7B,UAAI,SAAS;AACX,cAAM,MAAMC,YAAW,SAAS;AAChC,YAAI,KAAK;AACP,gBAAM,UACJ,QAAQ,KAAK,gBAAgB,SAAS,IAAI,YAAY,CAAC,KACvD,CAAC,MAAM,UAAU,EAAE,SAAS,IAAI,YAAY,CAAC;AAC/C,cAAI,QAAS;AAAA,QACf;AAAA,MACF;AACA,YAAM,QAAQ,cAAc,WAAW,OAAO,SAAS,EAAE,YAAY;AACrE,UAAI,CAAC,OAAO;AACV,aAAK,KAAK;AAAA,UACR,QAAQ,EAAE;AAAA,UACV,QAAQ;AAAA,UACR,KAAK,GAAG,UAAU,MAAM,EAAE,KAAK,SAAS;AAAA,QAC1C,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,OAAO,KAAK;AACvB;AAGO,SAAS,aAAa,QAAwB,UAA6C;AAChG,MAAI,OAAO,KAAK,WAAW,EAAG;AAC9B,MAAI,aAAa,SAAU;AAC3B,QAAM,OAAO,4CAA6B,OAAO,KAAK,kCAC9C,OAAO,KAAK,MAAM;AAC1B,MAAI,aAAa,SAAS;AACxB,YAAQ,MAAM,IAAI;AAAA,EACpB,OAAO;AACL,YAAQ,KAAK,IAAI;AAAA,EACnB;AAEA,QAAM,WAAW,oBAAI,IAAgC;AACrD,aAAW,KAAK,OAAO,MAAM;AAC3B,UAAM,MAAM,SAAS,IAAI,EAAE,MAAM,KAAK,CAAC;AACvC,QAAI,KAAK,CAAC;AACV,aAAS,IAAI,EAAE,QAAQ,GAAG;AAAA,EAC5B;AACA,aAAW,CAAC,KAAK,KAAK,KAAK,CAAC,GAAG,SAAS,QAAQ,CAAC,EAAE,KAAK,GAAG;AACzD,YAAQ,KAAK,KAAK,GAAG,EAAE;AACvB,eAAW,MAAM,OAAO;AACtB,cAAQ,KAAK,OAAO,GAAG,GAAG,EAAE;AAAA,IAC9B;AAAA,EACF;AACF;AAEA,SAASA,YAAW,QAAwB;AAC1C,QAAM,UAAU,OAAO,MAAM,GAAG,EAAE,CAAC;AACnC,QAAM,MAAM,QAAQ,YAAY,GAAG;AACnC,MAAI,OAAO,EAAG,QAAO;AACrB,SAAO,QAAQ,MAAM,MAAM,CAAC,EAAE,YAAY;AAC5C;AAEA,SAAS,cACP,KACA,OACA,SACA,kBACS;AACT,QAAM,SAAS,iBAAiB,QAAQ,GAAG,CAAC;AAC5C,MAAI,CAAC,OAAQ,QAAO;AAEpB,MAAI,OAAO,SAAS,GAAG,GAAG;AACxB,QACE,MAAM,eAAe,IAAI,MAAM,KAC/B,MAAM,eAAe,IAAI,SAAS,KAAK,KACvC,MAAM,eAAe,IAAI,SAAS,WAAW,GAC7C;AACA,aAAO;AAAA,IACT;AAEA,QAAI,kBAAkB;AACpB,YAAM,SAAS,iBAAiB,MAAM,GAAG,EAAE,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG;AAChE,UAAI,QAAQ;AACV,eACE,MAAM,eAAe,IAAI,GAAG,MAAM,IAAI,MAAM,EAAE,KAC9C,MAAM,eAAe,IAAI,GAAG,MAAM,IAAI,MAAM,KAAK,KACjD,MAAM,eAAe,IAAI,GAAG,MAAM,IAAI,MAAM,WAAW;AAAA,MAE3D;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,QAAQ,gBAAgB,SAAS,OAAO,YAAY;AACrE,MAAI,MAAM,QAAQ,IAAI,QAAQ,EAAG,QAAO;AAExC,QAAM,MAAM,QAAQ,gBAAgB,MAAM,aAAa,MAAM;AAC7D,QAAM,MAAM,QAAQ,gBAAgB,SAAS,OAAO,YAAY;AAChE,UAAQ,IAAI,IAAI,GAAG,GAAG,UAAU,KAAK;AACvC;;;AClGO,SAAS,2BACd,QACA,gBAAmC,CAAC,GACxB;AAEZ,QAAM,YAAY,MAAM,QAAQ,OAAO,UAAU,IAAI,OAAO,aAAa,CAAC;AAE1E,QAAM,gBAAmC;AAAA,IACvC,GAAG;AAAA,IACH,QAAQ,cAAc,UAAU,OAAO;AAAA,IACvC,MAAM,cAAc,QAAQ,OAAO;AAAA,IACnC,WAAW,cAAc,aAAa,OAAO;AAAA,IAC7C,MAAM;AAAA,MACJ,GAAG,cAAc;AAAA,MACjB,SAAS;AAAA,QACP,GAAI,cAAc,MAAM,WAAW,CAAC;AAAA,QACpC,GAAG;AAAA,MACL;AAAA,IACF;AAAA,EACF;AAGA,QAAM,aAAa,eAAe,aAAa;AAI/C,QAAM,eACJ,OAAO,OAAO,SAAS,YAAY,OAAO,SAAS,OAC/C,OAAO,OACP,CAAC;AAEP,QAAM,kBAA6B,MAAM,QAAQ,aAAa,OAAO,IAChE,aAAa,UACd,CAAC;AACL,QAAM,UAAU;AAAA,IACd,GAAG;AAAA,IACH,SAAS,CAAC,GAAG,iBAAiB,UAAU;AAAA,EAC1C;AAGA,QAAM,mBAAmB,OAAO,YAAY,CAAC;AAC7C,QAAM,iBAAkB,iBAA0C;AAGlE,QAAM,qBAAqB,eAAe,eAAe;AAAA,IACvD,QAAQ,cAAc,UAAU,OAAO;AAAA,IACvC,MAAM,cAAc,QAAQ,OAAO;AAAA,IACnC,WAAW,cAAc,aAAa,OAAO;AAAA,EAC/C,CAAC;AAED,QAAM,oBAAoB,CAAC,OAAmB;AAE5C,wBAAqB,IAAI,aAAa;AAGtC,QACE,mBAAmB,QAAQ,SAC3B,mBAAmB,MAAM,iBACzB;AACA,yBAAmB,EAAE;AAAA,IACvB;AAGA,OAAG,KAAK,MAAM;AAAA,MACZ;AAAA,MACA;AAAA,MACA,gBAAgB,UAAU;AAAA,IAC5B;AAGA,QAAI,OAAO,mBAAmB,YAAY;AACxC,qBAAe,EAAE;AAAA,IACnB;AAAA,EACF;AAGA,QAAM,cAAe,OAAO,eAAe,CAAC;AAQ5C,QAAM,cAAc,mBAAmB;AACvC,QAAM,cAAc,YAAY,QAAQ;AACxC,MAAI,gBAAgB,OAAO;AACzB,UAAM,eAAe,YAAY,YAAY;AAC7C,UAAM,aAAa,gBAAgB,WAAW,CAAC;AAC/C,QAAI,YAAY;AAKd,UAAI;AAIF,cAAM,aAAa;AAAA,UACjB,YAAY;AAAA,UACZ,YAAY;AAAA,QACd;AACA,YAAI,WAAW,SAAS,OAAO;AAC7B,cAAI;AACF,kCAAsB,oBAAoB,UAAU;AAAA,UACtD,SAAS,GAAG;AACV,oBAAQ;AAAA,cACN;AAAA,cACA,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAAA,YAC3C;AAAA,UACF;AAAA,QACF;AACA,cAAM,QAAQ,UAAU,kBAAkB;AAE1C,YAAI;AACF,gBAAM,SAAS,cAAc,OAAO,kBAAkB;AACtD,uBAAa,QAAQ,mBAAmB,QAAQ;AAAA,QAClD,QAAQ;AAAA,QAER;AAIA,cAAM,aAAc,OAAkG;AACtH,cAAM,aAAa,aACf,OAAO,KAAK,UAAU,EAAE,OAAO,CAAC,MAAM,MAAM,MAAM,IAClD,CAAC;AAEL,oBAAY,UAAU,gBAAgB,OAAO,oBAAoB;AAAA,UAC/D,GAAG;AAAA,UACH,iBAAiB;AAAA,YACf,GAAI,YAAY,mBAAmB,CAAC;AAAA,YACpC,GAAG;AAAA;AAAA,UACL;AAAA,QACF,CAAC;AAGD,YAAI,YAAY;AACd,qBAAW,QAAQ,YAAY;AAC7B,kBAAM,YAAY,WAAW,IAAI;AACjC,gBAAI,CAAC,UAAU,YAAa,WAAU,cAAc,CAAC;AACrD,gBAAI,UAAU,YAAY,YAAY,QAAW;AAC/C,wBAAU,YAAY,UAAU;AAAA,gBAC9B;AAAA,gBACA;AAAA,gBACA,EAAE,GAAG,aAAa,eAAe,KAAK;AAAA,cACxC;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAGA,YAAI,YAAY,WAAW,YAAY,QAAQ,QAAW;AACxD,sBAAY,MAAM;AAAA,YAChB;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF,SAAS,GAAG;AACV,gBAAQ;AAAA,UACN;AAAA,UACA,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAAA,QAC3C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,mBAAmB,QAAQ,OAAO;AACpC,gBAAY,UAAU;AAAA,MACpB,YAAY;AAAA,MACZ;AAAA,IACF;AAEA,gBAAY,MAAM;AAAA,MAChB,YAAY;AAAA,MACZ;AAAA,IACF;AAGA,UAAM,gBAAiB,OAA6E;AACpG,QAAI,eAAe;AACjB,iBAAW,QAAQ,OAAO,KAAK,aAAa,GAAG;AAC7C,cAAM,KAAK,cAAc,IAAI;AAC7B,YAAI,CAAC,GAAG,YAAa;AACrB,YAAI,GAAG,YAAY,QAAQ,QAAW;AACpC,aAAG,YAAY,MAAM;AAAA,YACnB,GAAG,YAAY;AAAA,YACf;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM;AAAA,IACN;AAAA,IACA,UAAU;AAAA,MACR,GAAG;AAAA,MACH,QAAQ;AAAA,IACV;AAAA,EACF;AACF;AAMA,SAAS,yBACP,GACA,0BAMA;AACA,MAAI,OAAoC;AACxC,MAAI;AACJ,MAAI,QAA6B;AACjC,MAAI;AAIJ,MAAI,MAAM,UAAa,MAAM,MAAM;AAAA,EAEnC,WAAW,MAAM,SAAS,MAAM,OAAO;AACrC,WAAO;AAAA,EACT,WAAW,MAAM,QAAQ,MAAM,aAAa;AAC1C,WAAO;AAAA,EACT,WAAW,MAAM,OAAO;AACtB,WAAO;AAAA,EACT,WAAW,OAAO,MAAM,UAAU;AAChC,UAAM,MAAM;AAOZ,QAAI,IAAI,MAAM;AACZ,aAAO,IAAI;AAAA,IACb,WAAW,IAAI,YAAY,OAAO;AAChC,aAAO;AAAA,IACT,WAAW,IAAI,YAAY,MAAM;AAC/B,aAAO;AAAA,IACT;AACA,cAAU,IAAI;AACd,QAAI,IAAI,uBAAuB,OAAW,SAAQ,IAAI;AACtD,eAAW,IAAI;AAAA,EACjB;AAEA,SAAO,EAAE,MAAM,SAAS,oBAAoB,OAAO,SAAS;AAC9D;AAwBA,SAAS,gBACP,YACoC;AACpC,SAAO,CAAC,UAAU;AAChB,UAAM,MAAM,MAAM;AAGlB,QAAI,CAAC,IAAK;AACV,QAAI,IAAI,SAAS,IAAI,QAAS;AAE9B,UAAM,QAAQ,WAAW,WAAW;AACpC,UAAM,UAAU,WAAW,aAAa;AACxC,QAAI,CAAC,SAAS,CAAC,QAAS;AAExB,QAAI,QAAQ;AACZ,QAAI,UAAU;AACd,QAAI,CAAC,IAAI,aAAa;AACpB,UAAI,cACF,OAAO,IAAI,aAAa,WACpB,IAAI,WACJ,OAAO,IAAI,SAAS,WAClB,IAAI,OACJ;AAAA,IACV;AACA,QAAI,CAAC,IAAI,iBAAkB,KAAI,mBAAmB,oBAAI,IAAI;AAAA,EAC5D;AACF;","names":["mditVueSlugify","import_node_fs","import_node_path","nodePath","import_node_path","fs","nodePath","import_node_fs","import_node_path","nodePath","fs","picomatch","matter","nodePath","fs","extractExt","import_node_fs","import_node_path","import_node_fs","import_node_path","fs","import_node_fs","import_node_path","nodePath","fs","import_node_fs","import_node_path","nodePath","fs","nodePath","fs","LINE_RE","WIKILINK_RE","buildTree","import_node_fs","import_node_path","nodePath","fs","humanize","walk","WIKILINK_RE","extractExt"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/core/slugify.ts","../src/core/config-bridge.ts","../src/core/vault/index.ts","../src/utils/path.ts","../src/utils/url.ts","../src/core/vault/scan.ts","../src/core/vault/ignore.ts","../src/core/vault/frontmatter.ts","../src/core/vault/headings.ts","../src/core/resolver.ts","../src/modules/wikilinks/render.ts","../src/utils/escape.ts","../src/core/asset-pipeline/build-emit.ts","../src/modules/embeds/image.ts","../src/modules/embeds/transclusion.ts","../src/modules/embeds/media.ts","../src/modules/wikilinks/rule.ts","../src/modules/wikilinks/index.ts","../src/modules/embeds/block-rule.ts","../src/modules/embeds/index.ts","../src/modules/callouts/types.ts","../src/modules/callouts/rule.ts","../src/modules/callouts/index.ts","../src/modules/highlight/rule.ts","../src/modules/highlight/index.ts","../src/modules/comments/rule.ts","../src/modules/comments/index.ts","../src/modules/footnotes/rule.ts","../src/modules/block-refs/rule.ts","../src/markdown-it.ts","../src/vite.ts","../src/core/asset-pipeline/dev-middleware.ts","../src/core/views/generate-md.ts","../src/core/views/generate-data.ts","../src/modules/tags/rule.ts","../src/core/views/sidebar-inject.ts","../src/core/sidebar-auto/parse-sidebar-md.ts","../src/core/sidebar-auto/generate.ts","../src/core/sidebar-auto/generate-folder-index.ts","../src/core/scan-wikilinks.ts","../src/vitepress.ts"],"sourcesContent":["/**\n * 默认入口 —— 主要导出 markdown-it 插件函数,并把其它常用 API re-export\n * 出来,方便高级用户从同一个包名取所有东西。\n */\n\nexport { default } from './markdown-it.js'\nexport { allYouNeedMarkdownIt } from './markdown-it.js'\n\nexport { viteAllYouNeed } from './vite.js'\nexport { defineConfigWithAllYouNeed } from './vitepress.js'\n\nexport { resolveOptions } from './core/config-bridge.js'\nexport {\n scanVault,\n createEmptyIndex,\n updateFile,\n removeFile,\n} from './core/vault/index.js'\nexport { resolveWikilink, resolveAsset } from './core/resolver.js'\nexport { defaultSlugify, extractCustomId } from './core/slugify.js'\n\nexport type {\n AllYouNeedOptions,\n ResolvedOptions,\n VaultIndex,\n FileEntry,\n AssetEntry,\n HeadingEntry,\n BacklinkEntry,\n ScanWarning,\n AllYouNeedEnv,\n ResolveResult,\n WikilinksModuleOptions,\n EmbedsModuleOptions,\n ScanOptions,\n AssetsOptions,\n PageLinkAttrs,\n PageLinkAttrsContext,\n ImageEmbedAttrs,\n ImageEmbedAttrsContext,\n} from './core/types.js'\n","/**\n * 锚点 slugifier。\n *\n * 默认用 @mdit-vue/shared 的 slugify —— 这是 VitePress 内部 markdown-it-anchor\n * 默认使用的实现,保证我们算出的 slug 和 anchor ID 100% 对得上(包括中文)。\n *\n * 用户在 VitePress 里覆写了 markdown.anchor.slugify 时,ConfigBridge 会把\n * 用户的函数读出来传给 ResolvedOptions.slugify,Resolver 直接用,无需走这里。\n */\n\nimport { slugify as mditVueSlugify } from '@mdit-vue/shared'\n\n/**\n * 默认 slugifier。\n */\nexport function defaultSlugify(text: string): string {\n return mditVueSlugify(text)\n}\n\n/**\n * 处理 `## 标题 {#custom-id}` 这种自定义 anchor 语法,\n * 返回 `{ text: '标题', slug: 'custom-id' | undefined }`。\n *\n * markdown-it-anchor 默认启用此扩展(`permalink.linkInsideHeader` 等无关),\n * 我们的 heading 收集器要做相同识别,否则 [[Page#标题]] 会按 slugify('标题')\n * 算,而 markdown-it-anchor 实际用了 'custom-id',结果不匹配。\n */\nconst CUSTOM_ID_RE = /\\s*\\{#([^}\\s]+)\\}\\s*$/\n\nexport function extractCustomId(headingText: string): {\n text: string\n customId: string | undefined\n} {\n const m = headingText.match(CUSTOM_ID_RE)\n if (!m) return { text: headingText, customId: undefined }\n return {\n text: headingText.replace(CUSTOM_ID_RE, ''),\n customId: m[1],\n }\n}\n","/**\n * VitePress / Vite 配置桥接。\n *\n * 负责把外部配置(VitePress site config、Vite 的 ResolvedConfig)和用户传入\n * 的插件选项合并,产出一份 ResolvedOptions —— 所有字段都填值,后续模块只看这份。\n */\n\nimport type {\n AllYouNeedOptions,\n ResolvedOptions,\n PageLinkAttrs,\n ImageEmbedAttrs,\n} from './types.js'\nimport { defaultSlugify } from './slugify.js'\n\nconst DEFAULT_ASSET_EXTENSIONS = [\n // 位图\n 'bmp',\n 'gif',\n 'jpeg',\n 'jpg',\n 'png',\n 'svg',\n 'webp',\n 'avif',\n 'ico',\n // 视频\n 'mp4',\n 'webm',\n 'mov',\n 'm4v',\n // 音频\n 'mp3',\n 'wav',\n 'ogg',\n 'm4a',\n 'flac',\n // 文档\n 'pdf',\n // Obsidian 专属\n 'canvas',\n 'excalidraw',\n]\n\nconst DEFAULT_IMAGE_EXTENSIONS = [\n 'bmp',\n 'gif',\n 'jpeg',\n 'jpg',\n 'png',\n 'svg',\n 'webp',\n 'avif',\n 'ico',\n]\n\n/**\n * 合并默认值与用户配置,产出 ResolvedOptions。\n *\n * @param user 用户传入(可能为空对象)\n * @param ctx 外部上下文(VitePress / Vite 决议出的值)\n */\nexport function resolveOptions(\n user: AllYouNeedOptions = {},\n ctx: {\n srcDir?: string\n base?: string\n cleanUrls?: boolean\n /** VitePress markdown.anchor.slugify 若被用户覆写 */\n externalSlugify?: (text: string) => string\n } = {},\n): ResolvedOptions {\n const srcDir = user.srcDir ?? ctx.srcDir ?? process.cwd()\n let base = user.base ?? ctx.base ?? '/'\n if (!base.startsWith('/')) base = '/' + base\n if (!base.endsWith('/')) base = base + '/'\n\n const cleanUrls = user.cleanUrls ?? ctx.cleanUrls ?? false\n const slugify = user.slugify ?? ctx.externalSlugify ?? defaultSlugify\n\n const wikilinksUser = user.wikilinks ?? {}\n const embedsUser = user.embeds ?? {}\n const scanUser = user.scan ?? {}\n const assetsUser = user.assets ?? {}\n const modulesUser = user.modules ?? {}\n const viewsUser = user.views ?? {}\n\n const wikilinksHtmlAttrs: PageLinkAttrs = wikilinksUser.htmlAttributes ?? {}\n const embedsHtmlAttrs: ImageEmbedAttrs = embedsUser.htmlAttributes ?? {}\n\n return {\n srcDir,\n base,\n cleanUrls,\n caseSensitive: user.caseSensitive ?? false,\n deadLink: user.deadLink ?? 'warn',\n onConflict: user.onConflict ?? 'shortest',\n onAliasConflict: user.onAliasConflict ?? 'first',\n\n scan: {\n include: scanUser.include ?? ['**/*.md', '**/*.markdown'],\n exclude: scanUser.exclude ?? [],\n followSymlinks: scanUser.followSymlinks ?? false,\n respectGitignore: scanUser.respectGitignore ?? true,\n assetExtensions: scanUser.assetExtensions ?? DEFAULT_ASSET_EXTENSIONS,\n },\n\n assets: {\n mode: assetsUser.mode ?? 'auto',\n preserveAssetPaths: assetsUser.preserveAssetPaths ?? false,\n outputDir: assetsUser.outputDir ?? '_assets',\n },\n\n wikilinks: {\n postProcessLinkTarget:\n wikilinksUser.postProcessLinkTarget ?? ((t: string) => t.trim()),\n postProcessLinkLabel:\n wikilinksUser.postProcessLinkLabel ?? ((l: string) => l.trim()),\n allowLinkLabelFormatting:\n wikilinksUser.allowLinkLabelFormatting ?? false,\n linkText: wikilinksUser.linkText ?? 'basename',\n htmlAttributes: wikilinksHtmlAttrs,\n },\n\n embeds: {\n imageFileExt: embedsUser.imageFileExt ?? DEFAULT_IMAGE_EXTENSIONS,\n defaultAltText: embedsUser.defaultAltText ?? false,\n postProcessImageTarget:\n embedsUser.postProcessImageTarget ?? ((t: string) => t.trim()),\n postProcessAltText:\n embedsUser.postProcessAltText ?? ((a: string) => a.trim()),\n uriSuffix: embedsUser.uriSuffix ?? '',\n transclusionMaxDepth: embedsUser.transclusionMaxDepth ?? 8,\n htmlAttributes: embedsHtmlAttrs,\n },\n\n views: {\n enabled: {\n graph: viewsUser.enabled?.graph ?? true,\n stats: viewsUser.enabled?.stats ?? true,\n tags: viewsUser.enabled?.tags ?? true,\n },\n urlPrefix: viewsUser.urlPrefix ?? '_perspectives_',\n names: {\n graph: viewsUser.names?.graph ?? 'graph',\n stats: viewsUser.names?.stats ?? 'stats',\n tags: viewsUser.names?.tags ?? 'tags',\n },\n // 'injectInto' 优先(v0.3+);否则从老的 'sidebar' 字段推断;再否则默认 'nav'\n injectInto:\n viewsUser.injectInto ??\n (viewsUser.sidebar === false\n ? 'off'\n : viewsUser.sidebar === 'auto'\n ? 'sidebar'\n : 'nav'),\n sidebar: viewsUser.sidebar ?? 'auto',\n sidebarText: {\n group: viewsUser.sidebarText?.group ?? 'Perspectives',\n graph: viewsUser.sidebarText?.graph ?? 'Graph',\n stats: viewsUser.sidebarText?.stats ?? 'Stats',\n tags: viewsUser.sidebarText?.tags ?? 'Tags',\n },\n graphMaxNodes: viewsUser.graphMaxNodes ?? 500,\n dataFileName: viewsUser.dataFileName ?? 'vault-data.json',\n parseInlineTags: viewsUser.parseInlineTags ?? true,\n },\n\n modules: {\n wikilinks: modulesUser.wikilinks ?? true,\n embeds: modulesUser.embeds ?? true,\n views: modulesUser.views ?? true,\n callouts: modulesUser.callouts ?? true,\n highlight: modulesUser.highlight ?? true,\n comments: modulesUser.comments ?? true,\n footnotes: modulesUser.footnotes ?? true,\n blockRefs: modulesUser.blockRefs ?? true,\n },\n\n sidebarAuto: user.sidebarAuto ?? {},\n\n slugify,\n }\n}\n","/**\n * VaultScanner —— 把 srcDir 扫成一份完整的 VaultIndex。\n *\n * 设计目标:\n * - 一次扫描产出所有衍生索引,后续模块只查不扫;\n * - 同步实现(简单可靠,性能足够);\n * - 增量更新(updateFile / removeFile)供 dev 模式 HMR 用。\n */\n\nimport fs from 'node:fs'\nimport nodePath from 'node:path'\nimport type {\n VaultIndex,\n FileEntry,\n AssetEntry,\n ResolvedOptions,\n ScanWarning,\n} from '../types.js'\nimport {\n toPosix,\n basename,\n extname,\n relative as relativePath,\n pathDepth,\n} from '../../utils/path.js'\nimport { buildUrl, applyCleanUrls } from '../../utils/url.js'\nimport { walk } from './scan.js'\nimport { buildIgnorer } from './ignore.js'\nimport {\n parseFrontmatter,\n normalizeAliases,\n normalizeTags,\n} from './frontmatter.js'\nimport { collectHeadings } from './headings.js'\n\nconst MD_EXTENSIONS = new Set(['md', 'markdown'])\n\n/**\n * 创建一份空 VaultIndex(供测试或没有 srcDir 时使用)。\n */\nexport function createEmptyIndex(\n srcDir = '',\n base = '/',\n cleanUrls = false,\n): VaultIndex {\n return {\n files: new Map(),\n assets: new Map(),\n byBasename: new Map(),\n byBasenameLower: new Map(),\n byAlias: new Map(),\n byRelativePath: new Map(),\n byUrl: new Map(),\n assetsByBasename: new Map(),\n assetsByBasenameLower: new Map(),\n assetsByRelativePath: new Map(),\n tags: new Map(),\n backlinks: new Map(),\n headings: new Map(),\n srcDir,\n base,\n cleanUrls,\n scannedAt: Date.now(),\n warnings: [],\n }\n}\n\n/**\n * 扫描 srcDir 并构建 VaultIndex。\n */\nexport function scanVault(options: ResolvedOptions): VaultIndex {\n const srcDir = toPosix(nodePath.resolve(options.srcDir))\n const index = createEmptyIndex(srcDir, options.base, options.cleanUrls)\n\n const isIgnored = buildIgnorer(\n srcDir,\n options.scan.exclude,\n options.scan.respectGitignore,\n )\n\n const assetExtSet = new Set(\n options.scan.assetExtensions.map((e) => e.toLowerCase()),\n )\n\n const entries = walk(srcDir, isIgnored, options.scan.followSymlinks)\n\n for (const ent of entries) {\n const ext = ent.extension\n if (MD_EXTENSIONS.has(ext)) {\n ingestMarkdown(index, ent.absolutePath, ent.size, ent.mtime, options)\n } else if (assetExtSet.has(ext)) {\n ingestAsset(index, ent.absolutePath, ent.size, ent.mtime, ext)\n }\n // 其它扩展静默跳过(.json、.ts 等)\n }\n\n index.scannedAt = Date.now()\n return index\n}\n\n/**\n * 把一个 .md 文件读入索引。\n */\nfunction ingestMarkdown(\n index: VaultIndex,\n absPath: string,\n size: number,\n mtime: number,\n options: ResolvedOptions,\n): void {\n let raw: string\n try {\n raw = fs.readFileSync(absPath, 'utf8')\n } catch (err) {\n index.warnings.push({\n kind: 'unreadable-file',\n message: `无法读取文件: ${absPath} (${\n err instanceof Error ? err.message : String(err)\n })`,\n affected: [absPath],\n })\n return\n }\n\n const { data, content, error } = parseFrontmatter(raw)\n if (error) {\n index.warnings.push({\n kind: 'invalid-frontmatter',\n message: `frontmatter 解析失败 (${absPath}): ${error}`,\n affected: [absPath],\n })\n }\n\n const aliases = normalizeAliases(data.aliases)\n const tags = normalizeTags(data.tags)\n const headings = collectHeadings(content, options.slugify)\n const rel = relativePath(index.srcDir, absPath)\n const base = basename(absPath, true)\n const ext = extname(absPath)\n const url = computeUrl(rel, options)\n\n const entry: FileEntry = {\n absolutePath: absPath,\n relativePath: rel,\n basename: base,\n extension: ext,\n url,\n frontmatter: data,\n aliases,\n tags,\n headings,\n mtime,\n size,\n content,\n }\n\n registerFileEntry(index, entry, options)\n}\n\n/**\n * 把一个 asset 文件加入索引。\n */\nfunction ingestAsset(\n index: VaultIndex,\n absPath: string,\n size: number,\n mtime: number,\n ext: string,\n): void {\n const rel = relativePath(index.srcDir, absPath)\n const base = basename(absPath)\n\n const entry: AssetEntry = {\n absolutePath: absPath,\n relativePath: rel,\n basename: base,\n extension: ext,\n mtime,\n size,\n referencedBy: new Set(),\n }\n\n index.assets.set(absPath, entry)\n index.assetsByRelativePath.set(rel, entry)\n pushToArrayMap(index.assetsByBasename, base, entry)\n pushToArrayMap(index.assetsByBasenameLower, base.toLowerCase(), entry)\n}\n\n/**\n * 把 FileEntry 写进所有查找索引。\n */\nfunction registerFileEntry(\n index: VaultIndex,\n entry: FileEntry,\n options: ResolvedOptions,\n): void {\n index.files.set(entry.absolutePath, entry)\n index.byRelativePath.set(entry.relativePath, entry)\n\n // URL 冲突:多文件指向同一 URL(常见原因:index.md 和 README.md 并存,\n // 它们都路由到 '/'。VitePress 会让其中一个 404)\n const existingAtUrl = index.byUrl.get(entry.url)\n if (existingAtUrl && existingAtUrl.absolutePath !== entry.absolutePath) {\n index.warnings.push({\n kind: 'unknown',\n message:\n `URL 冲突:文件 \"${entry.relativePath}\" 和 \"${existingAtUrl.relativePath}\" ` +\n `都路由到 \"${entry.url}\"。VitePress 会让其中一个 404。` +\n `建议在 .vitepress/config 加 srcExclude: ['${entry.relativePath}'](或另一个)。`,\n affected: [existingAtUrl.absolutePath, entry.absolutePath],\n })\n }\n index.byUrl.set(entry.url, entry)\n index.headings.set(entry.absolutePath, entry.headings)\n\n pushToArrayMap(index.byBasename, entry.basename, entry)\n pushToArrayMap(index.byBasenameLower, entry.basename.toLowerCase(), entry)\n\n for (const alias of entry.aliases) {\n const key = options.caseSensitive ? alias : alias.toLowerCase()\n if (index.byAlias.has(key)) {\n index.warnings.push({\n kind: 'duplicate-alias',\n message: `alias \"${alias}\" 同时被多个文件声明,按 onAliasConflict='${options.onAliasConflict}' 处理`,\n affected: [index.byAlias.get(key)!.absolutePath, entry.absolutePath],\n })\n if (options.onAliasConflict === 'first') continue\n // 'error' 由调用方在 build 时检查 warnings 决定是否抛\n }\n index.byAlias.set(key, entry)\n }\n\n for (const tag of entry.tags) {\n pushToArrayMap(index.tags, tag, entry)\n }\n}\n\n/**\n * 从 relativePath 计算 VitePress URL。\n *\n * - index.md / README.md → 目录根(`/` 或 `/dir/`)\n * (VitePress 默认把这两个文件都路由到目录根,所以同一目录下若两者并存\n * 会冲突,scanVault 末尾会有 URL 冲突告警)\n * - foo.md → /dir/foo (或 /dir/foo.html when !cleanUrls)\n */\nfunction computeUrl(rel: string, options: ResolvedOptions): string {\n const noExt = rel.replace(/\\.(md|markdown)$/i, '')\n // index.md / README.md 特殊处理:URL 为父目录\n const isIndex = /(^|\\/)(index|README)$/i.test(noExt)\n const pathPart = isIndex ? noExt.replace(/(^|\\/)(index|README)$/i, '$1') : noExt\n\n // 路径段切片,各段 buildUrl 时再编码\n const segments = pathPart.split('/').filter(Boolean)\n if (segments.length === 0) {\n // 根 index.md —— **不带 base**(VitePress 会自动 prepend)\n return '/'\n }\n\n // 应用 cleanUrls(若 false,末尾加 .html)\n const last = segments[segments.length - 1]!\n if (!isIndex) {\n segments[segments.length - 1] = applyCleanUrls(last, options.cleanUrls)\n } else if (!options.cleanUrls) {\n segments.push('index.html')\n }\n\n // ⚠ 关键:始终不带 base(用 '/' 做 site-root 相对 URL)。\n // VitePress 在 render 阶段对所有 sidebar/nav link + markdown link 自动\n // prepend base —— 带了会双重 prefix(GitHub Pages 等子路径部署 404)。\n return buildUrl('/', segments)\n}\n\n/** Map<K, V[]> push 工具 */\nfunction pushToArrayMap<K, V>(m: Map<K, V[]>, k: K, v: V): void {\n const arr = m.get(k)\n if (arr) arr.push(v)\n else m.set(k, [v])\n}\n\n/**\n * 增量更新:单个文件改了。\n * 把旧 entry 从所有索引清掉,再走 ingest。\n */\nexport function updateFile(\n index: VaultIndex,\n absPath: string,\n options: ResolvedOptions,\n): void {\n const posix = toPosix(absPath)\n removeFile(index, posix, options)\n let stat: fs.Stats\n try {\n stat = fs.statSync(posix)\n } catch {\n return\n }\n const ext = extname(posix)\n if (MD_EXTENSIONS.has(ext)) {\n ingestMarkdown(index, posix, stat.size, stat.mtimeMs, options)\n } else if (\n new Set(options.scan.assetExtensions.map((e) => e.toLowerCase())).has(ext)\n ) {\n ingestAsset(index, posix, stat.size, stat.mtimeMs, ext)\n }\n}\n\n/**\n * 增量更新:单个文件被删。\n */\nexport function removeFile(\n index: VaultIndex,\n absPath: string,\n options: ResolvedOptions,\n): void {\n const posix = toPosix(absPath)\n\n // 试 file\n const file = index.files.get(posix)\n if (file) {\n index.files.delete(posix)\n index.byRelativePath.delete(file.relativePath)\n index.byUrl.delete(file.url)\n index.headings.delete(posix)\n removeFromArrayMap(index.byBasename, file.basename, file)\n removeFromArrayMap(\n index.byBasenameLower,\n file.basename.toLowerCase(),\n file,\n )\n for (const alias of file.aliases) {\n const key = options.caseSensitive ? alias : alias.toLowerCase()\n if (index.byAlias.get(key) === file) index.byAlias.delete(key)\n }\n for (const tag of file.tags) {\n removeFromArrayMap(index.tags, tag, file)\n }\n return\n }\n\n // 试 asset\n const asset = index.assets.get(posix)\n if (asset) {\n index.assets.delete(posix)\n index.assetsByRelativePath.delete(asset.relativePath)\n removeFromArrayMap(index.assetsByBasename, asset.basename, asset)\n removeFromArrayMap(\n index.assetsByBasenameLower,\n asset.basename.toLowerCase(),\n asset,\n )\n }\n}\n\nfunction removeFromArrayMap<K, V>(m: Map<K, V[]>, k: K, v: V): void {\n const arr = m.get(k)\n if (!arr) return\n const idx = arr.indexOf(v)\n if (idx >= 0) arr.splice(idx, 1)\n if (arr.length === 0) m.delete(k)\n}\n\n/**\n * 多条目按\"路径深度浅 → 路径字典序\"排序的 helper,供 Resolver 'shortest' 用。\n */\nexport function sortByShortestPath<T extends { relativePath: string }>(\n items: T[],\n): T[] {\n return [...items].sort((a, b) => {\n const da = pathDepth(a.relativePath)\n const db = pathDepth(b.relativePath)\n if (da !== db) return da - db\n return a.relativePath.localeCompare(b.relativePath)\n })\n}\n\n","/**\n * 跨平台 POSIX 路径工具。\n *\n * 设计原则:\n * - 内部所有路径都用 POSIX 风格(正斜杠);进出 OS 边界才转换。\n * - 我们的索引 key 永远是 POSIX,不依赖运行平台。\n */\n\nimport nodePath from 'node:path'\n\n/** 把任意路径转成 POSIX 风格(替换 \\\\ 为 /)*/\nexport function toPosix(p: string): string {\n return p.replace(/\\\\/g, '/')\n}\n\n/** 计算相对路径,POSIX 风格 */\nexport function relative(from: string, to: string): string {\n return toPosix(nodePath.relative(from, to))\n}\n\n/** POSIX join */\nexport function posixJoin(...parts: string[]): string {\n return parts\n .filter((p) => p && p.length > 0)\n .map((p, i) => {\n let s = toPosix(p)\n if (i > 0) s = s.replace(/^\\/+/, '')\n if (i < parts.length - 1) s = s.replace(/\\/+$/, '')\n return s\n })\n .join('/')\n}\n\n/** 去掉尾部 .md / .markdown(若有);其它扩展名保留 */\nexport function stripMarkdownExt(target: string): string {\n return target.replace(/\\.(md|markdown)$/i, '')\n}\n\n/** 取 POSIX 风格 basename,可选去扩展 */\nexport function basename(p: string, stripExt = false): string {\n const idx = p.lastIndexOf('/')\n const file = idx === -1 ? p : p.slice(idx + 1)\n if (!stripExt) return file\n const dot = file.lastIndexOf('.')\n return dot <= 0 ? file : file.slice(0, dot)\n}\n\n/** 取扩展名(不含点,小写);无扩展返回 '' */\nexport function extname(p: string): string {\n const file = basename(p)\n const dot = file.lastIndexOf('.')\n if (dot <= 0) return ''\n return file.slice(dot + 1).toLowerCase()\n}\n\n/** 把 path 用 / 拆开,过滤空段 */\nexport function splitPath(p: string): string[] {\n return toPosix(p).split('/').filter(Boolean)\n}\n\n/** 路径深度(段数),用于 onConflict: 'shortest' */\nexport function pathDepth(relPath: string): number {\n return splitPath(relPath).length\n}\n\n/** 把绝对路径正规化为 POSIX */\nexport function normalizeAbs(p: string): string {\n return toPosix(nodePath.resolve(p))\n}\n","/**\n * URL 拼接 / 编码工具。\n *\n * 关键设计:\n * - 站内 URL 永远是绝对路径 + base 前缀;\n * - 路径段做 URI 编码(空格、中文 → %xx),但保留 '/' 和 '#';\n * - 输出的 URL 仍是字符串,attr 写入时再做 HTML escape(escape.ts 负责)。\n */\n\n/**\n * 给一段路径做 URL 编码,但保留 '/' 和 '#'。\n *\n * `encodeURI` 默认就保留 '/'、'#'、'?' 等,但会保留 '%' —— 我们假设传入的是\n * 原始路径(未编码),所以直接 encodeURI 就行。\n */\nexport function encodePath(s: string): string {\n return encodeURI(s)\n}\n\n/**\n * 拼接 base + 路径段(单个或多个)+ 可选锚点,产出最终 URL。\n *\n * - 多余的 '/' 会被折叠;\n * - 空段被跳过;\n * - 始终以 base 开头(若 base 提供);\n * - cleanUrls=false 时调用方负责加 '.html' 后缀(我们这里不管)。\n */\nexport function buildUrl(\n base: string,\n pathSegments: string[],\n anchor?: string,\n): string {\n // 归一化 base:确保以 / 开头并以 / 结尾\n let normBase = base || '/'\n if (!normBase.startsWith('/')) normBase = '/' + normBase\n if (!normBase.endsWith('/')) normBase = normBase + '/'\n\n // 拼接路径段(过滤空、去段头尾的 /)\n const joined = pathSegments\n .map((s) => s.replace(/^\\/+|\\/+$/g, ''))\n .filter(Boolean)\n .join('/')\n\n let url = normBase + joined\n // 折叠相邻多 /\n url = url.replace(/\\/{2,}/g, '/')\n // URI 编码(空格、中文)\n url = encodePath(url)\n\n if (anchor) {\n // anchor 也要编码,但不再处理 /\n url += '#' + encodeURIComponent(anchor).replace(/%2F/g, '/')\n }\n return url\n}\n\n/**\n * 给路径加上 cleanUrls 决定的扩展名。\n *\n * cleanUrls=true:不加任何后缀(VitePress 生成 .html 但路由用无扩展)。\n * cleanUrls=false:加 '.html'。\n *\n * 调用方应该在 buildUrl 之前对 path 段调用本函数(或之后再追加 .html)。\n */\nexport function applyCleanUrls(path: string, cleanUrls: boolean): string {\n if (cleanUrls) return path\n if (/\\.html$/i.test(path)) return path\n // 末尾的 / 表示目录路由,index.html\n if (path.endsWith('/')) return path + 'index.html'\n return path + '.html'\n}\n","/**\n * 文件系统遍历。\n *\n * 同步遍历 srcDir,产出绝对路径列表。性能预算:\n * - 10k 文件 / 千级目录,< 1s。\n * - 同步 fs(我们就一份索引,build/dev 启动时一次性建,简单可靠)。\n */\n\nimport fs from 'node:fs'\nimport nodePath from 'node:path'\nimport { toPosix, extname } from '../../utils/path.js'\n\nexport interface WalkEntry {\n absolutePath: string // POSIX 风格\n size: number\n mtime: number\n extension: string\n}\n\n/**\n * 递归遍历 srcDir,返回所有非忽略的文件条目。\n *\n * @param srcDir 绝对路径\n * @param isIgnored 判定函数\n * @param followSymlinks 是否跟随符号链接(默认 false)\n */\nexport function walk(\n srcDir: string,\n isIgnored: (absPath: string) => boolean,\n followSymlinks: boolean,\n): WalkEntry[] {\n const out: WalkEntry[] = []\n const seenInodes = new Set<string>() // 防符号链接环\n\n function visit(dir: string): void {\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true })\n } catch {\n return\n }\n\n for (const ent of entries) {\n const full = nodePath.join(dir, ent.name)\n const posix = toPosix(full)\n if (isIgnored(posix)) continue\n\n let isDir = ent.isDirectory()\n let isFile = ent.isFile()\n\n if (ent.isSymbolicLink()) {\n if (!followSymlinks) continue\n try {\n const stat = fs.statSync(full)\n isDir = stat.isDirectory()\n isFile = stat.isFile()\n } catch {\n continue\n }\n }\n\n if (isDir) {\n if (followSymlinks) {\n try {\n const stat = fs.statSync(full)\n const key = `${stat.dev}:${stat.ino}`\n if (seenInodes.has(key)) continue\n seenInodes.add(key)\n } catch {\n // 取不到 stat 就跳过\n continue\n }\n }\n visit(full)\n } else if (isFile) {\n try {\n const stat = fs.statSync(full)\n out.push({\n absolutePath: posix,\n size: stat.size,\n mtime: stat.mtimeMs,\n extension: extname(posix),\n })\n } catch {\n // 读不到 stat 就跳过\n }\n }\n }\n }\n\n visit(srcDir)\n return out\n}\n","/**\n * 文件忽略规则。\n *\n * 默认忽略列表针对\"VitePress 文档站 + Obsidian vault\"的典型布局,\n * 用户可通过 ResolvedOptions.scan.exclude 追加。\n */\n\nimport fs from 'node:fs'\nimport nodePath from 'node:path'\nimport picomatch from 'picomatch'\nimport { relative, toPosix } from '../../utils/path.js'\n\n/** 始终忽略,不可关闭 */\nexport const HARD_IGNORE_DIRS = new Set([\n 'node_modules',\n '.git',\n '.svn',\n '.hg',\n '.obsidian',\n '.trash',\n '.vitepress',\n '.next',\n '.nuxt',\n '.cache',\n '.idea',\n '.vscode',\n 'dist',\n 'build',\n])\n\n/**\n * 构造一个 (absolutePath) => boolean 的\"是否忽略\"判定函数。\n *\n * @param srcDir 扫描根目录(绝对路径)\n * @param userExclude 用户额外的 glob 列表\n * @param respectGitignore 是否读 srcDir/.gitignore\n */\nexport function buildIgnorer(\n srcDir: string,\n userExclude: string[],\n respectGitignore: boolean,\n): (absPath: string) => boolean {\n const patterns: string[] = [...userExclude]\n if (respectGitignore) {\n const gitignore = nodePath.join(srcDir, '.gitignore')\n try {\n const content = fs.readFileSync(gitignore, 'utf8')\n for (const line of content.split(/\\r?\\n/)) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith('#')) continue\n // .gitignore 规则不完全等价于 picomatch 的 glob,\n // 但对常见 'dist/'、'*.log' 这类够用了。\n patterns.push(trimmed.endsWith('/') ? trimmed + '**' : trimmed)\n }\n } catch {\n // .gitignore 不存在或不可读 —— 静默跳过\n }\n }\n\n const matchers = patterns.map((p) =>\n picomatch(p, { dot: true, nocase: false }),\n )\n\n return (absPath: string): boolean => {\n const rel = toPosix(relative(srcDir, absPath))\n if (!rel || rel.startsWith('..')) return true\n\n // 硬忽略:任意路径段命中即忽略\n for (const seg of rel.split('/')) {\n if (HARD_IGNORE_DIRS.has(seg)) return true\n }\n\n // 用户/gitignore 规则\n for (const m of matchers) {\n if (m(rel)) return true\n }\n return false\n }\n}\n","/**\n * frontmatter 解析。\n *\n * 用 gray-matter,Obsidian 和 Astro 都用它,YAML 兼容性好。\n * 解析失败时返回空 frontmatter + 原文,落 warning。\n */\n\nimport matter from 'gray-matter'\n\nexport interface ParsedFrontmatter {\n /** 解析后的 frontmatter 对象,失败时为空对象 */\n data: Record<string, unknown>\n /** 去掉 frontmatter 之后的正文 */\n content: string\n /** 解析错误信息,成功为 undefined */\n error?: string\n}\n\nexport function parseFrontmatter(raw: string): ParsedFrontmatter {\n try {\n const { data, content } = matter(raw)\n return { data: (data ?? {}) as Record<string, unknown>, content }\n } catch (err) {\n return {\n data: {},\n content: raw,\n error: err instanceof Error ? err.message : String(err),\n }\n }\n}\n\n/**\n * 把 frontmatter.aliases 归一化为字符串数组。支持:\n * - undefined / null → []\n * - string → [string]\n * - string[] → 原样过滤空字符串\n * - 其它 → []\n */\nexport function normalizeAliases(raw: unknown): string[] {\n if (raw == null) return []\n if (typeof raw === 'string') return raw.trim() ? [raw.trim()] : []\n if (Array.isArray(raw)) {\n return raw\n .filter((v): v is string => typeof v === 'string')\n .map((s) => s.trim())\n .filter(Boolean)\n }\n return []\n}\n\n/**\n * 把 frontmatter.tags 归一化为字符串数组(同上规则)。\n */\nexport function normalizeTags(raw: unknown): string[] {\n if (raw == null) return []\n if (typeof raw === 'string') {\n return raw\n .split(/[,\\s]+/)\n .map((s) => s.trim().replace(/^#/, ''))\n .filter(Boolean)\n }\n if (Array.isArray(raw)) {\n return raw\n .filter((v): v is string => typeof v === 'string')\n .map((s) => s.trim().replace(/^#/, ''))\n .filter(Boolean)\n }\n return []\n}\n","/**\n * Heading 收集。\n *\n * 不引入完整 markdown-it 单纯为了收 heading —— 自己用正则扫,够快、零依赖。\n * 处理 ATX 风格(# / ## / ###),不处理 Setext(`===` / `---` 下划线风格,\n * Obsidian / VitePress 实际都极少用)。\n *\n * 识别 `{#custom-id}` 自定义 anchor 语法。\n */\n\nimport type { HeadingEntry } from '../types.js'\nimport { extractCustomId } from '../slugify.js'\n\nconst HEADING_RE = /^(#{1,6})\\s+(.+?)\\s*$/\nconst FENCE_RE = /^(`{3,}|~{3,})/\n\n/**\n * 从源文件正文(去掉 frontmatter 之后)收集 heading。\n *\n * @param content 正文\n * @param slugify 与 VitePress 一致的 slug 函数\n */\nexport function collectHeadings(\n content: string,\n slugify: (text: string) => string,\n): HeadingEntry[] {\n const lines = content.split(/\\r?\\n/)\n const out: HeadingEntry[] = []\n\n let inFence = false\n let fenceMarker = ''\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!\n\n // 跳过代码块内部\n const fenceMatch = line.match(FENCE_RE)\n if (fenceMatch) {\n if (!inFence) {\n inFence = true\n fenceMarker = fenceMatch[1]!\n } else if (line.startsWith(fenceMarker)) {\n inFence = false\n fenceMarker = ''\n }\n continue\n }\n if (inFence) continue\n\n const m = line.match(HEADING_RE)\n if (!m) continue\n\n const level = m[1]!.length\n const rawText = m[2]!\n const { text, customId } = extractCustomId(rawText)\n const slug = customId ?? slugify(text)\n\n out.push({ level, text, slug, line: i })\n }\n\n return out\n}\n","/**\n * Resolver —— 把 wikilink target 解析成最终 URL。\n *\n * 解析顺序(对应 PLAN §5):\n * 1. trim、剥 .md/.markdown\n * 2. 拆 #heading\n * 3. 含 '/' → 按 byRelativePath 查\n * 4. 不含 '/' → byAlias → byBasename(冲突按 onConflict)\n * 5. heading 匹配 → 加 anchor;否则标记半死链\n */\n\nimport type {\n VaultIndex,\n ResolvedOptions,\n ResolveResult,\n FileEntry,\n} from './types.js'\nimport { sortByShortestPath } from './vault/index.js'\nimport { stripMarkdownExt, toPosix, basename } from '../utils/path.js'\n\n/**\n * 解析一个 wikilink target(已经从 [[]] / ![[]] 中取出的 raw 字符串,不含 pipe 部分)。\n *\n * @param rawTarget 例如 \"notes/a\" / \"a\" / \"a#heading\" / \"中文笔记\"\n * @param index vault 索引\n * @param options 已解析配置\n * @param kind 'page' | 'image' | 'transclusion';v0.1 image 走单独路径,这里\n * 只处理 'page' / 'transclusion'\n */\nexport function resolveWikilink(\n rawTarget: string,\n index: VaultIndex,\n options: ResolvedOptions,\n kind: 'page' | 'transclusion' = 'page',\n /** 写这个 wikilink 的源文件绝对路径(用于相对路径 fallback) */\n currentSourcePath?: string,\n): ResolveResult {\n // 1. 归一化:反斜杠 → 正斜杠、剥 markdown 扩展、trim\n let target = toPosix(rawTarget).trim()\n // 2. 拆 #heading\n const hashIdx = target.indexOf('#')\n let headingPart = ''\n if (hashIdx >= 0) {\n headingPart = target.slice(hashIdx + 1).trim()\n target = target.slice(0, hashIdx).trim()\n }\n // 剥 .md / .markdown\n target = stripMarkdownExt(target)\n\n // 3-4. 查 entry\n const entry = lookupEntry(target, index, options, currentSourcePath)\n\n if (!entry) {\n return {\n url: buildDeadUrl(rawTarget, options),\n defaultLabel: defaultLabel(target, headingPart, undefined, options),\n isDead: true,\n hasUnmatchedAnchor: false,\n kind,\n }\n }\n\n // 5. heading 匹配\n let url = entry.url\n let hasUnmatchedAnchor = false\n if (headingPart) {\n const heading = entry.headings.find(\n (h) =>\n h.text === headingPart ||\n h.slug === headingPart ||\n h.slug === options.slugify(headingPart),\n )\n if (heading) {\n url = entry.url + '#' + heading.slug\n } else {\n hasUnmatchedAnchor = true\n url = entry.url + '#' + encodeURIComponent(headingPart)\n }\n }\n\n return {\n url,\n defaultLabel: defaultLabel(target, headingPart, entry, options),\n isDead: false,\n hasUnmatchedAnchor,\n target: entry,\n kind,\n }\n}\n\n/**\n * 查目标 entry:含 '/' 按 byRelativePath,否则 byAlias → byBasename(冲突按策略)。\n */\nfunction lookupEntry(\n target: string,\n index: VaultIndex,\n options: ResolvedOptions,\n currentSourcePath?: string,\n): FileEntry | undefined {\n if (!target) return undefined\n\n // 含 '/':按路径查\n if (target.includes('/')) {\n // 用户写 'notes/a' → 找 'notes/a.md' 或 'notes/a.markdown'\n const variants = [\n target,\n target + '.md',\n target + '.markdown',\n target + '/index.md',\n target + '/index.markdown',\n ]\n for (const v of variants) {\n const e = index.byRelativePath.get(v)\n if (e) return e\n }\n // Fallback:相对当前 source 文件目录(模仿 Obsidian 行为)\n if (currentSourcePath) {\n // currentSourcePath 是绝对路径,先转 vault 相对再拼\n const srcDirAbs = index.srcDir\n const rel = toPosix(currentSourcePath).startsWith(srcDirAbs + '/')\n ? toPosix(currentSourcePath).slice(srcDirAbs.length + 1)\n : ''\n if (rel) {\n const curDir = rel.split('/').slice(0, -1).join('/')\n if (curDir) {\n const relVariants = [\n `${curDir}/${target}`,\n `${curDir}/${target}.md`,\n `${curDir}/${target}.markdown`,\n `${curDir}/${target}/index.md`,\n `${curDir}/${target}/index.markdown`,\n ]\n for (const v of relVariants) {\n const e = index.byRelativePath.get(v)\n if (e) return e\n }\n }\n }\n }\n return undefined\n }\n\n // 不含 '/':先 alias\n const aliasKey = options.caseSensitive ? target : target.toLowerCase()\n const aliased = index.byAlias.get(aliasKey)\n if (aliased) return aliased\n\n // 再 basename\n const bnMap = options.caseSensitive\n ? index.byBasename\n : index.byBasenameLower\n const bnKey = options.caseSensitive ? target : target.toLowerCase()\n const candidates = bnMap.get(bnKey)\n if (!candidates || candidates.length === 0) return undefined\n if (candidates.length === 1) return candidates[0]!\n\n // 多个 → onConflict\n switch (options.onConflict) {\n case 'shortest': {\n const sorted = sortByShortestPath(candidates)\n return sorted[0]!\n }\n case 'first':\n return candidates[0]!\n case 'error':\n // build 时由调用方根据 deadLink 决定;这里返回 undefined → 当作死链\n return undefined\n }\n}\n\n/**\n * 死链 URL —— 给一个尽量接近用户意图的 href,便于用户点开诊断。\n * 不抛错,渲染时附 wikilink--dead class。\n */\nfunction buildDeadUrl(rawTarget: string, options: ResolvedOptions): string {\n // 把 raw 字符串原样编码进 URL,带个 sentinel hash 让用户一眼能看出\n const safe = encodeURIComponent(stripMarkdownExt(rawTarget).split('#')[0]!)\n return options.base + safe\n}\n\n/**\n * 计算默认 label。\n * - 用户传了 alias 优先,这里只算\"没有 alias 时\" fallback。\n * - linkText='basename' / 'fullPath' / 自定义函数\n * - 带 heading 时:basename > heading\n */\nfunction defaultLabel(\n target: string,\n headingPart: string,\n entry: FileEntry | undefined,\n options: ResolvedOptions,\n): string {\n const lt = options.wikilinks.linkText\n let base: string\n if (typeof lt === 'function') {\n if (entry) {\n base = lt(entry, target)\n } else {\n // 死链时拿不到 entry,降级到 raw target 的 basename\n base = basename(target)\n }\n } else if (lt === 'fullPath') {\n base = entry ? entry.relativePath.replace(/\\.(md|markdown)$/i, '') : target\n } else {\n // 'basename'\n base = entry ? entry.basename : basename(target)\n }\n if (headingPart) {\n // Obsidian 风格 \"basename > 章节\"\n return `${base} > ${headingPart}`\n }\n return base\n}\n\n/**\n * 解析 image embed target → AssetEntry。\n * 与 resolveWikilink 类似,但走 assets 索引。\n */\nexport function resolveAsset(\n rawTarget: string,\n index: VaultIndex,\n options: ResolvedOptions,\n): {\n asset: import('./types.js').AssetEntry | undefined\n rawBasename: string\n} {\n const target = toPosix(rawTarget).trim()\n // 含 '/':按 assetsByRelativePath 查\n if (target.includes('/')) {\n return {\n asset: index.assetsByRelativePath.get(target),\n rawBasename: basename(target),\n }\n }\n const bn = options.caseSensitive ? target : target.toLowerCase()\n const map = options.caseSensitive\n ? index.assetsByBasename\n : index.assetsByBasenameLower\n const candidates = map.get(bn)\n if (!candidates || candidates.length === 0) {\n return { asset: undefined, rawBasename: target }\n }\n if (candidates.length === 1) {\n return { asset: candidates[0], rawBasename: target }\n }\n // 多个 asset 同名 → 也走 onConflict\n switch (options.onConflict) {\n case 'shortest': {\n const sorted = sortByShortestPath(candidates)\n return { asset: sorted[0], rawBasename: target }\n }\n case 'first':\n return { asset: candidates[0], rawBasename: target }\n case 'error':\n return { asset: undefined, rawBasename: target }\n }\n}\n","/**\n * wikilinks 渲染辅助 —— 把解析结果落成 markdown-it tokens。\n */\n\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type {\n ResolveResult,\n AllYouNeedEnv,\n PageLinkAttrs,\n PageLinkAttrsContext,\n} from '../../core/types.js'\n\n/**\n * 渲染正常 wikilink(`[[Page]]`、`[[Page|alias]]`、`[[Page#heading]]`)。\n */\nexport function renderPageLink(\n state: StateInline,\n result: ResolveResult,\n label: string,\n env: AllYouNeedEnv,\n): boolean {\n const open = state.push('link_open', 'a', 1)\n const classes = ['wikilink']\n if (result.hasUnmatchedAnchor) classes.push('wikilink--unmatched-anchor')\n\n const baseAttrs: Record<string, string> = {\n href: result.url,\n class: classes.join(' '),\n 'data-wikilink-target': result.target\n ? result.target.relativePath\n : '',\n }\n\n const extra = resolveExtraAttrs(env.options.wikilinks.htmlAttributes, {\n originalHref: result.url,\n label,\n target: result.target,\n isDead: result.isDead,\n hasUnmatchedAnchor: result.hasUnmatchedAnchor,\n })\n\n applyAttrs(open, baseAttrs, extra)\n\n // label 渲染:默认走 text token(安全);allowLinkLabelFormatting=true 时\n // 走 inline 解析,但带递归保护。\n emitLabel(state, label, env)\n\n state.push('link_close', 'a', -1)\n return true\n}\n\n/**\n * 渲染死链:**不输出 href**,避免点击跳转到不存在的页面误导用户。\n * 用 <a class=\"wikilink wikilink--dead\"> 不带 href → 视觉是链接、CSS 标红删除线、\n * 鼠标 cursor: not-allowed 提示;**不可点**。\n *\n * 仍把 raw target 写到 data-attr 上方便用户自查;title 是 hover 提示。\n */\nexport function renderDeadLink(\n state: StateInline,\n url: string,\n label: string,\n rawTarget: string,\n env: AllYouNeedEnv,\n): boolean {\n const open = state.push('link_open', 'a', 1)\n const baseAttrs: Record<string, string> = {\n // ⚠ 不写 href:点击不会跳转\n class: 'wikilink wikilink--dead',\n 'data-wikilink-target': rawTarget,\n title: `死链:找不到 [[${rawTarget}]]`,\n }\n const extra = resolveExtraAttrs(env.options.wikilinks.htmlAttributes, {\n originalHref: url,\n label,\n target: undefined,\n isDead: true,\n hasUnmatchedAnchor: false,\n })\n applyAttrs(open, baseAttrs, extra)\n\n emitLabel(state, label, env)\n\n state.push('link_close', 'a', -1)\n return true\n}\n\n/**\n * 推 label 文本 token(或 inline 解析的结果)。\n */\nfunction emitLabel(\n state: StateInline,\n label: string,\n env: AllYouNeedEnv,\n): void {\n if (env.options.wikilinks.allowLinkLabelFormatting) {\n // 递归保护:env 上挂一个深度计数,超过 3 直接回退到 text\n const depth = (env as unknown as { _labelDepth?: number })._labelDepth ?? 0\n if (depth < 3) {\n ;(env as unknown as { _labelDepth?: number })._labelDepth = depth + 1\n const md = state.md\n const html = md.renderInline(label, env)\n const token = state.push('html_inline', '', 0)\n token.content = html\n ;(env as unknown as { _labelDepth?: number })._labelDepth = depth\n return\n }\n }\n const t = state.push('text', '', 0)\n t.content = label\n}\n\n/**\n * 合并用户 htmlAttributes(函数或对象)。\n */\nfunction resolveExtraAttrs(\n htmlAttrs: PageLinkAttrs,\n ctx: PageLinkAttrsContext,\n): Record<string, string> {\n if (typeof htmlAttrs === 'function') return htmlAttrs(ctx)\n return htmlAttrs ?? {}\n}\n\n/**\n * 把 base + extra 应用到 token,extra 中重复的 key 覆盖 base\n * (例外:class 做合并而非覆盖)。\n */\nfunction applyAttrs(\n token: { attrSet(k: string, v: string): void },\n base: Record<string, string>,\n extra: Record<string, string>,\n): void {\n const merged: Record<string, string> = { ...base }\n for (const [k, v] of Object.entries(extra)) {\n if (k === 'class' && merged.class) {\n merged.class = merged.class + ' ' + v\n } else {\n merged[k] = v\n }\n }\n for (const [k, v] of Object.entries(merged)) {\n token.attrSet(k, v)\n }\n}\n","/**\n * HTML escape。\n *\n * 这里不依赖 markdown-it 的 md.utils.escapeHtml,因为我们的工具可能\n * 在 markdown-it 之外被调用(例如 build-emit 写 HTML 占位符)。\n */\nconst HTML_ESCAPE_MAP: Record<string, string> = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n}\n\nconst HTML_ESCAPE_RE = /[&<>\"']/g\n\nexport function escapeHtml(s: string): string {\n return s.replace(HTML_ESCAPE_RE, (c) => HTML_ESCAPE_MAP[c]!)\n}\n","/**\n * Asset 占位符 URL + dev 公开 URL helpers。\n *\n * 工作流(v0.1):\n * 1. markdown-it 渲染 ![[image.png]] 时,image.ts 调 buildPlaceholderUrl 出\n * `<img src=\"/__ayn_asset__/<encoded-relPath>\">`,并把 AssetEntry 登记。\n * 2. Vite 编译 .md→.vue 时 Vue compiler 把 `<img src>` 转成 import;Vite 的\n * import-analysis 走 resolveId → 我们插件在 src/vite.ts 拦截这个 URL。\n * 3. dev:resolveId 返回虚拟模块,load 导出 `buildPublicUrl(asset)` —— URL\n * 点回 vault asset(由 dev-middleware 流式响应)。\n * 4. build:load 调 `this.emitFile` 把文件丢给 Rollup,导出\n * `import.meta.ROLLUP_FILE_URL_<id>` —— Rollup 自动算 hash 并替换。\n *\n * 没有 transformIndexHtml/后期字符串替换的路径 —— 全部走标准 Vite 资源管线。\n */\n\nimport type { AssetEntry, ResolvedOptions } from '../types.js'\nimport { basename } from '../../utils/path.js'\n\n/** 占位符 URL 前缀,不会出现在合法 URL 里 */\nexport const ASSET_PLACEHOLDER_PREFIX = '/__ayn_asset__/'\n\n/**\n * 给 asset 构造占位符 URL,markdown-it 渲染阶段使用。\n * 形如 `/__ayn_asset__/<encoded relativePath>`(base 前置)。\n *\n * **用 encodeURI 而不是 encodeURIComponent** —— 我们希望保留 `/` 不被编码成 `%2F`。\n * 原因:Vite 在内部把 URL 路径中的 `%2F` 解码回 `/`,导致 resolveId/load 收到的 id\n * 时而带 `%2F` 时而带 `/`,匹配 byRelativePath 不稳定。统一用 encodeURI 让路径段\n * 保留 `/`,resolveId/load 拿到的 id 总是 `/` 形式,行为稳定。\n */\nexport function buildPlaceholderUrl(\n asset: AssetEntry,\n options: ResolvedOptions,\n): string {\n const id = encodeURI(asset.relativePath)\n return options.base + ASSET_PLACEHOLDER_PREFIX.slice(1) + id\n}\n\n/**\n * dev 模式下 asset 的最终公开 URL。\n *\n * - preserveAssetPaths=false(默认):URL = base + basename\n * - preserveAssetPaths=true:URL = base + relativePath\n *\n * 这俩 dev-middleware 都能服务(basename + relativePath 双查找)。\n */\nexport function buildPublicUrl(\n asset: AssetEntry,\n options: ResolvedOptions,\n): string {\n const path = options.assets.preserveAssetPaths\n ? asset.relativePath\n : basename(asset.absolutePath)\n return options.base + encodeURI(path)\n}\n","/**\n * image embed:`![[image.png]]`、`![[image.png|alt]]`、\n * `![[image.png|300]]`、`![[image.png|x200]]`、`![[image.png|300x200]]`、\n * `![[image.png|alt|300x200]]`。\n *\n * 实现说明:\n * - 渲染为 `<img>` HTML 字符串(`renderImageHtml`)。\n * - inline 场景:外层用 `html_inline` token 包(图片本身是 inline 元素,\n * 和段落文本混排 OK)。\n * - block 场景:外层用 `html_block` token 包(整行只有 ![[image]] 时,\n * 避免被多余 `<p>` 包裹)。\n * - **不用 markdown-it 的 'image' token**:默认渲染器假设 attrs 数组里一定\n * 有 'alt' 项,若没设会 `attrs[-1] = ...` 崩溃。\n */\n\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type {\n AllYouNeedEnv,\n ImageEmbedAttrs,\n ImageEmbedAttrsContext,\n} from '../../core/types.js'\nimport { resolveAsset } from '../../core/resolver.js'\nimport { basename } from '../../utils/path.js'\nimport { escapeHtml } from '../../utils/escape.js'\nimport {\n buildPlaceholderUrl,\n buildPublicUrl,\n} from '../../core/asset-pipeline/build-emit.js'\n\n// ── 公共渲染:返回 <img> 标签字符串 ───────────────────────────────\n\n/**\n * 把 ![[image|...]] 渲染为完整的 `<img>` HTML 字符串。\n * 不向 markdown-it state 推 token;调用方决定用 html_inline 还是 html_block。\n */\nexport function renderImageHtml(\n rawTarget: string,\n aliasParts: string[],\n env: AllYouNeedEnv,\n): string {\n const { index, options } = env\n\n const { altText, dim } = parseAltAndDim(aliasParts)\n\n const processedTarget = options.embeds.postProcessImageTarget(rawTarget)\n const { asset } = resolveAsset(processedTarget, index, options)\n\n let src: string\n if (asset) {\n asset.referencedBy.add(env.currentPath ?? '<unknown>')\n env.referencedAssets?.add(asset)\n src = buildPlaceholderUrl(asset, options) + options.embeds.uriSuffix\n } else {\n src =\n options.base +\n encodeURIComponent(basename(processedTarget)) +\n options.embeds.uriSuffix\n }\n\n const finalAlt = determineAlt(altText, processedTarget, options)\n\n const attrs: Record<string, string> = {\n src,\n alt: finalAlt ?? '',\n }\n if (dim.width !== undefined) attrs.width = String(dim.width)\n if (dim.height !== undefined) attrs.height = String(dim.height)\n\n const extra = resolveExtra(options.embeds.htmlAttributes, {\n originalHref: src,\n altText: finalAlt,\n dimensions: dim.raw,\n embedType: 'image',\n })\n for (const [k, v] of Object.entries(extra)) {\n if (k === 'class' && attrs.class) {\n attrs.class = attrs.class + ' ' + v\n } else {\n attrs[k] = v\n }\n }\n\n return (\n '<img ' +\n Object.entries(attrs)\n .map(([k, v]) => `${escapeAttrName(k)}=\"${escapeHtml(v)}\"`)\n .join(' ') +\n ' />'\n )\n}\n\n// ── inline 入口(从 wikilinks rule 调用)──────────────────────────\n\n/**\n * 处理 inline 上下文中的 ![[image|...]]:推 html_inline。\n */\nexport function handleImageEmbed(\n state: StateInline,\n rawTarget: string,\n aliasParts: string[],\n env: AllYouNeedEnv,\n): boolean {\n const html = renderImageHtml(rawTarget, aliasParts, env)\n const token = state.push('html_inline', '', 0)\n token.content = html\n return true\n}\n\n// ── 解析尺寸 + alt ───────────────────────────────────────────────\n\ninterface ParsedDim {\n width?: number\n height?: number\n raw: string\n}\n\nfunction parseAltAndDim(parts: string[]): {\n altText: string\n dim: ParsedDim\n} {\n if (parts.length === 0) return { altText: '', dim: { raw: '' } }\n const last = parts[parts.length - 1]!\n const parsedLast = tryParseDimension(last)\n if (parsedLast) {\n const alt = parts.slice(0, -1).join('|').trim()\n return { altText: alt, dim: { ...parsedLast, raw: last } }\n }\n return { altText: parts.join('|').trim(), dim: { raw: '' } }\n}\n\nfunction tryParseDimension(\n s: string,\n): { width?: number; height?: number } | undefined {\n const trimmed = s.trim().toLowerCase()\n if (!trimmed) return undefined\n\n if (trimmed.includes('x')) {\n const [w, h] = trimmed.split('x')\n const wOk = w === '' || /^\\d+$/.test(w!)\n const hOk = h === '' || /^\\d+$/.test(h!)\n if (!wOk || !hOk) return undefined\n if (w === '' && h === '') return undefined\n return {\n width: w === '' ? undefined : Number(w),\n height: h === '' ? undefined : Number(h),\n }\n }\n if (/^\\d+$/.test(trimmed)) {\n return { width: Number(trimmed) }\n }\n return undefined\n}\n\nfunction determineAlt(\n rawAlt: string,\n target: string,\n options: AllYouNeedEnv['options'],\n): string | undefined {\n if (rawAlt && rawAlt !== '') {\n return options.embeds.postProcessAltText(rawAlt)\n }\n const def = options.embeds.defaultAltText\n if (def === false) return undefined\n if (def === true) {\n const bn = basename(target)\n const dot = bn.lastIndexOf('.')\n const noExt = dot > 0 ? bn.slice(0, dot) : bn\n return options.embeds.postProcessAltText(noExt)\n }\n if (typeof def === 'string') {\n return def === '' ? '' : options.embeds.postProcessAltText(def)\n }\n return options.embeds.postProcessAltText(basename(target))\n}\n\nfunction resolveExtra(\n attrs: ImageEmbedAttrs,\n ctx: ImageEmbedAttrsContext,\n): Record<string, string> {\n if (typeof attrs === 'function') return attrs(ctx)\n return attrs ?? {}\n}\n\nfunction escapeAttrName(k: string): string {\n return k.replace(/[^a-zA-Z0-9_-]/g, '_')\n}\n\n// 防 unused\nexport { buildPublicUrl }\n","/**\n * 笔记 transclusion:`![[note]]`、`![[note#heading]]`。\n *\n * **transclusion 始终是 block-level**:它内部会含 `<h1>` / `<div>` / `<pre>`\n * 等 block 元素,放进 `<p>` 里会产生不合法 HTML。\n *\n * 两种入口:\n * - block 入口(从 embed block-rule 调用)→ 推 html_block,无 <p> 包裹。\n * - inline 入口(从 wikilinks rule 调用)→ 不真做 transclusion,降级为\n * 带告警的 `<a>` 链接 + warn 日志(原因同上)。\n *\n * 内部 helper renderTransclusionHtml 返回完整 `<div class=\"transclusion\">...</div>`\n * 字符串,供 block 入口使用。\n */\n\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type MarkdownIt from 'markdown-it'\nimport type { AllYouNeedEnv, FileEntry } from '../../core/types.js'\nimport { resolveWikilink } from '../../core/resolver.js'\nimport { escapeHtml } from '../../utils/escape.js'\n\ninterface TransclusionCacheEntry {\n html: string\n}\n\n/**\n * 公共渲染:返回完整 `<div class=\"transclusion\">…</div>` HTML 字符串。\n * 失败/循环/超深时返回带告警 class 的 div。\n */\nexport function renderTransclusionHtml(\n md: MarkdownIt,\n rawTarget: string,\n aliasParts: string[],\n env: AllYouNeedEnv,\n): string {\n const { index, options } = env\n const result = resolveWikilink(rawTarget, index, options, 'transclusion')\n\n if (result.isDead || !result.target) {\n return `<div class=\"transclusion transclusion--dead\" data-target=\"${escapeHtml(\n rawTarget,\n )}\">⚠️ 找不到笔记 <code>${escapeHtml(rawTarget)}</code></div>`\n }\n\n const target = result.target\n\n // 注册 backlink\n const arr = index.backlinks.get(target.absolutePath) ?? []\n if (env.currentPath) {\n arr.push({\n fromPath: env.currentPath,\n fromUrl: index.files.get(env.currentPath)?.url ?? '',\n context: '',\n isEmbed: true,\n line: -1,\n })\n }\n index.backlinks.set(target.absolutePath, arr)\n\n const stack = env.transclusionStack ?? []\n if (stack.includes(target.absolutePath)) {\n return `<div class=\"transclusion transclusion--cycle\" data-target=\"${escapeHtml(\n rawTarget,\n )}\">⚠️ 循环引用:<code>${escapeHtml(\n rawTarget,\n )}</code> 已在 transclusion 链上</div>`\n }\n\n const depth = env.transclusionDepth ?? 0\n if (depth >= options.embeds.transclusionMaxDepth) {\n return `<div class=\"transclusion transclusion--too-deep\" data-target=\"${escapeHtml(\n rawTarget,\n )}\">⚠️ transclusion 嵌套过深(> ${options.embeds.transclusionMaxDepth})</div>`\n }\n\n const headingPart = extractHeading(rawTarget)\n const fragment = headingPart\n ? sliceByHeading(target, headingPart, options.slugify)\n : target.content\n\n if (fragment == null) {\n return `<div class=\"transclusion transclusion--unmatched-anchor\" data-target=\"${escapeHtml(\n rawTarget,\n )}\">⚠️ 找不到章节 <code>#${escapeHtml(\n headingPart,\n )}</code></div>`\n }\n\n const cacheKey = `${target.absolutePath}::${headingPart ?? ''}`\n const cache = getCache(env)\n let inner: string\n const cached = cache.get(cacheKey)\n if (cached) {\n inner = cached.html\n } else {\n // ⚠️ 关键:childEnv **只显式继承**我们这个插件需要共享的字段。\n // 不能用 { ...env, ... } 浅拷贝,否则 env.frontmatter / env.__data /\n // env.headers / env.excerpt 等 VitePress per-page 字段会被引用共享。\n // 递归 md.render 时,@mdit-vue/plugin-frontmatter 等插件会就地重置\n // 这些字段(因为内联的 fragment 没有自己的 frontmatter),从而 **覆盖\n // 掉外层页面的 frontmatter** —— VitePress 后续读不到 pageData → 路由\n // 数据缺失 → 首页 404。这是 v0.1 收尾期最坑的一个 bug,见 transclusion 测试。\n const childEnv: AllYouNeedEnv = {\n index: env.index,\n options: env.options,\n currentPath: target.absolutePath,\n transclusionStack: [...stack, target.absolutePath],\n transclusionDepth: depth + 1,\n // 跨递归共享:asset 引用集合(build 时要 emit 所有被引用 asset)\n referencedAssets: env.referencedAssets,\n }\n // 跨递归共享:transclusion 渲染缓存(同一笔记被多处 embed 时复用)\n ;(childEnv as unknown as Record<string, unknown>)._transclusionCache = (\n env as unknown as Record<string, unknown>\n )._transclusionCache\n\n inner = md.render(fragment, childEnv)\n cache.set(cacheKey, { html: inner })\n }\n\n const sourceUrl = headingPart\n ? `${target.url}#${options.slugify(headingPart)}`\n : target.url\n\n const aliasData = aliasParts.length\n ? ` data-caption=\"${escapeHtml(aliasParts.join('|'))}\"`\n : ''\n\n // v0.2 美化:右上角\"前往源文件\"按钮 —— 极简箭头图标,不带 basename 文字\n // (basename 已经通过 data-source attr 可以读取;鼠标 hover title 也能看)\n const sourceLink =\n `<a class=\"transclusion-source-link\" ` +\n `href=\"${escapeHtml(sourceUrl)}\" ` +\n `aria-label=\"Go to source: ${escapeHtml(target.relativePath)}\" ` +\n `title=\"${escapeHtml(target.relativePath)}\">↗</a>`\n\n return (\n `<div class=\"transclusion\" data-source=\"${escapeHtml(target.relativePath)}\"` +\n ` data-source-url=\"${escapeHtml(sourceUrl)}\"${aliasData}>` +\n sourceLink +\n inner +\n `</div>`\n )\n}\n\n/**\n * inline 上下文中的 ![[note]] —— 不做真 transclusion,降级为带告警的链接。\n * 原因:transclusion 内含 block 元素(<h1>/<div> 等),嵌进 <p> 会产生不合法 HTML。\n */\nexport function handleTransclusion(\n state: StateInline,\n rawTarget: string,\n aliasParts: string[],\n env: AllYouNeedEnv,\n): boolean {\n if (env.options.deadLink !== 'silent') {\n console.warn(\n `vitepress-allyouneed: ![[${rawTarget}]] 在段落中无法 transclude(会产生不合法 HTML),已降级为链接。请单独放一行。`,\n )\n }\n const { index, options } = env\n const result = resolveWikilink(rawTarget, index, options, 'page')\n const url = result.url\n const label = aliasParts.length\n ? aliasParts.join('|').trim()\n : result.defaultLabel\n\n const html =\n `<a class=\"wikilink wikilink--inline-transclusion-degraded\" ` +\n `href=\"${escapeHtml(url)}\" ` +\n `data-wikilink-target=\"${escapeHtml(rawTarget)}\" ` +\n `title=\"行内 transclusion 已降级,见控制台\">` +\n `${escapeHtml(label)}</a>`\n\n const token = state.push('html_inline', '', 0)\n token.content = html\n return true\n}\n\nfunction extractHeading(raw: string): string {\n const hashIdx = raw.indexOf('#')\n if (hashIdx < 0) return ''\n return raw.slice(hashIdx + 1).trim()\n}\n\nfunction sliceByHeading(\n target: FileEntry,\n headingPart: string,\n slugify: (s: string) => string,\n): string | undefined {\n const matched = target.headings.find(\n (h) =>\n h.text === headingPart ||\n h.slug === headingPart ||\n h.slug === slugify(headingPart),\n )\n if (!matched) return undefined\n\n const lines = target.content.split(/\\r?\\n/)\n const startLine = matched.line + 1\n let endLine = lines.length\n for (let i = startLine; i < lines.length; i++) {\n const l = lines[i]!\n const m = l.match(/^(#{1,6})\\s+/)\n if (m && m[1]!.length <= matched.level) {\n endLine = i\n break\n }\n }\n return lines.slice(startLine, endLine).join('\\n').trim()\n}\n\nfunction getCache(env: AllYouNeedEnv): Map<string, TransclusionCacheEntry> {\n const e = env as unknown as {\n _transclusionCache?: Map<string, TransclusionCacheEntry>\n }\n if (!e._transclusionCache) e._transclusionCache = new Map()\n return e._transclusionCache\n}\n","/**\n * v0.3 — audio / video / pdf embed 渲染。\n *\n * 复用 image.ts 同款 asset 解析路径(走 resolveAsset + buildPlaceholderUrl),\n * 唯一差别是输出 `<audio>` / `<video>` / `<iframe>` 标签。\n *\n * 调用约定:\n * - block 上下文:返回 HTML 字符串,调用方包成 html_block token\n * - inline 上下文:由 wikilinks/rule.ts 通过 handleMediaEmbed 推 html_inline\n *\n * 尺寸语法继承 image:\n * - audio:忽略尺寸(audio 没有视觉尺寸)\n * - video:支持 width/height\n * - pdf:支持 width/height(iframe 直接吃)\n */\n\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type { AllYouNeedEnv } from '../../core/types.js'\nimport { resolveAsset } from '../../core/resolver.js'\nimport { basename } from '../../utils/path.js'\nimport { escapeHtml } from '../../utils/escape.js'\nimport { buildPlaceholderUrl } from '../../core/asset-pipeline/build-emit.js'\n\nconst AUDIO_EXTS = ['mp3', 'wav', 'ogg', 'm4a', 'flac', 'aac', 'webm']\nconst VIDEO_EXTS = ['mp4', 'webm', 'mov', 'm4v', 'avi', 'mkv']\nconst PDF_EXTS = ['pdf']\n\nexport function isAudioExt(ext: string): boolean {\n return AUDIO_EXTS.includes(ext.toLowerCase())\n}\nexport function isVideoExt(ext: string): boolean {\n return VIDEO_EXTS.includes(ext.toLowerCase())\n}\nexport function isPdfExt(ext: string): boolean {\n return PDF_EXTS.includes(ext.toLowerCase())\n}\n\n/** 把 ext 归到 media 类型;不是 media 时返回 null */\nexport function classifyMediaExt(\n ext: string,\n): 'audio' | 'video' | 'pdf' | null {\n if (isVideoExt(ext)) return 'video'\n if (isAudioExt(ext)) return 'audio'\n if (isPdfExt(ext)) return 'pdf'\n return null\n}\n\ninterface ParsedDim {\n width?: number\n height?: number\n}\n\n/** 取最后一段 alias 当尺寸 token(逻辑和 image.ts 一致,但这里精简一份) */\nfunction parseAliasDim(parts: string[]): ParsedDim {\n if (parts.length === 0) return {}\n const last = parts[parts.length - 1]!.trim().toLowerCase()\n if (!last) return {}\n if (last.includes('x')) {\n const [w, h] = last.split('x')\n const wOk = w === '' || /^\\d+$/.test(w!)\n const hOk = h === '' || /^\\d+$/.test(h!)\n if (!wOk || !hOk) return {}\n return {\n width: w === '' ? undefined : Number(w),\n height: h === '' ? undefined : Number(h),\n }\n }\n if (/^\\d+$/.test(last)) return { width: Number(last) }\n return {}\n}\n\n/** 解析 asset 路径 → 最终 src URL(沿用 image 同款 placeholder URL)*/\nfunction resolveSrc(rawTarget: string, env: AllYouNeedEnv): string {\n const { index, options } = env\n const processedTarget = options.embeds.postProcessImageTarget(rawTarget)\n const { asset } = resolveAsset(processedTarget, index, options)\n if (asset) {\n asset.referencedBy.add(env.currentPath ?? '<unknown>')\n env.referencedAssets?.add(asset)\n return buildPlaceholderUrl(asset, options) + options.embeds.uriSuffix\n }\n return (\n options.base +\n encodeURIComponent(basename(processedTarget)) +\n options.embeds.uriSuffix\n )\n}\n\n// ── 渲染:audio / video / pdf ─────────────────────────────────────\n\nexport function renderAudioHtml(\n rawTarget: string,\n _aliasParts: string[],\n env: AllYouNeedEnv,\n): string {\n const src = resolveSrc(rawTarget, env)\n return (\n `<audio class=\"ayn-embed ayn-embed--audio\" controls preload=\"metadata\" ` +\n `src=\"${escapeHtml(src)}\">` +\n `Your browser does not support the audio element.` +\n `</audio>`\n )\n}\n\nexport function renderVideoHtml(\n rawTarget: string,\n aliasParts: string[],\n env: AllYouNeedEnv,\n): string {\n const src = resolveSrc(rawTarget, env)\n const dim = parseAliasDim(aliasParts)\n const attrs: string[] = [\n `class=\"ayn-embed ayn-embed--video\"`,\n `controls`,\n `preload=\"metadata\"`,\n `src=\"${escapeHtml(src)}\"`,\n ]\n if (dim.width !== undefined) attrs.push(`width=\"${dim.width}\"`)\n if (dim.height !== undefined) attrs.push(`height=\"${dim.height}\"`)\n return (\n `<video ${attrs.join(' ')}>` +\n `Your browser does not support the video element.` +\n `</video>`\n )\n}\n\nexport function renderPdfHtml(\n rawTarget: string,\n aliasParts: string[],\n env: AllYouNeedEnv,\n): string {\n const src = resolveSrc(rawTarget, env)\n const dim = parseAliasDim(aliasParts)\n // 默认尺寸:全宽 + 600px 高(给 iframe 一个起码可读的视口)\n const width = dim.width !== undefined ? `${dim.width}px` : '100%'\n const height = dim.height !== undefined ? `${dim.height}px` : '600px'\n return (\n `<iframe class=\"ayn-embed ayn-embed--pdf\" ` +\n `src=\"${escapeHtml(src)}\" ` +\n `style=\"width:${escapeHtml(width)};height:${escapeHtml(height)};border:0\" ` +\n `loading=\"lazy\" title=\"${escapeHtml(basename(rawTarget))}\">` +\n `</iframe>`\n )\n}\n\n/**\n * inline 上下文入口:由 wikilinks/rule.ts 在判断 isMedia 后调用。\n * 推一个 html_inline token,内含适配的播放器/iframe HTML。\n */\nexport function handleMediaEmbed(\n state: StateInline,\n kind: 'audio' | 'video' | 'pdf',\n rawTarget: string,\n aliasParts: string[],\n env: AllYouNeedEnv,\n): boolean {\n let html: string\n if (kind === 'audio') html = renderAudioHtml(rawTarget, aliasParts, env)\n else if (kind === 'video') html = renderVideoHtml(rawTarget, aliasParts, env)\n else html = renderPdfHtml(rawTarget, aliasParts, env)\n const token = state.push('html_inline', '', 0)\n token.content = html\n return true\n}\n","/**\n * wikilinks inline rule:识别 [[...]] 与 ![[...]]。\n *\n * 这条规则在 wikilinks/embeds 都启用时被共用,内部按 isEmbed 分派。\n * 注册顺序:`md.inline.ruler.before('link', 'allyouneed_wikilinks', rule)`。\n */\n\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type {\n AllYouNeedEnv,\n ResolvedOptions,\n VaultIndex,\n} from '../../core/types.js'\nimport { resolveWikilink } from '../../core/resolver.js'\nimport {\n renderPageLink,\n renderDeadLink,\n} from './render.js'\nimport { handleImageEmbed } from '../embeds/image.js'\nimport { handleTransclusion } from '../embeds/transclusion.js'\nimport { classifyMediaExt, handleMediaEmbed } from '../embeds/media.js'\n\n/**\n * 构造 inline rule。\n *\n * @param md markdown-it 实例,仅用于把 env 取出来\n * @param scope 控制此规则处理哪些前缀:'both' / 'wikilinks-only' / 'embeds-only'\n */\nexport function makeWikilinkRule(\n scope: 'both' | 'wikilinks-only' | 'embeds-only',\n): (state: StateInline, silent: boolean) => boolean {\n return function wikilinkRule(state, silent) {\n const src = state.src\n const start = state.pos\n const max = state.posMax\n\n let isEmbed = false\n let inner: string\n\n // 探测 ![[ 或 [[\n if (\n src.charCodeAt(start) === 0x21 /* ! */ &&\n src.charCodeAt(start + 1) === 0x5b /* [ */ &&\n src.charCodeAt(start + 2) === 0x5b /* [ */\n ) {\n if (scope === 'wikilinks-only') return false\n isEmbed = true\n } else if (\n src.charCodeAt(start) === 0x5b /* [ */ &&\n src.charCodeAt(start + 1) === 0x5b /* [ */\n ) {\n if (scope === 'embeds-only') return false\n } else {\n return false\n }\n\n const innerStart = start + (isEmbed ? 3 : 2)\n const closeIdx = src.indexOf(']]', innerStart)\n if (closeIdx < 0 || closeIdx >= max) return false\n\n inner = src.slice(innerStart, closeIdx)\n if (inner.includes('\\n')) return false // 不跨行\n if (!inner.trim()) return false\n\n // 按 markdown-it 约定:silent 模式找到匹配返回 true\n if (silent) return true\n\n // 提取 env\n const env = state.env as AllYouNeedEnv\n if (!env || !env.index || !env.options) {\n // 没注入索引 → 视为不识别,把控制权交回 markdown-it 默认链\n return false\n }\n\n state.pos = closeIdx + 2 // 推进游标\n\n const parts = inner.split('|').map((p) => p.trim())\n const rawTarget = parts[0]!\n const aliasParts = parts.slice(1)\n\n if (isEmbed) {\n // 路由顺序:image → audio/video/pdf → transclusion(.md)\n const ext = extractExt(rawTarget)\n const isImage =\n ext && env.options.embeds.imageFileExt.includes(ext.toLowerCase())\n if (isImage) {\n return handleImageEmbed(state, rawTarget, aliasParts, env)\n }\n const mediaKind = ext ? classifyMediaExt(ext) : null\n if (mediaKind) {\n return handleMediaEmbed(state, mediaKind, rawTarget, aliasParts, env)\n }\n return handleTransclusion(state, rawTarget, aliasParts, env)\n }\n\n // 普通 [[wikilink]]\n return emitPageLink(state, rawTarget, aliasParts, env)\n }\n}\n\n/**\n * 取一个 path 的扩展名(小写,无点),无扩展名返回 ''。\n */\nfunction extractExt(target: string): string {\n // 拆 #heading 之前先剥\n const cleaned = target.split('#')[0]!\n const dot = cleaned.lastIndexOf('.')\n if (dot <= 0) return ''\n return cleaned.slice(dot + 1).toLowerCase()\n}\n\n/**\n * 渲染一个 [[wikilink]]:解析 target → URL → push tokens。\n */\nfunction emitPageLink(\n state: StateInline,\n rawTarget: string,\n aliasParts: string[],\n env: AllYouNeedEnv,\n): boolean {\n const { index, options } = env\n const userAlias = aliasParts.length > 0 ? aliasParts.join('|').trim() : ''\n const processed = options.wikilinks.postProcessLinkTarget(rawTarget)\n const result = resolveWikilink(processed, index, options, 'page', env.currentPath)\n\n const label = userAlias\n ? options.wikilinks.postProcessLinkLabel(userAlias)\n : result.defaultLabel\n\n // 登记 backlink(用于 graph 模块)\n registerBacklink(env, result.target?.absolutePath, false)\n\n if (result.isDead) {\n handleDeadLink(env, rawTarget)\n return renderDeadLink(state, result.url, label, rawTarget, env)\n }\n return renderPageLink(state, result, label, env)\n}\n\n/** 登记反向链接(target 是被链接的页面)*/\nfunction registerBacklink(\n env: AllYouNeedEnv,\n targetPath: string | undefined,\n isEmbed: boolean,\n): void {\n if (!targetPath || !env.currentPath) return\n const arr = env.index.backlinks.get(targetPath) ?? []\n arr.push({\n fromPath: env.currentPath,\n fromUrl: env.index.files.get(env.currentPath)?.url ?? '',\n context: '',\n isEmbed,\n line: -1,\n })\n env.index.backlinks.set(targetPath, arr)\n}\n\n/** 死链 → 按 deadLink 策略输出告警 */\nfunction handleDeadLink(env: AllYouNeedEnv, rawTarget: string): void {\n const { options } = env\n const msg = `vitepress-allyouneed: 死链 [[${rawTarget}]]${\n env.currentPath ? ` (in ${env.currentPath})` : ''\n }`\n if (options.deadLink === 'silent') return\n if (options.deadLink === 'warn') {\n console.warn(msg)\n return\n }\n // 'error':仍然渲染,但把错误推到 index.warnings 让 build 失败\n env.index.warnings.push({\n kind: 'unknown',\n message: msg,\n affected: env.currentPath ? [env.currentPath] : [],\n })\n}\n\n// 抑制 unused 警告\nexport type { VaultIndex, ResolvedOptions }\n","/**\n * wikilinks 模块入口。\n *\n * register(md, scope) 把规则装进 markdown-it 实例。scope 决定本规则\n * 同时还要不要处理 ![[]];当 wikilinks 模块单独启用、embeds 模块关闭时\n * 走 'wikilinks-only',反之亦然。两者都开就 'both'(同一个规则,内部分派)。\n */\n\nimport type MarkdownIt from 'markdown-it'\nimport { makeWikilinkRule } from './rule.js'\n\nexport function registerWikilinks(\n md: MarkdownIt,\n scope: 'both' | 'wikilinks-only' | 'embeds-only',\n): void {\n md.inline.ruler.before(\n 'link',\n 'allyouneed_wikilinks',\n makeWikilinkRule(scope),\n )\n}\n","/**\n * Block rule:整行只有 `![[...]]` 时按 block-level 处理,推 `html_block` token。\n *\n * 这条规则**必须**存在,否则 markdown-it 会把 `![[note]]` 当成段落里的 inline\n * 内容,渲染出 `<p><div class=\"transclusion\">...</div></p>` —— 不合法 HTML\n * (`<div>` 不能在 `<p>` 里),Vue/VitePress 会爆 hydration 警告。\n *\n * 配合 wikilinks/rule.ts 的 inline 规则:\n * - 单独一行的 ![[...]] → 本规则吃掉,html_block\n * - 段落中混合的 ![[...]] → inline 规则处理,image 走 html_inline,\n * transclusion 降级为链接\n */\n\nimport type StateBlock from 'markdown-it/lib/rules_block/state_block.mjs'\nimport type MarkdownIt from 'markdown-it'\nimport type { AllYouNeedEnv } from '../../core/types.js'\nimport { renderImageHtml } from './image.js'\nimport { renderTransclusionHtml } from './transclusion.js'\nimport {\n classifyMediaExt,\n renderAudioHtml,\n renderVideoHtml,\n renderPdfHtml,\n} from './media.js'\n\nconst LINE_RE = /^!\\[\\[([^\\n\\]]+)\\]\\]\\s*$/\n\nexport function registerEmbedBlockRule(md: MarkdownIt): void {\n md.block.ruler.before(\n 'paragraph',\n 'allyouneed_embed_block',\n makeRule(md),\n { alt: ['paragraph'] },\n )\n}\n\nfunction makeRule(md: MarkdownIt) {\n return function embedBlockRule(\n state: StateBlock,\n startLine: number,\n _endLine: number,\n silent: boolean,\n ): boolean {\n const start = state.bMarks[startLine]! + state.tShift[startLine]!\n const max = state.eMarks[startLine]!\n const lineText = state.src.slice(start, max)\n\n const m = lineText.match(LINE_RE)\n if (!m) return false\n if (silent) return true\n\n const env = state.env as AllYouNeedEnv\n if (!env || !env.index || !env.options) return false\n\n const inner = m[1]!\n const parts = inner.split('|').map((p) => p.trim())\n const rawTarget = parts[0]!\n const aliasParts = parts.slice(1)\n\n const ext = extractExt(rawTarget)\n const isImage =\n !!ext && env.options.embeds.imageFileExt.includes(ext.toLowerCase())\n const mediaKind = ext ? classifyMediaExt(ext) : null\n\n let html: string\n if (isImage) {\n html = renderImageHtml(rawTarget, aliasParts, env)\n } else if (mediaKind === 'audio') {\n html = renderAudioHtml(rawTarget, aliasParts, env)\n } else if (mediaKind === 'video') {\n html = renderVideoHtml(rawTarget, aliasParts, env)\n } else if (mediaKind === 'pdf') {\n html = renderPdfHtml(rawTarget, aliasParts, env)\n } else {\n html = renderTransclusionHtml(md, rawTarget, aliasParts, env)\n }\n\n const token = state.push('html_block', '', 0)\n token.content = html + '\\n'\n token.map = [startLine, startLine + 1]\n\n state.line = startLine + 1\n return true\n }\n}\n\nfunction extractExt(target: string): string {\n const cleaned = target.split('#')[0]!\n const dot = cleaned.lastIndexOf('.')\n if (dot <= 0) return ''\n return cleaned.slice(dot + 1).toLowerCase()\n}\n","/**\n * embeds 模块入口。\n *\n * embeds 模块有两条规则:\n * 1. **block rule**(`registerEmbedBlockRule`):整行只有 ![[...]] 时按 block-level\n * 处理,推 `html_block`。**必须有,否则 transclusion 会产生 `<div>` in `<p>` 不合法 HTML**。\n * 2. **inline rule**(共用 wikilinks 模块的 makeWikilinkRule):处理段落内混合的\n * ![[...]]。image 走 inline image,transclusion 降级为告警链接。\n *\n * markdown-it.ts 在两种情况下分别调用:\n * - wikilinks + embeds 都开:wikilinks/index.ts 注册 inline 'both';本文件注册 block。\n * - 只开 embeds:本文件 registerEmbedsOnly 注册 inline 'embeds-only';同时注册 block。\n */\n\nimport type MarkdownIt from 'markdown-it'\nimport { makeWikilinkRule } from '../wikilinks/rule.js'\nimport { registerEmbedBlockRule } from './block-rule.js'\n\nexport function registerEmbedsOnly(md: MarkdownIt): void {\n md.inline.ruler.before(\n 'link',\n 'allyouneed_embeds',\n makeWikilinkRule('embeds-only'),\n )\n registerEmbedBlockRule(md)\n}\n\nexport { registerEmbedBlockRule }\n","/**\n * Obsidian 13 种原生 callout 类型 + 别名映射。\n * 别名 → 规范名(用于 CSS class / 图标)\n */\n\nexport const CALLOUT_TYPES = {\n // Standard\n note: 'note',\n info: 'info',\n tip: 'tip',\n success: 'success',\n question: 'question',\n warning: 'warning',\n failure: 'failure',\n danger: 'danger',\n bug: 'bug',\n example: 'example',\n quote: 'quote',\n abstract: 'abstract',\n todo: 'todo',\n\n // Aliases (Obsidian 官方文档列出的别名)\n hint: 'tip',\n important: 'tip',\n check: 'success',\n done: 'success',\n help: 'question',\n faq: 'question',\n caution: 'warning',\n attention: 'warning',\n fail: 'failure',\n missing: 'failure',\n error: 'danger',\n cite: 'quote',\n summary: 'abstract',\n tldr: 'abstract',\n} as const\n\nexport type CalloutCanonical =\n | 'note' | 'info' | 'tip' | 'success' | 'question' | 'warning'\n | 'failure' | 'danger' | 'bug' | 'example' | 'quote' | 'abstract' | 'todo'\n\n/**\n * 把任意 raw type(可能是别名)归一化为 canonical。未知 type 退化到 'note'。\n */\nexport function normalizeCalloutType(raw: string): CalloutCanonical {\n const key = raw.trim().toLowerCase()\n const mapped = (CALLOUT_TYPES as Record<string, string>)[key]\n return (mapped ?? 'note') as CalloutCanonical\n}\n\n/** foldable 标记:`[!info]+` 默认开,`[!info]-` 默认关,无标记不可折叠 */\nexport type CalloutFoldable = 'open' | 'closed' | null\n\n/** 解析一行 `[!type][+-]? <title>` 的结果 */\nexport interface CalloutHeader {\n type: CalloutCanonical\n foldable: CalloutFoldable\n /** 用户写的 title;为空时调用方应用 DEFAULT_TITLES[type] */\n title: string\n}\n\n/** 每种 type 的默认标题(用户没写自定义 title 时用)*/\nexport const DEFAULT_TITLES: Record<CalloutCanonical, string> = {\n note: 'Note',\n info: 'Info',\n tip: 'Tip',\n success: 'Success',\n question: 'Question',\n warning: 'Warning',\n failure: 'Failure',\n danger: 'Danger',\n bug: 'Bug',\n example: 'Example',\n quote: 'Quote',\n abstract: 'Abstract',\n todo: 'Todo',\n}\n\n/** 每种 type 的 SVG icon path(用 lucide 风,inline 渲染)*/\nexport const CALLOUT_ICONS: Record<CalloutCanonical, string> = {\n note:\n '<path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>',\n info:\n '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M12 16v-4\"/><path d=\"M12 8h.01\"/>',\n tip:\n '<path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/>',\n success:\n '<path d=\"M21.801 10A10 10 0 1 1 17 3.335\"/><path d=\"m9 11 3 3L22 4\"/>',\n question:\n '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3\"/><path d=\"M12 17h.01\"/>',\n warning:\n '<path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/>',\n failure:\n '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"m15 9-6 6\"/><path d=\"m9 9 6 6\"/>',\n danger:\n '<path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/>',\n bug:\n '<path d=\"m8 2 1.88 1.88\"/><path d=\"M14.12 3.88 16 2\"/><path d=\"M9 7.13v-1a3.003 3.003 0 1 1 6 0v1\"/><path d=\"M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6\"/><path d=\"M12 20v-9\"/><path d=\"M6.53 9C4.6 8.8 3 7.1 3 5\"/><path d=\"M6 13H2\"/><path d=\"M3 21c0-2.1 1.7-3.9 3.8-4\"/><path d=\"M20.97 5c0 2.1-1.6 3.8-3.5 4\"/><path d=\"M22 13h-4\"/><path d=\"M17.2 17c2.1.1 3.8 1.9 3.8 4\"/>',\n example:\n '<path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><polyline points=\"14 2 14 8 20 8\"/><path d=\"M10 9H8\"/><path d=\"M16 13H8\"/><path d=\"M16 17H8\"/>',\n quote:\n '<path d=\"M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V20c0 1 0 1 1 1z\"/><path d=\"M15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 .25 0 .5 0 .75.031V14c0 1-1 2-2 2s-1.5.5-1.5 1V20c0 1 .5 1 1.75 1z\"/>',\n abstract:\n '<path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><polyline points=\"14 2 14 8 20 8\"/><line x1=\"16\" x2=\"8\" y1=\"13\" y2=\"13\"/><line x1=\"16\" x2=\"8\" y1=\"17\" y2=\"17\"/><line x1=\"10\" x2=\"8\" y1=\"9\" y2=\"9\"/>',\n todo:\n '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"m9 12 2 2 4-4\"/>',\n}\n","/**\n * Obsidian callouts —— `> [!type][+-]? <title>` 块语法。\n *\n * 实现思路:\n * - 注册一条 markdown-it **core** rule(在 'block' 之后跑),扫所有 token\n * 找到 blockquote_open ... paragraph_open ... 第一段首行是 `[!type] ...` 的,\n * 把整块 blockquote 改写成 html_block 包 `<div class=\"callout\">…</div>`\n * - 嵌套:Obsidian 嵌套 callout 用 `> > [!info]`,markdown-it blockquote\n * 本身递归,我们 core rule 也递归扫所有 blockquote_open\n * - 渲染 body:用 md.render(bodyMarkdown, env) 把内层 markdown 递归渲染\n * 成 HTML,贴到 .callout-content\n *\n * 不写 markdown-it 的 block ruler 自定义 —— blockquote 的解析已经稳,\n * 我们后置改写 token 流更安全。\n */\n\nimport type MarkdownIt from 'markdown-it'\nimport type Token from 'markdown-it/lib/token.mjs'\nimport type StateCore from 'markdown-it/lib/rules_core/state_core.mjs'\nimport type { AllYouNeedEnv } from '../../core/types.js'\nimport { escapeHtml } from '../../utils/escape.js'\nimport {\n normalizeCalloutType,\n DEFAULT_TITLES,\n CALLOUT_ICONS,\n type CalloutCanonical,\n type CalloutFoldable,\n type CalloutHeader,\n} from './types.js'\n\nconst HEADER_RE = /^\\[!([a-zA-Z]+)\\]([+-]?)\\s*(.*)$/\n\n/**\n * 解析 callout 头(第一段第一行)。返回 null 表示不是 callout。\n */\nexport function parseCalloutHeader(line: string): CalloutHeader | null {\n const m = HEADER_RE.exec(line.trim())\n if (!m) return null\n const type = normalizeCalloutType(m[1]!)\n const foldChar = m[2]!\n const foldable: CalloutFoldable =\n foldChar === '+' ? 'open' : foldChar === '-' ? 'closed' : null\n return { type, foldable, title: (m[3] ?? '').trim() }\n}\n\n/**\n * core 规则:扫 state.tokens,把 callout-blockquote 改写为 html_block。\n *\n * Token 结构:\n * blockquote_open\n * paragraph_open\n * inline { children: [text \"[!type] ...\", softbreak, text \"rest\"] }\n * paragraph_close\n * (可能有更多 children)\n * blockquote_close\n */\nexport function registerCalloutsCore(md: MarkdownIt): void {\n md.core.ruler.after(\n 'block',\n 'allyouneed_callouts',\n function calloutsRule(state: StateCore): boolean {\n const tokens = state.tokens\n // 从后往前扫,改写时 splice 不影响前面 index\n for (let i = tokens.length - 1; i >= 0; i--) {\n const t = tokens[i]!\n if (t.type !== 'blockquote_open') continue\n // 找配对的 blockquote_close\n const closeIdx = findMatchingClose(tokens, i)\n if (closeIdx < 0) continue\n // 检查首段第一行\n const inner = tokens.slice(i + 1, closeIdx)\n const header = extractHeader(inner)\n if (!header) continue\n // 提取剩余内容(去掉 header 行后的所有内容)\n const bodyHtml = renderBody(inner, header.firstLineRest, md, state.env)\n const html = renderCallout(header.parsed, bodyHtml)\n // 用 html_block 替换 blockquote_open...blockquote_close\n const newToken = new state.Token('html_block', '', 0)\n newToken.content = html + '\\n'\n newToken.map = t.map\n tokens.splice(i, closeIdx - i + 1, newToken)\n }\n return false\n },\n )\n}\n\n/** 找配对 blockquote_close,考虑嵌套 */\nfunction findMatchingClose(tokens: Token[], openIdx: number): number {\n let depth = 0\n for (let i = openIdx; i < tokens.length; i++) {\n const t = tokens[i]!\n if (t.type === 'blockquote_open') depth++\n else if (t.type === 'blockquote_close') {\n depth--\n if (depth === 0) return i\n }\n }\n return -1\n}\n\ninterface ExtractedHeader {\n parsed: CalloutHeader\n /** header 之后同一段的剩余文本(softbreak 之后的部分)*/\n firstLineRest: string\n}\n\n/**\n * 从 blockquote 内部 token 序列中提取 callout header。\n * Header 必须是首个 paragraph 的第一行。返回 null 表示不是 callout。\n */\nfunction extractHeader(inner: Token[]): ExtractedHeader | null {\n // 找第一个 paragraph_open\n if (inner.length === 0) return null\n const first = inner[0]!\n if (first.type !== 'paragraph_open') return null\n const inlineToken = inner[1]\n if (!inlineToken || inlineToken.type !== 'inline') return null\n\n const content = inlineToken.content\n // 取首行\n const newlineIdx = content.indexOf('\\n')\n const firstLine = newlineIdx >= 0 ? content.slice(0, newlineIdx) : content\n const rest = newlineIdx >= 0 ? content.slice(newlineIdx + 1) : ''\n\n const parsed = parseCalloutHeader(firstLine)\n if (!parsed) return null\n\n return { parsed, firstLineRest: rest }\n}\n\n/**\n * 渲染 callout body:把 header 之后的 markdown 内容用 md.render 递归渲染。\n */\nfunction renderBody(\n inner: Token[],\n firstLineRest: string,\n md: MarkdownIt,\n env: unknown,\n): string {\n // 重建 body markdown:首段去掉 header 行后的内容,加上 inner 后续 block\n // 简化策略:把 inner 渲染回 markdown 不容易,改成直接 render 剩余 tokens\n // 但 markdown-it 的 renderer 是 token → html,我们已经有 inner tokens 了。\n // 不过首段的 inline token 还含 header 行,需要替换 content。\n\n if (inner.length < 3) {\n // 只有空段,body 为空\n return ''\n }\n\n // Clone inner tokens,替换首段 inline.content 为 firstLineRest\n const cloned: Token[] = inner.map((t) => {\n const c = new (t.constructor as new (\n type: string,\n tag: string,\n nesting: number,\n ) => Token)(t.type, t.tag, t.nesting)\n Object.assign(c, t)\n // 注意 children 是数组,需要重新做 clone(避免共享)\n if (t.children) c.children = [...t.children]\n return c\n })\n\n // 替换首段 inline 的 content;若 rest 为空,把首段三个 token(open/inline/close)\n // 整段移除\n if (firstLineRest.trim() === '') {\n cloned.splice(0, 3)\n } else {\n const inlineToken = cloned[1]!\n inlineToken.content = firstLineRest\n // markdown-it 渲染 inline token 看的是 children 而不是 content;\n // 我们改了 content 必须重新 parse 一次,把新 children 填回去\n const newChildren: Token[] = []\n inlineToken.children = newChildren\n md.inline.parse(firstLineRest, md, env as object, newChildren)\n }\n\n return md.renderer.render(cloned, md.options, env)\n}\n\n/**\n * 渲染 callout 最终 HTML。\n */\nfunction renderCallout(header: CalloutHeader, bodyHtml: string): string {\n const { type, foldable, title } = header\n const displayTitle = title || DEFAULT_TITLES[type]\n const iconSvg =\n `<svg class=\"callout-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" ` +\n `stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">` +\n CALLOUT_ICONS[type] +\n `</svg>`\n\n const cls = `callout callout--${type}` + (foldable ? ' callout--foldable' : '')\n\n if (foldable) {\n const isOpen = foldable === 'open'\n return (\n `<details class=\"${cls}\" data-callout=\"${type}\"${isOpen ? ' open' : ''}>` +\n `<summary class=\"callout-title\">${iconSvg}<span class=\"callout-title-text\">${escapeHtml(displayTitle)}</span></summary>` +\n `<div class=\"callout-content\">${bodyHtml}</div>` +\n `</details>`\n )\n }\n\n return (\n `<div class=\"${cls}\" data-callout=\"${type}\">` +\n `<div class=\"callout-title\">${iconSvg}<span class=\"callout-title-text\">${escapeHtml(displayTitle)}</span></div>` +\n `<div class=\"callout-content\">${bodyHtml}</div>` +\n `</div>`\n )\n}\n\n// 防 unused\nexport type { CalloutCanonical, AllYouNeedEnv }\n","/**\n * v0.3 callouts 模块入口。\n *\n * Obsidian 13 种 callout 语法:\n * > [!type][+-]? <title>\n * > body lines...\n *\n * 实现在 rule.ts 里用 markdown-it 的 core ruler 后置改写 blockquote token 流。\n */\nimport type MarkdownIt from 'markdown-it'\nimport { registerCalloutsCore, parseCalloutHeader } from './rule.js'\n\nexport { registerCalloutsCore, parseCalloutHeader }\nexport * from './types.js'\n\nexport function registerCallouts(md: MarkdownIt): void {\n registerCalloutsCore(md)\n}\n","/**\n * v0.3 — Obsidian `==text==` 高亮 inline rule。\n *\n * 渲染为 `<mark>text</mark>`,内部 markdown 继续解析(支持 `==**bold**==`)。\n *\n * 直接照搬 markdown-it-mark 的 tokenize + postProcess 双阶段方案:\n * - tokenize:遇 `=`,统计连续个数 N;每 2 个 `=` 推一个 text token 进\n * state.tokens,并往 state.delimiters 注一项 {marker: 0x3D, ...}\n * - 中间内容由 markdown-it 后续 inline rule 继续 tokenize\n * - balance_pairs 自动配对所有 delimiter(对 marker 不挑剔)\n * - postProcess:扫 delimiters 找到 marker===0x3D 且 end!==-1 的,把\n * 对应 text token 改写为 mark_open / mark_close\n */\n\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type Token from 'markdown-it/lib/token.mjs'\nimport type MarkdownIt from 'markdown-it'\n\nconst EQ = 0x3d /* = */\n\nfunction tokenize(state: StateInline, silent: boolean): boolean {\n if (silent) return false\n const start = state.pos\n const marker = state.src.charCodeAt(start)\n if (marker !== EQ) return false\n\n const scanned = state.scanDelims(state.pos, true)\n let len = scanned.length\n const ch = String.fromCharCode(marker)\n\n if (len < 2) return false\n\n // 奇数个 `=`:把第一个当普通文本\n let token: Token\n if (len % 2) {\n token = state.push('text', '', 0)\n token.content = ch\n len -= 1\n }\n\n for (let i = 0; i < len; i += 2) {\n token = state.push('text', '', 0)\n token.content = ch + ch\n\n // state.delimiters 的类型 markdown-it 内部用,这里 cast 进去\n const delims = (state as unknown as { delimiters: unknown[] }).delimiters\n delims.push({\n marker,\n length: 0, // 关掉 emphasis 用的 \"rule of 3\"\n jump: i / 2, // 1 delimiter = 2 chars\n token: state.tokens.length - 1,\n end: -1,\n open: scanned.can_open,\n close: scanned.can_close,\n })\n }\n\n state.pos += scanned.length\n return true\n}\n\ninterface DelimEntry {\n marker: number\n end: number\n token: number\n}\n\nfunction postProcess(state: StateInline): void {\n const delimiters = (state as unknown as { delimiters: DelimEntry[] })\n .delimiters\n const loneMarkers: number[] = []\n const max = delimiters.length\n\n for (let i = 0; i < max; i++) {\n const startDelim = delimiters[i]!\n if (startDelim.marker !== EQ) continue\n if (startDelim.end === -1) continue\n\n const endDelim = delimiters[startDelim.end]!\n\n let token: Token = state.tokens[startDelim.token]!\n token.type = 'mark_open'\n token.tag = 'mark'\n token.nesting = 1\n token.markup = '=='\n token.content = ''\n\n token = state.tokens[endDelim.token]!\n token.type = 'mark_close'\n token.tag = 'mark'\n token.nesting = -1\n token.markup = '=='\n token.content = ''\n\n const prev = state.tokens[endDelim.token - 1]\n if (prev && prev.type === 'text' && prev.content === '=') {\n loneMarkers.push(endDelim.token - 1)\n }\n }\n\n // 奇数残留 `=` 移到 close 后面,避免出现 `<mark>=</mark>x`\n while (loneMarkers.length > 0) {\n const i = loneMarkers.pop()!\n let j = i + 1\n while (\n j < state.tokens.length &&\n state.tokens[j]!.type === 'mark_close'\n ) {\n j += 1\n }\n j -= 1\n if (i !== j) {\n const tmp = state.tokens[j]!\n state.tokens[j] = state.tokens[i]!\n state.tokens[i] = tmp\n }\n }\n}\n\nexport function registerHighlightInline(md: MarkdownIt): void {\n // 放在 emphasis 之前,确保 `==**x**==` 中 `==` 比 `*` 先被识别\n // 如果用户开了 markdown.math(`markdown-it-mathjax3` 注册了 math_inline),\n // 我们要排在它之后 —— 不然 `$...==...$` 公式里的 `==` 会被误吃。\n try {\n // 先尝试 'after math_inline';失败说明 math 没注册,退到 emphasis 之前\n md.inline.ruler.after('math_inline', 'allyouneed_highlight', tokenize)\n } catch {\n md.inline.ruler.before('emphasis', 'allyouneed_highlight', tokenize)\n }\n // postProcess 与 emphasis 同阶段 (ruler2),按 inline / sub-inline 两层都处理\n md.inline.ruler2.before(\n 'emphasis',\n 'allyouneed_highlight',\n function highlightPostProcess(state) {\n const tokens_meta = (\n state as unknown as { tokens_meta?: Array<{ delimiters?: DelimEntry[] } | null> }\n ).tokens_meta\n const curr = (state as unknown as { delimiters?: DelimEntry[] })\n .delimiters\n if (curr) postProcess(state)\n if (tokens_meta) {\n for (const m of tokens_meta) {\n if (m && m.delimiters) {\n const proxy = {\n ...state,\n delimiters: m.delimiters,\n } as unknown as StateInline\n postProcess(proxy)\n }\n }\n }\n return false\n },\n )\n}\n","/** v0.3 highlight (`==text==`) 模块入口 */\nimport type MarkdownIt from 'markdown-it'\nimport { registerHighlightInline } from './rule.js'\n\nexport { registerHighlightInline }\n\nexport function registerHighlight(md: MarkdownIt): void {\n registerHighlightInline(md)\n}\n","/**\n * v0.3 — Obsidian 注释 `%%comment%%` 语法。\n *\n * 行为:\n * - inline `%%...%%`:静默吃掉,不渲染任何内容\n * - block 形式:整段都被 `%%` 包起来(可能跨多行)\n * ```\n * %%\n * multi-line comment\n * %%\n * ```\n * 整块从 token 流移除\n *\n * 实现:\n * - inline rule:碰到 `%%` 找到下一个 `%%`(可跨行?Obsidian 实际只在同段内匹配),\n * 吃掉,不 push token\n * - block rule:行首是 `%%`,扫到下一行的 `%%`(独占一行),整段当注释吃掉\n */\n\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type StateBlock from 'markdown-it/lib/rules_block/state_block.mjs'\nimport type MarkdownIt from 'markdown-it'\n\nconst PCT = 0x25 // '%'\n\nexport function makeCommentInlineRule(): (\n state: StateInline,\n silent: boolean,\n) => boolean {\n return function commentInline(state, silent): boolean {\n const start = state.pos\n const max = state.posMax\n if (start + 4 > max) return false\n if (state.src.charCodeAt(start) !== PCT) return false\n if (state.src.charCodeAt(start + 1) !== PCT) return false\n\n // 找下一个 `%%`,允许换行(Obsidian 行内注释可跨行)\n let pos = start + 2\n let found = -1\n while (pos < max - 1) {\n if (\n state.src.charCodeAt(pos) === PCT &&\n state.src.charCodeAt(pos + 1) === PCT\n ) {\n found = pos\n break\n }\n pos += 1\n }\n\n if (found < 0) return false\n if (silent) return true\n\n // 吃掉,不 push 任何 token\n state.pos = found + 2\n return true\n }\n}\n\n/**\n * block-level comment:`%%` 单独成行(允许尾随空格)起,\n * 下一个 `%%` 单独成行止,整段吃掉。\n *\n * 注意:markdown-it 的 block rule 接口要返回 true 表示\"消耗了若干行\"。\n */\nexport function makeCommentBlockRule(): (\n state: StateBlock,\n startLine: number,\n endLine: number,\n silent: boolean,\n) => boolean {\n return function commentBlock(state, startLine, endLine, silent): boolean {\n const pos = state.bMarks[startLine]! + state.tShift[startLine]!\n const max = state.eMarks[startLine]!\n // 必须以 `%%` 开头\n if (pos + 2 > max) return false\n if (state.src.charCodeAt(pos) !== PCT) return false\n if (state.src.charCodeAt(pos + 1) !== PCT) return false\n // 这一行 `%%` 之后必须只剩空白(才算独占一行 fence)\n const restStart = pos + 2\n const rest = state.src.slice(restStart, max)\n if (rest.trim() !== '') return false\n\n if (silent) return true\n\n // 找闭合:下一行起,寻找以 `%%` 独占的一行\n let next = startLine + 1\n let closed = false\n while (next < endLine) {\n const lpos = state.bMarks[next]! + state.tShift[next]!\n const lmax = state.eMarks[next]!\n if (\n lpos + 2 <= lmax &&\n state.src.charCodeAt(lpos) === PCT &&\n state.src.charCodeAt(lpos + 1) === PCT &&\n state.src.slice(lpos + 2, lmax).trim() === ''\n ) {\n closed = true\n break\n }\n next += 1\n }\n\n // 没找到闭合就吃到 endLine\n const lastLine = closed ? next + 1 : next\n state.line = lastLine\n return true\n }\n}\n\nexport function registerCommentsInline(md: MarkdownIt): void {\n // 放在 highlight 之前,避免 `%%` 被高亮规则误判(highlight 看 `==` 不会冲突,\n // 但越早跑越简单)\n md.inline.ruler.before(\n 'emphasis',\n 'allyouneed_comment_inline',\n makeCommentInlineRule(),\n )\n}\n\nexport function registerCommentsBlock(md: MarkdownIt): void {\n md.block.ruler.before(\n 'fence',\n 'allyouneed_comment_block',\n makeCommentBlockRule(),\n { alt: [] },\n )\n}\n","/** v0.3 comments (`%%...%%`) 模块入口 */\nimport type MarkdownIt from 'markdown-it'\nimport {\n registerCommentsInline,\n registerCommentsBlock,\n} from './rule.js'\n\nexport { registerCommentsInline, registerCommentsBlock }\n\nexport function registerComments(md: MarkdownIt): void {\n registerCommentsBlock(md)\n registerCommentsInline(md)\n}\n","/**\n * v0.3 — Pandoc 风格脚注。\n *\n * 支持的子集:\n * - 引用:`text[^id]` → 上标 `<sup><a>1</a></sup>`,自增编号\n * - 定义:行首 `[^id]: text...`(单行,**不支持**多段缩进续行 —— 留到 v0.4)\n * - 渲染:文末追加 `<section class=\"footnotes\">`,每个 def 一个 `<li>`,\n * 带反向链接箭头 ↩ 回到引用处\n *\n * 实现:\n * - block rule:扫到 `[^id]:` 起,把整行剩余文本当 def content,推一个\n * 私有 token 'footnote_def'(content=md inline 源),不影响主流\n * - inline rule:扫到 `[^id]` 推 'footnote_ref' token,记 id + 占位 number\n * - core rule(post 'inline'):收集所有 def + ref,按出现顺序编号,\n * 渲染 ref 用最终 number;在 tokens 末尾追加 footnotes section html_block\n *\n * 安全:\n * - id 只允许 `[\\w-]+`\n * - 同 id 多次引用 → 共用编号,反链多个箭头\n * - 引用了不存在的 id → 渲染成普通文本,不崩\n */\n\nimport type StateBlock from 'markdown-it/lib/rules_block/state_block.mjs'\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type StateCore from 'markdown-it/lib/rules_core/state_core.mjs'\nimport type MarkdownIt from 'markdown-it'\nimport { escapeHtml } from '../../utils/escape.js'\n\n/** 定义行:行首(允许 indent ≤3) `[^id]: rest`\n * 注:为简单起见 indent 必须 ≤3(markdown-it 默认 paragraph 阈值) */\nconst DEF_RE = /^\\[\\^([\\w-]+)\\]:\\s*(.*)$/\n/** 引用:`[^id]`,id 只允许 \\w 和 - */\nconst REF_RE = /^\\[\\^([\\w-]+)\\]/\n\n// ── block rule:抓 def ────────────────────────────────────────────\n\nfunction defBlockRule(\n state: StateBlock,\n startLine: number,\n endLine: number,\n silent: boolean,\n): boolean {\n const start = state.bMarks[startLine]! + state.tShift[startLine]!\n const max = state.eMarks[startLine]!\n const tShift = state.tShift[startLine]!\n if (tShift > 3) return false\n const line = state.src.slice(start, max)\n const m = DEF_RE.exec(line)\n if (!m) return false\n if (silent) return true\n\n const id = m[1]!\n const content = (m[2] ?? '').trim()\n\n const token = state.push('footnote_def', '', 0)\n token.meta = { id, content }\n token.map = [startLine, startLine + 1]\n token.hidden = true // 不直接渲染,等 core rule 收集\n\n state.line = startLine + 1\n // 防 endLine unused\n void endLine\n return true\n}\n\n// ── inline rule:抓 ref ──────────────────────────────────────────\n\nfunction refInlineRule(state: StateInline, silent: boolean): boolean {\n const start = state.pos\n if (state.src.charCodeAt(start) !== 0x5b /* [ */) return false\n if (state.src.charCodeAt(start + 1) !== 0x5e /* ^ */) return false\n const slice = state.src.slice(start)\n const m = REF_RE.exec(slice)\n if (!m) return false\n if (silent) return true\n\n const id = m[1]!\n const token = state.push('footnote_ref', '', 0)\n token.meta = { id }\n state.pos = start + m[0].length\n return true\n}\n\n// ── core rule:收集 + 编号 + 渲染 section ────────────────────────\n\ninterface DefRecord {\n id: string\n content: string\n number: number\n /** 这条 def 被哪几个 ref 引用,ref index → ref-token-anchor-id */\n refAnchors: string[]\n}\n\nfunction collectAndRender(state: StateCore): boolean {\n const tokens = state.tokens\n // 收集所有 def\n const defs = new Map<string, DefRecord>()\n // 把 ref 按出现顺序编号(只在 def 存在时分配编号;不存在保留 token,后面 render 兜底)\n let refSeq = 0\n let nextNumber = 1\n\n // pass 1:收集 def(不渲染顺序无关,只需要 content)\n for (let i = 0; i < tokens.length; i++) {\n const t = tokens[i]!\n if (t.type !== 'footnote_def') continue\n const meta = t.meta as { id: string; content: string }\n if (!defs.has(meta.id)) {\n defs.set(meta.id, {\n id: meta.id,\n content: meta.content,\n number: -1, // 在 ref 第一次遇到时分配\n refAnchors: [],\n })\n }\n // 把这个 def token 标记为完全空(等 core 渲染替换)\n t.type = 'html_block'\n t.content = ''\n t.hidden = true\n }\n\n // pass 2:扫所有 inline children,把 footnote_ref 改写为 html_inline\n for (const t of tokens) {\n if (t.type !== 'inline' || !t.children) continue\n for (let j = 0; j < t.children.length; j++) {\n const c = t.children[j]!\n if (c.type !== 'footnote_ref') continue\n const meta = c.meta as { id: string }\n const rec = defs.get(meta.id)\n if (!rec) {\n // 没找到 def:降级成原始文本 `[^id]`\n c.type = 'text'\n c.content = `[^${meta.id}]`\n c.meta = null\n continue\n }\n if (rec.number === -1) rec.number = nextNumber++\n const anchorId = `fnref-${escapeHtmlAttr(rec.id)}-${++refSeq}`\n rec.refAnchors.push(anchorId)\n\n c.type = 'html_inline'\n c.content =\n `<sup class=\"ayn-footnote-ref\" id=\"${anchorId}\">` +\n `<a href=\"#fn-${escapeHtmlAttr(rec.id)}\" data-footnote-ref>` +\n `[${rec.number}]` +\n `</a></sup>`\n c.meta = null\n }\n }\n\n // pass 3:把所有用到的 def(rec.number !== -1)按 number 排序后追加 section\n const used = Array.from(defs.values())\n .filter((d) => d.number !== -1)\n .sort((a, b) => a.number - b.number)\n\n if (used.length === 0) return false\n\n let html = '<section class=\"ayn-footnotes\"><hr><ol class=\"ayn-footnotes-list\">'\n for (const rec of used) {\n const renderedContent = state.md.renderInline(rec.content, state.env)\n const backlinks = rec.refAnchors\n .map(\n (anchor, idx) =>\n `<a class=\"ayn-footnote-backref\" href=\"#${anchor}\" ` +\n `data-footnote-backref aria-label=\"Back to reference ${rec.number}-${idx + 1}\">` +\n // U+2191 ↑ (UPWARDS ARROW),不是 emoji 字符;CSS font-family 强制\n // 非 emoji 字体保证显示一致(见 shared.css)\n `↑` +\n `</a>`,\n )\n .join(' ')\n html +=\n `<li id=\"fn-${escapeHtmlAttr(rec.id)}\" class=\"ayn-footnote-item\">` +\n `<span class=\"ayn-footnote-content\">${renderedContent}</span> ` +\n backlinks +\n `</li>`\n }\n html += '</ol></section>'\n\n const tail = new state.Token('html_block', '', 0)\n tail.content = html + '\\n'\n tokens.push(tail)\n\n return false\n}\n\nfunction escapeHtmlAttr(s: string): string {\n // id 只允许 \\w-,但还是过一次 escapeHtml 防意外\n return escapeHtml(s)\n}\n\n// ── 注册 ────────────────────────────────────────────────────────\n\nexport function registerFootnotes(md: MarkdownIt): void {\n md.block.ruler.before('reference', 'allyouneed_footnote_def', defBlockRule, {\n alt: ['paragraph', 'reference'],\n })\n md.inline.ruler.after('emphasis', 'allyouneed_footnote_ref', refInlineRule)\n md.core.ruler.after('inline', 'allyouneed_footnote_collect', collectAndRender)\n}\n","/**\n * v0.3 — Obsidian block-ref marker `^block-id`。\n *\n * 行为(渲染层简化版):\n * - 段落中或独立行末尾的 `^id` 被识别,从渲染文本中**剥除**\n * - 在所在 block(paragraph / heading / li / blockquote 等)的 open token 上\n * 附 `id=\"^block-id\"` 属性,作 DOM 锚点\n * - 用户可以通过 `<page>#^block-id` 直接跳转(浏览器原生 anchor scroll)\n *\n * 不在此版本做:\n * - VaultIndex 层登记 block-id(让 `[[note#^id]]` 走 resolver 跳转)\n * 这块需要碰 vault scanner,留到 v0.4\n *\n * 实现:\n * - core ruler(after 'inline'):扫所有 inline token,找 `^id`(末尾或前空白),\n * 从 content / children 中剥掉,把 id 写到前一个 open token 的 attrs\n */\n\nimport type StateCore from 'markdown-it/lib/rules_core/state_core.mjs'\nimport type Token from 'markdown-it/lib/token.mjs'\nimport type MarkdownIt from 'markdown-it'\n\n/** 末尾形式:`...\\s^id` 或 `^id`(独占)*/\nconst BLOCK_ID_TAIL_RE = /(?:^|\\s)\\^([A-Za-z0-9_-]+)\\s*$/\n\nfunction blockRefsRule(state: StateCore): boolean {\n const tokens = state.tokens\n for (let i = 0; i < tokens.length; i++) {\n const t = tokens[i]!\n if (t.type !== 'inline' || !t.children || t.children.length === 0) continue\n\n // 拼 inline 末尾文本(只看最后一个 text token,够覆盖 95% 用例)\n const lastIdx = findLastTextIdx(t.children)\n if (lastIdx < 0) continue\n const lastText = t.children[lastIdx]!\n const m = BLOCK_ID_TAIL_RE.exec(lastText.content)\n if (!m) continue\n\n const id = m[1]!\n // 从 text 末尾剥掉(留下前置空白也一起去掉)\n const matchedAt = lastText.content.length - m[0].length\n lastText.content = lastText.content.slice(0, matchedAt).replace(/\\s+$/, '')\n\n // 同步 inline.content(否则后续渲染可能误用旧 content)\n t.content = t.content.replace(BLOCK_ID_TAIL_RE, '').replace(/\\s+$/, '')\n\n // 把 id 加到上一个 *_open token(paragraph_open / heading_open / li_open ...)\n const opener = findPreviousOpen(tokens, i)\n if (opener) {\n addAttr(opener, 'id', `^${id}`)\n addClass(opener, 'ayn-block-anchor')\n }\n\n // 若剥完之后 last text 空了,把它移除(避免空 text 影响布局)\n if (lastText.content === '') {\n t.children.splice(lastIdx, 1)\n }\n }\n return false\n}\n\nfunction findLastTextIdx(children: Token[]): number {\n for (let i = children.length - 1; i >= 0; i--) {\n if (children[i]!.type === 'text') return i\n }\n return -1\n}\n\nfunction findPreviousOpen(tokens: Token[], inlineIdx: number): Token | null {\n for (let i = inlineIdx - 1; i >= 0; i--) {\n const t = tokens[i]!\n if (t.nesting === 1) return t\n }\n return null\n}\n\nfunction addAttr(token: Token, name: string, value: string): void {\n const existing = token.attrIndex(name)\n if (existing >= 0) {\n token.attrs![existing]![1] = value\n } else {\n token.attrPush([name, value])\n }\n}\n\nfunction addClass(token: Token, cls: string): void {\n const idx = token.attrIndex('class')\n if (idx >= 0) {\n const cur = token.attrs![idx]![1] ?? ''\n if (!cur.split(/\\s+/).includes(cls)) {\n token.attrs![idx]![1] = (cur + ' ' + cls).trim()\n }\n } else {\n token.attrPush(['class', cls])\n }\n}\n\nexport function registerBlockRefs(md: MarkdownIt): void {\n md.core.ruler.after('inline', 'allyouneed_block_refs', blockRefsRule)\n}\n","/**\n * markdown-it 入口。\n *\n * 高级用法:用户自己创建 markdown-it 实例,然后 md.use(allYouNeed, options)。\n * 此模式下需要由调用方负责提供 VaultIndex(通过 markdown-it env)。\n *\n * 用法示例:\n *\n * ```ts\n * import allYouNeed from 'vitepress-allyouneed/markdown-it'\n * import { scanVault, resolveOptions } from 'vitepress-allyouneed'\n *\n * const options = resolveOptions({ srcDir: '/path/to/vault' })\n * const index = scanVault(options)\n *\n * md.use(allYouNeed, options)\n *\n * // render 时把 index 注入 env\n * const html = md.render(markdown, { index, options })\n * ```\n */\n\nimport type MarkdownIt from 'markdown-it'\nimport type { ResolvedOptions, AllYouNeedOptions } from './core/types.js'\nimport { resolveOptions } from './core/config-bridge.js'\nimport { registerWikilinks } from './modules/wikilinks/index.js'\nimport {\n registerEmbedsOnly,\n registerEmbedBlockRule,\n} from './modules/embeds/index.js'\nimport { registerCallouts } from './modules/callouts/index.js'\nimport { registerHighlight } from './modules/highlight/index.js'\nimport { registerComments } from './modules/comments/index.js'\nimport { registerFootnotes } from './modules/footnotes/index.js'\nimport { registerBlockRefs } from './modules/block-refs/index.js'\n\n/**\n * markdown-it 插件函数。\n *\n * @param md markdown-it 实例\n * @param options AllYouNeedOptions 或已 resolve 过的 ResolvedOptions\n */\nfunction allYouNeedMarkdownIt(\n md: MarkdownIt,\n options?: AllYouNeedOptions | ResolvedOptions,\n): void {\n const resolved: ResolvedOptions =\n options && isResolved(options)\n ? options\n : resolveOptions(options as AllYouNeedOptions | undefined)\n\n const {\n wikilinks: wlOn,\n embeds: emOn,\n callouts: coOn,\n highlight: hlOn,\n comments: cmOn,\n footnotes: fnOn,\n blockRefs: brOn,\n } = resolved.modules\n\n if (wlOn && emOn) {\n registerWikilinks(md, 'both')\n registerEmbedBlockRule(md)\n } else if (wlOn) {\n registerWikilinks(md, 'wikilinks-only')\n // embeds 关掉时不注册 block rule\n } else if (emOn) {\n registerEmbedsOnly(md) // 内含 inline + block\n }\n\n // v0.3:Obsidian callouts(独立 core ruler,与 wikilinks/embeds 解耦)\n if (coOn) {\n registerCallouts(md)\n }\n\n // v0.3:`==text==` 高亮\n if (hlOn) {\n registerHighlight(md)\n }\n\n // v0.3:`%%comment%%` 注释(整段隐藏)\n if (cmOn) {\n registerComments(md)\n }\n\n // v0.3:Pandoc 风格 footnotes\n if (fnOn) {\n registerFootnotes(md)\n }\n\n // v0.3:block-ref `^id` 锚点(渲染层)\n if (brOn) {\n registerBlockRefs(md)\n }\n}\n\nfunction isResolved(\n o: AllYouNeedOptions | ResolvedOptions,\n): o is ResolvedOptions {\n // ResolvedOptions 有 'slugify' + 'modules' + 'srcDir'(都是必填)\n return (\n typeof (o as ResolvedOptions).slugify === 'function' &&\n typeof (o as ResolvedOptions).srcDir === 'string' &&\n typeof (o as ResolvedOptions).modules === 'object' &&\n (o as ResolvedOptions).modules !== null\n )\n}\n\nexport default allYouNeedMarkdownIt\nexport { allYouNeedMarkdownIt }\n","/**\n * Vite 插件入口。\n *\n * 职责:\n * - configResolved 时扫描 vault 建立 VaultIndex\n * - configureServer 注册 dev middleware(asset 流式响应,作为兜底)\n * - **resolveId**:拦截 markdown-it 渲染时产出的 /__ayn_asset__/ 占位 URL,\n * **直接返回 asset 的绝对文件路径**,后续交给 Vite 自带的资源管线处理:\n * - dev:Vite 自动按文件路径服务,URL 形如 /<srcDir 相对>/<asset 路径>\n * - build:Vite 自动 emit + 加 hash,URL 形如 /<assetsDir>/<name>-<hash>.<ext>\n * 这样我们就完全不用维护虚拟模块、不用写 load()、不会再撞 ?import 之类的边界\n * - handleHotUpdate:dev 增量更新\n * - config 钩子扩 server.fs.allow:用户的 vault 可能在项目根外,Vite 默认拒绝\n *\n * 设计:**完全不用 `\\0` 虚拟模块**。虚拟模块需要 Vite 在 URL 里把 id 编码成\n * `__x00__...`,加上 ?import 之类的 query,加上 URL 里 `/` 的歧义,导致 load()\n * 的 id 形态不稳定,要么找不到 asset 要么返回 HTML 把页面崩了(实测 v0.1\n * 收尾时撞过)。让 Vite 处理真实文件路径就完全没这一摊烦心事。\n */\n\nimport fs from 'node:fs'\nimport nodePath from 'node:path'\nimport type { Plugin, ResolvedConfig } from 'vite'\nimport type {\n AllYouNeedOptions,\n ResolvedOptions,\n VaultIndex,\n} from './core/types.js'\nimport { resolveOptions } from './core/config-bridge.js'\nimport { scanVault, updateFile, removeFile } from './core/vault/index.js'\nimport { createDevMiddleware } from './core/asset-pipeline/dev-middleware.js'\nimport { ASSET_PLACEHOLDER_PREFIX } from './core/asset-pipeline/build-emit.js'\nimport { toPosix } from './utils/path.js'\nimport { generateViewMarkdown } from './core/views/generate-md.js'\nimport { writeVaultData } from './core/views/generate-data.js'\n\nexport interface VitePluginAllYouNeedReturn extends Plugin {\n __getOptions(): ResolvedOptions\n __getIndex(): VaultIndex | undefined\n}\n\n/** 剥掉 ?query 和 #hash —— Vite 会带各种后缀来 */\nfunction stripQueryAndHash(id: string): string {\n return id.split('?')[0]!.split('#')[0]!\n}\n\nexport function viteAllYouNeed(\n userOptions: AllYouNeedOptions = {},\n): VitePluginAllYouNeedReturn {\n let resolved: ResolvedOptions\n let index: VaultIndex | undefined\n let viteConfig: ResolvedConfig | undefined\n\n const plugin: VitePluginAllYouNeedReturn = {\n name: 'vitepress-allyouneed',\n\n /**\n * 在 Vite 配置定型前扩 server.fs.allow,让我们的 vault srcDir 可被 Vite\n * 服务(即便 srcDir 不在项目根下)。\n */\n config(_userViteConfig, _envCtx) {\n const srcDirOpt = userOptions.srcDir\n if (!srcDirOpt) return undefined\n const abs = toPosix(nodePath.resolve(srcDirOpt))\n return {\n server: {\n fs: {\n allow: [abs],\n },\n },\n }\n },\n\n configResolved(cfg) {\n viteConfig = cfg\n resolved = resolveOptions(userOptions, {\n srcDir: userOptions.srcDir ?? cfg.root,\n base: userOptions.base ?? cfg.base,\n cleanUrls: userOptions.cleanUrls,\n })\n try {\n index = scanVault(resolved)\n\n // v0.2:生成虚拟视图 .md(若 views 模块开)\n if (resolved.modules.views) {\n const mdReport = generateViewMarkdown(resolved, index)\n for (const written of mdReport.written) {\n cfg.logger.info(`[vitepress-allyouneed] 生成视图 ${written}`)\n }\n for (const skipped of mdReport.skipped) {\n cfg.logger.warn(\n `[vitepress-allyouneed] 跳过 ${skipped.path}: ${skipped.reason}`,\n )\n }\n if (mdReport.written.length > 0) {\n index = scanVault(resolved)\n }\n try {\n const dataReport = writeVaultData(index, resolved)\n cfg.logger.info(\n `[vitepress-allyouneed] 写 ${dataReport.path} (${dataReport.bytes}B)`,\n )\n } catch (err) {\n cfg.logger.warn(\n `[vitepress-allyouneed] vault-data.json 写入失败: ${\n err instanceof Error ? err.message : String(err)\n }`,\n )\n }\n }\n\n if (index.warnings.length > 0) {\n const top = index.warnings.slice(0, 10)\n for (const w of top) {\n cfg.logger.warn(`[vitepress-allyouneed] ${w.message}`)\n }\n if (index.warnings.length > top.length) {\n cfg.logger.warn(\n `[vitepress-allyouneed] (...还有 ${\n index.warnings.length - top.length\n } 条告警)`,\n )\n }\n }\n } catch (err) {\n cfg.logger.error(\n `[vitepress-allyouneed] vault 扫描失败: ${\n err instanceof Error ? err.message : String(err)\n }`,\n )\n index = undefined\n }\n },\n\n configureServer(server) {\n if (!index) return\n const mw = createDevMiddleware(index, resolved)\n return () => {\n server.middlewares.use(mw)\n }\n },\n\n handleHotUpdate(ctx) {\n if (!index) return\n try {\n const stat = fs.statSync(ctx.file)\n if (stat.isFile()) {\n updateFile(index, ctx.file, resolved)\n } else if (!fs.existsSync(ctx.file)) {\n removeFile(index, ctx.file, resolved)\n }\n } catch {\n removeFile(index, ctx.file, resolved)\n }\n // v0.2:数据变了 → 重新生成 vault-data.json\n if (resolved.modules.views) {\n try {\n writeVaultData(index, resolved)\n } catch {\n /* */\n }\n }\n },\n\n /**\n * 拦截占位符 URL,**返回真实绝对文件路径**(POSIX 风格)。\n *\n * Vite 拿到文件路径会:\n * - dev:按文件系统服务,id 经 transform 后变成 `export default '<url>'`\n * - build:emit asset、Rollup 自动加 hash,导出最终 URL\n */\n resolveId(id) {\n if (!index) return null\n const stripped = stripQueryAndHash(id)\n const ph = ASSET_PLACEHOLDER_PREFIX // '/__ayn_asset__/'\n const phIdx = stripped.indexOf(ph)\n if (phIdx < 0) return null\n const encoded = stripped.slice(phIdx + ph.length)\n let relPath: string\n try {\n relPath = decodeURI(encoded)\n } catch {\n return null\n }\n const asset = index.assetsByRelativePath.get(relPath)\n if (!asset) return null\n // 把原 query(?import / ?inline / ?url 等)透传给下游,否则 Vite 会\n // 用错误的 transform 来处理\n const query = id.slice(stripped.length)\n return asset.absolutePath + query\n },\n\n /**\n * 给 vitepress.ts wrapper 用。\n */\n __getOptions() {\n return resolved\n },\n __getIndex() {\n return index\n },\n }\n\n // 防 unused\n void viteConfig\n\n return plugin\n}\n\nexport default viteAllYouNeed\n","/**\n * Dev 模式中间件 —— 拦截未知 URL,从 vault asset 索引里找文件流式响应。\n *\n * 查找顺序:\n * 1. **按相对路径**(`/<base>/<relativePath>`)—— resolveId/load 路径下,\n * Vue 编译后的 `<img src>` 解析出来的 URL 走这条\n * 2. **按 basename** —— 用户直接在 markdown 用绝对 URL `/foo.png` 时兜底\n * 3. 都没命中 → next() 给 Vite 默认 404\n *\n * 零拷贝、零配置。改图片直接刷新就能看到。\n */\n\nimport fs from 'node:fs'\nimport nodePath from 'node:path'\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport type {\n VaultIndex,\n ResolvedOptions,\n AssetEntry,\n} from '../types.js'\nimport { basename } from '../../utils/path.js'\n\nexport type DevMiddleware = (\n req: IncomingMessage,\n res: ServerResponse,\n next: () => void,\n) => void\n\nexport function createDevMiddleware(\n index: VaultIndex,\n options: ResolvedOptions,\n): DevMiddleware {\n return (req, res, next) => {\n if (!req.url) return next()\n\n const cleanPath = req.url.split('?')[0]!.split('#')[0]!\n\n // 把 base 前缀剥掉,得到站内绝对路径\n let inSiteUrl = cleanPath\n if (options.base !== '/' && cleanPath.startsWith(options.base)) {\n inSiteUrl = '/' + cleanPath.slice(options.base.length)\n }\n\n let decoded: string\n try {\n decoded = decodeURIComponent(inSiteUrl)\n } catch {\n return next()\n }\n\n // 必须含扩展名才尝试解析(避免误吞 /about 这种页面路由)\n if (!/\\.[a-zA-Z0-9]+$/.test(decoded)) return next()\n\n // 1) 先按相对路径查\n const relCandidate = decoded.replace(/^\\/+/, '')\n let asset: AssetEntry | undefined =\n index.assetsByRelativePath.get(relCandidate)\n\n // 2) 再按 basename 查\n if (!asset) {\n const bn = basename(decoded)\n const map = options.caseSensitive\n ? index.assetsByBasename\n : index.assetsByBasenameLower\n const key = options.caseSensitive ? bn : bn.toLowerCase()\n const candidates = map.get(key)\n if (candidates && candidates.length > 0) asset = candidates[0]\n }\n\n if (!asset) return next()\n\n let stat: fs.Stats\n try {\n stat = fs.statSync(asset.absolutePath)\n } catch {\n return next()\n }\n\n res.statusCode = 200\n res.setHeader('Content-Type', guessMime(asset.extension))\n res.setHeader('Content-Length', String(stat.size))\n res.setHeader('Cache-Control', 'no-cache')\n\n fs.createReadStream(asset.absolutePath)\n .on('error', () => next())\n .pipe(res)\n }\n}\n\n// 极简 MIME 映射,够 vault 里常见 asset 用。\nconst MIME: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n bmp: 'image/bmp',\n avif: 'image/avif',\n ico: 'image/x-icon',\n mp4: 'video/mp4',\n webm: 'video/webm',\n mov: 'video/quicktime',\n m4v: 'video/x-m4v',\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n ogg: 'audio/ogg',\n m4a: 'audio/mp4',\n flac: 'audio/flac',\n pdf: 'application/pdf',\n canvas: 'application/json',\n excalidraw: 'application/json',\n}\n\nfunction guessMime(ext: string): string {\n return MIME[ext.toLowerCase()] ?? 'application/octet-stream'\n}\n\n// 防 unused\nexport { nodePath }\n","/**\n * v0.2 — 在 srcDir 根目录生成 3 个虚拟视图 .md 文件。\n *\n * - 不覆盖用户文件:已存在且没我们的 sentinel,跳过 + 告警\n * - 可重新生成:存在但带 sentinel(说明上次是我们生成的),允许覆盖升级模板\n */\n\nimport fs from 'node:fs'\nimport nodePath from 'node:path'\nimport type { ResolvedOptions, VaultIndex } from '../types.js'\n\nexport const VIEW_SENTINEL =\n '<!-- generated by vitepress-allyouneed (do not edit; will be regenerated) -->'\n\ntype ViewKind = 'graph' | 'stats' | 'tags'\n\ninterface ViewTemplate {\n kind: ViewKind\n fileName: string\n title: string\n component: string\n}\n\nexport interface GenerateMdReport {\n written: string[]\n skipped: { path: string; reason: string }[]\n}\n\nexport function generateViewMarkdown(\n options: ResolvedOptions,\n index: VaultIndex,\n): GenerateMdReport {\n const report: GenerateMdReport = { written: [], skipped: [] }\n if (!options.modules.views) return report\n\n const srcDir = nodePath.resolve(options.srcDir)\n const prefix = options.views.urlPrefix\n const viewDir = prefix ? nodePath.join(srcDir, prefix) : srcDir\n\n // 子目录方式时,先建目录\n if (prefix) {\n try {\n fs.mkdirSync(viewDir, { recursive: true })\n } catch {\n /* mkdir 失败下面 write 也会失败,统一在那里报 */\n }\n }\n\n const views = buildViewList(options)\n\n for (const v of views) {\n const target = nodePath.join(viewDir, v.fileName)\n\n if (fs.existsSync(target)) {\n let existing: string\n try {\n existing = fs.readFileSync(target, 'utf8')\n } catch {\n report.skipped.push({ path: target, reason: '文件不可读,跳过' })\n continue\n }\n if (!existing.includes(VIEW_SENTINEL)) {\n report.skipped.push({\n path: target,\n reason:\n `用户已有同名文件,不覆盖。要启用此视图请:` +\n `(a) 删除该文件 / (b) views.names.${v.kind} 改名 / (c) views.enabled.${v.kind}: false 关掉`,\n })\n continue\n }\n }\n\n try {\n fs.writeFileSync(target, renderTemplate(v), 'utf8')\n report.written.push(target)\n void index\n } catch (err) {\n report.skipped.push({\n path: target,\n reason: `写入失败: ${err instanceof Error ? err.message : String(err)}`,\n })\n }\n }\n\n return report\n}\n\nfunction buildViewList(options: ResolvedOptions): ViewTemplate[] {\n const { enabled, names, sidebarText, graphMaxNodes } = options.views\n const list: ViewTemplate[] = []\n if (enabled.graph) {\n list.push({\n kind: 'graph',\n fileName: `${names.graph}.md`,\n title: sidebarText.graph,\n // 把配置里的 graphMaxNodes 直接注入到组件 prop\n component: `<VaultGraph :max-nodes=\"${graphMaxNodes}\" />`,\n })\n }\n if (enabled.stats) {\n list.push({\n kind: 'stats',\n fileName: `${names.stats}.md`,\n title: sidebarText.stats,\n component: '<VaultStats />',\n })\n }\n if (enabled.tags) {\n list.push({\n kind: 'tags',\n fileName: `${names.tags}.md`,\n title: sidebarText.tags,\n component: '<Tags />',\n })\n }\n return list\n}\n\nfunction renderTemplate(v: ViewTemplate): string {\n // 关键:frontmatter `---` 必须是文件**第一行**,否则 VitePress / gray-matter\n // 不识别。sentinel HTML 注释放到 frontmatter 之后。\n // 视图页全屏展示 — sidebar/aside/outline 都隐藏,只剩中间 graph/stats/tags 组件\n return [\n '---',\n `title: ${v.title}`,\n 'layout: doc',\n 'sidebar: false',\n 'aside: false',\n 'outline: false',\n '---',\n '',\n VIEW_SENTINEL,\n '',\n `# ${v.title}`,\n '',\n v.component,\n '',\n ].join('\\n')\n}\n","/**\n * v0.2 — 把 VaultIndex 序列化为前端 JSON,放 srcDir/public/。\n *\n * 边(edges)和正文 #tag 在 markdown-it 渲染阶段才能被填进 VaultIndex.backlinks /\n * tags。我们这个函数在 vite plugin configResolved 阶段(渲染之前)就跑,\n * 所以**自己从 file.content 用正则提取** wikilink 和 #tag 写进 JSON,不依赖\n * 运行时 backlinks。否则 Graph 永远空 / Tags 不含正文标签。\n */\n\nimport fs from 'node:fs'\nimport nodePath from 'node:path'\nimport type {\n ResolvedOptions,\n VaultIndex,\n FileEntry,\n} from '../types.js'\nimport { stripMarkdownExt, toPosix, basename } from '../../utils/path.js'\n\nexport interface VaultData {\n nodes: VaultDataNode[]\n edges: VaultDataEdge[]\n tags: Record<string, VaultDataTagInfo>\n stats: VaultDataStats\n meta: { generatedAt: number; pluginVersion: string }\n}\nexport interface VaultDataNode {\n id: string\n title: string\n url: string\n tags: string[]\n mtime: number\n}\nexport interface VaultDataEdge {\n source: string\n target: string\n type: 'wikilink' | 'transclusion'\n}\nexport interface VaultDataTagInfo {\n count: number\n files: {\n id: string\n url: string\n title: string\n mtime: number\n path: string\n /** 该文件除了\"当前 tag\"之外的其它 tag */\n otherTags: string[]\n }[]\n}\nexport interface VaultDataStats {\n totalFiles: number\n totalAssets: number\n totalWikilinks: number\n totalTags: number\n totalWarnings: number\n mostRecent: { id: string; url: string; title: string; mtime: number }[]\n}\n\nconst PLUGIN_VERSION = '0.2.0-beta.0'\n\n// `[[...]]` 或 `![[...]]`,不跨行,允许 |alias 和 #heading\nconst WIKILINK_RE = /(!?)\\[\\[([^\\]\\n|#]+)(?:#[^\\]\\n|]*)?(?:\\|[^\\]\\n]*)?\\]\\]/g\n\n// 正文 #tag(和 src/modules/tags/rule.ts 的语义保持一致,但允许更宽前置字符)\nconst BODY_TAG_RE =\n /(?:^|[\\s([{,;。,;])#([\\p{L}_][\\p{L}\\p{N}_/-]*)/gu\n\nexport function buildVaultData(\n index: VaultIndex,\n options: ResolvedOptions,\n): VaultData {\n // 排除插件自动生成的视图文件(_perspectives_/graph.md 等),它们是系统\n // 生成的工具页,不应该出现在 stats / graph / tags 统计里\n const viewsPrefix = options.views.urlPrefix\n ? options.views.urlPrefix.replace(/^\\/+|\\/+$/g, '') + '/'\n : ''\n const isPerspective = (f: FileEntry): boolean => {\n if (!viewsPrefix) return false\n return f.relativePath.startsWith(viewsPrefix)\n }\n const userFiles: FileEntry[] = []\n for (const f of index.files.values()) {\n if (!isPerspective(f)) userFiles.push(f)\n }\n\n // 节点\n const nodes: VaultDataNode[] = []\n for (const f of userFiles) {\n nodes.push({\n id: f.relativePath,\n title: pickTitle(f),\n url: f.url,\n tags: [...f.tags],\n mtime: f.mtime,\n })\n }\n\n // 边:从每个文件的 content 用正则提取 wikilink\n // 同一 source→target 去重:若同时有 wikilink + transclusion,保留 transclusion\n // (transclusion 是更\"强\"的关系,渲染出来视觉上也更重)\n const edgeMap = new Map<string, VaultDataEdge>()\n for (const f of userFiles) {\n const matches = f.content.matchAll(WIKILINK_RE)\n for (const m of matches) {\n const isEmbed = m[1] === '!'\n const rawTarget = m[2]!.trim()\n const target = resolveTargetSimple(rawTarget, index, options)\n if (!target) continue\n if (isPerspective(target)) continue\n if (target.relativePath === f.relativePath) continue\n const key = `${f.relativePath}\u0000${target.relativePath}`\n const existing = edgeMap.get(key)\n // 已有 edge,且新的不是 embed(更强类型)→ 跳过\n if (existing && existing.type === 'transclusion' && !isEmbed) continue\n edgeMap.set(key, {\n source: f.relativePath,\n target: target.relativePath,\n type: isEmbed ? 'transclusion' : 'wikilink',\n })\n }\n }\n const edges: VaultDataEdge[] = [...edgeMap.values()]\n\n // 标签:frontmatter tags + 正文 #tag(若开 parseInlineTags)\n const tagsMap = new Map<string, FileEntry[]>()\n for (const f of userFiles) {\n const allTags = new Set(f.tags)\n if (options.views.parseInlineTags) {\n for (const tm of f.content.matchAll(BODY_TAG_RE)) {\n allTags.add(tm[1]!)\n }\n }\n for (const tag of allTags) {\n const arr = tagsMap.get(tag) ?? []\n arr.push(f)\n tagsMap.set(tag, arr)\n }\n }\n // 每个 file 完整 tag set(用于\"该文件除了当前 tag 之外的其它 tag\")\n const allTagsByFile = new Map<string, string[]>()\n for (const f of userFiles) {\n const set = new Set(f.tags)\n if (options.views.parseInlineTags) {\n for (const tm of f.content.matchAll(BODY_TAG_RE)) set.add(tm[1]!)\n }\n allTagsByFile.set(f.relativePath, [...set])\n }\n\n const tags: Record<string, VaultDataTagInfo> = {}\n for (const [tag, files] of tagsMap) {\n // 按 mtime 倒序(最近修改在上)\n const sorted = [...files].sort((a, b) => b.mtime - a.mtime)\n tags[tag] = {\n count: files.length,\n files: sorted.map((f) => ({\n id: f.relativePath,\n url: f.url,\n title: pickTitle(f),\n mtime: f.mtime,\n path: f.relativePath,\n otherTags: (allTagsByFile.get(f.relativePath) ?? []).filter(\n (t) => t !== tag,\n ),\n })),\n }\n }\n\n // 最近修改 10\n const mostRecent = [...userFiles]\n .sort((a, b) => b.mtime - a.mtime)\n .slice(0, 10)\n .map((f) => ({\n id: f.relativePath,\n url: f.url,\n title: pickTitle(f),\n mtime: f.mtime,\n }))\n\n return {\n nodes,\n edges,\n tags,\n stats: {\n totalFiles: userFiles.length,\n totalAssets: index.assets.size,\n totalWikilinks: edges.length,\n totalTags: Object.keys(tags).length,\n totalWarnings: index.warnings.length,\n mostRecent,\n },\n meta: { generatedAt: Date.now(), pluginVersion: PLUGIN_VERSION },\n }\n}\n\nexport function writeVaultData(\n index: VaultIndex,\n options: ResolvedOptions,\n): { path: string; bytes: number } {\n const data = buildVaultData(index, options)\n const json = JSON.stringify(data)\n const publicDir = nodePath.join(nodePath.resolve(options.srcDir), 'public')\n fs.mkdirSync(publicDir, { recursive: true })\n const out = nodePath.join(publicDir, options.views.dataFileName)\n fs.writeFileSync(out, json, 'utf8')\n return { path: out, bytes: json.length }\n}\n\nfunction pickTitle(f: FileEntry): string {\n const fm = f.frontmatter as { title?: unknown } | undefined\n if (fm && typeof fm.title === 'string' && fm.title.trim()) {\n return fm.title.trim()\n }\n return f.basename\n}\n\n/**\n * 简化版 target → FileEntry 查找,与 Resolver 行为基本一致但不导出 URL。\n */\nfunction resolveTargetSimple(\n rawTarget: string,\n index: VaultIndex,\n options: ResolvedOptions,\n): FileEntry | undefined {\n const target = stripMarkdownExt(toPosix(rawTarget))\n if (!target) return undefined\n\n // 路径形式\n if (target.includes('/')) {\n return (\n index.byRelativePath.get(target) ??\n index.byRelativePath.get(target + '.md') ??\n index.byRelativePath.get(target + '.markdown')\n )\n }\n\n // alias\n const aliasKey = options.caseSensitive ? target : target.toLowerCase()\n const aliased = index.byAlias.get(aliasKey)\n if (aliased) return aliased\n\n // basename\n const map = options.caseSensitive\n ? index.byBasename\n : index.byBasenameLower\n const candidates = map.get(\n options.caseSensitive ? target : target.toLowerCase(),\n )\n if (!candidates || candidates.length === 0) return undefined\n if (candidates.length === 1) return candidates[0]\n\n // 多个 → 取最短路径\n return [...candidates].sort(\n (a, b) =>\n a.relativePath.split('/').length - b.relativePath.split('/').length,\n )[0]\n}\n\n// 防 unused warn\nexport { basename }\n","/**\n * v0.2 — 正文 #tag inline rule(Unicode 友好,带边界过滤)。\n */\n\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs'\nimport type MarkdownIt from 'markdown-it'\nimport type { AllYouNeedEnv } from '../../core/types.js'\nimport { escapeHtml } from '../../utils/escape.js'\n\nconst TAG_RE = /^#([\\p{L}_][\\p{L}\\p{N}_/-]*)/u\n\nfunction isValidPrecedingChar(c: string | undefined): boolean {\n if (c === undefined) return true\n if (/\\s/.test(c)) return true\n if ('([{,;。,;'.includes(c)) return true\n return false\n}\n\nexport function makeTagRule(): (state: StateInline, silent: boolean) => boolean {\n return function tagRule(state, silent) {\n const start = state.pos\n const src = state.src\n if (src.charCodeAt(start) !== 0x23 /* # */) return false\n\n const prev = start === 0 ? undefined : src[start - 1]\n if (!isValidPrecedingChar(prev)) return false\n\n const slice = src.slice(start)\n const m = TAG_RE.exec(slice)\n if (!m) return false\n\n const tag = m[1]!\n if (silent) return true\n\n const env = state.env as AllYouNeedEnv & { referencedTags?: Set<string> }\n if (!env.referencedTags) env.referencedTags = new Set()\n env.referencedTags.add(tag)\n\n const tagsViewName = env.options?.views?.names?.tags ?? 'tags'\n const urlPrefix = env.options?.views?.urlPrefix ?? '_perspectives_'\n const base = env.options?.base ?? '/'\n const prefixSeg = urlPrefix ? `${urlPrefix}/` : ''\n const href = `${base}${prefixSeg}${tagsViewName}#${encodeURIComponent(tag)}`\n const html =\n `<a class=\"ayn-tag\" data-tag=\"${escapeHtml(tag)}\" ` +\n `href=\"${escapeHtml(href)}\">#${escapeHtml(tag)}</a>`\n\n const token = state.push('html_inline', '', 0)\n token.content = html\n\n state.pos = start + m[0].length\n return true\n }\n}\n\nexport function registerTagsInline(md: MarkdownIt): void {\n md.inline.ruler.before('link', 'allyouneed_tags', makeTagRule())\n}\n","/**\n * v0.2 — 把 3 个视图条目自动追加到 VitePress sidebar 末尾。\n *\n * 支持 array / object(per-path)/ undefined 三种 sidebar 形态。\n */\n\nimport type { ResolvedOptions } from '../types.js'\n\ninterface SidebarItem {\n text?: string\n link?: string\n items?: SidebarItem[]\n collapsed?: boolean\n base?: string\n}\n\ntype SidebarConfig =\n | SidebarItem[]\n | Record<string, SidebarItem[]>\n | undefined\n\nexport function injectViewsSidebar(\n sidebar: SidebarConfig,\n options: ResolvedOptions,\n): SidebarConfig {\n if (!options.modules.views) return sidebar\n const inject = options.views.injectInto\n const group = buildViewsGroup(options)\n if (!group) return sidebar\n\n // 即使 injectInto='nav' 或 'off',也要给 /_perspectives_/ URL 配 fallback\n // sidebar(per-folder 模式)。否则点 nav 下拉进 graph,左侧 sidebar 找不到\n // key 而显示空。\n const wantSidebar = inject === 'sidebar' || inject === 'both'\n\n if (Array.isArray(sidebar)) {\n if (wantSidebar && !sidebar.some((it) => it.text === group.text)) {\n sidebar.push(group)\n }\n return sidebar\n }\n\n if (sidebar && typeof sidebar === 'object') {\n if (wantSidebar) {\n // 每个 per-path sidebar 末尾追加 Perspectives 组\n for (const path of Object.keys(sidebar)) {\n const arr = sidebar[path]\n if (Array.isArray(arr) && !arr.some((it) => it.text === group.text)) {\n arr.push(group)\n }\n }\n }\n // _perspectives_/ 自身的 fallback sidebar(无论哪种 injectInto 都加)。\n // **key 不带 base**(VitePress sidebar 用 site-root 相对前缀做 URL 匹配)\n const prefix = options.views.urlPrefix\n ? options.views.urlPrefix.replace(/^\\/+|\\/+$/g, '')\n : ''\n if (prefix) {\n const persPath = `/${prefix}/`\n if (!sidebar[persPath]) {\n sidebar[persPath] = buildPerspectivesFallbackSidebar(\n sidebar,\n group,\n options.base.endsWith('/') ? options.base : options.base + '/',\n )\n }\n }\n return sidebar\n }\n\n return [group]\n}\n\n/**\n * 给 _perspectives_/ URL 单独生成一份 sidebar:\n * - 第一项总是\"返回首页\"\n * - 然后每个**其它顶层 path**(/guide/, /tour/, /test/ 等)做成一个简单 link 项,\n * 让用户从视图页能跳回任何 tab(VitePress 不会保留\"之前在哪\",这是 URL 决定的)\n * - 最后是 perspectives 组本身\n */\nfunction buildPerspectivesFallbackSidebar(\n allSidebars: Record<string, SidebarItem[]>,\n group: SidebarItem,\n base: string,\n): SidebarItem[] {\n // link 都 strip base(VitePress 会自动 prepend)\n const out: SidebarItem[] = [{ text: 'Home', link: '/' }]\n const topPaths = Object.keys(allSidebars).filter(\n (p) => p !== base && !p.endsWith('/_perspectives_/'),\n )\n for (const p of topPaths) {\n const seg =\n p.replace(/^\\/|\\/$/g, '').split('/').filter(Boolean).pop() ?? p\n const text = seg.charAt(0).toUpperCase() + seg.slice(1)\n // p 形如 '/vitepress-allyouneed/guide/' → strip base 后 '/guide/'\n const b = base.endsWith('/') ? base : base + '/'\n const stripped = b !== '/' && p.startsWith(b) ? '/' + p.slice(b.length) : p\n out.push({ text, link: stripped })\n }\n out.push(group)\n return out\n}\n\nfunction buildViewsGroup(options: ResolvedOptions): SidebarItem | null {\n const { enabled, names, sidebarText, urlPrefix } = options.views\n // ⚠ link **不带 base** —— VitePress sidebar/nav 约定:配置里 link 用 site-root\n // 相对路径,渲染时 VitePress 自动 prepend base。带了会双重 prefix 404(build 后)。\n const prefixSeg = urlPrefix ? `/${urlPrefix}` : ''\n const items: SidebarItem[] = []\n if (enabled.graph) {\n items.push({ text: sidebarText.graph, link: `${prefixSeg}/${names.graph}` })\n }\n if (enabled.stats) {\n items.push({ text: sidebarText.stats, link: `${prefixSeg}/${names.stats}` })\n }\n if (enabled.tags) {\n items.push({ text: sidebarText.tags, link: `${prefixSeg}/${names.tags}` })\n }\n if (items.length === 0) return null\n return {\n text: sidebarText.group,\n collapsed: true,\n items,\n }\n}\n\n// ── v0.3:把 Perspectives 放到 nav 下拉里(per-folder 模式推荐)─────\n\ninterface NavItem {\n text: string\n link?: string\n items?: NavItem[]\n activeMatch?: string\n}\n\ntype NavConfig = NavItem[] | undefined\n\n/**\n * 在 themeConfig.nav 末尾追加一个 Perspectives 下拉。\n * 仅当 views.injectInto ∈ {'nav','both'} 时调用。\n * 如果 nav 里已有同名(views.sidebarText.group)项,跳过避免重复。\n */\nexport function injectViewsNav(\n nav: NavConfig,\n options: ResolvedOptions,\n): NavConfig {\n if (!options.modules.views) return nav\n const inject = options.views.injectInto\n if (inject !== 'nav' && inject !== 'both') return nav\n\n const group = buildViewsGroup(options)\n if (!group || !group.items || group.items.length === 0) return nav\n\n const navItem: NavItem = {\n text: group.text!,\n items: group.items.map((it) => ({\n text: it.text!,\n link: it.link!,\n })),\n }\n\n const arr = Array.isArray(nav) ? [...nav] : []\n if (!arr.some((it) => it.text === navItem.text)) {\n arr.push(navItem)\n }\n return arr\n}\n","/**\n * v0.3 — 解析用户手写的 `_sidebar.md` 文件,作为该目录的 sidebar override。\n *\n * 两种写法都支持(混用也行,frontmatter.sidebar 优先):\n *\n * 1) frontmatter.sidebar 数组(VitePress 原生 sidebar shape)\n * ```yaml\n * ---\n * sidebar:\n * - text: Overview\n * link: /guide/overview\n * - text: Docs\n * collapsed: false\n * items:\n * - text: Install\n * link: /guide/docs/install\n * ---\n * ```\n *\n * 2) markdown 列表(更 Obsidian 友好,支持嵌套)\n * ```markdown\n * - [[overview|Overview]]\n * - Docs\n * - [[docs/install|Install]]\n * - [[docs/configure|Configure]]\n * - Advanced\n * - [[advanced/custom-theme|Custom theme]]\n * ```\n * - 每行 `-` 起,2 空格缩进表示子级(也支持 tab)\n * - 含 `[[wikilink|text]]` → SidebarItem { text, link }\n * - 含 `[text](link)` → 同\n * - 纯文字 → group title(无 link,可有 items)\n */\n\nimport type { FileEntry, VaultIndex, ResolvedOptions } from '../types.js'\nimport type { SidebarItem } from './types.js'\nimport { stripMarkdownExt, toPosix } from '../../utils/path.js'\n\n/** 检查一个 FileEntry 是不是 _sidebar.md(大小写不敏感) */\nexport function isSidebarOverrideFile(entry: FileEntry): boolean {\n return entry.basename.toLowerCase() === '_sidebar'\n}\n\n/**\n * 解析 _sidebar.md → SidebarItem[]。\n * 失败返回 null(调用方降级到自动生成)。\n */\nexport function parseSidebarOverride(\n entry: FileEntry,\n index: VaultIndex,\n options: ResolvedOptions,\n): SidebarItem[] | null {\n // 1) frontmatter.sidebar 优先\n const fmSidebar = (entry.frontmatter as { sidebar?: unknown }).sidebar\n if (Array.isArray(fmSidebar)) {\n return normalizeItems(fmSidebar as SidebarItem[])\n }\n\n // 2) markdown list 解析\n const items = parseList(entry.content, entry, index, options)\n if (items.length === 0) return null\n return items\n}\n\n/** 把用户写的 SidebarItem(可能字段不全)归一化 */\nfunction normalizeItems(items: SidebarItem[]): SidebarItem[] {\n return items.map((it) => {\n const out: SidebarItem = {}\n if (typeof it.text === 'string') out.text = it.text\n if (typeof it.link === 'string') out.link = it.link\n if (typeof it.base === 'string') out.base = it.base\n if (typeof it.collapsed === 'boolean') out.collapsed = it.collapsed\n if (Array.isArray(it.items)) out.items = normalizeItems(it.items)\n return out\n })\n}\n\n// ── markdown list 解析 ──────────────────────────────────────────\n\ninterface ParsedLine {\n indent: number\n text: string | null\n link: string | null\n collapsed?: boolean\n}\n\nconst LINE_RE = /^(\\s*)-\\s+(.*)$/\nconst WIKILINK_RE = /^\\[\\[([^\\]\\n|#]+)(?:#[^\\]\\n|]*)?(?:\\|([^\\]\\n]+))?\\]\\]/\nconst MD_LINK_RE = /^\\[([^\\]]+)\\]\\(([^)]+)\\)/\n\nfunction parseList(\n src: string,\n entry: FileEntry,\n index: VaultIndex,\n options: ResolvedOptions,\n): SidebarItem[] {\n const lines = src.split(/\\r?\\n/)\n const parsed: ParsedLine[] = []\n let inFence = false\n for (const raw of lines) {\n if (/^```|^~~~/.test(raw.trim())) {\n inFence = !inFence\n continue\n }\n if (inFence) continue\n const m = LINE_RE.exec(raw)\n if (!m) continue\n const indent = m[1]!.replace(/\\t/g, ' ').length\n const body = m[2]!.trim()\n parsed.push(parseLineBody(indent, body, entry, index, options))\n }\n return buildTree(parsed)\n}\n\nfunction parseLineBody(\n indent: number,\n body: string,\n entry: FileEntry,\n index: VaultIndex,\n options: ResolvedOptions,\n): ParsedLine {\n // [[wikilink|text]] / [[wikilink]]\n const wl = WIKILINK_RE.exec(body)\n if (wl) {\n const target = wl[1]!.trim()\n const customText = wl[2]?.trim()\n const resolved = resolveTarget(target, index, options, entry)\n return {\n indent,\n text: customText ?? defaultTextForTarget(target, resolved),\n link: resolved?.url ?? null,\n }\n }\n // [text](link)\n const ml = MD_LINK_RE.exec(body)\n if (ml) {\n return { indent, text: ml[1]!.trim(), link: ml[2]!.trim() }\n }\n // 纯文字 group title:支持 `Title -` 结尾控制 collapsed\n let text = body\n let collapsed: boolean | undefined\n if (text.endsWith(' +')) {\n collapsed = false\n text = text.slice(0, -2).trim()\n } else if (text.endsWith(' -')) {\n collapsed = true\n text = text.slice(0, -2).trim()\n }\n return { indent, text, link: null, collapsed }\n}\n\nfunction defaultTextForTarget(target: string, entry: FileEntry | undefined): string {\n if (entry) {\n const fm = entry.frontmatter as { sidebarTitle?: string; title?: string }\n if (typeof fm.sidebarTitle === 'string' && fm.sidebarTitle.trim()) {\n return fm.sidebarTitle.trim()\n }\n if (typeof fm.title === 'string' && fm.title.trim()) {\n return fm.title.trim()\n }\n return entry.basename\n }\n return target\n}\n\nfunction resolveTarget(\n raw: string,\n index: VaultIndex,\n options: ResolvedOptions,\n contextEntry: FileEntry,\n): FileEntry | undefined {\n const target = stripMarkdownExt(toPosix(raw))\n if (!target) return undefined\n // 路径(相对当前 _sidebar.md 所在目录,或绝对)\n if (target.includes('/')) {\n // 相对路径试一次\n const ctxDir = contextEntry.relativePath.split('/').slice(0, -1).join('/')\n const candidates = [\n target,\n target + '.md',\n ctxDir ? `${ctxDir}/${target}` : '',\n ctxDir ? `${ctxDir}/${target}.md` : '',\n ].filter(Boolean)\n for (const c of candidates) {\n const found = index.byRelativePath.get(c)\n if (found) return found\n }\n }\n // alias\n const aliasKey = options.caseSensitive ? target : target.toLowerCase()\n const aliased = index.byAlias.get(aliasKey)\n if (aliased) return aliased\n // basename\n const map = options.caseSensitive ? index.byBasename : index.byBasenameLower\n const key = options.caseSensitive ? target : target.toLowerCase()\n const arr = map.get(key)\n if (arr && arr.length > 0) return arr[0]\n return undefined\n}\n\n/** 把扁平的 ParsedLine[](带 indent)折成 SidebarItem 树 */\nfunction buildTree(lines: ParsedLine[]): SidebarItem[] {\n if (lines.length === 0) return []\n // 把所有 indent 归一化到 level(0、1、2 ...)\n const indents = [...new Set(lines.map((l) => l.indent))].sort((a, b) => a - b)\n const indentToLevel = new Map<number, number>()\n indents.forEach((i, idx) => indentToLevel.set(i, idx))\n\n const root: SidebarItem[] = []\n // 栈:[{ level, items }]\n const stack: Array<{ level: number; items: SidebarItem[] }> = [\n { level: -1, items: root },\n ]\n for (const l of lines) {\n const level = indentToLevel.get(l.indent) ?? 0\n while (stack.length > 0 && stack[stack.length - 1]!.level >= level) {\n stack.pop()\n }\n const parent = stack[stack.length - 1]!\n const item: SidebarItem = {}\n if (l.text) item.text = l.text\n if (l.link) item.link = l.link\n if (l.collapsed !== undefined) item.collapsed = l.collapsed\n parent.items.push(item)\n // 这个 item 可能成为后续行的 parent → 给它一个 items 数组\n item.items = []\n stack.push({ level, items: item.items })\n }\n // 清掉空的 items 数组(纯叶子)\n pruneEmptyItems(root)\n // 顶层根据\"items 非空但 collapsed 未设\"补默认 collapsed:true\n return root\n}\n\nfunction pruneEmptyItems(arr: SidebarItem[]): void {\n for (const it of arr) {\n if (it.items) {\n if (it.items.length === 0) delete it.items\n else pruneEmptyItems(it.items)\n }\n }\n}\n","/**\n * v0.3 — 从 VaultIndex 自动生成 VitePress sidebar。\n *\n * 支持:\n * - 任意嵌套深度(子目录递归变成 collapsible 子 group)\n * - 三种 mode:\n * 'tree' (默认)单一全局 array,顶层每个目录嵌套子项\n * 'flat' 顶层目录扁平化(老 v0.3 行为,保留兼容)\n * 'per-folder' Record<string, items[]>,VitePress 按 URL 前缀切换 sidebar\n * - frontmatter 控制:\n * sidebarTitle 覆盖标题\n * sidebarHidden 整篇隐藏(等价 sidebar: false)\n * order 排序权重(数字小在前)\n * sidebarCollapsed 作用在目录的 index.md 上,控制该 group 默认展开/折叠\n * sidebarGroup 把文件挂到\"虚拟 group\"(跨目录归类,常用于 docs / tour 等)\n * - 隐藏:\n * _-前缀目录(_drafts / _perspectives_ 等自动跳)\n * options.views.urlPrefix 目录(插件视图)\n * index.md / README.md 不作为 sibling 文件出现(已用作 group 入口)\n */\n\nimport type { FileEntry, VaultIndex, ResolvedOptions } from '../types.js'\nimport type {\n SidebarItem,\n ResolvedSidebarAutoOptions,\n SidebarAutoOptions,\n NavItem,\n} from './types.js'\nimport {\n isSidebarOverrideFile,\n parseSidebarOverride,\n} from './parse-sidebar-md.js'\n\nexport type { NavItem }\n\n// ── option resolver ──────────────────────────────────────────────\n\nexport function resolveSidebarAutoOptions(\n user: SidebarAutoOptions = {},\n): ResolvedSidebarAutoOptions {\n const strip = user.stripNumericPrefix ?? true\n return {\n mode: user.mode ?? 'fill-if-empty',\n exclude: user.exclude ?? [],\n collapsed: user.collapsed ?? true,\n sortBy: user.sortBy ?? 'order-then-title',\n // **闭包**绑定 stripNumericPrefix,让 user 设 false 时 default formatter 也尊重\n formatGroupTitle:\n user.formatGroupTitle ?? ((d: string) => humanize(d, strip)),\n formatItemTitle:\n user.formatItemTitle ?? ((e: FileEntry) => defaultItemTitle(e, strip)),\n hiddenKey: user.hiddenKey ?? 'sidebarHidden',\n titleKey: user.titleKey ?? 'sidebarTitle',\n orderKey: user.orderKey ?? 'order',\n autoNav: user.autoNav ?? false,\n homeNavText: user.homeNavText ?? 'Home',\n stripNumericPrefix: strip,\n groupOrder: user.groupOrder ?? [],\n maxDepth: user.maxDepth,\n groupLink: user.groupLink ?? 'all',\n includePrefix: user.includePrefix,\n excludePrefixes: user.excludePrefixes ?? [],\n foldersFirst: user.foldersFirst ?? false,\n }\n}\n\n/** item 标题计算(接收 stripNumericPrefix,在 resolveSidebarAutoOptions 阶段绑定) */\nfunction defaultItemTitle(entry: FileEntry, strip: boolean): string {\n const fm = entry.frontmatter\n const sidebarTitle = typeof fm.sidebarTitle === 'string' ? fm.sidebarTitle : ''\n if (sidebarTitle.trim()) return sidebarTitle.trim()\n const title = typeof fm.title === 'string' ? fm.title : ''\n if (title.trim()) return title.trim()\n const firstH1 = entry.headings.find((h) => h.level === 1)\n if (firstH1) return firstH1.text\n return humanize(entry.basename, strip)\n}\n\n/** 共用 humanize:剥可选前缀数字 → 替换 -/_ → Title Case */\nfunction humanize(name: string, strip: boolean): string {\n let s = name\n if (strip) s = s.replace(/^\\d+[-_.\\s]+/, '')\n return s\n .replace(/[-_]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/\\b\\w/g, (m) => m.toUpperCase())\n}\n\n// ── tree 数据结构 ───────────────────────────────────────────────\n\ninterface DirNode {\n /** 'folder1/sub' 形式;根节点为 '' */\n path: string\n /** 这层目录下的\"普通\"文件(不含 index/README/_sidebar) */\n files: FileEntry[]\n /** 子目录(map key = 段名,如 'sub') */\n children: Map<string, DirNode>\n /** 这层目录的 dirIndex 文件(同名 > index > README,大小写不敏感) */\n dirIndex?: FileEntry\n /** dirIndex 文件**正文为空**(只有 frontmatter)→ 不当 link,仅取 frontmatter */\n dirIndexEmpty?: boolean\n /** 这层目录的 _sidebar.md (手动 override 文件) */\n sidebarOverride?: FileEntry\n}\n\nfunction newNode(path: string): DirNode {\n return { path, files: [], children: new Map() }\n}\n\n// ── 主入口 ──────────────────────────────────────────────────────\n\nexport function generateSidebar(\n index: VaultIndex,\n options: ResolvedOptions,\n autoOptions: SidebarAutoOptions = {},\n): SidebarItem[] | Record<string, SidebarItem[]> {\n const opts = resolveSidebarAutoOptions(autoOptions)\n const viewsPrefix = options.views.urlPrefix\n ? options.views.urlPrefix.replace(/^\\/+|\\/+$/g, '')\n : ''\n\n // 1. 过滤可见文件\n const visible: FileEntry[] = []\n for (const entry of index.files.values()) {\n if (shouldExclude(entry, opts, viewsPrefix)) continue\n visible.push(entry)\n }\n\n // 2. 建 tree\n const root = buildTree(visible)\n\n // 3. 根据 mode 输出\n const layout = autoOptions.layout ?? 'tree'\n let result: SidebarItem[] | Record<string, SidebarItem[]>\n if (layout === 'per-folder') {\n result = toPerFolderSidebar(root, opts, options, index)\n } else if (layout === 'flat') {\n result = toFlatSidebar(root, opts)\n } else {\n result = toTreeSidebar(root, opts, index, options)\n }\n // 4. **关键**:strip 掉 link 里的 base prefix。\n // VitePress sidebar/nav 配置约定:link 不带 base,VitePress 渲染时自己 prepend。\n // 我们 entry.url 已经含 base(为了让 wikilink <a href> 直接可用),\n // sidebar 出口必须 strip,否则 build 后 (base !== '/') 会双重 prefix → 404。\n stripBaseFromConfig(result, options.base)\n return result\n}\n\n/** strip base prefix from all link fields, recursively */\nfunction stripBaseFromConfig(\n cfg: SidebarItem[] | Record<string, SidebarItem[]>,\n base: string,\n): void {\n if (Array.isArray(cfg)) {\n stripBaseFromItems(cfg, base)\n } else {\n for (const k of Object.keys(cfg)) {\n stripBaseFromItems(cfg[k]!, base)\n }\n }\n}\nfunction stripBaseFromItems(items: SidebarItem[], base: string): void {\n const b = base.endsWith('/') ? base : base + '/'\n for (const it of items) {\n if (it.link && b !== '/' && it.link.startsWith(b)) {\n it.link = '/' + it.link.slice(b.length)\n }\n if (it.items) stripBaseFromItems(it.items, base)\n }\n}\n\n// ── 建 tree ─────────────────────────────────────────────────────\n\nfunction buildTree(files: FileEntry[]): DirNode {\n const root = newNode('')\n for (const f of files) {\n const segs = f.relativePath.split('/')\n const dirSegs = segs.slice(0, -1)\n let node = root\n for (const seg of dirSegs) {\n let child = node.children.get(seg)\n if (!child) {\n child = newNode(node.path ? node.path + '/' + seg : seg)\n node.children.set(seg, child)\n }\n node = child\n }\n // _sidebar.md 单拎出来当 override(不出现在 sidebar item)\n if (isSidebarOverrideFile(f)) {\n node.sidebarOverride = f\n continue\n }\n // 先全部塞进 files,稍后 pickDirIndexes 挑出最优先级的当 dirIndex\n node.files.push(f)\n }\n pickDirIndexes(root)\n return root\n}\n\n/**\n * 在 tree 建好后,为每个非根 DirNode 选出\"文件夹索引页\"。\n *\n * 优先级(大小写不敏感):\n * 1. 与文件夹同名的 .md —— 例 `tour/tour.md` 给 tour/\n * 2. index.md\n * 3. README.md\n *\n * 选中的从 files 移到 node.dirIndex,作为 group 的 link 来源。\n * 用户文件不会被覆盖(这里只是\"找出来当 link\",不写文件)。\n *\n * 额外:若该 dirIndex 文件**只有 frontmatter、无正文内容**,记 dirIndexEmpty,\n * 渲染时不当 link(但 frontmatter 的 sidebarTitle / sidebarCollapsed 仍读)。\n */\nfunction pickDirIndexes(node: DirNode): void {\n const folderName = node.path.split('/').pop() ?? ''\n if (folderName) {\n const folderLc = folderName.toLowerCase()\n let best: { entry: FileEntry; priority: number } | null = null\n for (const f of node.files) {\n const bnLc = f.basename.toLowerCase()\n let p = 0\n if (bnLc === folderLc) p = 1\n else if (bnLc === 'index') p = 2\n else if (bnLc === 'readme') p = 3\n if (p > 0 && (best === null || p < best.priority)) {\n best = { entry: f, priority: p }\n }\n }\n if (best) {\n node.dirIndex = best.entry\n node.dirIndexEmpty = best.entry.content.trim() === ''\n node.files = node.files.filter((f) => f !== best!.entry)\n }\n }\n for (const child of node.children.values()) pickDirIndexes(child)\n}\n\n// ── tree 模式:嵌套 group ───────────────────────────────────────\n\nfunction toTreeSidebar(\n root: DirNode,\n opts: ResolvedSidebarAutoOptions,\n index: VaultIndex,\n options: ResolvedOptions,\n): SidebarItem[] {\n return renderNode(root, opts, /* depth */ 0, /* isRoot */ true, index, options)\n}\n\n/**\n * 渲染一个 DirNode 的内容(files + 子 groups)。\n * isRoot=true 时返回顶层 array;否则用于子 group 的 items。\n *\n * \"虚拟 group\" sidebarGroup:文件 frontmatter 里 sidebarGroup: 'X' 的会被\n * 抽出来挂到一个名为 X 的虚拟 group 下,跨目录归类。\n */\nfunction renderNode(\n node: DirNode,\n opts: ResolvedSidebarAutoOptions,\n depth: number,\n isRoot: boolean,\n index: VaultIndex,\n options: ResolvedOptions,\n): SidebarItem[] {\n // 嵌套深度限制\n if (opts.maxDepth !== undefined && depth > opts.maxDepth) return []\n\n // _sidebar.md 手动 override:解析成功就直接用,跳过自动生成\n if (node.sidebarOverride) {\n const override = parseSidebarOverride(node.sidebarOverride, index, options)\n if (override) return override\n }\n\n // 抽出 sidebarGroup 标记的文件(虚拟 group)\n const virtualGroups = new Map<string, FileEntry[]>()\n const normalFiles: FileEntry[] = []\n for (const f of node.files) {\n const g = readVirtualGroup(f)\n if (g) {\n const arr = virtualGroups.get(g) ?? []\n arr.push(f)\n virtualGroups.set(g, arr)\n } else {\n normalFiles.push(f)\n }\n }\n\n // 三段 collect:files / virtualGroups / childDirs\n\n // 1. 普通文件\n normalFiles.sort((a, b) => compareEntries(a, b, opts))\n const fileItems: SidebarItem[] = normalFiles.map((f) => ({\n text: opts.formatItemTitle(f),\n link: f.url,\n }))\n\n // 2. 虚拟 groups(按名字字母序)\n const virtualKeys = [...virtualGroups.keys()].sort()\n const virtualItems: SidebarItem[] = []\n for (const name of virtualKeys) {\n const items = virtualGroups.get(name)!.sort((a, b) => compareEntries(a, b, opts))\n virtualItems.push({\n text: name,\n collapsed: opts.collapsed,\n items: items.map((f) => ({ text: opts.formatItemTitle(f), link: f.url })),\n })\n }\n\n // 3. 子目录:按 groupOrder(仅顶级生效)然后字母序\n const folderItems: SidebarItem[] = []\n const childKeys = sortChildKeys(node, opts, isRoot)\n for (const key of childKeys) {\n const child = node.children.get(key)!\n const childItems = renderNode(child, opts, depth + 1, false, index, options)\n if (childItems.length === 0 && !child.dirIndex) continue\n\n const group: SidebarItem = {\n text: computeGroupText(child.path, child.dirIndex, opts),\n collapsed: resolveGroupCollapsed(child.dirIndex, opts),\n items: childItems,\n }\n if (\n child.dirIndex &&\n !child.dirIndexEmpty &&\n shouldLinkGroup(opts, isRoot)\n ) {\n group.link = child.dirIndex.url\n }\n folderItems.push(group)\n }\n\n // 按 foldersFirst 决定三段拼接顺序。\n // virtualGroups 始终跟着 folders(它们语义上也是\"分组\"),只是 files 和\n // folders 的相对位置可配。\n if (opts.foldersFirst) {\n return [...folderItems, ...virtualItems, ...fileItems]\n }\n return [...fileItems, ...virtualItems, ...folderItems]\n}\n\n/**\n * 递归找 DirNode 子树的\"第一个可访问 page\"的 url,作为 fallback link。\n * 顺序:本节点 dirIndex(若非空) → 本节点 files 排序后第一个 → 各子目录递归。\n */\nfunction findFirstPageUrl(\n node: DirNode,\n opts: ResolvedSidebarAutoOptions,\n): string | null {\n if (node.dirIndex && !node.dirIndexEmpty) return node.dirIndex.url\n if (node.files.length > 0) {\n const sorted = [...node.files].sort((a, b) => compareEntries(a, b, opts))\n return sorted[0]!.url\n }\n const childKeys = [...node.children.keys()].sort()\n for (const k of childKeys) {\n const u = findFirstPageUrl(node.children.get(k)!, opts)\n if (u) return u\n }\n return null\n}\n\n/** 根据 groupLink 决定本层 group 是否可点(顶级 isRoot=true) */\nfunction shouldLinkGroup(opts: ResolvedSidebarAutoOptions, isTopLevel: boolean): boolean {\n if (opts.groupLink === 'off') return false\n if (opts.groupLink === 'top-level') return isTopLevel\n return true // 'all'\n}\n\n/** 子目录排序:顶级用 groupOrder + 字母序 fallback,非顶级直接字母序 */\nfunction sortChildKeys(\n node: DirNode,\n opts: ResolvedSidebarAutoOptions,\n isTopLevel: boolean,\n): string[] {\n const keys = [...node.children.keys()]\n if (!isTopLevel || opts.groupOrder.length === 0) {\n return keys.sort()\n }\n // 顶级:把 groupOrder 命中的项按指定顺序;其余按字母在后\n const orderMap = new Map<string, number>()\n opts.groupOrder.forEach((name, i) => {\n // groupOrder 名字应该是 group title 或 dirname,匹配 dirname 段\n orderMap.set(name, i)\n orderMap.set(name.toLowerCase(), i)\n })\n const indexed: string[] = []\n const rest: string[] = []\n for (const k of keys) {\n const title = computeGroupText(\n node.children.get(k)!.path,\n node.children.get(k)!.dirIndex,\n opts,\n )\n if (orderMap.has(k) || orderMap.has(title)) {\n indexed.push(k)\n } else {\n rest.push(k)\n }\n }\n indexed.sort((a, b) => {\n const ta = computeGroupText(\n node.children.get(a)!.path,\n node.children.get(a)!.dirIndex,\n opts,\n )\n const tb = computeGroupText(\n node.children.get(b)!.path,\n node.children.get(b)!.dirIndex,\n opts,\n )\n const oa = orderMap.has(a) ? orderMap.get(a)! : orderMap.get(ta)!\n const ob = orderMap.has(b) ? orderMap.get(b)! : orderMap.get(tb)!\n return oa - ob\n })\n rest.sort()\n return [...indexed, ...rest]\n}\n\n// ── flat 模式(老版兼容):所有目录摊到顶层 ───────────────────\n\nfunction toFlatSidebar(root: DirNode, opts: ResolvedSidebarAutoOptions): SidebarItem[] {\n // 遍历整 tree,把每个非根节点都做成顶层 group(items 只含直系文件)\n const out: SidebarItem[] = []\n // 先根\n const rootFiles = [...root.files].sort((a, b) => compareEntries(a, b, opts))\n for (const f of rootFiles) out.push({ text: opts.formatItemTitle(f), link: f.url })\n\n const allDirs: DirNode[] = []\n walkDirs(root, allDirs)\n for (const d of allDirs) {\n const files = [...d.files].sort((a, b) => compareEntries(a, b, opts))\n const items = files.map((f) => ({ text: opts.formatItemTitle(f), link: f.url }))\n if (items.length === 0 && !d.dirIndex) continue\n const group: SidebarItem = {\n text: computeGroupText(d.path, d.dirIndex, opts),\n collapsed: resolveGroupCollapsed(d.dirIndex, opts),\n items,\n }\n // flat 模式所有 group 都在\"顶层\" — 用 isTopLevel=true\n if (d.dirIndex && !d.dirIndexEmpty && shouldLinkGroup(opts, true)) {\n group.link = d.dirIndex.url\n }\n out.push(group)\n }\n return out\n}\n\nfunction walkDirs(node: DirNode, out: DirNode[]): void {\n const keys = [...node.children.keys()].sort()\n for (const k of keys) {\n const child = node.children.get(k)!\n out.push(child)\n walkDirs(child, out)\n }\n}\n\n// ── per-folder 模式:每个顶层目录一个独立 sidebar ────────────────\n\nfunction toPerFolderSidebar(\n root: DirNode,\n opts: ResolvedSidebarAutoOptions,\n options: ResolvedOptions,\n index: VaultIndex,\n): Record<string, SidebarItem[]> {\n // ⚠ Record 的 **key**(VitePress 用来匹配 URL 前缀)和**每个 item 的 link**\n // 都用**不带 base 的形式**。VitePress 内部用 currentPath(已 strip base)\n // 做匹配,且会自动给 link prepend base。带 base 会双重 prefix。\n\n const out: Record<string, SidebarItem[]> = {}\n\n const rootItems: SidebarItem[] = []\n const sortedRootFiles = [...root.files].sort((a, b) => compareEntries(a, b, opts))\n for (const f of sortedRootFiles) {\n rootItems.push({ text: opts.formatItemTitle(f), link: f.url })\n }\n const topKeys = [...root.children.keys()].sort()\n for (const key of topKeys) {\n const child = root.children.get(key)!\n if (child.files.length === 0 && child.children.size === 0 && !child.dirIndex) {\n continue\n }\n const labelText = computeGroupText(child.path, child.dirIndex, opts)\n if (shouldLinkGroup(opts, /* isTopLevel */ true)) {\n const firstUrl =\n child.dirIndex && !child.dirIndexEmpty\n ? child.dirIndex.url\n : findFirstPageUrl(child, opts)\n // ⚠ 没有真实页面就**不加 link**(避免点击 → 假 URL → 404 → router 报模块加载失败)\n if (firstUrl) {\n rootItems.push({ text: labelText, link: firstUrl })\n } else {\n rootItems.push({ text: labelText })\n }\n } else {\n rootItems.push({ text: labelText })\n }\n }\n if (rootItems.length > 0) out['/'] = rootItems // 根 key 用 '/'\n\n for (const key of topKeys) {\n const child = root.children.get(key)!\n const items = renderNode(child, opts, /* depth */ 1, /* isRoot */ false, index, options)\n if (items.length === 0 && !child.dirIndex) continue\n\n const sidebar: SidebarItem[] = []\n const canLink =\n child.dirIndex &&\n !child.dirIndexEmpty &&\n shouldLinkGroup(opts, /* isTopLevel */ true)\n if (canLink) {\n sidebar.push({\n text: computeGroupText(child.path, child.dirIndex, opts),\n link: child.dirIndex!.url,\n })\n }\n sidebar.push(...items)\n\n out[`/${key}/`] = sidebar // key 不带 base\n }\n return out\n}\n\n// ── generateNav:从 vault 顶层目录生成 nav tabs ─────────────────\n\nexport function generateNav(\n index: VaultIndex,\n options: ResolvedOptions,\n autoOptions: SidebarAutoOptions = {},\n): NavItem[] {\n const opts = resolveSidebarAutoOptions(autoOptions)\n const viewsPrefix = options.views.urlPrefix\n ? options.views.urlPrefix.replace(/^\\/+|\\/+$/g, '')\n : ''\n\n const visible: FileEntry[] = []\n for (const entry of index.files.values()) {\n if (shouldExclude(entry, opts, viewsPrefix)) continue\n visible.push(entry)\n }\n const root = buildTree(visible)\n\n const base = options.base.endsWith('/') ? options.base : options.base + '/'\n // nav link 不带 base(VitePress 渲染时自动 prepend);activeMatch 是正则,**也不带** base\n const out: NavItem[] = [{ text: opts.homeNavText, link: '/' }]\n\n const topKeys = [...root.children.keys()].sort()\n for (const key of topKeys) {\n const child = root.children.get(key)!\n if (child.files.length === 0 && child.children.size === 0 && !child.dirIndex) {\n continue\n }\n const text = computeGroupText(child.path, child.dirIndex, opts)\n // 链接选取(dirIndex.url 在 v0.3+ 已经不带 base,直接用即可):\n // 1. 非空 dirIndex → dirIndex.url\n // 2. 否则递归找第一个有效 page\n // 3. 都没有 → **跳过这个 tab**(nav tab 必须可点,否则点不动反而困惑;\n // 不像 sidebar 里没 link 还能展开/折叠)\n let link: string\n if (child.dirIndex && !child.dirIndexEmpty) {\n link = stripBase(child.dirIndex.url, base)\n } else {\n const first = findFirstPageUrl(child, opts)\n if (!first) continue // skip whole tab\n link = first\n }\n const escapedPrefix = `/${key}/`.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n out.push({ text, link, activeMatch: '^' + escapedPrefix })\n }\n return out\n}\n\nfunction stripBase(url: string, base: string): string {\n const b = base.endsWith('/') ? base : base + '/'\n if (b === '/' || !url.startsWith(b)) return url\n return '/' + url.slice(b.length)\n}\n\n// ── helpers ───────────────────────────────────────────────────────\n\nfunction compareEntries(\n a: FileEntry,\n b: FileEntry,\n opts: ResolvedSidebarAutoOptions,\n): number {\n if (opts.sortBy === 'title') {\n return opts.formatItemTitle(a).localeCompare(opts.formatItemTitle(b))\n }\n if (opts.sortBy === 'mtime-desc') {\n return b.mtime - a.mtime\n }\n const oa = readOrder(a, opts.orderKey)\n const ob = readOrder(b, opts.orderKey)\n if (oa !== ob) return oa - ob\n return opts.formatItemTitle(a).localeCompare(opts.formatItemTitle(b))\n}\n\nfunction readOrder(entry: FileEntry, key: string): number {\n const v = entry.frontmatter[key]\n if (typeof v === 'number' && Number.isFinite(v)) return v\n return Number.POSITIVE_INFINITY\n}\n\nfunction readVirtualGroup(entry: FileEntry): string | null {\n const v = entry.frontmatter.sidebarGroup\n if (typeof v === 'string' && v.trim()) return v.trim()\n return null\n}\n\nfunction resolveGroupCollapsed(\n dirIndex: FileEntry | undefined,\n opts: ResolvedSidebarAutoOptions,\n): boolean {\n if (dirIndex) {\n const v = dirIndex.frontmatter.sidebarCollapsed\n if (typeof v === 'boolean') return v\n }\n return opts.collapsed\n}\n\nfunction shouldExclude(\n entry: FileEntry,\n opts: ResolvedSidebarAutoOptions,\n viewsPrefix: string,\n): boolean {\n if (entry.frontmatter[opts.hiddenKey] === true) return true\n if (viewsPrefix && entry.relativePath.startsWith(viewsPrefix + '/')) return true\n\n // i18n:includePrefix(只看子树) / excludePrefixes(屏蔽 locale 子树)\n if (opts.includePrefix) {\n const ip = opts.includePrefix.replace(/^\\/+|\\/+$/g, '')\n if (!entry.relativePath.startsWith(ip + '/') && entry.relativePath !== ip) {\n return true\n }\n }\n for (const ex of opts.excludePrefixes) {\n const xp = ex.replace(/^\\/+|\\/+$/g, '')\n if (entry.relativePath.startsWith(xp + '/') || entry.relativePath === xp) {\n return true\n }\n }\n\n // _ 前缀目录\n const segs = entry.relativePath.split('/')\n for (const seg of segs.slice(0, -1)) {\n if (seg.startsWith('_')) return true\n }\n for (const pat of opts.exclude) {\n if (matchSimpleGlob(entry.relativePath, pat)) return true\n }\n return false\n}\n\nfunction matchSimpleGlob(path: string, pat: string): boolean {\n const ESCAPE_RE = /[.+?^${}()|[\\]\\\\]/g\n const escaped = pat.replace(ESCAPE_RE, '\\\\$&')\n const expanded = escaped\n .replace(/\\*\\*/g, '__DOUBLESTAR__')\n .replace(/\\*/g, '[^/]*')\n .replace(/__DOUBLESTAR__/g, '.*')\n return new RegExp('^' + expanded + '$').test(path)\n}\n\n// isDirIndex 之前的判断被 pickDirIndexes 取代(支持同名优先)\n\nfunction computeGroupText(\n dir: string,\n dirIndex: FileEntry | undefined,\n opts: ResolvedSidebarAutoOptions,\n): string {\n if (dirIndex) {\n const fmTitle = dirIndex.frontmatter[opts.titleKey]\n if (typeof fmTitle === 'string' && fmTitle.trim()) return fmTitle.trim()\n const title = dirIndex.frontmatter.title\n if (typeof title === 'string' && title.trim()) return title.trim()\n const h1 = dirIndex.headings.find((h) => h.level === 1)\n if (h1) return h1.text\n }\n const last = dir.split('/').pop() ?? dir\n return opts.formatGroupTitle(last)\n}\n","/**\n * v0.3 — 给缺 index.md / README.md 的文件夹自动生成 index 页。\n *\n * 行为:\n * - 扫 srcDir 下所有目录,对**已有 .md 文件**但**无 index.md/README.md**的\n * 目录,生成一个简单的 index.md\n * - 内容:H1 = 目录名 humanized;然后列出直接子文件 + 子目录链接(用 wikilink)\n * - 用 sentinel 标记,下次升级时允许覆盖\n * - 不生成:`_` 前缀目录、views.urlPrefix 目录、根目录(根用户自己写 index)\n *\n * 时机:在 vault scan 之前调用(views generate-md 同期),让 scanVault 看到这些\n * 生成的 index,sidebar 自动识别为 group link。\n */\n\nimport fs from 'node:fs'\nimport nodePath from 'node:path'\nimport type { ResolvedOptions } from '../types.js'\n\nexport const FOLDER_INDEX_SENTINEL =\n '<!-- generated by vitepress-allyouneed/folder-index (do not edit; will be regenerated) -->'\n\nexport interface FolderIndexReport {\n written: string[]\n skipped: { path: string; reason: string }[]\n}\n\nexport type FolderIndexMode = 'off' | 'top-level' | 'all'\n\nexport interface FolderIndexOptions {\n /**\n * 三种模式:\n * - 'off' 完全不生成\n * - 'top-level' 只为**顶级目录**生成(即作为 nav tab 入口的那批),\n * 侧边栏内的子目录保持原版\"点击展开\"(不跳转)行为\n * - 'all' 所有非空目录都生成\n *\n * 默认 'top-level' —— 既保证 nav tab 能正确跳转,又不在所有子目录里写文件。\n */\n mode?: FolderIndexMode\n /** 排除的 dir(相对 srcDir,glob)。默认 [] */\n exclude?: string[]\n /** 模板生成函数,可覆盖 */\n template?: (ctx: TemplateContext) => string\n /** humanize 时剥 `01-foo` 等数字前缀,默认 true */\n stripNumericPrefix?: boolean\n\n /** @deprecated 老 v0.3 字段,等价 mode: enabled?'top-level':'off' */\n enabled?: boolean\n}\n\nexport interface TemplateContext {\n dirAbsPath: string\n dirRelPath: string\n /** 目录名(已 humanize) */\n title: string\n /** 直接子 .md 文件(相对该目录) */\n files: Array<{ name: string; relPath: string; title: string }>\n /** 直接子目录(已有内容的) */\n subDirs: Array<{ name: string; title: string }>\n}\n\nconst MD_RE = /\\.(md|markdown)$/i\nconst INDEX_RE = /^(index|README)\\.(md|markdown)$/i\n\nexport function generateFolderIndexes(\n options: ResolvedOptions,\n folderOpts: FolderIndexOptions = {},\n): FolderIndexReport {\n const report: FolderIndexReport = { written: [], skipped: [] }\n\n // 兼容 enabled / 推断 mode\n const mode: FolderIndexMode =\n folderOpts.mode ??\n (folderOpts.enabled === true\n ? 'top-level'\n : folderOpts.enabled === false\n ? 'off'\n : 'top-level')\n if (mode === 'off') return report\n\n const srcDir = nodePath.resolve(options.srcDir)\n const viewsPrefix = options.views.urlPrefix\n ? options.views.urlPrefix.replace(/^\\/+|\\/+$/g, '')\n : ''\n const strip = folderOpts.stripNumericPrefix ?? true\n const exclude = folderOpts.exclude ?? []\n const template = folderOpts.template ?? defaultTemplate\n\n // 收集要处理的目录;0.3.2:把 srcDir 根**也加进去**,\n // 避免用户没写 index.md 时 / 直接 404\n const dirsToProcess = [srcDir, ...collectDirs(srcDir, srcDir, viewsPrefix, exclude, mode)]\n\n for (const dirAbs of dirsToProcess) {\n const dirRel = nodePath.relative(srcDir, dirAbs).split(nodePath.sep).join('/')\n // 0.3.2:**根目录也生成**(模板会用 srcDir name 当标题)\n\n const entries = safeReaddir(dirAbs)\n if (entries.length === 0) continue\n\n // 检测候选 dirIndex 文件:\n // 1. 与文件夹同名的 .md(优先级最高,优先于 index/README)\n // 2. index.md\n // 3. README.md\n // 任一存在且**不是我们之前生成的**(没 sentinel)→ 跳过,把现成的当索引页\n const dirName = nodePath.basename(dirAbs).toLowerCase()\n const target = nodePath.join(dirAbs, 'index.md')\n\n let userHasOwnIndex = false\n let userIndexName = ''\n for (const e of entries) {\n if (!e.isFile()) continue\n const lower = e.name.toLowerCase()\n const isCandidate =\n lower === `${dirName}.md` ||\n lower === `${dirName}.markdown` ||\n INDEX_RE.test(e.name)\n if (!isCandidate) continue\n const content = safeRead(nodePath.join(dirAbs, e.name))\n if (content === null) continue\n // 用户文件(包括空 frontmatter-only 文件)都不覆盖。\n // 只有带 sentinel 的我们自己生成的旧文件才允许覆盖更新。\n if (!content.includes(FOLDER_INDEX_SENTINEL)) {\n userHasOwnIndex = true\n userIndexName = e.name\n break\n }\n }\n if (userHasOwnIndex) {\n // 用户自己加了 dirIndex(同名或 index/README)。若我们之前曾生成过\n // index.md / README.md(带 sentinel),清理掉,避免 sidebar 同时出现\n // \"用户文件\" + \"我们的旧生成\"两条 stale item。\n for (const candName of ['index.md', 'README.md']) {\n if (candName.toLowerCase() === userIndexName.toLowerCase()) continue\n const candPath = nodePath.join(dirAbs, candName)\n const candContent = safeRead(candPath)\n if (candContent && candContent.includes(FOLDER_INDEX_SENTINEL)) {\n try {\n fs.unlinkSync(candPath)\n report.skipped.push({\n path: candPath,\n reason: `被用户的 ${userIndexName} 取代,自动清理`,\n })\n } catch {\n /* 删失败就保留,不影响主流程 */\n }\n }\n }\n report.skipped.push({\n path: target,\n reason: `用户已有 ${userIndexName},不生成`,\n })\n continue\n }\n\n // 收集子文件 + 子目录\n const files: TemplateContext['files'] = []\n const subDirs: TemplateContext['subDirs'] = []\n for (const e of entries) {\n if (e.isFile() && MD_RE.test(e.name) && !INDEX_RE.test(e.name)) {\n const name = e.name.replace(MD_RE, '')\n files.push({\n name,\n relPath: name,\n title: humanize(name, strip),\n })\n } else if (e.isDirectory() && !e.name.startsWith('_')) {\n // 排除空子目录\n if (hasMdContent(nodePath.join(dirAbs, e.name))) {\n subDirs.push({ name: e.name, title: humanize(e.name, strip) })\n }\n }\n }\n\n // 空目录(子文件 + 子目录都为 0)→ 不生成\n if (files.length === 0 && subDirs.length === 0) {\n continue\n }\n\n files.sort((a, b) => a.title.localeCompare(b.title))\n subDirs.sort((a, b) => a.title.localeCompare(b.title))\n\n // 根目录(dirRel === '')用 srcDir basename 当 title;否则用最后一段\n const lastSeg =\n dirRel === ''\n ? nodePath.basename(srcDir)\n : dirRel.split('/').pop() ?? ''\n const ctx: TemplateContext = {\n dirAbsPath: dirAbs,\n dirRelPath: dirRel,\n title: humanize(lastSeg, strip) || 'Home',\n files,\n subDirs,\n }\n\n try {\n fs.writeFileSync(target, template(ctx), 'utf8')\n report.written.push(target)\n } catch (err) {\n report.skipped.push({\n path: target,\n reason: `写入失败: ${err instanceof Error ? err.message : String(err)}`,\n })\n }\n }\n\n return report\n}\n\nfunction collectDirs(\n root: string,\n cur: string,\n viewsPrefix: string,\n exclude: string[],\n mode: FolderIndexMode,\n): string[] {\n const out: string[] = []\n walk(cur, 0)\n return out\n\n function walk(dir: string, depth: number): void {\n // top-level 模式只收 depth 0 的直接子目录\n if (mode === 'top-level' && depth > 1) return\n\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true })\n } catch {\n return\n }\n for (const e of entries) {\n if (!e.isDirectory()) continue\n if (e.name.startsWith('.')) continue\n if (e.name.startsWith('_')) continue\n if (e.name === 'node_modules' || e.name === 'public') continue\n const full = nodePath.join(dir, e.name)\n const rel = nodePath.relative(root, full).split(nodePath.sep).join('/')\n if (viewsPrefix && (rel === viewsPrefix || rel.startsWith(viewsPrefix + '/'))) continue\n if (exclude.some((pat) => matchGlob(rel, pat))) continue\n out.push(full)\n if (mode === 'all') walk(full, depth + 1)\n }\n }\n}\n\nfunction hasMdContent(dir: string): boolean {\n try {\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n for (const e of entries) {\n if (e.isFile() && MD_RE.test(e.name)) return true\n if (e.isDirectory() && !e.name.startsWith('_') && !e.name.startsWith('.')) {\n if (hasMdContent(nodePath.join(dir, e.name))) return true\n }\n }\n } catch {\n /* ignore */\n }\n return false\n}\n\nfunction safeReaddir(dir: string): fs.Dirent[] {\n try {\n return fs.readdirSync(dir, { withFileTypes: true })\n } catch {\n return []\n }\n}\n\nfunction safeRead(p: string): string | null {\n try {\n return fs.readFileSync(p, 'utf8')\n } catch {\n return null\n }\n}\n\nfunction matchGlob(path: string, pat: string): boolean {\n const ESC = /[.+?^${}()|[\\]\\\\]/g\n const re = pat\n .replace(ESC, '\\\\$&')\n .replace(/\\*\\*/g, '__DS__')\n .replace(/\\*/g, '[^/]*')\n .replace(/__DS__/g, '.*')\n return new RegExp('^' + re + '$').test(path)\n}\n\n/** 文件夹名 humanize:`my-dir` / `01-foo_bar` → `My Dir` / `Foo Bar`(开 strip 时) */\nexport function humanize(name: string, stripNumeric: boolean): string {\n let s = name\n if (stripNumeric) {\n s = s.replace(/^\\d+[-_.\\s]+/, '')\n }\n return s\n .replace(/[-_]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/\\b\\w/g, (m) => m.toUpperCase())\n}\n\nfunction defaultTemplate(ctx: TemplateContext): string {\n const lines: string[] = []\n lines.push('---')\n lines.push(`title: ${ctx.title}`)\n lines.push(`sidebarTitle: ${ctx.title}`)\n lines.push('---')\n lines.push(FOLDER_INDEX_SENTINEL)\n lines.push('')\n lines.push(`# ${ctx.title}`)\n lines.push('')\n if (ctx.subDirs.length > 0) {\n lines.push('## Sections')\n lines.push('')\n for (const d of ctx.subDirs) {\n lines.push(`- [[${ctx.dirRelPath}/${d.name}/|${d.title}]]`)\n }\n lines.push('')\n }\n if (ctx.files.length > 0) {\n lines.push('## Pages')\n lines.push('')\n for (const f of ctx.files) {\n lines.push(`- [[${ctx.dirRelPath}/${f.relPath}|${f.title}]]`)\n }\n lines.push('')\n }\n return lines.join('\\n')\n}\n","/**\n * v0.3 — 启动时预扫所有 .md,找出死 wikilink,集中 console.warn 一次。\n *\n * 不影响渲染管线(渲染时 wikilink rule 自己也有 dead-link 检测+报警)。\n * 这个函数只是给开发者一个\"启动总览\",避免要 dev-server 打开每页才看到死链。\n */\n\nimport type { ResolvedOptions, VaultIndex } from './types.js'\nimport { stripMarkdownExt, toPosix } from '../utils/path.js'\n\nconst WIKILINK_RE = /(!?)\\[\\[([^\\]\\n|#]+)(?:#[^\\]\\n|]*)?(?:\\|[^\\]\\n]*)?\\]\\]/g\n\nexport interface DeadLinkReport {\n /** 总扫描的 wikilink 数 */\n total: number\n /** 死链(target 解析不到的)*/\n dead: Array<{ source: string; target: string; raw: string }>\n}\n\n/**\n * 把 fenced code block / inline code 全部抹掉成空白(保留长度,不破坏行号),\n * 这样后续 wikilink regex 不会扫到代码示例里的 `[[note]]`(它们渲染时也不会\n * 被 markdown-it 当 wikilink,因此不该报死链)。\n */\nfunction stripCodeForScan(src: string): string {\n // ``` fenced ```\n let r = src.replace(/```[\\s\\S]*?```/g, (m) => ' '.repeat(m.length))\n // ~~~ fenced ~~~\n r = r.replace(/~~~[\\s\\S]*?~~~/g, (m) => ' '.repeat(m.length))\n // 行内 code(支持多个反引号,简化:同数量反引号配对)\n r = r.replace(/(`+)(?:(?!\\1)[\\s\\S])*?\\1/g, (m) => ' '.repeat(m.length))\n return r\n}\n\nexport function scanWikilinks(\n index: VaultIndex,\n options: ResolvedOptions,\n): DeadLinkReport {\n const dead: DeadLinkReport['dead'] = []\n let total = 0\n\n for (const f of index.files.values()) {\n const cleaned = stripCodeForScan(f.content)\n const matches = cleaned.matchAll(WIKILINK_RE)\n for (const m of matches) {\n total += 1\n const isEmbed = m[1] === '!'\n const rawTarget = m[2]!.trim()\n // image/audio/video/pdf/transclusion 走 embed 通道,不参与 wikilink 死链检测\n if (isEmbed) {\n const ext = extractExt(rawTarget)\n if (ext) {\n const isAsset =\n options.scan.assetExtensions.includes(ext.toLowerCase()) ||\n ['md', 'markdown'].includes(ext.toLowerCase())\n if (isAsset) continue\n }\n }\n const found = resolveSimple(rawTarget, index, options, f.relativePath)\n if (!found) {\n dead.push({\n source: f.relativePath,\n target: rawTarget,\n raw: `${isEmbed ? '!' : ''}[[${rawTarget}]]`,\n })\n }\n }\n }\n return { total, dead }\n}\n\n/** vitepress.ts wrapper 用:扫完打印汇总 */\nexport function logDeadLinks(report: DeadLinkReport, deadLink: 'silent' | 'warn' | 'error'): void {\n if (report.dead.length === 0) return\n if (deadLink === 'silent') return\n const head = `vitepress-allyouneed: 共扫描 ${report.total} 个 wikilink, ` +\n `发现 ${report.dead.length} 个死链:`\n if (deadLink === 'error') {\n console.error(head)\n } else {\n console.warn(head)\n }\n // 按 source 分组打印,便于人眼看\n const bySource = new Map<string, typeof report.dead>()\n for (const d of report.dead) {\n const arr = bySource.get(d.source) ?? []\n arr.push(d)\n bySource.set(d.source, arr)\n }\n for (const [src, items] of [...bySource.entries()].sort()) {\n console.warn(` ${src}`)\n for (const it of items) {\n console.warn(` ${it.raw}`)\n }\n }\n}\n\nfunction extractExt(target: string): string {\n const cleaned = target.split('#')[0]!\n const dot = cleaned.lastIndexOf('.')\n if (dot <= 0) return ''\n return cleaned.slice(dot + 1).toLowerCase()\n}\n\nfunction resolveSimple(\n raw: string,\n index: VaultIndex,\n options: ResolvedOptions,\n currentSourceRel?: string,\n): boolean {\n const target = stripMarkdownExt(toPosix(raw))\n if (!target) return false\n // 路径形式\n if (target.includes('/')) {\n if (\n index.byRelativePath.has(target) ||\n index.byRelativePath.has(target + '.md') ||\n index.byRelativePath.has(target + '.markdown')\n ) {\n return true\n }\n // Fallback:相对当前源文件目录\n if (currentSourceRel) {\n const curDir = currentSourceRel.split('/').slice(0, -1).join('/')\n if (curDir) {\n return (\n index.byRelativePath.has(`${curDir}/${target}`) ||\n index.byRelativePath.has(`${curDir}/${target}.md`) ||\n index.byRelativePath.has(`${curDir}/${target}.markdown`)\n )\n }\n }\n return false\n }\n // alias\n const aliasKey = options.caseSensitive ? target : target.toLowerCase()\n if (index.byAlias.has(aliasKey)) return true\n // basename\n const map = options.caseSensitive ? index.byBasename : index.byBasenameLower\n const key = options.caseSensitive ? target : target.toLowerCase()\n return (map.get(key)?.length ?? 0) > 0\n}\n","/**\n * VitePress 接入入口 —— defineConfigWithAllYouNeed 零配置 wrapper。\n *\n * 用法:\n *\n * ```ts\n * // .vitepress/config.ts\n * import { defineConfigWithAllYouNeed } from 'vitepress-allyouneed/vitepress'\n *\n * export default defineConfigWithAllYouNeed({\n * title: 'My Vault',\n * srcDir: '../my-vault',\n * cleanUrls: true,\n * // ⚠️ index.md 和 README.md 同目录会冲突(都路由到 '/')。建议二选一:\n * srcExclude: ['README.md'],\n * }, {\n * onConflict: 'shortest',\n * })\n * ```\n *\n * 这个 wrapper 做的事:\n * 1. 创建 Vite 插件实例并注入 vite.plugins\n * 2. 在 markdown.config 中注册我们的 inline/block 规则\n * 3. 注册一条 markdown-it core 规则,在 'normalize' 阶段把 vault index/options\n * 就地注入 state.env(详见 makeEnvInjector 内的注释 —— 这一步**必须就地修改**,\n * 不能新建 env 对象,否则会让 VitePress 读不到 @mdit-vue/plugin-frontmatter\n * 写回的 frontmatter,从而导致首页 404)\n * 4. 把 srcDir/base/cleanUrls/srcExclude 等从 VitePress 配置同步给插件\n */\n\nimport type { UserConfig } from 'vitepress'\nimport type MarkdownIt from 'markdown-it'\nimport type { AllYouNeedOptions, AllYouNeedEnv } from './core/types.js'\nimport { viteAllYouNeed } from './vite.js'\nimport allYouNeedMarkdownIt from './markdown-it.js'\nimport { resolveOptions } from './core/config-bridge.js'\nimport { registerTagsInline } from './modules/tags/index.js'\nimport { injectViewsSidebar, injectViewsNav } from './core/views/sidebar-inject.js'\nimport { generateSidebar, generateNav } from './core/sidebar-auto/index.js'\nimport { generateFolderIndexes } from './core/sidebar-auto/generate-folder-index.js'\nimport { scanVault } from './core/vault/index.js'\nimport { scanWikilinks, logDeadLinks } from './core/scan-wikilinks.js'\n\nexport function defineConfigWithAllYouNeed(\n config: UserConfig,\n pluginOptions: AllYouNeedOptions = {},\n): UserConfig {\n // VitePress 的 srcExclude 也合并进我们扫描器,两边对同一份文件集合\n const vpExclude = Array.isArray(config.srcExclude) ? config.srcExclude : []\n\n const mergedOptions: AllYouNeedOptions = {\n ...pluginOptions,\n srcDir: pluginOptions.srcDir ?? config.srcDir,\n base: pluginOptions.base ?? config.base,\n cleanUrls: pluginOptions.cleanUrls ?? config.cleanUrls,\n scan: {\n ...pluginOptions.scan,\n exclude: [\n ...(pluginOptions.scan?.exclude ?? []),\n ...vpExclude,\n ],\n },\n }\n\n // Vite 插件(扫描 vault、暴露 __getIndex/__getOptions、装 resolveId/load)\n const vitePlugin = viteAllYouNeed(mergedOptions)\n\n // 合并 vite 配置 —— 详见 src/vite.ts 注释,这里用 any 化处理 plugins,\n // 因为 vite 的 PluginOption 类型递归很深,精确类型会让 wrapper 越写越脆\n const existingVite = (\n typeof config.vite === 'object' && config.vite !== null\n ? config.vite\n : {}\n ) as Record<string, unknown>\n const existingPlugins: unknown[] = Array.isArray(existingVite.plugins)\n ? (existingVite.plugins as unknown[])\n : []\n const newVite = {\n ...existingVite,\n plugins: [...existingPlugins, vitePlugin] as never[],\n } as UserConfig['vite']\n\n // 合并 markdown 配置\n const existingMarkdown = config.markdown ?? {}\n const existingConfig = (existingMarkdown as { config?: unknown }).config\n\n // v0.2:wrapper 内解析一次选项,供 sidebar 注入和 tags 开关判断\n const resolvedForWrapper = resolveOptions(mergedOptions, {\n srcDir: mergedOptions.srcDir ?? config.srcDir,\n base: mergedOptions.base ?? config.base,\n cleanUrls: mergedOptions.cleanUrls ?? config.cleanUrls,\n })\n\n const newMarkdownConfig = (md: MarkdownIt) => {\n // 1. 装我们的 inline/block 规则\n allYouNeedMarkdownIt(md, mergedOptions)\n\n // 2. v0.2:正文 #tag 规则\n if (\n resolvedForWrapper.modules.views &&\n resolvedForWrapper.views.parseInlineTags\n ) {\n registerTagsInline(md)\n }\n\n // 3. 装一条 core 规则,在 'normalize' 之前把 vault index/options 注入 state.env\n md.core.ruler.before(\n 'normalize',\n 'allyouneed_env_inject',\n makeEnvInjector(vitePlugin),\n )\n\n // 4. 让用户原 markdown.config 继续生效\n if (typeof existingConfig === 'function') {\n existingConfig(md)\n }\n }\n\n // v0.2/v0.3:自动注入视图条目 + sidebar 自动生成\n const themeConfig = (config.themeConfig ?? {}) as Record<string, unknown>\n\n // v0.3:sidebar 自动生成\n // - mode='off' 不动\n // - mode='fill-if-empty' 仅当用户没提供 sidebar 时填(默认)\n // - mode='force' 覆盖\n // 依赖 viteplugin.__getIndex(),但 index 在 Vite buildStart 才填好,所以这里\n // 用懒解析:把 themeConfig.sidebar 设为一个 getter,首次访问时再扫\n const sidebarAuto = resolvedForWrapper.sidebarAuto\n const sidebarMode = sidebarAuto.mode ?? 'fill-if-empty'\n if (sidebarMode !== 'off') {\n const userProvided = themeConfig.sidebar !== undefined\n const shouldFill = sidebarMode === 'force' || !userProvided\n if (shouldFill) {\n // 同步路径:scanVault 已在 Vite buildStart 跑过(若 dev/build);\n // 但 defineConfigWithAllYouNeed 时 buildStart 还没到 —— 此时 index 为空。\n // 解决:这里立即跑一次 scanVault(成本约 100ms,可接受),用结果生成 sidebar。\n // Vite buildStart 时 viteplugin 会再扫一次,index 实例不同但内容一致。\n try {\n // v0.3:autoFolderIndex —— 在 scan 前给缺 index 的目录建一份 index.md。\n // 支持三种模式:'off' / 'top-level'(默认) / 'all'。\n // 兼容旧写法:true → 'top-level',false → 'off'。\n const folderOpts = normalizeAutoFolderIndex(\n sidebarAuto.autoFolderIndex,\n sidebarAuto.stripNumericPrefix,\n )\n if (folderOpts.mode !== 'off') {\n try {\n generateFolderIndexes(resolvedForWrapper, folderOpts)\n } catch (e) {\n console.warn(\n 'vitepress-allyouneed: autoFolderIndex 生成失败,跳过。',\n e instanceof Error ? e.message : String(e),\n )\n }\n }\n const index = scanVault(resolvedForWrapper)\n // 启动时把所有死 wikilink 集中 warn 一次,免得只能 dev 打开每页才能看到\n try {\n const report = scanWikilinks(index, resolvedForWrapper)\n logDeadLinks(report, resolvedForWrapper.deadLink)\n } catch {\n /* 不阻塞 */\n }\n // v0.3:i18n 支持 — 用户配了 themeConfig.locales(VitePress 原生 i18n),\n // 对每个 non-root locale 自动用 includePrefix 生成对应 sidebar,\n // root sidebar 用 excludePrefixes 排掉这些 locale 子树。\n const localesObj = (config as { locales?: Record<string, { link?: string; themeConfig?: Record<string, unknown> }> }).locales\n const localeKeys = localesObj\n ? Object.keys(localesObj).filter((k) => k !== 'root')\n : []\n\n themeConfig.sidebar = generateSidebar(index, resolvedForWrapper, {\n ...sidebarAuto,\n excludePrefixes: [\n ...(sidebarAuto.excludePrefixes ?? []),\n ...localeKeys, // 根 sidebar 排除掉所有 locale 子树\n ],\n })\n\n // 每个 non-root locale 各自生成 sidebar(在它自己的 themeConfig 里)\n if (localesObj) {\n for (const lang of localeKeys) {\n const localeCfg = localesObj[lang]!\n if (!localeCfg.themeConfig) localeCfg.themeConfig = {}\n if (localeCfg.themeConfig.sidebar === undefined) {\n localeCfg.themeConfig.sidebar = generateSidebar(\n index,\n resolvedForWrapper,\n { ...sidebarAuto, includePrefix: lang },\n )\n }\n }\n }\n\n // v0.3:autoNav 开启时,nav 没写就自动填(每个顶层目录一个 tab)\n if (sidebarAuto.autoNav && themeConfig.nav === undefined) {\n themeConfig.nav = generateNav(\n index,\n resolvedForWrapper,\n sidebarAuto,\n )\n }\n } catch (e) {\n console.warn(\n 'vitepress-allyouneed: sidebar 自动生成失败,跳过。',\n e instanceof Error ? e.message : String(e),\n )\n }\n }\n }\n\n if (resolvedForWrapper.modules.views) {\n themeConfig.sidebar = injectViewsSidebar(\n themeConfig.sidebar as Parameters<typeof injectViewsSidebar>[0],\n resolvedForWrapper,\n )\n // v0.3:也可注入到 nav(views.injectInto: 'nav' | 'both')\n themeConfig.nav = injectViewsNav(\n themeConfig.nav as Parameters<typeof injectViewsNav>[0],\n resolvedForWrapper,\n )\n // v0.3 i18n:每个 locale 的 themeConfig.nav 也注入(否则 i18n 下顶层 nav 被覆盖,\n // 下拉就消失了)\n const localesForNav = (config as { locales?: Record<string, { themeConfig?: { nav?: unknown } }> }).locales\n if (localesForNav) {\n for (const lang of Object.keys(localesForNav)) {\n const lc = localesForNav[lang]!\n if (!lc.themeConfig) continue\n if (lc.themeConfig.nav !== undefined) {\n lc.themeConfig.nav = injectViewsNav(\n lc.themeConfig.nav as Parameters<typeof injectViewsNav>[0],\n resolvedForWrapper,\n )\n }\n }\n }\n }\n\n return {\n ...config,\n vite: newVite,\n themeConfig,\n markdown: {\n ...existingMarkdown,\n config: newMarkdownConfig,\n },\n }\n}\n\n/**\n * 把 sidebarAuto.autoFolderIndex(union 类型)归一化成 generateFolderIndexes\n * 接受的对象形式。**默认 mode = 'top-level'**(用户没显式传时)。\n */\nfunction normalizeAutoFolderIndex(\n v: unknown,\n globalStripNumericPrefix: boolean | undefined,\n): {\n mode: 'off' | 'top-level' | 'all'\n exclude?: string[]\n stripNumericPrefix?: boolean\n template?: import('./core/sidebar-auto/generate-folder-index.js').FolderIndexOptions['template']\n} {\n let mode: 'off' | 'top-level' | 'all' = 'top-level'\n let exclude: string[] | undefined\n let strip: boolean | undefined = globalStripNumericPrefix\n let template:\n | import('./core/sidebar-auto/generate-folder-index.js').FolderIndexOptions['template']\n | undefined\n\n if (v === undefined || v === null) {\n // 用默认 'top-level'\n } else if (v === false || v === 'off') {\n mode = 'off'\n } else if (v === true || v === 'top-level') {\n mode = 'top-level'\n } else if (v === 'all') {\n mode = 'all'\n } else if (typeof v === 'object') {\n const obj = v as {\n mode?: 'off' | 'top-level' | 'all'\n enabled?: boolean\n exclude?: string[]\n stripNumericPrefix?: boolean\n template?: import('./core/sidebar-auto/generate-folder-index.js').FolderIndexOptions['template']\n }\n if (obj.mode) {\n mode = obj.mode\n } else if (obj.enabled === false) {\n mode = 'off'\n } else if (obj.enabled === true) {\n mode = 'top-level'\n }\n exclude = obj.exclude\n if (obj.stripNumericPrefix !== undefined) strip = obj.stripNumericPrefix\n template = obj.template\n }\n\n return { mode, exclude, stripNumericPrefix: strip, template }\n}\n\n/**\n * 构造 markdown-it core 规则,职责:**就地** mutate state.env 注入 vault 数据。\n *\n * ─ 为什么必须就地 mutate,不能新建 env ─\n *\n * VitePress 的 markdown 渲染流程大致是:\n *\n * ```ts\n * const env = { relativePath, realPath, ... }\n * const html = md.render(src, env)\n * const { __data, frontmatter, headers, ... } = env // 读回!\n * ```\n *\n * `@mdit-vue/plugin-frontmatter` 等 markdown-it 插件会通过 mutate `state.env`\n * 把 frontmatter 写到 `env.__data` 上;VitePress 之后从同一个 env 引用读取。\n *\n * 如果我们在中间 wrap 一层,把 env 换成新对象传给 md.render,新对象上的 mutation\n * 不会反映到 VitePress 的原 env → frontmatter / pageData 丢失 → 路由空 → 404。\n *\n * 用 core ruler 在 markdown-it 内部插入一步处理,直接 mutate state.env(就是\n * VitePress 传进来的同一个对象),既能注入我们的数据又不破坏 VitePress 的链路。\n */\nfunction makeEnvInjector(\n vitePlugin: ReturnType<typeof viteAllYouNeed>,\n): (state: { env?: unknown }) => void {\n return (state) => {\n const env = state.env as\n | (Record<string, unknown> & Partial<AllYouNeedEnv>)\n | undefined\n if (!env) return\n if (env.index && env.options) return // 已注入\n\n const index = vitePlugin.__getIndex()\n const options = vitePlugin.__getOptions()\n if (!index || !options) return\n\n env.index = index\n env.options = options\n if (!env.currentPath) {\n env.currentPath =\n typeof env.realPath === 'string'\n ? env.realPath\n : typeof env.path === 'string'\n ? env.path\n : undefined\n }\n if (!env.referencedAssets) env.referencedAssets = new Set()\n }\n}\n\nexport default defineConfigWithAllYouNeed\n"],"mappings":"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","names":["mditVueSlugify","import_node_fs","import_node_path","nodePath","import_node_path","fs","nodePath","import_node_fs","import_node_path","nodePath","fs","picomatch","matter","nodePath","fs","extractExt","import_node_fs","import_node_path","import_node_fs","import_node_path","fs","import_node_fs","import_node_path","nodePath","fs","import_node_fs","import_node_path","nodePath","fs","nodePath","fs","LINE_RE","WIKILINK_RE","buildTree","import_node_fs","import_node_path","nodePath","fs","humanize","walk","WIKILINK_RE","extractExt"]}
|