flowdoc-gen 0.1.1 → 0.1.3

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,148 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+
3
+ type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
4
+ type ParameterLocation = "path" | "query" | "header" | "cookie";
5
+ type SchemaType = "string" | "number" | "integer" | "boolean" | "object" | "array" | "null";
6
+ interface JsonSchema {
7
+ type?: SchemaType | SchemaType[];
8
+ format?: string;
9
+ description?: string;
10
+ example?: unknown;
11
+ enum?: unknown[];
12
+ properties?: Record<string, JsonSchema>;
13
+ items?: JsonSchema;
14
+ required?: string[];
15
+ additionalProperties?: boolean | JsonSchema;
16
+ anyOf?: JsonSchema[];
17
+ oneOf?: JsonSchema[];
18
+ allOf?: JsonSchema[];
19
+ nullable?: boolean;
20
+ minimum?: number;
21
+ maximum?: number;
22
+ minLength?: number;
23
+ maxLength?: number;
24
+ minItems?: number;
25
+ maxItems?: number;
26
+ pattern?: string;
27
+ title?: string;
28
+ default?: unknown;
29
+ }
30
+ interface RouteParameter {
31
+ name: string;
32
+ in: ParameterLocation;
33
+ required: boolean;
34
+ schema: JsonSchema;
35
+ description?: string;
36
+ example?: unknown;
37
+ }
38
+ interface RequestBody {
39
+ required: boolean;
40
+ description?: string;
41
+ content: {
42
+ "application/json"?: {
43
+ schema: JsonSchema;
44
+ };
45
+ "multipart/form-data"?: {
46
+ schema: JsonSchema;
47
+ };
48
+ "application/x-www-form-urlencoded"?: {
49
+ schema: JsonSchema;
50
+ };
51
+ };
52
+ }
53
+ interface ResponseBody {
54
+ description: string;
55
+ content?: {
56
+ "application/json"?: {
57
+ schema: JsonSchema;
58
+ };
59
+ };
60
+ }
61
+ interface RouteDoc {
62
+ method: HttpMethod;
63
+ path: string;
64
+ summary?: string;
65
+ description?: string;
66
+ tags: string[];
67
+ parameters: RouteParameter[];
68
+ requestBody?: RequestBody;
69
+ responses: Record<string, ResponseBody>;
70
+ deprecated?: boolean;
71
+ security?: Array<Record<string, string[]>>;
72
+ middleware?: string[];
73
+ }
74
+ interface ApiGroup {
75
+ name: string;
76
+ description?: string;
77
+ routes: RouteDoc[];
78
+ }
79
+ interface FlowDocSpec {
80
+ info: {
81
+ title: string;
82
+ version: string;
83
+ description?: string;
84
+ baseUrl: string;
85
+ };
86
+ auth?: {
87
+ type: "bearer" | "apiKey" | "basic" | "oauth2";
88
+ headerName?: string;
89
+ queryName?: string;
90
+ };
91
+ groups: ApiGroup[];
92
+ generatedAt: string;
93
+ sourceFramework: "express" | "nestjs";
94
+ }
95
+ interface FlowDocConfig {
96
+ name: string;
97
+ version?: string;
98
+ description?: string;
99
+ framework: "express" | "nestjs";
100
+ entry: string;
101
+ baseUrl?: string;
102
+ auth?: FlowDocSpec["auth"];
103
+ output?: string;
104
+ theme?: {
105
+ brand?: string;
106
+ logo?: string;
107
+ darkMode?: boolean;
108
+ };
109
+ groups?: Record<string, string[]>;
110
+ exclude?: string[];
111
+ }
112
+
113
+ interface GenerateOptions {
114
+ config?: string;
115
+ output?: string;
116
+ quiet?: boolean;
117
+ }
118
+ declare const generate: (opts?: GenerateOptions) => Promise<FlowDocSpec>;
119
+
120
+ interface ServeOptions extends GenerateOptions {
121
+ port?: number;
122
+ noOpen?: boolean;
123
+ watch?: boolean;
124
+ }
125
+ declare const serve: (opts?: ServeOptions) => Promise<void>;
126
+
127
+ declare const init: (cwd?: string) => void;
128
+
129
+ interface FlowDocMiddlewareOptions {
130
+ /** Path to flowdoc.config.ts — defaults to auto-discovery from cwd */
131
+ config?: string;
132
+ /** Route prefix the middleware is mounted at — used only for the HTML shell */
133
+ path?: string;
134
+ }
135
+ /**
136
+ * Express middleware that serves flowdoc docs at whatever route you mount it on.
137
+ * baseUrl is auto-derived from each incoming request — no manual config needed.
138
+ *
139
+ * Usage:
140
+ * import { flowdoc } from "flowdoc";
141
+ * app.use("/docs", flowdoc());
142
+ */
143
+ declare const flowdoc: (opts?: FlowDocMiddlewareOptions) => (req: Request, res: Response, next: NextFunction) => Promise<void>;
144
+
145
+ /** Type-safe config helper — use in flowdoc.config.ts */
146
+ declare const defineConfig: (config: FlowDocConfig) => FlowDocConfig;
147
+
148
+ export { type FlowDocConfig, type FlowDocMiddlewareOptions, type FlowDocSpec, type GenerateOptions, type JsonSchema, type RouteDoc, type ServeOptions, defineConfig, flowdoc, generate, init, serve };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,115 @@
1
- import { FlowDocSpec } from '@flowdoc/core';
2
1
  import { Request, Response, NextFunction } from 'express';
