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.
@@ -1,15 +1,53 @@
1
- #!/usr/bin/env node
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ defineConfig: () => defineConfig,
34
+ flowdoc: () => flowdoc,
35
+ generate: () => generate,
36
+ init: () => init,
37
+ serve: () => serve
38
+ });
39
+ module.exports = __toCommonJS(src_exports);
2
40
 
3
41
  // src/generate.ts
4
- import { writeFileSync, mkdirSync, cpSync, existsSync as existsSync3 } from "fs";
5
- import { resolve as resolve3, join as join3, dirname as dirname2 } from "path";
6
- import { fileURLToPath } from "url";
7
- import chalk from "chalk";
8
- import ora from "ora";
42
+ var import_fs3 = require("fs");
43
+ var import_path3 = require("path");
44
+ var import_url = require("url");
45
+ var import_chalk = __toESM(require("chalk"), 1);
46
+ var import_ora = __toESM(require("ora"), 1);
9
47
 
10
48
  // ../core/dist/index.js
11
- import { existsSync } from "fs";
12
- import { resolve, join } from "path";
49
+ var import_fs = require("fs");
50
+ var import_path = require("path");
13
51
  var CONFIG_FILES = [
14
52
  "flowdoc.config.ts",
15
53
  "flowdoc.config.js",
@@ -17,13 +55,13 @@ var CONFIG_FILES = [
17
55
  ];
18
56
  var findConfigFile = (cwd) => {
19
57
  for (const file of CONFIG_FILES) {
20
- const full = join(cwd, file);
21
- if (existsSync(full)) return full;
58
+ const full = (0, import_path.join)(cwd, file);
59
+ if ((0, import_fs.existsSync)(full)) return full;
22
60
  }
23
61
  return null;
24
62
  };
25
63
  var loadConfig = async (configPath) => {
26
- const resolved = resolve(configPath);
64
+ const resolved = (0, import_path.resolve)(configPath);
27
65
  const mod = await import(resolved);
28
66
  const config = "default" in mod ? mod.default : mod;
29
67
  if (!config) throw new Error(`No config exported from ${configPath}`);
@@ -33,25 +71,21 @@ var resolveConfig = (config, cwd) => ({
33
71
  version: "1.0.0",
34
72
  baseUrl: "http://localhost:3000",
35
73
  ...config,
36
- entry: resolve(cwd, config.entry),
37
- output: resolve(cwd, config.output ?? "./docs-output")
74
+ entry: (0, import_path.resolve)(cwd, config.entry),
75
+ output: (0, import_path.resolve)(cwd, config.output ?? "./docs-output")
38
76
  });
39
77
 
40
78
  // ../parser/dist/index.js
41
- import {
42
- Project,
43
- Node as Node5,
44
- SyntaxKind as SyntaxKind3
45
- } from "ts-morph";
46
- import { glob } from "glob";
47
- import { resolve as resolve2, dirname, join as join2 } from "path";
48
- import { existsSync as existsSync2 } from "fs";
49
- import { Node } from "ts-morph";
50
- import { Node as Node2 } from "ts-morph";
51
- import { Node as Node3 } from "ts-morph";
52
- import { Node as Node4 } from "ts-morph";
79
+ var import_ts_morph = require("ts-morph");
80
+ var import_glob = require("glob");
81
+ var import_path2 = require("path");
82
+ var import_fs2 = require("fs");
83
+ var import_ts_morph2 = require("ts-morph");
84
+ var import_ts_morph3 = require("ts-morph");
85
+ var import_ts_morph4 = require("ts-morph");
86
+ var import_ts_morph5 = require("ts-morph");
53
87
  var zodNodeToJsonSchema = (node) => {
54
- if (!Node.isCallExpression(node)) return {};
88
+ if (!import_ts_morph2.Node.isCallExpression(node)) return {};
55
89
  const expr = node.getExpression();
56
90
  const callText = expr.getText();
57
91
  if (callText === "z.string") return buildStringSchema(node);
@@ -68,7 +102,7 @@ var zodNodeToJsonSchema = (node) => {
68
102
  if (callText === "z.date") return { type: "string", format: "date-time" };
69
103
  if (callText === "z.any") return {};
70
104
  if (callText === "z.unknown") return {};
71
- if (Node.isPropertyAccessExpression(expr)) {
105
+ if (import_ts_morph2.Node.isPropertyAccessExpression(expr)) {
72
106
  return buildChainedSchema(node);
73
107
  }
74
108
  return {};
@@ -91,23 +125,23 @@ var buildLiteralSchema = (node) => {
91
125
  };
92
126
  var buildEnumSchema = (node) => {
93
127
  const arg = node.getArguments()[0];
94
- if (!arg || !Node.isArrayLiteralExpression(arg)) return { type: "string" };
128
+ if (!arg || !import_ts_morph2.Node.isArrayLiteralExpression(arg)) return { type: "string" };
95
129
  const values = arg.getElements().map((el) => el.getText().replace(/['"]/g, ""));
96
130
  return { type: "string", enum: values };
97
131
  };
98
132
  var buildObjectSchema = (node) => {
99
133
  const arg = node.getArguments()[0];
100
- if (!arg || !Node.isObjectLiteralExpression(arg)) return { type: "object" };
134
+ if (!arg || !import_ts_morph2.Node.isObjectLiteralExpression(arg)) return { type: "object" };
101
135
  const properties = {};
102
136
  const required = [];
103
137
  for (const prop of arg.getProperties()) {
104
- if (!Node.isPropertyAssignment(prop)) continue;
138
+ if (!import_ts_morph2.Node.isPropertyAssignment(prop)) continue;
105
139
  const name = prop.getName();
106
- const init = prop.getInitializer();
107
- if (!init) continue;
108
- const childSchema = zodNodeToJsonSchema(init);
140
+ const init2 = prop.getInitializer();
141
+ if (!init2) continue;
142
+ const childSchema = zodNodeToJsonSchema(init2);
109
143
  properties[name] = childSchema;
110
- if (!isOptionalZodExpr(init)) {
144
+ if (!isOptionalZodExpr(init2)) {
111
145
  required.push(name);
112
146
  }
113
147
  }
@@ -124,7 +158,7 @@ var buildArraySchema = (node) => {
124
158
  };
125
159
  var buildUnionSchema = (node) => {
126
160
  const arg = node.getArguments()[0];
127
- if (!arg || !Node.isArrayLiteralExpression(arg)) return {};
161
+ if (!arg || !import_ts_morph2.Node.isArrayLiteralExpression(arg)) return {};
128
162
  const schemas = arg.getElements().map((el) => zodNodeToJsonSchema(el));
129
163
  return { anyOf: schemas };
130
164
  };
@@ -143,11 +177,11 @@ var buildChainedSchema = (node) => {
143
177
  var unwrapChain = (node) => {
144
178
  const methods = [];
145
179
  let current = node;
146
- while (Node.isCallExpression(current)) {
180
+ while (import_ts_morph2.Node.isCallExpression(current)) {
147
181
  const expr = current.getExpression();
148
- if (Node.isPropertyAccessExpression(expr)) {
182
+ if (import_ts_morph2.Node.isPropertyAccessExpression(expr)) {
149
183
  const obj = expr.getExpression();
150
- if (Node.isIdentifier(obj)) {
184
+ if (import_ts_morph2.Node.isIdentifier(obj)) {
151
185
  return { root: current, methods };
152
186
  }
153
187
  const methodName = expr.getName();
@@ -252,13 +286,13 @@ var extractZodSchemas = (sourceFile) => {
252
286
  const schemas = {};
253
287
  const varDeclarations = sourceFile.getVariableDeclarations();
254
288
  for (const decl of varDeclarations) {
255
- const init = decl.getInitializer();
256
- if (!init) continue;
257
- const text = init.getText();
289
+ const init2 = decl.getInitializer();
290
+ if (!init2) continue;
291
+ const text = init2.getText();
258
292
  if (!text.startsWith("z.")) continue;
259
293
  const name = decl.getName();
260
294
  try {
261
- schemas[name] = zodNodeToJsonSchema(init);
295
+ schemas[name] = zodNodeToJsonSchema(init2);
262
296
  } catch {
263
297
  }
264
298
  }
@@ -276,7 +310,7 @@ var YUP_ROOT_METHODS = /* @__PURE__ */ new Set([
276
310
  "lazy"
277
311
  ]);
278
312
  var yupNodeToJsonSchema = (node) => {
279
- if (!Node2.isCallExpression(node)) return {};
313
+ if (!import_ts_morph3.Node.isCallExpression(node)) return {};
280
314
  const chain = unwrapYupChain(node);
281
315
  if (!chain.root) return {};
282
316
  const base = buildYupBase(chain.rootMethod);
@@ -286,17 +320,17 @@ var yupNodeToJsonSchema = (node) => {
286
320
  var unwrapYupChain = (node) => {
287
321
  const methods = [];
288
322
  let current = node;
289
- while (Node2.isCallExpression(current)) {
323
+ while (import_ts_morph3.Node.isCallExpression(current)) {
290
324
  const expr = current.getExpression();
291
- if (!Node2.isPropertyAccessExpression(expr)) {
292
- if (Node2.isIdentifier(expr) && YUP_ROOT_METHODS.has(expr.getText())) {
325
+ if (!import_ts_morph3.Node.isPropertyAccessExpression(expr)) {
326
+ if (import_ts_morph3.Node.isIdentifier(expr) && YUP_ROOT_METHODS.has(expr.getText())) {
293
327
  return { root: current, rootMethod: expr.getText(), methods };
294
328
  }
295
329
  return { root: null, rootMethod: "", methods };
296
330
  }
297
331
  const obj = expr.getExpression();
298
332
  const methodName = expr.getName();
299
- if (Node2.isIdentifier(obj) && obj.getText() === "yup" && YUP_ROOT_METHODS.has(methodName)) {
333
+ if (import_ts_morph3.Node.isIdentifier(obj) && obj.getText() === "yup" && YUP_ROOT_METHODS.has(methodName)) {
300
334
  return { root: current, rootMethod: methodName, methods };
301
335
  }
302
336
  methods.unshift({ name: methodName, args: current.getArguments() });
@@ -379,14 +413,14 @@ var applyYupChain = (methods, schema) => {
379
413
  break;
380
414
  case "oneOf": {
381
415
  const arg = args[0];
382
- if (arg && Node2.isArrayLiteralExpression(arg)) {
416
+ if (arg && import_ts_morph3.Node.isArrayLiteralExpression(arg)) {
383
417
  schema.enum = arg.getElements().map((el) => el.getText().replace(/['"]/g, ""));
384
418
  }
385
419
  break;
386
420
  }
387
421
  case "shape": {
388
422
  const arg = args[0];
389
- if (arg && Node2.isObjectLiteralExpression(arg)) {
423
+ if (arg && import_ts_morph3.Node.isObjectLiteralExpression(arg)) {
390
424
  const { properties, required: req } = parseYupShape(arg);
391
425
  schema.type = "object";
392
426
  schema.properties = properties;
@@ -406,9 +440,9 @@ var applyYupChain = (methods, schema) => {
406
440
  }
407
441
  case "meta": {
408
442
  const arg = args[0];
409
- if (arg && Node2.isObjectLiteralExpression(arg)) {
443
+ if (arg && import_ts_morph3.Node.isObjectLiteralExpression(arg)) {
410
444
  for (const prop of arg.getProperties()) {
411
- if (Node2.isPropertyAssignment(prop) && prop.getName() === "description") {
445
+ if (import_ts_morph3.Node.isPropertyAssignment(prop) && prop.getName() === "description") {
412
446
  const s = getStr(prop.getInitializer());
413
447
  if (s) schema.description = s;
414
448
  }
@@ -428,13 +462,13 @@ var applyYupChain = (methods, schema) => {
428
462
  var parseYupShape = (arg) => {
429
463
  const properties = {};
430
464
  const required = [];
431
- if (!arg || !Node2.isObjectLiteralExpression(arg)) return { properties, required };
465
+ if (!arg || !import_ts_morph3.Node.isObjectLiteralExpression(arg)) return { properties, required };
432
466
  for (const prop of arg.getProperties()) {
433
- if (!Node2.isPropertyAssignment(prop)) continue;
467
+ if (!import_ts_morph3.Node.isPropertyAssignment(prop)) continue;
434
468
  const name = prop.getName();
435
- const init = prop.getInitializer();
436
- if (!init) continue;
437
- const childSchema = yupNodeToJsonSchema(init);
469
+ const init2 = prop.getInitializer();
470
+ if (!init2) continue;
471
+ const childSchema = yupNodeToJsonSchema(init2);
438
472
  const isReq = childSchema.__required === true;
439
473
  delete childSchema.__required;
440
474
  properties[name] = childSchema;
@@ -463,12 +497,12 @@ var isYupExpr = (text) => /^yup\.(?:string|number|boolean|object|array|date|mixe
463
497
  var extractYupSchemas = (sourceFile) => {
464
498
  const schemas = {};
465
499
  for (const decl of sourceFile.getVariableDeclarations()) {
466
- const init = decl.getInitializer();
467
- if (!init) continue;
468
- const text = init.getText();
500
+ const init2 = decl.getInitializer();
501
+ if (!init2) continue;
502
+ const text = init2.getText();
469
503
  if (!isYupExpr(text)) continue;
470
504
  try {
471
- const schema = yupNodeToJsonSchema(init);
505
+ const schema = yupNodeToJsonSchema(init2);
472
506
  if (Object.keys(schema).length > 0) schemas[decl.getName()] = schema;
473
507
  } catch {
474
508
  }
@@ -488,7 +522,7 @@ var JOI_PRIMITIVES = /* @__PURE__ */ new Set([
488
522
  "link"
489
523
  ]);
490
524
  var joiNodeToJsonSchema = (node, joiId = "Joi") => {
491
- if (!Node3.isCallExpression(node)) return {};
525
+ if (!import_ts_morph4.Node.isCallExpression(node)) return {};
492
526
  const chain = unwrapJoiChain(node, joiId);
493
527
  if (!chain.root) return {};
494
528
  const base = buildJoiBase(chain.rootMethod);
@@ -498,14 +532,14 @@ var joiNodeToJsonSchema = (node, joiId = "Joi") => {
498
532
  var unwrapJoiChain = (node, joiId) => {
499
533
  const methods = [];
500
534
  let current = node;
501
- while (Node3.isCallExpression(current)) {
535
+ while (import_ts_morph4.Node.isCallExpression(current)) {
502
536
  const expr = current.getExpression();
503
- if (!Node3.isPropertyAccessExpression(expr)) {
537
+ if (!import_ts_morph4.Node.isPropertyAccessExpression(expr)) {
504
538
  return { root: null, rootMethod: "", methods };
505
539
  }
506
540
  const obj = expr.getExpression();
507
541
  const methodName = expr.getName();
508
- if (Node3.isIdentifier(obj) && obj.getText() === joiId && JOI_PRIMITIVES.has(methodName)) {
542
+ if (import_ts_morph4.Node.isIdentifier(obj) && obj.getText() === joiId && JOI_PRIMITIVES.has(methodName)) {
509
543
  return { root: current, rootMethod: methodName, methods };
510
544
  }
511
545
  methods.unshift({ name: methodName, args: current.getArguments() });
@@ -603,7 +637,7 @@ var applyJoiChain = (methods, schema, joiId) => {
603
637
  }
604
638
  case "keys": {
605
639
  const arg = args[0];
606
- if (arg && Node3.isObjectLiteralExpression(arg)) {
640
+ if (arg && import_ts_morph4.Node.isObjectLiteralExpression(arg)) {
607
641
  const { properties, required } = parseJoiKeys(arg, joiId);
608
642
  schema.type = "object";
609
643
  schema.properties = properties;
@@ -637,13 +671,13 @@ var applyJoiChain = (methods, schema, joiId) => {
637
671
  var parseJoiKeys = (arg, joiId) => {
638
672
  const properties = {};
639
673
  const required = [];
640
- if (!arg || !Node3.isObjectLiteralExpression(arg)) return { properties, required };
674
+ if (!arg || !import_ts_morph4.Node.isObjectLiteralExpression(arg)) return { properties, required };
641
675
  for (const prop of arg.getProperties()) {
642
- if (!Node3.isPropertyAssignment(prop)) continue;
676
+ if (!import_ts_morph4.Node.isPropertyAssignment(prop)) continue;
643
677
  const name = prop.getName();
644
- const init = prop.getInitializer();
645
- if (!init) continue;
646
- const childSchema = joiNodeToJsonSchema(init, joiId);
678
+ const init2 = prop.getInitializer();
679
+ if (!init2) continue;
680
+ const childSchema = joiNodeToJsonSchema(init2, joiId);
647
681
  const isReq = childSchema.__required === true;
648
682
  delete childSchema.__required;
649
683
  properties[name] = childSchema;
@@ -683,11 +717,11 @@ var extractJoiSchemas = (sourceFile) => {
683
717
  const joiId = detectJoiId(sourceFile);
684
718
  if (!joiId) return schemas;
685
719
  for (const decl of sourceFile.getVariableDeclarations()) {
686
- const init = decl.getInitializer();
687
- if (!init) continue;
688
- if (!isJoiExpr(init.getText(), joiId)) continue;
720
+ const init2 = decl.getInitializer();
721
+ if (!init2) continue;
722
+ if (!isJoiExpr(init2.getText(), joiId)) continue;
689
723
  try {
690
- const schema = joiNodeToJsonSchema(init, joiId);
724
+ const schema = joiNodeToJsonSchema(init2, joiId);
691
725
  if (Object.keys(schema).length > 0) schemas[decl.getName()] = schema;
692
726
  } catch {
693
727
  }
@@ -777,7 +811,7 @@ var extractClassValidatorSchemas = (sourceFile) => {
777
811
  const firstArg = call?.getArguments()[0];
778
812
  if (firstArg) {
779
813
  const raw = firstArg.getText();
780
- if (Node4.isArrayLiteralExpression(firstArg)) {
814
+ if (import_ts_morph5.Node.isArrayLiteralExpression(firstArg)) {
781
815
  const values = firstArg.getElements().map((el) => el.getText().replace(/['"]/g, ""));
782
816
  CONSTRAINED[name](propSchema, values);
783
817
  } else {
@@ -824,20 +858,20 @@ var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
824
858
  var findTsConfig = (startDir) => {
825
859
  let dir = startDir;
826
860
  for (let i = 0; i < 5; i++) {
827
- const candidate = join2(dir, "tsconfig.json");
828
- if (existsSync2(candidate)) return candidate;
829
- const parent = dirname(dir);
861
+ const candidate = (0, import_path2.join)(dir, "tsconfig.json");
862
+ if ((0, import_fs2.existsSync)(candidate)) return candidate;
863
+ const parent = (0, import_path2.dirname)(dir);
830
864
  if (parent === dir) break;
831
865
  dir = parent;
832
866
  }
833
867
  return void 0;
834
868
  };
835
869
  var extractExpressRoutes = async (config) => {
836
- const cwd = existsSync2(config.entry) && !config.entry.endsWith(".ts") && !config.entry.endsWith(".js") ? config.entry : dirname(config.entry);
870
+ const cwd = (0, import_fs2.existsSync)(config.entry) && !config.entry.endsWith(".ts") && !config.entry.endsWith(".js") ? config.entry : (0, import_path2.dirname)(config.entry);
837
871
  const tsConfigPath = findTsConfig(cwd);
838
- const project = tsConfigPath ? new Project({ tsConfigFilePath: tsConfigPath, skipAddingFilesFromTsConfig: true }) : new Project({ compilerOptions: { allowJs: true, strict: false } });
839
- const patterns = ["**/*.ts", "**/*.js"].map((p) => resolve2(cwd, "**", p));
840
- const files = await glob(`${cwd}/**/*.{ts,js}`, {
872
+ const project = tsConfigPath ? new import_ts_morph.Project({ tsConfigFilePath: tsConfigPath, skipAddingFilesFromTsConfig: true }) : new import_ts_morph.Project({ compilerOptions: { allowJs: true, strict: false } });
873
+ const patterns = ["**/*.ts", "**/*.js"].map((p) => (0, import_path2.resolve)(cwd, "**", p));
874
+ const files = await (0, import_glob.glob)(`${cwd}/**/*.{ts,js}`, {
841
875
  ignore: ["**/node_modules/**", "**/dist/**", "**/*.d.ts", "**/*.spec.*", "**/*.test.*"]
842
876
  });
843
877
  for (const file of files) {
@@ -860,7 +894,7 @@ var extractExpressRoutes = async (config) => {
860
894
  };
861
895
  var extractRoutesFromFile = (sourceFile, ctx) => {
862
896
  const routes = [];
863
- const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind3.CallExpression);
897
+ const callExpressions = sourceFile.getDescendantsOfKind(import_ts_morph.SyntaxKind.CallExpression);
864
898
  for (const call of callExpressions) {
865
899
  const route = tryExtractRoute(call, ctx);
866
900
  if (route) routes.push(route);
@@ -869,14 +903,14 @@ var extractRoutesFromFile = (sourceFile, ctx) => {
869
903
  };
870
904
  var tryExtractRoute = (call, ctx) => {
871
905
  const expr = call.getExpression();
872
- if (!Node5.isPropertyAccessExpression(expr)) return null;
906
+ if (!import_ts_morph.Node.isPropertyAccessExpression(expr)) return null;
873
907
  const methodName = expr.getName().toUpperCase();
874
908
  if (!HTTP_METHODS.includes(methodName)) return null;
875
909
  const args = call.getArguments();
876
910
  if (args.length < 2) return null;
877
911
  const firstArg = args[0];
878
912
  if (!firstArg) return null;
879
- if (!Node5.isStringLiteral(firstArg) && !Node5.isTemplateExpression(firstArg) && !Node5.isNoSubstitutionTemplateLiteral(firstArg)) {
913
+ if (!import_ts_morph.Node.isStringLiteral(firstArg) && !import_ts_morph.Node.isTemplateExpression(firstArg) && !import_ts_morph.Node.isNoSubstitutionTemplateLiteral(firstArg)) {
880
914
  return null;
881
915
  }
882
916
  const rawPath = firstArg.getText().replace(/['"'`]/g, "");
@@ -1077,50 +1111,51 @@ var matchesGlob = (path, pattern) => {
1077
1111
  var capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
1078
1112
 
1079
1113
  // src/generate.ts
1114
+ var import_meta = {};
1080
1115
  var generate = async (opts = {}) => {
1081
1116
  const cwd = process.cwd();
1082
- const spinner = opts.quiet ? null : ora();
1117
+ const spinner = opts.quiet ? null : (0, import_ora.default)();
1083
1118
  spinner?.start("Loading flowdoc config...");
1084
- const configPath = opts.config ? resolve3(cwd, opts.config) : findConfigFile(cwd);
1119
+ const configPath = opts.config ? (0, import_path3.resolve)(cwd, opts.config) : findConfigFile(cwd);
1085
1120
  if (!configPath) {
1086
- spinner?.fail(chalk.red("No flowdoc.config.ts found. Run `flowdoc init` first."));
1121
+ spinner?.fail(import_chalk.default.red("No flowdoc.config.ts found. Run `flowdoc init` first."));
1087
1122
  process.exit(1);
1088
1123
  }
1089
1124
  let rawConfig;
1090
1125
  try {
1091
1126
  rawConfig = await loadConfig(configPath);
1092
1127
  } catch (err) {
1093
- spinner?.fail(chalk.red(`Failed to load config: ${String(err)}`));
1128
+ spinner?.fail(import_chalk.default.red(`Failed to load config: ${String(err)}`));
1094
1129
  process.exit(1);
1095
1130
  }
1096
1131
  const config = resolveConfig(rawConfig, cwd);
1097
- spinner?.succeed(`Config loaded \u2014 ${chalk.cyan(config.name)}`);
1098
- spinner?.start(`Scanning ${chalk.cyan(config.entry)} for routes...`);
1132
+ spinner?.succeed(`Config loaded \u2014 ${import_chalk.default.cyan(config.name)}`);
1133
+ spinner?.start(`Scanning ${import_chalk.default.cyan(config.entry)} for routes...`);
1099
1134
  let routes;
1100
1135
  try {
1101
1136
  routes = await extractExpressRoutes(config);
1102
1137
  } catch (err) {
1103
- spinner?.fail(chalk.red(`Parse failed: ${String(err)}`));
1138
+ spinner?.fail(import_chalk.default.red(`Parse failed: ${String(err)}`));
1104
1139
  process.exit(1);
1105
1140
  }
1106
1141
  spinner?.succeed(
1107
- `Found ${chalk.green(String(routes.length))} routes across ${chalk.cyan(config.framework)} app`
1142
+ `Found ${import_chalk.default.green(String(routes.length))} routes across ${import_chalk.default.cyan(config.framework)} app`
1108
1143
  );
1109
1144
  const spec = buildSpec(routes, config);
1110
- const outputDir = opts.output ? resolve3(cwd, opts.output) : config.output ?? resolve3(cwd, "docs-output");
1111
- mkdirSync(outputDir, { recursive: true });
1112
- const specPath = join3(outputDir, "flowdoc.json");
1113
- writeFileSync(specPath, JSON.stringify(spec, null, 2), "utf-8");
1145
+ const outputDir = opts.output ? (0, import_path3.resolve)(cwd, opts.output) : config.output ?? (0, import_path3.resolve)(cwd, "docs-output");
1146
+ (0, import_fs3.mkdirSync)(outputDir, { recursive: true });
1147
+ const specPath = (0, import_path3.join)(outputDir, "flowdoc.json");
1148
+ (0, import_fs3.writeFileSync)(specPath, JSON.stringify(spec, null, 2), "utf-8");
1114
1149
  await writeUiHtml(outputDir, config);
1115
1150
  if (!opts.quiet) {
1116
1151
  console.log();
1117
- console.log(chalk.bold(" flowdoc generated successfully"));
1152
+ console.log(import_chalk.default.bold(" flowdoc generated successfully"));
1118
1153
  console.log();
1119
- console.log(` ${chalk.gray("Spec:")} ${chalk.cyan(specPath)}`);
1120
- console.log(` ${chalk.gray("UI:")} ${chalk.cyan(join3(outputDir, "index.html"))}`);
1154
+ console.log(` ${import_chalk.default.gray("Spec:")} ${import_chalk.default.cyan(specPath)}`);
1155
+ console.log(` ${import_chalk.default.gray("UI:")} ${import_chalk.default.cyan((0, import_path3.join)(outputDir, "index.html"))}`);
1121
1156
  console.log();
1122
- console.log(` ${chalk.gray("Routes:")} ${chalk.green(String(routes.length))}`);
1123
- console.log(` ${chalk.gray("Groups:")} ${chalk.green(String(spec.groups.length))}`);
1157
+ console.log(` ${import_chalk.default.gray("Routes:")} ${import_chalk.default.green(String(routes.length))}`);
1158
+ console.log(` ${import_chalk.default.gray("Groups:")} ${import_chalk.default.green(String(spec.groups.length))}`);
1124
1159
  console.log();
1125
1160
  }
1126
1161
  return spec;
@@ -1129,15 +1164,15 @@ var writeUiHtml = async (outputDir, config) => {
1129
1164
  const brand = config.theme?.brand ?? "#6366f1";
1130
1165
  const title = config.name;
1131
1166
  const darkMode = config.theme?.darkMode !== false;
1132
- const cliRoot = dirname2(dirname2(fileURLToPath(import.meta.url)));
1133
- const uiAssetsSource = join3(cliRoot, "ui-assets");
1134
- const uiAssetsDest = join3(outputDir, "assets");
1135
- if (existsSync3(uiAssetsSource)) {
1136
- mkdirSync(uiAssetsDest, { recursive: true });
1137
- cpSync(uiAssetsSource, uiAssetsDest, { recursive: true });
1167
+ const cliRoot = (0, import_path3.dirname)((0, import_path3.dirname)((0, import_url.fileURLToPath)(import_meta.url)));
1168
+ const uiAssetsSource = (0, import_path3.join)(cliRoot, "ui-assets");
1169
+ const uiAssetsDest = (0, import_path3.join)(outputDir, "assets");
1170
+ if ((0, import_fs3.existsSync)(uiAssetsSource)) {
1171
+ (0, import_fs3.mkdirSync)(uiAssetsDest, { recursive: true });
1172
+ (0, import_fs3.cpSync)(uiAssetsSource, uiAssetsDest, { recursive: true });
1138
1173
  }
1139
1174
  const html = generateHtmlShell({ title, brand, darkMode });
1140
- writeFileSync(join3(outputDir, "index.html"), html, "utf-8");
1175
+ (0, import_fs3.writeFileSync)((0, import_path3.join)(outputDir, "index.html"), html, "utf-8");
1141
1176
  };
1142
1177
  var generateHtmlShell = ({ title, brand, darkMode }) => `<!DOCTYPE html>
1143
1178
  <html lang="en" class="${darkMode ? "dark" : ""}">
@@ -1158,9 +1193,218 @@ var generateHtmlShell = ({ title, brand, darkMode }) => `<!DOCTYPE html>
1158
1193
  </body>
1159
1194
  </html>`;
1160
1195
 
1161
- export {
1162
- findConfigFile,
1163
- loadConfig,
1164
- resolveConfig,
1165
- generate
1196
+ // src/serve.ts
1197
+ var import_http = require("http");
1198
+ var import_fs4 = require("fs");
1199
+ var import_path4 = require("path");
1200
+ var import_chalk2 = __toESM(require("chalk"), 1);
1201
+ var import_open = __toESM(require("open"), 1);
1202
+ var import_chokidar = __toESM(require("chokidar"), 1);
1203
+ var MIME_TYPES = {
1204
+ ".html": "text/html",
1205
+ ".js": "application/javascript",
1206
+ ".css": "text/css",
1207
+ ".json": "application/json",
1208
+ ".svg": "image/svg+xml",
1209
+ ".png": "image/png",
1210
+ ".ico": "image/x-icon"
1166
1211
  };
1212
+ var serve = async (opts = {}) => {
1213
+ const cwd = process.cwd();
1214
+ const outputDir = opts.output ?? (0, import_path4.join)(cwd, "docs-output");
1215
+ const port = opts.port ?? 4e3;
1216
+ await generate({ ...opts, quiet: false });
1217
+ const server = (0, import_http.createServer)((req, res) => {
1218
+ const url = req.url === "/" || req.url === "" ? "/index.html" : req.url ?? "/index.html";
1219
+ const filePath = (0, import_path4.join)(outputDir, url);
1220
+ if (!(0, import_fs4.existsSync)(filePath)) {
1221
+ res.writeHead(404);
1222
+ res.end("Not found");
1223
+ return;
1224
+ }
1225
+ const ext = (0, import_path4.extname)(filePath);
1226
+ const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
1227
+ res.writeHead(200, { "Content-Type": contentType });
1228
+ (0, import_fs4.createReadStream)(filePath).pipe(res);
1229
+ });
1230
+ server.listen(port, () => {
1231
+ const url = `http://localhost:${port}`;
1232
+ console.log();
1233
+ console.log(` ${import_chalk2.default.bold("flowdoc")} is running at ${import_chalk2.default.cyan(url)}`);
1234
+ if (opts.watch) {
1235
+ console.log(` ${import_chalk2.default.dim("watching for changes\u2026")}`);
1236
+ }
1237
+ console.log();
1238
+ if (!opts.noOpen) {
1239
+ void (0, import_open.default)(url);
1240
+ }
1241
+ });
1242
+ if (!opts.watch) return;
1243
+ const configPath = opts.config ?? findConfigFile(cwd) ?? "";
1244
+ let watchGlob = "src/**/*.ts";
1245
+ if (configPath) {
1246
+ try {
1247
+ const raw = await loadConfig(configPath);
1248
+ const config = resolveConfig(raw, cwd);
1249
+ const entryDir = (0, import_path4.resolve)(cwd, config.entry).replace(/\/[^/]+$/, "");
1250
+ watchGlob = `${entryDir}/**/*.ts`;
1251
+ } catch {
1252
+ }
1253
+ }
1254
+ let rebuilding = false;
1255
+ const watcher = import_chokidar.default.watch(watchGlob, {
1256
+ ignoreInitial: true,
1257
+ ignored: ["**/node_modules/**", "**/dist/**", "**/docs-output/**"]
1258
+ });
1259
+ const rebuild = async (filePath) => {
1260
+ if (rebuilding) return;
1261
+ rebuilding = true;
1262
+ console.log(` ${import_chalk2.default.dim("\u2192")} ${import_chalk2.default.yellow(filePath.replace(cwd + "/", ""))} changed \u2014 regenerating\u2026`);
1263
+ try {
1264
+ await generate({ ...opts, quiet: true });
1265
+ console.log(` ${import_chalk2.default.green("\u2713")} docs updated`);
1266
+ } catch (err) {
1267
+ console.error(` ${import_chalk2.default.red("\u2717")} regeneration failed:`, err instanceof Error ? err.message : err);
1268
+ } finally {
1269
+ rebuilding = false;
1270
+ }
1271
+ };
1272
+ watcher.on("add", rebuild).on("change", rebuild).on("unlink", rebuild);
1273
+ process.on("SIGINT", () => {
1274
+ void watcher.close();
1275
+ server.close();
1276
+ process.exit(0);
1277
+ });
1278
+ };
1279
+
1280
+ // src/init.ts
1281
+ var import_fs5 = require("fs");
1282
+ var import_path5 = require("path");
1283
+ var import_chalk3 = __toESM(require("chalk"), 1);
1284
+ var CONFIG_TEMPLATE = `import { defineConfig } from "flowdoc-gen";
1285
+
1286
+ export default defineConfig({
1287
+ name: "My API",
1288
+ version: "1.0.0",
1289
+ description: "API documentation generated by flowdoc",
1290
+ framework: "express",
1291
+ entry: "./src",
1292
+ output: "./docs-output",
1293
+ theme: {
1294
+ brand: "#6366f1",
1295
+ darkMode: true,
1296
+ },
1297
+ // groups: [
1298
+ // { name: "Auth", match: "/auth/**" },
1299
+ // { name: "Users", match: "/users/**" },
1300
+ // ],
1301
+ });
1302
+ `;
1303
+ var init = (cwd = process.cwd()) => {
1304
+ const configPath = (0, import_path5.resolve)(cwd, "flowdoc.config.ts");
1305
+ if ((0, import_fs5.existsSync)(configPath)) {
1306
+ console.log(import_chalk3.default.yellow(" flowdoc.config.ts already exists \u2014 skipping."));
1307
+ return;
1308
+ }
1309
+ (0, import_fs5.writeFileSync)(configPath, CONFIG_TEMPLATE, "utf-8");
1310
+ console.log();
1311
+ console.log(` ${import_chalk3.default.bold("flowdoc")} initialized`);
1312
+ console.log();
1313
+ console.log(` Created ${import_chalk3.default.cyan("flowdoc.config.ts")}`);
1314
+ console.log();
1315
+ console.log(" Next steps:");
1316
+ console.log(` 1. Edit ${import_chalk3.default.cyan("flowdoc.config.ts")} \u2014 set your entry path`);
1317
+ console.log(` 2. Run ${import_chalk3.default.cyan("flowdoc generate")} to build your docs`);
1318
+ console.log(` 3. Run ${import_chalk3.default.cyan("flowdoc serve")} to preview locally`);
1319
+ console.log();
1320
+ };
1321
+
1322
+ // src/middleware.ts
1323
+ var import_fs6 = require("fs");
1324
+ var import_path6 = require("path");
1325
+ var import_url2 = require("url");
1326
+ var import_meta2 = {};
1327
+ var MIME = {
1328
+ ".html": "text/html",
1329
+ ".js": "application/javascript",
1330
+ ".css": "text/css",
1331
+ ".json": "application/json"
1332
+ };
1333
+ var flowdoc = (opts = {}) => {
1334
+ const cwd = process.cwd();
1335
+ let outputDir = null;
1336
+ let ready = false;
1337
+ let initError = null;
1338
+ const init2 = (async () => {
1339
+ try {
1340
+ const configPath = opts.config ?? findConfigFile(cwd);
1341
+ if (!configPath) throw new Error("No flowdoc.config.ts found. Run `flowdoc init` first.");
1342
+ const rawConfig = await loadConfig(configPath);
1343
+ const config = resolveConfig(rawConfig, cwd);
1344
+ outputDir = config.output ?? (0, import_path6.join)(cwd, "docs-output");
1345
+ const routes = await extractExpressRoutes(config);
1346
+ const spec = buildSpec(routes, config);
1347
+ (0, import_fs6.mkdirSync)(outputDir, { recursive: true });
1348
+ (0, import_fs6.writeFileSync)((0, import_path6.join)(outputDir, "flowdoc.json"), JSON.stringify(spec, null, 2));
1349
+ const cliRoot = (0, import_path6.dirname)((0, import_path6.dirname)((0, import_url2.fileURLToPath)(import_meta2.url)));
1350
+ const uiAssetsSource = (0, import_path6.join)(cliRoot, "ui-assets");
1351
+ if ((0, import_fs6.existsSync)(uiAssetsSource)) {
1352
+ const dest = (0, import_path6.join)(outputDir, "assets");
1353
+ (0, import_fs6.mkdirSync)(dest, { recursive: true });
1354
+ (0, import_fs6.cpSync)(uiAssetsSource, dest, { recursive: true });
1355
+ }
1356
+ ready = true;
1357
+ } catch (err) {
1358
+ initError = err instanceof Error ? err.message : String(err);
1359
+ }
1360
+ })();
1361
+ return async (req, res, next) => {
1362
+ await init2;
1363
+ if (initError || !outputDir) {
1364
+ res.status(500).send(`flowdoc init failed: ${initError}`);
1365
+ return;
1366
+ }
1367
+ const urlPath = req.path === "/" || req.path === "" ? "/index.html" : req.path;
1368
+ if (urlPath === "/index.html") {
1369
+ const brand = "#6366f1";
1370
+ const baseUrl = `${req.protocol}://${req.get("host")}`;
1371
+ res.setHeader("Content-Type", "text/html");
1372
+ res.send(buildHtml({ baseUrl, brand }));
1373
+ return;
1374
+ }
1375
+ const filePath = (0, import_path6.join)(outputDir, urlPath);
1376
+ if (!(0, import_fs6.existsSync)(filePath)) {
1377
+ next();
1378
+ return;
1379
+ }
1380
+ const mime = MIME[(0, import_path6.extname)(filePath)] ?? "application/octet-stream";
1381
+ res.setHeader("Content-Type", mime);
1382
+ (0, import_fs6.createReadStream)(filePath).pipe(res);
1383
+ };
1384
+ };
1385
+ var buildHtml = ({ baseUrl, brand }) => `<!DOCTYPE html>
1386
+ <html lang="en" class="dark">
1387
+ <head>
1388
+ <meta charset="UTF-8" />
1389
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
1390
+ <title>API Docs</title>
1391
+ <script>
1392
+ window.__FLOWDOC_BRAND__ = "${brand}";
1393
+ window.__FLOWDOC_BASE_URL__ = "${baseUrl}";
1394
+ </script>
1395
+ <script type="module" crossorigin src="./assets/ui.js"></script>
1396
+ <link rel="stylesheet" href="./assets/index.css" />
1397
+ </head>
1398
+ <body><div id="root"></div></body>
1399
+ </html>`;
1400
+
1401
+ // src/index.ts
1402
+ var defineConfig = (config) => config;
1403
+ // Annotate the CommonJS export names for ESM import in node:
1404
+ 0 && (module.exports = {
1405
+ defineConfig,
1406
+ flowdoc,
1407
+ generate,
1408
+ init,
1409
+ serve
1410
+ });