vitepress-allyouneed 0.3.6 → 0.3.8
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 +26 -0
- package/dist/index.cjs +64 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +64 -5
- package/dist/index.js.map +1 -1
- package/dist/markdown-it.cjs +24 -3
- package/dist/markdown-it.cjs.map +1 -1
- package/dist/markdown-it.js +24 -3
- package/dist/markdown-it.js.map +1 -1
- package/dist/vite.cjs +13 -0
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.js +13 -0
- package/dist/vite.js.map +1 -1
- package/dist/vitepress.cjs +64 -5
- package/dist/vitepress.cjs.map +1 -1
- package/dist/vitepress.js +64 -5
- package/dist/vitepress.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
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.3.8] - 2026-05-21
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **wikilink 锚点匹配过严**:用户表格里大量写 `[[X#7.2]]` 想匹配 `## 7.2 Antike — Vorsokratiker`、`[[X#11.2 Kepler]]` 想匹配 `## 11.2 Die drei Kepler'schen Gesetze`、`[[X#4.2 Cavendish]]` 想匹配 `## 4.2 Cavendish-Experiment (8. Klasse, 1798)` 等。老 resolver 只做 exact text / slug match,以上全部归为 "unmatched-anchor"——页面能加载、锚点不跳。现在加两层 fallback:
|
|
9
|
+
1. **prefix-with-boundary**:`headingPart` 是 heading text 的前缀,且下一字符是 whitespace 或字符串末尾。处理 `#7.2` → `7.2 Antike...`,且**不**误匹配 `7.21 Andere ...`(下一字符不是空白)。
|
|
10
|
+
2. **token match**:`headingPart` 按空白拆 token,所有 token 都(忽略大小写)出现在 heading text 中。多个 candidate 取最短 text(最精确那条)。处理 `#11.2 Kepler` → `11.2 Die drei Kepler'schen Gesetze`(同时含 "11.2" 和 "kepler",H3 "1. Kepler'sches Gesetz" 不含 "11.2" 被排除)。
|
|
11
|
+
|
|
12
|
+
这一改更贴近 Obsidian 用户在表格里"section-number-only"或"number + keyword"的实际书写习惯。
|
|
13
|
+
|
|
14
|
+
### Tests
|
|
15
|
+
- 新增 `tests/v038-anchor-fuzzy.test.ts`,覆盖 exact / prefix / token / 误匹配防护 / unmatched fallback 等 7 个用例。
|
|
16
|
+
|
|
17
|
+
## [0.3.6] - 2026-05-20
|
|
18
|
+
|
|
19
|
+
针对用户反馈"Perspectives 有时不加载 / sidebar 有时错"的间歇性问题做了系统排查,5 个真 bug。
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- **Perspectives 在 `locales.root.themeConfig` 配置下消失**:VitePress 1.6 渲染时浅 merge `themeConfig` 与 `siteData.locales[k]?.themeConfig` —— locale 整个**替换**顶层 nav/sidebar。wrapper 之前 `if (lang === 'root') continue` 跳过 root,导致用户用标准 i18n 写法 `locales: { root: { themeConfig: { nav: [...] }}}` 时,顶层 Perspectives 被 root 的(未注入)nav 覆盖。现在所有 locale(含 root)都过 inject。
|
|
23
|
+
- **dev 模式下新增 / 删除文件后 sidebar/nav 不更新**:wrapper 只在 config time 跑一次 scan + 生成 sidebar,后续 hot-update 只刷新 Vite 插件的 index(用于 wikilink / asset / vault-data.json)。结构变化静默吞掉。现在 `handleHotUpdate` 检测到 `.md` 文件 add / remove 时 `console.warn` 提示"重启 dev 服务器才能反映 sidebar/nav 变化"。
|
|
24
|
+
- **空 `themeConfig.sidebar = {}` 或部分 per-path 配置下 Perspectives 在根路径消失**:`injectViewsSidebar` 老逻辑 `for (Object.keys(sidebar))` 在空 object 上跑 0 次,Perspectives 没塞任何路径;用户在 `/` 或非匹配路径访问时看不到。现在显式给 `/` key 兜底一份。
|
|
25
|
+
- **`themeConfig.nav` 是 function 时被替换为 `[Perspectives]`**:VitePress nav 支持 function(动态 / locale-aware)。老 `Array.isArray(fn) ? [...fn] : []` 把 function 错判成"无 nav",推 Perspectives 后用单元素数组覆盖用户函数。现在 `typeof === 'function'` 时 wrap 一层,运行时调用用户 fn + 追加 Perspectives;用户 fn 抛错时容错只返 Perspectives 并 warn。
|
|
26
|
+
- **perspective fallback sidebar 含标题为 `/` 的死项**:`buildPerspectivesFallbackSidebar` 过滤 `p !== base`,但 base 是 `/sub/` 时永远不等于 `/` → `/` 进 topPaths → seg 为空 → 渲染为 `text: '/'` 的死项。现在显式排除 `'/'` + 双保险 `if (!seg) continue`。
|
|
27
|
+
|
|
28
|
+
### Tests
|
|
29
|
+
- 新增 `tests/v036-perspective-locale.test.ts`,覆盖以上 5 个 bug。
|
|
30
|
+
|
|
5
31
|
## [0.3.5] - 2026-05-20
|
|
6
32
|
|
|
7
33
|
零配置导航更顺手:不写 `index.md` 也能从导航 / sidebar / 用户手写 wikilink 进到一个文件夹;默认 index 模板换成"文件管理器风格"(子文件夹在上、文件在下)。
|
package/dist/index.cjs
CHANGED
|
@@ -683,9 +683,7 @@ function resolveWikilink(rawTarget, index, options, kind = "page", currentSource
|
|
|
683
683
|
let url = entry.url;
|
|
684
684
|
let hasUnmatchedAnchor = false;
|
|
685
685
|
if (headingPart) {
|
|
686
|
-
const heading = entry.
|
|
687
|
-
(h) => h.text === headingPart || h.slug === headingPart || h.slug === options.slugify(headingPart)
|
|
688
|
-
);
|
|
686
|
+
const heading = matchHeading(entry, headingPart, options.slugify);
|
|
689
687
|
if (heading) {
|
|
690
688
|
url = entry.url + "#" + heading.slug;
|
|
691
689
|
} else {
|
|
@@ -765,6 +763,29 @@ function lookupEntry(target, index, options, currentSourcePath, forcePathStyle =
|
|
|
765
763
|
return void 0;
|
|
766
764
|
}
|
|
767
765
|
}
|
|
766
|
+
function matchHeading(entry, headingPart, slugify) {
|
|
767
|
+
const exact = entry.headings.find(
|
|
768
|
+
(h) => h.text === headingPart || h.slug === headingPart || h.slug === slugify(headingPart)
|
|
769
|
+
);
|
|
770
|
+
if (exact) return exact;
|
|
771
|
+
const lc = headingPart.toLowerCase();
|
|
772
|
+
const prefix = entry.headings.find((h) => {
|
|
773
|
+
const t = h.text.toLowerCase();
|
|
774
|
+
if (!t.startsWith(lc)) return false;
|
|
775
|
+
if (t.length === lc.length) return true;
|
|
776
|
+
return /\s/.test(h.text[lc.length]);
|
|
777
|
+
});
|
|
778
|
+
if (prefix) return prefix;
|
|
779
|
+
const tokens = headingPart.split(/\s+/).map((t) => t.trim()).filter(Boolean);
|
|
780
|
+
if (tokens.length === 0) return void 0;
|
|
781
|
+
const candidates = entry.headings.filter((h) => {
|
|
782
|
+
const lct = h.text.toLowerCase();
|
|
783
|
+
return tokens.every((tok) => lct.includes(tok.toLowerCase()));
|
|
784
|
+
});
|
|
785
|
+
if (candidates.length === 0) return void 0;
|
|
786
|
+
if (candidates.length === 1) return candidates[0];
|
|
787
|
+
return [...candidates].sort((a, b) => a.text.length - b.text.length)[0];
|
|
788
|
+
}
|
|
768
789
|
function findFirstFileInFolder(folderPath, index) {
|
|
769
790
|
const prefix = folderPath + "/";
|
|
770
791
|
const candidates = [];
|
|
@@ -2424,15 +2445,28 @@ function viteAllYouNeed(userOptions = {}) {
|
|
|
2424
2445
|
},
|
|
2425
2446
|
handleHotUpdate(ctx) {
|
|
2426
2447
|
if (!index) return;
|
|
2448
|
+
const isMd = /\.(md|markdown)$/i.test(ctx.file);
|
|
2449
|
+
const wasIndexed = isMd && index.files.has(ctx.file);
|
|
2450
|
+
let structuralChange = null;
|
|
2427
2451
|
try {
|
|
2428
2452
|
const stat = import_node_fs7.default.statSync(ctx.file);
|
|
2429
2453
|
if (stat.isFile()) {
|
|
2430
2454
|
updateFile(index, ctx.file, resolved);
|
|
2455
|
+
const isNowIndexed = index.files.has(ctx.file);
|
|
2456
|
+
if (!wasIndexed && isNowIndexed) structuralChange = "add";
|
|
2431
2457
|
} else if (!import_node_fs7.default.existsSync(ctx.file)) {
|
|
2432
2458
|
removeFile(index, ctx.file, resolved);
|
|
2459
|
+
if (wasIndexed) structuralChange = "remove";
|
|
2433
2460
|
}
|
|
2434
2461
|
} catch {
|
|
2435
2462
|
removeFile(index, ctx.file, resolved);
|
|
2463
|
+
if (wasIndexed) structuralChange = "remove";
|
|
2464
|
+
}
|
|
2465
|
+
if (structuralChange) {
|
|
2466
|
+
const rel = toPosix(ctx.file).replace(toPosix(resolved.srcDir) + "/", "");
|
|
2467
|
+
console.warn(
|
|
2468
|
+
`vitepress-allyouneed: \u68C0\u6D4B\u5230\u7ED3\u6784\u53D8\u5316(${structuralChange === "add" ? "\u65B0\u589E" : "\u5220\u9664"} ${rel}),sidebar/nav \u5DF2\u88AB\u70D8\u7119\u5230 VitePress \u914D\u7F6E\u4E2D,**\u91CD\u542F dev \u670D\u52A1\u5668**\u624D\u80FD\u53CD\u6620;wikilink/asset \u5DF2\u5B9E\u65F6\u5237\u65B0\u3002`
|
|
2469
|
+
);
|
|
2436
2470
|
}
|
|
2437
2471
|
if (resolved.modules.views) {
|
|
2438
2472
|
try {
|
|
@@ -2546,6 +2580,11 @@ function injectViewsSidebar(sidebar, options) {
|
|
|
2546
2580
|
arr.push(group);
|
|
2547
2581
|
}
|
|
2548
2582
|
}
|
|
2583
|
+
if (!sidebar["/"]) {
|
|
2584
|
+
sidebar["/"] = [group];
|
|
2585
|
+
} else if (!sidebar["/"].some((it) => it.text === group.text)) {
|
|
2586
|
+
sidebar["/"].push(group);
|
|
2587
|
+
}
|
|
2549
2588
|
}
|
|
2550
2589
|
const prefix = options.views.urlPrefix ? options.views.urlPrefix.replace(/^\/+|\/+$/g, "") : "";
|
|
2551
2590
|
if (prefix) {
|
|
@@ -2567,10 +2606,11 @@ function buildPerspectivesFallbackSidebar(allSidebars, group, base, viewsPrefix)
|
|
|
2567
2606
|
const out = [{ text: "Home", link: "/" }];
|
|
2568
2607
|
const persSuffix = `/${viewsPrefix}/`;
|
|
2569
2608
|
const topPaths = Object.keys(allSidebars).filter(
|
|
2570
|
-
(p) => p !== base && !p.endsWith(persSuffix)
|
|
2609
|
+
(p) => p !== "/" && p !== base && !p.endsWith(persSuffix)
|
|
2571
2610
|
);
|
|
2572
2611
|
for (const p of topPaths) {
|
|
2573
2612
|
const seg = p.replace(/^\/|\/$/g, "").split("/").filter(Boolean).pop() ?? p;
|
|
2613
|
+
if (!seg) continue;
|
|
2574
2614
|
const text = seg.charAt(0).toUpperCase() + seg.slice(1);
|
|
2575
2615
|
const b = base.endsWith("/") ? base : base + "/";
|
|
2576
2616
|
const stripped = b !== "/" && p.startsWith(b) ? "/" + p.slice(b.length) : p;
|
|
@@ -2612,6 +2652,26 @@ function injectViewsNav(nav, options) {
|
|
|
2612
2652
|
link: it.link
|
|
2613
2653
|
}))
|
|
2614
2654
|
};
|
|
2655
|
+
if (typeof nav === "function") {
|
|
2656
|
+
const userFn = nav;
|
|
2657
|
+
return () => {
|
|
2658
|
+
let arr2;
|
|
2659
|
+
try {
|
|
2660
|
+
const r = userFn();
|
|
2661
|
+
arr2 = Array.isArray(r) ? [...r] : [];
|
|
2662
|
+
} catch (e) {
|
|
2663
|
+
console.warn(
|
|
2664
|
+
"vitepress-allyouneed: themeConfig.nav \u51FD\u6570\u6267\u884C\u5931\u8D25,\u4EC5\u8FD4\u56DE Perspectives \u4E0B\u62C9\u3002",
|
|
2665
|
+
e instanceof Error ? e.message : String(e)
|
|
2666
|
+
);
|
|
2667
|
+
arr2 = [];
|
|
2668
|
+
}
|
|
2669
|
+
if (!arr2.some((it) => it && it.text === navItem.text)) {
|
|
2670
|
+
arr2.push(navItem);
|
|
2671
|
+
}
|
|
2672
|
+
return arr2;
|
|
2673
|
+
};
|
|
2674
|
+
}
|
|
2615
2675
|
const arr = Array.isArray(nav) ? [...nav] : [];
|
|
2616
2676
|
if (!arr.some((it) => it.text === navItem.text)) {
|
|
2617
2677
|
arr.push(navItem);
|
|
@@ -3675,7 +3735,6 @@ function defineConfigWithAllYouNeed(config, pluginOptions = {}) {
|
|
|
3675
3735
|
const localesForViews = config.locales;
|
|
3676
3736
|
if (localesForViews) {
|
|
3677
3737
|
for (const lang of Object.keys(localesForViews)) {
|
|
3678
|
-
if (lang === "root") continue;
|
|
3679
3738
|
const lc = localesForViews[lang];
|
|
3680
3739
|
if (!lc.themeConfig) lc.themeConfig = {};
|
|
3681
3740
|
if (lc.themeConfig.sidebar !== void 0) {
|