3
2
 
3
+ type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
4
+ type ParameterLocation = "path" | "query" | "header" | "cookie";
5
+ type SchemaType = "string" | "number" | "integer" | "boolean" | "object" | "array" | "null";
6
+ interface JsonSchema {
7
+ type?: SchemaType | SchemaType[];
8
+ format?: string;
9
+ description?: string;
10
+ example?: unknown;
11
+ enum?: unknown[];
12
+ properties?: Record<string, JsonSchema>;
13
+ items?: JsonSchema;
14
+ required?: string[];
15
+ additionalProperties?: boolean | JsonSchema;
16
+ anyOf?: JsonSchema[];
17
+ oneOf?: JsonSchema[];
18
+ allOf?: JsonSchema[];
19
+ nullable?: boolean;
20
+ minimum?: number;
21
+ maximum?: number;
22
+ minLength?: number;
23
+ maxLength?: number;
24
+ minItems?: number;
25
+ maxItems?: number;
26
+ pattern?: string;
27
+ title?: string;
28
+ default?: unknown;
29
+ }
30
+ interface RouteParameter {
31
+ name: string;
32
+ in: ParameterLocation;
33
+ required: boolean;
34
+ schema: JsonSchema;
35
+ description?: string;
36
+ example?: unknown;
37
+ }
38
+ interface RequestBody {
39
+ required: boolean;
40
+ description?: string;
41
+ content: {
42
+ "application/json"?: {
43
+ schema: JsonSchema;
44
+ };
45
+ "multipart/form-data"?: {
46
+ schema: JsonSchema;
47
+ };
48
+ "application/x-www-form-urlencoded"?: {
49
+ schema: JsonSchema;
50
+ };
51
+ };
52
+ }
53
+ interface ResponseBody {
54
+ description: string;
55
+ content?: {
56
+ "application/json"?: {
57
+ schema: JsonSchema;
58
+ };
59
+ };
60
+ }
61
+ interface RouteDoc {
62
+ method: HttpMethod;
63
+ path: string;
64
+ summary?: string;
65
+ description?: string;
66
+ tags: string[];
67
+ parameters: RouteParameter[];
68
+ requestBody?: RequestBody;
69
+ responses: Record<string, ResponseBody>;
70
+ deprecated?: boolean;
71
+ security?: Array<Record<string, string[]>>;
72
+ middleware?: string[];
73
+ }
74
+ interface ApiGroup {
75
+ name: string;
76
+ description?: string;
77
+ routes: RouteDoc[];
78
+ }
79
+ interface FlowDocSpec {
80
+ info: {
81
+ title: string;
82
+ version: string;
83
+ description?: string;
84
+ baseUrl: string;
85
+ };
86
+ auth?: {
87
+ type: "bearer" | "apiKey" | "basic" | "oauth2";
88
+ headerName?: string;
89
+ queryName?: string;
90
+ };
91
+ groups: ApiGroup[];
92
+ generatedAt: string;
93
+ sourceFramework: "express" | "nestjs";
94
+ }
95
+ interface FlowDocConfig {
96
+ name: string;
97
+ version?: string;
98
+ description?: string;
99
+ framework: "express" | "nestjs";
100
+ entry: string;
101
+ baseUrl?: string;
102
+ auth?: FlowDocSpec["auth"];
103
+ output?: string;
104
+ theme?: {
105
+ brand?: string;
106
+ logo?: string;
107
+ darkMode?: boolean;
108
+ };
109
+ groups?: Record<string, string[]>;
110
+ exclude?: string[];
111
+ }
112
+
4
113
  interface GenerateOptions {
5
114
  config?: string;
6
115
  output?: string;
@@ -33,4 +142,7 @@ interface FlowDocMiddlewareOptions {
33
142
  */
34
143
  declare const flowdoc: (opts?: FlowDocMiddlewareOptions) => (req: Request, res: Response, next: NextFunction) => Promise<void>;
35
144
 
36
- export { type FlowDocMiddlewareOptions, type GenerateOptions, type ServeOptions, flowdoc, generate, init, serve };
145
+ /** Type-safe config helper use in flowdoc.config.ts */
146
+ declare const defineConfig: (config: FlowDocConfig) => FlowDocConfig;
147
+
148
+ export { type FlowDocConfig, type FlowDocMiddlewareOptions, type FlowDocSpec, type GenerateOptions, type JsonSchema, type RouteDoc, type ServeOptions, defineConfig, flowdoc, generate, init, serve };
package/dist/index.js CHANGED
@@ -1244,31 +1244,24 @@ var serve = async (opts = {}) => {
1244
1244
  import { writeFileSync as writeFileSync2, existsSync as existsSync5 } from "fs";
1245
1245
  import { resolve as resolve5 } from "path";
1246
1246
  import chalk3 from "chalk";
1247
- var CONFIG_TEMPLATE = `import type { FlowDocConfig } from "@flowdoc/core";
1247
+ var CONFIG_TEMPLATE = `import { defineConfig } from "flowdoc-gen";
1248
1248
 
1249
- const config: FlowDocConfig = {
1249
+ export default defineConfig({
1250
1250
  name: "My API",
1251
1251
  version: "1.0.0",
1252
1252
  description: "API documentation generated by flowdoc",
1253
1253
  framework: "express",
1254
- entry: "./src", // folder or file containing your Express routes
1255
- baseUrl: "http://localhost:3000",
1256
- auth: {
1257
- type: "bearer",
1258
- },
1254
+ entry: "./src",
1259
1255
  output: "./docs-output",
1260
1256
  theme: {
1261
1257
  brand: "#6366f1",
1262
1258
  darkMode: true,
1263
1259
  },
1264
- // Optional: manually group routes under named sections
1265
- // groups: {
1266
- // "User Management": ["/users/**"],
1267
- // "Auth": ["/auth/**"],
1268
- // },
1269
- };
1270
-
1271
- export default config;
1260
+ // groups: [
1261
+ // { name: "Auth", match: "/auth/**" },
1262
+ // { name: "Users", match: "/users/**" },
1263
+ // ],
1264
+ });
1272
1265
  `;
1273
1266
  var init = (cwd = process.cwd()) => {
1274
1267
  const configPath = resolve5(cwd, "flowdoc.config.ts");
@@ -1366,7 +1359,11 @@ var buildHtml = ({ baseUrl, brand }) => `<!DOCTYPE html>
1366
1359
  </head>
1367
1360
  <body><div id="root"></div></body>
1368
1361
  </html>`;
1362
+
1363
+ // src/index.ts
1364
+ var defineConfig = (config) => config;
1369
1365
  export {
1366
+ defineConfig,
1370
1367
  flowdoc,
1371
1368
  generate,
1372
1369
  init,
@@ -2,31 +2,24 @@
2
2
  import { writeFileSync, existsSync } from "fs";
3
3
  import { resolve } from "path";
4
4
  import chalk from "chalk";
5
- var CONFIG_TEMPLATE = `import type { FlowDocConfig } from "@flowdoc/core";
5
+ var CONFIG_TEMPLATE = `import { defineConfig } from "flowdoc-gen";
6
6
 
7
- const config: FlowDocConfig = {
7
+ export default defineConfig({
8
8
  name: "My API",
9
9
  version: "1.0.0",
10
10
  description: "API documentation generated by flowdoc",
11
11
  framework: "express",
12
- entry: "./src", // folder or file containing your Express routes
13
- baseUrl: "http://localhost:3000",
14
- auth: {
15
- type: "bearer",
16
- },
12
+ entry: "./src",
17
13
  output: "./docs-output",
18
14
  theme: {
19
15
  brand: "#6366f1",
20
16
  darkMode: true,
21
17
  },
22
- // Optional: manually group routes under named sections
23
- // groups: {
24
- // "User Management": ["/users/**"],
25
- // "Auth": ["/auth/**"],
26
- // },
27
- };
28
-
29
- export default config;
18
+ // groups: [
19
+ // { name: "Auth", match: "/auth/**" },
20
+ // { name: "Users", match: "/users/**" },
21
+ // ],
22
+ });
30
23
  `;
31
24
  var init = (cwd = process.cwd()) => {
32
25
  const configPath = resolve(cwd, "flowdoc.config.ts");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowdoc-gen",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Auto-generate beautiful API documentation from your Express codebase — no annotations required",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,6 +11,7 @@
11
11
  "exports": {
12
12
  ".": {
13
13
  "import": "./dist/index.js",
14
+ "require": "./dist/index.cjs",
14
15
  "types": "./dist/index.d.ts"
15
16
  }
16
17
  },
package/dist/bin.d.ts DELETED
@@ -1 +0,0 @@
1
- #!/usr/bin/env node
@@ -1,51 +0,0 @@
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
- };
@@ -1,93 +0,0 @@
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
- };
@@ -1,52 +0,0 @@
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
- };