@boon4681/giri 0.0.2 → 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/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 +1168 -274
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +30 -4
- package/dist/index.js +858 -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_typescript3.default.findConfigFile(paths.cwd, import_typescript3.default.sys.fileExists, "tsconfig.json");
|
|
51
51
|
if (configPath) {
|
|
52
|
-
const parsed =
|
|
53
|
-
...
|
|
52
|
+
const parsed = import_typescript3.default.getParsedCommandLineOfConfigFile(configPath, {}, {
|
|
53
|
+
...import_typescript3.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_typescript3.default.createProgram(routeFiles, options);
|
|
62
62
|
}
|
|
63
|
-
var
|
|
63
|
+
var import_typescript3, DEFAULT_OPTIONS;
|
|
64
64
|
var init_program = __esm({
|
|
65
65
|
"src/generator/schema/program.ts"() {
|
|
66
66
|
"use strict";
|
|
67
|
-
|
|
67
|
+
import_typescript3 = __toESM(require("typescript"));
|
|
68
68
|
DEFAULT_OPTIONS = {
|
|
69
|
-
target:
|
|
70
|
-
module:
|
|
71
|
-
moduleResolution:
|
|
69
|
+
target: import_typescript3.default.ScriptTarget.ES2022,
|
|
70
|
+
module: import_typescript3.default.ModuleKind.NodeNext,
|
|
71
|
+
moduleResolution: import_typescript3.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_typescript4.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_typescript4.default.TypeFlags.Undefined | import_typescript4.default.TypeFlags.Void | import_typescript4.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_typescript4.default.IndexKind.String) ?? checker.getIndexInfoOfType(type, import_typescript4.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_typescript4.default.SymbolFlags.Optional) || Boolean(propType.flags & import_typescript4.default.TypeFlags.Union && propType.types.some((t) => t.flags & import_typescript4.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_typescript4.default.TypeFlags.Any | import_typescript4.default.TypeFlags.Unknown)) {
|
|
193
193
|
return {};
|
|
194
194
|
}
|
|
195
|
-
if (flags &
|
|
195
|
+
if (flags & import_typescript4.default.TypeFlags.Null) {
|
|
196
196
|
return { type: "null" };
|
|
197
197
|
}
|
|
198
|
-
if (flags & (
|
|
198
|
+
if (flags & (import_typescript4.default.TypeFlags.Undefined | import_typescript4.default.TypeFlags.Void)) {
|
|
199
199
|
return {};
|
|
200
200
|
}
|
|
201
|
-
if (flags & (
|
|
201
|
+
if (flags & (import_typescript4.default.TypeFlags.BigInt | import_typescript4.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_typescript4.default.TypeFlags.BooleanLiteral) {
|
|
212
212
|
return { type: "boolean", const: intrinsicName(type) === "true" };
|
|
213
213
|
}
|
|
214
|
-
if (flags &
|
|
214
|
+
if (flags & import_typescript4.default.TypeFlags.String) {
|
|
215
215
|
return { type: "string" };
|
|
216
216
|
}
|
|
217
|
-
if (flags &
|
|
217
|
+
if (flags & import_typescript4.default.TypeFlags.Number) {
|
|
218
218
|
return { type: "number" };
|
|
219
219
|
}
|
|
220
|
-
if (flags &
|
|
220
|
+
if (flags & import_typescript4.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_typescript4.default.TypeFlags.Object || type.isIntersection()) {
|
|
227
227
|
return walkObject(type, ctx);
|
|
228
228
|
}
|
|
229
229
|
return {};
|
|
230
230
|
}
|
|
231
|
-
var
|
|
231
|
+
var import_typescript4;
|
|
232
232
|
var init_json_schema = __esm({
|
|
233
233
|
"src/generator/schema/json-schema.ts"() {
|
|
234
234
|
"use strict";
|
|
235
|
-
|
|
235
|
+
import_typescript4 = __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_typescript5.default.canHaveModifiers(node) && (import_typescript5.default.getModifiers(node)?.some((m) => m.kind === import_typescript5.default.SyntaxKind.ExportKeyword) ?? false);
|
|
243
243
|
for (const statement of source.statements) {
|
|
244
|
-
if (
|
|
244
|
+
if (import_typescript5.default.isFunctionDeclaration(statement) && statement.name?.text === "handle" && isExported(statement)) {
|
|
245
245
|
found = statement;
|
|
246
246
|
}
|
|
247
|
-
if (
|
|
247
|
+
if (import_typescript5.default.isVariableStatement(statement) && isExported(statement)) {
|
|
248
248
|
for (const declaration of statement.declarationList.declarations) {
|
|
249
|
-
if (
|
|
249
|
+
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))) {
|
|
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_typescript5.default.isArrowFunction(fn) && !import_typescript5.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_typescript5.default.isFunctionDeclaration(node) || import_typescript5.default.isFunctionExpression(node) || import_typescript5.default.isArrowFunction(node)) {
|
|
267
267
|
return;
|
|
268
268
|
}
|
|
269
|
-
if (
|
|
269
|
+
if (import_typescript5.default.isReturnStatement(node) && node.expression) {
|
|
270
270
|
expressions.push(node.expression);
|
|
271
271
|
}
|
|
272
|
-
|
|
272
|
+
import_typescript5.default.forEachChild(node, visit);
|
|
273
273
|
};
|
|
274
|
-
|
|
274
|
+
import_typescript5.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_typescript5.default.isIdentifier(first.name) ? first.name.text : void 0;
|
|
289
|
+
}
|
|
290
|
+
function readFromCall(checker, expression, contextName) {
|
|
291
|
+
if (!import_typescript5.default.isCallExpression(expression) || !import_typescript5.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_typescript5.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_typescript5;
|
|
369
376
|
var init_responses = __esm({
|
|
370
377
|
"src/generator/schema/responses.ts"() {
|
|
371
378
|
"use strict";
|
|
372
|
-
|
|
379
|
+
import_typescript5 = __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
|
|
@@ -731,6 +817,7 @@ var import_node_fs2 = require("fs");
|
|
|
731
817
|
var import_promises = require("fs/promises");
|
|
732
818
|
var import_node_path2 = require("path");
|
|
733
819
|
var import_tinyglobby = require("tinyglobby");
|
|
820
|
+
var import_typescript = __toESM(require("typescript"));
|
|
734
821
|
var METHOD_ORDER = ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"];
|
|
735
822
|
var METHOD_FROM_FILE = new Map(
|
|
736
823
|
METHOD_ORDER.map((method) => [`+${method.toLowerCase()}`, method])
|
|
@@ -748,13 +835,120 @@ function methodFromFile(fileName) {
|
|
|
748
835
|
const stem = fileName.replace(/\.(?:[cm]?[jt]s|[jt]sx)$/, "").toLowerCase();
|
|
749
836
|
return METHOD_FROM_FILE.get(stem);
|
|
750
837
|
}
|
|
751
|
-
function
|
|
838
|
+
function hasExportModifier(node) {
|
|
839
|
+
return import_typescript.default.canHaveModifiers(node) && (import_typescript.default.getModifiers(node)?.some((modifier) => modifier.kind === import_typescript.default.SyntaxKind.ExportKeyword) ?? false);
|
|
840
|
+
}
|
|
841
|
+
function hasDeclareModifier(node) {
|
|
842
|
+
return import_typescript.default.canHaveModifiers(node) && (import_typescript.default.getModifiers(node)?.some((modifier) => modifier.kind === import_typescript.default.SyntaxKind.DeclareKeyword) ?? false);
|
|
843
|
+
}
|
|
844
|
+
function propertyName(node) {
|
|
845
|
+
if (import_typescript.default.isIdentifier(node) || import_typescript.default.isStringLiteralLike(node) || import_typescript.default.isNumericLiteral(node)) {
|
|
846
|
+
return node.text;
|
|
847
|
+
}
|
|
848
|
+
if (import_typescript.default.isPropertyAccessExpression(node)) {
|
|
849
|
+
return node.name.text;
|
|
850
|
+
}
|
|
851
|
+
if (import_typescript.default.isElementAccessExpression(node) && node.argumentExpression) {
|
|
852
|
+
const argument = node.argumentExpression;
|
|
853
|
+
if (import_typescript.default.isStringLiteralLike(argument)) {
|
|
854
|
+
return argument.text;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
return void 0;
|
|
858
|
+
}
|
|
859
|
+
function isExportsObject(node) {
|
|
860
|
+
return import_typescript.default.isIdentifier(node) && node.text === "exports";
|
|
861
|
+
}
|
|
862
|
+
function isModuleExports(node) {
|
|
863
|
+
return import_typescript.default.isPropertyAccessExpression(node) && import_typescript.default.isIdentifier(node.expression) && node.expression.text === "module" && node.name.text === "exports";
|
|
864
|
+
}
|
|
865
|
+
function isCommonJsHandleTarget(node) {
|
|
866
|
+
if (!import_typescript.default.isPropertyAccessExpression(node) && !import_typescript.default.isElementAccessExpression(node)) {
|
|
867
|
+
return false;
|
|
868
|
+
}
|
|
869
|
+
return propertyName(node) === "handle" && (isExportsObject(node.expression) || isModuleExports(node.expression));
|
|
870
|
+
}
|
|
871
|
+
function objectExportsHandle(node) {
|
|
872
|
+
if (!import_typescript.default.isObjectLiteralExpression(node)) {
|
|
873
|
+
return false;
|
|
874
|
+
}
|
|
875
|
+
return node.properties.some((property) => {
|
|
876
|
+
if (import_typescript.default.isShorthandPropertyAssignment(property)) {
|
|
877
|
+
return property.name.text === "handle";
|
|
878
|
+
}
|
|
879
|
+
return (import_typescript.default.isPropertyAssignment(property) || import_typescript.default.isMethodDeclaration(property)) && propertyName(property.name) === "handle";
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
function hasNamedHandleExport(source) {
|
|
883
|
+
for (const statement of source.statements) {
|
|
884
|
+
if (hasExportModifier(statement) && !hasDeclareModifier(statement) && import_typescript.default.isFunctionDeclaration(statement) && statement.name?.text === "handle") {
|
|
885
|
+
return true;
|
|
886
|
+
}
|
|
887
|
+
if (hasExportModifier(statement) && !hasDeclareModifier(statement) && import_typescript.default.isVariableStatement(statement)) {
|
|
888
|
+
if (statement.declarationList.declarations.some(
|
|
889
|
+
(declaration) => import_typescript.default.isIdentifier(declaration.name) && declaration.name.text === "handle"
|
|
890
|
+
)) {
|
|
891
|
+
return true;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
if (import_typescript.default.isExportDeclaration(statement) && !statement.isTypeOnly && statement.exportClause && import_typescript.default.isNamedExports(statement.exportClause)) {
|
|
895
|
+
if (statement.exportClause.elements.some(
|
|
896
|
+
(element) => !element.isTypeOnly && element.name.text === "handle"
|
|
897
|
+
)) {
|
|
898
|
+
return true;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
if (!import_typescript.default.isExpressionStatement(statement) || !import_typescript.default.isBinaryExpression(statement.expression)) {
|
|
902
|
+
continue;
|
|
903
|
+
}
|
|
904
|
+
const assignment = statement.expression;
|
|
905
|
+
if (assignment.operatorToken.kind !== import_typescript.default.SyntaxKind.EqualsToken) {
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
if (isCommonJsHandleTarget(assignment.left) || isModuleExports(assignment.left) && objectExportsHandle(assignment.right)) {
|
|
909
|
+
return true;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
return false;
|
|
913
|
+
}
|
|
914
|
+
function parseSource(file) {
|
|
915
|
+
return import_typescript.default.createSourceFile(
|
|
916
|
+
file,
|
|
917
|
+
(0, import_node_fs2.readFileSync)(file, "utf8"),
|
|
918
|
+
import_typescript.default.ScriptTarget.Latest,
|
|
919
|
+
true
|
|
920
|
+
);
|
|
921
|
+
}
|
|
922
|
+
function parseDiagnostics(source) {
|
|
923
|
+
return source.parseDiagnostics ?? [];
|
|
924
|
+
}
|
|
925
|
+
function formatSyntaxDiagnostic(diagnostic) {
|
|
926
|
+
const position = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
927
|
+
const message = import_typescript.default.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
|
|
928
|
+
return `${diagnostic.file.fileName}:${position.line + 1}:${position.character + 1} - error TS${diagnostic.code}: ${message}`;
|
|
929
|
+
}
|
|
930
|
+
function assertRouteHandleExport(file) {
|
|
931
|
+
const source = parseSource(file);
|
|
932
|
+
const diagnostics = parseDiagnostics(source);
|
|
933
|
+
if (diagnostics.length > 0) {
|
|
934
|
+
throw new SyntaxError(diagnostics.map(formatSyntaxDiagnostic).join("\n"));
|
|
935
|
+
}
|
|
936
|
+
if (!hasNamedHandleExport(source)) {
|
|
937
|
+
throw new Error(`${file} must export a named handle function.`);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
function sharedFileIn(dir, cache) {
|
|
941
|
+
if (cache?.has(dir)) {
|
|
942
|
+
return cache.get(dir);
|
|
943
|
+
}
|
|
752
944
|
for (const ext of ["ts", "tsx", "js", "jsx", "mjs", "cjs", "mts", "cts"]) {
|
|
753
945
|
const file = (0, import_node_path2.join)(dir, `+shared.${ext}`);
|
|
754
946
|
if ((0, import_node_fs2.existsSync)(file)) {
|
|
947
|
+
cache?.set(dir, file);
|
|
755
948
|
return file;
|
|
756
949
|
}
|
|
757
950
|
}
|
|
951
|
+
cache?.set(dir, void 0);
|
|
758
952
|
return void 0;
|
|
759
953
|
}
|
|
760
954
|
function physicalRouteSegments(routesDir, routeDir) {
|
|
@@ -823,7 +1017,7 @@ async function scanRouteFolders(routesDir) {
|
|
|
823
1017
|
function routeParamsForDir(routesDir, dir) {
|
|
824
1018
|
return pathFromSegments(physicalRouteSegments(routesDir, dir)).params;
|
|
825
1019
|
}
|
|
826
|
-
function sharedFilesForDir(routesDir, dir) {
|
|
1020
|
+
function sharedFilesForDir(routesDir, dir, cache) {
|
|
827
1021
|
const segments = physicalRouteSegments(routesDir, dir);
|
|
828
1022
|
const dirs = [routesDir];
|
|
829
1023
|
let current = routesDir;
|
|
@@ -831,7 +1025,7 @@ function sharedFilesForDir(routesDir, dir) {
|
|
|
831
1025
|
current = (0, import_node_path2.join)(current, segment);
|
|
832
1026
|
dirs.push(current);
|
|
833
1027
|
}
|
|
834
|
-
return dirs.map(sharedFileIn).filter((file) => Boolean(file));
|
|
1028
|
+
return dirs.map((currentDir) => sharedFileIn(currentDir, cache)).filter((file) => Boolean(file));
|
|
835
1029
|
}
|
|
836
1030
|
async function scanRoutes(routesDir) {
|
|
837
1031
|
if (!(0, import_node_fs2.existsSync)(routesDir)) {
|
|
@@ -843,6 +1037,7 @@ async function scanRoutes(routesDir) {
|
|
|
843
1037
|
onlyFiles: true
|
|
844
1038
|
});
|
|
845
1039
|
const routes = [];
|
|
1040
|
+
const sharedCache = /* @__PURE__ */ new Map();
|
|
846
1041
|
for (const file of files) {
|
|
847
1042
|
const method = methodFromFile((0, import_node_path2.basename)(file));
|
|
848
1043
|
if (!method) {
|
|
@@ -858,7 +1053,7 @@ async function scanRoutes(routesDir) {
|
|
|
858
1053
|
routeDir,
|
|
859
1054
|
routeSegments,
|
|
860
1055
|
params,
|
|
861
|
-
sharedFiles: sharedFilesForDir(routesDir, routeDir)
|
|
1056
|
+
sharedFiles: sharedFilesForDir(routesDir, routeDir, sharedCache)
|
|
862
1057
|
});
|
|
863
1058
|
}
|
|
864
1059
|
return routes.sort((left, right) => {
|
|
@@ -871,9 +1066,11 @@ async function scanRoutes(routesDir) {
|
|
|
871
1066
|
}
|
|
872
1067
|
|
|
873
1068
|
// src/app.ts
|
|
874
|
-
function loadModule(file) {
|
|
1069
|
+
function loadModule(file, force = true) {
|
|
875
1070
|
const resolved = require.resolve(file);
|
|
876
|
-
|
|
1071
|
+
if (force) {
|
|
1072
|
+
delete require.cache[resolved];
|
|
1073
|
+
}
|
|
877
1074
|
return require(resolved);
|
|
878
1075
|
}
|
|
879
1076
|
function interopDefault(value) {
|
|
@@ -935,20 +1132,13 @@ function resolveAliasTarget(cwd, target, capture = "") {
|
|
|
935
1132
|
}
|
|
936
1133
|
function matchAlias(request, key) {
|
|
937
1134
|
if (key.includes("*")) {
|
|
938
|
-
const [
|
|
939
|
-
if (request.startsWith(
|
|
940
|
-
return request.slice(
|
|
1135
|
+
const [prefix, suffix = ""] = key.split("*");
|
|
1136
|
+
if (request.startsWith(prefix) && request.endsWith(suffix)) {
|
|
1137
|
+
return request.slice(prefix.length, request.length - suffix.length);
|
|
941
1138
|
}
|
|
942
1139
|
return void 0;
|
|
943
1140
|
}
|
|
944
|
-
|
|
945
|
-
return "";
|
|
946
|
-
}
|
|
947
|
-
const prefix = `${key}/`;
|
|
948
|
-
if (request.startsWith(prefix)) {
|
|
949
|
-
return request.slice(prefix.length);
|
|
950
|
-
}
|
|
951
|
-
return void 0;
|
|
1141
|
+
return request === key ? "" : void 0;
|
|
952
1142
|
}
|
|
953
1143
|
function resolveAliasRequest(request, alias, cwd) {
|
|
954
1144
|
for (const [key, value] of Object.entries(alias ?? {})) {
|
|
@@ -1010,40 +1200,85 @@ function resolveGiriPaths(config, cwd = process.cwd()) {
|
|
|
1010
1200
|
async function buildGiriApp(config, options = {}) {
|
|
1011
1201
|
const paths = resolveGiriPaths(config, options.cwd);
|
|
1012
1202
|
const routes = await scanRoutes(paths.routesDir);
|
|
1203
|
+
if (options.lazy) {
|
|
1204
|
+
for (const route of routes) {
|
|
1205
|
+
assertRouteHandleExport(route.file);
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1013
1208
|
const app = config.adapter.createApp();
|
|
1014
1209
|
ensureGiriAliasResolver(paths.outDir);
|
|
1015
|
-
|
|
1016
|
-
|
|
1210
|
+
if (options.lazy && (!options.loaderRegistered || !options.aliasResolverRegistered)) {
|
|
1211
|
+
throw new Error("Lazy route loading requires persistent loader and alias registrations.");
|
|
1212
|
+
}
|
|
1213
|
+
const loader = options.loaderRegistered ? void 0 : await safeRegister();
|
|
1214
|
+
const unregisterAliasResolver = options.aliasResolverRegistered ? void 0 : registerAliasResolver(config.alias, paths.cwd);
|
|
1017
1215
|
try {
|
|
1018
|
-
|
|
1019
|
-
|
|
1216
|
+
const dirty = options.dirty;
|
|
1217
|
+
const forceReload = dirty === void 0;
|
|
1218
|
+
const isDirty = (file) => forceReload || dirty.has(file);
|
|
1219
|
+
const sharedCache = /* @__PURE__ */ new Map();
|
|
1220
|
+
const loadShared = (file) => {
|
|
1221
|
+
if (!sharedCache.has(file)) {
|
|
1222
|
+
sharedCache.set(file, loadModule(file, isDirty(file)));
|
|
1223
|
+
}
|
|
1224
|
+
return sharedCache.get(file);
|
|
1225
|
+
};
|
|
1226
|
+
const runtimeFor = (route) => {
|
|
1227
|
+
const routeModule = loadModule(route.file, isDirty(route.file));
|
|
1020
1228
|
if (typeof routeModule.handle !== "function") {
|
|
1021
1229
|
throw new Error(`${route.file} must export a named handle function.`);
|
|
1022
1230
|
}
|
|
1023
1231
|
const folderMiddleware = routeModule.config?.skipInherited ? [] : route.sharedFiles.flatMap(
|
|
1024
|
-
(file) => normalizeMiddleware(
|
|
1232
|
+
(file) => normalizeMiddleware(loadShared(file).middleware, file)
|
|
1025
1233
|
);
|
|
1026
1234
|
const verbMiddleware = normalizeMiddleware(routeModule.middleware, route.file);
|
|
1027
|
-
|
|
1235
|
+
return {
|
|
1028
1236
|
method: route.method,
|
|
1029
1237
|
path: route.path,
|
|
1030
1238
|
handle: routeModule.handle,
|
|
1031
1239
|
middleware: [...folderMiddleware, ...verbMiddleware],
|
|
1032
1240
|
input: routeInput(routeModule, route.file),
|
|
1033
|
-
services: options.services
|
|
1241
|
+
services: options.services,
|
|
1242
|
+
cookieSecret: config.cookieSecret
|
|
1243
|
+
};
|
|
1244
|
+
};
|
|
1245
|
+
for (const route of routes) {
|
|
1246
|
+
if (!options.lazy) {
|
|
1247
|
+
config.adapter.register(app, runtimeFor(route));
|
|
1248
|
+
continue;
|
|
1249
|
+
}
|
|
1250
|
+
let runtime;
|
|
1251
|
+
const getRuntime = () => {
|
|
1252
|
+
runtime ??= runtimeFor(route);
|
|
1253
|
+
return runtime;
|
|
1254
|
+
};
|
|
1255
|
+
config.adapter.register(app, {
|
|
1256
|
+
method: route.method,
|
|
1257
|
+
path: route.path,
|
|
1258
|
+
get handle() {
|
|
1259
|
+
return getRuntime().handle;
|
|
1260
|
+
},
|
|
1261
|
+
get middleware() {
|
|
1262
|
+
return getRuntime().middleware;
|
|
1263
|
+
},
|
|
1264
|
+
get input() {
|
|
1265
|
+
return getRuntime().input;
|
|
1266
|
+
},
|
|
1267
|
+
services: options.services,
|
|
1268
|
+
cookieSecret: config.cookieSecret
|
|
1034
1269
|
});
|
|
1035
1270
|
}
|
|
1036
1271
|
} finally {
|
|
1037
|
-
unregisterAliasResolver();
|
|
1038
|
-
unregister();
|
|
1272
|
+
unregisterAliasResolver?.();
|
|
1273
|
+
loader?.unregister();
|
|
1039
1274
|
}
|
|
1040
1275
|
return { app, routes, paths };
|
|
1041
1276
|
}
|
|
1042
1277
|
|
|
1043
1278
|
// src/generator/sync.ts
|
|
1044
|
-
var
|
|
1045
|
-
var
|
|
1046
|
-
var
|
|
1279
|
+
var import_node_fs8 = require("fs");
|
|
1280
|
+
var import_promises4 = require("fs/promises");
|
|
1281
|
+
var import_node_path12 = require("path");
|
|
1047
1282
|
|
|
1048
1283
|
// src/generator/app-types.ts
|
|
1049
1284
|
var import_node_fs4 = require("fs");
|
|
@@ -1295,6 +1530,7 @@ function buildOpenApiDocument(paths, routes, data = {}) {
|
|
|
1295
1530
|
const documentPaths = {};
|
|
1296
1531
|
const schemas = {};
|
|
1297
1532
|
const securitySchemes = {};
|
|
1533
|
+
const tagOrder = [];
|
|
1298
1534
|
for (const route of routes) {
|
|
1299
1535
|
if (data.hiddenFiles?.has(route.file)) {
|
|
1300
1536
|
continue;
|
|
@@ -1302,10 +1538,32 @@ function buildOpenApiDocument(paths, routes, data = {}) {
|
|
|
1302
1538
|
const responses = data.responsesByFile?.get(route.file);
|
|
1303
1539
|
const input = data.inputsByFile?.get(route.file);
|
|
1304
1540
|
const security = data.securityByFile?.get(route.file);
|
|
1541
|
+
const meta = data.openapiByFile?.get(route.file);
|
|
1305
1542
|
for (const [name, schema] of Object.entries(responses?.$defs ?? {})) {
|
|
1306
1543
|
schemas[name] = rewriteRefs(schema);
|
|
1307
1544
|
}
|
|
1308
|
-
const operation = {
|
|
1545
|
+
const operation = {};
|
|
1546
|
+
if (meta?.tags && meta.tags.length > 0) {
|
|
1547
|
+
operation.tags = meta.tags;
|
|
1548
|
+
for (const tag of meta.tags) {
|
|
1549
|
+
if (!tagOrder.includes(tag)) {
|
|
1550
|
+
tagOrder.push(tag);
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
if (meta?.summary) {
|
|
1555
|
+
operation.summary = meta.summary;
|
|
1556
|
+
}
|
|
1557
|
+
if (meta?.description) {
|
|
1558
|
+
operation.description = meta.description;
|
|
1559
|
+
}
|
|
1560
|
+
if (meta?.operationId) {
|
|
1561
|
+
operation.operationId = meta.operationId;
|
|
1562
|
+
}
|
|
1563
|
+
if (meta?.deprecated) {
|
|
1564
|
+
operation.deprecated = true;
|
|
1565
|
+
}
|
|
1566
|
+
operation.responses = buildResponses(responses?.responses ?? []);
|
|
1309
1567
|
const parameters = [...pathParameters(route), ...queryParameters(input?.query)];
|
|
1310
1568
|
if (parameters.length > 0) {
|
|
1311
1569
|
operation.parameters = parameters;
|
|
@@ -1337,6 +1595,9 @@ function buildOpenApiDocument(paths, routes, data = {}) {
|
|
|
1337
1595
|
info: readProjectInfo(paths.cwd),
|
|
1338
1596
|
paths: documentPaths
|
|
1339
1597
|
};
|
|
1598
|
+
if (tagOrder.length > 0) {
|
|
1599
|
+
document.tags = tagOrder.map((name) => ({ name }));
|
|
1600
|
+
}
|
|
1340
1601
|
const components = {};
|
|
1341
1602
|
if (Object.keys(schemas).length > 0) {
|
|
1342
1603
|
components.schemas = schemas;
|
|
@@ -1368,14 +1629,29 @@ function paramsType(params) {
|
|
|
1368
1629
|
${fields}
|
|
1369
1630
|
}`;
|
|
1370
1631
|
}
|
|
1371
|
-
function
|
|
1372
|
-
|
|
1373
|
-
|
|
1632
|
+
function middlewareVarsType(typesDir, sharedFile) {
|
|
1633
|
+
const spec = JSON.stringify(moduleSpecifier(typesDir, sharedFile));
|
|
1634
|
+
return `(typeof import(${spec}) extends { middleware: infer M } ? import("@boon4681/giri").InferStackVars<M> : {})`;
|
|
1635
|
+
}
|
|
1636
|
+
function ownSharedFile(dir, sharedFiles) {
|
|
1637
|
+
for (let index = sharedFiles.length - 1; index >= 0; index -= 1) {
|
|
1638
|
+
if ((0, import_node_path8.dirname)(sharedFiles[index]) === dir) {
|
|
1639
|
+
return sharedFiles[index];
|
|
1640
|
+
}
|
|
1374
1641
|
}
|
|
1375
|
-
return
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1642
|
+
return void 0;
|
|
1643
|
+
}
|
|
1644
|
+
function varsType(paths, file, dir, sharedFiles) {
|
|
1645
|
+
const typesDir = (0, import_node_path8.dirname)(file);
|
|
1646
|
+
const parts = [];
|
|
1647
|
+
if (dir !== paths.routesDir) {
|
|
1648
|
+
parts.push(`import(${JSON.stringify(importPath(file, typeFilePath(paths, (0, import_node_path8.dirname)(dir))))}).Vars`);
|
|
1649
|
+
}
|
|
1650
|
+
const ownShared = ownSharedFile(dir, sharedFiles);
|
|
1651
|
+
if (ownShared) {
|
|
1652
|
+
parts.push(middlewareVarsType(typesDir, ownShared));
|
|
1653
|
+
}
|
|
1654
|
+
return parts.length > 0 ? parts.join("\n & ") : "{}";
|
|
1379
1655
|
}
|
|
1380
1656
|
function methodExports(typesDir, verbs) {
|
|
1381
1657
|
return verbs.map(({ method, file }) => {
|
|
@@ -1386,14 +1662,14 @@ function methodExports(typesDir, verbs) {
|
|
|
1386
1662
|
});
|
|
1387
1663
|
}
|
|
1388
1664
|
async function writeParamTypes(paths, folders) {
|
|
1389
|
-
|
|
1665
|
+
await Promise.all(folders.map(({ dir, params, sharedFiles, verbs }) => {
|
|
1390
1666
|
const file = typeFilePath(paths, dir);
|
|
1391
1667
|
const typesDir = (0, import_node_path8.dirname)(file);
|
|
1392
1668
|
const lines = [
|
|
1393
1669
|
GENERATED_HEADER,
|
|
1394
1670
|
`export type Params = ${paramsType(params)};`,
|
|
1395
1671
|
"export type RouteParams = Params;",
|
|
1396
|
-
`type Vars = ${varsType(
|
|
1672
|
+
`export type Vars = ${varsType(paths, file, dir, sharedFiles)};`,
|
|
1397
1673
|
"export type Middleware<Injects extends Record<string, unknown> = {}> =",
|
|
1398
1674
|
' import("@boon4681/giri").Middleware<Params, import("@boon4681/giri").ValidatedInput, Injects>;',
|
|
1399
1675
|
'export type Handle<Input extends import("@boon4681/giri").ValidatedInput = import("@boon4681/giri").ValidatedInput> =',
|
|
@@ -1403,10 +1679,14 @@ async function writeParamTypes(paths, folders) {
|
|
|
1403
1679
|
lines.push(...methodExports(typesDir, verbs));
|
|
1404
1680
|
}
|
|
1405
1681
|
lines.push("");
|
|
1406
|
-
|
|
1407
|
-
}
|
|
1682
|
+
return writeGenerated(file, lines.join("\n"));
|
|
1683
|
+
}));
|
|
1408
1684
|
}
|
|
1409
1685
|
|
|
1686
|
+
// src/generator/route-meta.ts
|
|
1687
|
+
var import_node_fs6 = require("fs");
|
|
1688
|
+
var import_typescript2 = __toESM(require("typescript"));
|
|
1689
|
+
|
|
1410
1690
|
// src/generator/inputs.ts
|
|
1411
1691
|
function sanitize(schema) {
|
|
1412
1692
|
const { $schema, ...rest } = schema;
|
|
@@ -1467,28 +1747,315 @@ function readInput(routeModule) {
|
|
|
1467
1747
|
}
|
|
1468
1748
|
return input.body || input.query ? input : void 0;
|
|
1469
1749
|
}
|
|
1470
|
-
function
|
|
1471
|
-
|
|
1750
|
+
function hasExportModifier2(node) {
|
|
1751
|
+
return import_typescript2.default.canHaveModifiers(node) && (import_typescript2.default.getModifiers(node)?.some((modifier) => modifier.kind === import_typescript2.default.SyntaxKind.ExportKeyword) ?? false);
|
|
1752
|
+
}
|
|
1753
|
+
function unwrapExpression(expression) {
|
|
1754
|
+
let current = expression;
|
|
1755
|
+
while (import_typescript2.default.isParenthesizedExpression(current) || import_typescript2.default.isAsExpression(current) || import_typescript2.default.isSatisfiesExpression(current)) {
|
|
1756
|
+
current = current.expression;
|
|
1757
|
+
}
|
|
1758
|
+
return current;
|
|
1759
|
+
}
|
|
1760
|
+
function staticBoolean(expression) {
|
|
1761
|
+
const value = unwrapExpression(expression);
|
|
1762
|
+
if (value.kind === import_typescript2.default.SyntaxKind.TrueKeyword) {
|
|
1472
1763
|
return true;
|
|
1473
1764
|
}
|
|
1474
|
-
if (value ===
|
|
1765
|
+
if (value.kind === import_typescript2.default.SyntaxKind.FalseKeyword) {
|
|
1475
1766
|
return false;
|
|
1476
1767
|
}
|
|
1477
|
-
|
|
1478
|
-
|
|
1768
|
+
return void 0;
|
|
1769
|
+
}
|
|
1770
|
+
function staticString(expression) {
|
|
1771
|
+
const value = unwrapExpression(expression);
|
|
1772
|
+
return import_typescript2.default.isStringLiteralLike(value) ? value.text : void 0;
|
|
1773
|
+
}
|
|
1774
|
+
function staticStringArray(expression) {
|
|
1775
|
+
const value = unwrapExpression(expression);
|
|
1776
|
+
if (!import_typescript2.default.isArrayLiteralExpression(value)) {
|
|
1777
|
+
return void 0;
|
|
1778
|
+
}
|
|
1779
|
+
const strings = [];
|
|
1780
|
+
for (const element of value.elements) {
|
|
1781
|
+
const string = staticString(element);
|
|
1782
|
+
if (string === void 0) {
|
|
1783
|
+
return void 0;
|
|
1784
|
+
}
|
|
1785
|
+
strings.push(string);
|
|
1786
|
+
}
|
|
1787
|
+
return strings;
|
|
1788
|
+
}
|
|
1789
|
+
function propertyName2(name) {
|
|
1790
|
+
if (import_typescript2.default.isIdentifier(name) || import_typescript2.default.isStringLiteral(name) || import_typescript2.default.isNumericLiteral(name)) {
|
|
1791
|
+
return name.text;
|
|
1479
1792
|
}
|
|
1480
1793
|
return void 0;
|
|
1481
1794
|
}
|
|
1482
|
-
function
|
|
1795
|
+
function collectImportedNames(source) {
|
|
1796
|
+
const names = /* @__PURE__ */ new Set();
|
|
1797
|
+
for (const statement of source.statements) {
|
|
1798
|
+
if (!import_typescript2.default.isImportDeclaration(statement)) {
|
|
1799
|
+
continue;
|
|
1800
|
+
}
|
|
1801
|
+
const clause = statement.importClause;
|
|
1802
|
+
if (!clause) {
|
|
1803
|
+
continue;
|
|
1804
|
+
}
|
|
1805
|
+
if (clause.name) {
|
|
1806
|
+
names.add(clause.name.text);
|
|
1807
|
+
}
|
|
1808
|
+
const bindings = clause.namedBindings;
|
|
1809
|
+
if (bindings && import_typescript2.default.isNamespaceImport(bindings)) {
|
|
1810
|
+
names.add(bindings.name.text);
|
|
1811
|
+
}
|
|
1812
|
+
if (bindings && import_typescript2.default.isNamedImports(bindings)) {
|
|
1813
|
+
for (const element of bindings.elements) {
|
|
1814
|
+
names.add(element.name.text);
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
return names;
|
|
1819
|
+
}
|
|
1820
|
+
function expressionReferencesImportedMiddleware(expression, importedNames) {
|
|
1821
|
+
let found = false;
|
|
1822
|
+
const allowedImportedHelpers = /* @__PURE__ */ new Set(["stack", "fromHono"]);
|
|
1823
|
+
const visit = (node) => {
|
|
1824
|
+
if (found) {
|
|
1825
|
+
return;
|
|
1826
|
+
}
|
|
1827
|
+
if (import_typescript2.default.isIdentifier(node) && importedNames.has(node.text) && !allowedImportedHelpers.has(node.text)) {
|
|
1828
|
+
found = true;
|
|
1829
|
+
return;
|
|
1830
|
+
}
|
|
1831
|
+
import_typescript2.default.forEachChild(node, visit);
|
|
1832
|
+
};
|
|
1833
|
+
visit(expression);
|
|
1834
|
+
return found;
|
|
1835
|
+
}
|
|
1836
|
+
function parseStaticOpenApi(expression) {
|
|
1837
|
+
const value = unwrapExpression(expression);
|
|
1838
|
+
const boolean = staticBoolean(value);
|
|
1839
|
+
if (boolean !== void 0) {
|
|
1840
|
+
return boolean;
|
|
1841
|
+
}
|
|
1842
|
+
if (!import_typescript2.default.isObjectLiteralExpression(value)) {
|
|
1843
|
+
return void 0;
|
|
1844
|
+
}
|
|
1845
|
+
const openapi = {};
|
|
1846
|
+
for (const property of value.properties) {
|
|
1847
|
+
if (!import_typescript2.default.isPropertyAssignment(property)) {
|
|
1848
|
+
return void 0;
|
|
1849
|
+
}
|
|
1850
|
+
const name = propertyName2(property.name);
|
|
1851
|
+
if (!name) {
|
|
1852
|
+
return void 0;
|
|
1853
|
+
}
|
|
1854
|
+
if (name === "hidden") {
|
|
1855
|
+
const hidden = staticBoolean(property.initializer);
|
|
1856
|
+
if (hidden === void 0) {
|
|
1857
|
+
return void 0;
|
|
1858
|
+
}
|
|
1859
|
+
openapi.hidden = hidden;
|
|
1860
|
+
} else if (name === "tags") {
|
|
1861
|
+
const tags = staticStringArray(property.initializer);
|
|
1862
|
+
if (!tags) {
|
|
1863
|
+
return void 0;
|
|
1864
|
+
}
|
|
1865
|
+
openapi.tags = tags;
|
|
1866
|
+
} else if (name === "summary" || name === "description" || name === "operationId") {
|
|
1867
|
+
const string = staticString(property.initializer);
|
|
1868
|
+
if (string === void 0) {
|
|
1869
|
+
return void 0;
|
|
1870
|
+
}
|
|
1871
|
+
openapi[name] = string;
|
|
1872
|
+
} else if (name === "deprecated") {
|
|
1873
|
+
const deprecated = staticBoolean(property.initializer);
|
|
1874
|
+
if (deprecated === void 0) {
|
|
1875
|
+
return void 0;
|
|
1876
|
+
}
|
|
1877
|
+
openapi.deprecated = deprecated;
|
|
1878
|
+
} else {
|
|
1879
|
+
return void 0;
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
return openapi;
|
|
1883
|
+
}
|
|
1884
|
+
function readStaticModuleMeta(file) {
|
|
1885
|
+
let source;
|
|
1886
|
+
try {
|
|
1887
|
+
source = import_typescript2.default.createSourceFile(file, (0, import_node_fs6.readFileSync)(file, "utf8"), import_typescript2.default.ScriptTarget.Latest, true);
|
|
1888
|
+
} catch {
|
|
1889
|
+
return void 0;
|
|
1890
|
+
}
|
|
1891
|
+
const importedNames = collectImportedNames(source);
|
|
1892
|
+
const sourceText = source.getFullText();
|
|
1893
|
+
const canSkipMiddlewareRuntime = !sourceText.includes("defineMiddleware") && !sourceText.includes(".openapi");
|
|
1894
|
+
const meta = { middlewareSecurity: false };
|
|
1895
|
+
for (const statement of source.statements) {
|
|
1896
|
+
if (import_typescript2.default.isImportDeclaration(statement) || import_typescript2.default.isInterfaceDeclaration(statement) || import_typescript2.default.isTypeAliasDeclaration(statement) || import_typescript2.default.isEmptyStatement(statement) || !hasExportModifier2(statement)) {
|
|
1897
|
+
continue;
|
|
1898
|
+
}
|
|
1899
|
+
if (import_typescript2.default.isFunctionDeclaration(statement) && statement.name?.text === "handle") {
|
|
1900
|
+
continue;
|
|
1901
|
+
}
|
|
1902
|
+
if (import_typescript2.default.isVariableStatement(statement)) {
|
|
1903
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
1904
|
+
if (!import_typescript2.default.isIdentifier(declaration.name)) {
|
|
1905
|
+
return void 0;
|
|
1906
|
+
}
|
|
1907
|
+
const name = declaration.name.text;
|
|
1908
|
+
if (name === "openapi") {
|
|
1909
|
+
if (!declaration.initializer) {
|
|
1910
|
+
return void 0;
|
|
1911
|
+
}
|
|
1912
|
+
const openapi = parseStaticOpenApi(declaration.initializer);
|
|
1913
|
+
if (openapi === void 0) {
|
|
1914
|
+
return void 0;
|
|
1915
|
+
}
|
|
1916
|
+
meta.openapi = openapi;
|
|
1917
|
+
} else if (name === "handle") {
|
|
1918
|
+
if (!declaration.initializer || !import_typescript2.default.isArrowFunction(declaration.initializer) && !import_typescript2.default.isFunctionExpression(declaration.initializer)) {
|
|
1919
|
+
return void 0;
|
|
1920
|
+
}
|
|
1921
|
+
continue;
|
|
1922
|
+
} else if (name === "middleware") {
|
|
1923
|
+
if (!declaration.initializer || !canSkipMiddlewareRuntime || expressionReferencesImportedMiddleware(declaration.initializer, importedNames)) {
|
|
1924
|
+
return void 0;
|
|
1925
|
+
}
|
|
1926
|
+
meta.middlewareSecurity = false;
|
|
1927
|
+
continue;
|
|
1928
|
+
} else {
|
|
1929
|
+
return void 0;
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
continue;
|
|
1933
|
+
}
|
|
1934
|
+
return void 0;
|
|
1935
|
+
}
|
|
1936
|
+
return meta;
|
|
1937
|
+
}
|
|
1938
|
+
function resolveStaticOpenApi(route, routeModule, loadShared) {
|
|
1483
1939
|
let hidden = false;
|
|
1940
|
+
const tags = [];
|
|
1941
|
+
const meta = {};
|
|
1942
|
+
const apply = (value, isVerb) => {
|
|
1943
|
+
if (value === false) {
|
|
1944
|
+
hidden = true;
|
|
1945
|
+
return;
|
|
1946
|
+
}
|
|
1947
|
+
if (value === true) {
|
|
1948
|
+
hidden = false;
|
|
1949
|
+
return;
|
|
1950
|
+
}
|
|
1951
|
+
if (!value) {
|
|
1952
|
+
return;
|
|
1953
|
+
}
|
|
1954
|
+
if (typeof value.hidden === "boolean") {
|
|
1955
|
+
hidden = value.hidden;
|
|
1956
|
+
}
|
|
1957
|
+
if (value.tags) {
|
|
1958
|
+
tags.push(...value.tags);
|
|
1959
|
+
}
|
|
1960
|
+
if (typeof value.summary === "string") {
|
|
1961
|
+
meta.summary = value.summary;
|
|
1962
|
+
}
|
|
1963
|
+
if (typeof value.description === "string") {
|
|
1964
|
+
meta.description = value.description;
|
|
1965
|
+
}
|
|
1966
|
+
if (typeof value.deprecated === "boolean") {
|
|
1967
|
+
meta.deprecated = value.deprecated;
|
|
1968
|
+
}
|
|
1969
|
+
if (isVerb && typeof value.operationId === "string") {
|
|
1970
|
+
meta.operationId = value.operationId;
|
|
1971
|
+
}
|
|
1972
|
+
};
|
|
1484
1973
|
for (const file of route.sharedFiles) {
|
|
1485
|
-
const
|
|
1486
|
-
if (
|
|
1487
|
-
|
|
1974
|
+
const shared = loadShared(file);
|
|
1975
|
+
if (!shared) {
|
|
1976
|
+
return void 0;
|
|
1488
1977
|
}
|
|
1978
|
+
apply(shared.openapi, false);
|
|
1979
|
+
}
|
|
1980
|
+
apply(routeModule.openapi, true);
|
|
1981
|
+
if (tags.length > 0) {
|
|
1982
|
+
meta.tags = [...new Set(tags)];
|
|
1489
1983
|
}
|
|
1490
|
-
|
|
1491
|
-
|
|
1984
|
+
return { hidden, meta };
|
|
1985
|
+
}
|
|
1986
|
+
function extractStaticMeta(route, routeModule, loadShared) {
|
|
1987
|
+
const openapi = resolveStaticOpenApi(route, routeModule, loadShared);
|
|
1988
|
+
if (!openapi) {
|
|
1989
|
+
return void 0;
|
|
1990
|
+
}
|
|
1991
|
+
const meta = {};
|
|
1992
|
+
if (openapi.hidden) {
|
|
1993
|
+
meta.hidden = true;
|
|
1994
|
+
}
|
|
1995
|
+
if (Object.keys(openapi.meta).length > 0) {
|
|
1996
|
+
meta.openapi = openapi.meta;
|
|
1997
|
+
}
|
|
1998
|
+
return meta;
|
|
1999
|
+
}
|
|
2000
|
+
function extractRuntimeSharedMeta(route, routeModule, loadShared) {
|
|
2001
|
+
const meta = {};
|
|
2002
|
+
const security = collectSecurity(route, {}, loadShared);
|
|
2003
|
+
const { hidden, meta: openapi } = resolveOpenApi(route, { openapi: routeModule.openapi }, loadShared);
|
|
2004
|
+
if (security) {
|
|
2005
|
+
meta.security = security;
|
|
2006
|
+
}
|
|
2007
|
+
if (hidden) {
|
|
2008
|
+
meta.hidden = true;
|
|
2009
|
+
}
|
|
2010
|
+
if (Object.keys(openapi).length > 0) {
|
|
2011
|
+
meta.openapi = openapi;
|
|
2012
|
+
}
|
|
2013
|
+
return meta;
|
|
2014
|
+
}
|
|
2015
|
+
function resolveOpenApi(route, routeModule, loadShared) {
|
|
2016
|
+
let hidden = false;
|
|
2017
|
+
const tags = [];
|
|
2018
|
+
const meta = {};
|
|
2019
|
+
const apply = (value, isVerb) => {
|
|
2020
|
+
if (value === false) {
|
|
2021
|
+
hidden = true;
|
|
2022
|
+
return;
|
|
2023
|
+
}
|
|
2024
|
+
if (value === true) {
|
|
2025
|
+
hidden = false;
|
|
2026
|
+
return;
|
|
2027
|
+
}
|
|
2028
|
+
if (!value || typeof value !== "object") {
|
|
2029
|
+
return;
|
|
2030
|
+
}
|
|
2031
|
+
const o = value;
|
|
2032
|
+
if ("hidden" in o) {
|
|
2033
|
+
hidden = Boolean(o.hidden);
|
|
2034
|
+
}
|
|
2035
|
+
if (Array.isArray(o.tags)) {
|
|
2036
|
+
tags.push(...o.tags.filter((tag) => typeof tag === "string"));
|
|
2037
|
+
}
|
|
2038
|
+
if (typeof o.summary === "string") {
|
|
2039
|
+
meta.summary = o.summary;
|
|
2040
|
+
}
|
|
2041
|
+
if (typeof o.description === "string") {
|
|
2042
|
+
meta.description = o.description;
|
|
2043
|
+
}
|
|
2044
|
+
if (typeof o.deprecated === "boolean") {
|
|
2045
|
+
meta.deprecated = o.deprecated;
|
|
2046
|
+
}
|
|
2047
|
+
if (isVerb && typeof o.operationId === "string") {
|
|
2048
|
+
meta.operationId = o.operationId;
|
|
2049
|
+
}
|
|
2050
|
+
};
|
|
2051
|
+
for (const file of route.sharedFiles) {
|
|
2052
|
+
apply(loadShared(file).openapi, false);
|
|
2053
|
+
}
|
|
2054
|
+
apply(routeModule.openapi, true);
|
|
2055
|
+
if (tags.length > 0) {
|
|
2056
|
+
meta.tags = [...new Set(tags)];
|
|
2057
|
+
}
|
|
2058
|
+
return { hidden, meta };
|
|
1492
2059
|
}
|
|
1493
2060
|
function collectSecurity(route, routeModule, loadShared) {
|
|
1494
2061
|
const skipInherited = Boolean(
|
|
@@ -1520,6 +2087,33 @@ function collectSecurity(route, routeModule, loadShared) {
|
|
|
1520
2087
|
}
|
|
1521
2088
|
async function extractRouteMeta(config, paths, routes) {
|
|
1522
2089
|
const byFile = /* @__PURE__ */ new Map();
|
|
2090
|
+
const remainingRoutes = [];
|
|
2091
|
+
const runtimeSharedRoutes = [];
|
|
2092
|
+
const staticCache = /* @__PURE__ */ new Map();
|
|
2093
|
+
const loadStatic = (file) => {
|
|
2094
|
+
if (!staticCache.has(file)) {
|
|
2095
|
+
staticCache.set(file, readStaticModuleMeta(file));
|
|
2096
|
+
}
|
|
2097
|
+
return staticCache.get(file);
|
|
2098
|
+
};
|
|
2099
|
+
for (const route of routes) {
|
|
2100
|
+
const routeModule = loadStatic(route.file);
|
|
2101
|
+
if (!routeModule) {
|
|
2102
|
+
remainingRoutes.push(route);
|
|
2103
|
+
continue;
|
|
2104
|
+
}
|
|
2105
|
+
const meta = extractStaticMeta(route, routeModule, loadStatic);
|
|
2106
|
+
if (meta) {
|
|
2107
|
+
if (meta.hidden || meta.openapi) {
|
|
2108
|
+
byFile.set(route.file, meta);
|
|
2109
|
+
}
|
|
2110
|
+
continue;
|
|
2111
|
+
}
|
|
2112
|
+
runtimeSharedRoutes.push({ route, routeModule });
|
|
2113
|
+
}
|
|
2114
|
+
if (remainingRoutes.length === 0 && runtimeSharedRoutes.length === 0) {
|
|
2115
|
+
return byFile;
|
|
2116
|
+
}
|
|
1523
2117
|
const { unregister } = await safeRegister();
|
|
1524
2118
|
const unregisterAlias = registerAliasResolver(config.alias, paths.cwd);
|
|
1525
2119
|
const sharedCache = /* @__PURE__ */ new Map();
|
|
@@ -1534,13 +2128,19 @@ async function extractRouteMeta(config, paths, routes) {
|
|
|
1534
2128
|
return sharedCache.get(file);
|
|
1535
2129
|
};
|
|
1536
2130
|
try {
|
|
1537
|
-
for (const route of
|
|
2131
|
+
for (const { route, routeModule } of runtimeSharedRoutes) {
|
|
2132
|
+
const meta = extractRuntimeSharedMeta(route, routeModule, loadShared);
|
|
2133
|
+
if (meta.input || meta.security || meta.hidden || meta.openapi) {
|
|
2134
|
+
byFile.set(route.file, meta);
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
for (const route of remainingRoutes) {
|
|
1538
2138
|
try {
|
|
1539
2139
|
const routeModule = loadModule2(route.file);
|
|
1540
2140
|
const meta = {};
|
|
1541
2141
|
const input = readInput(routeModule);
|
|
1542
2142
|
const security = collectSecurity(route, routeModule, loadShared);
|
|
1543
|
-
const hidden =
|
|
2143
|
+
const { hidden, meta: openapi } = resolveOpenApi(route, routeModule, loadShared);
|
|
1544
2144
|
if (input) {
|
|
1545
2145
|
meta.input = input;
|
|
1546
2146
|
}
|
|
@@ -1550,7 +2150,10 @@ async function extractRouteMeta(config, paths, routes) {
|
|
|
1550
2150
|
if (hidden) {
|
|
1551
2151
|
meta.hidden = true;
|
|
1552
2152
|
}
|
|
1553
|
-
if (
|
|
2153
|
+
if (Object.keys(openapi).length > 0) {
|
|
2154
|
+
meta.openapi = openapi;
|
|
2155
|
+
}
|
|
2156
|
+
if (meta.input || meta.security || meta.hidden || meta.openapi) {
|
|
1554
2157
|
byFile.set(route.file, meta);
|
|
1555
2158
|
}
|
|
1556
2159
|
} catch {
|
|
@@ -1622,6 +2225,103 @@ async function writeTsConfig(paths, config) {
|
|
|
1622
2225
|
});
|
|
1623
2226
|
}
|
|
1624
2227
|
|
|
2228
|
+
// src/generator/cache.ts
|
|
2229
|
+
var import_node_crypto = require("crypto");
|
|
2230
|
+
var import_node_fs7 = require("fs");
|
|
2231
|
+
var import_promises3 = require("fs/promises");
|
|
2232
|
+
var import_node_path11 = require("path");
|
|
2233
|
+
var import_tinyglobby2 = require("tinyglobby");
|
|
2234
|
+
var CACHE_VERSION = 1;
|
|
2235
|
+
var SYNC_CACHE_NAME = ".sync-cache.json";
|
|
2236
|
+
function stableConfig(config) {
|
|
2237
|
+
const alias = Object.entries(config.alias ?? {}).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, Array.isArray(value) ? [...value] : value]);
|
|
2238
|
+
return { alias, outDir: config.outDir ?? ".giri" };
|
|
2239
|
+
}
|
|
2240
|
+
async function syncFingerprint(config, paths) {
|
|
2241
|
+
const outRelative = slash((0, import_node_path11.relative)(paths.cwd, paths.outDir));
|
|
2242
|
+
const ignore = ["**/node_modules/**", "**/.git/**"];
|
|
2243
|
+
if (outRelative && !outRelative.startsWith("..")) {
|
|
2244
|
+
ignore.push(`${outRelative}/**`);
|
|
2245
|
+
}
|
|
2246
|
+
const files = await (0, import_tinyglobby2.glob)([
|
|
2247
|
+
"src/**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs,json}",
|
|
2248
|
+
"giri.config.{ts,js,mts,cts,mjs,cjs}",
|
|
2249
|
+
"tsconfig*.json",
|
|
2250
|
+
"package.json",
|
|
2251
|
+
"package-lock.json",
|
|
2252
|
+
"npm-shrinkwrap.json",
|
|
2253
|
+
"yarn.lock",
|
|
2254
|
+
"pnpm-lock.yaml",
|
|
2255
|
+
"bun.lock",
|
|
2256
|
+
"bun.lockb"
|
|
2257
|
+
], {
|
|
2258
|
+
cwd: paths.cwd,
|
|
2259
|
+
absolute: false,
|
|
2260
|
+
onlyFiles: true,
|
|
2261
|
+
dot: true,
|
|
2262
|
+
ignore
|
|
2263
|
+
});
|
|
2264
|
+
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
2265
|
+
hash.update(JSON.stringify(stableConfig(config)));
|
|
2266
|
+
for (const file of files.sort()) {
|
|
2267
|
+
hash.update("\0");
|
|
2268
|
+
hash.update(slash(file));
|
|
2269
|
+
hash.update("\0");
|
|
2270
|
+
hash.update(await (0, import_promises3.readFile)((0, import_node_path11.resolve)(paths.cwd, file)));
|
|
2271
|
+
}
|
|
2272
|
+
return hash.digest("hex");
|
|
2273
|
+
}
|
|
2274
|
+
function cachePath(paths) {
|
|
2275
|
+
return (0, import_node_path11.join)(paths.outDir, SYNC_CACHE_NAME);
|
|
2276
|
+
}
|
|
2277
|
+
function serializePath(paths, file) {
|
|
2278
|
+
return slash((0, import_node_path11.relative)(paths.cwd, file));
|
|
2279
|
+
}
|
|
2280
|
+
function deserializePath(paths, file) {
|
|
2281
|
+
return slash((0, import_node_path11.resolve)(paths.cwd, file.split("/").join(import_node_path11.sep)));
|
|
2282
|
+
}
|
|
2283
|
+
function serializeMap(paths, values) {
|
|
2284
|
+
return [...values].map(([file, value]) => [serializePath(paths, file), value]);
|
|
2285
|
+
}
|
|
2286
|
+
function deserializeMap(paths, values) {
|
|
2287
|
+
return new Map(values.map(([file, value]) => [deserializePath(paths, file), value]));
|
|
2288
|
+
}
|
|
2289
|
+
async function readSyncCache(paths, fingerprint) {
|
|
2290
|
+
const file = cachePath(paths);
|
|
2291
|
+
if (!(0, import_node_fs7.existsSync)(file)) {
|
|
2292
|
+
return void 0;
|
|
2293
|
+
}
|
|
2294
|
+
try {
|
|
2295
|
+
const cache = JSON.parse(await (0, import_promises3.readFile)(file, "utf8"));
|
|
2296
|
+
if (cache.version !== CACHE_VERSION || cache.fingerprint !== fingerprint) {
|
|
2297
|
+
return void 0;
|
|
2298
|
+
}
|
|
2299
|
+
return {
|
|
2300
|
+
responsesByFile: deserializeMap(paths, cache.data.responsesByFile),
|
|
2301
|
+
inputsByFile: deserializeMap(paths, cache.data.inputsByFile),
|
|
2302
|
+
securityByFile: deserializeMap(paths, cache.data.securityByFile),
|
|
2303
|
+
hiddenFiles: new Set(cache.data.hiddenFiles.map((entry) => deserializePath(paths, entry))),
|
|
2304
|
+
openapiByFile: deserializeMap(paths, cache.data.openapiByFile)
|
|
2305
|
+
};
|
|
2306
|
+
} catch {
|
|
2307
|
+
return void 0;
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
async function writeSyncCache(paths, fingerprint, data) {
|
|
2311
|
+
const cache = {
|
|
2312
|
+
version: CACHE_VERSION,
|
|
2313
|
+
fingerprint,
|
|
2314
|
+
data: {
|
|
2315
|
+
responsesByFile: serializeMap(paths, data.responsesByFile),
|
|
2316
|
+
inputsByFile: serializeMap(paths, data.inputsByFile),
|
|
2317
|
+
securityByFile: serializeMap(paths, data.securityByFile),
|
|
2318
|
+
hiddenFiles: [...data.hiddenFiles].map((file) => serializePath(paths, file)),
|
|
2319
|
+
openapiByFile: serializeMap(paths, data.openapiByFile)
|
|
2320
|
+
}
|
|
2321
|
+
};
|
|
2322
|
+
await writeJson(cachePath(paths), cache);
|
|
2323
|
+
}
|
|
2324
|
+
|
|
1625
2325
|
// src/generator/sync.ts
|
|
1626
2326
|
async function typeFolders(paths, routes) {
|
|
1627
2327
|
const verbsByDir = /* @__PURE__ */ new Map();
|
|
@@ -1632,10 +2332,11 @@ async function typeFolders(paths, routes) {
|
|
|
1632
2332
|
verbsByDir.set(key, list);
|
|
1633
2333
|
}
|
|
1634
2334
|
const dirs = await scanRouteFolders(paths.routesDir);
|
|
2335
|
+
const sharedCache = /* @__PURE__ */ new Map();
|
|
1635
2336
|
return dirs.map((dir) => ({
|
|
1636
2337
|
dir,
|
|
1637
2338
|
params: routeParamsForDir(paths.routesDir, dir),
|
|
1638
|
-
sharedFiles: sharedFilesForDir(paths.routesDir, dir),
|
|
2339
|
+
sharedFiles: sharedFilesForDir(paths.routesDir, dir, sharedCache),
|
|
1639
2340
|
verbs: verbsByDir.get(slash(dir)) ?? []
|
|
1640
2341
|
}));
|
|
1641
2342
|
}
|
|
@@ -1647,11 +2348,9 @@ async function extractResponses(paths, routes) {
|
|
|
1647
2348
|
try {
|
|
1648
2349
|
const { createSchemaProgram: createSchemaProgram2, extractRouteResponses: extractRouteResponses2 } = await Promise.resolve().then(() => (init_schema(), schema_exports));
|
|
1649
2350
|
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
|
-
);
|
|
2351
|
+
const appTypes = (0, import_node_path12.join)(paths.outDir, "types", "app.d.ts");
|
|
2352
|
+
const roots = (0, import_node_fs8.existsSync)(appTypes) ? [...files, appTypes] : files;
|
|
2353
|
+
const program = createSchemaProgram2(paths, roots);
|
|
1655
2354
|
for (const file of files) {
|
|
1656
2355
|
byFile.set(file, extractRouteResponses2(program, file));
|
|
1657
2356
|
}
|
|
@@ -1664,8 +2363,9 @@ async function extractMeta(config, paths, routes) {
|
|
|
1664
2363
|
const inputsByFile = /* @__PURE__ */ new Map();
|
|
1665
2364
|
const securityByFile = /* @__PURE__ */ new Map();
|
|
1666
2365
|
const hiddenFiles = /* @__PURE__ */ new Set();
|
|
2366
|
+
const openapiByFile = /* @__PURE__ */ new Map();
|
|
1667
2367
|
if (routes.length === 0) {
|
|
1668
|
-
return { inputsByFile, securityByFile, hiddenFiles };
|
|
2368
|
+
return { inputsByFile, securityByFile, hiddenFiles, openapiByFile };
|
|
1669
2369
|
}
|
|
1670
2370
|
try {
|
|
1671
2371
|
const meta = await extractRouteMeta(config, paths, routes);
|
|
@@ -1679,63 +2379,91 @@ async function extractMeta(config, paths, routes) {
|
|
|
1679
2379
|
if (entry.hidden) {
|
|
1680
2380
|
hiddenFiles.add(file);
|
|
1681
2381
|
}
|
|
2382
|
+
if (entry.openapi) {
|
|
2383
|
+
openapiByFile.set(file, entry.openapi);
|
|
2384
|
+
}
|
|
1682
2385
|
}
|
|
1683
2386
|
} catch (error) {
|
|
1684
2387
|
console.warn(`giri: skipped input/security generation (${error.message}).`);
|
|
1685
2388
|
}
|
|
1686
|
-
return { inputsByFile, securityByFile, hiddenFiles };
|
|
2389
|
+
return { inputsByFile, securityByFile, hiddenFiles, openapiByFile };
|
|
1687
2390
|
}
|
|
1688
2391
|
async function syncProject(config, options = {}) {
|
|
1689
2392
|
const paths = resolveGiriPaths(config, options.cwd);
|
|
1690
2393
|
assertSafeOutDir(paths);
|
|
2394
|
+
const hadOutDir = (0, import_node_fs8.existsSync)(paths.outDir);
|
|
1691
2395
|
const routes = await scanRoutes(paths.routesDir);
|
|
1692
2396
|
const folders = await typeFolders(paths, routes);
|
|
1693
|
-
await (
|
|
2397
|
+
const fingerprint = await syncFingerprint(config, paths);
|
|
2398
|
+
const cached = await readSyncCache(paths, fingerprint);
|
|
2399
|
+
const generatedFiles = [
|
|
2400
|
+
(0, import_node_path12.join)(paths.outDir, "tsconfig.json"),
|
|
2401
|
+
(0, import_node_path12.join)(paths.outDir, "manifest.json"),
|
|
2402
|
+
(0, import_node_path12.join)(paths.outDir, "openapi.json"),
|
|
2403
|
+
(0, import_node_path12.join)(paths.outDir, "routes.d.ts"),
|
|
2404
|
+
(0, import_node_path12.join)(paths.outDir, "types", "app.d.ts"),
|
|
2405
|
+
...folders.map((folder) => typeFilePath(paths, folder.dir))
|
|
2406
|
+
];
|
|
2407
|
+
if (cached && generatedFiles.every(import_node_fs8.existsSync)) {
|
|
2408
|
+
return { paths, routes, folders, data: cached };
|
|
2409
|
+
}
|
|
2410
|
+
await (0, import_promises4.mkdir)(paths.outDir, { recursive: true });
|
|
1694
2411
|
await writeParamTypes(paths, folders);
|
|
1695
2412
|
await writeRouteTypes(paths, routes);
|
|
1696
2413
|
await writeAppTypes(paths);
|
|
1697
2414
|
await writeTsConfig(paths, config);
|
|
1698
|
-
const
|
|
1699
|
-
|
|
1700
|
-
|
|
2415
|
+
const data = cached ?? {
|
|
2416
|
+
responsesByFile: await extractResponses(paths, routes),
|
|
2417
|
+
...await extractMeta(config, paths, routes)
|
|
2418
|
+
};
|
|
1701
2419
|
await writeManifest(paths, routes, data);
|
|
1702
2420
|
await writeOpenApi(paths, routes, data);
|
|
1703
|
-
await
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
2421
|
+
await writeSyncCache(paths, fingerprint, data);
|
|
2422
|
+
if (hadOutDir) {
|
|
2423
|
+
await pruneDir(
|
|
2424
|
+
paths.outDir,
|
|
2425
|
+
/* @__PURE__ */ new Set([
|
|
2426
|
+
(0, import_node_path12.join)(paths.outDir, "tsconfig.json"),
|
|
2427
|
+
(0, import_node_path12.join)(paths.outDir, "manifest.json"),
|
|
2428
|
+
(0, import_node_path12.join)(paths.outDir, "openapi.json"),
|
|
2429
|
+
(0, import_node_path12.join)(paths.outDir, "routes.d.ts"),
|
|
2430
|
+
(0, import_node_path12.join)(paths.outDir, SYNC_CACHE_NAME),
|
|
2431
|
+
(0, import_node_path12.join)(paths.outDir, "types", "app.d.ts"),
|
|
2432
|
+
...folders.map((folder) => typeFilePath(paths, folder.dir))
|
|
2433
|
+
])
|
|
2434
|
+
);
|
|
2435
|
+
}
|
|
1714
2436
|
return { paths, routes, folders, data };
|
|
1715
2437
|
}
|
|
1716
2438
|
|
|
1717
2439
|
// src/generator/watch.ts
|
|
1718
|
-
var
|
|
2440
|
+
var import_node_fs10 = require("fs");
|
|
2441
|
+
var import_node_path15 = require("path");
|
|
2442
|
+
|
|
2443
|
+
// src/loader/import-graph.ts
|
|
2444
|
+
var import_node_fs9 = require("fs");
|
|
1719
2445
|
var import_node_path13 = require("path");
|
|
2446
|
+
var import_typescript6 = __toESM(require("typescript"));
|
|
2447
|
+
var import_tinyglobby3 = require("tinyglobby");
|
|
1720
2448
|
|
|
1721
2449
|
// src/loader/module-loader.ts
|
|
1722
|
-
var
|
|
2450
|
+
var import_node_path14 = require("path");
|
|
1723
2451
|
|
|
1724
2452
|
// src/lifecycle.ts
|
|
1725
|
-
var
|
|
1726
|
-
var
|
|
2453
|
+
var import_node_fs11 = require("fs");
|
|
2454
|
+
var import_node_path16 = require("path");
|
|
1727
2455
|
var MAIN_EXTENSIONS2 = ["ts", "tsx", "mts", "cts", "js", "jsx", "mjs", "cjs"];
|
|
1728
2456
|
function resolveMainFile(cwd) {
|
|
1729
2457
|
for (const ext of MAIN_EXTENSIONS2) {
|
|
1730
|
-
const file = (0,
|
|
1731
|
-
if ((0,
|
|
2458
|
+
const file = (0, import_node_path16.join)(cwd, "src", `main.${ext}`);
|
|
2459
|
+
if ((0, import_node_fs11.existsSync)(file)) {
|
|
1732
2460
|
return file;
|
|
1733
2461
|
}
|
|
1734
2462
|
}
|
|
1735
2463
|
return void 0;
|
|
1736
2464
|
}
|
|
1737
2465
|
async function loadLifecycle(cwd = process.cwd()) {
|
|
1738
|
-
const file = resolveMainFile((0,
|
|
2466
|
+
const file = resolveMainFile((0, import_node_path16.resolve)(cwd));
|
|
1739
2467
|
if (!file) {
|
|
1740
2468
|
return {};
|
|
1741
2469
|
}
|