vitepress-allyouneed 0.5.3 → 0.5.4

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,12 @@
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
+ ## [Unreleased]
6
+
7
+ ### Fixed
8
+ - **同名页面跨 locale / 区域解析错误**:`[[Gravitationsphysik]]` 这类 basename-only Wikilink 不再直接使用全局 `onConflict`。解析器现在先按源页面的同目录和最长共同路径前缀收窄候选(例如 `zh/themen/*` 优先于 `zh/selfcheck/*`,二者都优先于其它 locale),仍有歧义时才执行 `shortest` / `first` / `error`。
9
+ - 强化当前源页面定位:relativePath 精确匹配先于后缀兜底,且后缀存在多个 locale 命中时不再取扫描顺序中的第一个。
10
+
5
11
  ## [0.5.3] - 2026-06-20
6
12
 
7
13
  0.5.2 的 **Bug 2 修复不完整**(已发到 npm,故 0.5.2 标记 deprecated;请升到 0.5.3)。本版把它彻底修对,并补齐 i18n 实战验证。
package/README.md CHANGED
@@ -155,7 +155,7 @@ export default defineConfig({
155
155
  | `cleanUrls` | `boolean` | 跟 VitePress `cleanUrls` 走 | URL 是否带 `.html` |
156
156
  | `caseSensitive` | `boolean` | `false` | wikilink/asset 解析是否大小写敏感 |
157
157
  | `deadLink` | `'silent' \| 'warn' \| 'error'` | `'warn'` | 死链处理 |
158
- | `onConflict` | `'shortest' \| 'first' \| 'error'` | `'shortest'` | 同名文件冲突策略 |
158
+ | `onConflict` | `'shortest' \| 'first' \| 'error'` | `'shortest'` | 同名文件先按当前页面的同目录/共同路径前缀收窄,再执行冲突策略 |
159
159
  | `onAliasConflict` | `'first' \| 'error'` | `'first'` | alias 冲突策略 |
160
160
  | `slugify` | `(text: string) => string` | `@mdit-vue/shared` | 锚点 slugifier,必须与 VitePress `markdown.anchor.slugify` 一致 |
161
161
  | `assets.preserveAssetPaths` | `boolean` | `false` | true 保留原 vault 路径(`/assets/foo.png`)、不哈希;false 走 `/_assets/<hash>-foo.png` |
package/dist/index.cjs CHANGED
@@ -721,22 +721,22 @@ function findSelfEntry(currentSourcePath, index) {
721
721
  const norm = toPosix(currentSourcePath).replace(/^\.\//, "");
722
722
  const byNorm = index.files.get(norm);
723
723
  if (byNorm) return byNorm;
724
- let suffixHit;
724
+ const srcDir = toPosix(index.srcDir).replace(/\/$/, "");
725
+ const relativeNorm = norm.startsWith(srcDir + "/") ? norm.slice(srcDir.length + 1) : norm;
726
+ const byRelative = index.byRelativePath.get(relativeNorm);
727
+ if (byRelative) return byRelative;
728
+ const suffixHits = [];
725
729
  for (const e of index.files.values()) {
726
730
  const abs = e.absolutePath;
727
731
  if (abs === norm || abs.endsWith("/" + norm)) {
728
- suffixHit = e;
729
- break;
732
+ suffixHits.push(e);
733
+ continue;
730
734
  }
731
735
  if (e.relativePath && norm.endsWith("/" + e.relativePath)) {
732
- suffixHit = e;
733
- break;
736
+ suffixHits.push(e);
734
737
  }
735
738
  }
736
- if (suffixHit) return suffixHit;
737
- for (const e of index.files.values()) {
738
- if (e.relativePath && e.relativePath.replace(/^\.\//, "") === norm) return e;
739
- }
739
+ if (suffixHits.length === 1) return suffixHits[0];
740
740
  const bn = basename(norm);
741
741
  if (bn) {
742
742
  const matches = [];
@@ -808,17 +808,50 @@ function lookupEntry(target, index, options, currentSourcePath, forcePathStyle =
808
808
  const candidates = bnMap.get(bnKey);
809
809
  if (!candidates || candidates.length === 0) return void 0;
810
810
  if (candidates.length === 1) return candidates[0];
811
+ const contextualCandidates = narrowCandidatesBySource(
812
+ candidates,
813
+ currentSourcePath,
814
+ index
815
+ );
816
+ if (contextualCandidates.length === 1) return contextualCandidates[0];
811
817
  switch (options.onConflict) {
812
818
  case "shortest": {
813
- const sorted = sortByShortestPath(candidates);
819
+ const sorted = sortByShortestPath(contextualCandidates);
814
820
  return sorted[0];
815
821
  }
816
822
  case "first":
817
- return candidates[0];
823
+ return contextualCandidates[0];
818
824
  case "error":
819
825
  return void 0;
820
826
  }
821
827
  }
828
+ function narrowCandidatesBySource(candidates, currentSourcePath, index) {
829
+ if (!currentSourcePath) return candidates;
830
+ const source = findSelfEntry(currentSourcePath, index);
831
+ if (!source) return candidates;
832
+ const sourceDir = directorySegments(source.relativePath);
833
+ let bestScore = 0;
834
+ const scored = candidates.map((candidate) => {
835
+ const candidateDir = directorySegments(candidate.relativePath);
836
+ const exactDirectory = sourceDir.length === candidateDir.length && sourceDir.every((segment, i) => segment === candidateDir[i]);
837
+ if (exactDirectory) {
838
+ return { candidate, score: sourceDir.length + 1 };
839
+ }
840
+ let commonPrefix = 0;
841
+ const limit = Math.min(sourceDir.length, candidateDir.length);
842
+ while (commonPrefix < limit && sourceDir[commonPrefix] === candidateDir[commonPrefix]) {
843
+ commonPrefix += 1;
844
+ }
845
+ return { candidate, score: commonPrefix };
846
+ });
847
+ for (const item of scored) bestScore = Math.max(bestScore, item.score);
848
+ if (bestScore === 0) return candidates;
849
+ return scored.filter((item) => item.score === bestScore).map((item) => item.candidate);
850
+ }
851
+ function directorySegments(relativePath) {
852
+ const parts = toPosix(relativePath).replace(/^\.\//, "").split("/");
853
+ return parts.slice(0, -1);
854
+ }
822
855
  function matchHeading(entry, headingPart, slugify, mode) {
823
856
  const exact = entry.headings.find(
824
857
  (h) => h.text === headingPart || h.slug === headingPart || h.slug === slugify(headingPart)
@@ -2368,7 +2401,7 @@ function renderTemplate(v) {
2368
2401
  // src/core/views/generate-data.ts
2369
2402
  var import_node_fs6 = __toESM(require("fs"), 1);
2370
2403
  var import_node_path6 = __toESM(require("path"), 1);
2371
- var PLUGIN_VERSION = true ? "0.5.3" : "0.0.0-dev";
2404
+ var PLUGIN_VERSION = true ? "0.5.4" : "0.0.0-dev";
2372
2405
  var WIKILINK_RE = /(!?)\[\[([^\]\n]+)\]\]/g;
2373
2406
  var DEFAULT_BODY_TAG_RE = /(?:^|[\s([{,;。,;])#([\p{L}_][\p{L}\p{N}_/-]*)/gu;
2374
2407
  function buildBodyTagRe(userPattern) {