@kosmojs/dev 0.0.0

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.
Files changed (44) hide show
  1. package/package.json +57 -0
  2. package/pkg/base-plugin/routes.js +618 -0
  3. package/pkg/base-plugin/routes.js.map +7 -0
  4. package/pkg/base-plugin/worker.js +810 -0
  5. package/pkg/base-plugin/worker.js.map +7 -0
  6. package/pkg/index.js +1004 -0
  7. package/pkg/index.js.map +7 -0
  8. package/pkg/src/alias-plugin/index.d.ts +5 -0
  9. package/pkg/src/base-plugin/api-handler.d.ts +10 -0
  10. package/pkg/src/base-plugin/ast.d.ts +49 -0
  11. package/pkg/src/base-plugin/cache.d.ts +20 -0
  12. package/pkg/src/base-plugin/index.d.ts +4 -0
  13. package/pkg/src/base-plugin/routes.d.ts +13 -0
  14. package/pkg/src/base-plugin/spinner.d.ts +8 -0
  15. package/pkg/src/base-plugin/worker.d.ts +17 -0
  16. package/pkg/src/define-plugin/index.d.ts +9 -0
  17. package/pkg/src/index.d.ts +6 -0
  18. package/pkg/src/stub-generator/index.d.ts +8 -0
  19. package/pkg/stub-generator/index.js +51 -0
  20. package/pkg/stub-generator/index.js.map +7 -0
  21. package/pkg/test/@fixtures/app/@src/api/articles/[...path]/index.d.ts +0 -0
  22. package/pkg/test/@fixtures/app/@src/api/books/[category]/[[author]]/index.d.ts +0 -0
  23. package/pkg/test/@fixtures/app/@src/api/books/[category]/index.d.ts +0 -0
  24. package/pkg/test/@fixtures/app/@src/api/books/index.d.ts +0 -0
  25. package/pkg/test/@fixtures/app/@src/api/files/[[folder]]/[[id]].json/index.d.ts +0 -0
  26. package/pkg/test/@fixtures/app/@src/api/files/[[folder]]/index.d.ts +0 -0
  27. package/pkg/test/@fixtures/app/@src/api/index/index.d.ts +0 -0
  28. package/pkg/test/@fixtures/app/@src/api/pages/[...path].html/index.d.ts +0 -0
  29. package/pkg/test/@fixtures/app/@src/api/users/[id].json/index.d.ts +0 -0
  30. package/pkg/test/@fixtures/app/lib/@src/{api}/articles/[...path]/types.d.ts +3 -0
  31. package/pkg/test/@fixtures/app/lib/@src/{api}/books/[category]/[[author]]/types.d.ts +4 -0
  32. package/pkg/test/@fixtures/app/lib/@src/{api}/books/[category]/types.d.ts +3 -0
  33. package/pkg/test/@fixtures/app/lib/@src/{api}/books/types.d.ts +1 -0
  34. package/pkg/test/@fixtures/app/lib/@src/{api}/files/[[folder]]/[[id]].json/types.d.ts +4 -0
  35. package/pkg/test/@fixtures/app/lib/@src/{api}/files/[[folder]]/types.d.ts +3 -0
  36. package/pkg/test/@fixtures/app/lib/@src/{api}/index/types.d.ts +1 -0
  37. package/pkg/test/@fixtures/app/lib/@src/{api}/pages/[...path].html/types.d.ts +3 -0
  38. package/pkg/test/@fixtures/app/lib/@src/{api}/users/[id].json/types.d.ts +3 -0
  39. package/pkg/test/@fixtures/ast/extractTypeDeclarations/exports/with-referenced-files.d.ts +1 -0
  40. package/pkg/test/@fixtures/ast/extractTypeDeclarations/imports/with-referenced-files.d.ts +1 -0
  41. package/pkg/test/ast/extractParamsRefinements.test.d.ts +1 -0
  42. package/pkg/test/ast/extractRouteMethods.test.d.ts +1 -0
  43. package/pkg/test/ast/extractTypeDeclarations.test.d.ts +1 -0
  44. package/pkg/test/routes/resolver.test.d.ts +1 -0
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "type": "module",
3
+ "name": "@kosmojs/dev",
4
+ "version": "0.0.0",
5
+ "cacheVersion": "001",
6
+ "author": "Slee Woo",
7
+ "license": "MIT",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "files": [
12
+ "pkg/*"
13
+ ],
14
+ "exports": {
15
+ ".": {
16
+ "types": "./pkg/src/index.d.ts",
17
+ "default": "./pkg/index.js"
18
+ },
19
+ "./routes": {
20
+ "types": "./pkg/src/base-plugin/routes.d.ts",
21
+ "default": "./pkg/base-plugin/routes.js"
22
+ },
23
+ "./stub-generator": {
24
+ "types": "./pkg/src/stub-generator/index.d.ts",
25
+ "default": "./pkg/stub-generator/index.js"
26
+ },
27
+ "./package.json": "./package.json"
28
+ },
29
+ "dependencies": {
30
+ "chokidar": "^4.0.3",
31
+ "crc": "^4.3.2",
32
+ "dotenv": "^17.2.3",
33
+ "esbuild": "^0.25.12",
34
+ "fs-extra": "^11.3.2",
35
+ "ora": "^9.0.0",
36
+ "picomatch": "^4.0.3",
37
+ "tfusion": "^0.0.23",
38
+ "tinyglobby": "^0.2.15",
39
+ "ts-morph": "^27.0.2",
40
+ "typescript": "^5.9.3",
41
+ "@kosmojs/api": "^0.0.0",
42
+ "@kosmojs/api-generator": "^0.0.0",
43
+ "@kosmojs/config": "^0.0.0",
44
+ "@kosmojs/devlib": "^0.0.0",
45
+ "@kosmojs/fetch-generator": "^0.0.0"
46
+ },
47
+ "devDependencies": {
48
+ "@types/fs-extra": "^11.0.4",
49
+ "@types/koa": "^3.0.1",
50
+ "@types/picomatch": "^4.0.2",
51
+ "vite": "^7.2.2"
52
+ },
53
+ "scripts": {
54
+ "build": "esbuilder src/index.ts src/base-plugin/routes.ts src/base-plugin/worker.ts src/stub-generator/index.ts",
55
+ "test": "vitest --root ../../.. --project core/dev"
56
+ }
57
+ }
@@ -0,0 +1,618 @@
1
+ // src/base-plugin/routes.ts
2
+ import { dirname, join, resolve as resolve3 } from "node:path";
3
+ import crc3 from "crc/crc32";
4
+ import picomatch from "picomatch";
5
+ import { glob } from "tinyglobby";
6
+ import {
7
+ defaults,
8
+ pathResolver as pathResolver2,
9
+ pathTokensFactory,
10
+ render,
11
+ renderToFile
12
+ } from "@kosmojs/devlib";
13
+
14
+ // src/base-plugin/ast.ts
15
+ import { resolve } from "node:path";
16
+ import crc from "crc/crc32";
17
+ import { flattener } from "tfusion";
18
+ import {
19
+ Project,
20
+ SyntaxKind
21
+ } from "ts-morph";
22
+ import { HTTPMethods } from "@kosmojs/api";
23
+ var createProject = (opts) => new Project(opts);
24
+ var resolveRouteSignature = async (route, opts) => {
25
+ const {
26
+ sourceFile = createProject().addSourceFileAtPath(route.fileFullpath)
27
+ } = { ...opts };
28
+ const [typeDeclarations, referencedFiles] = extractTypeDeclarations(
29
+ sourceFile,
30
+ opts
31
+ );
32
+ const defaultExport = extractDefaultExport(sourceFile);
33
+ const paramsRefinements = defaultExport ? extractParamsRefinements(defaultExport) : void 0;
34
+ const methods = defaultExport ? extractRouteMethods(defaultExport, route) : [];
35
+ const payloadTypes = methods.flatMap((e) => {
36
+ return e.payloadType ? [e.payloadType] : [];
37
+ });
38
+ const responseTypes = methods.flatMap((e) => {
39
+ return e.responseType ? [e.responseType] : [];
40
+ });
41
+ return {
42
+ typeDeclarations,
43
+ paramsRefinements,
44
+ methods: methods.map((e) => e.method),
45
+ payloadTypes,
46
+ responseTypes,
47
+ referencedFiles
48
+ };
49
+ };
50
+ var extractDefaultExport = (sourceFile) => {
51
+ const [defaultExport] = sourceFile.getExportAssignments().flatMap((exportAssignment) => {
52
+ if (exportAssignment.isExportEquals()) {
53
+ return [];
54
+ }
55
+ const callExpression = exportAssignment.getExpression();
56
+ return callExpression.isKind(SyntaxKind.CallExpression) ? [callExpression] : [];
57
+ });
58
+ return defaultExport;
59
+ };
60
+ var extractParamsRefinements = (callExpression) => {
61
+ const [firstGeneric] = extractGenerics(callExpression);
62
+ if (!firstGeneric?.node.isKind(SyntaxKind.TupleType)) {
63
+ return;
64
+ }
65
+ const tupleElements = firstGeneric.node.getElements();
66
+ if (!tupleElements?.length) {
67
+ return;
68
+ }
69
+ return tupleElements.map((node, index) => {
70
+ return {
71
+ index,
72
+ text: node.getText()
73
+ };
74
+ });
75
+ };
76
+ var extractRouteMethods = (callExpression, route) => {
77
+ const funcDeclaration = callExpression.getFirstChildByKind(SyntaxKind.ArrowFunction) || callExpression.getFirstChildByKind(SyntaxKind.FunctionExpression);
78
+ if (!funcDeclaration) {
79
+ return [];
80
+ }
81
+ const arrayLiteralExpression = funcDeclaration.getFirstChildByKind(
82
+ SyntaxKind.ArrayLiteralExpression
83
+ );
84
+ if (!arrayLiteralExpression) {
85
+ return [];
86
+ }
87
+ const callExpressions = [];
88
+ for (const e of arrayLiteralExpression.getChildrenOfKind(
89
+ SyntaxKind.CallExpression
90
+ )) {
91
+ const name = e.getExpression().getText();
92
+ if (HTTPMethods[name]) {
93
+ callExpressions.push([e, name]);
94
+ }
95
+ }
96
+ const methods = [];
97
+ const skipValidationFilter = (e) => /@skip-validation/.test(e);
98
+ for (const [callExpression2, method] of callExpressions) {
99
+ const [payloadGeneric, responseGeneric] = extractGenerics(callExpression2);
100
+ const payloadText = payloadGeneric?.node ? payloadGeneric.node.getChildren().length === 0 ? "{}" : payloadGeneric.node.getFullText() : void 0;
101
+ const responseText = responseGeneric?.node.getText();
102
+ const responseType = responseText ? {
103
+ id: ["ResponseT", crc(route.importName + method)].join(""),
104
+ method,
105
+ skipValidation: responseGeneric?.comments ? responseGeneric.comments.some(skipValidationFilter) : false,
106
+ text: ["never", "object"].includes(responseText) ? "{}" : responseText,
107
+ resolvedType: void 0
108
+ } : void 0;
109
+ const payloadType = payloadText ? {
110
+ id: ["PayloadT", crc(route.importName + method)].join(""),
111
+ responseTypeId: responseType?.id,
112
+ method,
113
+ skipValidation: payloadGeneric?.comments ? payloadGeneric.comments.some(skipValidationFilter) : false,
114
+ isOptional: payloadText ? payloadText === "{}" || route.optionalParams : true,
115
+ text: payloadText,
116
+ resolvedType: void 0
117
+ } : void 0;
118
+ methods.push({
119
+ method,
120
+ payloadType,
121
+ responseType
122
+ });
123
+ }
124
+ return methods;
125
+ };
126
+ var extractTypeDeclarations = (sourceFile, opts) => {
127
+ const declarations = [];
128
+ const referencedFiles = opts?.withReferencedFiles ? [] : void 0;
129
+ for (const declaration of sourceFile.getImportDeclarations()) {
130
+ const modulePath = declaration.getModuleSpecifierValue();
131
+ const path = /^\.\.?\/?/.test(modulePath) ? opts?.relpathResolver ? opts.relpathResolver(modulePath) : modulePath : modulePath;
132
+ const typeOnlyDeclaration = declaration.isTypeOnly();
133
+ const defaultImport = typeOnlyDeclaration ? declaration.getDefaultImport() : void 0;
134
+ if (defaultImport) {
135
+ const name = defaultImport.getText();
136
+ const text = `import type ${name} from "${path}";`;
137
+ declarations.push({
138
+ importDeclaration: {
139
+ name,
140
+ path
141
+ },
142
+ text
143
+ });
144
+ if (referencedFiles) {
145
+ referencedFiles.push(...getReferencedFiles(defaultImport));
146
+ }
147
+ }
148
+ for (const namedImport of declaration.getNamedImports()) {
149
+ if (namedImport.isTypeOnly() || typeOnlyDeclaration) {
150
+ const nameNode = namedImport.getNameNode();
151
+ const name = nameNode.getText();
152
+ const alias = namedImport.getAliasNode()?.getText();
153
+ const nameText = alias ? `${name} as ${alias}` : name;
154
+ declarations.push({
155
+ importDeclaration: {
156
+ name,
157
+ alias,
158
+ path
159
+ },
160
+ text: `import type { ${nameText} } from "${path}";`
161
+ });
162
+ if (referencedFiles) {
163
+ if (nameNode.isKind(SyntaxKind.Identifier)) {
164
+ referencedFiles.push(...getReferencedFiles(nameNode));
165
+ }
166
+ }
167
+ }
168
+ }
169
+ }
170
+ for (const declaration of sourceFile.getTypeAliases()) {
171
+ const name = declaration.getName();
172
+ const text = declaration.getFullText().trim();
173
+ declarations.push({
174
+ typeAliasDeclaration: { name },
175
+ text
176
+ });
177
+ }
178
+ for (const declaration of sourceFile.getInterfaces()) {
179
+ const name = declaration.getName();
180
+ const text = declaration.getFullText().trim();
181
+ declarations.push({
182
+ interfaceDeclaration: { name },
183
+ text
184
+ });
185
+ }
186
+ for (const declaration of sourceFile.getEnums()) {
187
+ const name = declaration.getName();
188
+ const text = declaration.getFullText().trim();
189
+ declarations.push({
190
+ enumDeclaration: { name },
191
+ text
192
+ });
193
+ }
194
+ for (const declaration of sourceFile.getExportDeclarations()) {
195
+ const typeOnlyDeclaration = declaration.isTypeOnly();
196
+ const modulePath = declaration.getModuleSpecifierValue();
197
+ const path = modulePath ? /^\.\.?\/?/.test(modulePath) ? opts?.relpathResolver ? opts.relpathResolver(modulePath) : modulePath : modulePath : void 0;
198
+ for (const namedExport of declaration.getNamedExports()) {
199
+ if (namedExport.isTypeOnly() || typeOnlyDeclaration) {
200
+ const nameNode = namedExport.getNameNode();
201
+ const name = nameNode.getText();
202
+ const alias = namedExport.getAliasNode()?.getText();
203
+ const nameText = alias ? `${name} as ${alias}` : name;
204
+ declarations.push({
205
+ exportDeclaration: {
206
+ name,
207
+ alias: alias ?? name,
208
+ path
209
+ },
210
+ text: path ? `export type { ${nameText} } from "${path}";` : `export type { ${nameText} };`
211
+ });
212
+ if (referencedFiles) {
213
+ if (nameNode.isKind(SyntaxKind.Identifier)) {
214
+ referencedFiles.push(...getReferencedFiles(nameNode));
215
+ }
216
+ }
217
+ }
218
+ }
219
+ }
220
+ return referencedFiles ? [declarations, [...new Set(referencedFiles)]] : [declarations];
221
+ };
222
+ var getReferencedFiles = (importIdentifier) => {
223
+ const declarations = importIdentifier?.getSymbol()?.getAliasedSymbol()?.getDeclarations() || [];
224
+ return declarations.flatMap((e) => {
225
+ const sourceFile = e.getSourceFile();
226
+ return sourceFile ? [sourceFile.getFilePath()] : [];
227
+ });
228
+ };
229
+ var extractGenerics = (callExpression) => {
230
+ return callExpression.getTypeArguments().map((node) => {
231
+ return {
232
+ node,
233
+ comments: node.getLeadingCommentRanges().map((range) => range.getText().trim())
234
+ };
235
+ });
236
+ };
237
+ var typeResolverFactory = ({ appRoot }) => {
238
+ const project = createProject({
239
+ tsConfigFilePath: resolve(appRoot, "tsconfig.json"),
240
+ skipAddingFilesFromTsConfig: true
241
+ });
242
+ const literalTypesResolver = (literalTypes, options) => {
243
+ const sourceFile = project.createSourceFile(
244
+ `${crc(literalTypes)}-${Date.now()}.ts`,
245
+ literalTypes,
246
+ { overwrite: true }
247
+ );
248
+ const resolvedTypes = flattener(project, sourceFile, {
249
+ ...options,
250
+ stripComments: true
251
+ });
252
+ project.removeSourceFile(sourceFile);
253
+ return resolvedTypes;
254
+ };
255
+ return {
256
+ getSourceFile: (fileFullpath) => {
257
+ return project.getSourceFile(fileFullpath) || project.addSourceFileAtPath(fileFullpath);
258
+ },
259
+ refreshSourceFile: async (fileFullpath) => {
260
+ const sourceFile = project.getSourceFile(fileFullpath);
261
+ if (sourceFile) {
262
+ await sourceFile.refreshFromFileSystem();
263
+ }
264
+ },
265
+ literalTypesResolver
266
+ };
267
+ };
268
+
269
+ // src/base-plugin/cache.ts
270
+ import { resolve as resolve2 } from "node:path";
271
+ import crc2 from "crc/crc32";
272
+ import fsx from "fs-extra";
273
+ import pkg from "@kosmojs/dev/package.json" with { type: "json" };
274
+ import { pathResolver } from "@kosmojs/devlib";
275
+ var cacheFactory = (route, {
276
+ appRoot,
277
+ sourceFolder,
278
+ extraContext
279
+ }) => {
280
+ const cacheFile = pathResolver({
281
+ appRoot,
282
+ sourceFolder
283
+ }).resolve("apiLibDir", route.importPath, "cache.json");
284
+ const getCache = async (opt) => {
285
+ if (await fsx.exists(cacheFile)) {
286
+ try {
287
+ const cache = JSON.parse(await fsx.readFile(cacheFile, "utf8"));
288
+ return opt?.validate ? validateCache(cache) : cache;
289
+ } catch (_e) {
290
+ }
291
+ }
292
+ return void 0;
293
+ };
294
+ const persistCache = async ({
295
+ referencedFiles: _referencedFiles,
296
+ ...rest
297
+ }) => {
298
+ const hash = await generateFileHash(route.fileFullpath, {
299
+ ...extraContext
300
+ });
301
+ const referencedFiles = {};
302
+ for (const file of _referencedFiles) {
303
+ referencedFiles[
304
+ // Strip project root to ensure cached paths are relative
305
+ // and portable across environments (CI, local, etc.)
306
+ file.replace(`${appRoot}/`, "")
307
+ ] = await generateFileHash(file);
308
+ }
309
+ const cache = { ...rest, hash, referencedFiles };
310
+ await fsx.outputJson(cacheFile, cache, { spaces: 2 });
311
+ return cache;
312
+ };
313
+ const validateCache = async (cache) => {
314
+ if (!cache?.hash) {
315
+ return;
316
+ }
317
+ if (!cache.typeDeclarations || !cache.referencedFiles) {
318
+ return;
319
+ }
320
+ const hash = await generateFileHash(route.fileFullpath, {
321
+ ...extraContext
322
+ });
323
+ if (!identicalHashSum(cache.hash, hash)) {
324
+ return;
325
+ }
326
+ for (const [file, hash2] of Object.entries(cache.referencedFiles)) {
327
+ if (!identicalHashSum(hash2, await generateFileHash(resolve2(appRoot, file)))) {
328
+ return;
329
+ }
330
+ }
331
+ return cache;
332
+ };
333
+ return {
334
+ getCache,
335
+ validateCache,
336
+ persistCache
337
+ };
338
+ };
339
+ var generateFileHash = async (file, extraContext) => {
340
+ let fileContent;
341
+ try {
342
+ fileContent = await fsx.readFile(file, "utf8");
343
+ } catch (_e) {
344
+ return 0;
345
+ }
346
+ return fileContent ? crc2(
347
+ JSON.stringify({
348
+ ...extraContext,
349
+ [pkg.cacheVersion]: fileContent
350
+ })
351
+ ) : 0;
352
+ };
353
+ var identicalHashSum = (a, b) => {
354
+ return a === b;
355
+ };
356
+
357
+ // src/base-plugin/templates/resolved-types.hbs
358
+ var resolved_types_default = "{{#each resolvedTypes}}\nexport type {{name}} = {{text}};\n{{/each}}\n";
359
+
360
+ // src/base-plugin/templates/types.hbs
361
+ var types_default = '{{#each typeDeclarations}}{{text}}\n{{/each}}\n\nexport type {{params.id}} = {\n {{#each paramsSchema}}\n "{{name}}"{{#unless isRequired}}?{{/unless}}:{{#if isRest}} Array<{{/if}}\n {{#if refinement}}{{refinement.text}}{{else}}string{{/if}}\n {{#if isRest}}>{{/if}}\n {{/each}}\n};\n\n{{#each payloadTypes}}\nexport type {{id}} = {{text}};\n{{/each}}\n\n{{#each responseTypes}}\nexport type {{id}} = {{text}};\n{{/each}}\n';
362
+
363
+ // src/base-plugin/routes.ts
364
+ var routes_default = async (pluginOptions) => {
365
+ const {
366
+ appRoot,
367
+ sourceFolder,
368
+ generators = [],
369
+ formatters = [],
370
+ refineTypeName
371
+ } = pluginOptions;
372
+ let resolveTypes = false;
373
+ for (const { options } of generators) {
374
+ if (options?.resolveTypes) {
375
+ resolveTypes = true;
376
+ }
377
+ }
378
+ const {
379
+ //
380
+ literalTypesResolver,
381
+ getSourceFile,
382
+ refreshSourceFile
383
+ } = typeResolverFactory(pluginOptions);
384
+ const routeFilePatterns = [
385
+ `${defaults.apiDir}/**/index.ts`,
386
+ `${defaults.pagesDir}/**/index.{ts,tsx,vue,svelte}`
387
+ ];
388
+ const resolveRouteFile = (file) => {
389
+ const [_sourceFolder, folder, ...rest] = resolve3(appRoot, file).replace(`${appRoot}/`, "").split("/");
390
+ if (!folder || _sourceFolder !== sourceFolder || rest.length < 2) {
391
+ return;
392
+ }
393
+ return picomatch.isMatch(join(folder, ...rest), routeFilePatterns) ? [folder, rest.join("/")] : void 0;
394
+ };
395
+ const resolversFactory = (routeFiles2) => {
396
+ const resolvers = /* @__PURE__ */ new Map();
397
+ const entries = routeFiles2.flatMap((_file) => {
398
+ const resolvedPaths = resolveRouteFile(_file);
399
+ if (!resolvedPaths) {
400
+ return [];
401
+ }
402
+ const [folder, file] = resolvedPaths;
403
+ const fileFullpath = join(appRoot, sourceFolder, folder, file);
404
+ const pathTokens = pathTokensFactory(dirname(file));
405
+ const name = pathTokens.map((e) => e.orig).join("/");
406
+ const importPath = dirname(file);
407
+ const importName = [
408
+ importPath.split(/\[/)[0].replace(/^\W+|\W+$/g, "").replace(/\W+/g, "_"),
409
+ crc3(importPath)
410
+ ].join("_");
411
+ return [
412
+ {
413
+ name,
414
+ folder,
415
+ file,
416
+ fileFullpath,
417
+ pathTokens,
418
+ importPath,
419
+ importName
420
+ }
421
+ ];
422
+ });
423
+ for (const entry of entries.filter((e) => e.folder === defaults.apiDir)) {
424
+ const {
425
+ name,
426
+ file,
427
+ folder,
428
+ fileFullpath,
429
+ pathTokens,
430
+ importPath,
431
+ importName
432
+ } = entry;
433
+ const handler = async (updatedFile) => {
434
+ const paramsSchema = pathTokens.flatMap((e) => {
435
+ return e.param ? [e.param] : [];
436
+ });
437
+ const optionalParams = paramsSchema.length ? !paramsSchema.some((e) => e.isRequired) : true;
438
+ const { getCache, persistCache } = cacheFactory(
439
+ { file, fileFullpath, importName, importPath },
440
+ {
441
+ appRoot,
442
+ sourceFolder,
443
+ extraContext: { resolveTypes }
444
+ }
445
+ );
446
+ let cache = await getCache({ validate: true });
447
+ if (!cache) {
448
+ if (updatedFile === fileFullpath) {
449
+ await refreshSourceFile(fileFullpath);
450
+ }
451
+ const {
452
+ typeDeclarations,
453
+ paramsRefinements,
454
+ methods,
455
+ payloadTypes,
456
+ responseTypes,
457
+ referencedFiles = []
458
+ } = await resolveRouteSignature(
459
+ { importName, fileFullpath, optionalParams },
460
+ {
461
+ withReferencedFiles: true,
462
+ sourceFile: getSourceFile(fileFullpath),
463
+ relpathResolver(path) {
464
+ return join(sourceFolder, defaults.apiDir, dirname(file), path);
465
+ }
466
+ }
467
+ );
468
+ const numericParams = paramsRefinements ? paramsRefinements.flatMap(({ text, index }) => {
469
+ if (text === "number") {
470
+ const param = paramsSchema.at(index);
471
+ return param ? [param.name] : [];
472
+ }
473
+ return [];
474
+ }) : [];
475
+ const typesFile = pathResolver2({ appRoot, sourceFolder }).resolve(
476
+ "apiLibDir",
477
+ importPath,
478
+ "types.ts"
479
+ );
480
+ const params = {
481
+ id: ["ParamsT", crc3(name)].join(""),
482
+ schema: paramsSchema,
483
+ resolvedType: void 0
484
+ };
485
+ const typesFileContent = render(types_default, {
486
+ params,
487
+ paramsSchema: paramsSchema.map((param, index) => {
488
+ return {
489
+ ...param,
490
+ refinement: paramsRefinements?.at(index)
491
+ };
492
+ }),
493
+ typeDeclarations,
494
+ payloadTypes,
495
+ responseTypes
496
+ });
497
+ const resolvedTypes = resolveTypes ? literalTypesResolver(typesFileContent, {
498
+ overrides: [...payloadTypes, ...responseTypes].reduce(
499
+ (map, { id, skipValidation }) => {
500
+ if (skipValidation) {
501
+ map[id] = "never";
502
+ }
503
+ return map;
504
+ },
505
+ { [refineTypeName]: refineTypeName }
506
+ ),
507
+ withProperties: [params.id, ...payloadTypes.map((e) => e.id)],
508
+ formatters
509
+ }) : void 0;
510
+ await renderToFile(
511
+ typesFile,
512
+ resolvedTypes ? resolved_types_default : typesFileContent,
513
+ { resolvedTypes }
514
+ );
515
+ params.resolvedType = resolvedTypes?.find(
516
+ (e) => e.name === params.id
517
+ );
518
+ cache = await persistCache({
519
+ params,
520
+ methods,
521
+ typeDeclarations,
522
+ numericParams,
523
+ // text was needed at writing types.ts file, dropping from cache
524
+ payloadTypes: payloadTypes.map(({ text, ...rest }) => {
525
+ return {
526
+ ...rest,
527
+ resolvedType: resolvedTypes?.find((e) => e.name === rest.id)
528
+ };
529
+ }),
530
+ responseTypes: responseTypes.map(({ text, ...rest }) => {
531
+ return {
532
+ ...rest,
533
+ resolvedType: resolvedTypes?.find((e) => e.name === rest.id)
534
+ };
535
+ }),
536
+ referencedFiles
537
+ });
538
+ }
539
+ const route = {
540
+ name,
541
+ pathTokens,
542
+ params: cache.params,
543
+ numericParams: cache.numericParams,
544
+ optionalParams,
545
+ importName,
546
+ importPath,
547
+ folder,
548
+ file,
549
+ fileFullpath,
550
+ methods: cache.methods,
551
+ typeDeclarations: cache.typeDeclarations,
552
+ payloadTypes: cache.payloadTypes,
553
+ responseTypes: cache.responseTypes,
554
+ referencedFiles: Object.keys(cache.referencedFiles).map(
555
+ // expand referenced files path,
556
+ // they are stored as relative in cache
557
+ (e) => resolve3(appRoot, e)
558
+ )
559
+ };
560
+ return {
561
+ kind: "api",
562
+ route
563
+ };
564
+ };
565
+ resolvers.set(fileFullpath, { name, handler });
566
+ }
567
+ for (const entry of entries.filter((e) => e.folder === defaults.pagesDir)) {
568
+ const {
569
+ //
570
+ name,
571
+ folder,
572
+ file,
573
+ fileFullpath,
574
+ pathTokens,
575
+ importPath,
576
+ importName
577
+ } = entry;
578
+ const handler = async () => {
579
+ const route = {
580
+ name,
581
+ pathTokens,
582
+ params: {
583
+ schema: pathTokens.flatMap((e) => e.param ? [e.param] : [])
584
+ },
585
+ folder,
586
+ file,
587
+ fileFullpath,
588
+ importPath,
589
+ importName
590
+ };
591
+ return {
592
+ kind: "page",
593
+ route
594
+ };
595
+ };
596
+ resolvers.set(fileFullpath, { name, handler });
597
+ }
598
+ return resolvers;
599
+ };
600
+ const routeFiles = await glob(routeFilePatterns, {
601
+ cwd: resolve3(appRoot, sourceFolder),
602
+ absolute: true,
603
+ onlyFiles: true,
604
+ ignore: [
605
+ `${defaults.apiDir}/index.ts`,
606
+ `${defaults.pagesDir}/index.ts{x,}`
607
+ ]
608
+ });
609
+ return {
610
+ resolvers: resolversFactory(routeFiles),
611
+ resolversFactory,
612
+ resolveRouteFile
613
+ };
614
+ };
615
+ export {
616
+ routes_default as default
617
+ };
618
+ //# sourceMappingURL=routes.js.map