@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
@@ -0,0 +1,810 @@
1
+ // src/base-plugin/worker.ts
2
+ import { parentPort, workerData } from "node:worker_threads";
3
+ import chokidar from "chokidar";
4
+ import crc4 from "crc/crc32";
5
+ import {
6
+ pathResolver as pathResolver3
7
+ } from "@kosmojs/devlib";
8
+
9
+ // src/base-plugin/routes.ts
10
+ import { dirname, join, resolve as resolve3 } from "node:path";
11
+ import crc3 from "crc/crc32";
12
+ import picomatch from "picomatch";
13
+ import { glob } from "tinyglobby";
14
+ import {
15
+ defaults,
16
+ pathResolver as pathResolver2,
17
+ pathTokensFactory,
18
+ render,
19
+ renderToFile
20
+ } from "@kosmojs/devlib";
21
+
22
+ // src/base-plugin/ast.ts
23
+ import { resolve } from "node:path";
24
+ import crc from "crc/crc32";
25
+ import { flattener } from "tfusion";
26
+ import {
27
+ Project,
28
+ SyntaxKind
29
+ } from "ts-morph";
30
+ import { HTTPMethods } from "@kosmojs/api";
31
+ var createProject = (opts) => new Project(opts);
32
+ var resolveRouteSignature = async (route, opts) => {
33
+ const {
34
+ sourceFile = createProject().addSourceFileAtPath(route.fileFullpath)
35
+ } = { ...opts };
36
+ const [typeDeclarations, referencedFiles] = extractTypeDeclarations(
37
+ sourceFile,
38
+ opts
39
+ );
40
+ const defaultExport = extractDefaultExport(sourceFile);
41
+ const paramsRefinements = defaultExport ? extractParamsRefinements(defaultExport) : void 0;
42
+ const methods = defaultExport ? extractRouteMethods(defaultExport, route) : [];
43
+ const payloadTypes = methods.flatMap((e) => {
44
+ return e.payloadType ? [e.payloadType] : [];
45
+ });
46
+ const responseTypes = methods.flatMap((e) => {
47
+ return e.responseType ? [e.responseType] : [];
48
+ });
49
+ return {
50
+ typeDeclarations,
51
+ paramsRefinements,
52
+ methods: methods.map((e) => e.method),
53
+ payloadTypes,
54
+ responseTypes,
55
+ referencedFiles
56
+ };
57
+ };
58
+ var extractDefaultExport = (sourceFile) => {
59
+ const [defaultExport] = sourceFile.getExportAssignments().flatMap((exportAssignment) => {
60
+ if (exportAssignment.isExportEquals()) {
61
+ return [];
62
+ }
63
+ const callExpression = exportAssignment.getExpression();
64
+ return callExpression.isKind(SyntaxKind.CallExpression) ? [callExpression] : [];
65
+ });
66
+ return defaultExport;
67
+ };
68
+ var extractParamsRefinements = (callExpression) => {
69
+ const [firstGeneric] = extractGenerics(callExpression);
70
+ if (!firstGeneric?.node.isKind(SyntaxKind.TupleType)) {
71
+ return;
72
+ }
73
+ const tupleElements = firstGeneric.node.getElements();
74
+ if (!tupleElements?.length) {
75
+ return;
76
+ }
77
+ return tupleElements.map((node, index) => {
78
+ return {
79
+ index,
80
+ text: node.getText()
81
+ };
82
+ });
83
+ };
84
+ var extractRouteMethods = (callExpression, route) => {
85
+ const funcDeclaration = callExpression.getFirstChildByKind(SyntaxKind.ArrowFunction) || callExpression.getFirstChildByKind(SyntaxKind.FunctionExpression);
86
+ if (!funcDeclaration) {
87
+ return [];
88
+ }
89
+ const arrayLiteralExpression = funcDeclaration.getFirstChildByKind(
90
+ SyntaxKind.ArrayLiteralExpression
91
+ );
92
+ if (!arrayLiteralExpression) {
93
+ return [];
94
+ }
95
+ const callExpressions = [];
96
+ for (const e of arrayLiteralExpression.getChildrenOfKind(
97
+ SyntaxKind.CallExpression
98
+ )) {
99
+ const name = e.getExpression().getText();
100
+ if (HTTPMethods[name]) {
101
+ callExpressions.push([e, name]);
102
+ }
103
+ }
104
+ const methods = [];
105
+ const skipValidationFilter = (e) => /@skip-validation/.test(e);
106
+ for (const [callExpression2, method] of callExpressions) {
107
+ const [payloadGeneric, responseGeneric] = extractGenerics(callExpression2);
108
+ const payloadText = payloadGeneric?.node ? payloadGeneric.node.getChildren().length === 0 ? "{}" : payloadGeneric.node.getFullText() : void 0;
109
+ const responseText = responseGeneric?.node.getText();
110
+ const responseType = responseText ? {
111
+ id: ["ResponseT", crc(route.importName + method)].join(""),
112
+ method,
113
+ skipValidation: responseGeneric?.comments ? responseGeneric.comments.some(skipValidationFilter) : false,
114
+ text: ["never", "object"].includes(responseText) ? "{}" : responseText,
115
+ resolvedType: void 0
116
+ } : void 0;
117
+ const payloadType = payloadText ? {
118
+ id: ["PayloadT", crc(route.importName + method)].join(""),
119
+ responseTypeId: responseType?.id,
120
+ method,
121
+ skipValidation: payloadGeneric?.comments ? payloadGeneric.comments.some(skipValidationFilter) : false,
122
+ isOptional: payloadText ? payloadText === "{}" || route.optionalParams : true,
123
+ text: payloadText,
124
+ resolvedType: void 0
125
+ } : void 0;
126
+ methods.push({
127
+ method,
128
+ payloadType,
129
+ responseType
130
+ });
131
+ }
132
+ return methods;
133
+ };
134
+ var extractTypeDeclarations = (sourceFile, opts) => {
135
+ const declarations = [];
136
+ const referencedFiles = opts?.withReferencedFiles ? [] : void 0;
137
+ for (const declaration of sourceFile.getImportDeclarations()) {
138
+ const modulePath = declaration.getModuleSpecifierValue();
139
+ const path = /^\.\.?\/?/.test(modulePath) ? opts?.relpathResolver ? opts.relpathResolver(modulePath) : modulePath : modulePath;
140
+ const typeOnlyDeclaration = declaration.isTypeOnly();
141
+ const defaultImport = typeOnlyDeclaration ? declaration.getDefaultImport() : void 0;
142
+ if (defaultImport) {
143
+ const name = defaultImport.getText();
144
+ const text = `import type ${name} from "${path}";`;
145
+ declarations.push({
146
+ importDeclaration: {
147
+ name,
148
+ path
149
+ },
150
+ text
151
+ });
152
+ if (referencedFiles) {
153
+ referencedFiles.push(...getReferencedFiles(defaultImport));
154
+ }
155
+ }
156
+ for (const namedImport of declaration.getNamedImports()) {
157
+ if (namedImport.isTypeOnly() || typeOnlyDeclaration) {
158
+ const nameNode = namedImport.getNameNode();
159
+ const name = nameNode.getText();
160
+ const alias = namedImport.getAliasNode()?.getText();
161
+ const nameText = alias ? `${name} as ${alias}` : name;
162
+ declarations.push({
163
+ importDeclaration: {
164
+ name,
165
+ alias,
166
+ path
167
+ },
168
+ text: `import type { ${nameText} } from "${path}";`
169
+ });
170
+ if (referencedFiles) {
171
+ if (nameNode.isKind(SyntaxKind.Identifier)) {
172
+ referencedFiles.push(...getReferencedFiles(nameNode));
173
+ }
174
+ }
175
+ }
176
+ }
177
+ }
178
+ for (const declaration of sourceFile.getTypeAliases()) {
179
+ const name = declaration.getName();
180
+ const text = declaration.getFullText().trim();
181
+ declarations.push({
182
+ typeAliasDeclaration: { name },
183
+ text
184
+ });
185
+ }
186
+ for (const declaration of sourceFile.getInterfaces()) {
187
+ const name = declaration.getName();
188
+ const text = declaration.getFullText().trim();
189
+ declarations.push({
190
+ interfaceDeclaration: { name },
191
+ text
192
+ });
193
+ }
194
+ for (const declaration of sourceFile.getEnums()) {
195
+ const name = declaration.getName();
196
+ const text = declaration.getFullText().trim();
197
+ declarations.push({
198
+ enumDeclaration: { name },
199
+ text
200
+ });
201
+ }
202
+ for (const declaration of sourceFile.getExportDeclarations()) {
203
+ const typeOnlyDeclaration = declaration.isTypeOnly();
204
+ const modulePath = declaration.getModuleSpecifierValue();
205
+ const path = modulePath ? /^\.\.?\/?/.test(modulePath) ? opts?.relpathResolver ? opts.relpathResolver(modulePath) : modulePath : modulePath : void 0;
206
+ for (const namedExport of declaration.getNamedExports()) {
207
+ if (namedExport.isTypeOnly() || typeOnlyDeclaration) {
208
+ const nameNode = namedExport.getNameNode();
209
+ const name = nameNode.getText();
210
+ const alias = namedExport.getAliasNode()?.getText();
211
+ const nameText = alias ? `${name} as ${alias}` : name;
212
+ declarations.push({
213
+ exportDeclaration: {
214
+ name,
215
+ alias: alias ?? name,
216
+ path
217
+ },
218
+ text: path ? `export type { ${nameText} } from "${path}";` : `export type { ${nameText} };`
219
+ });
220
+ if (referencedFiles) {
221
+ if (nameNode.isKind(SyntaxKind.Identifier)) {
222
+ referencedFiles.push(...getReferencedFiles(nameNode));
223
+ }
224
+ }
225
+ }
226
+ }
227
+ }
228
+ return referencedFiles ? [declarations, [...new Set(referencedFiles)]] : [declarations];
229
+ };
230
+ var getReferencedFiles = (importIdentifier) => {
231
+ const declarations = importIdentifier?.getSymbol()?.getAliasedSymbol()?.getDeclarations() || [];
232
+ return declarations.flatMap((e) => {
233
+ const sourceFile = e.getSourceFile();
234
+ return sourceFile ? [sourceFile.getFilePath()] : [];
235
+ });
236
+ };
237
+ var extractGenerics = (callExpression) => {
238
+ return callExpression.getTypeArguments().map((node) => {
239
+ return {
240
+ node,
241
+ comments: node.getLeadingCommentRanges().map((range) => range.getText().trim())
242
+ };
243
+ });
244
+ };
245
+ var typeResolverFactory = ({ appRoot: appRoot2 }) => {
246
+ const project = createProject({
247
+ tsConfigFilePath: resolve(appRoot2, "tsconfig.json"),
248
+ skipAddingFilesFromTsConfig: true
249
+ });
250
+ const literalTypesResolver = (literalTypes, options) => {
251
+ const sourceFile = project.createSourceFile(
252
+ `${crc(literalTypes)}-${Date.now()}.ts`,
253
+ literalTypes,
254
+ { overwrite: true }
255
+ );
256
+ const resolvedTypes = flattener(project, sourceFile, {
257
+ ...options,
258
+ stripComments: true
259
+ });
260
+ project.removeSourceFile(sourceFile);
261
+ return resolvedTypes;
262
+ };
263
+ return {
264
+ getSourceFile: (fileFullpath) => {
265
+ return project.getSourceFile(fileFullpath) || project.addSourceFileAtPath(fileFullpath);
266
+ },
267
+ refreshSourceFile: async (fileFullpath) => {
268
+ const sourceFile = project.getSourceFile(fileFullpath);
269
+ if (sourceFile) {
270
+ await sourceFile.refreshFromFileSystem();
271
+ }
272
+ },
273
+ literalTypesResolver
274
+ };
275
+ };
276
+
277
+ // src/base-plugin/cache.ts
278
+ import { resolve as resolve2 } from "node:path";
279
+ import crc2 from "crc/crc32";
280
+ import fsx from "fs-extra";
281
+ import pkg from "@kosmojs/dev/package.json" with { type: "json" };
282
+ import { pathResolver } from "@kosmojs/devlib";
283
+ var cacheFactory = (route, {
284
+ appRoot: appRoot2,
285
+ sourceFolder: sourceFolder2,
286
+ extraContext
287
+ }) => {
288
+ const cacheFile = pathResolver({
289
+ appRoot: appRoot2,
290
+ sourceFolder: sourceFolder2
291
+ }).resolve("apiLibDir", route.importPath, "cache.json");
292
+ const getCache = async (opt) => {
293
+ if (await fsx.exists(cacheFile)) {
294
+ try {
295
+ const cache = JSON.parse(await fsx.readFile(cacheFile, "utf8"));
296
+ return opt?.validate ? validateCache(cache) : cache;
297
+ } catch (_e) {
298
+ }
299
+ }
300
+ return void 0;
301
+ };
302
+ const persistCache = async ({
303
+ referencedFiles: _referencedFiles,
304
+ ...rest
305
+ }) => {
306
+ const hash = await generateFileHash(route.fileFullpath, {
307
+ ...extraContext
308
+ });
309
+ const referencedFiles = {};
310
+ for (const file of _referencedFiles) {
311
+ referencedFiles[
312
+ // Strip project root to ensure cached paths are relative
313
+ // and portable across environments (CI, local, etc.)
314
+ file.replace(`${appRoot2}/`, "")
315
+ ] = await generateFileHash(file);
316
+ }
317
+ const cache = { ...rest, hash, referencedFiles };
318
+ await fsx.outputJson(cacheFile, cache, { spaces: 2 });
319
+ return cache;
320
+ };
321
+ const validateCache = async (cache) => {
322
+ if (!cache?.hash) {
323
+ return;
324
+ }
325
+ if (!cache.typeDeclarations || !cache.referencedFiles) {
326
+ return;
327
+ }
328
+ const hash = await generateFileHash(route.fileFullpath, {
329
+ ...extraContext
330
+ });
331
+ if (!identicalHashSum(cache.hash, hash)) {
332
+ return;
333
+ }
334
+ for (const [file, hash2] of Object.entries(cache.referencedFiles)) {
335
+ if (!identicalHashSum(hash2, await generateFileHash(resolve2(appRoot2, file)))) {
336
+ return;
337
+ }
338
+ }
339
+ return cache;
340
+ };
341
+ return {
342
+ getCache,
343
+ validateCache,
344
+ persistCache
345
+ };
346
+ };
347
+ var generateFileHash = async (file, extraContext) => {
348
+ let fileContent;
349
+ try {
350
+ fileContent = await fsx.readFile(file, "utf8");
351
+ } catch (_e) {
352
+ return 0;
353
+ }
354
+ return fileContent ? crc2(
355
+ JSON.stringify({
356
+ ...extraContext,
357
+ [pkg.cacheVersion]: fileContent
358
+ })
359
+ ) : 0;
360
+ };
361
+ var identicalHashSum = (a, b) => {
362
+ return a === b;
363
+ };
364
+
365
+ // src/base-plugin/templates/resolved-types.hbs
366
+ var resolved_types_default = "{{#each resolvedTypes}}\nexport type {{name}} = {{text}};\n{{/each}}\n";
367
+
368
+ // src/base-plugin/templates/types.hbs
369
+ 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';
370
+
371
+ // src/base-plugin/routes.ts
372
+ var routes_default = async (pluginOptions) => {
373
+ const {
374
+ appRoot: appRoot2,
375
+ sourceFolder: sourceFolder2,
376
+ generators: generators2 = [],
377
+ formatters: formatters2 = [],
378
+ refineTypeName
379
+ } = pluginOptions;
380
+ let resolveTypes = false;
381
+ for (const { options } of generators2) {
382
+ if (options?.resolveTypes) {
383
+ resolveTypes = true;
384
+ }
385
+ }
386
+ const {
387
+ //
388
+ literalTypesResolver,
389
+ getSourceFile,
390
+ refreshSourceFile
391
+ } = typeResolverFactory(pluginOptions);
392
+ const routeFilePatterns = [
393
+ `${defaults.apiDir}/**/index.ts`,
394
+ `${defaults.pagesDir}/**/index.{ts,tsx,vue,svelte}`
395
+ ];
396
+ const resolveRouteFile2 = (file) => {
397
+ const [_sourceFolder, folder, ...rest] = resolve3(appRoot2, file).replace(`${appRoot2}/`, "").split("/");
398
+ if (!folder || _sourceFolder !== sourceFolder2 || rest.length < 2) {
399
+ return;
400
+ }
401
+ return picomatch.isMatch(join(folder, ...rest), routeFilePatterns) ? [folder, rest.join("/")] : void 0;
402
+ };
403
+ const resolversFactory2 = (routeFiles2) => {
404
+ const resolvers2 = /* @__PURE__ */ new Map();
405
+ const entries = routeFiles2.flatMap((_file) => {
406
+ const resolvedPaths = resolveRouteFile2(_file);
407
+ if (!resolvedPaths) {
408
+ return [];
409
+ }
410
+ const [folder, file] = resolvedPaths;
411
+ const fileFullpath = join(appRoot2, sourceFolder2, folder, file);
412
+ const pathTokens = pathTokensFactory(dirname(file));
413
+ const name = pathTokens.map((e) => e.orig).join("/");
414
+ const importPath = dirname(file);
415
+ const importName = [
416
+ importPath.split(/\[/)[0].replace(/^\W+|\W+$/g, "").replace(/\W+/g, "_"),
417
+ crc3(importPath)
418
+ ].join("_");
419
+ return [
420
+ {
421
+ name,
422
+ folder,
423
+ file,
424
+ fileFullpath,
425
+ pathTokens,
426
+ importPath,
427
+ importName
428
+ }
429
+ ];
430
+ });
431
+ for (const entry of entries.filter((e) => e.folder === defaults.apiDir)) {
432
+ const {
433
+ name,
434
+ file,
435
+ folder,
436
+ fileFullpath,
437
+ pathTokens,
438
+ importPath,
439
+ importName
440
+ } = entry;
441
+ const handler = async (updatedFile) => {
442
+ const paramsSchema = pathTokens.flatMap((e) => {
443
+ return e.param ? [e.param] : [];
444
+ });
445
+ const optionalParams = paramsSchema.length ? !paramsSchema.some((e) => e.isRequired) : true;
446
+ const { getCache, persistCache } = cacheFactory(
447
+ { file, fileFullpath, importName, importPath },
448
+ {
449
+ appRoot: appRoot2,
450
+ sourceFolder: sourceFolder2,
451
+ extraContext: { resolveTypes }
452
+ }
453
+ );
454
+ let cache = await getCache({ validate: true });
455
+ if (!cache) {
456
+ if (updatedFile === fileFullpath) {
457
+ await refreshSourceFile(fileFullpath);
458
+ }
459
+ const {
460
+ typeDeclarations,
461
+ paramsRefinements,
462
+ methods,
463
+ payloadTypes,
464
+ responseTypes,
465
+ referencedFiles = []
466
+ } = await resolveRouteSignature(
467
+ { importName, fileFullpath, optionalParams },
468
+ {
469
+ withReferencedFiles: true,
470
+ sourceFile: getSourceFile(fileFullpath),
471
+ relpathResolver(path) {
472
+ return join(sourceFolder2, defaults.apiDir, dirname(file), path);
473
+ }
474
+ }
475
+ );
476
+ const numericParams = paramsRefinements ? paramsRefinements.flatMap(({ text, index }) => {
477
+ if (text === "number") {
478
+ const param = paramsSchema.at(index);
479
+ return param ? [param.name] : [];
480
+ }
481
+ return [];
482
+ }) : [];
483
+ const typesFile = pathResolver2({ appRoot: appRoot2, sourceFolder: sourceFolder2 }).resolve(
484
+ "apiLibDir",
485
+ importPath,
486
+ "types.ts"
487
+ );
488
+ const params = {
489
+ id: ["ParamsT", crc3(name)].join(""),
490
+ schema: paramsSchema,
491
+ resolvedType: void 0
492
+ };
493
+ const typesFileContent = render(types_default, {
494
+ params,
495
+ paramsSchema: paramsSchema.map((param, index) => {
496
+ return {
497
+ ...param,
498
+ refinement: paramsRefinements?.at(index)
499
+ };
500
+ }),
501
+ typeDeclarations,
502
+ payloadTypes,
503
+ responseTypes
504
+ });
505
+ const resolvedTypes = resolveTypes ? literalTypesResolver(typesFileContent, {
506
+ overrides: [...payloadTypes, ...responseTypes].reduce(
507
+ (map, { id, skipValidation }) => {
508
+ if (skipValidation) {
509
+ map[id] = "never";
510
+ }
511
+ return map;
512
+ },
513
+ { [refineTypeName]: refineTypeName }
514
+ ),
515
+ withProperties: [params.id, ...payloadTypes.map((e) => e.id)],
516
+ formatters: formatters2
517
+ }) : void 0;
518
+ await renderToFile(
519
+ typesFile,
520
+ resolvedTypes ? resolved_types_default : typesFileContent,
521
+ { resolvedTypes }
522
+ );
523
+ params.resolvedType = resolvedTypes?.find(
524
+ (e) => e.name === params.id
525
+ );
526
+ cache = await persistCache({
527
+ params,
528
+ methods,
529
+ typeDeclarations,
530
+ numericParams,
531
+ // text was needed at writing types.ts file, dropping from cache
532
+ payloadTypes: payloadTypes.map(({ text, ...rest }) => {
533
+ return {
534
+ ...rest,
535
+ resolvedType: resolvedTypes?.find((e) => e.name === rest.id)
536
+ };
537
+ }),
538
+ responseTypes: responseTypes.map(({ text, ...rest }) => {
539
+ return {
540
+ ...rest,
541
+ resolvedType: resolvedTypes?.find((e) => e.name === rest.id)
542
+ };
543
+ }),
544
+ referencedFiles
545
+ });
546
+ }
547
+ const route = {
548
+ name,
549
+ pathTokens,
550
+ params: cache.params,
551
+ numericParams: cache.numericParams,
552
+ optionalParams,
553
+ importName,
554
+ importPath,
555
+ folder,
556
+ file,
557
+ fileFullpath,
558
+ methods: cache.methods,
559
+ typeDeclarations: cache.typeDeclarations,
560
+ payloadTypes: cache.payloadTypes,
561
+ responseTypes: cache.responseTypes,
562
+ referencedFiles: Object.keys(cache.referencedFiles).map(
563
+ // expand referenced files path,
564
+ // they are stored as relative in cache
565
+ (e) => resolve3(appRoot2, e)
566
+ )
567
+ };
568
+ return {
569
+ kind: "api",
570
+ route
571
+ };
572
+ };
573
+ resolvers2.set(fileFullpath, { name, handler });
574
+ }
575
+ for (const entry of entries.filter((e) => e.folder === defaults.pagesDir)) {
576
+ const {
577
+ //
578
+ name,
579
+ folder,
580
+ file,
581
+ fileFullpath,
582
+ pathTokens,
583
+ importPath,
584
+ importName
585
+ } = entry;
586
+ const handler = async () => {
587
+ const route = {
588
+ name,
589
+ pathTokens,
590
+ params: {
591
+ schema: pathTokens.flatMap((e) => e.param ? [e.param] : [])
592
+ },
593
+ folder,
594
+ file,
595
+ fileFullpath,
596
+ importPath,
597
+ importName
598
+ };
599
+ return {
600
+ kind: "page",
601
+ route
602
+ };
603
+ };
604
+ resolvers2.set(fileFullpath, { name, handler });
605
+ }
606
+ return resolvers2;
607
+ };
608
+ const routeFiles = await glob(routeFilePatterns, {
609
+ cwd: resolve3(appRoot2, sourceFolder2),
610
+ absolute: true,
611
+ onlyFiles: true,
612
+ ignore: [
613
+ `${defaults.apiDir}/index.ts`,
614
+ `${defaults.pagesDir}/index.ts{x,}`
615
+ ]
616
+ });
617
+ return {
618
+ resolvers: resolversFactory2(routeFiles),
619
+ resolversFactory: resolversFactory2,
620
+ resolveRouteFile: resolveRouteFile2
621
+ };
622
+ };
623
+
624
+ // src/base-plugin/worker.ts
625
+ var {
626
+ //
627
+ generatorModules,
628
+ formatterModules,
629
+ ...restOptions
630
+ } = workerData;
631
+ var generators = [];
632
+ var formatters = [];
633
+ for (const [path, opts] of generatorModules) {
634
+ generators.push(await import(path).then((m) => m.default(opts)));
635
+ }
636
+ for (const [path, opts] of formatterModules) {
637
+ formatters.push(await import(path).then((m) => m.default(opts).formatter));
638
+ }
639
+ var resolvedOptions = {
640
+ ...restOptions,
641
+ generators,
642
+ formatters
643
+ };
644
+ var { appRoot, sourceFolder } = resolvedOptions;
645
+ var watchHandlers = [];
646
+ var resolvedRoutes = /* @__PURE__ */ new Map();
647
+ var {
648
+ //
649
+ resolvers,
650
+ resolversFactory,
651
+ resolveRouteFile
652
+ } = await routes_default(resolvedOptions);
653
+ var { resolve: resolve4 } = pathResolver3({ appRoot, sourceFolder });
654
+ var spinnerFactory = (startText) => {
655
+ const id = [startText, Date.now().toString()].map(crc4).join(":");
656
+ const postMessage = (method, text) => {
657
+ const spinner = { id, startText, method, text };
658
+ parentPort?.postMessage({ spinner });
659
+ };
660
+ const postError = (error) => {
661
+ parentPort?.postMessage({ error: structuredClone(error) });
662
+ };
663
+ return {
664
+ id,
665
+ startText,
666
+ text(text) {
667
+ postMessage("text", text);
668
+ },
669
+ append(text) {
670
+ postMessage("append", text);
671
+ },
672
+ succeed(text) {
673
+ postMessage("succeed", text);
674
+ },
675
+ failed(error) {
676
+ postError(error);
677
+ postMessage("failed", error?.stack || error?.message);
678
+ }
679
+ };
680
+ };
681
+ var createEventHandler = async (file) => {
682
+ const [resolver] = resolversFactory([file]).values();
683
+ if (resolver) {
684
+ const spinner = spinnerFactory(`Resolving ${resolver.name} Route`);
685
+ try {
686
+ const resolvedRoute = await resolver.handler();
687
+ resolvers.set(file, resolver);
688
+ resolvedRoutes.set(resolvedRoute.route.fileFullpath, resolvedRoute);
689
+ spinner.succeed();
690
+ } catch (error) {
691
+ spinner.failed(error);
692
+ }
693
+ }
694
+ };
695
+ var updateEventHandler = async (file) => {
696
+ const relatedResolvers = /* @__PURE__ */ new Map();
697
+ if (resolvedRoutes.has(file)) {
698
+ const resolver = resolvers.get(file);
699
+ if (resolver) {
700
+ relatedResolvers.set(file, resolver);
701
+ }
702
+ } else {
703
+ const referencedRoutes = resolvedRoutes.values().filter(({ kind, route }) => {
704
+ return kind === "api" ? route.referencedFiles.includes(file) : false;
705
+ });
706
+ for (const { route } of referencedRoutes) {
707
+ const resolver = resolvers.get(route.fileFullpath);
708
+ if (resolver) {
709
+ relatedResolvers.set(route.fileFullpath, resolver);
710
+ }
711
+ }
712
+ }
713
+ let spinner = spinnerFactory(`Updating ${relatedResolvers.size} Routes`);
714
+ for (const resolver of relatedResolvers.values()) {
715
+ spinner.append(resolver.name);
716
+ try {
717
+ const route = await resolver.handler(file);
718
+ resolvedRoutes.set(route.route.fileFullpath, route);
719
+ } catch (error) {
720
+ spinner.failed(error);
721
+ spinner = spinnerFactory(`Updating ${relatedResolvers.size} Routes`);
722
+ }
723
+ }
724
+ spinner.succeed();
725
+ };
726
+ var deleteEventHandler = async () => {
727
+ };
728
+ var runWatchHandlers = async (event) => {
729
+ let spinner = spinnerFactory("Running Generators");
730
+ const routes = Array.from(resolvedRoutes.values());
731
+ for (const { name, handler } of watchHandlers) {
732
+ spinner.append(name);
733
+ try {
734
+ await handler(structuredClone(routes), event);
735
+ } catch (error) {
736
+ spinner.failed(error);
737
+ spinner = spinnerFactory("Running Generators");
738
+ }
739
+ }
740
+ spinner.succeed();
741
+ };
742
+ var watcher = chokidar.watch(
743
+ [
744
+ // watching for changes in sourceFolder's apiDir and pagesDir
745
+ resolve4("apiDir"),
746
+ resolve4("pagesDir")
747
+ ],
748
+ {
749
+ ...resolvedOptions.watcher.options,
750
+ awaitWriteFinish: typeof resolvedOptions.watcher.options?.awaitWriteFinish === "object" ? resolvedOptions.watcher.options.awaitWriteFinish : {
751
+ stabilityThreshold: resolvedOptions.watcher.delay,
752
+ pollInterval: Math.floor(resolvedOptions.watcher.delay / 4)
753
+ },
754
+ // Do Not emit "add" event for existing files
755
+ ignoreInitial: true
756
+ // Not using Chokidar's `ignored` option.
757
+ // Instead, allow all events through and filter them manually as needed.
758
+ }
759
+ );
760
+ watcher.on("all", async (event, file) => {
761
+ if (event.endsWith("Dir")) {
762
+ return;
763
+ }
764
+ if (!resolveRouteFile(file)) {
765
+ return;
766
+ }
767
+ const match = {
768
+ add: { handler: createEventHandler, kind: "create" },
769
+ change: { handler: updateEventHandler, kind: "update" },
770
+ unlink: { handler: deleteEventHandler, kind: "delete" }
771
+ }[event];
772
+ if (match) {
773
+ const { handler, kind } = match;
774
+ await handler(file);
775
+ await runWatchHandlers({ kind, file });
776
+ }
777
+ });
778
+ {
779
+ let spinner = spinnerFactory("Resolving Routes");
780
+ for (const { name, handler } of resolvers.values()) {
781
+ spinner.append(
782
+ `[ ${resolvedRoutes.size + 1} of ${resolvers.size} ] ${name}`
783
+ );
784
+ try {
785
+ const resolvedEntry = await handler();
786
+ resolvedRoutes.set(resolvedEntry.route.fileFullpath, resolvedEntry);
787
+ } catch (error) {
788
+ spinner.failed(error);
789
+ spinner = spinnerFactory("Resolving Routes");
790
+ }
791
+ }
792
+ spinner.succeed();
793
+ }
794
+ {
795
+ let spinner = spinnerFactory("Initializing Generators");
796
+ for (const { name, factory } of generators) {
797
+ spinner.append(name);
798
+ try {
799
+ const { watchHandler } = await factory(resolvedOptions);
800
+ watchHandlers.push({ name, handler: watchHandler });
801
+ } catch (error) {
802
+ spinner.failed(error);
803
+ spinner = spinnerFactory("Initializing Generators");
804
+ }
805
+ }
806
+ spinner.succeed();
807
+ }
808
+ await runWatchHandlers();
809
+ parentPort?.postMessage("ready");
810
+ //# sourceMappingURL=worker.js.map