-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathgenerate-sidebar.js
More file actions
209 lines (169 loc) · 6.12 KB
/
Copy pathgenerate-sidebar.js
File metadata and controls
209 lines (169 loc) · 6.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/**
* Generate Docusaurus sidebar from SUMMARY.md
* This script parses docs/SUMMARY.md and creates a sidebar structure
*/
const fs = require('fs');
const path = require('path');
function parseSummaryMd(filePath) {
const content = fs.readFileSync(filePath, 'utf-8');
const lines = content.split(/\r?\n/); // Handle both \n and \r\n
const sidebar = [];
const stack = [{ items: sidebar, level: -1 }];
// Helper function to check if a line item has subitems
function hasSubitems(currentIndex, currentLevel) {
for (let j = currentIndex + 1; j < lines.length; j++) {
const nextLine = lines[j];
const nextLineTrimmed = nextLine.trim();
// Skip empty lines
if (!nextLineTrimmed) continue;
// Stop at section headers
if (nextLineTrimmed.match(/^##\s+/)) return false;
const nextIndent = nextLine.match(/^(\s*)/)[1].length;
const nextLevel = Math.floor(nextIndent / 2) + 1;
// If next item is at a deeper level, this item has subitems
if (nextLevel > currentLevel) return true;
// If next item is at the same or shallower level, no subitems
if (nextLevel <= currentLevel) return false;
}
return false;
}
for (let i = 0; i < lines.length; i++) {
let line = lines[i].trim(); // Trim to remove any trailing whitespace
// Skip empty lines and the title
if (!line || line.startsWith('# ')) continue;
// Check if it's a section header (## Something)
const headerMatch = line.match(/^##\s+(.+)$/);
if (headerMatch) {
const label = headerMatch[1].trim();
const sectionCategory = {
type: 'category',
label: label,
items: [],
collapsible: false,
className: 'sidebar-section-header',
};
sidebar.push(sectionCategory);
stack.length = 1; // Reset stack to root
stack.push({ items: sectionCategory.items, level: 0 });
continue;
}
// Get original line with indentation for level calculation
const originalLine = lines[i];
const indent = originalLine.match(/^(\s*)/)[1].length;
// Level 0 = root items (under section headers)
// Level 1 = first level of nesting, etc.
const level = Math.floor(indent / 2) + 1; // +1 because section headers are level 0
// Check if it's a folder marker (📁Folder Name)
const folderMatch = line.match(/^-\s+(📁.+)$/);
if (folderMatch) {
const label = folderMatch[1].trim(); // Keep the emoji in the label
const category = {
type: 'category',
label: label,
items: [],
collapsed: true,
};
// Find the right parent
while (stack.length > level && stack[stack.length - 1].level >= level) {
stack.pop();
}
const parent = stack[stack.length - 1];
if (parent.items) {
parent.items.push(category);
}
stack.push({ items: category.items, level: level });
continue;
}
// Check if it's a link ([Label](path.md))
const linkMatch = line.match(/^-\s+\[(.+?)\]\((.+?)\)$/);
if (linkMatch) {
const label = linkMatch[1];
let docPath = linkMatch[2];
// Convert path to Docusaurus doc ID
// Remove .md extension
docPath = docPath.replace(/\.md$/, '');
// Keep README as-is (both root and folder READMEs)
// Docusaurus will use the document ID based on the file name
// Check if this link has subitems - if so, create a category
if (hasSubitems(i, level)) {
const category = {
type: 'category',
label: label,
link: {
type: 'doc',
id: docPath,
},
items: [],
collapsed: true,
};
// Find the right parent
while (stack.length > level && stack[stack.length - 1].level >= level) {
stack.pop();
}
const parent = stack[stack.length - 1];
if (parent.items) {
parent.items.push(category);
}
stack.push({ items: category.items, level: level });
} else {
// No subitems, create a regular doc item
const docItem = {
type: 'doc',
id: docPath,
label: label,
};
// Find the right parent
while (stack.length > level && stack[stack.length - 1].level >= level) {
stack.pop();
}
const parent = stack[stack.length - 1];
if (parent.items) {
parent.items.push(docItem);
}
}
}
}
return sidebar;
}
function generateSidebarsJs(sidebar) {
// Convert sidebar to JSON string while preserving Unicode characters (emojis)
const sidebarJson = JSON.stringify(sidebar, null, 2)
.replace(/\\u[\dA-F]{4}/gi, (match) => {
return String.fromCharCode(parseInt(match.replace(/\\u/g, ''), 16));
});
const sidebarCode = `/**
* Creating a sidebar enables you to:
- create an ordered group of docs
- render a sidebar for each doc of that group
- provide next/previous navigation
The sidebars can be generated from the filesystem, or explicitly defined here.
Create as many sidebars as you want.
This file is auto-generated from docs/SUMMARY.md
Run 'node generate-sidebar.js' to regenerate
*/
// @ts-check
/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
const sidebars = {
tutorialSidebar: ${sidebarJson},
};
module.exports = sidebars;
`;
return sidebarCode;
}
// Main execution
try {
const summaryPath = path.join(__dirname, 'docs', 'SUMMARY.md');
const sidebarPath = path.join(__dirname, 'sidebars.js');
console.log('Parsing SUMMARY.md...');
const sidebar = parseSummaryMd(summaryPath);
console.log('Generating sidebars.js...');
console.log('Sidebar structure:', JSON.stringify(sidebar, null, 2).substring(0, 500));
const sidebarCode = generateSidebarsJs(sidebar);
fs.writeFileSync(sidebarPath, sidebarCode, 'utf-8');
console.log(`Wrote ${sidebarCode.length} bytes to ${sidebarPath}`);
console.log('✅ Successfully generated sidebars.js from SUMMARY.md');
console.log(` Found ${sidebar.length} top-level items`);
} catch (error) {
console.error('❌ Error generating sidebar:', error.message);
process.exit(1);
}