@boon4681/giri 0.0.2 → 0.0.3-alpha-1
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/adapters/hono.d.ts +25 -4
- package/dist/adapters/hono.js +180 -17
- package/dist/adapters/hono.js.map +1 -1
- package/dist/cli.js +985 -252
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +30 -4
- package/dist/index.js +750 -130
- package/dist/index.js.map +1 -1
- package/dist/{types-DkrKD1S4.d.ts → types-BvRph0mx.d.ts} +92 -2
- package/dist/validators/valibot.d.ts +1 -1
- package/dist/validators/valibot.js.map +1 -1
- package/dist/validators/zod.d.ts +1 -1
- package/dist/validators/zod.js.map +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -47,10 +47,10 @@ var init_es5 = __esm({
|
|
|
47
47
|
// src/generator/schema/program.ts
|
|
48
48
|
function createSchemaProgram(paths, routeFiles) {
|
|
49
49
|
let options = { ...DEFAULT_OPTIONS };
|
|
50
|
-
const configPath =
|
|
50
|
+
const configPath = import_typescript2.default.findConfigFile(paths.cwd, import_typescript2.default.sys.fileExists, "tsconfig.json");
|
|
51
51
|
if (configPath) {
|
|
52
|
-
const parsed =
|
|
53
|
-
...
|
|
52
|
+
const parsed = import_typescript2.default.getParsedCommandLineOfConfigFile(configPath, {}, {
|
|
53
|
+
...import_typescript2.default.sys,
|
|
54
54
|
onUnRecoverableConfigFileDiagnostic: () => {
|
|
55
55
|
}
|
|
56
56
|
});
|
|
@@ -58,17 +58,17 @@ function createSchemaProgram(paths, routeFiles) {
|
|
|
58
58
|
options = { ...parsed.options, noEmit: true };
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
return
|
|
61
|
+
return import_typescript2.default.createProgram(routeFiles, options);
|
|
62
62
|
}
|
|
63
|
-
var
|
|
63
|
+
var import_typescript2, DEFAULT_OPTIONS;
|
|
64
64
|
var init_program = __esm({
|
|
65
65
|
"src/generator/schema/program.ts"() {
|
|
66
66
|
"use strict";
|
|
67
|
-
|
|
67
|
+
import_typescript2 = __toESM(require("typescript"));
|
|
68
68
|
DEFAULT_OPTIONS = {
|
|
69
|
-
target:
|
|
70
|
-
module:
|
|
71
|
-
moduleResolution:
|
|
69
|
+
target: import_typescript2.default.ScriptTarget.ES2022,
|
|
70
|
+
module: import_typescript2.default.ModuleKind.NodeNext,
|
|
71
|
+
moduleResolution: import_typescript2.default.ModuleResolutionKind.NodeNext,
|
|
72
72
|
strict: true,
|
|
73
73
|
skipLibCheck: true,
|
|
74
74
|
noEmit: true
|
|
@@ -102,7 +102,7 @@ function literalValuesOf(types) {
|
|
|
102
102
|
for (const member of types) {
|
|
103
103
|
if (member.isStringLiteral() || member.isNumberLiteral()) {
|
|
104
104
|
values.push(member.value);
|
|
105
|
-
} else if (member.flags &
|
|
105
|
+
} else if (member.flags & import_typescript3.default.TypeFlags.BooleanLiteral) {
|
|
106
106
|
values.push(intrinsicName(member) === "true");
|
|
107
107
|
} else {
|
|
108
108
|
return void 0;
|
|
@@ -111,7 +111,7 @@ function literalValuesOf(types) {
|
|
|
111
111
|
return values;
|
|
112
112
|
}
|
|
113
113
|
function walkUnion(type, ctx) {
|
|
114
|
-
const flag =
|
|
114
|
+
const flag = import_typescript3.default.TypeFlags.Undefined | import_typescript3.default.TypeFlags.Void | import_typescript3.default.TypeFlags.Never;
|
|
115
115
|
const members = type.types.filter((member) => !(member.flags & flag));
|
|
116
116
|
if (members.length === 1) {
|
|
117
117
|
return walkType(members[0], ctx);
|
|
@@ -124,13 +124,13 @@ function walkUnion(type, ctx) {
|
|
|
124
124
|
}
|
|
125
125
|
function buildObjectSchema(type, ctx) {
|
|
126
126
|
const { checker } = ctx;
|
|
127
|
-
const indexInfo = checker.getIndexInfoOfType(type,
|
|
127
|
+
const indexInfo = checker.getIndexInfoOfType(type, import_typescript3.default.IndexKind.String) ?? checker.getIndexInfoOfType(type, import_typescript3.default.IndexKind.Number);
|
|
128
128
|
const properties = {};
|
|
129
129
|
const required = [];
|
|
130
130
|
for (const symbol of checker.getPropertiesOfType(type)) {
|
|
131
131
|
const name = symbol.getName();
|
|
132
132
|
const propType = checker.getTypeOfSymbolAtLocation(symbol, ctx.location);
|
|
133
|
-
const optional = Boolean(symbol.getFlags() &
|
|
133
|
+
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
134
|
properties[name] = walkType(propType, ctx);
|
|
135
135
|
if (!optional) {
|
|
136
136
|
required.push(name);
|
|
@@ -189,16 +189,16 @@ function walkObject(type, ctx) {
|
|
|
189
189
|
}
|
|
190
190
|
function walkType(type, ctx) {
|
|
191
191
|
const flags = type.flags;
|
|
192
|
-
if (flags & (
|
|
192
|
+
if (flags & (import_typescript3.default.TypeFlags.Any | import_typescript3.default.TypeFlags.Unknown)) {
|
|
193
193
|
return {};
|
|
194
194
|
}
|
|
195
|
-
if (flags &
|
|
195
|
+
if (flags & import_typescript3.default.TypeFlags.Null) {
|
|
196
196
|
return { type: "null" };
|
|
197
197
|
}
|
|
198
|
-
if (flags & (
|
|
198
|
+
if (flags & (import_typescript3.default.TypeFlags.Undefined | import_typescript3.default.TypeFlags.Void)) {
|
|
199
199
|
return {};
|
|
200
200
|
}
|
|
201
|
-
if (flags & (
|
|
201
|
+
if (flags & (import_typescript3.default.TypeFlags.BigInt | import_typescript3.default.TypeFlags.BigIntLiteral)) {
|
|
202
202
|
ctx.warnings.push("bigint is not JSON-serializable (JSON.stringify throws); documented as string.");
|
|
203
203
|
return { type: "string" };
|
|
204
204
|
}
|
|
@@ -208,45 +208,45 @@ function walkType(type, ctx) {
|
|
|
208
208
|
if (type.isNumberLiteral()) {
|
|
209
209
|
return { type: "number", const: type.value };
|
|
210
210
|
}
|
|
211
|
-
if (flags &
|
|
211
|
+
if (flags & import_typescript3.default.TypeFlags.BooleanLiteral) {
|
|
212
212
|
return { type: "boolean", const: intrinsicName(type) === "true" };
|
|
213
213
|
}
|
|
214
|
-
if (flags &
|
|
214
|
+
if (flags & import_typescript3.default.TypeFlags.String) {
|
|
215
215
|
return { type: "string" };
|
|
216
216
|
}
|
|
217
|
-
if (flags &
|
|
217
|
+
if (flags & import_typescript3.default.TypeFlags.Number) {
|
|
218
218
|
return { type: "number" };
|
|
219
219
|
}
|
|
220
|
-
if (flags &
|
|
220
|
+
if (flags & import_typescript3.default.TypeFlags.Boolean) {
|
|
221
221
|
return { type: "boolean" };
|
|
222
222
|
}
|
|
223
223
|
if (type.isUnion()) {
|
|
224
224
|
return walkUnion(type, ctx);
|
|
225
225
|
}
|
|
226
|
-
if (flags &
|
|
226
|
+
if (flags & import_typescript3.default.TypeFlags.Object || type.isIntersection()) {
|
|
227
227
|
return walkObject(type, ctx);
|
|
228
228
|
}
|
|
229
229
|
return {};
|
|
230
230
|
}
|
|
231
|
-
var
|
|
231
|
+
var import_typescript3;
|
|
232
232
|
var init_json_schema = __esm({
|
|
233
233
|
"src/generator/schema/json-schema.ts"() {
|
|
234
234
|
"use strict";
|
|
235
|
-
|
|
235
|
+
import_typescript3 = __toESM(require("typescript"));
|
|
236
236
|
}
|
|
237
237
|
});
|
|
238
238
|
|
|
239
239
|
// src/generator/schema/responses.ts
|
|
240
240
|
function findHandleFunction(source) {
|
|
241
241
|
let found;
|
|
242
|
-
const isExported = (node) =>
|
|
242
|
+
const isExported = (node) => import_typescript4.default.canHaveModifiers(node) && (import_typescript4.default.getModifiers(node)?.some((m) => m.kind === import_typescript4.default.SyntaxKind.ExportKeyword) ?? false);
|
|
243
243
|
for (const statement of source.statements) {
|
|
244
|
-
if (
|
|
244
|
+
if (import_typescript4.default.isFunctionDeclaration(statement) && statement.name?.text === "handle" && isExported(statement)) {
|
|
245
245
|
found = statement;
|
|
246
246
|
}
|
|
247
|
-
if (
|
|
247
|
+
if (import_typescript4.default.isVariableStatement(statement) && isExported(statement)) {
|
|
248
248
|
for (const declaration of statement.declarationList.declarations) {
|
|
249
|
-
if (
|
|
249
|
+
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
250
|
found = declaration.initializer;
|
|
251
251
|
}
|
|
252
252
|
}
|
|
@@ -255,7 +255,7 @@ function findHandleFunction(source) {
|
|
|
255
255
|
return found;
|
|
256
256
|
}
|
|
257
257
|
function collectReturnExpressions(fn) {
|
|
258
|
-
if (
|
|
258
|
+
if (import_typescript4.default.isArrowFunction(fn) && !import_typescript4.default.isBlock(fn.body)) {
|
|
259
259
|
return [fn.body];
|
|
260
260
|
}
|
|
261
261
|
if (!fn.body) {
|
|
@@ -263,15 +263,15 @@ function collectReturnExpressions(fn) {
|
|
|
263
263
|
}
|
|
264
264
|
const expressions = [];
|
|
265
265
|
const visit = (node) => {
|
|
266
|
-
if (
|
|
266
|
+
if (import_typescript4.default.isFunctionDeclaration(node) || import_typescript4.default.isFunctionExpression(node) || import_typescript4.default.isArrowFunction(node)) {
|
|
267
267
|
return;
|
|
268
268
|
}
|
|
269
|
-
if (
|
|
269
|
+
if (import_typescript4.default.isReturnStatement(node) && node.expression) {
|
|
270
270
|
expressions.push(node.expression);
|
|
271
271
|
}
|
|
272
|
-
|
|
272
|
+
import_typescript4.default.forEachChild(node, visit);
|
|
273
273
|
};
|
|
274
|
-
|
|
274
|
+
import_typescript4.default.forEachChild(fn.body, visit);
|
|
275
275
|
return expressions;
|
|
276
276
|
}
|
|
277
277
|
function propertyType(checker, type, name, location) {
|
|
@@ -283,15 +283,21 @@ function isTypedResponse2(checker, type) {
|
|
|
283
283
|
checker.getPropertyOfType(type, "data") && checker.getPropertyOfType(type, "status") && checker.getPropertyOfType(type, "format")
|
|
284
284
|
);
|
|
285
285
|
}
|
|
286
|
-
function
|
|
287
|
-
|
|
286
|
+
function firstParameterName(fn) {
|
|
287
|
+
const [first] = fn.parameters;
|
|
288
|
+
return first && import_typescript4.default.isIdentifier(first.name) ? first.name.text : void 0;
|
|
289
|
+
}
|
|
290
|
+
function readFromCall(checker, expression, contextName) {
|
|
291
|
+
if (!import_typescript4.default.isCallExpression(expression) || !import_typescript4.default.isPropertyAccessExpression(expression.expression)) {
|
|
288
292
|
return void 0;
|
|
289
293
|
}
|
|
290
294
|
const method = expression.expression.name.text;
|
|
291
295
|
if (method !== "json" && method !== "text") {
|
|
292
296
|
return void 0;
|
|
293
297
|
}
|
|
294
|
-
|
|
298
|
+
const target = expression.expression.expression;
|
|
299
|
+
const directContextCall = contextName && import_typescript4.default.isIdentifier(target) && target.text === contextName;
|
|
300
|
+
if (!directContextCall && !isTypedResponse2(checker, checker.getTypeAtLocation(expression))) {
|
|
295
301
|
return void 0;
|
|
296
302
|
}
|
|
297
303
|
const [dataArg, statusArg] = expression.arguments;
|
|
@@ -331,6 +337,7 @@ function extractRouteResponses(program, file) {
|
|
|
331
337
|
return result;
|
|
332
338
|
}
|
|
333
339
|
const ctx = createWalkContext(checker, fn);
|
|
340
|
+
const contextName = firstParameterName(fn);
|
|
334
341
|
const byStatus = /* @__PURE__ */ new Map();
|
|
335
342
|
const record = (hit) => {
|
|
336
343
|
const schema = walkType(hit.data, ctx);
|
|
@@ -339,7 +346,7 @@ function extractRouteResponses(program, file) {
|
|
|
339
346
|
byStatus.set(hit.status, bucket);
|
|
340
347
|
};
|
|
341
348
|
for (const expression of collectReturnExpressions(fn)) {
|
|
342
|
-
const fromCall = readFromCall(checker, expression);
|
|
349
|
+
const fromCall = readFromCall(checker, expression, contextName);
|
|
343
350
|
if (fromCall) {
|
|
344
351
|
record(fromCall);
|
|
345
352
|
continue;
|
|
@@ -365,11 +372,11 @@ function extractRouteResponses(program, file) {
|
|
|
365
372
|
result.$defs = ctx.defs;
|
|
366
373
|
return result;
|
|
367
374
|
}
|
|
368
|
-
var
|
|
375
|
+
var import_typescript4;
|
|
369
376
|
var init_responses = __esm({
|
|
370
377
|
"src/generator/schema/responses.ts"() {
|
|
371
378
|
"use strict";
|
|
372
|
-
|
|
379
|
+
import_typescript4 = __toESM(require("typescript"));
|
|
373
380
|
init_json_schema();
|
|
374
381
|
}
|
|
375
382
|
});
|
|
@@ -425,6 +432,21 @@ var bodySchemaBrand = /* @__PURE__ */ Symbol.for("giri.body-schema");
|
|
|
425
432
|
|
|
426
433
|
// src/context.ts
|
|
427
434
|
var BODYLESS_STATUS = /* @__PURE__ */ new Set([101, 103, 204, 205, 304]);
|
|
435
|
+
var pendingResponseBrand = /* @__PURE__ */ Symbol("giri.pending-response");
|
|
436
|
+
function getPending(context) {
|
|
437
|
+
return context[pendingResponseBrand];
|
|
438
|
+
}
|
|
439
|
+
var unsupportedCookieJar = {
|
|
440
|
+
get: cookiesUnsupported,
|
|
441
|
+
all: cookiesUnsupported,
|
|
442
|
+
set: cookiesUnsupported,
|
|
443
|
+
delete: cookiesUnsupported,
|
|
444
|
+
getSigned: cookiesUnsupported,
|
|
445
|
+
setSigned: cookiesUnsupported
|
|
446
|
+
};
|
|
447
|
+
function cookiesUnsupported() {
|
|
448
|
+
throw new Error("The active adapter does not support cookies.");
|
|
449
|
+
}
|
|
428
450
|
function createTypedResponse(data, status, format, headers) {
|
|
429
451
|
return {
|
|
430
452
|
[typedResponseBrand]: { data, status, format },
|
|
@@ -441,6 +463,13 @@ function createContext(options) {
|
|
|
441
463
|
const url = new URL(options.request.url);
|
|
442
464
|
const store = /* @__PURE__ */ new Map();
|
|
443
465
|
const validated = options.validated ?? {};
|
|
466
|
+
const pending = { headers: new Headers() };
|
|
467
|
+
const defaultStatus = () => pending.status ?? 200;
|
|
468
|
+
const cookies = options.cookies ? options.cookies({
|
|
469
|
+
request: options.request,
|
|
470
|
+
append: (header) => pending.headers.append("set-cookie", header),
|
|
471
|
+
secret: options.cookieSecret
|
|
472
|
+
}) : unsupportedCookieJar;
|
|
444
473
|
const context = {
|
|
445
474
|
params: options.params ?? {},
|
|
446
475
|
app: options.app ?? {},
|
|
@@ -458,16 +487,45 @@ function createContext(options) {
|
|
|
458
487
|
throw new Error(`No validated ${String(key)} data is available for this route.`);
|
|
459
488
|
}
|
|
460
489
|
return validated[key];
|
|
461
|
-
}
|
|
490
|
+
},
|
|
491
|
+
cookie: (name) => cookies.get(name),
|
|
492
|
+
cookies: () => cookies.all(),
|
|
493
|
+
signedCookie: (name) => cookies.getSigned(name)
|
|
462
494
|
},
|
|
463
495
|
set: (key, value) => {
|
|
464
496
|
store.set(key, value);
|
|
465
497
|
},
|
|
466
498
|
get: (key) => store.get(key),
|
|
467
|
-
json: (data, status
|
|
468
|
-
text: (text, status
|
|
499
|
+
json: (data, status, headers) => createTypedResponse(data, status ?? defaultStatus(), "json", headers),
|
|
500
|
+
text: (text, status, headers) => createTypedResponse(text, status ?? defaultStatus(), "text", headers),
|
|
501
|
+
html: (html, status, headers) => createTypedResponse(html, status ?? defaultStatus(), "html", headers),
|
|
502
|
+
body: (data, status, headers) => new Response(data, { status: status ?? defaultStatus(), headers }),
|
|
503
|
+
newResponse: (data, status, headers) => new Response(data, { status: status ?? defaultStatus(), headers }),
|
|
504
|
+
redirect: (location, status) => new Response(null, { status: status ?? 302, headers: { Location: location } }),
|
|
505
|
+
notFound: () => new Response("404 Not Found", { status: 404 }),
|
|
506
|
+
header: (name, value, options2) => {
|
|
507
|
+
if (value === void 0) {
|
|
508
|
+
pending.headers.delete(name);
|
|
509
|
+
} else if (options2?.append) {
|
|
510
|
+
pending.headers.append(name, value);
|
|
511
|
+
} else {
|
|
512
|
+
pending.headers.set(name, value);
|
|
513
|
+
}
|
|
514
|
+
},
|
|
515
|
+
status: (code) => {
|
|
516
|
+
pending.status = code;
|
|
517
|
+
},
|
|
518
|
+
cookie: (name, value, options2) => {
|
|
519
|
+
if (value === null) {
|
|
520
|
+
cookies.delete(name, options2);
|
|
521
|
+
} else {
|
|
522
|
+
cookies.set(name, value, options2);
|
|
523
|
+
}
|
|
524
|
+
},
|
|
525
|
+
signedCookie: (name, value, options2) => cookies.setSigned(name, value, options2)
|
|
469
526
|
};
|
|
470
527
|
context[nativeContextBrand] = options.native;
|
|
528
|
+
context[pendingResponseBrand] = pending;
|
|
471
529
|
return context;
|
|
472
530
|
}
|
|
473
531
|
function typedResponseToResponse(response) {
|
|
@@ -478,14 +536,41 @@ function typedResponseToResponse(response) {
|
|
|
478
536
|
if (response.format === "text" && !headers.has("content-type")) {
|
|
479
537
|
headers.set("content-type", "text/plain; charset=utf-8");
|
|
480
538
|
}
|
|
539
|
+
if (response.format === "html" && !headers.has("content-type")) {
|
|
540
|
+
headers.set("content-type", "text/html; charset=utf-8");
|
|
541
|
+
}
|
|
481
542
|
const body = BODYLESS_STATUS.has(response.status) ? null : response.format === "json" ? JSON.stringify(response.data) : String(response.data);
|
|
482
543
|
return new Response(body, {
|
|
483
544
|
status: response.status,
|
|
484
545
|
headers
|
|
485
546
|
});
|
|
486
547
|
}
|
|
487
|
-
function toResponse(response) {
|
|
488
|
-
|
|
548
|
+
function toResponse(response, context) {
|
|
549
|
+
const base = isTypedResponse(response) ? typedResponseToResponse(response) : response;
|
|
550
|
+
const pending = context ? getPending(context) : void 0;
|
|
551
|
+
if (!pending) {
|
|
552
|
+
return base;
|
|
553
|
+
}
|
|
554
|
+
let hasPending = false;
|
|
555
|
+
pending.headers.forEach(() => {
|
|
556
|
+
hasPending = true;
|
|
557
|
+
});
|
|
558
|
+
if (!hasPending) {
|
|
559
|
+
return base;
|
|
560
|
+
}
|
|
561
|
+
const headers = new Headers(base.headers);
|
|
562
|
+
pending.headers.forEach((value, key) => {
|
|
563
|
+
if (key === "set-cookie") {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
if (!headers.has(key)) {
|
|
567
|
+
headers.set(key, value);
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
for (const cookie of pending.headers.getSetCookie?.() ?? []) {
|
|
571
|
+
headers.append("set-cookie", cookie);
|
|
572
|
+
}
|
|
573
|
+
return new Response(base.body, { status: base.status, statusText: base.statusText, headers });
|
|
489
574
|
}
|
|
490
575
|
async function composeMiddleware(middleware, handle, context) {
|
|
491
576
|
let index = -1;
|
|
@@ -686,7 +771,8 @@ var configSchema = import_typebox.Type.Object({
|
|
|
686
771
|
port: import_typebox.Type.Optional(import_typebox.Type.Number()),
|
|
687
772
|
hostname: import_typebox.Type.Optional(import_typebox.Type.String())
|
|
688
773
|
}, { additionalProperties: false })),
|
|
689
|
-
errorSchema: import_typebox.Type.Optional(import_typebox.Type.Any())
|
|
774
|
+
errorSchema: import_typebox.Type.Optional(import_typebox.Type.Any()),
|
|
775
|
+
cookieSecret: import_typebox.Type.Optional(import_typebox.Type.String())
|
|
690
776
|
}, { additionalProperties: false });
|
|
691
777
|
|
|
692
778
|
// src/loader/loader.ts
|
|
@@ -748,13 +834,18 @@ function methodFromFile(fileName) {
|
|
|
748
834
|
const stem = fileName.replace(/\.(?:[cm]?[jt]s|[jt]sx)$/, "").toLowerCase();
|
|
749
835
|
return METHOD_FROM_FILE.get(stem);
|
|
750
836
|
}
|
|
751
|
-
function sharedFileIn(dir) {
|
|
837
|
+
function sharedFileIn(dir, cache) {
|
|
838
|
+
if (cache?.has(dir)) {
|
|
839
|
+
return cache.get(dir);
|
|
840
|
+
}
|
|
752
841
|
for (const ext of ["ts", "tsx", "js", "jsx", "mjs", "cjs", "mts", "cts"]) {
|
|
753
842
|
const file = (0, import_node_path2.join)(dir, `+shared.${ext}`);
|
|
754
843
|
if ((0, import_node_fs2.existsSync)(file)) {
|
|
844
|
+
cache?.set(dir, file);
|
|
755
845
|
return file;
|
|
756
846
|
}
|
|
757
847
|
}
|
|
848
|
+
cache?.set(dir, void 0);
|
|
758
849
|
return void 0;
|
|
759
850
|
}
|
|
760
851
|
function physicalRouteSegments(routesDir, routeDir) {
|
|
@@ -823,7 +914,7 @@ async function scanRouteFolders(routesDir) {
|
|
|
823
914
|
function routeParamsForDir(routesDir, dir) {
|
|
824
915
|
return pathFromSegments(physicalRouteSegments(routesDir, dir)).params;
|
|
825
916
|
}
|
|
826
|
-
function sharedFilesForDir(routesDir, dir) {
|
|
917
|
+
function sharedFilesForDir(routesDir, dir, cache) {
|
|
827
918
|
const segments = physicalRouteSegments(routesDir, dir);
|
|
828
919
|
const dirs = [routesDir];
|
|
829
920
|
let current = routesDir;
|
|
@@ -831,7 +922,7 @@ function sharedFilesForDir(routesDir, dir) {
|
|
|
831
922
|
current = (0, import_node_path2.join)(current, segment);
|
|
832
923
|
dirs.push(current);
|
|
833
924
|
}
|
|
834
|
-
return dirs.map(sharedFileIn).filter((file) => Boolean(file));
|
|
925
|
+
return dirs.map((currentDir) => sharedFileIn(currentDir, cache)).filter((file) => Boolean(file));
|
|
835
926
|
}
|
|
836
927
|
async function scanRoutes(routesDir) {
|
|
837
928
|
if (!(0, import_node_fs2.existsSync)(routesDir)) {
|
|
@@ -843,6 +934,7 @@ async function scanRoutes(routesDir) {
|
|
|
843
934
|
onlyFiles: true
|
|
844
935
|
});
|
|
845
936
|
const routes = [];
|
|
937
|
+
const sharedCache = /* @__PURE__ */ new Map();
|
|
846
938
|
for (const file of files) {
|
|
847
939
|
const method = methodFromFile((0, import_node_path2.basename)(file));
|
|
848
940
|
if (!method) {
|
|
@@ -858,7 +950,7 @@ async function scanRoutes(routesDir) {
|
|
|
858
950
|
routeDir,
|
|
859
951
|
routeSegments,
|
|
860
952
|
params,
|
|
861
|
-
sharedFiles: sharedFilesForDir(routesDir, routeDir)
|
|
953
|
+
sharedFiles: sharedFilesForDir(routesDir, routeDir, sharedCache)
|
|
862
954
|
});
|
|
863
955
|
}
|
|
864
956
|
return routes.sort((left, right) => {
|
|
@@ -871,9 +963,11 @@ async function scanRoutes(routesDir) {
|
|
|
871
963
|
}
|
|
872
964
|
|
|
873
965
|
// src/app.ts
|
|
874
|
-
function loadModule(file) {
|
|
966
|
+
function loadModule(file, force = true) {
|
|
875
967
|
const resolved = require.resolve(file);
|
|
876
|
-
|
|
968
|
+
if (force) {
|
|
969
|
+
delete require.cache[resolved];
|
|
970
|
+
}
|
|
877
971
|
return require(resolved);
|
|
878
972
|
}
|
|
879
973
|
function interopDefault(value) {
|
|
@@ -935,20 +1029,13 @@ function resolveAliasTarget(cwd, target, capture = "") {
|
|
|
935
1029
|
}
|
|
936
1030
|
function matchAlias(request, key) {
|
|
937
1031
|
if (key.includes("*")) {
|
|
938
|
-
const [
|
|
939
|
-
if (request.startsWith(
|
|
940
|
-
return request.slice(
|
|
1032
|
+
const [prefix, suffix = ""] = key.split("*");
|
|
1033
|
+
if (request.startsWith(prefix) && request.endsWith(suffix)) {
|
|
1034
|
+
return request.slice(prefix.length, request.length - suffix.length);
|
|
941
1035
|
}
|
|
942
1036
|
return void 0;
|
|
943
1037
|
}
|
|
944
|
-
|
|
945
|
-
return "";
|
|
946
|
-
}
|
|
947
|
-
const prefix = `${key}/`;
|
|
948
|
-
if (request.startsWith(prefix)) {
|
|
949
|
-
return request.slice(prefix.length);
|
|
950
|
-
}
|
|
951
|
-
return void 0;
|
|
1038
|
+
return request === key ? "" : void 0;
|
|
952
1039
|
}
|
|
953
1040
|
function resolveAliasRequest(request, alias, cwd) {
|
|
954
1041
|
for (const [key, value] of Object.entries(alias ?? {})) {
|
|
@@ -1012,38 +1099,78 @@ async function buildGiriApp(config, options = {}) {
|
|
|
1012
1099
|
const routes = await scanRoutes(paths.routesDir);
|
|
1013
1100
|
const app = config.adapter.createApp();
|
|
1014
1101
|
ensureGiriAliasResolver(paths.outDir);
|
|
1015
|
-
|
|
1016
|
-
|
|
1102
|
+
if (options.lazy && (!options.loaderRegistered || !options.aliasResolverRegistered)) {
|
|
1103
|
+
throw new Error("Lazy route loading requires persistent loader and alias registrations.");
|
|
1104
|
+
}
|
|
1105
|
+
const loader = options.loaderRegistered ? void 0 : await safeRegister();
|
|
1106
|
+
const unregisterAliasResolver = options.aliasResolverRegistered ? void 0 : registerAliasResolver(config.alias, paths.cwd);
|
|
1017
1107
|
try {
|
|
1018
|
-
|
|
1019
|
-
|
|
1108
|
+
const dirty = options.dirty;
|
|
1109
|
+
const forceReload = dirty === void 0;
|
|
1110
|
+
const isDirty = (file) => forceReload || dirty.has(file);
|
|
1111
|
+
const sharedCache = /* @__PURE__ */ new Map();
|
|
1112
|
+
const loadShared = (file) => {
|
|
1113
|
+
if (!sharedCache.has(file)) {
|
|
1114
|
+
sharedCache.set(file, loadModule(file, isDirty(file)));
|
|
1115
|
+
}
|
|
1116
|
+
return sharedCache.get(file);
|
|
1117
|
+
};
|
|
1118
|
+
const runtimeFor = (route) => {
|
|
1119
|
+
const routeModule = loadModule(route.file, isDirty(route.file));
|
|
1020
1120
|
if (typeof routeModule.handle !== "function") {
|
|
1021
1121
|
throw new Error(`${route.file} must export a named handle function.`);
|
|
1022
1122
|
}
|
|
1023
1123
|
const folderMiddleware = routeModule.config?.skipInherited ? [] : route.sharedFiles.flatMap(
|
|
1024
|
-
(file) => normalizeMiddleware(
|
|
1124
|
+
(file) => normalizeMiddleware(loadShared(file).middleware, file)
|
|
1025
1125
|
);
|
|
1026
1126
|
const verbMiddleware = normalizeMiddleware(routeModule.middleware, route.file);
|
|
1027
|
-
|
|
1127
|
+
return {
|
|
1028
1128
|
method: route.method,
|
|
1029
1129
|
path: route.path,
|
|
1030
1130
|
handle: routeModule.handle,
|
|
1031
1131
|
middleware: [...folderMiddleware, ...verbMiddleware],
|
|
1032
1132
|
input: routeInput(routeModule, route.file),
|
|
1033
|
-
services: options.services
|
|
1133
|
+
services: options.services,
|
|
1134
|
+
cookieSecret: config.cookieSecret
|
|
1135
|
+
};
|
|
1136
|
+
};
|
|
1137
|
+
for (const route of routes) {
|
|
1138
|
+
if (!options.lazy) {
|
|
1139
|
+
config.adapter.register(app, runtimeFor(route));
|
|
1140
|
+
continue;
|
|
1141
|
+
}
|
|
1142
|
+
let runtime;
|
|
1143
|
+
const getRuntime = () => {
|
|
1144
|
+
runtime ??= runtimeFor(route);
|
|
1145
|
+
return runtime;
|
|
1146
|
+
};
|
|
1147
|
+
config.adapter.register(app, {
|
|
1148
|
+
method: route.method,
|
|
1149
|
+
path: route.path,
|
|
1150
|
+
get handle() {
|
|
1151
|
+
return getRuntime().handle;
|
|
1152
|
+
},
|
|
1153
|
+
get middleware() {
|
|
1154
|
+
return getRuntime().middleware;
|
|
1155
|
+
},
|
|
1156
|
+
get input() {
|
|
1157
|
+
return getRuntime().input;
|
|
1158
|
+
},
|
|
1159
|
+
services: options.services,
|
|
1160
|
+
cookieSecret: config.cookieSecret
|
|
1034
1161
|
});
|
|
1035
1162
|
}
|
|
1036
1163
|
} finally {
|
|
1037
|
-
unregisterAliasResolver();
|
|
1038
|
-
unregister();
|
|
1164
|
+
unregisterAliasResolver?.();
|
|
1165
|
+
loader?.unregister();
|
|
1039
1166
|
}
|
|
1040
1167
|
return { app, routes, paths };
|
|
1041
1168
|
}
|
|
1042
1169
|
|
|
1043
1170
|
// src/generator/sync.ts
|
|
1044
|
-
var
|
|
1045
|
-
var
|
|
1046
|
-
var
|
|
1171
|
+
var import_node_fs8 = require("fs");
|
|
1172
|
+
var import_promises4 = require("fs/promises");
|
|
1173
|
+
var import_node_path12 = require("path");
|
|
1047
1174
|
|
|
1048
1175
|
// src/generator/app-types.ts
|
|
1049
1176
|
var import_node_fs4 = require("fs");
|
|
@@ -1295,6 +1422,7 @@ function buildOpenApiDocument(paths, routes, data = {}) {
|
|
|
1295
1422
|
const documentPaths = {};
|
|
1296
1423
|
const schemas = {};
|
|
1297
1424
|
const securitySchemes = {};
|
|
1425
|
+
const tagOrder = [];
|
|
1298
1426
|
for (const route of routes) {
|
|
1299
1427
|
if (data.hiddenFiles?.has(route.file)) {
|
|
1300
1428
|
continue;
|
|
@@ -1302,10 +1430,32 @@ function buildOpenApiDocument(paths, routes, data = {}) {
|
|
|
1302
1430
|
const responses = data.responsesByFile?.get(route.file);
|
|
1303
1431
|
const input = data.inputsByFile?.get(route.file);
|
|
1304
1432
|
const security = data.securityByFile?.get(route.file);
|
|
1433
|
+
const meta = data.openapiByFile?.get(route.file);
|
|
1305
1434
|
for (const [name, schema] of Object.entries(responses?.$defs ?? {})) {
|
|
1306
1435
|
schemas[name] = rewriteRefs(schema);
|
|
1307
1436
|
}
|
|
1308
|
-
const operation = {
|
|
1437
|
+
const operation = {};
|
|
1438
|
+
if (meta?.tags && meta.tags.length > 0) {
|
|
1439
|
+
operation.tags = meta.tags;
|
|
1440
|
+
for (const tag of meta.tags) {
|
|
1441
|
+
if (!tagOrder.includes(tag)) {
|
|
1442
|
+
tagOrder.push(tag);
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
if (meta?.summary) {
|
|
1447
|
+
operation.summary = meta.summary;
|
|
1448
|
+
}
|
|
1449
|
+
if (meta?.description) {
|
|
1450
|
+
operation.description = meta.description;
|
|
1451
|
+
}
|
|
1452
|
+
if (meta?.operationId) {
|
|
1453
|
+
operation.operationId = meta.operationId;
|
|
1454
|
+
}
|
|
1455
|
+
if (meta?.deprecated) {
|
|
1456
|
+
operation.deprecated = true;
|
|
1457
|
+
}
|
|
1458
|
+
operation.responses = buildResponses(responses?.responses ?? []);
|
|
1309
1459
|
const parameters = [...pathParameters(route), ...queryParameters(input?.query)];
|
|
1310
1460
|
if (parameters.length > 0) {
|
|
1311
1461
|
operation.parameters = parameters;
|
|
@@ -1337,6 +1487,9 @@ function buildOpenApiDocument(paths, routes, data = {}) {
|
|
|
1337
1487
|
info: readProjectInfo(paths.cwd),
|
|
1338
1488
|
paths: documentPaths
|
|
1339
1489
|
};
|
|
1490
|
+
if (tagOrder.length > 0) {
|
|
1491
|
+
document.tags = tagOrder.map((name) => ({ name }));
|
|
1492
|
+
}
|
|
1340
1493
|
const components = {};
|
|
1341
1494
|
if (Object.keys(schemas).length > 0) {
|
|
1342
1495
|
components.schemas = schemas;
|
|
@@ -1368,14 +1521,29 @@ function paramsType(params) {
|
|
|
1368
1521
|
${fields}
|
|
1369
1522
|
}`;
|
|
1370
1523
|
}
|
|
1371
|
-
function
|
|
1372
|
-
|
|
1373
|
-
|
|
1524
|
+
function middlewareVarsType(typesDir, sharedFile) {
|
|
1525
|
+
const spec = JSON.stringify(moduleSpecifier(typesDir, sharedFile));
|
|
1526
|
+
return `(typeof import(${spec}) extends { middleware: infer M } ? import("@boon4681/giri").InferStackVars<M> : {})`;
|
|
1527
|
+
}
|
|
1528
|
+
function ownSharedFile(dir, sharedFiles) {
|
|
1529
|
+
for (let index = sharedFiles.length - 1; index >= 0; index -= 1) {
|
|
1530
|
+
if ((0, import_node_path8.dirname)(sharedFiles[index]) === dir) {
|
|
1531
|
+
return sharedFiles[index];
|
|
1532
|
+
}
|
|
1374
1533
|
}
|
|
1375
|
-
return
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1534
|
+
return void 0;
|
|
1535
|
+
}
|
|
1536
|
+
function varsType(paths, file, dir, sharedFiles) {
|
|
1537
|
+
const typesDir = (0, import_node_path8.dirname)(file);
|
|
1538
|
+
const parts = [];
|
|
1539
|
+
if (dir !== paths.routesDir) {
|
|
1540
|
+
parts.push(`import(${JSON.stringify(importPath(file, typeFilePath(paths, (0, import_node_path8.dirname)(dir))))}).Vars`);
|
|
1541
|
+
}
|
|
1542
|
+
const ownShared = ownSharedFile(dir, sharedFiles);
|
|
1543
|
+
if (ownShared) {
|
|
1544
|
+
parts.push(middlewareVarsType(typesDir, ownShared));
|
|
1545
|
+
}
|
|
1546
|
+
return parts.length > 0 ? parts.join("\n & ") : "{}";
|
|
1379
1547
|
}
|
|
1380
1548
|
function methodExports(typesDir, verbs) {
|
|
1381
1549
|
return verbs.map(({ method, file }) => {
|
|
@@ -1386,14 +1554,14 @@ function methodExports(typesDir, verbs) {
|
|
|
1386
1554
|
});
|
|
1387
1555
|
}
|
|
1388
1556
|
async function writeParamTypes(paths, folders) {
|
|
1389
|
-
|
|
1557
|
+
await Promise.all(folders.map(({ dir, params, sharedFiles, verbs }) => {
|
|
1390
1558
|
const file = typeFilePath(paths, dir);
|
|
1391
1559
|
const typesDir = (0, import_node_path8.dirname)(file);
|
|
1392
1560
|
const lines = [
|
|
1393
1561
|
GENERATED_HEADER,
|
|
1394
1562
|
`export type Params = ${paramsType(params)};`,
|
|
1395
1563
|
"export type RouteParams = Params;",
|
|
1396
|
-
`type Vars = ${varsType(
|
|
1564
|
+
`export type Vars = ${varsType(paths, file, dir, sharedFiles)};`,
|
|
1397
1565
|
"export type Middleware<Injects extends Record<string, unknown> = {}> =",
|
|
1398
1566
|
' import("@boon4681/giri").Middleware<Params, import("@boon4681/giri").ValidatedInput, Injects>;',
|
|
1399
1567
|
'export type Handle<Input extends import("@boon4681/giri").ValidatedInput = import("@boon4681/giri").ValidatedInput> =',
|
|
@@ -1403,10 +1571,14 @@ async function writeParamTypes(paths, folders) {
|
|
|
1403
1571
|
lines.push(...methodExports(typesDir, verbs));
|
|
1404
1572
|
}
|
|
1405
1573
|
lines.push("");
|
|
1406
|
-
|
|
1407
|
-
}
|
|
1574
|
+
return writeGenerated(file, lines.join("\n"));
|
|
1575
|
+
}));
|
|
1408
1576
|
}
|
|
1409
1577
|
|
|
1578
|
+
// src/generator/route-meta.ts
|
|
1579
|
+
var import_node_fs6 = require("fs");
|
|
1580
|
+
var import_typescript = __toESM(require("typescript"));
|
|
1581
|
+
|
|
1410
1582
|
// src/generator/inputs.ts
|
|
1411
1583
|
function sanitize(schema) {
|
|
1412
1584
|
const { $schema, ...rest } = schema;
|
|
@@ -1467,28 +1639,315 @@ function readInput(routeModule) {
|
|
|
1467
1639
|
}
|
|
1468
1640
|
return input.body || input.query ? input : void 0;
|
|
1469
1641
|
}
|
|
1470
|
-
function
|
|
1471
|
-
|
|
1642
|
+
function hasExportModifier(node) {
|
|
1643
|
+
return import_typescript.default.canHaveModifiers(node) && (import_typescript.default.getModifiers(node)?.some((modifier) => modifier.kind === import_typescript.default.SyntaxKind.ExportKeyword) ?? false);
|
|
1644
|
+
}
|
|
1645
|
+
function unwrapExpression(expression) {
|
|
1646
|
+
let current = expression;
|
|
1647
|
+
while (import_typescript.default.isParenthesizedExpression(current) || import_typescript.default.isAsExpression(current) || import_typescript.default.isSatisfiesExpression(current)) {
|
|
1648
|
+
current = current.expression;
|
|
1649
|
+
}
|
|
1650
|
+
return current;
|
|
1651
|
+
}
|
|
1652
|
+
function staticBoolean(expression) {
|
|
1653
|
+
const value = unwrapExpression(expression);
|
|
1654
|
+
if (value.kind === import_typescript.default.SyntaxKind.TrueKeyword) {
|
|
1472
1655
|
return true;
|
|
1473
1656
|
}
|
|
1474
|
-
if (value ===
|
|
1657
|
+
if (value.kind === import_typescript.default.SyntaxKind.FalseKeyword) {
|
|
1475
1658
|
return false;
|
|
1476
1659
|
}
|
|
1477
|
-
|
|
1478
|
-
|
|
1660
|
+
return void 0;
|
|
1661
|
+
}
|
|
1662
|
+
function staticString(expression) {
|
|
1663
|
+
const value = unwrapExpression(expression);
|
|
1664
|
+
return import_typescript.default.isStringLiteralLike(value) ? value.text : void 0;
|
|
1665
|
+
}
|
|
1666
|
+
function staticStringArray(expression) {
|
|
1667
|
+
const value = unwrapExpression(expression);
|
|
1668
|
+
if (!import_typescript.default.isArrayLiteralExpression(value)) {
|
|
1669
|
+
return void 0;
|
|
1670
|
+
}
|
|
1671
|
+
const strings = [];
|
|
1672
|
+
for (const element of value.elements) {
|
|
1673
|
+
const string = staticString(element);
|
|
1674
|
+
if (string === void 0) {
|
|
1675
|
+
return void 0;
|
|
1676
|
+
}
|
|
1677
|
+
strings.push(string);
|
|
1678
|
+
}
|
|
1679
|
+
return strings;
|
|
1680
|
+
}
|
|
1681
|
+
function propertyName(name) {
|
|
1682
|
+
if (import_typescript.default.isIdentifier(name) || import_typescript.default.isStringLiteral(name) || import_typescript.default.isNumericLiteral(name)) {
|
|
1683
|
+
return name.text;
|
|
1479
1684
|
}
|
|
1480
1685
|
return void 0;
|
|
1481
1686
|
}
|
|
1482
|
-
function
|
|
1687
|
+
function collectImportedNames(source) {
|
|
1688
|
+
const names = /* @__PURE__ */ new Set();
|
|
1689
|
+
for (const statement of source.statements) {
|
|
1690
|
+
if (!import_typescript.default.isImportDeclaration(statement)) {
|
|
1691
|
+
continue;
|
|
1692
|
+
}
|
|
1693
|
+
const clause = statement.importClause;
|
|
1694
|
+
if (!clause) {
|
|
1695
|
+
continue;
|
|
1696
|
+
}
|
|
1697
|
+
if (clause.name) {
|
|
1698
|
+
names.add(clause.name.text);
|
|
1699
|
+
}
|
|
1700
|
+
const bindings = clause.namedBindings;
|
|
1701
|
+
if (bindings && import_typescript.default.isNamespaceImport(bindings)) {
|
|
1702
|
+
names.add(bindings.name.text);
|
|
1703
|
+
}
|
|
1704
|
+
if (bindings && import_typescript.default.isNamedImports(bindings)) {
|
|
1705
|
+
for (const element of bindings.elements) {
|
|
1706
|
+
names.add(element.name.text);
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
return names;
|
|
1711
|
+
}
|
|
1712
|
+
function expressionReferencesImportedMiddleware(expression, importedNames) {
|
|
1713
|
+
let found = false;
|
|
1714
|
+
const allowedImportedHelpers = /* @__PURE__ */ new Set(["stack", "fromHono"]);
|
|
1715
|
+
const visit = (node) => {
|
|
1716
|
+
if (found) {
|
|
1717
|
+
return;
|
|
1718
|
+
}
|
|
1719
|
+
if (import_typescript.default.isIdentifier(node) && importedNames.has(node.text) && !allowedImportedHelpers.has(node.text)) {
|
|
1720
|
+
found = true;
|
|
1721
|
+
return;
|
|
1722
|
+
}
|
|
1723
|
+
import_typescript.default.forEachChild(node, visit);
|
|
1724
|
+
};
|
|
1725
|
+
visit(expression);
|
|
1726
|
+
return found;
|
|
1727
|
+
}
|
|
1728
|
+
function parseStaticOpenApi(expression) {
|
|
1729
|
+
const value = unwrapExpression(expression);
|
|
1730
|
+
const boolean = staticBoolean(value);
|
|
1731
|
+
if (boolean !== void 0) {
|
|
1732
|
+
return boolean;
|
|
1733
|
+
}
|
|
1734
|
+
if (!import_typescript.default.isObjectLiteralExpression(value)) {
|
|
1735
|
+
return void 0;
|
|
1736
|
+
}
|
|
1737
|
+
const openapi = {};
|
|
1738
|
+
for (const property of value.properties) {
|
|
1739
|
+
if (!import_typescript.default.isPropertyAssignment(property)) {
|
|
1740
|
+
return void 0;
|
|
1741
|
+
}
|
|
1742
|
+
const name = propertyName(property.name);
|
|
1743
|
+
if (!name) {
|
|
1744
|
+
return void 0;
|
|
1745
|
+
}
|
|
1746
|
+
if (name === "hidden") {
|
|
1747
|
+
const hidden = staticBoolean(property.initializer);
|
|
1748
|
+
if (hidden === void 0) {
|
|
1749
|
+
return void 0;
|
|
1750
|
+
}
|
|
1751
|
+
openapi.hidden = hidden;
|
|
1752
|
+
} else if (name === "tags") {
|
|
1753
|
+
const tags = staticStringArray(property.initializer);
|
|
1754
|
+
if (!tags) {
|
|
1755
|
+
return void 0;
|
|
1756
|
+
}
|
|
1757
|
+
openapi.tags = tags;
|
|
1758
|
+
} else if (name === "summary" || name === "description" || name === "operationId") {
|
|
1759
|
+
const string = staticString(property.initializer);
|
|
1760
|
+
if (string === void 0) {
|
|
1761
|
+
return void 0;
|
|
1762
|
+
}
|
|
1763
|
+
openapi[name] = string;
|
|
1764
|
+
} else if (name === "deprecated") {
|
|
1765
|
+
const deprecated = staticBoolean(property.initializer);
|
|
1766
|
+
if (deprecated === void 0) {
|
|
1767
|
+
return void 0;
|
|
1768
|
+
}
|
|
1769
|
+
openapi.deprecated = deprecated;
|
|
1770
|
+
} else {
|
|
1771
|
+
return void 0;
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
return openapi;
|
|
1775
|
+
}
|
|
1776
|
+
function readStaticModuleMeta(file) {
|
|
1777
|
+
let source;
|
|
1778
|
+
try {
|
|
1779
|
+
source = import_typescript.default.createSourceFile(file, (0, import_node_fs6.readFileSync)(file, "utf8"), import_typescript.default.ScriptTarget.Latest, true);
|
|
1780
|
+
} catch {
|
|
1781
|
+
return void 0;
|
|
1782
|
+
}
|
|
1783
|
+
const importedNames = collectImportedNames(source);
|
|
1784
|
+
const sourceText = source.getFullText();
|
|
1785
|
+
const canSkipMiddlewareRuntime = !sourceText.includes("defineMiddleware") && !sourceText.includes(".openapi");
|
|
1786
|
+
const meta = { middlewareSecurity: false };
|
|
1787
|
+
for (const statement of source.statements) {
|
|
1788
|
+
if (import_typescript.default.isImportDeclaration(statement) || import_typescript.default.isInterfaceDeclaration(statement) || import_typescript.default.isTypeAliasDeclaration(statement) || import_typescript.default.isEmptyStatement(statement) || !hasExportModifier(statement)) {
|
|
1789
|
+
continue;
|
|
1790
|
+
}
|
|
1791
|
+
if (import_typescript.default.isFunctionDeclaration(statement) && statement.name?.text === "handle") {
|
|
1792
|
+
continue;
|
|
1793
|
+
}
|
|
1794
|
+
if (import_typescript.default.isVariableStatement(statement)) {
|
|
1795
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
1796
|
+
if (!import_typescript.default.isIdentifier(declaration.name)) {
|
|
1797
|
+
return void 0;
|
|
1798
|
+
}
|
|
1799
|
+
const name = declaration.name.text;
|
|
1800
|
+
if (name === "openapi") {
|
|
1801
|
+
if (!declaration.initializer) {
|
|
1802
|
+
return void 0;
|
|
1803
|
+
}
|
|
1804
|
+
const openapi = parseStaticOpenApi(declaration.initializer);
|
|
1805
|
+
if (openapi === void 0) {
|
|
1806
|
+
return void 0;
|
|
1807
|
+
}
|
|
1808
|
+
meta.openapi = openapi;
|
|
1809
|
+
} else if (name === "handle") {
|
|
1810
|
+
if (!declaration.initializer || !import_typescript.default.isArrowFunction(declaration.initializer) && !import_typescript.default.isFunctionExpression(declaration.initializer)) {
|
|
1811
|
+
return void 0;
|
|
1812
|
+
}
|
|
1813
|
+
continue;
|
|
1814
|
+
} else if (name === "middleware") {
|
|
1815
|
+
if (!declaration.initializer || !canSkipMiddlewareRuntime || expressionReferencesImportedMiddleware(declaration.initializer, importedNames)) {
|
|
1816
|
+
return void 0;
|
|
1817
|
+
}
|
|
1818
|
+
meta.middlewareSecurity = false;
|
|
1819
|
+
continue;
|
|
1820
|
+
} else {
|
|
1821
|
+
return void 0;
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
continue;
|
|
1825
|
+
}
|
|
1826
|
+
return void 0;
|
|
1827
|
+
}
|
|
1828
|
+
return meta;
|
|
1829
|
+
}
|
|
1830
|
+
function resolveStaticOpenApi(route, routeModule, loadShared) {
|
|
1483
1831
|
let hidden = false;
|
|
1832
|
+
const tags = [];
|
|
1833
|
+
const meta = {};
|
|
1834
|
+
const apply = (value, isVerb) => {
|
|
1835
|
+
if (value === false) {
|
|
1836
|
+
hidden = true;
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1839
|
+
if (value === true) {
|
|
1840
|
+
hidden = false;
|
|
1841
|
+
return;
|
|
1842
|
+
}
|
|
1843
|
+
if (!value) {
|
|
1844
|
+
return;
|
|
1845
|
+
}
|
|
1846
|
+
if (typeof value.hidden === "boolean") {
|
|
1847
|
+
hidden = value.hidden;
|
|
1848
|
+
}
|
|
1849
|
+
if (value.tags) {
|
|
1850
|
+
tags.push(...value.tags);
|
|
1851
|
+
}
|
|
1852
|
+
if (typeof value.summary === "string") {
|
|
1853
|
+
meta.summary = value.summary;
|
|
1854
|
+
}
|
|
1855
|
+
if (typeof value.description === "string") {
|
|
1856
|
+
meta.description = value.description;
|
|
1857
|
+
}
|
|
1858
|
+
if (typeof value.deprecated === "boolean") {
|
|
1859
|
+
meta.deprecated = value.deprecated;
|
|
1860
|
+
}
|
|
1861
|
+
if (isVerb && typeof value.operationId === "string") {
|
|
1862
|
+
meta.operationId = value.operationId;
|
|
1863
|
+
}
|
|
1864
|
+
};
|
|
1484
1865
|
for (const file of route.sharedFiles) {
|
|
1485
|
-
const
|
|
1486
|
-
if (
|
|
1487
|
-
|
|
1866
|
+
const shared = loadShared(file);
|
|
1867
|
+
if (!shared) {
|
|
1868
|
+
return void 0;
|
|
1869
|
+
}
|
|
1870
|
+
apply(shared.openapi, false);
|
|
1871
|
+
}
|
|
1872
|
+
apply(routeModule.openapi, true);
|
|
1873
|
+
if (tags.length > 0) {
|
|
1874
|
+
meta.tags = [...new Set(tags)];
|
|
1875
|
+
}
|
|
1876
|
+
return { hidden, meta };
|
|
1877
|
+
}
|
|
1878
|
+
function extractStaticMeta(route, routeModule, loadShared) {
|
|
1879
|
+
const openapi = resolveStaticOpenApi(route, routeModule, loadShared);
|
|
1880
|
+
if (!openapi) {
|
|
1881
|
+
return void 0;
|
|
1882
|
+
}
|
|
1883
|
+
const meta = {};
|
|
1884
|
+
if (openapi.hidden) {
|
|
1885
|
+
meta.hidden = true;
|
|
1886
|
+
}
|
|
1887
|
+
if (Object.keys(openapi.meta).length > 0) {
|
|
1888
|
+
meta.openapi = openapi.meta;
|
|
1889
|
+
}
|
|
1890
|
+
return meta;
|
|
1891
|
+
}
|
|
1892
|
+
function extractRuntimeSharedMeta(route, routeModule, loadShared) {
|
|
1893
|
+
const meta = {};
|
|
1894
|
+
const security = collectSecurity(route, {}, loadShared);
|
|
1895
|
+
const { hidden, meta: openapi } = resolveOpenApi(route, { openapi: routeModule.openapi }, loadShared);
|
|
1896
|
+
if (security) {
|
|
1897
|
+
meta.security = security;
|
|
1898
|
+
}
|
|
1899
|
+
if (hidden) {
|
|
1900
|
+
meta.hidden = true;
|
|
1901
|
+
}
|
|
1902
|
+
if (Object.keys(openapi).length > 0) {
|
|
1903
|
+
meta.openapi = openapi;
|
|
1904
|
+
}
|
|
1905
|
+
return meta;
|
|
1906
|
+
}
|
|
1907
|
+
function resolveOpenApi(route, routeModule, loadShared) {
|
|
1908
|
+
let hidden = false;
|
|
1909
|
+
const tags = [];
|
|
1910
|
+
const meta = {};
|
|
1911
|
+
const apply = (value, isVerb) => {
|
|
1912
|
+
if (value === false) {
|
|
1913
|
+
hidden = true;
|
|
1914
|
+
return;
|
|
1915
|
+
}
|
|
1916
|
+
if (value === true) {
|
|
1917
|
+
hidden = false;
|
|
1918
|
+
return;
|
|
1919
|
+
}
|
|
1920
|
+
if (!value || typeof value !== "object") {
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
const o = value;
|
|
1924
|
+
if ("hidden" in o) {
|
|
1925
|
+
hidden = Boolean(o.hidden);
|
|
1926
|
+
}
|
|
1927
|
+
if (Array.isArray(o.tags)) {
|
|
1928
|
+
tags.push(...o.tags.filter((tag) => typeof tag === "string"));
|
|
1929
|
+
}
|
|
1930
|
+
if (typeof o.summary === "string") {
|
|
1931
|
+
meta.summary = o.summary;
|
|
1932
|
+
}
|
|
1933
|
+
if (typeof o.description === "string") {
|
|
1934
|
+
meta.description = o.description;
|
|
1935
|
+
}
|
|
1936
|
+
if (typeof o.deprecated === "boolean") {
|
|
1937
|
+
meta.deprecated = o.deprecated;
|
|
1488
1938
|
}
|
|
1939
|
+
if (isVerb && typeof o.operationId === "string") {
|
|
1940
|
+
meta.operationId = o.operationId;
|
|
1941
|
+
}
|
|
1942
|
+
};
|
|
1943
|
+
for (const file of route.sharedFiles) {
|
|
1944
|
+
apply(loadShared(file).openapi, false);
|
|
1945
|
+
}
|
|
1946
|
+
apply(routeModule.openapi, true);
|
|
1947
|
+
if (tags.length > 0) {
|
|
1948
|
+
meta.tags = [...new Set(tags)];
|
|
1489
1949
|
}
|
|
1490
|
-
|
|
1491
|
-
return verb ?? hidden;
|
|
1950
|
+
return { hidden, meta };
|
|
1492
1951
|
}
|
|
1493
1952
|
function collectSecurity(route, routeModule, loadShared) {
|
|
1494
1953
|
const skipInherited = Boolean(
|
|
@@ -1520,6 +1979,33 @@ function collectSecurity(route, routeModule, loadShared) {
|
|
|
1520
1979
|
}
|
|
1521
1980
|
async function extractRouteMeta(config, paths, routes) {
|
|
1522
1981
|
const byFile = /* @__PURE__ */ new Map();
|
|
1982
|
+
const remainingRoutes = [];
|
|
1983
|
+
const runtimeSharedRoutes = [];
|
|
1984
|
+
const staticCache = /* @__PURE__ */ new Map();
|
|
1985
|
+
const loadStatic = (file) => {
|
|
1986
|
+
if (!staticCache.has(file)) {
|
|
1987
|
+
staticCache.set(file, readStaticModuleMeta(file));
|
|
1988
|
+
}
|
|
1989
|
+
return staticCache.get(file);
|
|
1990
|
+
};
|
|
1991
|
+
for (const route of routes) {
|
|
1992
|
+
const routeModule = loadStatic(route.file);
|
|
1993
|
+
if (!routeModule) {
|
|
1994
|
+
remainingRoutes.push(route);
|
|
1995
|
+
continue;
|
|
1996
|
+
}
|
|
1997
|
+
const meta = extractStaticMeta(route, routeModule, loadStatic);
|
|
1998
|
+
if (meta) {
|
|
1999
|
+
if (meta.hidden || meta.openapi) {
|
|
2000
|
+
byFile.set(route.file, meta);
|
|
2001
|
+
}
|
|
2002
|
+
continue;
|
|
2003
|
+
}
|
|
2004
|
+
runtimeSharedRoutes.push({ route, routeModule });
|
|
2005
|
+
}
|
|
2006
|
+
if (remainingRoutes.length === 0 && runtimeSharedRoutes.length === 0) {
|
|
2007
|
+
return byFile;
|
|
2008
|
+
}
|
|
1523
2009
|
const { unregister } = await safeRegister();
|
|
1524
2010
|
const unregisterAlias = registerAliasResolver(config.alias, paths.cwd);
|
|
1525
2011
|
const sharedCache = /* @__PURE__ */ new Map();
|
|
@@ -1534,13 +2020,19 @@ async function extractRouteMeta(config, paths, routes) {
|
|
|
1534
2020
|
return sharedCache.get(file);
|
|
1535
2021
|
};
|
|
1536
2022
|
try {
|
|
1537
|
-
for (const route of
|
|
2023
|
+
for (const { route, routeModule } of runtimeSharedRoutes) {
|
|
2024
|
+
const meta = extractRuntimeSharedMeta(route, routeModule, loadShared);
|
|
2025
|
+
if (meta.input || meta.security || meta.hidden || meta.openapi) {
|
|
2026
|
+
byFile.set(route.file, meta);
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
for (const route of remainingRoutes) {
|
|
1538
2030
|
try {
|
|
1539
2031
|
const routeModule = loadModule2(route.file);
|
|
1540
2032
|
const meta = {};
|
|
1541
2033
|
const input = readInput(routeModule);
|
|
1542
2034
|
const security = collectSecurity(route, routeModule, loadShared);
|
|
1543
|
-
const hidden =
|
|
2035
|
+
const { hidden, meta: openapi } = resolveOpenApi(route, routeModule, loadShared);
|
|
1544
2036
|
if (input) {
|
|
1545
2037
|
meta.input = input;
|
|
1546
2038
|
}
|
|
@@ -1550,7 +2042,10 @@ async function extractRouteMeta(config, paths, routes) {
|
|
|
1550
2042
|
if (hidden) {
|
|
1551
2043
|
meta.hidden = true;
|
|
1552
2044
|
}
|
|
1553
|
-
if (
|
|
2045
|
+
if (Object.keys(openapi).length > 0) {
|
|
2046
|
+
meta.openapi = openapi;
|
|
2047
|
+
}
|
|
2048
|
+
if (meta.input || meta.security || meta.hidden || meta.openapi) {
|
|
1554
2049
|
byFile.set(route.file, meta);
|
|
1555
2050
|
}
|
|
1556
2051
|
} catch {
|
|
@@ -1622,6 +2117,103 @@ async function writeTsConfig(paths, config) {
|
|
|
1622
2117
|
});
|
|
1623
2118
|
}
|
|
1624
2119
|
|
|
2120
|
+
// src/generator/cache.ts
|
|
2121
|
+
var import_node_crypto = require("crypto");
|
|
2122
|
+
var import_node_fs7 = require("fs");
|
|
2123
|
+
var import_promises3 = require("fs/promises");
|
|
2124
|
+
var import_node_path11 = require("path");
|
|
2125
|
+
var import_tinyglobby2 = require("tinyglobby");
|
|
2126
|
+
var CACHE_VERSION = 1;
|
|
2127
|
+
var SYNC_CACHE_NAME = ".sync-cache.json";
|
|
2128
|
+
function stableConfig(config) {
|
|
2129
|
+
const alias = Object.entries(config.alias ?? {}).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, Array.isArray(value) ? [...value] : value]);
|
|
2130
|
+
return { alias, outDir: config.outDir ?? ".giri" };
|
|
2131
|
+
}
|
|
2132
|
+
async function syncFingerprint(config, paths) {
|
|
2133
|
+
const outRelative = slash((0, import_node_path11.relative)(paths.cwd, paths.outDir));
|
|
2134
|
+
const ignore = ["**/node_modules/**", "**/.git/**"];
|
|
2135
|
+
if (outRelative && !outRelative.startsWith("..")) {
|
|
2136
|
+
ignore.push(`${outRelative}/**`);
|
|
2137
|
+
}
|
|
2138
|
+
const files = await (0, import_tinyglobby2.glob)([
|
|
2139
|
+
"src/**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs,json}",
|
|
2140
|
+
"giri.config.{ts,js,mts,cts,mjs,cjs}",
|
|
2141
|
+
"tsconfig*.json",
|
|
2142
|
+
"package.json",
|
|
2143
|
+
"package-lock.json",
|
|
2144
|
+
"npm-shrinkwrap.json",
|
|
2145
|
+
"yarn.lock",
|
|
2146
|
+
"pnpm-lock.yaml",
|
|
2147
|
+
"bun.lock",
|
|
2148
|
+
"bun.lockb"
|
|
2149
|
+
], {
|
|
2150
|
+
cwd: paths.cwd,
|
|
2151
|
+
absolute: false,
|
|
2152
|
+
onlyFiles: true,
|
|
2153
|
+
dot: true,
|
|
2154
|
+
ignore
|
|
2155
|
+
});
|
|
2156
|
+
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
2157
|
+
hash.update(JSON.stringify(stableConfig(config)));
|
|
2158
|
+
for (const file of files.sort()) {
|
|
2159
|
+
hash.update("\0");
|
|
2160
|
+
hash.update(slash(file));
|
|
2161
|
+
hash.update("\0");
|
|
2162
|
+
hash.update(await (0, import_promises3.readFile)((0, import_node_path11.resolve)(paths.cwd, file)));
|
|
2163
|
+
}
|
|
2164
|
+
return hash.digest("hex");
|
|
2165
|
+
}
|
|
2166
|
+
function cachePath(paths) {
|
|
2167
|
+
return (0, import_node_path11.join)(paths.outDir, SYNC_CACHE_NAME);
|
|
2168
|
+
}
|
|
2169
|
+
function serializePath(paths, file) {
|
|
2170
|
+
return slash((0, import_node_path11.relative)(paths.cwd, file));
|
|
2171
|
+
}
|
|
2172
|
+
function deserializePath(paths, file) {
|
|
2173
|
+
return slash((0, import_node_path11.resolve)(paths.cwd, file.split("/").join(import_node_path11.sep)));
|
|
2174
|
+
}
|
|
2175
|
+
function serializeMap(paths, values) {
|
|
2176
|
+
return [...values].map(([file, value]) => [serializePath(paths, file), value]);
|
|
2177
|
+
}
|
|
2178
|
+
function deserializeMap(paths, values) {
|
|
2179
|
+
return new Map(values.map(([file, value]) => [deserializePath(paths, file), value]));
|
|
2180
|
+
}
|
|
2181
|
+
async function readSyncCache(paths, fingerprint) {
|
|
2182
|
+
const file = cachePath(paths);
|
|
2183
|
+
if (!(0, import_node_fs7.existsSync)(file)) {
|
|
2184
|
+
return void 0;
|
|
2185
|
+
}
|
|
2186
|
+
try {
|
|
2187
|
+
const cache = JSON.parse(await (0, import_promises3.readFile)(file, "utf8"));
|
|
2188
|
+
if (cache.version !== CACHE_VERSION || cache.fingerprint !== fingerprint) {
|
|
2189
|
+
return void 0;
|
|
2190
|
+
}
|
|
2191
|
+
return {
|
|
2192
|
+
responsesByFile: deserializeMap(paths, cache.data.responsesByFile),
|
|
2193
|
+
inputsByFile: deserializeMap(paths, cache.data.inputsByFile),
|
|
2194
|
+
securityByFile: deserializeMap(paths, cache.data.securityByFile),
|
|
2195
|
+
hiddenFiles: new Set(cache.data.hiddenFiles.map((entry) => deserializePath(paths, entry))),
|
|
2196
|
+
openapiByFile: deserializeMap(paths, cache.data.openapiByFile)
|
|
2197
|
+
};
|
|
2198
|
+
} catch {
|
|
2199
|
+
return void 0;
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
async function writeSyncCache(paths, fingerprint, data) {
|
|
2203
|
+
const cache = {
|
|
2204
|
+
version: CACHE_VERSION,
|
|
2205
|
+
fingerprint,
|
|
2206
|
+
data: {
|
|
2207
|
+
responsesByFile: serializeMap(paths, data.responsesByFile),
|
|
2208
|
+
inputsByFile: serializeMap(paths, data.inputsByFile),
|
|
2209
|
+
securityByFile: serializeMap(paths, data.securityByFile),
|
|
2210
|
+
hiddenFiles: [...data.hiddenFiles].map((file) => serializePath(paths, file)),
|
|
2211
|
+
openapiByFile: serializeMap(paths, data.openapiByFile)
|
|
2212
|
+
}
|
|
2213
|
+
};
|
|
2214
|
+
await writeJson(cachePath(paths), cache);
|
|
2215
|
+
}
|
|
2216
|
+
|
|
1625
2217
|
// src/generator/sync.ts
|
|
1626
2218
|
async function typeFolders(paths, routes) {
|
|
1627
2219
|
const verbsByDir = /* @__PURE__ */ new Map();
|
|
@@ -1632,10 +2224,11 @@ async function typeFolders(paths, routes) {
|
|
|
1632
2224
|
verbsByDir.set(key, list);
|
|
1633
2225
|
}
|
|
1634
2226
|
const dirs = await scanRouteFolders(paths.routesDir);
|
|
2227
|
+
const sharedCache = /* @__PURE__ */ new Map();
|
|
1635
2228
|
return dirs.map((dir) => ({
|
|
1636
2229
|
dir,
|
|
1637
2230
|
params: routeParamsForDir(paths.routesDir, dir),
|
|
1638
|
-
sharedFiles: sharedFilesForDir(paths.routesDir, dir),
|
|
2231
|
+
sharedFiles: sharedFilesForDir(paths.routesDir, dir, sharedCache),
|
|
1639
2232
|
verbs: verbsByDir.get(slash(dir)) ?? []
|
|
1640
2233
|
}));
|
|
1641
2234
|
}
|
|
@@ -1647,11 +2240,9 @@ async function extractResponses(paths, routes) {
|
|
|
1647
2240
|
try {
|
|
1648
2241
|
const { createSchemaProgram: createSchemaProgram2, extractRouteResponses: extractRouteResponses2 } = await Promise.resolve().then(() => (init_schema(), schema_exports));
|
|
1649
2242
|
const files = [...new Set(routes.map((route) => route.file))];
|
|
1650
|
-
const appTypes = (0,
|
|
1651
|
-
const
|
|
1652
|
-
|
|
1653
|
-
(0, import_node_fs6.existsSync)(appTypes) ? [...files, appTypes] : files
|
|
1654
|
-
);
|
|
2243
|
+
const appTypes = (0, import_node_path12.join)(paths.outDir, "types", "app.d.ts");
|
|
2244
|
+
const roots = (0, import_node_fs8.existsSync)(appTypes) ? [...files, appTypes] : files;
|
|
2245
|
+
const program = createSchemaProgram2(paths, roots);
|
|
1655
2246
|
for (const file of files) {
|
|
1656
2247
|
byFile.set(file, extractRouteResponses2(program, file));
|
|
1657
2248
|
}
|
|
@@ -1664,8 +2255,9 @@ async function extractMeta(config, paths, routes) {
|
|
|
1664
2255
|
const inputsByFile = /* @__PURE__ */ new Map();
|
|
1665
2256
|
const securityByFile = /* @__PURE__ */ new Map();
|
|
1666
2257
|
const hiddenFiles = /* @__PURE__ */ new Set();
|
|
2258
|
+
const openapiByFile = /* @__PURE__ */ new Map();
|
|
1667
2259
|
if (routes.length === 0) {
|
|
1668
|
-
return { inputsByFile, securityByFile, hiddenFiles };
|
|
2260
|
+
return { inputsByFile, securityByFile, hiddenFiles, openapiByFile };
|
|
1669
2261
|
}
|
|
1670
2262
|
try {
|
|
1671
2263
|
const meta = await extractRouteMeta(config, paths, routes);
|
|
@@ -1679,63 +2271,91 @@ async function extractMeta(config, paths, routes) {
|
|
|
1679
2271
|
if (entry.hidden) {
|
|
1680
2272
|
hiddenFiles.add(file);
|
|
1681
2273
|
}
|
|
2274
|
+
if (entry.openapi) {
|
|
2275
|
+
openapiByFile.set(file, entry.openapi);
|
|
2276
|
+
}
|
|
1682
2277
|
}
|
|
1683
2278
|
} catch (error) {
|
|
1684
2279
|
console.warn(`giri: skipped input/security generation (${error.message}).`);
|
|
1685
2280
|
}
|
|
1686
|
-
return { inputsByFile, securityByFile, hiddenFiles };
|
|
2281
|
+
return { inputsByFile, securityByFile, hiddenFiles, openapiByFile };
|
|
1687
2282
|
}
|
|
1688
2283
|
async function syncProject(config, options = {}) {
|
|
1689
2284
|
const paths = resolveGiriPaths(config, options.cwd);
|
|
1690
2285
|
assertSafeOutDir(paths);
|
|
2286
|
+
const hadOutDir = (0, import_node_fs8.existsSync)(paths.outDir);
|
|
1691
2287
|
const routes = await scanRoutes(paths.routesDir);
|
|
1692
2288
|
const folders = await typeFolders(paths, routes);
|
|
1693
|
-
await (
|
|
2289
|
+
const fingerprint = await syncFingerprint(config, paths);
|
|
2290
|
+
const cached = await readSyncCache(paths, fingerprint);
|
|
2291
|
+
const generatedFiles = [
|
|
2292
|
+
(0, import_node_path12.join)(paths.outDir, "tsconfig.json"),
|
|
2293
|
+
(0, import_node_path12.join)(paths.outDir, "manifest.json"),
|
|
2294
|
+
(0, import_node_path12.join)(paths.outDir, "openapi.json"),
|
|
2295
|
+
(0, import_node_path12.join)(paths.outDir, "routes.d.ts"),
|
|
2296
|
+
(0, import_node_path12.join)(paths.outDir, "types", "app.d.ts"),
|
|
2297
|
+
...folders.map((folder) => typeFilePath(paths, folder.dir))
|
|
2298
|
+
];
|
|
2299
|
+
if (cached && generatedFiles.every(import_node_fs8.existsSync)) {
|
|
2300
|
+
return { paths, routes, folders, data: cached };
|
|
2301
|
+
}
|
|
2302
|
+
await (0, import_promises4.mkdir)(paths.outDir, { recursive: true });
|
|
1694
2303
|
await writeParamTypes(paths, folders);
|
|
1695
2304
|
await writeRouteTypes(paths, routes);
|
|
1696
2305
|
await writeAppTypes(paths);
|
|
1697
2306
|
await writeTsConfig(paths, config);
|
|
1698
|
-
const
|
|
1699
|
-
|
|
1700
|
-
|
|
2307
|
+
const data = cached ?? {
|
|
2308
|
+
responsesByFile: await extractResponses(paths, routes),
|
|
2309
|
+
...await extractMeta(config, paths, routes)
|
|
2310
|
+
};
|
|
1701
2311
|
await writeManifest(paths, routes, data);
|
|
1702
2312
|
await writeOpenApi(paths, routes, data);
|
|
1703
|
-
await
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
2313
|
+
await writeSyncCache(paths, fingerprint, data);
|
|
2314
|
+
if (hadOutDir) {
|
|
2315
|
+
await pruneDir(
|
|
2316
|
+
paths.outDir,
|
|
2317
|
+
/* @__PURE__ */ new Set([
|
|
2318
|
+
(0, import_node_path12.join)(paths.outDir, "tsconfig.json"),
|
|
2319
|
+
(0, import_node_path12.join)(paths.outDir, "manifest.json"),
|
|
2320
|
+
(0, import_node_path12.join)(paths.outDir, "openapi.json"),
|
|
2321
|
+
(0, import_node_path12.join)(paths.outDir, "routes.d.ts"),
|
|
2322
|
+
(0, import_node_path12.join)(paths.outDir, SYNC_CACHE_NAME),
|
|
2323
|
+
(0, import_node_path12.join)(paths.outDir, "types", "app.d.ts"),
|
|
2324
|
+
...folders.map((folder) => typeFilePath(paths, folder.dir))
|
|
2325
|
+
])
|
|
2326
|
+
);
|
|
2327
|
+
}
|
|
1714
2328
|
return { paths, routes, folders, data };
|
|
1715
2329
|
}
|
|
1716
2330
|
|
|
1717
2331
|
// src/generator/watch.ts
|
|
1718
|
-
var
|
|
2332
|
+
var import_node_fs10 = require("fs");
|
|
2333
|
+
var import_node_path15 = require("path");
|
|
2334
|
+
|
|
2335
|
+
// src/loader/import-graph.ts
|
|
2336
|
+
var import_node_fs9 = require("fs");
|
|
1719
2337
|
var import_node_path13 = require("path");
|
|
2338
|
+
var import_typescript5 = __toESM(require("typescript"));
|
|
2339
|
+
var import_tinyglobby3 = require("tinyglobby");
|
|
1720
2340
|
|
|
1721
2341
|
// src/loader/module-loader.ts
|
|
1722
|
-
var
|
|
2342
|
+
var import_node_path14 = require("path");
|
|
1723
2343
|
|
|
1724
2344
|
// src/lifecycle.ts
|
|
1725
|
-
var
|
|
1726
|
-
var
|
|
2345
|
+
var import_node_fs11 = require("fs");
|
|
2346
|
+
var import_node_path16 = require("path");
|
|
1727
2347
|
var MAIN_EXTENSIONS2 = ["ts", "tsx", "mts", "cts", "js", "jsx", "mjs", "cjs"];
|
|
1728
2348
|
function resolveMainFile(cwd) {
|
|
1729
2349
|
for (const ext of MAIN_EXTENSIONS2) {
|
|
1730
|
-
const file = (0,
|
|
1731
|
-
if ((0,
|
|
2350
|
+
const file = (0, import_node_path16.join)(cwd, "src", `main.${ext}`);
|
|
2351
|
+
if ((0, import_node_fs11.existsSync)(file)) {
|
|
1732
2352
|
return file;
|
|
1733
2353
|
}
|
|
1734
2354
|
}
|
|
1735
2355
|
return void 0;
|
|
1736
2356
|
}
|
|
1737
2357
|
async function loadLifecycle(cwd = process.cwd()) {
|
|
1738
|
-
const file = resolveMainFile((0,
|
|
2358
|
+
const file = resolveMainFile((0, import_node_path16.resolve)(cwd));
|
|
1739
2359
|
if (!file) {
|
|
1740
2360
|
return {};
|
|
1741
2361
|
}
|