@takazudo/zudo-doc 9.1.0 → 9.1.2

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
@@ -8,6 +8,18 @@ The format is based on Keep a Changelog, and release notes are generated from th
8
8
 
9
9
  No unreleased changes.
10
10
 
11
+ ## [9.1.2] - 2026-11-03
12
+
13
+ ### Bug Fixes
14
+
15
+ - Require the ZFB 5.2.0 family (`^5.2.0`) so client navigation respects native link targets, including document base targets, resolves form actions against the document base, and cancels obsolete navigation when the browser traverses same-document history. This prevents a delayed navigation from overwriting the page selected by Back. (aaef3135)
16
+
17
+ ## [9.1.1] - 2026-10-30
18
+
19
+ ### Bug Fixes
20
+
21
+ - `categoryMatch` once again owns its dash "satellite" directories, fixing a 9.1.0 regression. With the 9.1.0 whole-segment rule, `categoryMatch: "claude"` stopped claiming the generated `claude-md/`, `claude-skills/`, and `claude-commands/` trees (and `"codex"` its `codex-*` trees), so those pages lost the Claude tab and its sidebar. A value now owns `foo`, `foo/...`, and `foo-*`, but still not `foo2`; the longest matching value wins, so an explicit `foo-bar` keeps its own section. (4975426b)
22
+
11
23
  ## [9.1.0] - 2026-10-28
12
24
 
13
25
  ### Features
package/README.md CHANGED
@@ -109,7 +109,7 @@ If your project renders **semi-trusted or user-submitted** HTML in a preview, ov
109
109
 
110
110
  **6.0.0** is the coordinated major release of `@takazudo/zudo-doc`,
111
111
  `@takazudo/zudo-doc-history-server` and `create-zudo-doc`. The current workspace
