vitepress-allyouneed 0.5.2 → 0.5.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 CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  本项目遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/);版本号遵循 [SemVer](https://semver.org/lang/zh-CN/)。
4
4
 
5
+ ## [0.5.3] - 2026-06-20
6
+
7
+ 0.5.2 的 **Bug 2 修复不完整**(已发到 npm,故 0.5.2 标记 deprecated;请升到 0.5.3)。本版把它彻底修对,并补齐 i18n 实战验证。
8
+
9
+ ### Fixed
10
+ - **自引用锚点 `[[#heading]]` 在 i18n / 重名文件布局下仍然全部死链**(0.5.2 的修复在那些场景下无效)。
11
+ - 根因:0.5.2 用 `index.files.get(currentSourcePath)` **精确取键**把"当前文件路径"映射回 entry。但渲染期的 `env.currentPath`(VitePress 的 `env.realPath`/`env.path`)与 index 键(`entry.absolutePath`,扫描时 `toPosix` 过)的**归一化形态在不同版本/配置(尤其 i18n 多 locale + 同名文件,如 `Astronomie und Exobiologie.md` 在 root 与 `/zh/` 各一份)下不一致**,精确 get 一旦 miss → 自引用又全死链。0.5.2 的单文件 renderer 验证没有真实 locale 上下文,给了**假阳性**。
12
+ - 修复:`core/resolver.ts` 新增 `findSelfEntry()`,逐级回退命中当前文件:精确键 → `toPosix` 归一键 → 后缀(相对路径,`/` 边界防误配)→ `relativePath` 相等 → basename 唯一兜底。**归一化先于 basename 兜底**,确保重名文件解析到正确的那一个(root 不串 zh)。
13
+ - 验证:用**真实 `vitepress build`**(含 i18n root + `/zh/` 同名文件)产出的 HTML 核对 `class="wikilink"` 标签 —— 两个 locale 的自引用锚点均为 live `href` 且各指向本文件 heading,0 个 `wikilink--dead`。新增 9 条回归测试(路径归一化形态 + DE/ZH 重名)。
14
+
15
+ > 注:验证渲染 HTML 时只匹配 `class="wikilink"` 的 `<a>`;VitePress 给每个标题加的 header-anchor permalink(`href="#slug"`)会让 naive 的 `href="#…"` grep 误判死链为 live。
16
+
5
17
  ## [0.5.2] - 2026-06-20
6
18
 
7
19
  实战(90 页 DE+ZH 物理知识库,重 KaTeX / Wikilink / GFM 表格)发现的三个 build-blocker / 死链 bug,纯插件侧可修,无需改任何内容。
@@ -11,8 +23,9 @@
11
23
  - 根因:`modules/tags/rule.ts` 的 `#tag` inline rule 注册在 `link` 之前;markdown-it 的 link 核心规则用 `parseLinkLabel → skipToken` 以 **silent 模式**扫描 `[...]` label,本规则在 silent 下 `return true` 却**没推进 `state.pos`**,触发 markdown-it 的安全检查并经 `parseLinkLabel` 对未消费的 `[` 递归。0.5.1 已修了 wikilink rule 的同款问题,但 tag rule 漏改 —— 复现文件正是报告里的 `themen/Astronomie und Exobiologie.md`(`[[#Biomarker|…]]` 被表格 `|` 拆成 `[[#Biomarker`,其中 `#Biomarker` 命中 tag rule)。
12
24
  - 修复:silent 模式下也把 `state.pos` 推过匹配长度再 `return true`,token 产出仍门控在 `!silent`(对齐 markdown-it 自带规则)。
13
25
  - **页内跳转锚点 `[[#heading]]` 即使 slug 精确匹配也被判死链 / 失去 `href`**(报告:仅德语主题就 74 处)。
14
- - 根因:自引用 wikilink(只有 `#anchor`、无文件部分)解析时 `target` 被切成空串 → `lookupEntry('')`/`resolveSimple('')` 返回空 → 整条 wikilink 误判 dead。
15
- - 修复:`core/resolver.ts` `core/scan-wikilinks.ts` 双路径统一处理 —— heading 部分且无文件部分时解析到**当前文件本身**,后续 heading 匹配(exact slug,各 `anchorMatch` 模式通吃)正常命中;`scan-wikilinks` 不再把自引用锚点计入死链汇总。
26
+ - 根因①:自引用 wikilink(只有 `#anchor`、无文件部分)解析时 `target` 被切成空串 → `lookupEntry('')`/`resolveSimple('')` 返回空 → 整条 wikilink 误判 dead。
27
+ - 根因②(关键,初版漏掉):把"当前文件路径"映射回 entry 时用 `index.files.get(currentSourcePath)` **精确取键**。但渲染期传进来的 `env.currentPath`(= VitePress `env.realPath`/`env.path`)与 index 键(`entry.absolutePath`,扫描时 `toPosix` 过)的**归一化形态在不同版本/配置下不保证一致**(反斜杠、前导 `./`、相对 vs 绝对、`srcDir` 解析差异),精确 get 一旦 miss → 自引用又**全部死链**。
28
+ - 修复:`core/resolver.ts` 新增 `findSelfEntry` —— 精确键 → `toPosix` 归一键 → 后缀(相对路径)匹配(`/` 边界防误配)→ `relativePath` 相等 → basename 唯一兜底,逐级回退;对重名文件(报告里 `Astronomie und Exobiologie.md` DE+ZH 共存)用归一化优先于 basename 兜底,确保解析到**正确**的那个文件而非串台。`core/scan-wikilinks.ts` 同步不再把自引用锚点计入死链汇总。heading 匹配(exact slug,各 `anchorMatch` 模式通吃)随后正常命中。
16
29
  - **缺失的 embed 资源(`![[foo.gif]]` / 音视频 / PDF 指向不存在文件)把整个 Vite/Rollup 构建硬中断**,报 `Rollup failed to resolve import "/foo.gif"`。
17
30
  - 根因:`modules/embeds/image.ts` 与 `modules/embeds/media.ts` 在 asset 解析不到时回退成绝对路径 `/{basename}`,该 URL 被 VitePress 的 Vite 插件当模块 import,Rollup 解析不到即 throw。
18
31
  - 修复:缺失资源不再产出会被 Vite 解析的 `src`,改为按 `deadLink` 策略告警(`silent`/`warn`/`error`,`error` 推 `index.warnings` 让构建以非零退出但不中断渲染)+ 渲染一个**不触发 Vite 解析**的占位 `<span class="ayn-embed ayn-embed--missing">`,与死链行为一致,绝不 throw。
package/README.md CHANGED
@@ -4,12 +4,12 @@
4
4
 
5
5
  Forked from [`actuallysomecat/markdown-it-wikilinks-plus`](https://github.com/actuallysomecat/markdown-it-wikilinks-plus) (MIT) 并针对 VitePress 大幅重写。
6
6
 
7
- ## 当前版本:0.5.2(2026-06-20)
7
+ ## 当前版本:0.5.3(2026-06-20)
8
8
 
9
- **实战 build-blocker 修复**(详见 [CHANGELOG](./CHANGELOG.md#052---2026-06-20)):
9
+ **实战 build-blocker 修复**(详见 [CHANGELOG](./CHANGELOG.md#053---2026-06-20)):
10
10
 
11
11
  - `#tag` 出现在 link label / 嵌套方括号 / GFM 表格单元格时不再让 `vitepress build` 整站崩溃(`inline rule didn't increment state.pos`)。
12
- - 页内自引用锚点 `[[#heading]]` 不再被误判死链 —— slug 精确匹配现在正常生成可点击 `href`。
12
+ - 页内自引用锚点 `[[#heading]]` 不再被误判死链 —— i18n / 同名文件布局下也能正常生成可点击 `href`(0.5.2 此修复不完整,0.5.3 修对)。
13
13
  - 缺失的 embed 资源(`![[foo.gif]]` / 音视频 / PDF)不再硬中断 Vite 构建,改为按 `deadLink` 策略告警 + 渲染占位标记。
14
14
 
15
15
  ### 0.5.1:主题集成大改 —— 目标:让第三方 VitePress 主题作者不需要知道本插件存在
package/dist/index.cjs CHANGED
@@ -682,7 +682,7 @@ function resolveWikilink(rawTarget, index, options, kind = "page", currentSource
682
682
  target = stripMarkdownExt(target);
683
683
  let selfEntry;
684
684
  if (!target && headingPart && currentSourcePath) {
685
- selfEntry = index.files.get(currentSourcePath);
685
+ selfEntry = findSelfEntry(currentSourcePath, index);
686
686
  }
687
687
  const entry = selfEntry ?? lookupEntry(target, index, options, currentSourcePath, wasFolderForm);
688
688
  if (!entry) {
@@ -715,6 +715,39 @@ function resolveWikilink(rawTarget, index, options, kind = "page", currentSource
715
715
  kind
716
716
  };
717
717
  }
718
+ function findSelfEntry(currentSourcePath, index) {
719
+ const direct = index.files.get(currentSourcePath);
720
+ if (direct) return direct;
721
+ const norm = toPosix(currentSourcePath).replace(/^\.\//, "");
722
+ const byNorm = index.files.get(norm);
723
+ if (byNorm) return byNorm;
724
+ let suffixHit;
725
+ for (const e of index.files.values()) {
726
+ const abs = e.absolutePath;
727
+ if (abs === norm || abs.endsWith("/" + norm)) {
728
+ suffixHit = e;
729
+ break;
730
+ }
731
+ if (e.relativePath && norm.endsWith("/" + e.relativePath)) {
732
+ suffixHit = e;
733
+ break;
734
+ }
735
+ }
736
+ if (suffixHit) return suffixHit;
737
+ for (const e of index.files.values()) {
738
+ if (e.relativePath && e.relativePath.replace(/^\.\//, "") === norm) return e;
739
+ }
740
+ const bn = basename(norm);
741
+ if (bn) {
742
+ const matches = [];
743
+ for (const e of index.files.values()) {
744
+ if (basename(e.absolutePath) === bn) matches.push(e);
745
+ if (matches.length > 1) break;
746
+ }
747
+ if (matches.length === 1) return matches[0];
748
+ }
749
+ return void 0;
750
+ }
718
751
  function lookupEntry(target, index, options, currentSourcePath, forcePathStyle = false) {
719
752
  if (!target) return void 0;
720
753
  if (target.includes("/") || forcePathStyle) {
@@ -2335,7 +2368,7 @@ function renderTemplate(v) {
2335
2368
  // src/core/views/generate-data.ts
2336
2369
  var import_node_fs6 = __toESM(require("fs"), 1);
2337
2370
  var import_node_path6 = __toESM(require("path"), 1);
2338
- var PLUGIN_VERSION = true ? "0.5.2" : "0.0.0-dev";
2371
+ var PLUGIN_VERSION = true ? "0.5.3" : "0.0.0-dev";
2339
2372
  var WIKILINK_RE = /(!?)\[\[([^\]\n]+)\]\]/g;
2340
2373
  var DEFAULT_BODY_TAG_RE = /(?:^|[\s([{,;。,;])#([\p{L}_][\p{L}\p{N}_/-]*)/gu;
2341
2374
  function buildBodyTagRe(userPattern) {