@kosmojs/dev 0.1.1 → 0.1.6
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/package.json +17 -18
- package/pkg/chassis.js +24 -1399
- package/pkg/chassis.js.map +1 -1
- package/pkg/index.js +16 -5688
- package/pkg/index.js.map +1 -1
- package/pkg/assets/pkg-BO-iPG8y.js +0 -54
- package/pkg/assets/pkg-BO-iPG8y.js.map +0 -1
package/pkg/chassis.js
CHANGED
|
@@ -1,1390 +1,17 @@
|
|
|
1
|
-
import { n as defaults$3 } from "./assets/pkg-BO-iPG8y.js";
|
|
2
|
-
import "node:module";
|
|
3
1
|
import { dirname, join, resolve } from "node:path";
|
|
4
|
-
import
|
|
5
|
-
import { flattener } from "tfusion";
|
|
6
|
-
import { Project, SyntaxKind } from "ts-morph";
|
|
7
|
-
import { access, constants, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
8
|
-
import handlebars from "handlebars";
|
|
9
|
-
import { parse } from "path-to-regexp";
|
|
10
|
-
import mimeTypes from "mime-types";
|
|
11
|
-
import { Spinner } from "@topcli/spinner";
|
|
12
|
-
import picomatch from "picomatch";
|
|
13
|
-
import { build, createServer } from "vite";
|
|
14
|
-
import { styleText } from "node:util";
|
|
2
|
+
import { defaults } from "@kosmojs/core";
|
|
15
3
|
import http from "node:http";
|
|
16
4
|
import net from "node:net";
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
coreDir: "core",
|
|
24
|
-
srcDir: "src",
|
|
25
|
-
libDir: "lib",
|
|
26
|
-
configDir: "config",
|
|
27
|
-
apiDir: "api",
|
|
28
|
-
pagesDir: "pages",
|
|
29
|
-
entryDir: "entry",
|
|
30
|
-
fetchDir: "fetch",
|
|
31
|
-
refineTypeName: "VRefine"
|
|
32
|
-
};
|
|
33
|
-
/**
|
|
34
|
-
* Request metadata validation targets.
|
|
35
|
-
* */
|
|
36
|
-
var RequestMetadataTargets$2 = {
|
|
37
|
-
query: "URL query parameters",
|
|
38
|
-
headers: "HTTP request headers",
|
|
39
|
-
cookies: "HTTP cookies"
|
|
40
|
-
};
|
|
41
|
-
/**
|
|
42
|
-
* Request body validation targets.
|
|
43
|
-
*
|
|
44
|
-
* Body formats are mutually exclusive - only one should be specified per handler.
|
|
45
|
-
*
|
|
46
|
-
* **Development behavior:**
|
|
47
|
-
* - If multiple formats are defined, the builder displays a warning and
|
|
48
|
-
* disables validation schemas for the affected handler.
|
|
49
|
-
* - If an unsuitable target is defined (e.g., `json`, `form`)
|
|
50
|
-
* for a method without a body like GET, HEAD), a warning is displayed and
|
|
51
|
-
* validation schemas are disabled for that handler.
|
|
52
|
-
*
|
|
53
|
-
* This ensures misconfigurations are detected during development
|
|
54
|
-
* for runtime to execute without false positive validation failures.
|
|
55
|
-
*
|
|
56
|
-
* Always define exactly one target that is suitable for current handler.
|
|
57
|
-
* */
|
|
58
|
-
var RequestBodyTargets$2 = {
|
|
59
|
-
json: "JSON request body",
|
|
60
|
-
form: "URL-encoded or Multipart form",
|
|
61
|
-
raw: "Raw body format (string/Buffer/ArrayBuffer/Blob)"
|
|
62
|
-
};
|
|
63
|
-
var RequestValidationTargets = {
|
|
64
|
-
...RequestMetadataTargets$2,
|
|
65
|
-
...RequestBodyTargets$2
|
|
66
|
-
};
|
|
67
|
-
var HTTPMethods = /* @__PURE__ */ function(HTTPMethods) {
|
|
68
|
-
HTTPMethods["HEAD"] = "HEAD";
|
|
69
|
-
HTTPMethods["OPTIONS"] = "OPTIONS";
|
|
70
|
-
HTTPMethods["GET"] = "GET";
|
|
71
|
-
HTTPMethods["PUT"] = "PUT";
|
|
72
|
-
HTTPMethods["PATCH"] = "PATCH";
|
|
73
|
-
HTTPMethods["POST"] = "POST";
|
|
74
|
-
HTTPMethods["DELETE"] = "DELETE";
|
|
75
|
-
return HTTPMethods;
|
|
76
|
-
}({});
|
|
77
|
-
var astFactory = () => {
|
|
78
|
-
const createProject = (opts) => new Project(opts);
|
|
79
|
-
const resolveRouteSignature = async (route, opts) => {
|
|
80
|
-
const { sourceFile = createProject().addSourceFileAtPath(route.fileFullpath) } = { ...opts };
|
|
81
|
-
const [typeDeclarations, referencedFiles] = extractTypeDeclarations(sourceFile, opts);
|
|
82
|
-
const defaultExport = extractDefaultExport(sourceFile);
|
|
83
|
-
const paramsRefinements = defaultExport ? extractParamsRefinements(defaultExport) : void 0;
|
|
84
|
-
const methods = defaultExport ? extractRouteMethods(route, defaultExport) : [];
|
|
85
|
-
return {
|
|
86
|
-
typeDeclarations,
|
|
87
|
-
paramsRefinements,
|
|
88
|
-
methods: methods.map((e) => e.method),
|
|
89
|
-
validationDefinitions: methods.flatMap((e) => e.validationDefinitions),
|
|
90
|
-
referencedFiles
|
|
91
|
-
};
|
|
92
|
-
};
|
|
93
|
-
const extractDefaultExport = (sourceFile) => {
|
|
94
|
-
const [defaultExport] = sourceFile.getExportAssignments().flatMap((exportAssignment) => {
|
|
95
|
-
if (exportAssignment.isExportEquals()) return [];
|
|
96
|
-
const callExpression = exportAssignment.getExpression();
|
|
97
|
-
return callExpression.isKind(SyntaxKind.CallExpression) ? [callExpression] : [];
|
|
98
|
-
});
|
|
99
|
-
return defaultExport;
|
|
100
|
-
};
|
|
101
|
-
const extractParamsRefinements = (callExpression) => {
|
|
102
|
-
const [_routeName, paramsGeneric] = extractGenerics(callExpression);
|
|
103
|
-
if (!paramsGeneric?.isKind(SyntaxKind.TupleType)) return;
|
|
104
|
-
return paramsGeneric.getElements().map((node, index) => {
|
|
105
|
-
return {
|
|
106
|
-
index,
|
|
107
|
-
text: node.getText()
|
|
108
|
-
};
|
|
109
|
-
});
|
|
110
|
-
};
|
|
111
|
-
const extractRouteMethods = (route, callExpression) => {
|
|
112
|
-
const funcDeclaration = callExpression.getFirstChildByKind(SyntaxKind.ArrowFunction) || callExpression.getFirstChildByKind(SyntaxKind.FunctionExpression);
|
|
113
|
-
if (!funcDeclaration) return [];
|
|
114
|
-
const arrayLiteralExpression = funcDeclaration.getFirstChildByKind(SyntaxKind.ArrayLiteralExpression);
|
|
115
|
-
if (!arrayLiteralExpression) return [];
|
|
116
|
-
const callExpressions = [];
|
|
117
|
-
for (const e of arrayLiteralExpression.getChildrenOfKind(SyntaxKind.CallExpression)) {
|
|
118
|
-
const name = e.getExpression().getText();
|
|
119
|
-
if (HTTPMethods[name]) callExpressions.push([e, name]);
|
|
120
|
-
}
|
|
121
|
-
const methods = [];
|
|
122
|
-
for (const [callExpression, method] of callExpressions) {
|
|
123
|
-
const [vDefs, vOpts] = extractGenerics(callExpression);
|
|
124
|
-
methods.push({
|
|
125
|
-
method,
|
|
126
|
-
validationDefinitions: extractValidationDefinitions(route, method, vDefs, vOpts)
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
return methods;
|
|
130
|
-
};
|
|
131
|
-
/** Parse a boolean literal type node */
|
|
132
|
-
const parseRuntimeValidation = (typeNode) => {
|
|
133
|
-
if (typeNode.isKind(SyntaxKind.LiteralType)) {
|
|
134
|
-
const literal = typeNode.getFirstChild();
|
|
135
|
-
if (literal?.isKind(SyntaxKind.TrueKeyword)) return true;
|
|
136
|
-
else if (literal?.isKind(SyntaxKind.FalseKeyword)) return false;
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
const extractResponseVariant = (typeNode) => {
|
|
140
|
-
if (!typeNode.isKind(SyntaxKind.TupleType)) return;
|
|
141
|
-
let status = 200;
|
|
142
|
-
let contentType;
|
|
143
|
-
let body;
|
|
144
|
-
const [statusNode, contentTypeNode, bodyNode] = typeNode.getElements();
|
|
145
|
-
if (statusNode?.isKind(SyntaxKind.LiteralType)) {
|
|
146
|
-
const literal = statusNode.getFirstChildByKind(SyntaxKind.NumericLiteral);
|
|
147
|
-
if (literal) status = Number(literal.getText());
|
|
148
|
-
}
|
|
149
|
-
if (contentTypeNode) contentType = extractStringLiteral(contentTypeNode);
|
|
150
|
-
if (bodyNode) {
|
|
151
|
-
body = bodyNode.getText();
|
|
152
|
-
if (["object"].includes(body)) body = "{}";
|
|
153
|
-
}
|
|
154
|
-
return {
|
|
155
|
-
status,
|
|
156
|
-
contentType,
|
|
157
|
-
body
|
|
158
|
-
};
|
|
159
|
-
};
|
|
160
|
-
/** Parse opts TypeLiteral into a map keyed by target */
|
|
161
|
-
const parseValidationOptions = (typeNode) => {
|
|
162
|
-
const opts = {};
|
|
163
|
-
if (!typeNode?.isKind(SyntaxKind.TypeLiteral)) return opts;
|
|
164
|
-
for (const prop of typeNode.getMembers()) {
|
|
165
|
-
if (!prop.isKind(SyntaxKind.PropertySignature)) continue;
|
|
166
|
-
const target = prop.getName();
|
|
167
|
-
const typeNode = prop.getTypeNodeOrThrow();
|
|
168
|
-
if (!typeNode.isKind(SyntaxKind.TypeLiteral)) continue;
|
|
169
|
-
let contentType;
|
|
170
|
-
let runtimeValidation;
|
|
171
|
-
const customErrors = {};
|
|
172
|
-
for (const member of typeNode.getMembers()) {
|
|
173
|
-
if (!member.isKind(SyntaxKind.PropertySignature)) continue;
|
|
174
|
-
const nameNode = member.getNameNode();
|
|
175
|
-
const valueNode = member.getTypeNodeOrThrow();
|
|
176
|
-
const name = nameNode.isKind(SyntaxKind.StringLiteral) ? nameNode.getLiteralText() : nameNode.getText();
|
|
177
|
-
if (name === "contentType") contentType = extractStringLiteral(valueNode);
|
|
178
|
-
else if (name === "runtimeValidation") runtimeValidation = parseRuntimeValidation(valueNode);
|
|
179
|
-
else if (name.startsWith("error")) {
|
|
180
|
-
const literal = extractStringLiteral(valueNode);
|
|
181
|
-
if (literal) customErrors[name] = literal;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
opts[target] = {
|
|
185
|
-
contentType,
|
|
186
|
-
runtimeValidation,
|
|
187
|
-
customErrors
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
return opts;
|
|
191
|
-
};
|
|
192
|
-
const extractStringLiteral = (typeNode) => {
|
|
193
|
-
const literal = typeNode.isKind(SyntaxKind.LiteralType) ? typeNode.getFirstChildByKind(SyntaxKind.StringLiteral) : void 0;
|
|
194
|
-
return literal ? literal.getLiteralText() : void 0;
|
|
195
|
-
};
|
|
196
|
-
/**
|
|
197
|
-
* Extract validation definitions from route handler generics.
|
|
198
|
-
* Merges defs (schemas) and opts (validation options) into a flat array.
|
|
199
|
-
* */
|
|
200
|
-
const extractValidationDefinitions = (route, method, defsNode, optsNode) => {
|
|
201
|
-
const definitions = [];
|
|
202
|
-
if (!defsNode?.isKind(SyntaxKind.TypeLiteral)) return definitions;
|
|
203
|
-
const optsMap = parseValidationOptions(optsNode);
|
|
204
|
-
const createId = (target, hash) => {
|
|
205
|
-
return [
|
|
206
|
-
target.replace(/^./, (c) => c.toUpperCase()),
|
|
207
|
-
"T",
|
|
208
|
-
method,
|
|
209
|
-
crc(route.id + hash)
|
|
210
|
-
].join("");
|
|
211
|
-
};
|
|
212
|
-
for (const prop of defsNode.getMembers()) {
|
|
213
|
-
if (!prop.isKind(SyntaxKind.PropertySignature)) continue;
|
|
214
|
-
const target = prop.getName();
|
|
215
|
-
const typeNode = prop.getTypeNodeOrThrow();
|
|
216
|
-
if (target === "response") {
|
|
217
|
-
const variants = typeNode.isKind(SyntaxKind.UnionType) ? typeNode.getChildrenOfKind(SyntaxKind.TupleType) : [typeNode];
|
|
218
|
-
definitions.push({
|
|
219
|
-
...optsMap[target],
|
|
220
|
-
method,
|
|
221
|
-
target,
|
|
222
|
-
variants: variants.flatMap((e, i) => {
|
|
223
|
-
const { status, contentType, body } = extractResponseVariant(e) || {};
|
|
224
|
-
if (!status) return [];
|
|
225
|
-
if (contentType && typeof contentType !== "string") {
|
|
226
|
-
console.warn(styleText(["bold", "red"], `✗ The second element of a response variant should specify the Response Content Type`));
|
|
227
|
-
console.warn(styleText(["blue"], ` Example: [200, "json", Schema]`));
|
|
228
|
-
console.warn(` Route: ${route.name}; Method: ${method}; Response Variant: #${i}`);
|
|
229
|
-
console.warn();
|
|
230
|
-
}
|
|
231
|
-
return [{
|
|
232
|
-
id: createId(target, JSON.stringify([
|
|
233
|
-
status,
|
|
234
|
-
contentType,
|
|
235
|
-
body
|
|
236
|
-
])),
|
|
237
|
-
status,
|
|
238
|
-
contentType,
|
|
239
|
-
body
|
|
240
|
-
}];
|
|
241
|
-
})
|
|
242
|
-
});
|
|
243
|
-
} else if (Object.keys(RequestValidationTargets).includes(target)) definitions.push({
|
|
244
|
-
...optsMap[target],
|
|
245
|
-
method,
|
|
246
|
-
target,
|
|
247
|
-
schema: {
|
|
248
|
-
id: createId(target),
|
|
249
|
-
text: typeNode.getText()
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
return definitions;
|
|
254
|
-
};
|
|
255
|
-
const extractTypeDeclarations = (sourceFile, opts) => {
|
|
256
|
-
const declarations = [];
|
|
257
|
-
const referencedFiles = opts?.withReferencedFiles ? [] : void 0;
|
|
258
|
-
for (const declaration of sourceFile.getImportDeclarations()) {
|
|
259
|
-
const modulePath = declaration.getModuleSpecifierValue();
|
|
260
|
-
const path = /^\.\.?\/?/.test(modulePath) ? opts?.relpathResolver ? opts.relpathResolver(modulePath) : modulePath : modulePath;
|
|
261
|
-
const typeOnlyDeclaration = declaration.isTypeOnly();
|
|
262
|
-
const defaultImport = typeOnlyDeclaration ? declaration.getDefaultImport() : void 0;
|
|
263
|
-
if (defaultImport) {
|
|
264
|
-
const name = defaultImport.getText();
|
|
265
|
-
const text = `import type ${name} from "${path}";`;
|
|
266
|
-
declarations.push({
|
|
267
|
-
importDeclaration: {
|
|
268
|
-
name,
|
|
269
|
-
path
|
|
270
|
-
},
|
|
271
|
-
text
|
|
272
|
-
});
|
|
273
|
-
if (referencedFiles) referencedFiles.push(...getReferencedFiles(defaultImport));
|
|
274
|
-
}
|
|
275
|
-
const namespaceImport = typeOnlyDeclaration ? declaration.getNamespaceImport() : void 0;
|
|
276
|
-
if (namespaceImport) {
|
|
277
|
-
const name = namespaceImport.getText();
|
|
278
|
-
const text = `import type * as ${name} from "${path}";`;
|
|
279
|
-
declarations.push({
|
|
280
|
-
importDeclaration: {
|
|
281
|
-
name,
|
|
282
|
-
path
|
|
283
|
-
},
|
|
284
|
-
text
|
|
285
|
-
});
|
|
286
|
-
if (referencedFiles) referencedFiles.push(...getReferencedFiles(namespaceImport));
|
|
287
|
-
}
|
|
288
|
-
for (const namedImport of declaration.getNamedImports()) if (namedImport.isTypeOnly() || typeOnlyDeclaration) {
|
|
289
|
-
const nameNode = namedImport.getNameNode();
|
|
290
|
-
const name = nameNode.getText();
|
|
291
|
-
const alias = namedImport.getAliasNode()?.getText();
|
|
292
|
-
const nameText = alias ? `${name} as ${alias}` : name;
|
|
293
|
-
declarations.push({
|
|
294
|
-
importDeclaration: {
|
|
295
|
-
name,
|
|
296
|
-
alias,
|
|
297
|
-
path
|
|
298
|
-
},
|
|
299
|
-
text: `import type { ${nameText} } from "${path}";`
|
|
300
|
-
});
|
|
301
|
-
if (referencedFiles) {
|
|
302
|
-
if (nameNode.isKind(SyntaxKind.Identifier)) referencedFiles.push(...getReferencedFiles(nameNode));
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
for (const declaration of sourceFile.getTypeAliases()) {
|
|
307
|
-
const name = declaration.getName();
|
|
308
|
-
const text = declaration.getFullText().trim();
|
|
309
|
-
declarations.push({
|
|
310
|
-
typeAliasDeclaration: { name },
|
|
311
|
-
text
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
|
-
for (const declaration of sourceFile.getInterfaces()) {
|
|
315
|
-
const name = declaration.getName();
|
|
316
|
-
const text = declaration.getFullText().trim();
|
|
317
|
-
declarations.push({
|
|
318
|
-
interfaceDeclaration: { name },
|
|
319
|
-
text
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
for (const declaration of sourceFile.getEnums()) {
|
|
323
|
-
const name = declaration.getName();
|
|
324
|
-
const text = declaration.getFullText().trim();
|
|
325
|
-
declarations.push({
|
|
326
|
-
enumDeclaration: { name },
|
|
327
|
-
text
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
for (const declaration of sourceFile.getExportDeclarations()) {
|
|
331
|
-
const typeOnlyDeclaration = declaration.isTypeOnly();
|
|
332
|
-
const modulePath = declaration.getModuleSpecifierValue();
|
|
333
|
-
const path = modulePath ? /^\.\.?\/?/.test(modulePath) ? opts?.relpathResolver ? opts.relpathResolver(modulePath) : modulePath : modulePath : void 0;
|
|
334
|
-
for (const namedExport of declaration.getNamedExports()) if (namedExport.isTypeOnly() || typeOnlyDeclaration) {
|
|
335
|
-
const nameNode = namedExport.getNameNode();
|
|
336
|
-
const name = nameNode.getText();
|
|
337
|
-
const alias = namedExport.getAliasNode()?.getText();
|
|
338
|
-
const nameText = alias ? `${name} as ${alias}` : name;
|
|
339
|
-
declarations.push({
|
|
340
|
-
exportDeclaration: {
|
|
341
|
-
name,
|
|
342
|
-
alias: alias ?? name,
|
|
343
|
-
path
|
|
344
|
-
},
|
|
345
|
-
text: path ? `export type { ${nameText} } from "${path}";` : `export type { ${nameText} };`
|
|
346
|
-
});
|
|
347
|
-
if (referencedFiles) {
|
|
348
|
-
if (nameNode.isKind(SyntaxKind.Identifier)) referencedFiles.push(...getReferencedFiles(nameNode));
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
return referencedFiles ? [declarations, [...new Set(referencedFiles)]] : [declarations];
|
|
353
|
-
};
|
|
354
|
-
const getReferencedFiles = (importIdentifier) => {
|
|
355
|
-
return (importIdentifier?.getSymbol()?.getAliasedSymbol()?.getDeclarations() || []).flatMap((e) => {
|
|
356
|
-
const sourceFile = e.getSourceFile();
|
|
357
|
-
return sourceFile ? [sourceFile.getFilePath()] : [];
|
|
358
|
-
});
|
|
359
|
-
};
|
|
360
|
-
const extractGenerics = (callExpression) => {
|
|
361
|
-
return callExpression.getTypeArguments();
|
|
362
|
-
};
|
|
363
|
-
const typeResolverFactory = ({ root, name }) => {
|
|
364
|
-
const project = createProject({
|
|
365
|
-
tsConfigFilePath: resolve(root, join(defaults$2.srcDir, name, "tsconfig.json")),
|
|
366
|
-
skipAddingFilesFromTsConfig: true
|
|
367
|
-
});
|
|
368
|
-
const literalTypesResolver = (literalTypes, options) => {
|
|
369
|
-
const sourceFile = project.createSourceFile(`${crc(literalTypes)}-${Date.now()}.ts`, literalTypes, { overwrite: true });
|
|
370
|
-
const resolvedTypes = flattener(project, sourceFile, {
|
|
371
|
-
...options,
|
|
372
|
-
stripComments: true
|
|
373
|
-
});
|
|
374
|
-
project.removeSourceFile(sourceFile);
|
|
375
|
-
return resolvedTypes;
|
|
376
|
-
};
|
|
377
|
-
return {
|
|
378
|
-
getSourceFile: (fileFullpath) => {
|
|
379
|
-
return project.getSourceFile(fileFullpath) || project.addSourceFileAtPath(fileFullpath);
|
|
380
|
-
},
|
|
381
|
-
refreshSourceFile: async (fileFullpath) => {
|
|
382
|
-
const sourceFile = project.getSourceFile(fileFullpath);
|
|
383
|
-
if (sourceFile) await sourceFile.refreshFromFileSystem();
|
|
384
|
-
},
|
|
385
|
-
literalTypesResolver
|
|
386
|
-
};
|
|
387
|
-
};
|
|
388
|
-
return {
|
|
389
|
-
createProject,
|
|
390
|
-
extractDefaultExport,
|
|
391
|
-
extractParamsRefinements,
|
|
392
|
-
extractRouteMethods,
|
|
393
|
-
extractTypeDeclarations,
|
|
394
|
-
resolveRouteSignature,
|
|
395
|
-
typeResolverFactory
|
|
396
|
-
};
|
|
397
|
-
};
|
|
398
|
-
var pathResolver$1 = (sourceFolder) => {
|
|
399
|
-
const createPath = (...a) => {
|
|
400
|
-
return sourceFolder.root ? resolve(sourceFolder.root, join(...a)) : join(...a);
|
|
401
|
-
};
|
|
402
|
-
const createImport = {
|
|
403
|
-
src(a, { origin }) {
|
|
404
|
-
return origin === "src" ? join(defaults$2.srcPrefix, ...a) : join(defaults$2.appPrefix, defaults$2.srcDir, sourceFolder.name, ...a);
|
|
405
|
-
},
|
|
406
|
-
api(a, o) {
|
|
407
|
-
return this.src([defaults$2.apiDir, ...a], o);
|
|
408
|
-
},
|
|
409
|
-
pages(a, o) {
|
|
410
|
-
return this.src([defaults$2.pagesDir, ...a], o);
|
|
411
|
-
},
|
|
412
|
-
lib(a, { origin }) {
|
|
413
|
-
return origin === "src" ? join(defaults$2.libPrefix, ...a) : join(defaults$2.appPrefix, defaults$2.libDir, sourceFolder.name, ...a);
|
|
414
|
-
},
|
|
415
|
-
libCore(a, o) {
|
|
416
|
-
return this.lib(["core", ...a], o);
|
|
417
|
-
},
|
|
418
|
-
libApi(a, o) {
|
|
419
|
-
return this.lib([defaults$2.apiDir, ...a], o);
|
|
420
|
-
},
|
|
421
|
-
libEntry(a, o) {
|
|
422
|
-
return this.lib([defaults$2.entryDir, ...a], o);
|
|
423
|
-
}
|
|
424
|
-
};
|
|
425
|
-
return {
|
|
426
|
-
createPath: {
|
|
427
|
-
src(...a) {
|
|
428
|
-
return createPath(defaults$2.srcDir, sourceFolder.name, ...a);
|
|
429
|
-
},
|
|
430
|
-
api(...a) {
|
|
431
|
-
return this.src(defaults$2.apiDir, ...a);
|
|
432
|
-
},
|
|
433
|
-
pages(...a) {
|
|
434
|
-
return this.src(defaults$2.pagesDir, ...a);
|
|
435
|
-
},
|
|
436
|
-
entry(...a) {
|
|
437
|
-
return this.src(defaults$2.entryDir, ...a);
|
|
438
|
-
},
|
|
439
|
-
lib(...a) {
|
|
440
|
-
return createPath(defaults$2.libDir, sourceFolder.name, ...a);
|
|
441
|
-
},
|
|
442
|
-
libCore(...a) {
|
|
443
|
-
return this.lib("core", ...a);
|
|
444
|
-
},
|
|
445
|
-
libApi(...a) {
|
|
446
|
-
return this.lib(defaults$2.apiDir, ...a);
|
|
447
|
-
},
|
|
448
|
-
libEntry(...a) {
|
|
449
|
-
return this.lib(defaults$2.entryDir, ...a);
|
|
450
|
-
},
|
|
451
|
-
libPages(...a) {
|
|
452
|
-
return this.lib(defaults$2.pagesDir, ...a);
|
|
453
|
-
},
|
|
454
|
-
distDir(...a) {
|
|
455
|
-
return createPath(sourceFolder.distDir, sourceFolder.name, ...a);
|
|
456
|
-
}
|
|
457
|
-
},
|
|
458
|
-
createImport,
|
|
459
|
-
createImportHelpers(o) {
|
|
460
|
-
if (!["src", "lib"].includes(o?.origin)) throw new Error(`createImportHelpers: required exactly one argument of shape { origin: "src|lib" }`);
|
|
461
|
-
return { createImport(key, ...a) {
|
|
462
|
-
return createImport[key](a.slice(0, -1), o);
|
|
463
|
-
} };
|
|
464
|
-
}
|
|
465
|
-
};
|
|
466
|
-
};
|
|
467
|
-
var pathExists$1 = async (path) => {
|
|
468
|
-
try {
|
|
469
|
-
await access(path, constants.F_OK);
|
|
470
|
-
return true;
|
|
471
|
-
} catch {
|
|
472
|
-
return false;
|
|
473
|
-
}
|
|
474
|
-
};
|
|
475
|
-
var render$1 = (template, context, options) => {
|
|
476
|
-
const { noEscape = true, renderer = handlebars } = { ...options };
|
|
477
|
-
return renderer.compile(template, { noEscape })(context);
|
|
478
|
-
};
|
|
479
|
-
var renderToFile$1 = async (file, template, context, options) => {
|
|
480
|
-
const content = render$1(template, context, options);
|
|
481
|
-
/**
|
|
482
|
-
* Two fs calls (exists + read) are worth it to avoid touching the file
|
|
483
|
-
* and triggering watchers unnecessarily.
|
|
484
|
-
* */
|
|
485
|
-
if (await pathExists$1(file)) {
|
|
486
|
-
const { overwrite = true } = { ...options };
|
|
487
|
-
if (overwrite === false) return;
|
|
488
|
-
const fileContent = await readFile(file, "utf8");
|
|
489
|
-
if (typeof overwrite === "function" && !overwrite(fileContent)) return;
|
|
490
|
-
if (crc(content) === crc(fileContent)) return;
|
|
491
|
-
}
|
|
492
|
-
await mkdir(dirname(file), { recursive: true });
|
|
493
|
-
await writeFile(file, content, "utf8");
|
|
494
|
-
};
|
|
495
|
-
/**
|
|
496
|
-
* Parse a filesystem route path into structured PathToken array.
|
|
497
|
-
*
|
|
498
|
-
* Uses path-to-regexp v8 AST for parsing, with directory-friendly syntax:
|
|
499
|
-
* - [param] => required param - :param
|
|
500
|
-
* - {param} => optional param - {:param}
|
|
501
|
-
* - {...param} => splat - {*param}
|
|
502
|
-
*
|
|
503
|
-
* Direct :param syntax is prohibited outside {} to avoid ambiguity.
|
|
504
|
-
* Inside {} it is treated as path-to-regexp power syntax and used as-is.
|
|
505
|
-
*
|
|
506
|
-
* Examples:
|
|
507
|
-
* Required: [id], [name]
|
|
508
|
-
* Optional: {name}, {format}
|
|
509
|
-
* Splat: {...path}
|
|
510
|
-
* Mixed segments: shop/[id]-{name}
|
|
511
|
-
* Power syntax: {-v:version{-:pre}}, :name{@:version{.:min}}.js
|
|
512
|
-
* */
|
|
513
|
-
var pathTokensFactory = (path, { transformStaticValue = normalizeStaticValue } = {}) => {
|
|
514
|
-
/**
|
|
515
|
-
* Recursively extract parts from path-to-regexp AST tokens.
|
|
516
|
-
* A param inside a group is optional; top-level params are required.
|
|
517
|
-
* Wildcard tokens are always splat.
|
|
518
|
-
* Slash-only text nodes (restored for parsing) are skipped.
|
|
519
|
-
* */
|
|
520
|
-
const extractParts = (tokens, createConst, insideGroup = false) => {
|
|
521
|
-
const parts = [];
|
|
522
|
-
for (const token of tokens) switch (token.type) {
|
|
523
|
-
case "text":
|
|
524
|
-
if (token.value !== "/") parts.push({
|
|
525
|
-
type: "static",
|
|
526
|
-
value: transformStaticValue(token.value)
|
|
527
|
-
});
|
|
528
|
-
break;
|
|
529
|
-
case "param":
|
|
530
|
-
parts.push({
|
|
531
|
-
type: "param",
|
|
532
|
-
kind: insideGroup ? "optional" : "required",
|
|
533
|
-
name: token.name,
|
|
534
|
-
const: createConst(token.name)
|
|
535
|
-
});
|
|
536
|
-
break;
|
|
537
|
-
case "wildcard":
|
|
538
|
-
parts.push({
|
|
539
|
-
type: "param",
|
|
540
|
-
kind: "splat",
|
|
541
|
-
name: token.name,
|
|
542
|
-
const: createConst(token.name)
|
|
543
|
-
});
|
|
544
|
-
break;
|
|
545
|
-
case "group":
|
|
546
|
-
parts.push(...extractParts(token.tokens, createConst, true));
|
|
547
|
-
break;
|
|
548
|
-
}
|
|
549
|
-
return parts;
|
|
550
|
-
};
|
|
551
|
-
const patternTransforms = [
|
|
552
|
-
(s) => s.replace(/\[(\w+)\]/g, ":$1"),
|
|
553
|
-
(s) => s.replace(/\{(\w+)\}/g, "{:$1}"),
|
|
554
|
-
(s) => s.replace(/\{\.\.\./g, "{*"),
|
|
555
|
-
(s) => {
|
|
556
|
-
return s.startsWith("{") ? s.replace(/^\{/, "{/") : s;
|
|
557
|
-
}
|
|
558
|
-
];
|
|
559
|
-
const detectBareParams = (s) => {
|
|
560
|
-
let depth = 0;
|
|
561
|
-
for (const [i, ch] of [...s].entries()) if (ch === "{") depth += 1;
|
|
562
|
-
else if (ch === "}") depth -= 1;
|
|
563
|
-
else if (ch === ":" && depth === 0) return s.slice(i + 1).match(/^\w+/)?.[0] || ":";
|
|
564
|
-
};
|
|
565
|
-
return path.replace(/^index\/?/, "").split("/").flatMap((orig) => {
|
|
566
|
-
if (!orig.length) return [];
|
|
567
|
-
const bareParam = detectBareParams(orig);
|
|
568
|
-
if (bareParam === ":") throw new Error(`${path} contains colons outside braces, use : only within {}`);
|
|
569
|
-
else if (bareParam) throw new Error(`${path} contains bare params, use [${bareParam}] instead of :${bareParam}`);
|
|
570
|
-
const pattern = patternTransforms.reduce((src, fn) => fn(src), orig);
|
|
571
|
-
const { tokens } = parse(pattern.replace(/\{[^}]*\}|(\+)/g, (m, p1) => p1 ? "\\+" : m));
|
|
572
|
-
const parts = extractParts(tokens, (val) => {
|
|
573
|
-
return /\W/.test(val) || /^\d/.test(val) ? [val.replace(/^\d+|\W/g, "_"), crc(orig)].join("_") : val;
|
|
574
|
-
});
|
|
575
|
-
const isStatic = parts.length === 1 ? parts[0].type === "static" : false;
|
|
576
|
-
const isParam = parts.length === 1 ? parts[0].type === "param" : false;
|
|
577
|
-
return [{
|
|
578
|
-
kind: isStatic ? "static" : isParam ? "param" : "mixed",
|
|
579
|
-
orig,
|
|
580
|
-
pattern,
|
|
581
|
-
parts
|
|
582
|
-
}];
|
|
583
|
-
});
|
|
584
|
-
};
|
|
585
|
-
var createPathPattern = (tokens) => {
|
|
586
|
-
return tokens.map(({ pattern }, i) => {
|
|
587
|
-
const next = tokens[i + 1];
|
|
588
|
-
if (!next || next.pattern.includes("/")) return pattern;
|
|
589
|
-
return tokens.slice(i + 1).some((e) => {
|
|
590
|
-
return e.parts.some((e) => {
|
|
591
|
-
return e.type === "static" || e.kind === "required";
|
|
592
|
-
});
|
|
593
|
-
}) ? `${pattern}/` : pattern;
|
|
594
|
-
}).join("");
|
|
595
|
-
};
|
|
596
|
-
var createHonoPattern = (tokens) => {
|
|
597
|
-
const staticValue = ({ value }) => {
|
|
598
|
-
return normalizeStaticValue(value);
|
|
599
|
-
};
|
|
600
|
-
const paramValue = (p) => {
|
|
601
|
-
if (p.kind === "splat") return `*`;
|
|
602
|
-
if (p.kind === "optional") return `:${p.name}?`;
|
|
603
|
-
return `:${p.name}`;
|
|
604
|
-
};
|
|
605
|
-
const escapeRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
606
|
-
const tokensToRegex = (tokens) => {
|
|
607
|
-
return tokens.flatMap((t) => {
|
|
608
|
-
if (t.type === "text") return t.value === "/" ? [] : [escapeRegex(t.value)];
|
|
609
|
-
if (t.type === "wildcard") return [".+"];
|
|
610
|
-
if (t.type === "param") return ["[^/]+"];
|
|
611
|
-
if (t.type === "group") return [`(?:${tokensToRegex(t.tokens)})?`];
|
|
612
|
-
return [];
|
|
613
|
-
}).join("");
|
|
614
|
-
};
|
|
615
|
-
return tokens.flatMap((token, i) => {
|
|
616
|
-
if (token.kind === "static") return [staticValue(token.parts[0])];
|
|
617
|
-
if (token.kind === "param") return [paramValue(token.parts[0])];
|
|
618
|
-
const { tokens } = parse(token.pattern.replace(/\//g, ""));
|
|
619
|
-
return [`:_${i}{${tokensToRegex(tokens)}}`];
|
|
620
|
-
}).join("/");
|
|
621
|
-
};
|
|
622
|
-
var normalizeStaticValue = (value) => {
|
|
623
|
-
return value.replace(/\+/g, "\\\\+");
|
|
624
|
-
};
|
|
625
|
-
var API_INDEX_PATTERN = `index.ts`;
|
|
626
|
-
var API_USE_PATTERN = `use.ts`;
|
|
627
|
-
var PAGE_INDEX_PATTERN = `index.{tsx,vue,mdx,md}`;
|
|
628
|
-
var PAGE_LAYOUT_PATTERN = `layout.{tsx,vue,mdx}`;
|
|
629
|
-
var ROUTE_FILE_PATTERNS = [
|
|
630
|
-
`${defaults$2.apiDir}/**/${API_INDEX_PATTERN}`,
|
|
631
|
-
`${defaults$2.apiDir}/**/${API_USE_PATTERN}`,
|
|
632
|
-
`${defaults$2.pagesDir}/**/${PAGE_INDEX_PATTERN}`,
|
|
633
|
-
`${defaults$2.pagesDir}/**/${PAGE_LAYOUT_PATTERN}`
|
|
634
|
-
];
|
|
635
|
-
var scanRoutes = async (sourceFolder) => {
|
|
636
|
-
const { createPath } = pathResolver$1(sourceFolder);
|
|
637
|
-
return glob(ROUTE_FILE_PATTERNS, {
|
|
638
|
-
cwd: createPath.src(),
|
|
639
|
-
absolute: true,
|
|
640
|
-
onlyFiles: true,
|
|
641
|
-
followSymbolicLinks: false,
|
|
642
|
-
ignore: [
|
|
643
|
-
`${defaults$2.apiDir}/${API_INDEX_PATTERN}`,
|
|
644
|
-
`${defaults$2.apiDir}/${API_USE_PATTERN}`,
|
|
645
|
-
`${defaults$2.pagesDir}/${PAGE_INDEX_PATTERN}`,
|
|
646
|
-
`${defaults$2.pagesDir}/${PAGE_LAYOUT_PATTERN}`
|
|
647
|
-
]
|
|
648
|
-
});
|
|
649
|
-
};
|
|
650
|
-
var isRouteFile = (file, sourceFolder) => {
|
|
651
|
-
const [_sourceFolder, _folder, ...rest] = resolve(sourceFolder.root, file).replace(`${sourceFolder.root}/${defaults$2.srcDir}/`, "").split("/");
|
|
652
|
-
/**
|
|
653
|
-
* Ensure the file:
|
|
654
|
-
* - is under the correct source root
|
|
655
|
-
* - belongs to a known route folder (`api/` or `pages/`)
|
|
656
|
-
* - is nested at least one level deep (not a direct child of the folder)
|
|
657
|
-
* */
|
|
658
|
-
if (!_folder || _sourceFolder !== sourceFolder.name || rest.length < 2) return false;
|
|
659
|
-
return picomatch.isMatch(join(_folder, ...rest), ROUTE_FILE_PATTERNS) ? [_folder, rest.join("/")] : false;
|
|
660
|
-
};
|
|
661
|
-
var isApiRoute = (file) => {
|
|
662
|
-
return picomatch.matchBase(file, `**/${API_INDEX_PATTERN}`);
|
|
663
|
-
};
|
|
664
|
-
var isApiUse = (file) => {
|
|
665
|
-
return picomatch.matchBase(file, `**/${API_USE_PATTERN}`);
|
|
666
|
-
};
|
|
667
|
-
var isPageRoute = (file) => {
|
|
668
|
-
return picomatch.matchBase(file, `**/${PAGE_INDEX_PATTERN}`);
|
|
669
|
-
};
|
|
670
|
-
var isPageLayout = (file) => {
|
|
671
|
-
return picomatch.matchBase(file, `**/${PAGE_LAYOUT_PATTERN}`);
|
|
672
|
-
};
|
|
673
|
-
var createRouteEntry = (fileFullpath, sourceFolder) => {
|
|
674
|
-
const resolvedPaths = isRouteFile(fileFullpath, sourceFolder);
|
|
675
|
-
if (!resolvedPaths) return;
|
|
676
|
-
const [folder, file] = resolvedPaths;
|
|
677
|
-
const id = `${file.replace(/\W+/g, "_")}_${crc(file)}`;
|
|
678
|
-
const name = dirname(file);
|
|
679
|
-
try {
|
|
680
|
-
const pathTokens = pathTokensFactory(dirname(file));
|
|
681
|
-
return {
|
|
682
|
-
id,
|
|
683
|
-
name,
|
|
684
|
-
folder,
|
|
685
|
-
file,
|
|
686
|
-
fileFullpath,
|
|
687
|
-
pathTokens,
|
|
688
|
-
pathPattern: createPathPattern(pathTokens),
|
|
689
|
-
honoPattern: createHonoPattern(pathTokens)
|
|
690
|
-
};
|
|
691
|
-
} catch (error) {
|
|
692
|
-
console.error(`❗${styleText("red", "ERROR")}: Failed parsing path for "${styleText("cyan", file)}"`);
|
|
693
|
-
console.error(error);
|
|
694
|
-
return;
|
|
695
|
-
}
|
|
696
|
-
};
|
|
697
|
-
var resolved_types_default = "{{#each resolvedTypes}}\nexport type {{name}} = {{text}};\n{{/each}}\n";
|
|
698
|
-
var types_default = "{{#each typeDeclarations}}{{text}}\n{{/each}}\n\nexport type {{params.id}} = {\n {{#each paramsSchema}}\n \"{{name}}\"{{#unless isRequired}}?{{/unless}}: {{#if refinement}}\n {{refinement.text}},\n {{else}}\n {{#if isSplat}}Array<string>{{else}}string{{/if}},\n {{/if}}\n {{/each}}\n};\n\n{{#each validationTypes}}export type {{id}} = {{text}};\n{{/each}}\n";
|
|
699
|
-
var resolverFactory = (sourceFolder, cacheFactory) => {
|
|
700
|
-
const { generators = [], refineTypeName = defaults$2.refineTypeName } = sourceFolder.config;
|
|
701
|
-
const { typeResolverFactory, resolveRouteSignature } = astFactory();
|
|
702
|
-
const resolveTypes = generators.some(({ meta }) => meta.resolveTypes);
|
|
703
|
-
const { literalTypesResolver, getSourceFile, refreshSourceFile } = typeResolverFactory(sourceFolder);
|
|
704
|
-
return {
|
|
705
|
-
pageLayoutResolver(entry) {
|
|
706
|
-
const { name } = entry;
|
|
707
|
-
const handler = async () => {
|
|
708
|
-
return {
|
|
709
|
-
kind: "pageLayout",
|
|
710
|
-
entry
|
|
711
|
-
};
|
|
712
|
-
};
|
|
713
|
-
return {
|
|
714
|
-
name,
|
|
715
|
-
handler
|
|
716
|
-
};
|
|
717
|
-
},
|
|
718
|
-
pageRouteResolver(entry) {
|
|
719
|
-
const { id, name, folder, file, fileFullpath, pathTokens, pathPattern, honoPattern } = entry;
|
|
720
|
-
const handler = async () => {
|
|
721
|
-
return {
|
|
722
|
-
kind: "pageRoute",
|
|
723
|
-
entry: {
|
|
724
|
-
id,
|
|
725
|
-
name,
|
|
726
|
-
pathTokens,
|
|
727
|
-
pathPattern,
|
|
728
|
-
honoPattern,
|
|
729
|
-
params: { schema: pathTokens.flatMap((e) => {
|
|
730
|
-
return e.parts.filter((p) => p.type === "param");
|
|
731
|
-
}) },
|
|
732
|
-
folder,
|
|
733
|
-
file,
|
|
734
|
-
fileFullpath
|
|
735
|
-
}
|
|
736
|
-
};
|
|
737
|
-
};
|
|
738
|
-
return {
|
|
739
|
-
name,
|
|
740
|
-
handler
|
|
741
|
-
};
|
|
742
|
-
},
|
|
743
|
-
apiUseResolver(entry) {
|
|
744
|
-
const { name } = entry;
|
|
745
|
-
const handler = async () => {
|
|
746
|
-
return {
|
|
747
|
-
kind: "apiUse",
|
|
748
|
-
entry
|
|
749
|
-
};
|
|
750
|
-
};
|
|
751
|
-
return {
|
|
752
|
-
name,
|
|
753
|
-
handler
|
|
754
|
-
};
|
|
755
|
-
},
|
|
756
|
-
apiRouteResolver(entry) {
|
|
757
|
-
const { id, name, file, folder, fileFullpath, pathTokens, pathPattern, honoPattern } = entry;
|
|
758
|
-
const handler = async (updatedFile) => {
|
|
759
|
-
const paramsSchema = pathTokens.flatMap((e) => {
|
|
760
|
-
return e.parts.flatMap((p) => {
|
|
761
|
-
return p.type === "param" ? [p] : [];
|
|
762
|
-
});
|
|
763
|
-
});
|
|
764
|
-
const optionalParams = paramsSchema.length ? paramsSchema.filter((e) => e.kind === "required").length === 0 : true;
|
|
765
|
-
const cacheStore = cacheFactory ? cacheFactory({
|
|
766
|
-
id,
|
|
767
|
-
file,
|
|
768
|
-
fileFullpath
|
|
769
|
-
}, sourceFolder, { resolveTypes }) : void 0;
|
|
770
|
-
let cache = cacheStore ? await cacheStore.get({ validate: true }) : void 0;
|
|
771
|
-
if (!cache) {
|
|
772
|
-
if (updatedFile === fileFullpath) await refreshSourceFile(fileFullpath);
|
|
773
|
-
const { typeDeclarations, paramsRefinements, methods, validationDefinitions, referencedFiles = [] } = await resolveRouteSignature({
|
|
774
|
-
id,
|
|
775
|
-
name,
|
|
776
|
-
fileFullpath,
|
|
777
|
-
optionalParams
|
|
778
|
-
}, {
|
|
779
|
-
withReferencedFiles: true,
|
|
780
|
-
sourceFile: getSourceFile(fileFullpath),
|
|
781
|
-
relpathResolver(path) {
|
|
782
|
-
return join(sourceFolder.name, defaults$2.apiDir, dirname(file), path);
|
|
783
|
-
}
|
|
784
|
-
});
|
|
785
|
-
const validationTypes = validationDefinitions.flatMap((def) => {
|
|
786
|
-
return def.target === "response" ? def.variants.flatMap(({ id, body }) => {
|
|
787
|
-
return body ? [{
|
|
788
|
-
id,
|
|
789
|
-
text: body
|
|
790
|
-
}] : [];
|
|
791
|
-
}) : [def.schema];
|
|
792
|
-
});
|
|
793
|
-
const numericParams = paramsRefinements ? paramsRefinements.flatMap(({ text, index }) => {
|
|
794
|
-
if (text === "number") {
|
|
795
|
-
const param = paramsSchema.at(index);
|
|
796
|
-
return param ? [param.name] : [];
|
|
797
|
-
}
|
|
798
|
-
return [];
|
|
799
|
-
}) : [];
|
|
800
|
-
const typesFile = pathResolver$1(sourceFolder).createPath.libApi(dirname(file), "types.ts");
|
|
801
|
-
const params = {
|
|
802
|
-
id: ["ParamsT", crc(name)].join(""),
|
|
803
|
-
schema: paramsSchema,
|
|
804
|
-
resolvedType: void 0
|
|
805
|
-
};
|
|
806
|
-
const typesFileContent = render$1(types_default, {
|
|
807
|
-
params,
|
|
808
|
-
paramsSchema: paramsSchema.map((param, index) => {
|
|
809
|
-
return {
|
|
810
|
-
...param,
|
|
811
|
-
isRequired: param.kind === "required",
|
|
812
|
-
isSplat: param.kind === "splat",
|
|
813
|
-
refinement: paramsRefinements?.at(index)
|
|
814
|
-
};
|
|
815
|
-
}),
|
|
816
|
-
typeDeclarations,
|
|
817
|
-
validationTypes
|
|
818
|
-
});
|
|
819
|
-
const resolvedTypes = resolveTypes ? literalTypesResolver(typesFileContent, {
|
|
820
|
-
stripComments: true,
|
|
821
|
-
overrides: { [refineTypeName]: refineTypeName },
|
|
822
|
-
withProperties: [params.id, ...validationTypes.flatMap(({ id }) => id)]
|
|
823
|
-
}) : void 0;
|
|
824
|
-
/**
|
|
825
|
-
* Deploy types.ts file; required by core generators (like fetch).
|
|
826
|
-
* If types resolved, write resolved types;
|
|
827
|
-
* otherwise write original types extracted from API route.
|
|
828
|
-
* */
|
|
829
|
-
await renderToFile$1(typesFile, resolvedTypes ? resolved_types_default : typesFileContent, { resolvedTypes });
|
|
830
|
-
params.resolvedType = resolvedTypes?.find((e) => e.name === params.id);
|
|
831
|
-
cache = {
|
|
832
|
-
hash: 0,
|
|
833
|
-
referencedFiles: {},
|
|
834
|
-
params,
|
|
835
|
-
methods,
|
|
836
|
-
typeDeclarations,
|
|
837
|
-
numericParams,
|
|
838
|
-
validationDefinitions: validationDefinitions.map((def) => {
|
|
839
|
-
return {
|
|
840
|
-
...def,
|
|
841
|
-
...def.target === "response" ? { variants: def.variants.map((variant) => {
|
|
842
|
-
return {
|
|
843
|
-
...variant,
|
|
844
|
-
resolvedType: resolvedTypes?.find((e) => e.name === variant.id)
|
|
845
|
-
};
|
|
846
|
-
}) } : { schema: {
|
|
847
|
-
...def.schema,
|
|
848
|
-
resolvedType: resolvedTypes?.find((e) => e.name === def.schema.id)
|
|
849
|
-
} }
|
|
850
|
-
};
|
|
851
|
-
})
|
|
852
|
-
};
|
|
853
|
-
if (cacheStore) {
|
|
854
|
-
const { referencedFiles: _void, ...rest } = cache;
|
|
855
|
-
cache = await cacheStore.set({
|
|
856
|
-
...rest,
|
|
857
|
-
referencedFiles
|
|
858
|
-
});
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
const validationDefinitions = cache.validationDefinitions.flatMap((def) => {
|
|
862
|
-
let augmentedDef = def;
|
|
863
|
-
if (def.target === "response") augmentedDef = {
|
|
864
|
-
...def,
|
|
865
|
-
variants: def.variants.flatMap((variant, i) => {
|
|
866
|
-
if (typeof variant.contentType !== "string") return [variant];
|
|
867
|
-
if (variant.contentType.includes("/")) return [variant];
|
|
868
|
-
const contentType = mimeTypes.lookup(variant.contentType);
|
|
869
|
-
if (contentType === false) {
|
|
870
|
-
console.warn(styleText(["bold", "red"], "✗ Failed resolving Response Content Type"));
|
|
871
|
-
console.warn(` Invalid value provided for mime-types lookup - ${variant.contentType}`);
|
|
872
|
-
console.warn(styleText(["cyan"], ` Response variant #${i} excluded from route schemas`));
|
|
873
|
-
console.warn(` Route: ${name}; Method: ${def.method}`);
|
|
874
|
-
console.warn();
|
|
875
|
-
return [];
|
|
876
|
-
}
|
|
877
|
-
return [{
|
|
878
|
-
...variant,
|
|
879
|
-
contentType
|
|
880
|
-
}];
|
|
881
|
-
})
|
|
882
|
-
};
|
|
883
|
-
else if (def.contentType && !def.contentType.includes("/")) {
|
|
884
|
-
const contentType = mimeTypes.lookup(def.contentType);
|
|
885
|
-
if (contentType === false) {
|
|
886
|
-
console.warn(styleText(["bold", "red"], "✗ Failed resolving Response Content Type"));
|
|
887
|
-
console.warn(` Invalid value provided for mime-types lookup - ${def.contentType}`);
|
|
888
|
-
console.warn(` Route: ${name}; Method: ${def.method}`);
|
|
889
|
-
console.warn();
|
|
890
|
-
} else augmentedDef = {
|
|
891
|
-
...def,
|
|
892
|
-
contentType
|
|
893
|
-
};
|
|
894
|
-
}
|
|
895
|
-
return augmentedDef ? [augmentedDef] : [];
|
|
896
|
-
});
|
|
897
|
-
return {
|
|
898
|
-
kind: "apiRoute",
|
|
899
|
-
entry: {
|
|
900
|
-
id,
|
|
901
|
-
name,
|
|
902
|
-
pathTokens,
|
|
903
|
-
pathPattern,
|
|
904
|
-
honoPattern,
|
|
905
|
-
params: cache.params,
|
|
906
|
-
numericParams: cache.numericParams,
|
|
907
|
-
optionalParams,
|
|
908
|
-
folder,
|
|
909
|
-
file,
|
|
910
|
-
fileFullpath,
|
|
911
|
-
methods: cache.methods,
|
|
912
|
-
typeDeclarations: cache.typeDeclarations,
|
|
913
|
-
validationDefinitions,
|
|
914
|
-
referencedFiles: Object.keys(cache.referencedFiles).map((e) => resolve(sourceFolder.root, e))
|
|
915
|
-
}
|
|
916
|
-
};
|
|
917
|
-
};
|
|
918
|
-
return {
|
|
919
|
-
name,
|
|
920
|
-
handler
|
|
921
|
-
};
|
|
922
|
-
}
|
|
923
|
-
};
|
|
924
|
-
};
|
|
925
|
-
var routesFactory = async (sourceFolder, cacheFactory) => {
|
|
926
|
-
const { apiRouteResolver, apiUseResolver, pageRouteResolver, pageLayoutResolver } = resolverFactory(sourceFolder, cacheFactory);
|
|
927
|
-
const resolversFactory = (routeFiles) => {
|
|
928
|
-
const resolvers = /* @__PURE__ */ new Map();
|
|
929
|
-
const entries = routeFiles.flatMap((file) => {
|
|
930
|
-
const entry = createRouteEntry(file, sourceFolder);
|
|
931
|
-
return entry ? [entry] : [];
|
|
932
|
-
});
|
|
933
|
-
for (const entry of entries) if (entry.folder === defaults$2.apiDir) {
|
|
934
|
-
if (isApiRoute(entry.file)) resolvers.set(entry.fileFullpath, apiRouteResolver(entry));
|
|
935
|
-
else if (isApiUse(entry.file)) resolvers.set(entry.fileFullpath, apiUseResolver(entry));
|
|
936
|
-
} else if (entry.folder === defaults$2.pagesDir) {
|
|
937
|
-
if (isPageRoute(entry.file)) resolvers.set(entry.fileFullpath, pageRouteResolver(entry));
|
|
938
|
-
else if (isPageLayout(entry.file)) resolvers.set(entry.fileFullpath, pageLayoutResolver(entry));
|
|
939
|
-
}
|
|
940
|
-
return resolvers;
|
|
941
|
-
};
|
|
942
|
-
return {
|
|
943
|
-
resolvers: resolversFactory(await scanRoutes(sourceFolder)),
|
|
944
|
-
resolversFactory
|
|
945
|
-
};
|
|
946
|
-
};
|
|
947
|
-
var spinnerFactory = (startText) => {
|
|
948
|
-
const spinner = new Spinner().start(startText);
|
|
949
|
-
let _text = startText;
|
|
950
|
-
return {
|
|
951
|
-
text(text) {
|
|
952
|
-
_text = text;
|
|
953
|
-
spinner.text = text;
|
|
954
|
-
},
|
|
955
|
-
append(text) {
|
|
956
|
-
spinner.text = `${_text} › ${text}`;
|
|
957
|
-
},
|
|
958
|
-
succeed(text) {
|
|
959
|
-
if (text) this.append(text);
|
|
960
|
-
else this.text(_text);
|
|
961
|
-
spinner.succeed();
|
|
962
|
-
},
|
|
963
|
-
failed(text) {
|
|
964
|
-
if (text) this.text([_text, text].join("\n"));
|
|
965
|
-
spinner.failed();
|
|
966
|
-
}
|
|
967
|
-
};
|
|
968
|
-
};
|
|
969
|
-
//#endregion
|
|
970
|
-
//#region ../../generators/core-generator/pkg/index.js
|
|
971
|
-
var routeRenderHelpers = () => {
|
|
972
|
-
return {
|
|
973
|
-
pageLinkBase({ name, pathPattern, params }) {
|
|
974
|
-
return JSON.stringify({
|
|
975
|
-
name,
|
|
976
|
-
pathPattern,
|
|
977
|
-
params
|
|
978
|
-
});
|
|
979
|
-
},
|
|
980
|
-
serializeParamsTupleElements: (route) => {
|
|
981
|
-
return route.params.schema.map((p, i) => {
|
|
982
|
-
if (p.kind === "splat") {
|
|
983
|
-
const suffix = route.params.schema[i + 1] ? "" : "?";
|
|
984
|
-
return `${p.const + suffix}: Array<string | number>`;
|
|
985
|
-
}
|
|
986
|
-
return p.kind === "optional" ? `${p.const}?: string | number` : `${p.const}: string | number`;
|
|
987
|
-
}).join(", ");
|
|
988
|
-
},
|
|
989
|
-
serializeParamsLiteral(route) {
|
|
990
|
-
return `{ ${route.params.schema.map((e) => {
|
|
991
|
-
return [[e.name, e.kind === "required" ? "" : "?"].join(""), e.kind === "splat" ? "Array<string>" : "string"].join(": ");
|
|
992
|
-
}).join("; ")} }`;
|
|
993
|
-
}
|
|
994
|
-
};
|
|
995
|
-
};
|
|
996
|
-
var defaults$1 = {
|
|
997
|
-
appPrefix: "@",
|
|
998
|
-
srcPrefix: "~",
|
|
999
|
-
libPrefix: "_",
|
|
1000
|
-
coreDir: "core",
|
|
1001
|
-
srcDir: "src",
|
|
1002
|
-
libDir: "lib",
|
|
1003
|
-
configDir: "config",
|
|
1004
|
-
apiDir: "api",
|
|
1005
|
-
pagesDir: "pages",
|
|
1006
|
-
entryDir: "entry",
|
|
1007
|
-
fetchDir: "fetch",
|
|
1008
|
-
refineTypeName: "VRefine"
|
|
1009
|
-
};
|
|
1010
|
-
/**
|
|
1011
|
-
* Request metadata validation targets.
|
|
1012
|
-
* */
|
|
1013
|
-
var RequestMetadataTargets$1 = {
|
|
1014
|
-
query: "URL query parameters",
|
|
1015
|
-
headers: "HTTP request headers",
|
|
1016
|
-
cookies: "HTTP cookies"
|
|
1017
|
-
};
|
|
1018
|
-
/**
|
|
1019
|
-
* Request body validation targets.
|
|
1020
|
-
*
|
|
1021
|
-
* Body formats are mutually exclusive - only one should be specified per handler.
|
|
1022
|
-
*
|
|
1023
|
-
* **Development behavior:**
|
|
1024
|
-
* - If multiple formats are defined, the builder displays a warning and
|
|
1025
|
-
* disables validation schemas for the affected handler.
|
|
1026
|
-
* - If an unsuitable target is defined (e.g., `json`, `form`)
|
|
1027
|
-
* for a method without a body like GET, HEAD), a warning is displayed and
|
|
1028
|
-
* validation schemas are disabled for that handler.
|
|
1029
|
-
*
|
|
1030
|
-
* This ensures misconfigurations are detected during development
|
|
1031
|
-
* for runtime to execute without false positive validation failures.
|
|
1032
|
-
*
|
|
1033
|
-
* Always define exactly one target that is suitable for current handler.
|
|
1034
|
-
* */
|
|
1035
|
-
var RequestBodyTargets$1 = {
|
|
1036
|
-
json: "JSON request body",
|
|
1037
|
-
form: "URL-encoded or Multipart form",
|
|
1038
|
-
raw: "Raw body format (string/Buffer/ArrayBuffer/Blob)"
|
|
1039
|
-
};
|
|
1040
|
-
({
|
|
1041
|
-
...RequestMetadataTargets$1,
|
|
1042
|
-
...RequestBodyTargets$1
|
|
1043
|
-
});
|
|
1044
|
-
var defineGenerator = (f) => f;
|
|
1045
|
-
var defineGeneratorFactory = (f) => f;
|
|
1046
|
-
var pathResolver = (sourceFolder) => {
|
|
1047
|
-
const createPath = (...a) => {
|
|
1048
|
-
return sourceFolder.root ? resolve(sourceFolder.root, join(...a)) : join(...a);
|
|
1049
|
-
};
|
|
1050
|
-
const createImport = {
|
|
1051
|
-
src(a, { origin }) {
|
|
1052
|
-
return origin === "src" ? join(defaults$1.srcPrefix, ...a) : join(defaults$1.appPrefix, defaults$1.srcDir, sourceFolder.name, ...a);
|
|
1053
|
-
},
|
|
1054
|
-
api(a, o) {
|
|
1055
|
-
return this.src([defaults$1.apiDir, ...a], o);
|
|
1056
|
-
},
|
|
1057
|
-
pages(a, o) {
|
|
1058
|
-
return this.src([defaults$1.pagesDir, ...a], o);
|
|
1059
|
-
},
|
|
1060
|
-
lib(a, { origin }) {
|
|
1061
|
-
return origin === "src" ? join(defaults$1.libPrefix, ...a) : join(defaults$1.appPrefix, defaults$1.libDir, sourceFolder.name, ...a);
|
|
1062
|
-
},
|
|
1063
|
-
libCore(a, o) {
|
|
1064
|
-
return this.lib(["core", ...a], o);
|
|
1065
|
-
},
|
|
1066
|
-
libApi(a, o) {
|
|
1067
|
-
return this.lib([defaults$1.apiDir, ...a], o);
|
|
1068
|
-
},
|
|
1069
|
-
libEntry(a, o) {
|
|
1070
|
-
return this.lib([defaults$1.entryDir, ...a], o);
|
|
1071
|
-
}
|
|
1072
|
-
};
|
|
1073
|
-
return {
|
|
1074
|
-
createPath: {
|
|
1075
|
-
src(...a) {
|
|
1076
|
-
return createPath(defaults$1.srcDir, sourceFolder.name, ...a);
|
|
1077
|
-
},
|
|
1078
|
-
api(...a) {
|
|
1079
|
-
return this.src(defaults$1.apiDir, ...a);
|
|
1080
|
-
},
|
|
1081
|
-
pages(...a) {
|
|
1082
|
-
return this.src(defaults$1.pagesDir, ...a);
|
|
1083
|
-
},
|
|
1084
|
-
entry(...a) {
|
|
1085
|
-
return this.src(defaults$1.entryDir, ...a);
|
|
1086
|
-
},
|
|
1087
|
-
lib(...a) {
|
|
1088
|
-
return createPath(defaults$1.libDir, sourceFolder.name, ...a);
|
|
1089
|
-
},
|
|
1090
|
-
libCore(...a) {
|
|
1091
|
-
return this.lib("core", ...a);
|
|
1092
|
-
},
|
|
1093
|
-
libApi(...a) {
|
|
1094
|
-
return this.lib(defaults$1.apiDir, ...a);
|
|
1095
|
-
},
|
|
1096
|
-
libEntry(...a) {
|
|
1097
|
-
return this.lib(defaults$1.entryDir, ...a);
|
|
1098
|
-
},
|
|
1099
|
-
libPages(...a) {
|
|
1100
|
-
return this.lib(defaults$1.pagesDir, ...a);
|
|
1101
|
-
},
|
|
1102
|
-
distDir(...a) {
|
|
1103
|
-
return createPath(sourceFolder.distDir, sourceFolder.name, ...a);
|
|
1104
|
-
}
|
|
1105
|
-
},
|
|
1106
|
-
createImport,
|
|
1107
|
-
createImportHelpers(o) {
|
|
1108
|
-
if (!["src", "lib"].includes(o?.origin)) throw new Error(`createImportHelpers: required exactly one argument of shape { origin: "src|lib" }`);
|
|
1109
|
-
return { createImport(key, ...a) {
|
|
1110
|
-
return createImport[key](a.slice(0, -1), o);
|
|
1111
|
-
} };
|
|
1112
|
-
}
|
|
1113
|
-
};
|
|
1114
|
-
};
|
|
1115
|
-
var pathExists = async (path) => {
|
|
1116
|
-
try {
|
|
1117
|
-
await access(path, constants.F_OK);
|
|
1118
|
-
return true;
|
|
1119
|
-
} catch {
|
|
1120
|
-
return false;
|
|
1121
|
-
}
|
|
1122
|
-
};
|
|
1123
|
-
var render = (template, context, options) => {
|
|
1124
|
-
const { noEscape = true, renderer = handlebars } = { ...options };
|
|
1125
|
-
return renderer.compile(template, { noEscape })(context);
|
|
1126
|
-
};
|
|
1127
|
-
var renderToFile = async (file, template, context, options) => {
|
|
1128
|
-
const content = render(template, context, options);
|
|
1129
|
-
/**
|
|
1130
|
-
* Two fs calls (exists + read) are worth it to avoid touching the file
|
|
1131
|
-
* and triggering watchers unnecessarily.
|
|
1132
|
-
* */
|
|
1133
|
-
if (await pathExists(file)) {
|
|
1134
|
-
const { overwrite = true } = { ...options };
|
|
1135
|
-
if (overwrite === false) return;
|
|
1136
|
-
const fileContent = await readFile(file, "utf8");
|
|
1137
|
-
if (typeof overwrite === "function" && !overwrite(fileContent)) return;
|
|
1138
|
-
if (crc(content) === crc(fileContent)) return;
|
|
1139
|
-
}
|
|
1140
|
-
await mkdir(dirname(file), { recursive: true });
|
|
1141
|
-
await writeFile(file, content, "utf8");
|
|
1142
|
-
};
|
|
1143
|
-
var renderFactory = (options) => {
|
|
1144
|
-
const createRenderer = (selfOoptions) => {
|
|
1145
|
-
const renderer = handlebars.create();
|
|
1146
|
-
renderer.registerPartial({
|
|
1147
|
-
...options?.partials,
|
|
1148
|
-
...selfOoptions?.partials
|
|
1149
|
-
});
|
|
1150
|
-
renderer.registerHelper({
|
|
1151
|
-
...options?.helpers,
|
|
1152
|
-
...selfOoptions?.helpers
|
|
1153
|
-
});
|
|
1154
|
-
return renderer;
|
|
1155
|
-
};
|
|
1156
|
-
return {
|
|
1157
|
-
render(template, context, selfOoptions) {
|
|
1158
|
-
return render(template, context, {
|
|
1159
|
-
...options,
|
|
1160
|
-
...selfOoptions,
|
|
1161
|
-
renderer: createRenderer(selfOoptions)
|
|
1162
|
-
});
|
|
1163
|
-
},
|
|
1164
|
-
async renderToFile(file, template, context, selfOoptions) {
|
|
1165
|
-
return renderToFile(options?.outdir ? join(options.outdir, file) : file, template, context, {
|
|
1166
|
-
...options,
|
|
1167
|
-
...selfOoptions,
|
|
1168
|
-
renderer: createRenderer(selfOoptions)
|
|
1169
|
-
});
|
|
1170
|
-
}
|
|
1171
|
-
};
|
|
1172
|
-
};
|
|
1173
|
-
`${defaults$1.apiDir}`, `${defaults$1.apiDir}`, `${defaults$1.pagesDir}`, `${defaults$1.pagesDir}`;
|
|
1174
|
-
var package_default$1 = {
|
|
1175
|
-
type: "module",
|
|
1176
|
-
"private": true,
|
|
1177
|
-
name: "@kosmojs/core-generator",
|
|
1178
|
-
version: "0.1.0",
|
|
1179
|
-
author: "Slee Woo",
|
|
1180
|
-
license: "MIT",
|
|
1181
|
-
files: ["pkg/*"],
|
|
1182
|
-
imports: { "#templates/*": "./src/templates/*" },
|
|
1183
|
-
exports: { ".": {
|
|
1184
|
-
"types": "./pkg/index.d.ts",
|
|
1185
|
-
"default": "./pkg/index.js"
|
|
1186
|
-
} },
|
|
1187
|
-
scripts: { "build": "wsbuild src/index.ts" },
|
|
1188
|
-
devDependencies: {
|
|
1189
|
-
"@kosmojs/core": "workspace:^",
|
|
1190
|
-
"@kosmojs/lib": "workspace:^",
|
|
1191
|
-
"path-to-regexp": "^8.4.2"
|
|
1192
|
-
}
|
|
1193
|
-
};
|
|
1194
|
-
var config_default = "export const base = \"{{config.base}}\";\nexport const apiBase = \"{{config.apiBase}}\";\n";
|
|
1195
|
-
var core_default = "export * from \"./config\";\nexport * from \"./routeMap\";\n";
|
|
1196
|
-
var pathMapper_default = "import { compile } from \"path-to-regexp\";\n\nimport type { PathMapperSignature } from \"@kosmojs/core\";\nimport { createHost, join, stringify } from \"@kosmojs/core/fetch\";\n\nexport const pathMapper = <ParamsT extends readonly unknown[]>(\n basePath: string,\n routeName: string,\n pathPattern: string,\n paramsMap: Array<[name: string, kind: string]>,\n numericParams: Array<string>,\n): PathMapperSignature<ParamsT> => {\n const toPath = compile(pathPattern);\n\n const castParam = (name: string, value: unknown) => {\n if (numericParams.includes(name)) {\n const n = Number(value);\n return Number.isFinite(n) ? n : String(value);\n }\n return String(value);\n };\n\n const paramsMapper: PathMapperSignature<ParamsT>[\"paramsMapper\"] = (\n params,\n ) => {\n return paramsMap.reduce<Record<string, unknown>>((map, [name, kind], i) => {\n if (kind === \"splat\") {\n if (Array.isArray(params[i]) && params[i].length) {\n map[name] = params[i].map((v) => castParam(name, v));\n }\n } else if (params[i] !== undefined) {\n map[name] = castParam(name, params[i]);\n }\n return map;\n }, {});\n };\n\n const parametrize: PathMapperSignature<ParamsT>[\"parametrize\"] = (params) => {\n try {\n return toPath(paramsMapper(params) as never);\n } catch (error) {\n console.error(`❗ERROR: Failed building path for ${routeName}`);\n throw error;\n }\n };\n\n const base: PathMapperSignature<ParamsT>[\"base\"] = (params, query) => {\n const path = join(\"/\", parametrize(params));\n return query ? [path, stringify(query)].join(\"?\") : path;\n };\n\n const path: PathMapperSignature<ParamsT>[\"path\"] = (params, query) => {\n return join(basePath, base(params, query));\n };\n\n const href: PathMapperSignature<ParamsT>[\"href\"] = (host, params, query) => {\n return createHost(host) + path(params, query);\n };\n\n return {\n paramsMapper,\n parametrize,\n base,\n path,\n href,\n };\n};\n";
|
|
1197
|
-
var routeMap_default = "{{> pathMapper}}\n\nimport { base, apiBase } from \"./config\";\n\n{{#if pageRoutes.length}}\nexport type LinkProps =\n {{#each pageRoutes}}\n | [ \"{{name}}\", {{serializeParamsTupleElements .}} ]\n {{/each}};\n{{else}}\nexport type LinkProps = never;\n{{/if}}\n\nexport const apiRouteMap = {\n {{#each apiRoutes}}\n \"{{name}}\": pathMapper<[{{serializeParamsTupleElements .}}]>(\n apiBase,\n \"{{name}}\",\n \"{{pathPattern}}\",\n [{{#each params.schema}}[\"{{name}}\", \"{{kind}}\"], {{/each}}],\n [{{#each numericParams}}\"{{.}}\", {{/each}}],\n ),\n {{/each}}\n};\n\nexport const pageRouteMap = {\n {{#each pageRoutes}}\n \"{{name}}\": pathMapper<[{{serializeParamsTupleElements .}}]>(\n base,\n \"{{name}}\",\n \"{{pathPattern}}\",\n [{{#each params.schema}}[\"{{name}}\", \"{{kind}}\"], {{/each}}],\n [{{#each numericParams}}\"{{.}}\", {{/each}}],\n ),\n {{/each}}\n};\n";
|
|
1198
|
-
var env_d_default = "declare const KOSMO_PRODUCTION_BUILD: boolean;\n\n/**\n * Enhances base TypeScript types with JSON Schema validation constraints.\n * Allows declaring refined types that carry validation metadata for runtime\n * schema validation while maintaining full TypeScript type safety.\n *\n * Useful for generating validation schemas and ensuring\n * data conforms to specific business rules beyond basic type checking.\n * */\ndeclare type VRefine<\n T extends unknown[] | number | string | object,\n _ extends T extends unknown[]\n ? TArrayOptions\n : T extends number\n ? TNumberOptions\n : T extends string\n ? TStringOptions\n : TObjectOptions,\n> = T;\n\n/**\n * Type definitions inspired by and gently adapted from TypeBox.\n * Original TypeBox created by sinclairzx81: https://github.com/sinclairzx81/typebox\n * TypeBox is licensed under MIT: https://github.com/sinclairzx81/typebox/blob/main/license\n *\n * These types provide JSON Schema compatible type refinements for TypeScript.\n * */\ninterface TSchema {}\n\n// ------------------------------------------------------------------\n// ObjectOptions\n// ------------------------------------------------------------------\ninterface TObjectOptions {\n /**\n * Defines whether additional properties are allowed beyond those explicitly defined in `properties`.\n */\n additionalProperties?: TSchema | boolean;\n /**\n * The minimum number of properties required in the object.\n */\n minProperties?: number;\n /**\n * The maximum number of properties allowed in the object.\n */\n maxProperties?: number;\n /**\n * Defines conditional requirements for properties.\n */\n dependencies?: Record<string, boolean | TSchema | string[]>;\n /**\n * Specifies properties that *must* be present if a given property is present.\n */\n dependentRequired?: Record<string, string[]>;\n /**\n * Defines schemas that apply if a specific property is present.\n */\n dependentSchemas?: Record<string, TSchema>;\n /**\n * Maps regular expressions to schemas properties matching a pattern must validate against the schema.\n */\n patternProperties?: Record<string, TSchema>;\n /**\n * A schema that all property names within the object must validate against.\n */\n propertyNames?: TSchema;\n}\n\n// ------------------------------------------------------------------\n// ArrayOptions\n// ------------------------------------------------------------------\ninterface TArrayOptions {\n /**\n * The minimum number of items allowed in the array.\n */\n minItems?: number;\n /**\n * The maximum number of items allowed in the array.\n */\n maxItems?: number;\n /**\n * A schema that at least one item in the array must validate against.\n */\n contains?: TSchema;\n /**\n * The minimum number of array items that must validate against the `contains` schema.\n */\n minContains?: number;\n /**\n * The maximum number of array items that may validate against the `contains` schema.\n */\n maxContains?: number;\n /**\n * An array of schemas, where each schema in `prefixItems` validates against items at corresponding positions from the beginning of the array.\n */\n prefixItems?: TSchema[];\n /**\n * If `true`, all items in the array must be unique.\n */\n uniqueItems?: boolean;\n}\n\n// ------------------------------------------------------------------\n// NumberOptions\n// ------------------------------------------------------------------\ninterface TNumberOptions {\n /**\n * Specifies an exclusive upper limit for the number (number must be less than this value).\n */\n exclusiveMaximum?: number | bigint;\n /**\n * Specifies an exclusive lower limit for the number (number must be greater than this value).\n */\n exclusiveMinimum?: number | bigint;\n /**\n * Specifies an inclusive upper limit for the number (number must be less than or equal to this value).\n */\n maximum?: number | bigint;\n /**\n * Specifies an inclusive lower limit for the number (number must be greater than or equal to this value).\n */\n minimum?: number | bigint;\n /**\n * Specifies that the number must be a multiple of this value.\n */\n multipleOf?: number | bigint;\n}\n\n// ------------------------------------------------------------------\n// StringOptions\n// ------------------------------------------------------------------\ntype TFormat =\n | \"date-time\"\n | \"date\"\n | \"duration\"\n | \"email\"\n | \"hostname\"\n | \"idn-email\"\n | \"idn-hostname\"\n | \"ipv4\"\n | \"ipv6\"\n | \"iri-reference\"\n | \"iri\"\n | \"json-pointer-uri-fragment\"\n | \"json-pointer\"\n | \"json-string\"\n | \"regex\"\n | \"relative-json-pointer\"\n | \"time\"\n | \"uri-reference\"\n | \"uri-template\"\n | \"url\"\n | \"uuid\";\n\ninterface TStringOptions {\n /**\n * Specifies the expected string format.\n *\n * Common values include:\n * - `base64` – Base64-encoded string.\n * - `date-time` – [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date-time format.\n * - `date` – [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date (YYYY-MM-DD).\n * - `duration` – [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) duration format.\n * - `email` – RFC 5321/5322 compliant email address.\n * - `hostname` – RFC 1034/1035 compliant host name.\n * - `idn-email` – Internationalized email address.\n * - `idn-hostname` – Internationalized host name.\n * - `ipv4` – IPv4 address.\n * - `ipv6` – IPv6 address.\n * - `iri` / `iri-reference` – Internationalized Resource Identifier.\n * - `json-pointer` / `json-pointer-uri-fragment` – JSON Pointer format.\n * - `json-string` – String containing valid JSON.\n * - `regex` – Regular expression syntax.\n * - `relative-json-pointer` – Relative JSON Pointer format.\n * - `time` – [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) time (HH:MM:SS).\n * - `uri-reference` / `uri-template` – URI reference or template.\n * - `url` – Web URL format.\n * - `uuid` – RFC 4122 UUID string.\n *\n * May also be a custom format string.\n */\n format?: TFormat;\n /**\n * Specifies the minimum number of characters allowed in the string.\n * Must be a non-negative integer.\n */\n minLength?: number;\n /**\n * Specifies the maximum number of characters allowed in the string.\n * Must be a non-negative integer.\n */\n maxLength?: number;\n /**\n * Specifies a regular expression pattern that the string value must match.\n * Can be provided as a string (ECMA-262 regex syntax) or a `RegExp` object.\n */\n pattern?: string | RegExp;\n}\n";
|
|
1199
|
-
var gitignore_default = "# Ignore all files\n*\n\n# But don't ignore directories (so Git can traverse them)\n!*/\n\n# And don't ignore these files at any depth\n!cache.json\n!types.ts\n";
|
|
1200
|
-
var schemas_default = "// stub schemas, specialized generators supposed to overwrite this file\nimport type { ValidationSchemas } from \"@kosmojs/core/api\";\nexport type { ValidationSchemas };\nexport const validationSchemas: ValidationSchemas = {};\n";
|
|
1201
|
-
var defaults = {
|
|
1202
|
-
appPrefix: "@",
|
|
1203
|
-
srcPrefix: "~",
|
|
1204
|
-
libPrefix: "_",
|
|
1205
|
-
coreDir: "core",
|
|
1206
|
-
srcDir: "src",
|
|
1207
|
-
libDir: "lib",
|
|
1208
|
-
configDir: "config",
|
|
1209
|
-
apiDir: "api",
|
|
1210
|
-
pagesDir: "pages",
|
|
1211
|
-
entryDir: "entry",
|
|
1212
|
-
fetchDir: "fetch",
|
|
1213
|
-
refineTypeName: "VRefine"
|
|
1214
|
-
};
|
|
1215
|
-
/**
|
|
1216
|
-
* Request metadata validation targets.
|
|
1217
|
-
* */
|
|
1218
|
-
var RequestMetadataTargets = {
|
|
1219
|
-
query: "URL query parameters",
|
|
1220
|
-
headers: "HTTP request headers",
|
|
1221
|
-
cookies: "HTTP cookies"
|
|
1222
|
-
};
|
|
1223
|
-
/**
|
|
1224
|
-
* Request body validation targets.
|
|
1225
|
-
*
|
|
1226
|
-
* Body formats are mutually exclusive - only one should be specified per handler.
|
|
1227
|
-
*
|
|
1228
|
-
* **Development behavior:**
|
|
1229
|
-
* - If multiple formats are defined, the builder displays a warning and
|
|
1230
|
-
* disables validation schemas for the affected handler.
|
|
1231
|
-
* - If an unsuitable target is defined (e.g., `json`, `form`)
|
|
1232
|
-
* for a method without a body like GET, HEAD), a warning is displayed and
|
|
1233
|
-
* validation schemas are disabled for that handler.
|
|
1234
|
-
*
|
|
1235
|
-
* This ensures misconfigurations are detected during development
|
|
1236
|
-
* for runtime to execute without false positive validation failures.
|
|
1237
|
-
*
|
|
1238
|
-
* Always define exactly one target that is suitable for current handler.
|
|
1239
|
-
* */
|
|
1240
|
-
var RequestBodyTargets = {
|
|
1241
|
-
json: "JSON request body",
|
|
1242
|
-
form: "URL-encoded or Multipart form",
|
|
1243
|
-
raw: "Raw body format (string/Buffer/ArrayBuffer/Blob)"
|
|
1244
|
-
};
|
|
1245
|
-
({
|
|
1246
|
-
...RequestMetadataTargets,
|
|
1247
|
-
...RequestBodyTargets
|
|
1248
|
-
});
|
|
1249
|
-
var generateTsconfig = (sourceFolder) => {
|
|
1250
|
-
const rootDir = "${configDir}";
|
|
1251
|
-
const compilerOptions = {
|
|
1252
|
-
types: ["@types/node", "vite/client"],
|
|
1253
|
-
moduleResolution: "bundler",
|
|
1254
|
-
module: "ESNext",
|
|
1255
|
-
target: "ESNext",
|
|
1256
|
-
strict: true,
|
|
1257
|
-
exactOptionalPropertyTypes: true,
|
|
1258
|
-
noImplicitAny: true,
|
|
1259
|
-
noImplicitThis: true,
|
|
1260
|
-
noImplicitOverride: true,
|
|
1261
|
-
noImplicitReturns: true,
|
|
1262
|
-
noUnusedLocals: false,
|
|
1263
|
-
noUnusedParameters: false,
|
|
1264
|
-
allowArbitraryExtensions: true,
|
|
1265
|
-
allowImportingTsExtensions: true,
|
|
1266
|
-
allowUnreachableCode: false,
|
|
1267
|
-
allowUnusedLabels: false,
|
|
1268
|
-
useUnknownInCatchVariables: true,
|
|
1269
|
-
noFallthroughCasesInSwitch: true,
|
|
1270
|
-
noUncheckedSideEffectImports: true,
|
|
1271
|
-
resolveJsonModule: true,
|
|
1272
|
-
esModuleInterop: true,
|
|
1273
|
-
verbatimModuleSyntax: true,
|
|
1274
|
-
skipLibCheck: true,
|
|
1275
|
-
noEmit: true
|
|
1276
|
-
};
|
|
1277
|
-
if (sourceFolder) return {
|
|
1278
|
-
include: [
|
|
1279
|
-
`${rootDir}/`,
|
|
1280
|
-
`${rootDir}/../../${defaults.libDir}/${sourceFolder}/`,
|
|
1281
|
-
`${rootDir}/../../**/*.d.ts`
|
|
1282
|
-
],
|
|
1283
|
-
compilerOptions: {
|
|
1284
|
-
...compilerOptions,
|
|
1285
|
-
types: [...compilerOptions.types],
|
|
1286
|
-
paths: {
|
|
1287
|
-
[`${defaults.appPrefix}/*`]: [`${rootDir}/../../*`],
|
|
1288
|
-
[`${defaults.srcPrefix}/*`]: [`${rootDir}/*`],
|
|
1289
|
-
[`${defaults.libPrefix}/*`]: [`${rootDir}/../../${defaults.libDir}/${sourceFolder}/*`]
|
|
1290
|
-
},
|
|
1291
|
-
jsx: "preserve"
|
|
1292
|
-
}
|
|
1293
|
-
};
|
|
1294
|
-
return {
|
|
1295
|
-
include: [`${rootDir}/`],
|
|
1296
|
-
exclude: [`${rootDir}/${defaults.srcDir}/`],
|
|
1297
|
-
compilerOptions: {
|
|
1298
|
-
...compilerOptions,
|
|
1299
|
-
paths: { [`${defaults.appPrefix}/*`]: [`${rootDir}/*`] }
|
|
1300
|
-
}
|
|
1301
|
-
};
|
|
1302
|
-
};
|
|
1303
|
-
var factory = defineGeneratorFactory((meta, sourceFolder) => {
|
|
1304
|
-
const { createPath, createImportHelpers } = pathResolver(sourceFolder);
|
|
1305
|
-
const start = async () => {
|
|
1306
|
-
await renderToFile(createPath.lib("../tsconfig.base.json"), JSON.stringify(generateTsconfig(), void 0, 2), {});
|
|
1307
|
-
{
|
|
1308
|
-
const tsconfig = generateTsconfig(sourceFolder.name);
|
|
1309
|
-
const compilerOptions = {};
|
|
1310
|
-
const types = new Set(tsconfig.compilerOptions.types || []);
|
|
1311
|
-
for (const { meta } of sourceFolder.config.generators || []) {
|
|
1312
|
-
if (meta.jsxImportSource) compilerOptions.jsxImportSource = meta.jsxImportSource;
|
|
1313
|
-
for (const type of meta.types || []) types.add(type);
|
|
1314
|
-
}
|
|
1315
|
-
await renderToFile(createPath.lib("tsconfig.base.json"), JSON.stringify({
|
|
1316
|
-
...tsconfig,
|
|
1317
|
-
compilerOptions: {
|
|
1318
|
-
...tsconfig.compilerOptions,
|
|
1319
|
-
...compilerOptions,
|
|
1320
|
-
types: [...types.values()]
|
|
1321
|
-
}
|
|
1322
|
-
}, void 0, 2), {});
|
|
1323
|
-
}
|
|
1324
|
-
/**
|
|
1325
|
-
* expose VRefine as a global type.
|
|
1326
|
-
* not supposed to be overriden by generators.
|
|
1327
|
-
* */
|
|
1328
|
-
await renderToFile(createPath.lib("../env.d.ts"), env_d_default, {});
|
|
1329
|
-
/**
|
|
1330
|
-
* deploy a default gitignore file that ignore everything,
|
|
1331
|
-
* except cache.json files; if file exists, do not override.
|
|
1332
|
-
* */
|
|
1333
|
-
await renderToFile(createPath.lib("../.gitignore"), gitignore_default, {}, { overwrite: false });
|
|
1334
|
-
/**
|
|
1335
|
-
* deploy a stub SSG file.
|
|
1336
|
-
* generators that support SSG will override it as needed.
|
|
1337
|
-
* then SSG generator will import it and generate static files for exported routes.
|
|
1338
|
-
* */
|
|
1339
|
-
await renderToFile(createPath.lib("ssg.ts"), "export default [];", {});
|
|
1340
|
-
};
|
|
1341
|
-
const generateLibFiles = async (entries) => {
|
|
1342
|
-
const { renderToFile } = renderFactory({
|
|
1343
|
-
helpers: {
|
|
1344
|
-
...createImportHelpers({ origin: "lib" }),
|
|
1345
|
-
...routeRenderHelpers()
|
|
1346
|
-
},
|
|
1347
|
-
partials: { pathMapper: pathMapper_default }
|
|
1348
|
-
});
|
|
1349
|
-
await renderToFile(createPath.libCore("routeMap.ts"), routeMap_default, {
|
|
1350
|
-
apiRoutes: entries.flatMap(({ kind, entry }) => {
|
|
1351
|
-
return kind === "apiRoute" ? [entry] : [];
|
|
1352
|
-
}),
|
|
1353
|
-
pageRoutes: entries.flatMap(({ kind, entry }) => {
|
|
1354
|
-
return kind === "pageRoute" ? [entry] : [];
|
|
1355
|
-
})
|
|
1356
|
-
});
|
|
1357
|
-
for (const [file, template] of [["config.ts", config_default], ["index.ts", core_default]]) await renderToFile(createPath.libCore(file), template, sourceFolder);
|
|
1358
|
-
for (const { kind, entry } of entries) if (kind === "apiRoute") await renderToFile(createPath.libApi(dirname(entry.file), "schemas.ts"), schemas_default, { route: entry }, { overwrite: false });
|
|
1359
|
-
};
|
|
1360
|
-
return {
|
|
1361
|
-
meta,
|
|
1362
|
-
options: void 0,
|
|
1363
|
-
start,
|
|
1364
|
-
watch: generateLibFiles,
|
|
1365
|
-
build: generateLibFiles
|
|
1366
|
-
};
|
|
1367
|
-
});
|
|
1368
|
-
/**
|
|
1369
|
-
* Generates stub files required by various generators.
|
|
1370
|
-
* Ensures cross-generator dependencies remain resolvable
|
|
1371
|
-
* even if specialized generators supposed to generate these files are not installed.
|
|
1372
|
-
* */
|
|
1373
|
-
var src_default = defineGenerator(() => {
|
|
1374
|
-
const meta = {
|
|
1375
|
-
name: "Core",
|
|
1376
|
-
dependencies: { "path-to-regexp": package_default$1.devDependencies["path-to-regexp"] }
|
|
1377
|
-
};
|
|
1378
|
-
return {
|
|
1379
|
-
meta,
|
|
1380
|
-
options: void 0,
|
|
1381
|
-
factory: (sourceFolder) => factory(meta, sourceFolder)
|
|
1382
|
-
};
|
|
1383
|
-
});
|
|
5
|
+
import { styleText } from "node:util";
|
|
6
|
+
import { build, createServer } from "vite";
|
|
7
|
+
import { pathExists, pathResolver, routesFactory, spinnerFactory } from "@kosmojs/lib";
|
|
8
|
+
import coreGenerator from "@kosmojs/core-generator";
|
|
9
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
10
|
+
import crc from "crc/crc32";
|
|
1384
11
|
var package_default = {
|
|
1385
12
|
type: "module",
|
|
1386
13
|
name: "@kosmojs/dev",
|
|
1387
|
-
version: "0.1.
|
|
14
|
+
version: "0.1.5",
|
|
1388
15
|
cacheVersion: "001",
|
|
1389
16
|
author: "Slee Woo",
|
|
1390
17
|
license: "MIT",
|
|
@@ -1401,8 +28,7 @@ var package_default = {
|
|
|
1401
28
|
"./package.json": "./package.json"
|
|
1402
29
|
},
|
|
1403
30
|
scripts: { "build": "wsbuild src/index.ts src/chassis.ts" },
|
|
1404
|
-
dependencies: {
|
|
1405
|
-
devDependencies: {
|
|
31
|
+
dependencies: {
|
|
1406
32
|
"@kosmojs/core": "workspace:^",
|
|
1407
33
|
"@kosmojs/core-generator": "workspace:^",
|
|
1408
34
|
"@kosmojs/fetch-generator": "workspace:^",
|
|
@@ -1416,7 +42,9 @@ var package_default = {
|
|
|
1416
42
|
"@kosmojs/ssg-generator": "workspace:^",
|
|
1417
43
|
"@kosmojs/ssr-generator": "workspace:^",
|
|
1418
44
|
"@kosmojs/typebox-generator": "workspace:^",
|
|
1419
|
-
"@kosmojs/vue-generator": "workspace:^"
|
|
45
|
+
"@kosmojs/vue-generator": "workspace:^",
|
|
46
|
+
"crc": "^4.3.2",
|
|
47
|
+
"vite": "^8.0.10"
|
|
1420
48
|
}
|
|
1421
49
|
};
|
|
1422
50
|
//#endregion
|
|
@@ -1427,7 +55,7 @@ var package_default = {
|
|
|
1427
55
|
* import resolves to the actual published package.json.
|
|
1428
56
|
* */
|
|
1429
57
|
var cacheFactory = (route, sourceFolder, extraContext) => {
|
|
1430
|
-
const cacheFile = pathResolver
|
|
58
|
+
const cacheFile = pathResolver(sourceFolder).createPath.libApi(dirname(route.file), "cache.json");
|
|
1431
59
|
const validateCache = async (cache) => {
|
|
1432
60
|
if (!cache?.hash) return;
|
|
1433
61
|
if (!cache.typeDeclarations || !cache.referencedFiles) return;
|
|
@@ -1438,7 +66,7 @@ var cacheFactory = (route, sourceFolder, extraContext) => {
|
|
|
1438
66
|
};
|
|
1439
67
|
return {
|
|
1440
68
|
async get(opt) {
|
|
1441
|
-
if (await pathExists
|
|
69
|
+
if (await pathExists(cacheFile)) try {
|
|
1442
70
|
const cache = JSON.parse(await readFile(cacheFile, "utf8"));
|
|
1443
71
|
return opt?.validate ? validateCache(cache) : cache;
|
|
1444
72
|
} catch (_e) {}
|
|
@@ -1491,7 +119,7 @@ var chassis_default = async (projectSettings) => {
|
|
|
1491
119
|
if (command === "build") {
|
|
1492
120
|
for (const sourceFolder of projectSettings.sourceFolders) {
|
|
1493
121
|
const { config } = sourceFolder;
|
|
1494
|
-
const { createPath } = pathResolver
|
|
122
|
+
const { createPath } = pathResolver(sourceFolder);
|
|
1495
123
|
const resolvedRoutes = [];
|
|
1496
124
|
{
|
|
1497
125
|
const { resolvers } = await routesFactory(sourceFolder, cacheFactory);
|
|
@@ -1532,12 +160,9 @@ var chassis_default = async (projectSettings) => {
|
|
|
1532
160
|
const apiGenerator = generators.find((e) => e.meta.slot === "api");
|
|
1533
161
|
if (apiGenerator) {
|
|
1534
162
|
const dir = createPath.distDir("api");
|
|
1535
|
-
const
|
|
1536
|
-
return
|
|
1537
|
-
|
|
1538
|
-
...meta.devDependencies
|
|
1539
|
-
});
|
|
1540
|
-
});
|
|
163
|
+
const externalizeOptions = apiGenerator.options ? Object.entries(apiGenerator.options).flatMap(([k, v]) => {
|
|
164
|
+
return k === "external" || k === "noExternal" ? [[k, v]] : [];
|
|
165
|
+
}) : [];
|
|
1541
166
|
await build({
|
|
1542
167
|
configFile: false,
|
|
1543
168
|
root: createPath.src(),
|
|
@@ -1547,7 +172,7 @@ var chassis_default = async (projectSettings) => {
|
|
|
1547
172
|
...config.define,
|
|
1548
173
|
KOSMO_PRODUCTION_BUILD: "true"
|
|
1549
174
|
},
|
|
1550
|
-
ssr: {
|
|
175
|
+
ssr: externalizeOptions.length ? Object.fromEntries(externalizeOptions) : { external: true },
|
|
1551
176
|
resolve: {
|
|
1552
177
|
...config.resolve,
|
|
1553
178
|
tsconfigPaths: true,
|
|
@@ -1580,7 +205,7 @@ var chassis_default = async (projectSettings) => {
|
|
|
1580
205
|
let port = await findFreePort(devPort);
|
|
1581
206
|
for (const sourceFolder of projectSettings.sourceFolders) {
|
|
1582
207
|
const { config } = sourceFolder;
|
|
1583
|
-
const { createPath } = pathResolver
|
|
208
|
+
const { createPath } = pathResolver(sourceFolder);
|
|
1584
209
|
const requestMatchers = matchersFactory(sourceFolder);
|
|
1585
210
|
const generators = folderGenerators(sourceFolder);
|
|
1586
211
|
const plugins = [...config.plugins || []];
|
|
@@ -1615,7 +240,7 @@ var chassis_default = async (projectSettings) => {
|
|
|
1615
240
|
for (const sourceFolder of projectSettings.sourceFolders) {
|
|
1616
241
|
const { config } = sourceFolder;
|
|
1617
242
|
if (!folderGenerators(sourceFolder).find((e) => e.meta.slot === "api")) continue;
|
|
1618
|
-
const { createPath } = pathResolver
|
|
243
|
+
const { createPath } = pathResolver(sourceFolder);
|
|
1619
244
|
const requestMatchers = matchersFactory(sourceFolder);
|
|
1620
245
|
const viteServer = await createServer({
|
|
1621
246
|
configFile: false,
|
|
@@ -1637,7 +262,7 @@ var chassis_default = async (projectSettings) => {
|
|
|
1637
262
|
const env = viteServer.environments.api;
|
|
1638
263
|
const loadDevSetup = async () => {
|
|
1639
264
|
env.runner.clearCache();
|
|
1640
|
-
return env.runner.import(join(defaults
|
|
265
|
+
return env.runner.import(join(defaults.apiDir, "dev.ts")).then((e) => e.default);
|
|
1641
266
|
};
|
|
1642
267
|
let devSetup = await loadDevSetup();
|
|
1643
268
|
for (const [evt, handler] of Object.entries(eventMap[sourceFolder.name])) viteServer.watcher.on(evt, async (file) => {
|
|
@@ -1713,7 +338,7 @@ var folderGenerators = (sourceFolder) => {
|
|
|
1713
338
|
for (const base of generators) if (base.meta.slot) coreGenerators[base.meta.slot] = base;
|
|
1714
339
|
else userGenerators.push(base);
|
|
1715
340
|
return [
|
|
1716
|
-
|
|
341
|
+
coreGenerator(),
|
|
1717
342
|
...coreGenerators.api ? [coreGenerators.api] : [],
|
|
1718
343
|
...coreGenerators.fetch && coreGenerators.api ? [coreGenerators.fetch] : [],
|
|
1719
344
|
...userGenerators,
|
|
@@ -1723,7 +348,7 @@ var folderGenerators = (sourceFolder) => {
|
|
|
1723
348
|
};
|
|
1724
349
|
var eventFactory = async (sourceFolder) => {
|
|
1725
350
|
const { resolvers, resolversFactory } = await routesFactory(sourceFolder, cacheFactory);
|
|
1726
|
-
const { createPath } = pathResolver
|
|
351
|
+
const { createPath } = pathResolver(sourceFolder);
|
|
1727
352
|
const generators = [];
|
|
1728
353
|
for (const base of folderGenerators(sourceFolder)) {
|
|
1729
354
|
const factory = base.factory(sourceFolder);
|