starlight-cannoli-plugins 0.1.0 → 1.0.0
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.
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
// src/plugins/starlight-index-only-sidebar.ts
|
|
2
|
+
import { join as join2 } from "path";
|
|
3
|
+
|
|
4
|
+
// src/plugins/utils/sidebar-builder-utils.ts
|
|
5
|
+
import * as fs from "fs";
|
|
6
|
+
import * as path from "path";
|
|
7
|
+
import { parse as parseYaml } from "yaml";
|
|
8
|
+
function isDir(filePath) {
|
|
9
|
+
try {
|
|
10
|
+
return fs.statSync(filePath).isDirectory();
|
|
11
|
+
} catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function findIndexMd(dirPath) {
|
|
16
|
+
const indexMd = path.join(dirPath, "index.md");
|
|
17
|
+
const indexMdx = path.join(dirPath, "index.mdx");
|
|
18
|
+
try {
|
|
19
|
+
if (fs.statSync(indexMd).isFile()) return indexMd;
|
|
20
|
+
if (fs.statSync(indexMdx).isFile()) return indexMdx;
|
|
21
|
+
} catch {
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
function parseFrontmatter(filePath) {
|
|
26
|
+
try {
|
|
27
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
28
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
29
|
+
if (!match) return {};
|
|
30
|
+
const frontmatter = parseYaml(match[1]);
|
|
31
|
+
return typeof frontmatter === "object" && frontmatter ? frontmatter : {};
|
|
32
|
+
} catch {
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function getSlug(dirPath, rootDir) {
|
|
37
|
+
const normalized = path.normalize(dirPath).replace(/\\/g, "/");
|
|
38
|
+
const rootParent = path.normalize(path.dirname(rootDir)).replace(/\\/g, "/");
|
|
39
|
+
const slug = normalized.startsWith(rootParent) ? normalized.slice(rootParent.length + 1) : normalized;
|
|
40
|
+
return slug + "/index";
|
|
41
|
+
}
|
|
42
|
+
function hasIndexMdInSubtree(dirPath) {
|
|
43
|
+
const indexFile = findIndexMd(dirPath);
|
|
44
|
+
if (indexFile) {
|
|
45
|
+
const fm = parseFrontmatter(indexFile);
|
|
46
|
+
if (fm.draft || fm.sidebar?.hidden) return false;
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const entries = fs.readdirSync(dirPath);
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
if (entry === "assets") continue;
|
|
53
|
+
const fullPath = path.join(dirPath, entry);
|
|
54
|
+
if (isDir(fullPath) && hasIndexMdInSubtree(fullPath)) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
} catch {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
function isGroupItem(item) {
|
|
64
|
+
return "items" in item;
|
|
65
|
+
}
|
|
66
|
+
function pathSegmentToLabel(pathSegment) {
|
|
67
|
+
let label = pathSegment.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
68
|
+
const match = label.match(/^([a-z]+) [0-9]{2,}/i);
|
|
69
|
+
if (match) {
|
|
70
|
+
const firstGroup = match[1];
|
|
71
|
+
const uppercasedFirstGroup = firstGroup.toUpperCase();
|
|
72
|
+
label = uppercasedFirstGroup + label.substring(firstGroup.length);
|
|
73
|
+
}
|
|
74
|
+
return label;
|
|
75
|
+
}
|
|
76
|
+
function buildSidebarItems(dirPath, rootDir, currentDepth, maxDepth, dirnameDeterminesLabels, parentDirName = "") {
|
|
77
|
+
const items = [];
|
|
78
|
+
const indexFile = findIndexMd(dirPath);
|
|
79
|
+
if (indexFile) {
|
|
80
|
+
const fm = parseFrontmatter(indexFile);
|
|
81
|
+
if (!fm.draft && !fm.sidebar?.hidden) {
|
|
82
|
+
let label;
|
|
83
|
+
if (currentDepth >= maxDepth && parentDirName) {
|
|
84
|
+
label = parentDirName;
|
|
85
|
+
} else if (dirnameDeterminesLabels) {
|
|
86
|
+
label = "Overview";
|
|
87
|
+
} else {
|
|
88
|
+
label = fm.title || "Overview";
|
|
89
|
+
}
|
|
90
|
+
items.push({
|
|
91
|
+
label,
|
|
92
|
+
slug: getSlug(dirPath, rootDir)
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (currentDepth >= maxDepth) {
|
|
97
|
+
const flattenedItems = flattenIndexFilesAtDepth(
|
|
98
|
+
dirPath,
|
|
99
|
+
rootDir,
|
|
100
|
+
dirnameDeterminesLabels
|
|
101
|
+
);
|
|
102
|
+
items.push(...flattenedItems);
|
|
103
|
+
return items;
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const entries = fs.readdirSync(dirPath).sort();
|
|
107
|
+
for (const entry of entries) {
|
|
108
|
+
if (entry === "assets") continue;
|
|
109
|
+
const fullPath = path.join(dirPath, entry);
|
|
110
|
+
if (!isDir(fullPath)) continue;
|
|
111
|
+
if (!hasIndexMdInSubtree(fullPath)) continue;
|
|
112
|
+
const subItems = buildSidebarItems(
|
|
113
|
+
fullPath,
|
|
114
|
+
rootDir,
|
|
115
|
+
currentDepth + 1,
|
|
116
|
+
maxDepth,
|
|
117
|
+
dirnameDeterminesLabels,
|
|
118
|
+
entry
|
|
119
|
+
);
|
|
120
|
+
const hasIndex = findIndexMd(fullPath) !== null;
|
|
121
|
+
if (!hasIndex) {
|
|
122
|
+
const allGroups = subItems.length > 0 && subItems.every(isGroupItem);
|
|
123
|
+
if (allGroups || subItems.length === 1 && isGroupItem(subItems[0])) {
|
|
124
|
+
items.push(...subItems);
|
|
125
|
+
} else {
|
|
126
|
+
items.push({
|
|
127
|
+
label: pathSegmentToLabel(entry),
|
|
128
|
+
items: subItems
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
items.push({
|
|
133
|
+
label: pathSegmentToLabel(entry),
|
|
134
|
+
items: subItems
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} catch {
|
|
139
|
+
}
|
|
140
|
+
return items;
|
|
141
|
+
}
|
|
142
|
+
function flattenIndexFilesAtDepth(dirPath, rootDir, dirnameDeterminesLabels) {
|
|
143
|
+
const items = [];
|
|
144
|
+
try {
|
|
145
|
+
const entries = fs.readdirSync(dirPath);
|
|
146
|
+
for (const entry of entries) {
|
|
147
|
+
if (entry === "assets") continue;
|
|
148
|
+
const fullPath = path.join(dirPath, entry);
|
|
149
|
+
if (!isDir(fullPath)) continue;
|
|
150
|
+
const indexFile = findIndexMd(fullPath);
|
|
151
|
+
if (indexFile) {
|
|
152
|
+
const fm = parseFrontmatter(indexFile);
|
|
153
|
+
if (!fm.draft && !fm.sidebar?.hidden) {
|
|
154
|
+
items.push({
|
|
155
|
+
label: pathSegmentToLabel(entry),
|
|
156
|
+
slug: getSlug(fullPath, rootDir)
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
items.push(
|
|
161
|
+
...flattenIndexFilesAtDepth(fullPath, rootDir, dirnameDeterminesLabels)
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
} catch {
|
|
165
|
+
}
|
|
166
|
+
return items;
|
|
167
|
+
}
|
|
168
|
+
function getIndexMdSidebarItems(directory, options = {}) {
|
|
169
|
+
const maxDepth = options.maxDepthNesting ?? 100;
|
|
170
|
+
const dirnameDeterminesLabels = options.dirnameDeterminesLabels ?? true;
|
|
171
|
+
const rootDirName = pathSegmentToLabel(path.basename(directory));
|
|
172
|
+
const items = buildSidebarItems(
|
|
173
|
+
directory,
|
|
174
|
+
directory,
|
|
175
|
+
0,
|
|
176
|
+
maxDepth,
|
|
177
|
+
dirnameDeterminesLabels
|
|
178
|
+
);
|
|
179
|
+
return [
|
|
180
|
+
{
|
|
181
|
+
label: rootDirName,
|
|
182
|
+
items
|
|
183
|
+
}
|
|
184
|
+
];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/plugins/starlight-index-only-sidebar.ts
|
|
188
|
+
var SITE_DOCS_ROOT = "./src/content/docs";
|
|
189
|
+
function normalizeSlug(slug) {
|
|
190
|
+
return slug.endsWith("/index") ? slug.slice(0, -6) : slug;
|
|
191
|
+
}
|
|
192
|
+
function normalizeItems(items) {
|
|
193
|
+
return items.map((item) => {
|
|
194
|
+
if ("items" in item) {
|
|
195
|
+
return {
|
|
196
|
+
label: item.label,
|
|
197
|
+
items: normalizeItems(item.items)
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
if ("slug" in item) {
|
|
201
|
+
return {
|
|
202
|
+
label: item.label,
|
|
203
|
+
slug: normalizeSlug(item.slug)
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return item;
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
function starlightIndexOnlySidebar(pluginOptions) {
|
|
210
|
+
return {
|
|
211
|
+
name: "index-only-sidebar",
|
|
212
|
+
hooks: {
|
|
213
|
+
"config:setup": (hookOptions) => {
|
|
214
|
+
const { updateConfig } = hookOptions;
|
|
215
|
+
const { directories, maxDepthNesting, dirnameDeterminesLabels } = pluginOptions;
|
|
216
|
+
const functionOptions = {
|
|
217
|
+
maxDepthNesting,
|
|
218
|
+
dirnameDeterminesLabels
|
|
219
|
+
};
|
|
220
|
+
const sidebarItems = directories.map((directory) => {
|
|
221
|
+
const dirPath = join2(SITE_DOCS_ROOT, directory);
|
|
222
|
+
const rawItems = getIndexMdSidebarItems(dirPath, functionOptions);
|
|
223
|
+
const rootGroup = rawItems[0];
|
|
224
|
+
if (!rootGroup || !("items" in rootGroup)) {
|
|
225
|
+
return void 0;
|
|
226
|
+
}
|
|
227
|
+
const items = rootGroup.items || [];
|
|
228
|
+
const normalizedItems = normalizeItems(items);
|
|
229
|
+
return {
|
|
230
|
+
label: rootGroup.label,
|
|
231
|
+
items: normalizedItems
|
|
232
|
+
};
|
|
233
|
+
}).filter(
|
|
234
|
+
(group) => group !== void 0 && group.items.length > 0
|
|
235
|
+
);
|
|
236
|
+
updateConfig({
|
|
237
|
+
sidebar: sidebarItems
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export {
|
|
245
|
+
starlightIndexOnlySidebar
|
|
246
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { HookParameters } from '@astrojs/starlight/types';
|
|
2
2
|
|
|
3
|
-
type
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
type TOptions = {
|
|
4
|
+
maxDepthNesting?: number;
|
|
5
|
+
dirnameDeterminesLabels?: boolean;
|
|
6
6
|
};
|
|
7
|
-
type TIndexOnlySidebarPluginOptions = {
|
|
8
|
-
directories:
|
|
9
|
-
dirnameDeterminesLabel?: boolean;
|
|
7
|
+
type TIndexOnlySidebarPluginOptions = TOptions & {
|
|
8
|
+
directories: string[];
|
|
10
9
|
};
|
|
11
|
-
declare function starlightIndexOnlySidebar(
|
|
10
|
+
declare function starlightIndexOnlySidebar(pluginOptions: TIndexOnlySidebarPluginOptions): {
|
|
12
11
|
name: string;
|
|
13
12
|
hooks: {
|
|
14
13
|
"config:setup": (hookOptions: HookParameters<"config:setup">) => void;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "starlight-cannoli-plugins",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "1.0.0",
|
|
5
5
|
"description": "Starlight plugins for automatic sidebar generation and link validation",
|
|
6
6
|
"license": "ISC",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -36,13 +36,16 @@
|
|
|
36
36
|
"url": "https://github.com/OccasionalCoderByTrade/astro-starlight-plugins"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"prepublishOnly": "npm run build
|
|
39
|
+
"app:dev": "node scripts/sync-docs-to-public.js && rm -rf .astro/ && astro dev --port 5600",
|
|
40
|
+
"app:build": "rm -rf .astro/ && node scripts/sync-docs-to-public.js && astro build",
|
|
41
|
+
"app:preview": "astro build && astro preview --port 5600",
|
|
42
|
+
"app:help": "astro --help",
|
|
43
|
+
"app:check": "astro check",
|
|
44
|
+
"lib:build": "tsup",
|
|
45
|
+
"prepublishOnly": "npm run lib:build",
|
|
46
|
+
"tree:index": "tree -P index.md src/content/docs",
|
|
47
|
+
"tree:depth": "bash scripts/tree-depth.sh",
|
|
48
|
+
"clean:empty-dirs": "find src/content/docs -type d -empty -delete"
|
|
46
49
|
},
|
|
47
50
|
"dependencies": {
|
|
48
51
|
"glob": "^13.0.6",
|
|
@@ -64,29 +67,31 @@
|
|
|
64
67
|
"devDependencies": {
|
|
65
68
|
"@astrojs/check": "^0.9.6",
|
|
66
69
|
"@astrojs/starlight": "^0.37.6",
|
|
70
|
+
"@eslint/js": "^10.0.1",
|
|
71
|
+
"@eslint/markdown": "^7.5.1",
|
|
67
72
|
"@expressive-code/plugin-line-numbers": "^0.41.7",
|
|
68
73
|
"@hpcc-js/wasm": "^2.33.1",
|
|
74
|
+
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
|
69
75
|
"@types/hast": "^2.3.10",
|
|
76
|
+
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
|
77
|
+
"@typescript-eslint/parser": "^8.56.1",
|
|
70
78
|
"astro": "^5.6.1",
|
|
79
|
+
"eslint": "^10.0.2",
|
|
80
|
+
"eslint-md-cannoli-plugins": "^1.0.2",
|
|
81
|
+
"globals": "^17.4.0",
|
|
71
82
|
"hast": "^1.0.0",
|
|
83
|
+
"jiti": "^2.6.1",
|
|
84
|
+
"lodash": "^4.17.23",
|
|
72
85
|
"rehype-graphviz": "^0.3.0",
|
|
73
86
|
"rehype-mathjax": "^7.1.0",
|
|
74
87
|
"rehype-raw": "^7.0.0",
|
|
75
88
|
"remark-math": "^6.0.0",
|
|
89
|
+
"sass-embedded": "^1.97.3",
|
|
76
90
|
"sharp": "^0.34.2",
|
|
77
91
|
"tsup": "^8.3.0",
|
|
92
|
+
"tsx": "^4.21.0",
|
|
78
93
|
"typescript": "^5.9.3",
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"@eslint/markdown": "^7.5.1",
|
|
82
|
-
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
|
83
|
-
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
|
84
|
-
"@typescript-eslint/parser": "^8.56.1",
|
|
85
|
-
"eslint": "^10.0.2",
|
|
86
|
-
"eslint-md-cannoli-plugins": "^1.0.2",
|
|
87
|
-
"globals": "^17.4.0",
|
|
88
|
-
"jiti": "^2.6.1",
|
|
89
|
-
"sass-embedded": "^1.97.3",
|
|
90
|
-
"typescript-eslint": "^8.56.1"
|
|
94
|
+
"typescript-eslint": "^8.56.1",
|
|
95
|
+
"vfile": "^6.0.0"
|
|
91
96
|
}
|
|
92
97
|
}
|
package/dist/chunk-6XXMT37V.js
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
// src/plugins/starlight-index-only-sidebar.ts
|
|
2
|
-
import { readFileSync, readdirSync, statSync } from "fs";
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
import { parse as parseYaml } from "yaml";
|
|
5
|
-
var SITE_DOCS_ROOT = "./src/content/docs";
|
|
6
|
-
function getFrontmatterMetadata(mdFilePath) {
|
|
7
|
-
const defaultMetadata = {
|
|
8
|
-
title: null,
|
|
9
|
-
draft: false,
|
|
10
|
-
sidebarHidden: false
|
|
11
|
-
};
|
|
12
|
-
try {
|
|
13
|
-
const content = readFileSync(mdFilePath, "utf-8");
|
|
14
|
-
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
15
|
-
if (!match) return defaultMetadata;
|
|
16
|
-
const frontmatterText = match[1];
|
|
17
|
-
const frontmatter = parseYaml(frontmatterText);
|
|
18
|
-
if (!frontmatter || typeof frontmatter !== "object") {
|
|
19
|
-
return defaultMetadata;
|
|
20
|
-
}
|
|
21
|
-
const title = typeof frontmatter.title === "string" ? frontmatter.title : null;
|
|
22
|
-
const draft = frontmatter.draft === true;
|
|
23
|
-
let sidebarHidden = false;
|
|
24
|
-
if (frontmatter.sidebar) {
|
|
25
|
-
if (typeof frontmatter.sidebar === "object" && frontmatter.sidebar !== null) {
|
|
26
|
-
sidebarHidden = frontmatter.sidebar.hidden === true;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return {
|
|
30
|
-
title,
|
|
31
|
-
draft,
|
|
32
|
-
sidebarHidden
|
|
33
|
-
};
|
|
34
|
-
} catch {
|
|
35
|
-
return defaultMetadata;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
function pathSegmentToLabel(pathSegment) {
|
|
39
|
-
let label = pathSegment.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
40
|
-
const match = label.match(/^([a-z]+) [0-9]{2,}/i);
|
|
41
|
-
if (match) {
|
|
42
|
-
const firstGroup = match[1];
|
|
43
|
-
const uppercasedFirstGroup = firstGroup.toUpperCase();
|
|
44
|
-
label = uppercasedFirstGroup + label.substring(firstGroup.length);
|
|
45
|
-
}
|
|
46
|
-
return label;
|
|
47
|
-
}
|
|
48
|
-
function processRootIndex(dir, basePath, dirDeterminesLabel, items) {
|
|
49
|
-
if (!basePath || basePath.includes("/")) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
const indexPath = join(dir, "index.md");
|
|
53
|
-
try {
|
|
54
|
-
statSync(indexPath);
|
|
55
|
-
} catch {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
const metadata = getFrontmatterMetadata(indexPath);
|
|
59
|
-
if (metadata.draft || metadata.sidebarHidden) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
if (dirDeterminesLabel) {
|
|
63
|
-
const lastSegment = basePath.split("/").pop() || basePath;
|
|
64
|
-
items.push({
|
|
65
|
-
label: pathSegmentToLabel(lastSegment),
|
|
66
|
-
slug: basePath
|
|
67
|
-
});
|
|
68
|
-
} else {
|
|
69
|
-
items.push(basePath);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function buildIndexSidebar(dir, basePath = "", docsRoot, dirDeterminesLabel = false) {
|
|
73
|
-
const items = [];
|
|
74
|
-
try {
|
|
75
|
-
processRootIndex(dir, basePath, dirDeterminesLabel, items);
|
|
76
|
-
const entries = readdirSync(dir).sort();
|
|
77
|
-
for (const entry of entries) {
|
|
78
|
-
if (entry.startsWith(".")) continue;
|
|
79
|
-
const fullPath = join(dir, entry);
|
|
80
|
-
const stat = statSync(fullPath);
|
|
81
|
-
if (stat.isDirectory()) {
|
|
82
|
-
const indexPath = join(fullPath, "index.md");
|
|
83
|
-
const slug = basePath ? `${basePath}/${entry}` : entry;
|
|
84
|
-
try {
|
|
85
|
-
statSync(indexPath);
|
|
86
|
-
const metadata = getFrontmatterMetadata(indexPath);
|
|
87
|
-
if (metadata.draft || metadata.sidebarHidden) {
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
const subItems = buildIndexSidebar(fullPath, slug, docsRoot, dirDeterminesLabel);
|
|
91
|
-
if (subItems.length > 0) {
|
|
92
|
-
let groupLabel;
|
|
93
|
-
if (dirDeterminesLabel) {
|
|
94
|
-
groupLabel = pathSegmentToLabel(entry);
|
|
95
|
-
} else {
|
|
96
|
-
const title = metadata.title || entry;
|
|
97
|
-
groupLabel = title;
|
|
98
|
-
}
|
|
99
|
-
items.push({
|
|
100
|
-
label: groupLabel,
|
|
101
|
-
items: [dirDeterminesLabel ? { label: groupLabel, slug } : slug, ...subItems]
|
|
102
|
-
});
|
|
103
|
-
} else {
|
|
104
|
-
if (dirDeterminesLabel) {
|
|
105
|
-
items.push({
|
|
106
|
-
label: pathSegmentToLabel(entry),
|
|
107
|
-
slug
|
|
108
|
-
});
|
|
109
|
-
} else {
|
|
110
|
-
items.push(slug);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
} catch {
|
|
114
|
-
const subItems = buildIndexSidebar(fullPath, slug, docsRoot, dirDeterminesLabel);
|
|
115
|
-
if (subItems.length > 0) {
|
|
116
|
-
items.push(...subItems);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
} catch (error) {
|
|
122
|
-
console.error(`Error reading directory ${dir}:`, error);
|
|
123
|
-
}
|
|
124
|
-
return items.sort((a, b) => {
|
|
125
|
-
const aIsGroup = typeof a === "object" && "items" in a;
|
|
126
|
-
const bIsGroup = typeof b === "object" && "items" in b;
|
|
127
|
-
if (!aIsGroup && bIsGroup) return -1;
|
|
128
|
-
if (aIsGroup && !bIsGroup) return 1;
|
|
129
|
-
return 0;
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
function starlightIndexOnlySidebar(options) {
|
|
133
|
-
return {
|
|
134
|
-
name: "index-only-sidebar",
|
|
135
|
-
hooks: {
|
|
136
|
-
"config:setup": (hookOptions) => {
|
|
137
|
-
const { updateConfig } = hookOptions;
|
|
138
|
-
const dirnameDeterminesLabel = options.dirnameDeterminesLabel ?? false;
|
|
139
|
-
const sidebarItems = options.directories.map((dirConfig) => {
|
|
140
|
-
const dirItems = buildIndexSidebar(
|
|
141
|
-
join(SITE_DOCS_ROOT, dirConfig.directory),
|
|
142
|
-
dirConfig.directory,
|
|
143
|
-
SITE_DOCS_ROOT,
|
|
144
|
-
dirnameDeterminesLabel
|
|
145
|
-
);
|
|
146
|
-
const label = dirnameDeterminesLabel ? pathSegmentToLabel(dirConfig.directory) : dirConfig.label;
|
|
147
|
-
return {
|
|
148
|
-
label,
|
|
149
|
-
items: dirItems
|
|
150
|
-
};
|
|
151
|
-
}).filter((group) => group.items.length > 0);
|
|
152
|
-
updateConfig({
|
|
153
|
-
sidebar: sidebarItems
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export {
|
|
161
|
-
starlightIndexOnlySidebar
|
|
162
|
-
};
|