112
- targets the published **zfb 5.1.5** family (peer floor **^5.1.5**).
112
+ targets the published **zfb 5.2.0** family (peer floor **^5.2.0**).
113
113
  [Upstream #4097](https://github.com/Takazudo/zudo-front-builder/issues/4097) is
114
114
  resolved; its strict published 4.3.1 consumer control passed 3/3 with no skips or
115
115
  retries in the [source-bound verification](../../docs/findings/zfb-4.3.1/verification.md).
@@ -111,8 +111,8 @@ export declare function assertValidSearchMaxBodyLength(searchMaxBodyLength: numb
111
111
  * Warn about `categoryMatch` values that cannot express the intended
112
112
  * dropdown grouping.
113
113
  *
114
- * A category matcher is compared with the first slug segment by the nav-scope
115
- * resolver, so a value containing `/` never matches. Likewise, duplicate
114
+ * A category matcher is compared with the first slug segment (and its `-`
115
+ * satellites) by the nav-scope resolver, so a value containing `/` never matches. Likewise, duplicate
116
116
  * child values make every matching child category-active. Children grouped
117
117
  * under one top-level directory should omit `categoryMatch` and rely on the
118
118
  * deepest matching child path; Learn-style children should use distinct
@@ -17,6 +17,17 @@ export interface NavScopeHeaderNavItem {
17
17
  * headerNav array instead of reading `settings.headerNav` directly.
18
18
  */
19
19
  export declare function getCategoryOrder(headerNav: NavScopeHeaderNavItem[]): string[];
20
+ /**
21
+ * Resolve which explicit categoryMatch owns a slug's top-level category.
22
+ *
23
+ * A matcher `m` owns the top-level segment `m` itself and its dash
24
+ * "satellites" (`m-*`), the same convention `groupSatelliteNodes` uses for the
25
+ * generated `claude-md/`, `claude-skills/`, `codex-agents-md/`, … trees. `foo`
26
+ * does not own `foo2`. When several matchers apply, the longest wins, so an
27
+ * explicit `foo-bar` keeps `foo-bar` and `foo-bar-*` out of `foo`. `"!"` is
28
+ * ignored; callers apply the fallback themselves.
29
+ */
30
+ export declare function resolveCategoryOwner(slug: string, explicitMatches: readonly string[]): string | undefined;
20
31
  /**
21
32
  * Given a doc's slug (e.g. "getting-started/introduction" or "guides/overview"),
22
33
  * return the categoryMatch value of the headerNav item it belongs to.
@@ -28,7 +39,8 @@ export declare function getNavSectionForSlug(slug: string, headerNav: NavScopeHe
28
39
  /**
29
40
  * Filter top-level NavNodes by a headerNav categoryMatch value.
30
41
  * - `"!"` means everything NOT claimed by explicit matchers
31
- * - `"claude"` means nodes whose slug is `"claude"` or under `"claude/"`
42
+ * - `"claude"` means nodes owned by `"claude"` per `resolveCategoryOwner`
43
+ * (`claude`, `claude/…`, and dash satellites such as `claude-md`)
32
44
  * - `undefined` means all nodes
33
45
  *
34
46
  * Parameterized version of the host's `getNavSubtree()` — receives the
@@ -10,31 +10,36 @@ function getCategoryOrder(headerNav) {
10
10
  return matches;
11
11
  });
12
12
  }
13
- function getNavSectionForSlug(slug, headerNav) {
13
+ function resolveCategoryOwner(slug, explicitMatches) {
14
14
  const topCategory = slug.split("/")[0] ?? "";
15
- const all = getCategoryOrder(headerNav);
16
- const explicitMatch = all.find((cm) => cm !== "!" && topCategory === cm);
15
+ let owner;
16
+ for (const cm of explicitMatches) {
17
+ if (cm === "!" || !cm) continue;
18
+ if (topCategory !== cm && !topCategory.startsWith(cm + "-")) continue;
19
+ if (owner === void 0 || cm.length > owner.length) owner = cm;
20
+ }
21
+ return owner;
22
+ }
23
+ function getNavSectionForSlug(slug, headerNav) {
24
+ const explicitMatch = resolveCategoryOwner(slug, getCategoryOrder(headerNav));
17
25
  if (explicitMatch !== void 0) return explicitMatch;
18
26
  const defaultItem = headerNav.find(
19
27
  (item) => item.categoryMatch === "!"
20
28
  );
21
29
  return defaultItem?.categoryMatch;
22
30
  }
23
- function matchesCategory(slug, match) {
24
- return slug === match || slug.startsWith(match + "/");
25
- }
26
31
  function getNavSubtree(tree, categoryMatch, headerNav) {
27
32
  if (!categoryMatch) return tree;
33
+ const explicitMatches = getCategoryOrder(headerNav);
28
34
  if (categoryMatch === "!") {
29
- const explicitPrefixes = getCategoryOrder(headerNav).filter((cm) => cm !== "!");
30
- return tree.filter(
31
- (node) => !explicitPrefixes.some((prefix) => matchesCategory(node.slug, prefix))
32
- );
35
+ return tree.filter((node) => resolveCategoryOwner(node.slug, explicitMatches) === void 0);
33
36
  }
34
- return tree.filter((node) => matchesCategory(node.slug, categoryMatch));
37
+ const candidates = explicitMatches.includes(categoryMatch) ? explicitMatches : [...explicitMatches, categoryMatch];
38
+ return tree.filter((node) => resolveCategoryOwner(node.slug, candidates) === categoryMatch);
35
39
  }
36
40
  export {
37
41
  getCategoryOrder,
38
42
  getNavSectionForSlug,
39
- getNavSubtree
43
+ getNavSubtree,
44
+ resolveCategoryOwner
40
45
  };
@@ -1,3 +1,4 @@
1
+ import { resolveCategoryOwner } from "../nav-scope/index.js";
1
2
  function findNode(tree, slug) {
2
3
  for (const node of tree) {
3
4
  if (node.slug === slug) return node;
@@ -65,17 +66,13 @@ function resolveItem(item, tree, lang) {
65
66
  }
66
67
  }
67
68
  }
68
- function matchesCategory(slug, match) {
69
- return slug === match || slug.startsWith(match + "/");
70
- }
71
69
  function filterByCategory(tree, categoryMatch, explicitPrefixes) {
72
70
  if (!categoryMatch) return tree;
73
71
  if (categoryMatch === "!") {
74
- return tree.filter(
75
- (node) => !explicitPrefixes.some((prefix) => matchesCategory(node.slug, prefix))
76
- );
72
+ return tree.filter((node) => resolveCategoryOwner(node.slug, explicitPrefixes) === void 0);
77
73
  }
78
- return tree.filter((node) => matchesCategory(node.slug, categoryMatch));
74
+ const candidates = explicitPrefixes.includes(categoryMatch) ? explicitPrefixes : [...explicitPrefixes, categoryMatch];
75
+ return tree.filter((node) => resolveCategoryOwner(node.slug, candidates) === categoryMatch);
79
76
  }
80
77
  function buildSidebarForSection(docs, lang, categoryMatch, categoryMeta, sidebars, buildNavTree, explicitCategoryPrefixes) {
81
78
  const tree = buildNavTree(docs, lang, categoryMeta);
@@ -1,5 +1,6 @@
1
1
  import { buildSidebarTree } from "../sidebar-tree/build-tree.js";
2
2
  import { toRouteSlug } from "../slug/index.js";
3
+ import { resolveCategoryOwner } from "../nav-scope/index.js";
3
4
  function isNavVisible(doc) {
4
5
  return !doc.data.unlisted && !doc.data.standalone;
5
6
  }
@@ -88,7 +89,7 @@ function groupSatelliteNodes(tree, prefixes) {
88
89
  const satelliteIdxs = [];
89
90
  for (let i = 0; i < result.length; i++) {
90
91
  const node = result[i];
91
- if (node && i !== primaryIdx && node.slug.startsWith(`${prefix}-`)) {
92
+ if (node && i !== primaryIdx && node.slug.startsWith(`${prefix}-`) && resolveCategoryOwner(node.slug, prefixes) === prefix) {
92
93
  satelliteIdxs.push(i);
93
94
  }
94
95
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takazudo/zudo-doc",
3
- "version": "9.1.0",
3
+ "version": "9.1.2",
4
4
  "type": "module",
5
5
  "description": "zudo-doc framework primitives layer that sits on top of zfb's engine — sidebar, theme, TOC, breadcrumb, layouts, head injection, View Transitions, SSR-skip wrappers (per ADR-003).",
6
6
  "license": "MIT",
@@ -753,9 +753,9 @@
753
753
  "peerDependencies": {
754
754
  "@modelcontextprotocol/sdk": "1.32.2",
755
755
  "@takazudo/zdtp": "^0.5.2 || ^0.6.0 || ^0.7.0 || ^0.8.0 || ^0.9.0",
756
- "@takazudo/zfb": "^5.1.5",
757
- "@takazudo/zfb-md-wasm": "^5.1.5",
758
- "@takazudo/zfb-runtime": "^5.1.5",
756
+ "@takazudo/zfb": "^5.2.0",
757
+ "@takazudo/zfb-md-wasm": "^5.2.0",
758
+ "@takazudo/zfb-runtime": "^5.2.0",
759
759
  "@takazudo/zudo-doc-history-server": "^9.0.0",
760
760
  "diff": "^8.0.0",
761
761
  "katex": "^0.18.2 || ^0.19.0",
@@ -796,9 +796,9 @@
796
796
  "devDependencies": {
797
797
  "@modelcontextprotocol/sdk": "1.32.2",
798
798
  "@takazudo/mdx-formatter": "1.3.0",
799
- "@takazudo/zfb": "5.1.5",
800
- "@takazudo/zfb-md-wasm": "5.1.5",
801
- "@takazudo/zfb-runtime": "5.1.5",
799
+ "@takazudo/zfb": "5.2.0",
800
+ "@takazudo/zfb-md-wasm": "5.2.0",
801
+ "@takazudo/zfb-runtime": "5.2.0",
802
802
  "@types/fs-extra": "^11.0.4",
803
803
  "@types/minimist": "^1.2.5",
804
804
  "@types/node": "^25.9.9",
@@ -809,7 +809,7 @@
809
809
  "typescript": "^5.0.0",
810
810
  "vitest": "^4.1.12",
811
811
  "zod": "^4.6.7",
812
- "@takazudo/zudo-doc-history-server": "9.1.0"
812
+ "@takazudo/zudo-doc-history-server": "9.1.2"
813
813
  },
814
814
  "scripts": {
815
815
  "gen:search-widget-script": "node scripts/gen-search-widget-script.mjs",