flowdoc-gen 0.1.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,51 @@
1
+ import {
2
+ generate
3
+ } from "./chunk-SAMPAR3A.js";
4
+
5
+ // src/serve.ts
6
+ import { createServer } from "http";
7
+ import { createReadStream, existsSync } from "fs";
8
+ import { join, extname } from "path";
9
+ import chalk from "chalk";
10
+ import open from "open";
11
+ var MIME_TYPES = {
12
+ ".html": "text/html",
13
+ ".js": "application/javascript",
14
+ ".css": "text/css",
15
+ ".json": "application/json",
16
+ ".svg": "image/svg+xml",
17
+ ".png": "image/png",
18
+ ".ico": "image/x-icon"
19
+ };
20
+ var serve = async (opts = {}) => {
21
+ const spec = await generate({ ...opts, quiet: false });
22
+ const cwd = process.cwd();
23
+ const outputDir = opts.output ?? join(cwd, "docs-output");
24
+ const port = opts.port ?? 4e3;
25
+ const server = createServer((req, res) => {
26
+ const url = req.url === "/" || req.url === "" ? "/index.html" : req.url ?? "/index.html";
27
+ const filePath = join(outputDir, url);
28
+ if (!existsSync(filePath)) {
29
+ res.writeHead(404);
30
+ res.end("Not found");
31
+ return;
32
+ }
33
+ const ext = extname(filePath);
34
+ const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
35
+ res.writeHead(200, { "Content-Type": contentType });
36
+ createReadStream(filePath).pipe(res);
37
+ });
38
+ server.listen(port, () => {
39
+ const url = `http://localhost:${port}`;
40
+ console.log();
41
+ console.log(` ${chalk.bold("flowdoc")} is running at ${chalk.cyan(url)}`);
42
+ console.log();
43
+ if (!opts.noOpen) {
44
+ void open(url);
45
+ }
46
+ });
47
+ };
48
+
49
+ export {
50
+ serve
51
+ };
@@ -0,0 +1,93 @@
1
+ // src/generate.ts
2
+ import { writeFileSync, mkdirSync, cpSync, existsSync } from "fs";
3
+ import { resolve, join, dirname } from "path";
4
+ import { fileURLToPath } from "url";
5
+ import chalk from "chalk";
6
+ import ora from "ora";
7
+ import { findConfigFile, loadConfig, resolveConfig } from "@flowdoc/core";
8
+ import { extractExpressRoutes } from "@flowdoc/parser";
9
+ import { buildSpec } from "@flowdoc/parser";
10
+ var generate = async (opts = {}) => {
11
+ const cwd = process.cwd();
12
+ const spinner = opts.quiet ? null : ora();
13
+ spinner?.start("Loading flowdoc config...");
14
+ const configPath = opts.config ? resolve(cwd, opts.config) : findConfigFile(cwd);
15
+ if (!configPath) {
16
+ spinner?.fail(chalk.red("No flowdoc.config.ts found. Run `flowdoc init` first."));
17
+ process.exit(1);
18
+ }
19
+ let rawConfig;
20
+ try {
21
+ rawConfig = await loadConfig(configPath);
22
+ } catch (err) {
23
+ spinner?.fail(chalk.red(`Failed to load config: ${String(err)}`));
24
+ process.exit(1);
25
+ }
26
+ const config = resolveConfig(rawConfig, cwd);
27
+ spinner?.succeed(`Config loaded \u2014 ${chalk.cyan(config.name)}`);
28
+ spinner?.start(`Scanning ${chalk.cyan(config.entry)} for routes...`);
29
+ let routes;
30
+ try {
31
+ routes = await extractExpressRoutes(config);
32
+ } catch (err) {
33
+ spinner?.fail(chalk.red(`Parse failed: ${String(err)}`));
34
+ process.exit(1);
35
+ }
36
+ spinner?.succeed(
37
+ `Found ${chalk.green(String(routes.length))} routes across ${chalk.cyan(config.framework)} app`
38
+ );
39
+ const spec = buildSpec(routes, config);
40
+ const outputDir = opts.output ? resolve(cwd, opts.output) : config.output ?? resolve(cwd, "docs-output");
41
+ mkdirSync(outputDir, { recursive: true });
42
+ const specPath = join(outputDir, "flowdoc.json");
43
+ writeFileSync(specPath, JSON.stringify(spec, null, 2), "utf-8");
44
+ await writeUiHtml(outputDir, config);
45
+ if (!opts.quiet) {
46
+ console.log();
47
+ console.log(chalk.bold(" flowdoc generated successfully"));
48
+ console.log();
49
+ console.log(` ${chalk.gray("Spec:")} ${chalk.cyan(specPath)}`);
50
+ console.log(` ${chalk.gray("UI:")} ${chalk.cyan(join(outputDir, "index.html"))}`);
51
+ console.log();
52
+ console.log(` ${chalk.gray("Routes:")} ${chalk.green(String(routes.length))}`);
53
+ console.log(` ${chalk.gray("Groups:")} ${chalk.green(String(spec.groups.length))}`);
54
+ console.log();
55
+ }
56
+ return spec;
57
+ };
58
+ var writeUiHtml = async (outputDir, config) => {
59
+ const brand = config.theme?.brand ?? "#6366f1";
60
+ const title = config.name;
61
+ const darkMode = config.theme?.darkMode !== false;
62
+ const cliRoot = dirname(dirname(fileURLToPath(import.meta.url)));
63
+ const uiAssetsSource = join(cliRoot, "ui-assets");
64
+ const uiAssetsDest = join(outputDir, "assets");
65
+ if (existsSync(uiAssetsSource)) {
66
+ mkdirSync(uiAssetsDest, { recursive: true });
67
+ cpSync(uiAssetsSource, uiAssetsDest, { recursive: true });
68
+ }
69
+ const html = generateHtmlShell({ title, brand, darkMode });
70
+ writeFileSync(join(outputDir, "index.html"), html, "utf-8");
71
+ };
72
+ var generateHtmlShell = ({ title, brand, darkMode }) => `<!DOCTYPE html>
73
+ <html lang="en" class="${darkMode ? "dark" : ""}">
74
+ <head>
75
+ <meta charset="UTF-8" />
76
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
+ <title>${title} \u2014 API Docs</title>
78
+ <meta name="description" content="API documentation generated by flowdoc" />
79
+ <script>
80
+ window.__FLOWDOC_BRAND__ = "${brand}";
81
+ window.__FLOWDOC_DARK__ = ${String(darkMode)};
82
+ </script>
83
+ <script type="module" crossorigin src="./assets/ui.js"></script>
84
+ <link rel="stylesheet" href="./assets/index.css" />
85
+ </head>
86
+ <body>
87
+ <div id="root"></div>
88
+ </body>
89
+ </html>`;
90
+
91
+ export {
92
+ generate
93
+ };
@@ -0,0 +1,52 @@
1
+ // src/init.ts
2
+ import { writeFileSync, existsSync } from "fs";
3
+ import { resolve } from "path";
4
+ import chalk from "chalk";
5
+ var CONFIG_TEMPLATE = `import type { FlowDocConfig } from "@flowdoc/core";
6
+
7
+ const config: FlowDocConfig = {
8
+ name: "My API",
9
+ version: "1.0.0",
10
+ description: "API documentation generated by flowdoc",
11
+ framework: "express",
12
+ entry: "./src", // folder or file containing your Express routes
13
+ baseUrl: "http://localhost:3000",
14
+ auth: {
15
+ type: "bearer",
16
+ },
17
+ output: "./docs-output",
18
+ theme: {
19
+ brand: "#6366f1",
20
+ darkMode: true,
21
+ },
22
+ // Optional: manually group routes under named sections
23
+ // groups: {
24
+ // "User Management": ["/users/**"],
25
+ // "Auth": ["/auth/**"],
26
+ // },
27
+ };
28
+
29
+ export default config;
30
+ `;
31
+ var init = (cwd = process.cwd()) => {
32
+ const configPath = resolve(cwd, "flowdoc.config.ts");
33
+ if (existsSync(configPath)) {
34
+ console.log(chalk.yellow(" flowdoc.config.ts already exists \u2014 skipping."));
35
+ return;
36
+ }
37
+ writeFileSync(configPath, CONFIG_TEMPLATE, "utf-8");
38
+ console.log();
39
+ console.log(` ${chalk.bold("flowdoc")} initialized`);
40
+ console.log();
41
+ console.log(` Created ${chalk.cyan("flowdoc.config.ts")}`);
42
+ console.log();
43
+ console.log(" Next steps:");
44
+ console.log(` 1. Edit ${chalk.cyan("flowdoc.config.ts")} \u2014 set your entry path`);
45
+ console.log(` 2. Run ${chalk.cyan("flowdoc generate")} to build your docs`);
46
+ console.log(` 3. Run ${chalk.cyan("flowdoc serve")} to preview locally`);
47
+ console.log();
48
+ };
49
+
50
+ export {
51
+ init
52
+ };