@openpkg-ts/doc-generator 0.6.2 → 0.6.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/dist/cli.js DELETED
@@ -1,387 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- __require,
4
- __toESM,
5
- createDocs,
6
- exportToMarkdown,
7
- toDocusaurusSidebarJS,
8
- toFumadocsMetaJSON,
9
- toHTML,
10
- toJSONString,
11
- toNavigation,
12
- toPagefindRecords
13
- } from "./shared/server-4yabn81t.js";
14
-
15
- // src/cli.ts
16
- import { readFileSync } from "node:fs";
17
- import * as path4 from "node:path";
18
- import { fileURLToPath } from "node:url";
19
- import { Command } from "commander";
20
-
21
- // src/cli/build.ts
22
- import { exec } from "node:child_process";
23
- import * as fs from "node:fs";
24
- import * as path from "node:path";
25
- import { promisify } from "node:util";
26
- var execAsync = promisify(exec);
27
- function registerBuildCommand(program) {
28
- program.command("build <spec>").description("Build static HTML documentation site").option("-o, --out <dir>", "Output directory", "./api-docs").option("-t, --title <title>", "Site title override").option("--no-search", "Disable Pagefind search indexing").option("--verbose", "Verbose output").action(async (specPath, options) => {
29
- try {
30
- const resolvedSpec = path.resolve(specPath);
31
- if (!fs.existsSync(resolvedSpec)) {
32
- console.error(`Error: Spec file not found: ${resolvedSpec}`);
33
- process.exit(1);
34
- }
35
- const docs = createDocs(resolvedSpec);
36
- const outDir = path.resolve(options.out);
37
- const exports = docs.getAllExports();
38
- if (options.verbose) {
39
- console.log(`Spec: ${resolvedSpec}`);
40
- console.log(`Output: ${outDir}`);
41
- console.log(`Exports: ${exports.length}`);
42
- }
43
- fs.mkdirSync(outDir, { recursive: true });
44
- console.log("Generating HTML...");
45
- const indexHtml = toHTML(docs.spec, {
46
- title: options.title,
47
- includeStyles: true,
48
- fullDocument: true
49
- });
50
- fs.writeFileSync(path.join(outDir, "index.html"), indexHtml);
51
- const pagesDir = path.join(outDir, "api");
52
- fs.mkdirSync(pagesDir, { recursive: true });
53
- for (const exp of exports) {
54
- const exportHtml = toHTML(docs.spec, {
55
- export: exp.name,
56
- title: options.title ? `${exp.name} | ${options.title}` : undefined,
57
- includeStyles: true,
58
- fullDocument: true,
59
- headContent: `<link rel="canonical" href="./api/${slugify(exp.name)}.html">`
60
- });
61
- const filename = `${slugify(exp.name)}.html`;
62
- fs.writeFileSync(path.join(pagesDir, filename), exportHtml);
63
- if (options.verbose) {
64
- console.log(` api/${filename}`);
65
- }
66
- }
67
- console.log(`Generated ${exports.length + 1} HTML files`);
68
- if (options.search !== false) {
69
- console.log("Building search index...");
70
- try {
71
- await execAsync(`npx pagefind --site ${outDir} --output-subdir _pagefind`, {
72
- cwd: process.cwd()
73
- });
74
- console.log("Search index created");
75
- } catch (err) {
76
- if (options.verbose) {
77
- console.log("Pagefind not available, generating search.json fallback");
78
- }
79
- const records = toPagefindRecords(docs.spec, {
80
- baseUrl: "/api"
81
- });
82
- fs.writeFileSync(path.join(outDir, "search.json"), JSON.stringify(records, null, 2));
83
- console.log("Generated search.json fallback");
84
- }
85
- }
86
- console.log(`
87
- Build complete: ${outDir}`);
88
- console.log(`
89
- To serve locally:`);
90
- console.log(` npx serve ${outDir}`);
91
- } catch (err) {
92
- console.error("Error:", err instanceof Error ? err.message : err);
93
- process.exit(1);
94
- }
95
- });
96
- }
97
- function slugify(name) {
98
- return name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
99
- }
100
-
101
- // src/cli/dev.ts
102
- import * as fs2 from "node:fs";
103
- import * as http from "node:http";
104
- import * as path2 from "node:path";
105
- function registerDevCommand(program) {
106
- program.command("dev <spec>").description("Start dev server with hot reload").option("-p, --port <port>", "Port to serve on", "3001").option("-h, --host <host>", "Host to bind to", "localhost").option("--open", "Open browser on start").option("--verbose", "Verbose output").action(async (specPath, options) => {
107
- try {
108
- const resolvedSpec = path2.resolve(specPath);
109
- if (!fs2.existsSync(resolvedSpec)) {
110
- console.error(`Error: Spec file not found: ${resolvedSpec}`);
111
- process.exit(1);
112
- }
113
- const port = Number.parseInt(options.port, 10);
114
- const host = options.host ?? "localhost";
115
- let docs = createDocs(resolvedSpec);
116
- let lastMtime = fs2.statSync(resolvedSpec).mtimeMs;
117
- console.log(`
118
- Starting dev server...`);
119
- console.log(` Spec: ${resolvedSpec}`);
120
- console.log(` Exports: ${docs.getAllExports().length}`);
121
- const watcher = fs2.watch(resolvedSpec, (eventType) => {
122
- if (eventType === "change") {
123
- const currentMtime = fs2.statSync(resolvedSpec).mtimeMs;
124
- if (currentMtime !== lastMtime) {
125
- lastMtime = currentMtime;
126
- try {
127
- docs = createDocs(resolvedSpec);
128
- console.log(`
129
- [${new Date().toLocaleTimeString()}] Spec reloaded (${docs.getAllExports().length} exports)`);
130
- } catch (err) {
131
- console.error(`
132
- [${new Date().toLocaleTimeString()}] Error reloading spec:`, err instanceof Error ? err.message : err);
133
- }
134
- }
135
- }
136
- });
137
- const server = http.createServer((req, res) => {
138
- const url = new URL(req.url || "/", `http://${host}:${port}`);
139
- const pathname = url.pathname;
140
- if (options.verbose) {
141
- console.log(`${req.method} ${pathname}`);
142
- }
143
- try {
144
- if (pathname.startsWith("/api/")) {
145
- const exportName = pathname.replace("/api/", "").replace(".html", "").replace(/-/g, "");
146
- const exp = findExport(docs, exportName);
147
- if (exp) {
148
- const html = toHTML(docs.spec, {
149
- export: exp.name,
150
- includeStyles: true,
151
- fullDocument: true,
152
- headContent: hotReloadScript(port)
153
- });
154
- res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
155
- res.end(html);
156
- return;
157
- }
158
- }
159
- if (pathname === "/" || pathname === "/index.html") {
160
- const html = toHTML(docs.spec, {
161
- includeStyles: true,
162
- fullDocument: true,
163
- headContent: hotReloadScript(port)
164
- });
165
- res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
166
- res.end(html);
167
- return;
168
- }
169
- if (pathname === "/__reload") {
170
- res.writeHead(200, {
171
- "Content-Type": "text/event-stream",
172
- "Cache-Control": "no-cache",
173
- Connection: "keep-alive"
174
- });
175
- const interval = setInterval(() => {
176
- res.write(`data: ping
177
-
178
- `);
179
- }, 2000);
180
- const reloadWatcher = fs2.watch(resolvedSpec, () => {
181
- res.write(`data: reload
182
-
183
- `);
184
- });
185
- req.on("close", () => {
186
- clearInterval(interval);
187
- reloadWatcher.close();
188
- });
189
- return;
190
- }
191
- res.writeHead(404, { "Content-Type": "text/html" });
192
- res.end("<h1>404 Not Found</h1>");
193
- } catch (err) {
194
- console.error("Server error:", err);
195
- res.writeHead(500, { "Content-Type": "text/html" });
196
- res.end(`<h1>500 Server Error</h1><pre>${err instanceof Error ? err.message : err}</pre>`);
197
- }
198
- });
199
- server.listen(port, host, () => {
200
- console.log(`
201
- Local: http://${host}:${port}/`);
202
- console.log(`
203
- Watching for spec changes...`);
204
- console.log(` Press Ctrl+C to stop
205
- `);
206
- if (options.open) {
207
- const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
208
- import("node:child_process").then(({ exec: exec2 }) => {
209
- exec2(`${openCmd} http://${host}:${port}/`);
210
- });
211
- }
212
- });
213
- process.on("SIGINT", () => {
214
- console.log(`
215
-
216
- Shutting down...`);
217
- watcher.close();
218
- server.close();
219
- process.exit(0);
220
- });
221
- } catch (err) {
222
- console.error("Error:", err instanceof Error ? err.message : err);
223
- process.exit(1);
224
- }
225
- });
226
- }
227
- function findExport(docs, searchName) {
228
- const lowerSearch = searchName.toLowerCase();
229
- return docs.getAllExports().find((exp) => {
230
- const lowerName = exp.name.toLowerCase().replace(/[^a-z0-9]/g, "");
231
- return lowerName === lowerSearch || exp.id === searchName;
232
- });
233
- }
234
- function hotReloadScript(port) {
235
- return `
236
- <script>
237
- (function() {
238
- const source = new EventSource('http://localhost:${port}/__reload');
239
- source.onmessage = function(e) {
240
- if (e.data === 'reload') {
241
- window.location.reload();
242
- }
243
- };
244
- source.onerror = function() {
245
- source.close();
246
- setTimeout(() => window.location.reload(), 1000);
247
- };
248
- })();
249
- </script>`;
250
- }
251
-
252
- // src/cli/generate.ts
253
- import * as fs3 from "node:fs";
254
- import * as path3 from "node:path";
255
- function slugify2(name) {
256
- return name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
257
- }
258
- function registerGenerateCommand(program) {
259
- program.command("generate <spec>").description("Generate MDX or JSON files from OpenPkg spec").option("-o, --out <dir>", "Output directory", "./api-docs").option("-f, --format <format>", "Output format: mdx or json", "mdx").option("--nav <format>", "Navigation format: fumadocs, docusaurus, generic").option("--flat", "Flat file structure (no grouping folders)").option("--group-by <groupBy>", "Group by: kind, module, tag, none", "kind").option("--base-path <path>", "Base path for navigation links", "/api").option("--verbose", "Verbose output").action(async (specPath, options) => {
260
- try {
261
- const resolvedSpec = path3.resolve(specPath);
262
- if (!fs3.existsSync(resolvedSpec)) {
263
- console.error(`Error: Spec file not found: ${resolvedSpec}`);
264
- process.exit(1);
265
- }
266
- const docs = createDocs(resolvedSpec);
267
- const exports = docs.getAllExports();
268
- const outDir = path3.resolve(options.out);
269
- if (options.verbose) {
270
- console.log(`Spec: ${resolvedSpec}`);
271
- console.log(`Output: ${outDir}`);
272
- console.log(`Format: ${options.format}`);
273
- console.log(`Exports: ${exports.length}`);
274
- }
275
- fs3.mkdirSync(outDir, { recursive: true });
276
- if (options.format === "json") {
277
- const jsonContent = toJSONString(docs.spec, { pretty: true });
278
- const jsonPath = path3.join(outDir, "api.json");
279
- fs3.writeFileSync(jsonPath, jsonContent);
280
- console.log(`Generated ${jsonPath}`);
281
- } else {
282
- const groupBy = options.groupBy ?? "kind";
283
- const isFlat = options.flat ?? false;
284
- const groups = new Map;
285
- for (const exp of exports) {
286
- let groupKey;
287
- if (isFlat || groupBy === "none") {
288
- groupKey = "";
289
- } else if (groupBy === "kind") {
290
- groupKey = `${exp.kind}s`;
291
- } else if (groupBy === "module") {
292
- groupKey = extractModule(exp.source?.file) || "core";
293
- } else if (groupBy === "tag") {
294
- const categoryTag = exp.tags?.find((t) => t.name === "category" || t.name === "@category");
295
- groupKey = categoryTag?.text || "other";
296
- } else {
297
- groupKey = "";
298
- }
299
- const existing = groups.get(groupKey) ?? [];
300
- existing.push(exp);
301
- groups.set(groupKey, existing);
302
- }
303
- let fileCount = 0;
304
- for (const [group, groupExports] of groups) {
305
- const groupDir = group ? path3.join(outDir, slugify2(group)) : outDir;
306
- if (group) {
307
- fs3.mkdirSync(groupDir, { recursive: true });
308
- }
309
- for (const exp of groupExports) {
310
- const mdx = exportToMarkdown(exp, {
311
- frontmatter: true,
312
- codeSignatures: true
313
- });
314
- const filename = `${slugify2(exp.name)}.mdx`;
315
- const filePath = path3.join(groupDir, filename);
316
- fs3.writeFileSync(filePath, mdx);
317
- fileCount++;
318
- if (options.verbose) {
319
- console.log(` ${group ? `${group}/` : ""}${filename}`);
320
- }
321
- }
322
- }
323
- console.log(`Generated ${fileCount} MDX files in ${outDir}`);
324
- }
325
- if (options.nav) {
326
- const basePath = options.basePath ?? "/api";
327
- const navOptions = {
328
- format: options.nav,
329
- groupBy: options.groupBy ?? "kind",
330
- basePath
331
- };
332
- let navContent;
333
- let navFilename;
334
- switch (options.nav) {
335
- case "fumadocs":
336
- navContent = toFumadocsMetaJSON(docs.spec, navOptions);
337
- navFilename = "meta.json";
338
- break;
339
- case "docusaurus":
340
- navContent = toDocusaurusSidebarJS(docs.spec, navOptions);
341
- navFilename = "sidebars.js";
342
- break;
343
- default:
344
- navContent = JSON.stringify(toNavigation(docs.spec, navOptions), null, 2);
345
- navFilename = "nav.json";
346
- break;
347
- }
348
- const navPath = path3.join(outDir, navFilename);
349
- fs3.writeFileSync(navPath, navContent);
350
- console.log(`Generated ${navPath}`);
351
- }
352
- } catch (err) {
353
- console.error("Error:", err instanceof Error ? err.message : err);
354
- process.exit(1);
355
- }
356
- });
357
- }
358
- function extractModule(filePath) {
359
- if (!filePath)
360
- return;
361
- const parts = filePath.split("/");
362
- const lastPart = parts[parts.length - 1];
363
- if (lastPart === "index.ts" || lastPart === "index.tsx") {
364
- return parts[parts.length - 2];
365
- }
366
- return lastPart.replace(/\.[jt]sx?$/, "");
367
- }
368
-
369
- // src/cli.ts
370
- var __filename2 = fileURLToPath(import.meta.url);
371
- var __dirname2 = path4.dirname(__filename2);
372
- var version = "0.0.1";
373
- try {
374
- const packageJson = JSON.parse(readFileSync(path4.join(__dirname2, "../package.json"), "utf-8"));
375
- version = packageJson.version;
376
- } catch {}
377
- var program = new Command;
378
- program.name("openpkg-docs").description("Generate API documentation from OpenPkg specs").version(version).option("-c, --config <path>", "Config file path").option("-v, --verbose", "Verbose output");
379
- registerBuildCommand(program);
380
- registerGenerateCommand(program);
381
- registerDevCommand(program);
382
- program.command("*", { hidden: true }).action(() => {
383
- program.outputHelp();
384
- });
385
- program.parseAsync().catch(() => {
386
- process.exit(1);
387
- });