@boon4681/giri 0.0.2-alpha-7 → 0.0.2-alpha-8

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/index.js CHANGED
@@ -45,12 +45,18 @@ var init_es5 = __esm({
45
45
  });
46
46
 
47
47
  // src/generator/schema/program.ts
48
- function createSchemaProgram(paths, routeFiles) {
48
+ function leanOptions(options) {
49
+ return {
50
+ ...options,
51
+ types: []
52
+ };
53
+ }
54
+ function createSchemaProgram(paths, routeFiles, programOptions = {}) {
49
55
  let options = { ...DEFAULT_OPTIONS };
50
- const configPath = import_typescript.default.findConfigFile(paths.cwd, import_typescript.default.sys.fileExists, "tsconfig.json");
56
+ const configPath = import_typescript2.default.findConfigFile(paths.cwd, import_typescript2.default.sys.fileExists, "tsconfig.json");
51
57
  if (configPath) {
52
- const parsed = import_typescript.default.getParsedCommandLineOfConfigFile(configPath, {}, {
53
- ...import_typescript.default.sys,
58
+ const parsed = import_typescript2.default.getParsedCommandLineOfConfigFile(configPath, {}, {
59
+ ...import_typescript2.default.sys,
54
60
  onUnRecoverableConfigFileDiagnostic: () => {
55
61
  }
56
62
  });
@@ -58,17 +64,20 @@ function createSchemaProgram(paths, routeFiles) {
58
64
  options = { ...parsed.options, noEmit: true };
59
65
  }
60
66
  }
61
- return import_typescript.default.createProgram(routeFiles, options);
67
+ if (programOptions.lean) {
68
+ options = leanOptions(options);
69
+ }
70
+ return import_typescript2.default.createProgram(routeFiles, options);
62
71
  }
63
- var import_typescript, DEFAULT_OPTIONS;
72
+ var import_typescript2, DEFAULT_OPTIONS;
64
73
  var init_program = __esm({
65
74
  "src/generator/schema/program.ts"() {
66
75
  "use strict";
67
- import_typescript = __toESM(require("typescript"));
76
+ import_typescript2 = __toESM(require("typescript"));
68
77
  DEFAULT_OPTIONS = {
69
- target: import_typescript.default.ScriptTarget.ES2022,
70
- module: import_typescript.default.ModuleKind.NodeNext,
71
- moduleResolution: import_typescript.default.ModuleResolutionKind.NodeNext,
78
+ target: import_typescript2.default.ScriptTarget.ES2022,
79
+ module: import_typescript2.default.ModuleKind.NodeNext,
80
+ moduleResolution: import_typescript2.default.ModuleResolutionKind.NodeNext,
72
81
  strict: true,
73
82
  skipLibCheck: true,
74
83
  noEmit: true
@@ -102,7 +111,7 @@ function literalValuesOf(types) {
102
111
  for (const member of types) {
103
112
  if (member.isStringLiteral() || member.isNumberLiteral()) {
104
113
  values.push(member.value);
105
- } else if (member.flags & import_typescript2.default.TypeFlags.BooleanLiteral) {
114
+ } else if (member.flags & import_typescript3.default.TypeFlags.BooleanLiteral) {
106
115
  values.push(intrinsicName(member) === "true");
107
116
  } else {
108
117
  return void 0;
@@ -111,7 +120,7 @@ function literalValuesOf(types) {
111
120
  return values;
112
121
  }
113
122
  function walkUnion(type, ctx) {
114
- const flag = import_typescript2.default.TypeFlags.Undefined | import_typescript2.default.TypeFlags.Void | import_typescript2.default.TypeFlags.Never;
123
+ const flag = import_typescript3.default.TypeFlags.Undefined | import_typescript3.default.TypeFlags.Void | import_typescript3.default.TypeFlags.Never;
115
124
  const members = type.types.filter((member) => !(member.flags & flag));
116
125
  if (members.length === 1) {
117
126
  return walkType(members[0], ctx);
@@ -124,13 +133,13 @@ function walkUnion(type, ctx) {
124
133
  }
125
134
  function buildObjectSchema(type, ctx) {
126
135
  const { checker } = ctx;
127
- const indexInfo = checker.getIndexInfoOfType(type, import_typescript2.default.IndexKind.String) ?? checker.getIndexInfoOfType(type, import_typescript2.default.IndexKind.Number);
136
+ const indexInfo = checker.getIndexInfoOfType(type, import_typescript3.default.IndexKind.String) ?? checker.getIndexInfoOfType(type, import_typescript3.default.IndexKind.Number);
128
137
  const properties = {};
129
138
  const required = [];
130
139
  for (const symbol of checker.getPropertiesOfType(type)) {
131
140
  const name = symbol.getName();
132
141
  const propType = checker.getTypeOfSymbolAtLocation(symbol, ctx.location);
133
- const optional = Boolean(symbol.getFlags() & import_typescript2.default.SymbolFlags.Optional) || Boolean(propType.flags & import_typescript2.default.TypeFlags.Union && propType.types.some((t) => t.flags & import_typescript2.default.TypeFlags.Undefined));
142
+ const optional = Boolean(symbol.getFlags() & import_typescript3.default.SymbolFlags.Optional) || Boolean(propType.flags & import_typescript3.default.TypeFlags.Union && propType.types.some((t) => t.flags & import_typescript3.default.TypeFlags.Undefined));
134
143
  properties[name] = walkType(propType, ctx);
135
144
  if (!optional) {
136
145
  required.push(name);
@@ -189,16 +198,16 @@ function walkObject(type, ctx) {
189
198
  }
190
199
  function walkType(type, ctx) {
191
200
  const flags = type.flags;
192
- if (flags & (import_typescript2.default.TypeFlags.Any | import_typescript2.default.TypeFlags.Unknown)) {
201
+ if (flags & (import_typescript3.default.TypeFlags.Any | import_typescript3.default.TypeFlags.Unknown)) {
193
202
  return {};
194
203
  }
195
- if (flags & import_typescript2.default.TypeFlags.Null) {
204
+ if (flags & import_typescript3.default.TypeFlags.Null) {
196
205
  return { type: "null" };
197
206
  }
198
- if (flags & (import_typescript2.default.TypeFlags.Undefined | import_typescript2.default.TypeFlags.Void)) {
207
+ if (flags & (import_typescript3.default.TypeFlags.Undefined | import_typescript3.default.TypeFlags.Void)) {
199
208
  return {};
200
209
  }
201
- if (flags & (import_typescript2.default.TypeFlags.BigInt | import_typescript2.default.TypeFlags.BigIntLiteral)) {
210
+ if (flags & (import_typescript3.default.TypeFlags.BigInt | import_typescript3.default.TypeFlags.BigIntLiteral)) {
202
211
  ctx.warnings.push("bigint is not JSON-serializable (JSON.stringify throws); documented as string.");
203
212
  return { type: "string" };
204
213
  }
@@ -208,45 +217,45 @@ function walkType(type, ctx) {
208
217
  if (type.isNumberLiteral()) {
209
218
  return { type: "number", const: type.value };
210
219
  }
211
- if (flags & import_typescript2.default.TypeFlags.BooleanLiteral) {
220
+ if (flags & import_typescript3.default.TypeFlags.BooleanLiteral) {
212
221
  return { type: "boolean", const: intrinsicName(type) === "true" };
213
222
  }
214
- if (flags & import_typescript2.default.TypeFlags.String) {
223
+ if (flags & import_typescript3.default.TypeFlags.String) {
215
224
  return { type: "string" };
216
225
  }
217
- if (flags & import_typescript2.default.TypeFlags.Number) {
226
+ if (flags & import_typescript3.default.TypeFlags.Number) {
218
227
  return { type: "number" };
219
228
  }
220
- if (flags & import_typescript2.default.TypeFlags.Boolean) {
229
+ if (flags & import_typescript3.default.TypeFlags.Boolean) {
221
230
  return { type: "boolean" };
222
231
  }
223
232
  if (type.isUnion()) {
224
233
  return walkUnion(type, ctx);
225
234
  }
226
- if (flags & import_typescript2.default.TypeFlags.Object || type.isIntersection()) {
235
+ if (flags & import_typescript3.default.TypeFlags.Object || type.isIntersection()) {
227
236
  return walkObject(type, ctx);
228
237
  }
229
238
  return {};
230
239
  }
231
- var import_typescript2;
240
+ var import_typescript3;
232
241
  var init_json_schema = __esm({
233
242
  "src/generator/schema/json-schema.ts"() {
234
243
  "use strict";
235
- import_typescript2 = __toESM(require("typescript"));
244
+ import_typescript3 = __toESM(require("typescript"));
236
245
  }
237
246
  });
238
247
 
239
248
  // src/generator/schema/responses.ts
240
249
  function findHandleFunction(source) {
241
250
  let found;
242
- const isExported = (node) => import_typescript3.default.canHaveModifiers(node) && (import_typescript3.default.getModifiers(node)?.some((m) => m.kind === import_typescript3.default.SyntaxKind.ExportKeyword) ?? false);
251
+ const isExported = (node) => import_typescript4.default.canHaveModifiers(node) && (import_typescript4.default.getModifiers(node)?.some((m) => m.kind === import_typescript4.default.SyntaxKind.ExportKeyword) ?? false);
243
252
  for (const statement of source.statements) {
244
- if (import_typescript3.default.isFunctionDeclaration(statement) && statement.name?.text === "handle" && isExported(statement)) {
253
+ if (import_typescript4.default.isFunctionDeclaration(statement) && statement.name?.text === "handle" && isExported(statement)) {
245
254
  found = statement;
246
255
  }
247
- if (import_typescript3.default.isVariableStatement(statement) && isExported(statement)) {
256
+ if (import_typescript4.default.isVariableStatement(statement) && isExported(statement)) {
248
257
  for (const declaration of statement.declarationList.declarations) {
249
- if (import_typescript3.default.isIdentifier(declaration.name) && declaration.name.text === "handle" && declaration.initializer && (import_typescript3.default.isArrowFunction(declaration.initializer) || import_typescript3.default.isFunctionExpression(declaration.initializer))) {
258
+ if (import_typescript4.default.isIdentifier(declaration.name) && declaration.name.text === "handle" && declaration.initializer && (import_typescript4.default.isArrowFunction(declaration.initializer) || import_typescript4.default.isFunctionExpression(declaration.initializer))) {
250
259
  found = declaration.initializer;
251
260
  }
252
261
  }
@@ -255,7 +264,7 @@ function findHandleFunction(source) {
255
264
  return found;
256
265
  }
257
266
  function collectReturnExpressions(fn) {
258
- if (import_typescript3.default.isArrowFunction(fn) && !import_typescript3.default.isBlock(fn.body)) {
267
+ if (import_typescript4.default.isArrowFunction(fn) && !import_typescript4.default.isBlock(fn.body)) {
259
268
  return [fn.body];
260
269
  }
261
270
  if (!fn.body) {
@@ -263,15 +272,15 @@ function collectReturnExpressions(fn) {
263
272
  }
264
273
  const expressions = [];
265
274
  const visit = (node) => {
266
- if (import_typescript3.default.isFunctionDeclaration(node) || import_typescript3.default.isFunctionExpression(node) || import_typescript3.default.isArrowFunction(node)) {
275
+ if (import_typescript4.default.isFunctionDeclaration(node) || import_typescript4.default.isFunctionExpression(node) || import_typescript4.default.isArrowFunction(node)) {
267
276
  return;
268
277
  }
269
- if (import_typescript3.default.isReturnStatement(node) && node.expression) {
278
+ if (import_typescript4.default.isReturnStatement(node) && node.expression) {
270
279
  expressions.push(node.expression);
271
280
  }
272
- import_typescript3.default.forEachChild(node, visit);
281
+ import_typescript4.default.forEachChild(node, visit);
273
282
  };
274
- import_typescript3.default.forEachChild(fn.body, visit);
283
+ import_typescript4.default.forEachChild(fn.body, visit);
275
284
  return expressions;
276
285
  }
277
286
  function propertyType(checker, type, name, location) {
@@ -283,15 +292,21 @@ function isTypedResponse2(checker, type) {
283
292
  checker.getPropertyOfType(type, "data") && checker.getPropertyOfType(type, "status") && checker.getPropertyOfType(type, "format")
284
293
  );
285
294
  }
286
- function readFromCall(checker, expression) {
287
- if (!import_typescript3.default.isCallExpression(expression) || !import_typescript3.default.isPropertyAccessExpression(expression.expression)) {
295
+ function firstParameterName(fn) {
296
+ const [first] = fn.parameters;
297
+ return first && import_typescript4.default.isIdentifier(first.name) ? first.name.text : void 0;
298
+ }
299
+ function readFromCall(checker, expression, contextName) {
300
+ if (!import_typescript4.default.isCallExpression(expression) || !import_typescript4.default.isPropertyAccessExpression(expression.expression)) {
288
301
  return void 0;
289
302
  }
290
303
  const method = expression.expression.name.text;
291
304
  if (method !== "json" && method !== "text") {
292
305
  return void 0;
293
306
  }
294
- if (!isTypedResponse2(checker, checker.getTypeAtLocation(expression))) {
307
+ const target = expression.expression.expression;
308
+ const directContextCall = contextName && import_typescript4.default.isIdentifier(target) && target.text === contextName;
309
+ if (!directContextCall && !isTypedResponse2(checker, checker.getTypeAtLocation(expression))) {
295
310
  return void 0;
296
311
  }
297
312
  const [dataArg, statusArg] = expression.arguments;
@@ -331,6 +346,7 @@ function extractRouteResponses(program, file) {
331
346
  return result;
332
347
  }
333
348
  const ctx = createWalkContext(checker, fn);
349
+ const contextName = firstParameterName(fn);
334
350
  const byStatus = /* @__PURE__ */ new Map();
335
351
  const record = (hit) => {
336
352
  const schema = walkType(hit.data, ctx);
@@ -339,7 +355,7 @@ function extractRouteResponses(program, file) {
339
355
  byStatus.set(hit.status, bucket);
340
356
  };
341
357
  for (const expression of collectReturnExpressions(fn)) {
342
- const fromCall = readFromCall(checker, expression);
358
+ const fromCall = readFromCall(checker, expression, contextName);
343
359
  if (fromCall) {
344
360
  record(fromCall);
345
361
  continue;
@@ -365,11 +381,11 @@ function extractRouteResponses(program, file) {
365
381
  result.$defs = ctx.defs;
366
382
  return result;
367
383
  }
368
- var import_typescript3;
384
+ var import_typescript4;
369
385
  var init_responses = __esm({
370
386
  "src/generator/schema/responses.ts"() {
371
387
  "use strict";
372
- import_typescript3 = __toESM(require("typescript"));
388
+ import_typescript4 = __toESM(require("typescript"));
373
389
  init_json_schema();
374
390
  }
375
391
  });
@@ -827,13 +843,18 @@ function methodFromFile(fileName) {
827
843
  const stem = fileName.replace(/\.(?:[cm]?[jt]s|[jt]sx)$/, "").toLowerCase();
828
844
  return METHOD_FROM_FILE.get(stem);
829
845
  }
830
- function sharedFileIn(dir) {
846
+ function sharedFileIn(dir, cache) {
847
+ if (cache?.has(dir)) {
848
+ return cache.get(dir);
849
+ }
831
850
  for (const ext of ["ts", "tsx", "js", "jsx", "mjs", "cjs", "mts", "cts"]) {
832
851
  const file = (0, import_node_path2.join)(dir, `+shared.${ext}`);
833
852
  if ((0, import_node_fs2.existsSync)(file)) {
853
+ cache?.set(dir, file);
834
854
  return file;
835
855
  }
836
856
  }
857
+ cache?.set(dir, void 0);
837
858
  return void 0;
838
859
  }
839
860
  function physicalRouteSegments(routesDir, routeDir) {
@@ -902,7 +923,7 @@ async function scanRouteFolders(routesDir) {
902
923
  function routeParamsForDir(routesDir, dir) {
903
924
  return pathFromSegments(physicalRouteSegments(routesDir, dir)).params;
904
925
  }
905
- function sharedFilesForDir(routesDir, dir) {
926
+ function sharedFilesForDir(routesDir, dir, cache) {
906
927
  const segments = physicalRouteSegments(routesDir, dir);
907
928
  const dirs = [routesDir];
908
929
  let current = routesDir;
@@ -910,7 +931,7 @@ function sharedFilesForDir(routesDir, dir) {
910
931
  current = (0, import_node_path2.join)(current, segment);
911
932
  dirs.push(current);
912
933
  }
913
- return dirs.map(sharedFileIn).filter((file) => Boolean(file));
934
+ return dirs.map((currentDir) => sharedFileIn(currentDir, cache)).filter((file) => Boolean(file));
914
935
  }
915
936
  async function scanRoutes(routesDir) {
916
937
  if (!(0, import_node_fs2.existsSync)(routesDir)) {
@@ -922,6 +943,7 @@ async function scanRoutes(routesDir) {
922
943
  onlyFiles: true
923
944
  });
924
945
  const routes = [];
946
+ const sharedCache = /* @__PURE__ */ new Map();
925
947
  for (const file of files) {
926
948
  const method = methodFromFile((0, import_node_path2.basename)(file));
927
949
  if (!method) {
@@ -937,7 +959,7 @@ async function scanRoutes(routesDir) {
937
959
  routeDir,
938
960
  routeSegments,
939
961
  params,
940
- sharedFiles: sharedFilesForDir(routesDir, routeDir)
962
+ sharedFiles: sharedFilesForDir(routesDir, routeDir, sharedCache)
941
963
  });
942
964
  }
943
965
  return routes.sort((left, right) => {
@@ -950,9 +972,11 @@ async function scanRoutes(routesDir) {
950
972
  }
951
973
 
952
974
  // src/app.ts
953
- function loadModule(file) {
975
+ function loadModule(file, force = true) {
954
976
  const resolved = require.resolve(file);
955
- delete require.cache[resolved];
977
+ if (force) {
978
+ delete require.cache[resolved];
979
+ }
956
980
  return require(resolved);
957
981
  }
958
982
  function interopDefault(value) {
@@ -1087,13 +1111,23 @@ async function buildGiriApp(config, options = {}) {
1087
1111
  const { unregister } = await safeRegister();
1088
1112
  const unregisterAliasResolver = registerAliasResolver(config.alias, paths.cwd);
1089
1113
  try {
1114
+ const dirty = options.dirty;
1115
+ const forceReload = dirty === void 0;
1116
+ const isDirty = (file) => forceReload || dirty.has(file);
1117
+ const sharedCache = /* @__PURE__ */ new Map();
1118
+ const loadShared = (file) => {
1119
+ if (!sharedCache.has(file)) {
1120
+ sharedCache.set(file, loadModule(file, isDirty(file)));
1121
+ }
1122
+ return sharedCache.get(file);
1123
+ };
1090
1124
  for (const route of routes) {
1091
- const routeModule = loadModule(route.file);
1125
+ const routeModule = loadModule(route.file, isDirty(route.file));
1092
1126
  if (typeof routeModule.handle !== "function") {
1093
1127
  throw new Error(`${route.file} must export a named handle function.`);
1094
1128
  }
1095
1129
  const folderMiddleware = routeModule.config?.skipInherited ? [] : route.sharedFiles.flatMap(
1096
- (file) => normalizeMiddleware(loadModule(file).middleware, file)
1130
+ (file) => normalizeMiddleware(loadShared(file).middleware, file)
1097
1131
  );
1098
1132
  const verbMiddleware = normalizeMiddleware(routeModule.middleware, route.file);
1099
1133
  config.adapter.register(app, {
@@ -1114,7 +1148,7 @@ async function buildGiriApp(config, options = {}) {
1114
1148
  }
1115
1149
 
1116
1150
  // src/generator/sync.ts
1117
- var import_node_fs6 = require("fs");
1151
+ var import_node_fs7 = require("fs");
1118
1152
  var import_promises3 = require("fs/promises");
1119
1153
  var import_node_path11 = require("path");
1120
1154
 
@@ -1368,6 +1402,7 @@ function buildOpenApiDocument(paths, routes, data = {}) {
1368
1402
  const documentPaths = {};
1369
1403
  const schemas = {};
1370
1404
  const securitySchemes = {};
1405
+ const tagOrder = [];
1371
1406
  for (const route of routes) {
1372
1407
  if (data.hiddenFiles?.has(route.file)) {
1373
1408
  continue;
@@ -1375,10 +1410,32 @@ function buildOpenApiDocument(paths, routes, data = {}) {
1375
1410
  const responses = data.responsesByFile?.get(route.file);
1376
1411
  const input = data.inputsByFile?.get(route.file);
1377
1412
  const security = data.securityByFile?.get(route.file);
1413
+ const meta = data.openapiByFile?.get(route.file);
1378
1414
  for (const [name, schema] of Object.entries(responses?.$defs ?? {})) {
1379
1415
  schemas[name] = rewriteRefs(schema);
1380
1416
  }
1381
- const operation = { responses: buildResponses(responses?.responses ?? []) };
1417
+ const operation = {};
1418
+ if (meta?.tags && meta.tags.length > 0) {
1419
+ operation.tags = meta.tags;
1420
+ for (const tag of meta.tags) {
1421
+ if (!tagOrder.includes(tag)) {
1422
+ tagOrder.push(tag);
1423
+ }
1424
+ }
1425
+ }
1426
+ if (meta?.summary) {
1427
+ operation.summary = meta.summary;
1428
+ }
1429
+ if (meta?.description) {
1430
+ operation.description = meta.description;
1431
+ }
1432
+ if (meta?.operationId) {
1433
+ operation.operationId = meta.operationId;
1434
+ }
1435
+ if (meta?.deprecated) {
1436
+ operation.deprecated = true;
1437
+ }
1438
+ operation.responses = buildResponses(responses?.responses ?? []);
1382
1439
  const parameters = [...pathParameters(route), ...queryParameters(input?.query)];
1383
1440
  if (parameters.length > 0) {
1384
1441
  operation.parameters = parameters;
@@ -1410,6 +1467,9 @@ function buildOpenApiDocument(paths, routes, data = {}) {
1410
1467
  info: readProjectInfo(paths.cwd),
1411
1468
  paths: documentPaths
1412
1469
  };
1470
+ if (tagOrder.length > 0) {
1471
+ document.tags = tagOrder.map((name) => ({ name }));
1472
+ }
1413
1473
  const components = {};
1414
1474
  if (Object.keys(schemas).length > 0) {
1415
1475
  components.schemas = schemas;
@@ -1441,14 +1501,29 @@ function paramsType(params) {
1441
1501
  ${fields}
1442
1502
  }`;
1443
1503
  }
1444
- function varsType(typesDir, sharedFiles) {
1445
- if (sharedFiles.length === 0) {
1446
- return "{}";
1504
+ function middlewareVarsType(typesDir, sharedFile) {
1505
+ const spec = JSON.stringify(moduleSpecifier(typesDir, sharedFile));
1506
+ return `(typeof import(${spec}) extends { middleware: infer M } ? import("@boon4681/giri").InferStackVars<M> : {})`;
1507
+ }
1508
+ function ownSharedFile(dir, sharedFiles) {
1509
+ for (let index = sharedFiles.length - 1; index >= 0; index -= 1) {
1510
+ if ((0, import_node_path8.dirname)(sharedFiles[index]) === dir) {
1511
+ return sharedFiles[index];
1512
+ }
1447
1513
  }
1448
- return sharedFiles.map((file) => {
1449
- const spec = JSON.stringify(moduleSpecifier(typesDir, file));
1450
- return `(typeof import(${spec}) extends { middleware: infer M } ? import("@boon4681/giri").InferStackVars<M> : {})`;
1451
- }).join("\n & ");
1514
+ return void 0;
1515
+ }
1516
+ function varsType(paths, file, dir, sharedFiles) {
1517
+ const typesDir = (0, import_node_path8.dirname)(file);
1518
+ const parts = [];
1519
+ if (dir !== paths.routesDir) {
1520
+ parts.push(`import(${JSON.stringify(importPath(file, typeFilePath(paths, (0, import_node_path8.dirname)(dir))))}).Vars`);
1521
+ }
1522
+ const ownShared = ownSharedFile(dir, sharedFiles);
1523
+ if (ownShared) {
1524
+ parts.push(middlewareVarsType(typesDir, ownShared));
1525
+ }
1526
+ return parts.length > 0 ? parts.join("\n & ") : "{}";
1452
1527
  }
1453
1528
  function methodExports(typesDir, verbs) {
1454
1529
  return verbs.map(({ method, file }) => {
@@ -1459,14 +1534,14 @@ function methodExports(typesDir, verbs) {
1459
1534
  });
1460
1535
  }
1461
1536
  async function writeParamTypes(paths, folders) {
1462
- for (const { dir, params, sharedFiles, verbs } of folders) {
1537
+ await Promise.all(folders.map(({ dir, params, sharedFiles, verbs }) => {
1463
1538
  const file = typeFilePath(paths, dir);
1464
1539
  const typesDir = (0, import_node_path8.dirname)(file);
1465
1540
  const lines = [
1466
1541
  GENERATED_HEADER,
1467
1542
  `export type Params = ${paramsType(params)};`,
1468
1543
  "export type RouteParams = Params;",
1469
- `type Vars = ${varsType(typesDir, sharedFiles)};`,
1544
+ `export type Vars = ${varsType(paths, file, dir, sharedFiles)};`,
1470
1545
  "export type Middleware<Injects extends Record<string, unknown> = {}> =",
1471
1546
  ' import("@boon4681/giri").Middleware<Params, import("@boon4681/giri").ValidatedInput, Injects>;',
1472
1547
  'export type Handle<Input extends import("@boon4681/giri").ValidatedInput = import("@boon4681/giri").ValidatedInput> =',
@@ -1476,10 +1551,14 @@ async function writeParamTypes(paths, folders) {
1476
1551
  lines.push(...methodExports(typesDir, verbs));
1477
1552
  }
1478
1553
  lines.push("");
1479
- await writeGenerated(file, lines.join("\n"));
1480
- }
1554
+ return writeGenerated(file, lines.join("\n"));
1555
+ }));
1481
1556
  }
1482
1557
 
1558
+ // src/generator/route-meta.ts
1559
+ var import_node_fs6 = require("fs");
1560
+ var import_typescript = __toESM(require("typescript"));
1561
+
1483
1562
  // src/generator/inputs.ts
1484
1563
  function sanitize(schema) {
1485
1564
  const { $schema, ...rest } = schema;
@@ -1540,28 +1619,315 @@ function readInput(routeModule) {
1540
1619
  }
1541
1620
  return input.body || input.query ? input : void 0;
1542
1621
  }
1543
- function hiddenFrom(value) {
1544
- if (value === false) {
1622
+ function hasExportModifier(node) {
1623
+ return import_typescript.default.canHaveModifiers(node) && (import_typescript.default.getModifiers(node)?.some((modifier) => modifier.kind === import_typescript.default.SyntaxKind.ExportKeyword) ?? false);
1624
+ }
1625
+ function unwrapExpression(expression) {
1626
+ let current = expression;
1627
+ while (import_typescript.default.isParenthesizedExpression(current) || import_typescript.default.isAsExpression(current) || import_typescript.default.isSatisfiesExpression(current)) {
1628
+ current = current.expression;
1629
+ }
1630
+ return current;
1631
+ }
1632
+ function staticBoolean(expression) {
1633
+ const value = unwrapExpression(expression);
1634
+ if (value.kind === import_typescript.default.SyntaxKind.TrueKeyword) {
1545
1635
  return true;
1546
1636
  }
1547
- if (value === true) {
1637
+ if (value.kind === import_typescript.default.SyntaxKind.FalseKeyword) {
1548
1638
  return false;
1549
1639
  }
1550
- if (value && typeof value === "object" && "hidden" in value) {
1551
- return Boolean(value.hidden);
1640
+ return void 0;
1641
+ }
1642
+ function staticString(expression) {
1643
+ const value = unwrapExpression(expression);
1644
+ return import_typescript.default.isStringLiteralLike(value) ? value.text : void 0;
1645
+ }
1646
+ function staticStringArray(expression) {
1647
+ const value = unwrapExpression(expression);
1648
+ if (!import_typescript.default.isArrayLiteralExpression(value)) {
1649
+ return void 0;
1650
+ }
1651
+ const strings = [];
1652
+ for (const element of value.elements) {
1653
+ const string = staticString(element);
1654
+ if (string === void 0) {
1655
+ return void 0;
1656
+ }
1657
+ strings.push(string);
1658
+ }
1659
+ return strings;
1660
+ }
1661
+ function propertyName(name) {
1662
+ if (import_typescript.default.isIdentifier(name) || import_typescript.default.isStringLiteral(name) || import_typescript.default.isNumericLiteral(name)) {
1663
+ return name.text;
1552
1664
  }
1553
1665
  return void 0;
1554
1666
  }
1555
- function collectHidden(route, routeModule, loadShared) {
1667
+ function collectImportedNames(source) {
1668
+ const names = /* @__PURE__ */ new Set();
1669
+ for (const statement of source.statements) {
1670
+ if (!import_typescript.default.isImportDeclaration(statement)) {
1671
+ continue;
1672
+ }
1673
+ const clause = statement.importClause;
1674
+ if (!clause) {
1675
+ continue;
1676
+ }
1677
+ if (clause.name) {
1678
+ names.add(clause.name.text);
1679
+ }
1680
+ const bindings = clause.namedBindings;
1681
+ if (bindings && import_typescript.default.isNamespaceImport(bindings)) {
1682
+ names.add(bindings.name.text);
1683
+ }
1684
+ if (bindings && import_typescript.default.isNamedImports(bindings)) {
1685
+ for (const element of bindings.elements) {
1686
+ names.add(element.name.text);
1687
+ }
1688
+ }
1689
+ }
1690
+ return names;
1691
+ }
1692
+ function expressionReferencesImportedMiddleware(expression, importedNames) {
1693
+ let found = false;
1694
+ const allowedImportedHelpers = /* @__PURE__ */ new Set(["stack", "fromHono"]);
1695
+ const visit = (node) => {
1696
+ if (found) {
1697
+ return;
1698
+ }
1699
+ if (import_typescript.default.isIdentifier(node) && importedNames.has(node.text) && !allowedImportedHelpers.has(node.text)) {
1700
+ found = true;
1701
+ return;
1702
+ }
1703
+ import_typescript.default.forEachChild(node, visit);
1704
+ };
1705
+ visit(expression);
1706
+ return found;
1707
+ }
1708
+ function parseStaticOpenApi(expression) {
1709
+ const value = unwrapExpression(expression);
1710
+ const boolean = staticBoolean(value);
1711
+ if (boolean !== void 0) {
1712
+ return boolean;
1713
+ }
1714
+ if (!import_typescript.default.isObjectLiteralExpression(value)) {
1715
+ return void 0;
1716
+ }
1717
+ const openapi = {};
1718
+ for (const property of value.properties) {
1719
+ if (!import_typescript.default.isPropertyAssignment(property)) {
1720
+ return void 0;
1721
+ }
1722
+ const name = propertyName(property.name);
1723
+ if (!name) {
1724
+ return void 0;
1725
+ }
1726
+ if (name === "hidden") {
1727
+ const hidden = staticBoolean(property.initializer);
1728
+ if (hidden === void 0) {
1729
+ return void 0;
1730
+ }
1731
+ openapi.hidden = hidden;
1732
+ } else if (name === "tags") {
1733
+ const tags = staticStringArray(property.initializer);
1734
+ if (!tags) {
1735
+ return void 0;
1736
+ }
1737
+ openapi.tags = tags;
1738
+ } else if (name === "summary" || name === "description" || name === "operationId") {
1739
+ const string = staticString(property.initializer);
1740
+ if (string === void 0) {
1741
+ return void 0;
1742
+ }
1743
+ openapi[name] = string;
1744
+ } else if (name === "deprecated") {
1745
+ const deprecated = staticBoolean(property.initializer);
1746
+ if (deprecated === void 0) {
1747
+ return void 0;
1748
+ }
1749
+ openapi.deprecated = deprecated;
1750
+ } else {
1751
+ return void 0;
1752
+ }
1753
+ }
1754
+ return openapi;
1755
+ }
1756
+ function readStaticModuleMeta(file) {
1757
+ let source;
1758
+ try {
1759
+ source = import_typescript.default.createSourceFile(file, (0, import_node_fs6.readFileSync)(file, "utf8"), import_typescript.default.ScriptTarget.Latest, true);
1760
+ } catch {
1761
+ return void 0;
1762
+ }
1763
+ const importedNames = collectImportedNames(source);
1764
+ const sourceText = source.getFullText();
1765
+ const canSkipMiddlewareRuntime = !sourceText.includes("defineMiddleware") && !sourceText.includes(".openapi");
1766
+ const meta = { middlewareSecurity: false };
1767
+ for (const statement of source.statements) {
1768
+ if (import_typescript.default.isImportDeclaration(statement) || import_typescript.default.isInterfaceDeclaration(statement) || import_typescript.default.isTypeAliasDeclaration(statement) || import_typescript.default.isEmptyStatement(statement) || !hasExportModifier(statement)) {
1769
+ continue;
1770
+ }
1771
+ if (import_typescript.default.isFunctionDeclaration(statement) && statement.name?.text === "handle") {
1772
+ continue;
1773
+ }
1774
+ if (import_typescript.default.isVariableStatement(statement)) {
1775
+ for (const declaration of statement.declarationList.declarations) {
1776
+ if (!import_typescript.default.isIdentifier(declaration.name)) {
1777
+ return void 0;
1778
+ }
1779
+ const name = declaration.name.text;
1780
+ if (name === "openapi") {
1781
+ if (!declaration.initializer) {
1782
+ return void 0;
1783
+ }
1784
+ const openapi = parseStaticOpenApi(declaration.initializer);
1785
+ if (openapi === void 0) {
1786
+ return void 0;
1787
+ }
1788
+ meta.openapi = openapi;
1789
+ } else if (name === "handle") {
1790
+ if (!declaration.initializer || !import_typescript.default.isArrowFunction(declaration.initializer) && !import_typescript.default.isFunctionExpression(declaration.initializer)) {
1791
+ return void 0;
1792
+ }
1793
+ continue;
1794
+ } else if (name === "middleware") {
1795
+ if (!declaration.initializer || !canSkipMiddlewareRuntime || expressionReferencesImportedMiddleware(declaration.initializer, importedNames)) {
1796
+ return void 0;
1797
+ }
1798
+ meta.middlewareSecurity = false;
1799
+ continue;
1800
+ } else {
1801
+ return void 0;
1802
+ }
1803
+ }
1804
+ continue;
1805
+ }
1806
+ return void 0;
1807
+ }
1808
+ return meta;
1809
+ }
1810
+ function resolveStaticOpenApi(route, routeModule, loadShared) {
1556
1811
  let hidden = false;
1812
+ const tags = [];
1813
+ const meta = {};
1814
+ const apply = (value, isVerb) => {
1815
+ if (value === false) {
1816
+ hidden = true;
1817
+ return;
1818
+ }
1819
+ if (value === true) {
1820
+ hidden = false;
1821
+ return;
1822
+ }
1823
+ if (!value) {
1824
+ return;
1825
+ }
1826
+ if (typeof value.hidden === "boolean") {
1827
+ hidden = value.hidden;
1828
+ }
1829
+ if (value.tags) {
1830
+ tags.push(...value.tags);
1831
+ }
1832
+ if (typeof value.summary === "string") {
1833
+ meta.summary = value.summary;
1834
+ }
1835
+ if (typeof value.description === "string") {
1836
+ meta.description = value.description;
1837
+ }
1838
+ if (typeof value.deprecated === "boolean") {
1839
+ meta.deprecated = value.deprecated;
1840
+ }
1841
+ if (isVerb && typeof value.operationId === "string") {
1842
+ meta.operationId = value.operationId;
1843
+ }
1844
+ };
1557
1845
  for (const file of route.sharedFiles) {
1558
- const opinion = hiddenFrom(loadShared(file).openapi);
1559
- if (opinion !== void 0) {
1560
- hidden = opinion;
1846
+ const shared = loadShared(file);
1847
+ if (!shared) {
1848
+ return void 0;
1849
+ }
1850
+ apply(shared.openapi, false);
1851
+ }
1852
+ apply(routeModule.openapi, true);
1853
+ if (tags.length > 0) {
1854
+ meta.tags = [...new Set(tags)];
1855
+ }
1856
+ return { hidden, meta };
1857
+ }
1858
+ function extractStaticMeta(route, routeModule, loadShared) {
1859
+ const openapi = resolveStaticOpenApi(route, routeModule, loadShared);
1860
+ if (!openapi) {
1861
+ return void 0;
1862
+ }
1863
+ const meta = {};
1864
+ if (openapi.hidden) {
1865
+ meta.hidden = true;
1866
+ }
1867
+ if (Object.keys(openapi.meta).length > 0) {
1868
+ meta.openapi = openapi.meta;
1869
+ }
1870
+ return meta;
1871
+ }
1872
+ function extractRuntimeSharedMeta(route, routeModule, loadShared) {
1873
+ const meta = {};
1874
+ const security = collectSecurity(route, {}, loadShared);
1875
+ const { hidden, meta: openapi } = resolveOpenApi(route, { openapi: routeModule.openapi }, loadShared);
1876
+ if (security) {
1877
+ meta.security = security;
1878
+ }
1879
+ if (hidden) {
1880
+ meta.hidden = true;
1881
+ }
1882
+ if (Object.keys(openapi).length > 0) {
1883
+ meta.openapi = openapi;
1884
+ }
1885
+ return meta;
1886
+ }
1887
+ function resolveOpenApi(route, routeModule, loadShared) {
1888
+ let hidden = false;
1889
+ const tags = [];
1890
+ const meta = {};
1891
+ const apply = (value, isVerb) => {
1892
+ if (value === false) {
1893
+ hidden = true;
1894
+ return;
1895
+ }
1896
+ if (value === true) {
1897
+ hidden = false;
1898
+ return;
1899
+ }
1900
+ if (!value || typeof value !== "object") {
1901
+ return;
1902
+ }
1903
+ const o = value;
1904
+ if ("hidden" in o) {
1905
+ hidden = Boolean(o.hidden);
1906
+ }
1907
+ if (Array.isArray(o.tags)) {
1908
+ tags.push(...o.tags.filter((tag) => typeof tag === "string"));
1909
+ }
1910
+ if (typeof o.summary === "string") {
1911
+ meta.summary = o.summary;
1561
1912
  }
1913
+ if (typeof o.description === "string") {
1914
+ meta.description = o.description;
1915
+ }
1916
+ if (typeof o.deprecated === "boolean") {
1917
+ meta.deprecated = o.deprecated;
1918
+ }
1919
+ if (isVerb && typeof o.operationId === "string") {
1920
+ meta.operationId = o.operationId;
1921
+ }
1922
+ };
1923
+ for (const file of route.sharedFiles) {
1924
+ apply(loadShared(file).openapi, false);
1925
+ }
1926
+ apply(routeModule.openapi, true);
1927
+ if (tags.length > 0) {
1928
+ meta.tags = [...new Set(tags)];
1562
1929
  }
1563
- const verb = hiddenFrom(routeModule.openapi);
1564
- return verb ?? hidden;
1930
+ return { hidden, meta };
1565
1931
  }
1566
1932
  function collectSecurity(route, routeModule, loadShared) {
1567
1933
  const skipInherited = Boolean(
@@ -1593,6 +1959,33 @@ function collectSecurity(route, routeModule, loadShared) {
1593
1959
  }
1594
1960
  async function extractRouteMeta(config, paths, routes) {
1595
1961
  const byFile = /* @__PURE__ */ new Map();
1962
+ const remainingRoutes = [];
1963
+ const runtimeSharedRoutes = [];
1964
+ const staticCache = /* @__PURE__ */ new Map();
1965
+ const loadStatic = (file) => {
1966
+ if (!staticCache.has(file)) {
1967
+ staticCache.set(file, readStaticModuleMeta(file));
1968
+ }
1969
+ return staticCache.get(file);
1970
+ };
1971
+ for (const route of routes) {
1972
+ const routeModule = loadStatic(route.file);
1973
+ if (!routeModule) {
1974
+ remainingRoutes.push(route);
1975
+ continue;
1976
+ }
1977
+ const meta = extractStaticMeta(route, routeModule, loadStatic);
1978
+ if (meta) {
1979
+ if (meta.hidden || meta.openapi) {
1980
+ byFile.set(route.file, meta);
1981
+ }
1982
+ continue;
1983
+ }
1984
+ runtimeSharedRoutes.push({ route, routeModule });
1985
+ }
1986
+ if (remainingRoutes.length === 0 && runtimeSharedRoutes.length === 0) {
1987
+ return byFile;
1988
+ }
1596
1989
  const { unregister } = await safeRegister();
1597
1990
  const unregisterAlias = registerAliasResolver(config.alias, paths.cwd);
1598
1991
  const sharedCache = /* @__PURE__ */ new Map();
@@ -1607,13 +2000,19 @@ async function extractRouteMeta(config, paths, routes) {
1607
2000
  return sharedCache.get(file);
1608
2001
  };
1609
2002
  try {
1610
- for (const route of routes) {
2003
+ for (const { route, routeModule } of runtimeSharedRoutes) {
2004
+ const meta = extractRuntimeSharedMeta(route, routeModule, loadShared);
2005
+ if (meta.input || meta.security || meta.hidden || meta.openapi) {
2006
+ byFile.set(route.file, meta);
2007
+ }
2008
+ }
2009
+ for (const route of remainingRoutes) {
1611
2010
  try {
1612
2011
  const routeModule = loadModule2(route.file);
1613
2012
  const meta = {};
1614
2013
  const input = readInput(routeModule);
1615
2014
  const security = collectSecurity(route, routeModule, loadShared);
1616
- const hidden = collectHidden(route, routeModule, loadShared);
2015
+ const { hidden, meta: openapi } = resolveOpenApi(route, routeModule, loadShared);
1617
2016
  if (input) {
1618
2017
  meta.input = input;
1619
2018
  }
@@ -1623,7 +2022,10 @@ async function extractRouteMeta(config, paths, routes) {
1623
2022
  if (hidden) {
1624
2023
  meta.hidden = true;
1625
2024
  }
1626
- if (meta.input || meta.security || meta.hidden) {
2025
+ if (Object.keys(openapi).length > 0) {
2026
+ meta.openapi = openapi;
2027
+ }
2028
+ if (meta.input || meta.security || meta.hidden || meta.openapi) {
1627
2029
  byFile.set(route.file, meta);
1628
2030
  }
1629
2031
  } catch {
@@ -1705,10 +2107,11 @@ async function typeFolders(paths, routes) {
1705
2107
  verbsByDir.set(key, list);
1706
2108
  }
1707
2109
  const dirs = await scanRouteFolders(paths.routesDir);
2110
+ const sharedCache = /* @__PURE__ */ new Map();
1708
2111
  return dirs.map((dir) => ({
1709
2112
  dir,
1710
2113
  params: routeParamsForDir(paths.routesDir, dir),
1711
- sharedFiles: sharedFilesForDir(paths.routesDir, dir),
2114
+ sharedFiles: sharedFilesForDir(paths.routesDir, dir, sharedCache),
1712
2115
  verbs: verbsByDir.get(slash(dir)) ?? []
1713
2116
  }));
1714
2117
  }
@@ -1721,24 +2124,63 @@ async function extractResponses(paths, routes) {
1721
2124
  const { createSchemaProgram: createSchemaProgram2, extractRouteResponses: extractRouteResponses2 } = await Promise.resolve().then(() => (init_schema(), schema_exports));
1722
2125
  const files = [...new Set(routes.map((route) => route.file))];
1723
2126
  const appTypes = (0, import_node_path11.join)(paths.outDir, "types", "app.d.ts");
1724
- const program = createSchemaProgram2(
1725
- paths,
1726
- (0, import_node_fs6.existsSync)(appTypes) ? [...files, appTypes] : files
1727
- );
2127
+ const roots = (0, import_node_fs7.existsSync)(appTypes) ? [...files, appTypes] : files;
2128
+ const program = createSchemaProgram2(paths, roots, { lean: true });
2129
+ const fallbackFiles = [];
1728
2130
  for (const file of files) {
1729
- byFile.set(file, extractRouteResponses2(program, file));
2131
+ const responses = extractRouteResponses2(program, file);
2132
+ byFile.set(file, responses);
2133
+ if (hasLooseResponseSchema(responses)) {
2134
+ fallbackFiles.push(file);
2135
+ }
2136
+ }
2137
+ if (fallbackFiles.length > 0) {
2138
+ const fullProgram = createSchemaProgram2(
2139
+ paths,
2140
+ (0, import_node_fs7.existsSync)(appTypes) ? [...fallbackFiles, appTypes] : fallbackFiles
2141
+ );
2142
+ for (const file of fallbackFiles) {
2143
+ byFile.set(file, extractRouteResponses2(fullProgram, file));
2144
+ }
1730
2145
  }
1731
2146
  } catch (error) {
1732
2147
  console.warn(`giri: skipped response schema generation (${error.message}).`);
1733
2148
  }
1734
2149
  return byFile;
1735
2150
  }
2151
+ function isLooseSchema(value) {
2152
+ if (!value || typeof value !== "object") {
2153
+ return false;
2154
+ }
2155
+ const schema = value;
2156
+ const keys = Object.keys(schema);
2157
+ if (keys.length === 0) {
2158
+ return true;
2159
+ }
2160
+ if (typeof schema.$ref === "string") {
2161
+ return false;
2162
+ }
2163
+ if (Array.isArray(schema.anyOf) && schema.anyOf.some(isLooseSchema)) {
2164
+ return true;
2165
+ }
2166
+ if (schema.items && isLooseSchema(schema.items)) {
2167
+ return true;
2168
+ }
2169
+ if (schema.properties && typeof schema.properties === "object") {
2170
+ return Object.values(schema.properties).some(isLooseSchema);
2171
+ }
2172
+ return false;
2173
+ }
2174
+ function hasLooseResponseSchema(responses) {
2175
+ return responses.responses.some((response) => isLooseSchema(response.schema));
2176
+ }
1736
2177
  async function extractMeta(config, paths, routes) {
1737
2178
  const inputsByFile = /* @__PURE__ */ new Map();
1738
2179
  const securityByFile = /* @__PURE__ */ new Map();
1739
2180
  const hiddenFiles = /* @__PURE__ */ new Set();
2181
+ const openapiByFile = /* @__PURE__ */ new Map();
1740
2182
  if (routes.length === 0) {
1741
- return { inputsByFile, securityByFile, hiddenFiles };
2183
+ return { inputsByFile, securityByFile, hiddenFiles, openapiByFile };
1742
2184
  }
1743
2185
  try {
1744
2186
  const meta = await extractRouteMeta(config, paths, routes);
@@ -1752,15 +2194,19 @@ async function extractMeta(config, paths, routes) {
1752
2194
  if (entry.hidden) {
1753
2195
  hiddenFiles.add(file);
1754
2196
  }
2197
+ if (entry.openapi) {
2198
+ openapiByFile.set(file, entry.openapi);
2199
+ }
1755
2200
  }
1756
2201
  } catch (error) {
1757
2202
  console.warn(`giri: skipped input/security generation (${error.message}).`);
1758
2203
  }
1759
- return { inputsByFile, securityByFile, hiddenFiles };
2204
+ return { inputsByFile, securityByFile, hiddenFiles, openapiByFile };
1760
2205
  }
1761
2206
  async function syncProject(config, options = {}) {
1762
2207
  const paths = resolveGiriPaths(config, options.cwd);
1763
2208
  assertSafeOutDir(paths);
2209
+ const hadOutDir = (0, import_node_fs7.existsSync)(paths.outDir);
1764
2210
  const routes = await scanRoutes(paths.routesDir);
1765
2211
  const folders = await typeFolders(paths, routes);
1766
2212
  await (0, import_promises3.mkdir)(paths.outDir, { recursive: true });
@@ -1769,39 +2215,41 @@ async function syncProject(config, options = {}) {
1769
2215
  await writeAppTypes(paths);
1770
2216
  await writeTsConfig(paths, config);
1771
2217
  const responsesByFile = await extractResponses(paths, routes);
1772
- const { inputsByFile, securityByFile, hiddenFiles } = await extractMeta(config, paths, routes);
1773
- const data = { responsesByFile, inputsByFile, securityByFile, hiddenFiles };
2218
+ const { inputsByFile, securityByFile, hiddenFiles, openapiByFile } = await extractMeta(config, paths, routes);
2219
+ const data = { responsesByFile, inputsByFile, securityByFile, hiddenFiles, openapiByFile };
1774
2220
  await writeManifest(paths, routes, data);
1775
2221
  await writeOpenApi(paths, routes, data);
1776
- await pruneDir(
1777
- paths.outDir,
1778
- /* @__PURE__ */ new Set([
1779
- (0, import_node_path11.join)(paths.outDir, "tsconfig.json"),
1780
- (0, import_node_path11.join)(paths.outDir, "manifest.json"),
1781
- (0, import_node_path11.join)(paths.outDir, "openapi.json"),
1782
- (0, import_node_path11.join)(paths.outDir, "routes.d.ts"),
1783
- (0, import_node_path11.join)(paths.outDir, "types", "app.d.ts"),
1784
- ...folders.map((folder) => typeFilePath(paths, folder.dir))
1785
- ])
1786
- );
2222
+ if (hadOutDir) {
2223
+ await pruneDir(
2224
+ paths.outDir,
2225
+ /* @__PURE__ */ new Set([
2226
+ (0, import_node_path11.join)(paths.outDir, "tsconfig.json"),
2227
+ (0, import_node_path11.join)(paths.outDir, "manifest.json"),
2228
+ (0, import_node_path11.join)(paths.outDir, "openapi.json"),
2229
+ (0, import_node_path11.join)(paths.outDir, "routes.d.ts"),
2230
+ (0, import_node_path11.join)(paths.outDir, "types", "app.d.ts"),
2231
+ ...folders.map((folder) => typeFilePath(paths, folder.dir))
2232
+ ])
2233
+ );
2234
+ }
1787
2235
  return { paths, routes, folders, data };
1788
2236
  }
1789
2237
 
1790
2238
  // src/generator/watch.ts
1791
- var import_node_fs7 = require("fs");
2239
+ var import_node_fs8 = require("fs");
1792
2240
  var import_node_path13 = require("path");
1793
2241
 
1794
2242
  // src/loader/module-loader.ts
1795
2243
  var import_node_path12 = require("path");
1796
2244
 
1797
2245
  // src/lifecycle.ts
1798
- var import_node_fs8 = require("fs");
2246
+ var import_node_fs9 = require("fs");
1799
2247
  var import_node_path14 = require("path");
1800
2248
  var MAIN_EXTENSIONS2 = ["ts", "tsx", "mts", "cts", "js", "jsx", "mjs", "cjs"];
1801
2249
  function resolveMainFile(cwd) {
1802
2250
  for (const ext of MAIN_EXTENSIONS2) {
1803
2251
  const file = (0, import_node_path14.join)(cwd, "src", `main.${ext}`);
1804
- if ((0, import_node_fs8.existsSync)(file)) {
2252
+ if ((0, import_node_fs9.existsSync)(file)) {
1805
2253
  return file;
1806
2254
  }
1807
2255
  }