@takazudo/zudo-doc 9.1.0 → 9.1.1
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,12 @@ 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.1] - 2026-10-30
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
- `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)
|
|
16
|
+
|
|
11
17
|
## [9.1.0] - 2026-10-28
|
|
12
18
|
|
|
13
19
|
### Features
|
|
@@ -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
|
|
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
|
|
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
|
package/dist/nav-scope/index.js
CHANGED
|
@@ -10,31 +10,36 @@ function getCategoryOrder(headerNav) {
|
|
|
10
10
|
return matches;
|
|
11
11
|
});
|
|
12
12
|
}
|
|
13
|
-
function
|
|
13
|
+
function resolveCategoryOwner(slug, explicitMatches) {
|
|
14
14
|
const topCategory = slug.split("/")[0] ?? "";
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
3
|
+
"version": "9.1.1",
|
|
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",
|
|
@@ -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.
|
|
812
|
+
"@takazudo/zudo-doc-history-server": "9.1.1"
|
|
813
813
|
},
|
|
814
814
|
"scripts": {
|
|
815
815
|
"gen:search-widget-script": "node scripts/gen-search-widget-script.mjs",
|