@boon4681/giri 0.0.3-alpha-1 → 0.0.3-alpha-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -48,10 +48,10 @@ var init_es5 = __esm({
48
48
  // src/generator/schema/program.ts
49
49
  function createSchemaProgram(paths, routeFiles) {
50
50
  let options = { ...DEFAULT_OPTIONS };
51
- const configPath = import_typescript2.default.findConfigFile(paths.cwd, import_typescript2.default.sys.fileExists, "tsconfig.json");
51
+ const configPath = import_typescript3.default.findConfigFile(paths.cwd, import_typescript3.default.sys.fileExists, "tsconfig.json");
52
52
  if (configPath) {
53
- const parsed = import_typescript2.default.getParsedCommandLineOfConfigFile(configPath, {}, {
54
- ...import_typescript2.default.sys,
53
+ const parsed = import_typescript3.default.getParsedCommandLineOfConfigFile(configPath, {}, {
54
+ ...import_typescript3.default.sys,
55
55
  onUnRecoverableConfigFileDiagnostic: () => {
56
56
  }
57
57
  });
@@ -59,17 +59,17 @@ function createSchemaProgram(paths, routeFiles) {
59
59
  options = { ...parsed.options, noEmit: true };
60
60
  }
61
61
  }
62
- return import_typescript2.default.createProgram(routeFiles, options);
62
+ return import_typescript3.default.createProgram(routeFiles, options);
63
63
  }
64
- var import_typescript2, DEFAULT_OPTIONS;
64
+ var import_typescript3, DEFAULT_OPTIONS;
65
65
  var init_program = __esm({
66
66
  "src/generator/schema/program.ts"() {
67
67
  "use strict";
68
- import_typescript2 = __toESM(require("typescript"));
68
+ import_typescript3 = __toESM(require("typescript"));
69
69
  DEFAULT_OPTIONS = {
70
- target: import_typescript2.default.ScriptTarget.ES2022,
71
- module: import_typescript2.default.ModuleKind.NodeNext,
72
- moduleResolution: import_typescript2.default.ModuleResolutionKind.NodeNext,
70
+ target: import_typescript3.default.ScriptTarget.ES2022,
71
+ module: import_typescript3.default.ModuleKind.NodeNext,
72
+ moduleResolution: import_typescript3.default.ModuleResolutionKind.NodeNext,
73
73
  strict: true,
74
74
  skipLibCheck: true,
75
75
  noEmit: true
@@ -103,7 +103,7 @@ function literalValuesOf(types) {
103
103
  for (const member of types) {
104
104
  if (member.isStringLiteral() || member.isNumberLiteral()) {
105
105
  values.push(member.value);
106
- } else if (member.flags & import_typescript3.default.TypeFlags.BooleanLiteral) {
106
+ } else if (member.flags & import_typescript4.default.TypeFlags.BooleanLiteral) {
107
107
  values.push(intrinsicName(member) === "true");
108
108
  } else {
109
109
  return void 0;
@@ -112,7 +112,7 @@ function literalValuesOf(types) {
112
112
  return values;
113
113
  }
114
114
  function walkUnion(type, ctx) {
115
- const flag = import_typescript3.default.TypeFlags.Undefined | import_typescript3.default.TypeFlags.Void | import_typescript3.default.TypeFlags.Never;
115
+ const flag = import_typescript4.default.TypeFlags.Undefined | import_typescript4.default.TypeFlags.Void | import_typescript4.default.TypeFlags.Never;
116
116
  const members = type.types.filter((member) => !(member.flags & flag));
117
117
  if (members.length === 1) {
118
118
  return walkType(members[0], ctx);
@@ -125,13 +125,13 @@ function walkUnion(type, ctx) {
125
125
  }
126
126
  function buildObjectSchema(type, ctx) {
127
127
  const { checker } = ctx;
128
- const indexInfo = checker.getIndexInfoOfType(type, import_typescript3.default.IndexKind.String) ?? checker.getIndexInfoOfType(type, import_typescript3.default.IndexKind.Number);
128
+ const indexInfo = checker.getIndexInfoOfType(type, import_typescript4.default.IndexKind.String) ?? checker.getIndexInfoOfType(type, import_typescript4.default.IndexKind.Number);
129
129
  const properties = {};
130
130
  const required = [];
131
131
  for (const symbol of checker.getPropertiesOfType(type)) {
132
132
  const name = symbol.getName();
133
133
  const propType = checker.getTypeOfSymbolAtLocation(symbol, ctx.location);
134
- 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
+ const optional = Boolean(symbol.getFlags() & import_typescript4.default.SymbolFlags.Optional) || Boolean(propType.flags & import_typescript4.default.TypeFlags.Union && propType.types.some((t) => t.flags & import_typescript4.default.TypeFlags.Undefined));
135
135
  properties[name] = walkType(propType, ctx);
136
136
  if (!optional) {
137
137
  required.push(name);
@@ -190,16 +190,16 @@ function walkObject(type, ctx) {
190
190
  }
191
191
  function walkType(type, ctx) {
192
192
  const flags = type.flags;
193
- if (flags & (import_typescript3.default.TypeFlags.Any | import_typescript3.default.TypeFlags.Unknown)) {
193
+ if (flags & (import_typescript4.default.TypeFlags.Any | import_typescript4.default.TypeFlags.Unknown)) {
194
194
  return {};
195
195
  }
196
- if (flags & import_typescript3.default.TypeFlags.Null) {
196
+ if (flags & import_typescript4.default.TypeFlags.Null) {
197
197
  return { type: "null" };
198
198
  }
199
- if (flags & (import_typescript3.default.TypeFlags.Undefined | import_typescript3.default.TypeFlags.Void)) {
199
+ if (flags & (import_typescript4.default.TypeFlags.Undefined | import_typescript4.default.TypeFlags.Void)) {
200
200
  return {};
201
201
  }
202
- if (flags & (import_typescript3.default.TypeFlags.BigInt | import_typescript3.default.TypeFlags.BigIntLiteral)) {
202
+ if (flags & (import_typescript4.default.TypeFlags.BigInt | import_typescript4.default.TypeFlags.BigIntLiteral)) {
203
203
  ctx.warnings.push("bigint is not JSON-serializable (JSON.stringify throws); documented as string.");
204
204
  return { type: "string" };
205
205
  }
@@ -209,45 +209,45 @@ function walkType(type, ctx) {
209
209
  if (type.isNumberLiteral()) {
210
210
  return { type: "number", const: type.value };
211
211
  }
212
- if (flags & import_typescript3.default.TypeFlags.BooleanLiteral) {
212
+ if (flags & import_typescript4.default.TypeFlags.BooleanLiteral) {
213
213
  return { type: "boolean", const: intrinsicName(type) === "true" };
214
214
  }
215
- if (flags & import_typescript3.default.TypeFlags.String) {
215
+ if (flags & import_typescript4.default.TypeFlags.String) {
216
216
  return { type: "string" };
217
217
  }
218
- if (flags & import_typescript3.default.TypeFlags.Number) {
218
+ if (flags & import_typescript4.default.TypeFlags.Number) {
219
219
  return { type: "number" };
220
220
  }
221
- if (flags & import_typescript3.default.TypeFlags.Boolean) {
221
+ if (flags & import_typescript4.default.TypeFlags.Boolean) {
222
222
  return { type: "boolean" };
223
223
  }
224
224
  if (type.isUnion()) {
225
225
  return walkUnion(type, ctx);
226
226
  }
227
- if (flags & import_typescript3.default.TypeFlags.Object || type.isIntersection()) {
227
+ if (flags & import_typescript4.default.TypeFlags.Object || type.isIntersection()) {
228
228
  return walkObject(type, ctx);
229
229
  }
230
230
  return {};
231
231
  }
232
- var import_typescript3;
232
+ var import_typescript4;
233
233
  var init_json_schema = __esm({
234
234
  "src/generator/schema/json-schema.ts"() {
235
235
  "use strict";
236
- import_typescript3 = __toESM(require("typescript"));
236
+ import_typescript4 = __toESM(require("typescript"));
237
237
  }
238
238
  });
239
239
 
240
240
  // src/generator/schema/responses.ts
241
241
  function findHandleFunction(source) {
242
242
  let found;
243
- const isExported = (node) => import_typescript4.default.canHaveModifiers(node) && (import_typescript4.default.getModifiers(node)?.some((m) => m.kind === import_typescript4.default.SyntaxKind.ExportKeyword) ?? false);
243
+ const isExported = (node) => import_typescript5.default.canHaveModifiers(node) && (import_typescript5.default.getModifiers(node)?.some((m) => m.kind === import_typescript5.default.SyntaxKind.ExportKeyword) ?? false);
244
244
  for (const statement of source.statements) {
245
- if (import_typescript4.default.isFunctionDeclaration(statement) && statement.name?.text === "handle" && isExported(statement)) {
245
+ if (import_typescript5.default.isFunctionDeclaration(statement) && statement.name?.text === "handle" && isExported(statement)) {
246
246
  found = statement;
247
247
  }
248
- if (import_typescript4.default.isVariableStatement(statement) && isExported(statement)) {
248
+ if (import_typescript5.default.isVariableStatement(statement) && isExported(statement)) {
249
249
  for (const declaration of statement.declarationList.declarations) {
250
- 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
+ if (import_typescript5.default.isIdentifier(declaration.name) && declaration.name.text === "handle" && declaration.initializer && (import_typescript5.default.isArrowFunction(declaration.initializer) || import_typescript5.default.isFunctionExpression(declaration.initializer))) {
251
251
  found = declaration.initializer;
252
252
  }
253
253
  }
@@ -256,7 +256,7 @@ function findHandleFunction(source) {
256
256
  return found;
257
257
  }
258
258
  function collectReturnExpressions(fn) {
259
- if (import_typescript4.default.isArrowFunction(fn) && !import_typescript4.default.isBlock(fn.body)) {
259
+ if (import_typescript5.default.isArrowFunction(fn) && !import_typescript5.default.isBlock(fn.body)) {
260
260
  return [fn.body];
261
261
  }
262
262
  if (!fn.body) {
@@ -264,15 +264,15 @@ function collectReturnExpressions(fn) {
264
264
  }
265
265
  const expressions = [];
266
266
  const visit = (node) => {
267
- if (import_typescript4.default.isFunctionDeclaration(node) || import_typescript4.default.isFunctionExpression(node) || import_typescript4.default.isArrowFunction(node)) {
267
+ if (import_typescript5.default.isFunctionDeclaration(node) || import_typescript5.default.isFunctionExpression(node) || import_typescript5.default.isArrowFunction(node)) {
268
268
  return;
269
269
  }
270
- if (import_typescript4.default.isReturnStatement(node) && node.expression) {
270
+ if (import_typescript5.default.isReturnStatement(node) && node.expression) {
271
271
  expressions.push(node.expression);
272
272
  }
273
- import_typescript4.default.forEachChild(node, visit);
273
+ import_typescript5.default.forEachChild(node, visit);
274
274
  };
275
- import_typescript4.default.forEachChild(fn.body, visit);
275
+ import_typescript5.default.forEachChild(fn.body, visit);
276
276
  return expressions;
277
277
  }
278
278
  function propertyType(checker, type, name, location) {
@@ -286,10 +286,10 @@ function isTypedResponse(checker, type) {
286
286
  }
287
287
  function firstParameterName(fn) {
288
288
  const [first] = fn.parameters;
289
- return first && import_typescript4.default.isIdentifier(first.name) ? first.name.text : void 0;
289
+ return first && import_typescript5.default.isIdentifier(first.name) ? first.name.text : void 0;
290
290
  }
291
291
  function readFromCall(checker, expression, contextName) {
292
- if (!import_typescript4.default.isCallExpression(expression) || !import_typescript4.default.isPropertyAccessExpression(expression.expression)) {
292
+ if (!import_typescript5.default.isCallExpression(expression) || !import_typescript5.default.isPropertyAccessExpression(expression.expression)) {
293
293
  return void 0;
294
294
  }
295
295
  const method = expression.expression.name.text;
@@ -297,7 +297,7 @@ function readFromCall(checker, expression, contextName) {
297
297
  return void 0;
298
298
  }
299
299
  const target = expression.expression.expression;
300
- const directContextCall = contextName && import_typescript4.default.isIdentifier(target) && target.text === contextName;
300
+ const directContextCall = contextName && import_typescript5.default.isIdentifier(target) && target.text === contextName;
301
301
  if (!directContextCall && !isTypedResponse(checker, checker.getTypeAtLocation(expression))) {
302
302
  return void 0;
303
303
  }
@@ -373,11 +373,11 @@ function extractRouteResponses(program, file) {
373
373
  result.$defs = ctx.defs;
374
374
  return result;
375
375
  }
376
- var import_typescript4;
376
+ var import_typescript5;
377
377
  var init_responses = __esm({
378
378
  "src/generator/schema/responses.ts"() {
379
379
  "use strict";
380
- import_typescript4 = __toESM(require("typescript"));
380
+ import_typescript5 = __toESM(require("typescript"));
381
381
  init_json_schema();
382
382
  }
383
383
  });
@@ -516,6 +516,7 @@ var import_node_fs2 = require("fs");
516
516
  var import_promises = require("fs/promises");
517
517
  var import_node_path2 = require("path");
518
518
  var import_tinyglobby = require("tinyglobby");
519
+ var import_typescript = __toESM(require("typescript"));
519
520
  var METHOD_ORDER = ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"];
520
521
  var METHOD_FROM_FILE = new Map(
521
522
  METHOD_ORDER.map((method) => [`+${method.toLowerCase()}`, method])
@@ -533,6 +534,117 @@ function methodFromFile(fileName) {
533
534
  const stem = fileName.replace(/\.(?:[cm]?[jt]s|[jt]sx)$/, "").toLowerCase();
534
535
  return METHOD_FROM_FILE.get(stem);
535
536
  }
537
+ function hasExportModifier(node) {
538
+ return import_typescript.default.canHaveModifiers(node) && (import_typescript.default.getModifiers(node)?.some((modifier) => modifier.kind === import_typescript.default.SyntaxKind.ExportKeyword) ?? false);
539
+ }
540
+ function hasDeclareModifier(node) {
541
+ return import_typescript.default.canHaveModifiers(node) && (import_typescript.default.getModifiers(node)?.some((modifier) => modifier.kind === import_typescript.default.SyntaxKind.DeclareKeyword) ?? false);
542
+ }
543
+ function propertyName(node) {
544
+ if (import_typescript.default.isIdentifier(node) || import_typescript.default.isStringLiteralLike(node) || import_typescript.default.isNumericLiteral(node)) {
545
+ return node.text;
546
+ }
547
+ if (import_typescript.default.isPropertyAccessExpression(node)) {
548
+ return node.name.text;
549
+ }
550
+ if (import_typescript.default.isElementAccessExpression(node) && node.argumentExpression) {
551
+ const argument = node.argumentExpression;
552
+ if (import_typescript.default.isStringLiteralLike(argument)) {
553
+ return argument.text;
554
+ }
555
+ }
556
+ return void 0;
557
+ }
558
+ function isExportsObject(node) {
559
+ return import_typescript.default.isIdentifier(node) && node.text === "exports";
560
+ }
561
+ function isModuleExports(node) {
562
+ return import_typescript.default.isPropertyAccessExpression(node) && import_typescript.default.isIdentifier(node.expression) && node.expression.text === "module" && node.name.text === "exports";
563
+ }
564
+ function isCommonJsHandleTarget(node) {
565
+ if (!import_typescript.default.isPropertyAccessExpression(node) && !import_typescript.default.isElementAccessExpression(node)) {
566
+ return false;
567
+ }
568
+ return propertyName(node) === "handle" && (isExportsObject(node.expression) || isModuleExports(node.expression));
569
+ }
570
+ function objectExportsHandle(node) {
571
+ if (!import_typescript.default.isObjectLiteralExpression(node)) {
572
+ return false;
573
+ }
574
+ return node.properties.some((property) => {
575
+ if (import_typescript.default.isShorthandPropertyAssignment(property)) {
576
+ return property.name.text === "handle";
577
+ }
578
+ return (import_typescript.default.isPropertyAssignment(property) || import_typescript.default.isMethodDeclaration(property)) && propertyName(property.name) === "handle";
579
+ });
580
+ }
581
+ function hasNamedHandleExport(source) {
582
+ for (const statement of source.statements) {
583
+ if (hasExportModifier(statement) && !hasDeclareModifier(statement) && import_typescript.default.isFunctionDeclaration(statement) && statement.name?.text === "handle") {
584
+ return true;
585
+ }
586
+ if (hasExportModifier(statement) && !hasDeclareModifier(statement) && import_typescript.default.isVariableStatement(statement)) {
587
+ if (statement.declarationList.declarations.some(
588
+ (declaration) => import_typescript.default.isIdentifier(declaration.name) && declaration.name.text === "handle"
589
+ )) {
590
+ return true;
591
+ }
592
+ }
593
+ if (import_typescript.default.isExportDeclaration(statement) && !statement.isTypeOnly && statement.exportClause && import_typescript.default.isNamedExports(statement.exportClause)) {
594
+ if (statement.exportClause.elements.some(
595
+ (element) => !element.isTypeOnly && element.name.text === "handle"
596
+ )) {
597
+ return true;
598
+ }
599
+ }
600
+ if (!import_typescript.default.isExpressionStatement(statement) || !import_typescript.default.isBinaryExpression(statement.expression)) {
601
+ continue;
602
+ }
603
+ const assignment = statement.expression;
604
+ if (assignment.operatorToken.kind !== import_typescript.default.SyntaxKind.EqualsToken) {
605
+ continue;
606
+ }
607
+ if (isCommonJsHandleTarget(assignment.left) || isModuleExports(assignment.left) && objectExportsHandle(assignment.right)) {
608
+ return true;
609
+ }
610
+ }
611
+ return false;
612
+ }
613
+ function parseSource(file) {
614
+ return import_typescript.default.createSourceFile(
615
+ file,
616
+ (0, import_node_fs2.readFileSync)(file, "utf8"),
617
+ import_typescript.default.ScriptTarget.Latest,
618
+ true
619
+ );
620
+ }
621
+ function parseDiagnostics(source) {
622
+ return source.parseDiagnostics ?? [];
623
+ }
624
+ function formatSyntaxDiagnostic(diagnostic) {
625
+ const position = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
626
+ const message = import_typescript.default.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
627
+ return `${diagnostic.file.fileName}:${position.line + 1}:${position.character + 1} - error TS${diagnostic.code}: ${message}`;
628
+ }
629
+ function assertSourceSyntax(file) {
630
+ if (!/\.(?:[cm]?[jt]s|[jt]sx)$/i.test(file)) {
631
+ return;
632
+ }
633
+ const diagnostics = parseDiagnostics(parseSource(file));
634
+ if (diagnostics.length > 0) {
635
+ throw new SyntaxError(diagnostics.map(formatSyntaxDiagnostic).join("\n"));
636
+ }
637
+ }
638
+ function assertRouteHandleExport(file) {
639
+ const source = parseSource(file);
640
+ const diagnostics = parseDiagnostics(source);
641
+ if (diagnostics.length > 0) {
642
+ throw new SyntaxError(diagnostics.map(formatSyntaxDiagnostic).join("\n"));
643
+ }
644
+ if (!hasNamedHandleExport(source)) {
645
+ throw new Error(`${file} must export a named handle function.`);
646
+ }
647
+ }
536
648
  function sharedFileIn(dir, cache) {
537
649
  if (cache?.has(dir)) {
538
650
  return cache.get(dir);
@@ -812,6 +924,11 @@ function resolveGiriPaths(config, cwd = process.cwd()) {
812
924
  async function buildGiriApp(config, options = {}) {
813
925
  const paths = resolveGiriPaths(config, options.cwd);
814
926
  const routes = await scanRoutes(paths.routesDir);
927
+ if (options.lazy) {
928
+ for (const route of routes) {
929
+ assertRouteHandleExport(route.file);
930
+ }
931
+ }
815
932
  const app = config.adapter.createApp();
816
933
  ensureGiriAliasResolver(paths.outDir);
817
934
  if (options.lazy && (!options.loaderRegistered || !options.aliasResolverRegistered)) {
@@ -1292,7 +1409,7 @@ async function writeParamTypes(paths, folders) {
1292
1409
 
1293
1410
  // src/generator/route-meta.ts
1294
1411
  var import_node_fs6 = require("fs");
1295
- var import_typescript = __toESM(require("typescript"));
1412
+ var import_typescript2 = __toESM(require("typescript"));
1296
1413
 
1297
1414
  // src/generator/inputs.ts
1298
1415
  function sanitize(schema) {
@@ -1354,33 +1471,33 @@ function readInput(routeModule) {
1354
1471
  }
1355
1472
  return input.body || input.query ? input : void 0;
1356
1473
  }
1357
- function hasExportModifier(node) {
1358
- return import_typescript.default.canHaveModifiers(node) && (import_typescript.default.getModifiers(node)?.some((modifier) => modifier.kind === import_typescript.default.SyntaxKind.ExportKeyword) ?? false);
1474
+ function hasExportModifier2(node) {
1475
+ return import_typescript2.default.canHaveModifiers(node) && (import_typescript2.default.getModifiers(node)?.some((modifier) => modifier.kind === import_typescript2.default.SyntaxKind.ExportKeyword) ?? false);
1359
1476
  }
1360
1477
  function unwrapExpression(expression) {
1361
1478
  let current = expression;
1362
- while (import_typescript.default.isParenthesizedExpression(current) || import_typescript.default.isAsExpression(current) || import_typescript.default.isSatisfiesExpression(current)) {
1479
+ while (import_typescript2.default.isParenthesizedExpression(current) || import_typescript2.default.isAsExpression(current) || import_typescript2.default.isSatisfiesExpression(current)) {
1363
1480
  current = current.expression;
1364
1481
  }
1365
1482
  return current;
1366
1483
  }
1367
1484
  function staticBoolean(expression) {
1368
1485
  const value = unwrapExpression(expression);
1369
- if (value.kind === import_typescript.default.SyntaxKind.TrueKeyword) {
1486
+ if (value.kind === import_typescript2.default.SyntaxKind.TrueKeyword) {
1370
1487
  return true;
1371
1488
  }
1372
- if (value.kind === import_typescript.default.SyntaxKind.FalseKeyword) {
1489
+ if (value.kind === import_typescript2.default.SyntaxKind.FalseKeyword) {
1373
1490
  return false;
1374
1491
  }
1375
1492
  return void 0;
1376
1493
  }
1377
1494
  function staticString(expression) {
1378
1495
  const value = unwrapExpression(expression);
1379
- return import_typescript.default.isStringLiteralLike(value) ? value.text : void 0;
1496
+ return import_typescript2.default.isStringLiteralLike(value) ? value.text : void 0;
1380
1497
  }
1381
1498
  function staticStringArray(expression) {
1382
1499
  const value = unwrapExpression(expression);
1383
- if (!import_typescript.default.isArrayLiteralExpression(value)) {
1500
+ if (!import_typescript2.default.isArrayLiteralExpression(value)) {
1384
1501
  return void 0;
1385
1502
  }
1386
1503
  const strings = [];
@@ -1393,8 +1510,8 @@ function staticStringArray(expression) {
1393
1510
  }
1394
1511
  return strings;
1395
1512
  }
1396
- function propertyName(name) {
1397
- if (import_typescript.default.isIdentifier(name) || import_typescript.default.isStringLiteral(name) || import_typescript.default.isNumericLiteral(name)) {
1513
+ function propertyName2(name) {
1514
+ if (import_typescript2.default.isIdentifier(name) || import_typescript2.default.isStringLiteral(name) || import_typescript2.default.isNumericLiteral(name)) {
1398
1515
  return name.text;
1399
1516
  }
1400
1517
  return void 0;
@@ -1402,7 +1519,7 @@ function propertyName(name) {
1402
1519
  function collectImportedNames(source) {
1403
1520
  const names = /* @__PURE__ */ new Set();
1404
1521
  for (const statement of source.statements) {
1405
- if (!import_typescript.default.isImportDeclaration(statement)) {
1522
+ if (!import_typescript2.default.isImportDeclaration(statement)) {
1406
1523
  continue;
1407
1524
  }
1408
1525
  const clause = statement.importClause;
@@ -1413,10 +1530,10 @@ function collectImportedNames(source) {
1413
1530
  names.add(clause.name.text);
1414
1531
  }
1415
1532
  const bindings = clause.namedBindings;
1416
- if (bindings && import_typescript.default.isNamespaceImport(bindings)) {
1533
+ if (bindings && import_typescript2.default.isNamespaceImport(bindings)) {
1417
1534
  names.add(bindings.name.text);
1418
1535
  }
1419
- if (bindings && import_typescript.default.isNamedImports(bindings)) {
1536
+ if (bindings && import_typescript2.default.isNamedImports(bindings)) {
1420
1537
  for (const element of bindings.elements) {
1421
1538
  names.add(element.name.text);
1422
1539
  }
@@ -1431,11 +1548,11 @@ function expressionReferencesImportedMiddleware(expression, importedNames) {
1431
1548
  if (found) {
1432
1549
  return;
1433
1550
  }
1434
- if (import_typescript.default.isIdentifier(node) && importedNames.has(node.text) && !allowedImportedHelpers.has(node.text)) {
1551
+ if (import_typescript2.default.isIdentifier(node) && importedNames.has(node.text) && !allowedImportedHelpers.has(node.text)) {
1435
1552
  found = true;
1436
1553
  return;
1437
1554
  }
1438
- import_typescript.default.forEachChild(node, visit);
1555
+ import_typescript2.default.forEachChild(node, visit);
1439
1556
  };
1440
1557
  visit(expression);
1441
1558
  return found;
@@ -1446,15 +1563,15 @@ function parseStaticOpenApi(expression) {
1446
1563
  if (boolean !== void 0) {
1447
1564
  return boolean;
1448
1565
  }
1449
- if (!import_typescript.default.isObjectLiteralExpression(value)) {
1566
+ if (!import_typescript2.default.isObjectLiteralExpression(value)) {
1450
1567
  return void 0;
1451
1568
  }
1452
1569
  const openapi = {};
1453
1570
  for (const property of value.properties) {
1454
- if (!import_typescript.default.isPropertyAssignment(property)) {
1571
+ if (!import_typescript2.default.isPropertyAssignment(property)) {
1455
1572
  return void 0;
1456
1573
  }
1457
- const name = propertyName(property.name);
1574
+ const name = propertyName2(property.name);
1458
1575
  if (!name) {
1459
1576
  return void 0;
1460
1577
  }
@@ -1491,7 +1608,7 @@ function parseStaticOpenApi(expression) {
1491
1608
  function readStaticModuleMeta(file) {
1492
1609
  let source;
1493
1610
  try {
1494
- source = import_typescript.default.createSourceFile(file, (0, import_node_fs6.readFileSync)(file, "utf8"), import_typescript.default.ScriptTarget.Latest, true);
1611
+ source = import_typescript2.default.createSourceFile(file, (0, import_node_fs6.readFileSync)(file, "utf8"), import_typescript2.default.ScriptTarget.Latest, true);
1495
1612
  } catch {
1496
1613
  return void 0;
1497
1614
  }
@@ -1500,15 +1617,15 @@ function readStaticModuleMeta(file) {
1500
1617
  const canSkipMiddlewareRuntime = !sourceText.includes("defineMiddleware") && !sourceText.includes(".openapi");
1501
1618
  const meta = { middlewareSecurity: false };
1502
1619
  for (const statement of source.statements) {
1503
- if (import_typescript.default.isImportDeclaration(statement) || import_typescript.default.isInterfaceDeclaration(statement) || import_typescript.default.isTypeAliasDeclaration(statement) || import_typescript.default.isEmptyStatement(statement) || !hasExportModifier(statement)) {
1620
+ if (import_typescript2.default.isImportDeclaration(statement) || import_typescript2.default.isInterfaceDeclaration(statement) || import_typescript2.default.isTypeAliasDeclaration(statement) || import_typescript2.default.isEmptyStatement(statement) || !hasExportModifier2(statement)) {
1504
1621
  continue;
1505
1622
  }
1506
- if (import_typescript.default.isFunctionDeclaration(statement) && statement.name?.text === "handle") {
1623
+ if (import_typescript2.default.isFunctionDeclaration(statement) && statement.name?.text === "handle") {
1507
1624
  continue;
1508
1625
  }
1509
- if (import_typescript.default.isVariableStatement(statement)) {
1626
+ if (import_typescript2.default.isVariableStatement(statement)) {
1510
1627
  for (const declaration of statement.declarationList.declarations) {
1511
- if (!import_typescript.default.isIdentifier(declaration.name)) {
1628
+ if (!import_typescript2.default.isIdentifier(declaration.name)) {
1512
1629
  return void 0;
1513
1630
  }
1514
1631
  const name = declaration.name.text;
@@ -1522,7 +1639,7 @@ function readStaticModuleMeta(file) {
1522
1639
  }
1523
1640
  meta.openapi = openapi;
1524
1641
  } else if (name === "handle") {
1525
- if (!declaration.initializer || !import_typescript.default.isArrowFunction(declaration.initializer) && !import_typescript.default.isFunctionExpression(declaration.initializer)) {
1642
+ if (!declaration.initializer || !import_typescript2.default.isArrowFunction(declaration.initializer) && !import_typescript2.default.isFunctionExpression(declaration.initializer)) {
1526
1643
  return void 0;
1527
1644
  }
1528
1645
  continue;
@@ -2050,7 +2167,7 @@ var import_node_path15 = require("path");
2050
2167
  // src/loader/import-graph.ts
2051
2168
  var import_node_fs9 = require("fs");
2052
2169
  var import_node_path13 = require("path");
2053
- var import_typescript5 = __toESM(require("typescript"));
2170
+ var import_typescript6 = __toESM(require("typescript"));
2054
2171
  var import_tinyglobby3 = require("tinyglobby");
2055
2172
  var RESOLVE_EXTS = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
2056
2173
  var JS_EXT = /\.(?:c|m)?jsx?$/;
@@ -2096,25 +2213,25 @@ function resolveSpecifier(specifier, fromFile, alias, cwd) {
2096
2213
  function importSpecifiers(file) {
2097
2214
  let source;
2098
2215
  try {
2099
- source = import_typescript5.default.createSourceFile(file, (0, import_node_fs9.readFileSync)(file, "utf8"), import_typescript5.default.ScriptTarget.Latest, false);
2216
+ source = import_typescript6.default.createSourceFile(file, (0, import_node_fs9.readFileSync)(file, "utf8"), import_typescript6.default.ScriptTarget.Latest, false);
2100
2217
  } catch {
2101
2218
  return [];
2102
2219
  }
2103
2220
  const specifiers = [];
2104
2221
  const visit = (node) => {
2105
- if ((import_typescript5.default.isImportDeclaration(node) || import_typescript5.default.isExportDeclaration(node)) && node.moduleSpecifier && import_typescript5.default.isStringLiteral(node.moduleSpecifier)) {
2222
+ if ((import_typescript6.default.isImportDeclaration(node) || import_typescript6.default.isExportDeclaration(node)) && node.moduleSpecifier && import_typescript6.default.isStringLiteral(node.moduleSpecifier)) {
2106
2223
  specifiers.push(node.moduleSpecifier.text);
2107
- } else if (import_typescript5.default.isImportEqualsDeclaration(node) && import_typescript5.default.isExternalModuleReference(node.moduleReference) && import_typescript5.default.isStringLiteralLike(node.moduleReference.expression)) {
2224
+ } else if (import_typescript6.default.isImportEqualsDeclaration(node) && import_typescript6.default.isExternalModuleReference(node.moduleReference) && import_typescript6.default.isStringLiteralLike(node.moduleReference.expression)) {
2108
2225
  specifiers.push(node.moduleReference.expression.text);
2109
- } else if (import_typescript5.default.isCallExpression(node)) {
2110
- const isRequire = import_typescript5.default.isIdentifier(node.expression) && node.expression.text === "require";
2111
- const isDynamicImport = node.expression.kind === import_typescript5.default.SyntaxKind.ImportKeyword;
2226
+ } else if (import_typescript6.default.isCallExpression(node)) {
2227
+ const isRequire = import_typescript6.default.isIdentifier(node.expression) && node.expression.text === "require";
2228
+ const isDynamicImport = node.expression.kind === import_typescript6.default.SyntaxKind.ImportKeyword;
2112
2229
  const [first] = node.arguments;
2113
- if ((isRequire || isDynamicImport) && first && import_typescript5.default.isStringLiteralLike(first)) {
2230
+ if ((isRequire || isDynamicImport) && first && import_typescript6.default.isStringLiteralLike(first)) {
2114
2231
  specifiers.push(first.text);
2115
2232
  }
2116
2233
  }
2117
- import_typescript5.default.forEachChild(node, visit);
2234
+ import_typescript6.default.forEachChild(node, visit);
2118
2235
  };
2119
2236
  visit(source);
2120
2237
  return specifiers;
@@ -2135,6 +2252,7 @@ async function buildImportGraph(config, cwd) {
2135
2252
  if (file.startsWith(outDir)) {
2136
2253
  continue;
2137
2254
  }
2255
+ nodes.add(toSlash(file));
2138
2256
  for (const specifier of importSpecifiers(file)) {
2139
2257
  const dep = resolveSpecifier(specifier, file, config.alias, root);
2140
2258
  if (!dep || dep.startsWith(outDir)) {
@@ -2142,7 +2260,6 @@ async function buildImportGraph(config, cwd) {
2142
2260
  }
2143
2261
  const from = toSlash(file);
2144
2262
  const to = toSlash(dep);
2145
- nodes.add(from);
2146
2263
  nodes.add(to);
2147
2264
  let set = importers.get(to);
2148
2265
  if (!set) {
@@ -2204,7 +2321,9 @@ function createWatchUpdater(config, initial) {
2204
2321
  const paths = initial.paths;
2205
2322
  let routes = initial.routes;
2206
2323
  const data = initial.data;
2324
+ let metadataQueue = Promise.resolve();
2207
2325
  const fullResync = async () => {
2326
+ await metadataQueue;
2208
2327
  purgeProjectModules(paths.cwd);
2209
2328
  const result = await syncProject(config, { cwd: paths.cwd });
2210
2329
  routes = result.routes;
@@ -2216,39 +2335,54 @@ function createWatchUpdater(config, initial) {
2216
2335
  purgeGeneratedModules(paths.outDir);
2217
2336
  return "full";
2218
2337
  };
2219
- const reextractRoute = async (route) => {
2220
- const key = route.file;
2338
+ const reextractRoutes = async (affected) => {
2339
+ if (affected.length === 0) {
2340
+ return;
2341
+ }
2221
2342
  try {
2222
2343
  const { createSchemaProgram: createSchemaProgram2, extractRouteResponses: extractRouteResponses2 } = await Promise.resolve().then(() => (init_schema(), schema_exports));
2223
2344
  const appTypes = (0, import_node_path15.join)(paths.outDir, "types", "app.d.ts");
2224
- const program = createSchemaProgram2(paths, (0, import_node_fs10.existsSync)(appTypes) ? [key, appTypes] : [key]);
2225
- data.responsesByFile.set(key, extractRouteResponses2(program, key));
2345
+ const files = affected.map((route) => route.file);
2346
+ const program = createSchemaProgram2(
2347
+ paths,
2348
+ (0, import_node_fs10.existsSync)(appTypes) ? [...files, appTypes] : files
2349
+ );
2350
+ for (const route of affected) {
2351
+ data.responsesByFile.set(
2352
+ route.file,
2353
+ extractRouteResponses2(program, route.file)
2354
+ );
2355
+ }
2226
2356
  } catch {
2227
2357
  }
2228
2358
  try {
2229
- const meta = await extractRouteMeta(config, paths, [route]);
2230
- const entry = meta.get(key);
2231
- data.inputsByFile.delete(key);
2232
- data.securityByFile.delete(key);
2233
- data.hiddenFiles.delete(key);
2234
- data.openapiByFile.delete(key);
2235
- if (entry?.input) {
2236
- data.inputsByFile.set(key, entry.input);
2237
- }
2238
- if (entry?.security) {
2239
- data.securityByFile.set(key, entry.security);
2240
- }
2241
- if (entry?.hidden) {
2242
- data.hiddenFiles.add(key);
2243
- }
2244
- if (entry?.openapi) {
2245
- data.openapiByFile.set(key, entry.openapi);
2359
+ const meta = await extractRouteMeta(config, paths, affected);
2360
+ for (const route of affected) {
2361
+ const key = route.file;
2362
+ const entry = meta.get(key);
2363
+ data.inputsByFile.delete(key);
2364
+ data.securityByFile.delete(key);
2365
+ data.hiddenFiles.delete(key);
2366
+ data.openapiByFile.delete(key);
2367
+ if (entry?.input) {
2368
+ data.inputsByFile.set(key, entry.input);
2369
+ }
2370
+ if (entry?.security) {
2371
+ data.securityByFile.set(key, entry.security);
2372
+ }
2373
+ if (entry?.hidden) {
2374
+ data.hiddenFiles.add(key);
2375
+ }
2376
+ if (entry?.openapi) {
2377
+ data.openapiByFile.set(key, entry.openapi);
2378
+ }
2246
2379
  }
2247
2380
  } catch {
2248
2381
  }
2249
2382
  };
2250
2383
  return {
2251
- async apply(filename) {
2384
+ settled: () => metadataQueue,
2385
+ async apply(filename, options = {}) {
2252
2386
  if (!filename) {
2253
2387
  return fullResync();
2254
2388
  }
@@ -2260,9 +2394,21 @@ function createWatchUpdater(config, initial) {
2260
2394
  if ((0, import_node_fs10.statSync)(abs).isDirectory()) {
2261
2395
  return "skip";
2262
2396
  }
2263
- const graph = await buildImportGraph(config, paths.cwd);
2397
+ assertSourceSyntax(abs);
2264
2398
  const isRoute = routes.some((candidate) => slash(candidate.file) === file);
2265
- if (!graph.nodes.has(file) && !isRoute) {
2399
+ const isShared = routes.some(
2400
+ (route) => route.sharedFiles.some((shared) => slash(shared) === file)
2401
+ );
2402
+ const isMethodFile = /^\+(?:get|post|put|patch|delete|options|head)\.(?:[cm]?[jt]s|[jt]sx)$/i.test((0, import_node_path15.basename)(file));
2403
+ const isNewRouteStructure = file.startsWith(`${slash(paths.routesDir)}/`) && /^\+(?:get|post|put|patch|delete|options|head|shared)\.(?:[cm]?[jt]s|[jt]sx)$/i.test((0, import_node_path15.basename)(file)) && !isRoute && !isShared;
2404
+ if (isRoute || isNewRouteStructure && isMethodFile) {
2405
+ assertRouteHandleExport(abs);
2406
+ }
2407
+ if (isNewRouteStructure) {
2408
+ return fullResync();
2409
+ }
2410
+ const graph = await buildImportGraph(config, paths.cwd);
2411
+ if (!graph.nodes.has(file) && !isRoute && !isShared) {
2266
2412
  return fullResync();
2267
2413
  }
2268
2414
  const dependents = collectDependents(graph, file);
@@ -2270,13 +2416,20 @@ function createWatchUpdater(config, initial) {
2270
2416
  (route) => dependents.has(slash(route.file)) || route.sharedFiles.some((shared) => dependents.has(slash(shared)))
2271
2417
  );
2272
2418
  purgeModules(dependents);
2273
- for (const route of affected) {
2274
- await reextractRoute(route);
2419
+ const refreshMetadata = async () => {
2420
+ await reextractRoutes(affected);
2421
+ await writeManifest(paths, routes, data);
2422
+ await writeOpenApi(paths, routes, data);
2423
+ await writeSyncCache(paths, await syncFingerprint(config, paths), data);
2424
+ purgeGeneratedModules(paths.outDir);
2425
+ };
2426
+ const task = metadataQueue.then(refreshMetadata);
2427
+ metadataQueue = task.catch((error) => {
2428
+ console.error("giri: deferred metadata update failed", error);
2429
+ });
2430
+ if (!options.deferMetadata) {
2431
+ await task;
2275
2432
  }
2276
- await writeManifest(paths, routes, data);
2277
- await writeOpenApi(paths, routes, data);
2278
- await writeSyncCache(paths, await syncFingerprint(config, paths), data);
2279
- purgeGeneratedModules(paths.outDir);
2280
2433
  return "incremental";
2281
2434
  }
2282
2435
  };
@@ -2368,6 +2521,12 @@ var tag = {
2368
2521
  warn: color.bold(color.yellow(`[${TAG}]`)),
2369
2522
  error: color.bold(color.red(`[${TAG}]`))
2370
2523
  };
2524
+ function formatError(error) {
2525
+ if (error instanceof Error) {
2526
+ return error.stack ?? `${error.name}: ${error.message}`;
2527
+ }
2528
+ return String(error);
2529
+ }
2371
2530
  var log2 = {
2372
2531
  info(message, scope) {
2373
2532
  console.log(line(tag.info, message, scope));
@@ -2717,7 +2876,9 @@ async function serveProject(config, flags) {
2717
2876
  let fullSync = false;
2718
2877
  const dirtySet = /* @__PURE__ */ new Set();
2719
2878
  for (const name of batch) {
2720
- const outcome = await updater.apply(name || null);
2879
+ const outcome = await updater.apply(name || null, {
2880
+ deferMetadata: true
2881
+ });
2721
2882
  if (outcome === "skip") {
2722
2883
  continue;
2723
2884
  }
@@ -2743,7 +2904,7 @@ async function serveProject(config, flags) {
2743
2904
  }
2744
2905
  }
2745
2906
  } catch (error) {
2746
- log2.error(error instanceof Error ? error.message : String(error), "watch");
2907
+ log2.error(formatError(error), "watch");
2747
2908
  } finally {
2748
2909
  syncing = false;
2749
2910
  }