@kosmojs/dev 0.0.20 → 0.0.22
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/LICENSE +21 -0
- package/package.json +11 -10
- package/pkg/{src/ast.d.ts → ast.d.ts} +11 -16
- package/pkg/{src/base-plugin → base-plugin}/api-handler.d.ts +1 -1
- package/pkg/{src/base-plugin → base-plugin}/worker.d.ts +1 -2
- package/pkg/base-plugin/worker.js +489 -221
- package/pkg/base-plugin/worker.js.map +4 -4
- package/pkg/{src/cache.d.ts → cache.d.ts} +1 -1
- package/pkg/index.js +640 -296
- package/pkg/index.js.map +4 -4
- package/pkg/{src/paths.d.ts → paths.d.ts} +2 -2
- package/pkg/{src/render.d.ts → render.d.ts} +4 -4
- package/pkg/routes-factory/base.d.ts +47 -0
- package/pkg/{src/routes-factory → routes-factory}/index.d.ts +1 -0
- package/pkg/stub-generator/index.js +1 -12
- package/pkg/stub-generator/index.js.map +2 -2
- package/pkg/{src/types.d.ts → types.d.ts} +55 -38
- package/pkg/src/routes-factory/base.d.ts +0 -17
- package/pkg/test/@fixtures/app/lib/@src/{api}/articles/[...path]/index.ts/types.d.ts +0 -3
- package/pkg/test/@fixtures/app/lib/@src/{api}/articles/[...path]/types.d.ts +0 -3
- package/pkg/test/@fixtures/app/lib/@src/{api}/books/[category]/[[author]]/index.ts/types.d.ts +0 -4
- package/pkg/test/@fixtures/app/lib/@src/{api}/books/[category]/[[author]]/types.d.ts +0 -4
- package/pkg/test/@fixtures/app/lib/@src/{api}/books/[category]/index.ts/types.d.ts +0 -3
- package/pkg/test/@fixtures/app/lib/@src/{api}/books/[category]/types.d.ts +0 -3
- package/pkg/test/@fixtures/app/lib/@src/{api}/books/index.ts/types.d.ts +0 -1
- package/pkg/test/@fixtures/app/lib/@src/{api}/books/types.d.ts +0 -1
- package/pkg/test/@fixtures/app/lib/@src/{api}/files/[[folder]]/[[id]].json/index.ts/types.d.ts +0 -4
- package/pkg/test/@fixtures/app/lib/@src/{api}/files/[[folder]]/[[id]].json/types.d.ts +0 -4
- package/pkg/test/@fixtures/app/lib/@src/{api}/files/[[folder]]/index.ts/types.d.ts +0 -3
- package/pkg/test/@fixtures/app/lib/@src/{api}/files/[[folder]]/types.d.ts +0 -3
- package/pkg/test/@fixtures/app/lib/@src/{api}/index/index.ts/types.d.ts +0 -1
- package/pkg/test/@fixtures/app/lib/@src/{api}/index/types.d.ts +0 -1
- package/pkg/test/@fixtures/app/lib/@src/{api}/pages/[...path].html/index.ts/types.d.ts +0 -3
- package/pkg/test/@fixtures/app/lib/@src/{api}/pages/[...path].html/types.d.ts +0 -3
- package/pkg/test/@fixtures/app/lib/@src/{api}/users/[id].json/index.ts/types.d.ts +0 -3
- package/pkg/test/@fixtures/app/lib/@src/{api}/users/[id].json/types.d.ts +0 -3
- package/pkg/test/@fixtures/app/src/test/api/articles/[...path]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/api/books/[category]/[[author]]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/api/books/[category]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/api/books/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/api/files/[[folder]]/[[id]].json/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/api/files/[[folder]]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/api/index/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/api/pages/[...path].html/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/api/users/[id].json/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/about/careers/[jobId]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/about/careers/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/about/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/about/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/about/team/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/account/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/account/profile/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/resources/[[type]]/[...path]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/resources/[[type]]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/resources/[[type]]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/resources/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/resources/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/settings/general/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/settings/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/settings/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/settings/permissions/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/users/[userId]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/users/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/users/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/admin/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/admin/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/blog/[[category]]/[[tag]]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/blog/[[category]]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/blog/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/blog/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/blog/post/[slug]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/blog/post/[slug]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/contact/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/contact/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/courses/[courseId]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/courses/[courseId]/lessons/[[lessonId]]/assignments/[...assignmentPath]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/dashboard/[view]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/dashboard/analytics/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/dashboard/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/dashboard/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/dashboard/settings/billing/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/dashboard/settings/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/dashboard/settings/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/dashboard/settings/notifications/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/dashboard/settings/profile/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/dashboard/settings/security/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/dashboard/settings/security/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/docs/[...path]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/docs/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/docs/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/files/[...filePath]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/files/[...filePath]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/legal/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/legal/privacy/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/legal/terms/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/news/[category]/articles/[...articlePath]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/news/[category]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/portal/[clientId]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/portal/[clientId]/reports/[reportType]/data/[dataView]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/portal/[clientId]/reports/[reportType]/data/[dataView]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/portal/[clientId]/reports/[reportType]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/portal/[clientId]/reports/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/portal/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/products/[id]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/products/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/profile/[username]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/profile/[username]/posts/[postId]/comments/[...thread]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/profile/[username]/posts/[postId]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/files/[...path]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/files/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/files/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/tasks/[taskId]/comments/[commentId]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/tasks/[taskId]/comments/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/tasks/[taskId]/comments/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/tasks/[taskId]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/tasks/[taskId]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/tasks/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/tasks/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/team/[userId]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/team/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/team/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/projects/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/properties/[[city]]/filters/[...filters]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/properties/filters/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/properties/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/search/[[query]]/[[page]]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/search/[[query]]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/search/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/[category]/[productId]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/[category]/[productId]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/cart/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/checkout/confirm/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/checkout/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/checkout/payment/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/checkout/shipping/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/checkout/shipping/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/orders/[orderId]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/orders/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/orders/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/product/[id]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/product/[id]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/product/[id]/reviews/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/products/[[category]]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/products/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/shop/products/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/signup/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/store/[category]/filters/[...filters]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/store/[category]/sort/[sortBy]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/store/[category]/sort/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/store/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/users/[username]/followers/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/users/[username]/following/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/users/[username]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/users/[username]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/users/[username]/posts/[postId]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/users/[username]/posts/[postId]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/users/[username]/posts/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/users/[username]/posts/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/users/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/users/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/workspace/[workspaceId]/analytics/[range]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/workspace/[workspaceId]/analytics/[range]/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/workspace/[workspaceId]/analytics/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/workspace/[workspaceId]/analytics/layout.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/workspace/[workspaceId]/team/[memberId]/permissions/[...permissionPath]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/src/test/pages/workspace/[workspaceId]/team/layout.d.ts +0 -0
- package/pkg/test/@fixtures/ast/extractTypeDeclarations/exports/with-referenced-files.d.ts +0 -1
- package/pkg/test/@fixtures/ast/extractTypeDeclarations/imports/with-referenced-files.d.ts +0 -1
- package/pkg/test/ast/extractParamsRefinements.test.d.ts +0 -1
- package/pkg/test/ast/extractRouteMethods.test.d.ts +0 -1
- package/pkg/test/ast/extractTypeDeclarations.test.d.ts +0 -1
- package/pkg/test/routes/index.d.ts +0 -4
- package/pkg/test/routes/nesting.test.d.ts +0 -1
- package/pkg/test/routes/resolver.test.d.ts +0 -1
- package/pkg/test/routes/routes.test.d.ts +0 -1
- /package/pkg/{src/alias-plugin → alias-plugin}/index.d.ts +0 -0
- /package/pkg/{src/base-plugin → base-plugin}/index.d.ts +0 -0
- /package/pkg/{src/base-plugin → base-plugin}/spinner.d.ts +0 -0
- /package/pkg/{src/defaults.d.ts → defaults.d.ts} +0 -0
- /package/pkg/{src/define-plugin → define-plugin}/index.d.ts +0 -0
- /package/pkg/{src/fs.d.ts → fs.d.ts} +0 -0
- /package/pkg/{src/index.d.ts → index.d.ts} +0 -0
- /package/pkg/{src/routes-factory → routes-factory}/nesting.d.ts +0 -0
- /package/pkg/{src/routes-factory → routes-factory}/resolve.d.ts +0 -0
- /package/pkg/{src/stub-generator → stub-generator}/index.d.ts +0 -0
- /package/pkg/{src/typebox.d.ts → typebox.d.ts} +0 -0
package/pkg/index.js
CHANGED
|
@@ -60,9 +60,6 @@ var pathResolver = ({
|
|
|
60
60
|
},
|
|
61
61
|
libEntry(...a) {
|
|
62
62
|
return this.lib(defaults.entryDir, ...a);
|
|
63
|
-
},
|
|
64
|
-
fetch(...a) {
|
|
65
|
-
return this.lib(defaults.fetchDir, ...a);
|
|
66
63
|
}
|
|
67
64
|
};
|
|
68
65
|
return {
|
|
@@ -96,9 +93,6 @@ var pathResolver = ({
|
|
|
96
93
|
},
|
|
97
94
|
libPages(...a) {
|
|
98
95
|
return this.lib(defaults.pagesDir, ...a);
|
|
99
|
-
},
|
|
100
|
-
fetch(...a) {
|
|
101
|
-
return this.lib(defaults.fetchDir, ...a);
|
|
102
96
|
}
|
|
103
97
|
},
|
|
104
98
|
createImport,
|
|
@@ -175,98 +169,33 @@ var alias_plugin_default = (appRoot, opt) => {
|
|
|
175
169
|
};
|
|
176
170
|
|
|
177
171
|
// src/base-plugin/index.ts
|
|
172
|
+
import { writeFile as writeFile3 } from "node:fs/promises";
|
|
178
173
|
import { basename as basename2, join as join5, resolve as resolve5 } from "node:path";
|
|
179
|
-
import { styleText as
|
|
174
|
+
import { styleText as styleText4 } from "node:util";
|
|
180
175
|
import { Worker } from "node:worker_threads";
|
|
181
176
|
import stubGenerator from "@kosmojs/dev/stub-generator";
|
|
182
177
|
|
|
183
178
|
// src/routes-factory/resolve.ts
|
|
184
179
|
import { dirname as dirname3, join as join3, resolve as resolve3 } from "node:path";
|
|
180
|
+
import { styleText as styleText2 } from "node:util";
|
|
185
181
|
import crc5 from "crc/crc32";
|
|
182
|
+
import mimeTypes from "mime-types";
|
|
186
183
|
import picomatch from "picomatch";
|
|
187
184
|
import { glob as glob2 } from "tinyglobby";
|
|
188
185
|
|
|
189
|
-
// src/render.ts
|
|
190
|
-
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
191
|
-
import { dirname, join as join2 } from "node:path";
|
|
192
|
-
import crc from "crc/crc32";
|
|
193
|
-
import handlebars from "handlebars";
|
|
194
|
-
|
|
195
|
-
// src/fs.ts
|
|
196
|
-
import { access, constants } from "node:fs/promises";
|
|
197
|
-
var pathExists = async (path) => {
|
|
198
|
-
try {
|
|
199
|
-
await access(path, constants.F_OK);
|
|
200
|
-
return true;
|
|
201
|
-
} catch {
|
|
202
|
-
return false;
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
// src/render.ts
|
|
207
|
-
var render = (template, context2, options) => {
|
|
208
|
-
const { noEscape = true, renderer = handlebars } = { ...options };
|
|
209
|
-
return renderer.compile(template, { noEscape })(context2);
|
|
210
|
-
};
|
|
211
|
-
var renderAsFile = (file, template, context2, options) => {
|
|
212
|
-
const { formatters, ...renderOpts } = { ...options };
|
|
213
|
-
const content = render(template, context2, renderOpts);
|
|
214
|
-
return Array.isArray(formatters) ? formatters.reduce((c, f) => f(c, file), content) : content;
|
|
215
|
-
};
|
|
216
|
-
var renderToFile = async (file, template, context2, options) => {
|
|
217
|
-
const content = renderAsFile(file, template, context2, options);
|
|
218
|
-
if (await pathExists(file)) {
|
|
219
|
-
const { overwrite = true } = { ...options };
|
|
220
|
-
if (overwrite === false) {
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
const fileContent = await readFile(file, "utf8");
|
|
224
|
-
if (typeof overwrite === "function" && !overwrite(fileContent)) {
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
if (crc(content) === crc(fileContent)) {
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
await mkdir(dirname(file), { recursive: true });
|
|
232
|
-
await writeFile(file, content, "utf8");
|
|
233
|
-
};
|
|
234
|
-
var renderFactory = (options) => {
|
|
235
|
-
const renderer = handlebars.create();
|
|
236
|
-
if (options?.partials) {
|
|
237
|
-
renderer.registerPartial(options.partials);
|
|
238
|
-
}
|
|
239
|
-
if (options?.helpers) {
|
|
240
|
-
renderer.registerHelper(options.helpers);
|
|
241
|
-
}
|
|
242
|
-
return {
|
|
243
|
-
render(template, context2, selfOoptions) {
|
|
244
|
-
return render(template, context2, {
|
|
245
|
-
renderer,
|
|
246
|
-
...options,
|
|
247
|
-
...selfOoptions
|
|
248
|
-
});
|
|
249
|
-
},
|
|
250
|
-
async renderToFile(file, template, context2, selfOoptions) {
|
|
251
|
-
return renderToFile(
|
|
252
|
-
options?.outdir ? join2(options.outdir, file) : file,
|
|
253
|
-
template,
|
|
254
|
-
context2,
|
|
255
|
-
{ renderer, ...options, ...selfOoptions }
|
|
256
|
-
);
|
|
257
|
-
}
|
|
258
|
-
};
|
|
259
|
-
};
|
|
260
|
-
|
|
261
186
|
// src/ast.ts
|
|
262
187
|
import { resolve } from "node:path";
|
|
263
|
-
import
|
|
188
|
+
import { styleText } from "node:util";
|
|
189
|
+
import crc from "crc/crc32";
|
|
264
190
|
import { flattener } from "tfusion";
|
|
265
191
|
import {
|
|
266
192
|
Project,
|
|
267
193
|
SyntaxKind
|
|
268
194
|
} from "ts-morph";
|
|
269
|
-
import {
|
|
195
|
+
import {
|
|
196
|
+
HTTPMethods,
|
|
197
|
+
RequestValidationTargets
|
|
198
|
+
} from "@kosmojs/api";
|
|
270
199
|
var createProject = (opts) => new Project(opts);
|
|
271
200
|
var resolveRouteSignature = async (route, opts) => {
|
|
272
201
|
const {
|
|
@@ -278,19 +207,12 @@ var resolveRouteSignature = async (route, opts) => {
|
|
|
278
207
|
);
|
|
279
208
|
const defaultExport = extractDefaultExport(sourceFile);
|
|
280
209
|
const paramsRefinements = defaultExport ? extractParamsRefinements(defaultExport) : void 0;
|
|
281
|
-
const methods = defaultExport ? extractRouteMethods(
|
|
282
|
-
const payloadTypes = methods.flatMap((e) => {
|
|
283
|
-
return e.payloadType ? [e.payloadType] : [];
|
|
284
|
-
});
|
|
285
|
-
const responseTypes = methods.flatMap((e) => {
|
|
286
|
-
return e.responseType ? [e.responseType] : [];
|
|
287
|
-
});
|
|
210
|
+
const methods = defaultExport ? extractRouteMethods(route, defaultExport) : [];
|
|
288
211
|
return {
|
|
289
212
|
typeDeclarations,
|
|
290
213
|
paramsRefinements,
|
|
291
214
|
methods: methods.map((e) => e.method),
|
|
292
|
-
|
|
293
|
-
responseTypes,
|
|
215
|
+
validationDefinitions: methods.flatMap((e) => e.validationDefinitions),
|
|
294
216
|
referencedFiles
|
|
295
217
|
};
|
|
296
218
|
};
|
|
@@ -305,22 +227,23 @@ var extractDefaultExport = (sourceFile) => {
|
|
|
305
227
|
return defaultExport;
|
|
306
228
|
};
|
|
307
229
|
var extractParamsRefinements = (callExpression) => {
|
|
308
|
-
const [
|
|
309
|
-
|
|
230
|
+
const [
|
|
231
|
+
_routeName,
|
|
232
|
+
// first generic - the route name
|
|
233
|
+
paramsGeneric
|
|
234
|
+
// second generic - params refinements
|
|
235
|
+
] = extractGenerics(callExpression);
|
|
236
|
+
if (!paramsGeneric?.isKind(SyntaxKind.TupleType)) {
|
|
310
237
|
return;
|
|
311
238
|
}
|
|
312
|
-
|
|
313
|
-
if (!tupleElements?.length) {
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
316
|
-
return tupleElements.map((node, index) => {
|
|
239
|
+
return paramsGeneric.getElements().map((node, index) => {
|
|
317
240
|
return {
|
|
318
241
|
index,
|
|
319
242
|
text: node.getText()
|
|
320
243
|
};
|
|
321
244
|
});
|
|
322
245
|
};
|
|
323
|
-
var extractRouteMethods = (
|
|
246
|
+
var extractRouteMethods = (route, callExpression) => {
|
|
324
247
|
const funcDeclaration = callExpression.getFirstChildByKind(SyntaxKind.ArrowFunction) || callExpression.getFirstChildByKind(SyntaxKind.FunctionExpression);
|
|
325
248
|
if (!funcDeclaration) {
|
|
326
249
|
return [];
|
|
@@ -341,35 +264,173 @@ var extractRouteMethods = (callExpression, route) => {
|
|
|
341
264
|
}
|
|
342
265
|
}
|
|
343
266
|
const methods = [];
|
|
344
|
-
const skipValidationFilter = (e) => /@skip-validation/.test(e);
|
|
345
267
|
for (const [callExpression2, method] of callExpressions) {
|
|
346
|
-
const [
|
|
347
|
-
const payloadText = payloadGeneric?.node ? payloadGeneric.node.getChildren().length === 0 ? "{}" : payloadGeneric.node.getFullText() : void 0;
|
|
348
|
-
const responseText = responseGeneric?.node.getText();
|
|
349
|
-
const responseType = responseText ? {
|
|
350
|
-
id: ["ResponseT", crc2(route.id + method)].join(""),
|
|
351
|
-
method,
|
|
352
|
-
skipValidation: responseGeneric?.comments ? responseGeneric.comments.some(skipValidationFilter) : false,
|
|
353
|
-
text: ["never", "object"].includes(responseText) ? "{}" : responseText,
|
|
354
|
-
resolvedType: void 0
|
|
355
|
-
} : void 0;
|
|
356
|
-
const payloadType = payloadText ? {
|
|
357
|
-
id: ["PayloadT", crc2(route.id + method)].join(""),
|
|
358
|
-
responseTypeId: responseType?.id,
|
|
359
|
-
method,
|
|
360
|
-
skipValidation: payloadGeneric?.comments ? payloadGeneric.comments.some(skipValidationFilter) : false,
|
|
361
|
-
isOptional: payloadText ? payloadText === "{}" || route.optionalParams : true,
|
|
362
|
-
text: payloadText,
|
|
363
|
-
resolvedType: void 0
|
|
364
|
-
} : void 0;
|
|
268
|
+
const [vDefs, vOpts] = extractGenerics(callExpression2);
|
|
365
269
|
methods.push({
|
|
366
270
|
method,
|
|
367
|
-
|
|
368
|
-
|
|
271
|
+
validationDefinitions: extractValidationDefinitions(
|
|
272
|
+
route,
|
|
273
|
+
method,
|
|
274
|
+
vDefs,
|
|
275
|
+
vOpts
|
|
276
|
+
)
|
|
369
277
|
});
|
|
370
278
|
}
|
|
371
279
|
return methods;
|
|
372
280
|
};
|
|
281
|
+
var parseRuntimeValidation = (typeNode) => {
|
|
282
|
+
if (typeNode.isKind(SyntaxKind.LiteralType)) {
|
|
283
|
+
const literal = typeNode.getFirstChild();
|
|
284
|
+
if (literal?.isKind(SyntaxKind.TrueKeyword)) {
|
|
285
|
+
return true;
|
|
286
|
+
} else if (literal?.isKind(SyntaxKind.FalseKeyword)) {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return void 0;
|
|
291
|
+
};
|
|
292
|
+
var extractResponseVariant = (typeNode) => {
|
|
293
|
+
if (!typeNode.isKind(SyntaxKind.TupleType)) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
let status = 200;
|
|
297
|
+
let contentType;
|
|
298
|
+
let body;
|
|
299
|
+
const [statusNode, contentTypeNode, bodyNode] = typeNode.getElements();
|
|
300
|
+
if (statusNode?.isKind(SyntaxKind.LiteralType)) {
|
|
301
|
+
const literal = statusNode.getFirstChildByKind(SyntaxKind.NumericLiteral);
|
|
302
|
+
if (literal) {
|
|
303
|
+
status = Number(literal.getText());
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
if (contentTypeNode) {
|
|
307
|
+
contentType = extractStringLiteral(contentTypeNode);
|
|
308
|
+
}
|
|
309
|
+
if (bodyNode) {
|
|
310
|
+
body = bodyNode.getText();
|
|
311
|
+
if (["object"].includes(body)) {
|
|
312
|
+
body = "{}";
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return { status, contentType, body };
|
|
316
|
+
};
|
|
317
|
+
var parseValidationOptions = (typeNode) => {
|
|
318
|
+
const opts = {};
|
|
319
|
+
if (!typeNode?.isKind(SyntaxKind.TypeLiteral)) {
|
|
320
|
+
return opts;
|
|
321
|
+
}
|
|
322
|
+
for (const prop of typeNode.getMembers()) {
|
|
323
|
+
if (!prop.isKind(SyntaxKind.PropertySignature)) {
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
const target = prop.getName();
|
|
327
|
+
const typeNode2 = prop.getTypeNodeOrThrow();
|
|
328
|
+
if (!typeNode2.isKind(SyntaxKind.TypeLiteral)) {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
let contentType;
|
|
332
|
+
let runtimeValidation;
|
|
333
|
+
const customErrors = {};
|
|
334
|
+
for (const member of typeNode2.getMembers()) {
|
|
335
|
+
if (!member.isKind(SyntaxKind.PropertySignature)) {
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
const nameNode = member.getNameNode();
|
|
339
|
+
const valueNode = member.getTypeNodeOrThrow();
|
|
340
|
+
const name = nameNode.isKind(SyntaxKind.StringLiteral) ? nameNode.getLiteralText() : nameNode.getText();
|
|
341
|
+
if (name === "contentType") {
|
|
342
|
+
contentType = extractStringLiteral(valueNode);
|
|
343
|
+
} else if (name === "runtimeValidation") {
|
|
344
|
+
runtimeValidation = parseRuntimeValidation(valueNode);
|
|
345
|
+
} else if (name.startsWith("error")) {
|
|
346
|
+
const literal = extractStringLiteral(valueNode);
|
|
347
|
+
if (literal) {
|
|
348
|
+
customErrors[name] = literal;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
opts[target] = {
|
|
353
|
+
contentType,
|
|
354
|
+
runtimeValidation,
|
|
355
|
+
customErrors
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
return opts;
|
|
359
|
+
};
|
|
360
|
+
var extractStringLiteral = (typeNode) => {
|
|
361
|
+
const literal = typeNode.isKind(SyntaxKind.LiteralType) ? typeNode.getFirstChildByKind(SyntaxKind.StringLiteral) : void 0;
|
|
362
|
+
return literal ? literal.getLiteralText() : void 0;
|
|
363
|
+
};
|
|
364
|
+
var extractValidationDefinitions = (route, method, defsNode, optsNode) => {
|
|
365
|
+
const definitions = [];
|
|
366
|
+
if (!defsNode?.isKind(SyntaxKind.TypeLiteral)) {
|
|
367
|
+
return definitions;
|
|
368
|
+
}
|
|
369
|
+
const optsMap = parseValidationOptions(optsNode);
|
|
370
|
+
const createId = (target, hash) => {
|
|
371
|
+
return [
|
|
372
|
+
target.replace(/^./, (c) => c.toUpperCase()),
|
|
373
|
+
"T",
|
|
374
|
+
method,
|
|
375
|
+
crc(route.id + hash)
|
|
376
|
+
].join("");
|
|
377
|
+
};
|
|
378
|
+
for (const prop of defsNode.getMembers()) {
|
|
379
|
+
if (!prop.isKind(SyntaxKind.PropertySignature)) {
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
const target = prop.getName();
|
|
383
|
+
const typeNode = prop.getTypeNodeOrThrow();
|
|
384
|
+
if (target === "response") {
|
|
385
|
+
const variants = typeNode.isKind(SyntaxKind.UnionType) ? typeNode.getChildrenOfKind(SyntaxKind.TupleType) : [typeNode];
|
|
386
|
+
definitions.push({
|
|
387
|
+
...optsMap[target],
|
|
388
|
+
method,
|
|
389
|
+
target,
|
|
390
|
+
variants: variants.flatMap((e, i) => {
|
|
391
|
+
const { status, contentType, body } = extractResponseVariant(e) || {};
|
|
392
|
+
if (!status) {
|
|
393
|
+
return [];
|
|
394
|
+
}
|
|
395
|
+
if (contentType && typeof contentType !== "string") {
|
|
396
|
+
console.warn(
|
|
397
|
+
styleText(
|
|
398
|
+
["bold", "red"],
|
|
399
|
+
`\u2717 The second element of a response variant should specify the Response Content Type`
|
|
400
|
+
)
|
|
401
|
+
);
|
|
402
|
+
console.warn(
|
|
403
|
+
styleText(["blue"], ` Example: [200, "json", Schema]`)
|
|
404
|
+
);
|
|
405
|
+
console.warn(
|
|
406
|
+
` Route: ${route.name}; Method: ${method}; Response Variant: #${i}`
|
|
407
|
+
);
|
|
408
|
+
console.warn();
|
|
409
|
+
}
|
|
410
|
+
return [
|
|
411
|
+
{
|
|
412
|
+
id: createId(target, JSON.stringify([status, contentType, body])),
|
|
413
|
+
status,
|
|
414
|
+
contentType,
|
|
415
|
+
body
|
|
416
|
+
}
|
|
417
|
+
];
|
|
418
|
+
})
|
|
419
|
+
});
|
|
420
|
+
} else if (Object.keys(RequestValidationTargets).includes(target)) {
|
|
421
|
+
definitions.push({
|
|
422
|
+
...optsMap[target],
|
|
423
|
+
method,
|
|
424
|
+
target,
|
|
425
|
+
schema: {
|
|
426
|
+
id: createId(target),
|
|
427
|
+
text: typeNode.getText()
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return definitions;
|
|
433
|
+
};
|
|
373
434
|
var extractTypeDeclarations = (sourceFile, opts) => {
|
|
374
435
|
const declarations = [];
|
|
375
436
|
const referencedFiles = opts?.withReferencedFiles ? [] : void 0;
|
|
@@ -474,12 +535,7 @@ var getReferencedFiles = (importIdentifier) => {
|
|
|
474
535
|
});
|
|
475
536
|
};
|
|
476
537
|
var extractGenerics = (callExpression) => {
|
|
477
|
-
return callExpression.getTypeArguments()
|
|
478
|
-
return {
|
|
479
|
-
node,
|
|
480
|
-
comments: node.getLeadingCommentRanges().map((range) => range.getText().trim())
|
|
481
|
-
};
|
|
482
|
-
});
|
|
538
|
+
return callExpression.getTypeArguments();
|
|
483
539
|
};
|
|
484
540
|
var typeResolverFactory = ({ appRoot }) => {
|
|
485
541
|
const project = createProject({
|
|
@@ -488,7 +544,7 @@ var typeResolverFactory = ({ appRoot }) => {
|
|
|
488
544
|
});
|
|
489
545
|
const literalTypesResolver = (literalTypes, options) => {
|
|
490
546
|
const sourceFile = project.createSourceFile(
|
|
491
|
-
`${
|
|
547
|
+
`${crc(literalTypes)}-${Date.now()}.ts`,
|
|
492
548
|
literalTypes,
|
|
493
549
|
{ overwrite: true }
|
|
494
550
|
);
|
|
@@ -514,10 +570,23 @@ var typeResolverFactory = ({ appRoot }) => {
|
|
|
514
570
|
};
|
|
515
571
|
|
|
516
572
|
// src/cache.ts
|
|
517
|
-
import { mkdir
|
|
518
|
-
import { dirname
|
|
519
|
-
import
|
|
573
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
574
|
+
import { dirname, resolve as resolve2 } from "node:path";
|
|
575
|
+
import crc2 from "crc/crc32";
|
|
520
576
|
import self from "@kosmojs/dev/package.json" with { type: "json" };
|
|
577
|
+
|
|
578
|
+
// src/fs.ts
|
|
579
|
+
import { access, constants } from "node:fs/promises";
|
|
580
|
+
var pathExists = async (path) => {
|
|
581
|
+
try {
|
|
582
|
+
await access(path, constants.F_OK);
|
|
583
|
+
return true;
|
|
584
|
+
} catch {
|
|
585
|
+
return false;
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
// src/cache.ts
|
|
521
590
|
var cacheFactory = (route, {
|
|
522
591
|
appRoot,
|
|
523
592
|
sourceFolder,
|
|
@@ -526,11 +595,11 @@ var cacheFactory = (route, {
|
|
|
526
595
|
const cacheFile = pathResolver({
|
|
527
596
|
appRoot,
|
|
528
597
|
sourceFolder
|
|
529
|
-
}).createPath.libApi(
|
|
598
|
+
}).createPath.libApi(dirname(route.file), "cache.json");
|
|
530
599
|
const getCache = async (opt) => {
|
|
531
600
|
if (await pathExists(cacheFile)) {
|
|
532
601
|
try {
|
|
533
|
-
const cache = JSON.parse(await
|
|
602
|
+
const cache = JSON.parse(await readFile(cacheFile, "utf8"));
|
|
534
603
|
return opt?.validate ? validateCache(cache) : cache;
|
|
535
604
|
} catch (_e) {
|
|
536
605
|
}
|
|
@@ -553,8 +622,8 @@ var cacheFactory = (route, {
|
|
|
553
622
|
] = await generateFileHash(file);
|
|
554
623
|
}
|
|
555
624
|
const cache = { ...rest, hash, referencedFiles };
|
|
556
|
-
await
|
|
557
|
-
await
|
|
625
|
+
await mkdir(dirname(cacheFile), { recursive: true });
|
|
626
|
+
await writeFile(cacheFile, JSON.stringify(cache, null, 2), "utf8");
|
|
558
627
|
return cache;
|
|
559
628
|
};
|
|
560
629
|
const validateCache = async (cache) => {
|
|
@@ -586,11 +655,11 @@ var cacheFactory = (route, {
|
|
|
586
655
|
var generateFileHash = async (file, extraContext) => {
|
|
587
656
|
let fileContent;
|
|
588
657
|
try {
|
|
589
|
-
fileContent = await
|
|
658
|
+
fileContent = await readFile(file, "utf8");
|
|
590
659
|
} catch (_e) {
|
|
591
660
|
return 0;
|
|
592
661
|
}
|
|
593
|
-
return fileContent ?
|
|
662
|
+
return fileContent ? crc2(
|
|
594
663
|
JSON.stringify({
|
|
595
664
|
...extraContext,
|
|
596
665
|
[self.cacheVersion]: fileContent
|
|
@@ -601,75 +670,230 @@ var identicalHashSum = (a, b) => {
|
|
|
601
670
|
return a === b;
|
|
602
671
|
};
|
|
603
672
|
|
|
673
|
+
// src/render.ts
|
|
674
|
+
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
675
|
+
import { dirname as dirname2, join as join2 } from "node:path";
|
|
676
|
+
import crc3 from "crc/crc32";
|
|
677
|
+
import handlebars from "handlebars";
|
|
678
|
+
var render = (template, context2, options) => {
|
|
679
|
+
const { noEscape = true, renderer = handlebars } = { ...options };
|
|
680
|
+
return renderer.compile(template, { noEscape })(context2);
|
|
681
|
+
};
|
|
682
|
+
var renderToFile = async (file, template, context2, options) => {
|
|
683
|
+
const content = render(template, context2, options);
|
|
684
|
+
if (await pathExists(file)) {
|
|
685
|
+
const { overwrite = true } = { ...options };
|
|
686
|
+
if (overwrite === false) {
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
const fileContent = await readFile2(file, "utf8");
|
|
690
|
+
if (typeof overwrite === "function" && !overwrite(fileContent)) {
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
if (crc3(content) === crc3(fileContent)) {
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
await mkdir2(dirname2(file), { recursive: true });
|
|
698
|
+
await writeFile2(file, content, "utf8");
|
|
699
|
+
};
|
|
700
|
+
var renderFactory = (options) => {
|
|
701
|
+
const renderer = handlebars.create();
|
|
702
|
+
renderer.registerPartial({ ...options?.partials });
|
|
703
|
+
renderer.registerHelper({ ...options?.helpers });
|
|
704
|
+
return {
|
|
705
|
+
render(template, context2, selfOoptions) {
|
|
706
|
+
return render(template, context2, {
|
|
707
|
+
renderer,
|
|
708
|
+
...options,
|
|
709
|
+
...selfOoptions
|
|
710
|
+
});
|
|
711
|
+
},
|
|
712
|
+
async renderToFile(file, template, context2, selfOoptions) {
|
|
713
|
+
return renderToFile(
|
|
714
|
+
options?.outdir ? join2(options.outdir, file) : file,
|
|
715
|
+
template,
|
|
716
|
+
context2,
|
|
717
|
+
{ renderer, ...options, ...selfOoptions }
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
};
|
|
722
|
+
var renderHelpers = {
|
|
723
|
+
createParamsLiteral: (params) => {
|
|
724
|
+
return params.schema.map((p) => {
|
|
725
|
+
return p.kind === "splat" ? `${p.const}?: Array<string | number>` : p.kind === "optional" ? `${p.const}?: string | number` : `${p.const}: string | number`;
|
|
726
|
+
}).join(", ");
|
|
727
|
+
}
|
|
728
|
+
};
|
|
729
|
+
|
|
604
730
|
// src/routes-factory/base.ts
|
|
605
731
|
import crc4 from "crc/crc32";
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
const
|
|
612
|
-
const
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
param
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
};
|
|
732
|
+
import { parse } from "path-to-regexp";
|
|
733
|
+
var pathTokensFactory = (path, {
|
|
734
|
+
transformStaticValue = normalizeStaticValue
|
|
735
|
+
} = {}) => {
|
|
736
|
+
const extractParts = (tokens2, createConst, insideGroup = false) => {
|
|
737
|
+
const parts = [];
|
|
738
|
+
for (const token of tokens2) {
|
|
739
|
+
switch (token.type) {
|
|
740
|
+
case "text":
|
|
741
|
+
if (token.value !== "/") {
|
|
742
|
+
parts.push({
|
|
743
|
+
type: "static",
|
|
744
|
+
value: transformStaticValue(token.value)
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
break;
|
|
748
|
+
case "param":
|
|
749
|
+
parts.push({
|
|
750
|
+
type: "param",
|
|
751
|
+
kind: insideGroup ? "optional" : "required",
|
|
752
|
+
name: token.name,
|
|
753
|
+
const: createConst(token.name)
|
|
754
|
+
});
|
|
755
|
+
break;
|
|
756
|
+
case "wildcard":
|
|
757
|
+
parts.push({
|
|
758
|
+
type: "param",
|
|
759
|
+
kind: "splat",
|
|
760
|
+
name: token.name,
|
|
761
|
+
const: createConst(token.name)
|
|
762
|
+
});
|
|
763
|
+
break;
|
|
764
|
+
case "group":
|
|
765
|
+
parts.push(...extractParts(token.tokens, createConst, true));
|
|
766
|
+
break;
|
|
642
767
|
}
|
|
643
768
|
}
|
|
644
|
-
return
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
769
|
+
return parts;
|
|
770
|
+
};
|
|
771
|
+
const patternTransforms = [
|
|
772
|
+
// Transform required params: [id] => :id
|
|
773
|
+
// Only pure \w param names,
|
|
774
|
+
// [some-id] used as is, not treated as param,
|
|
775
|
+
// use [some_id] instead.
|
|
776
|
+
(s) => s.replace(/\[(\w+)\]/g, ":$1"),
|
|
777
|
+
// Transform optional params: {id} => {:id}
|
|
778
|
+
// Only pure \w param names,
|
|
779
|
+
// anything else treated as a path-to-regexp pattern and used as is.
|
|
780
|
+
// {some-id} treated as an optional static segment.
|
|
781
|
+
// use {some_id} for simple param syntax
|
|
782
|
+
// or {:some-id} pattern where :some is the param name and -id is a static segment.
|
|
783
|
+
(s) => s.replace(/\{(\w+)\}/g, "{:$1}"),
|
|
784
|
+
// Transform splat params: {...param} => {*param}
|
|
785
|
+
(s) => s.replace(/\{\.\.\./g, "{*"),
|
|
786
|
+
// Insert leading slash inside optional/splat groups.
|
|
787
|
+
// {:name} => {/:name}
|
|
788
|
+
// {*name} => {/*name}
|
|
789
|
+
(s) => {
|
|
790
|
+
return s.startsWith("{") ? s.replace(/^\{/, "{/") : s;
|
|
791
|
+
}
|
|
792
|
+
];
|
|
793
|
+
const detectBareParams = (s) => {
|
|
794
|
+
let depth = 0;
|
|
795
|
+
for (const [i, ch] of [...s].entries()) {
|
|
796
|
+
if (ch === "{") {
|
|
797
|
+
depth += 1;
|
|
798
|
+
} else if (ch === "}") {
|
|
799
|
+
depth -= 1;
|
|
800
|
+
} else if (ch === ":" && depth === 0) {
|
|
801
|
+
const match = s.slice(i + 1).match(/^\w+/);
|
|
802
|
+
return match?.[0] || ":";
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
return;
|
|
806
|
+
};
|
|
807
|
+
const tokens = path.replace(/^index\/?/, "").split("/").flatMap((orig) => {
|
|
808
|
+
if (!orig.length) {
|
|
809
|
+
return [];
|
|
810
|
+
}
|
|
811
|
+
const bareParam = detectBareParams(orig);
|
|
812
|
+
if (bareParam === ":") {
|
|
813
|
+
throw new Error(
|
|
814
|
+
`${path} contains colons outside braces, use : only within {}`
|
|
815
|
+
);
|
|
816
|
+
} else if (bareParam) {
|
|
817
|
+
throw new Error(
|
|
818
|
+
`${path} contains bare params, use [${bareParam}] instead of :${bareParam}`
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
const pattern = patternTransforms.reduce((src, fn) => fn(src), orig);
|
|
822
|
+
const { tokens: tokens2 } = parse(pattern);
|
|
823
|
+
const parts = extractParts(tokens2, (val) => {
|
|
824
|
+
return /\W/.test(val) || /^\d/.test(val) ? [val.replace(/^\d+|\W/g, "_"), crc4(orig)].join("_") : val;
|
|
825
|
+
});
|
|
826
|
+
const isStatic = parts.length === 1 ? parts[0].type === "static" : false;
|
|
827
|
+
const isParam = parts.length === 1 ? parts[0].type === "param" : false;
|
|
828
|
+
const kind = isStatic ? "static" : isParam ? "param" : "mixed";
|
|
829
|
+
return [
|
|
830
|
+
{
|
|
831
|
+
kind,
|
|
832
|
+
orig,
|
|
833
|
+
pattern,
|
|
834
|
+
parts
|
|
835
|
+
}
|
|
836
|
+
];
|
|
651
837
|
});
|
|
838
|
+
return [
|
|
839
|
+
tokens,
|
|
840
|
+
tokens.map(({ pattern }, i) => {
|
|
841
|
+
const next = tokens[i + 1];
|
|
842
|
+
if (!next || next.pattern.includes("/")) {
|
|
843
|
+
return pattern;
|
|
844
|
+
}
|
|
845
|
+
const slashRequired = tokens.slice(i + 1).some((e) => {
|
|
846
|
+
return e.parts.some((e2) => {
|
|
847
|
+
return e2.type === "static" || e2.kind === "required";
|
|
848
|
+
});
|
|
849
|
+
});
|
|
850
|
+
return slashRequired ? `${pattern}/` : pattern;
|
|
851
|
+
}).join("")
|
|
852
|
+
];
|
|
853
|
+
};
|
|
854
|
+
var normalizeStaticValue = (value) => {
|
|
855
|
+
return value.replace(/\+/g, "\\\\+");
|
|
652
856
|
};
|
|
653
857
|
var sortRoutes = (a, b) => {
|
|
654
|
-
const
|
|
655
|
-
const
|
|
656
|
-
if (
|
|
657
|
-
return
|
|
858
|
+
const aSpecificity = routeSpecificity(a.pathTokens);
|
|
859
|
+
const bSpecificity = routeSpecificity(b.pathTokens);
|
|
860
|
+
if (aSpecificity !== bSpecificity) {
|
|
861
|
+
return bSpecificity - aSpecificity;
|
|
658
862
|
}
|
|
659
863
|
if (a.pathTokens.length !== b.pathTokens.length) {
|
|
660
864
|
return a.pathTokens.length - b.pathTokens.length;
|
|
661
865
|
}
|
|
662
866
|
return a.name.localeCompare(b.name);
|
|
663
867
|
};
|
|
664
|
-
var
|
|
665
|
-
return
|
|
868
|
+
var paramWeight = (part) => {
|
|
869
|
+
return {
|
|
870
|
+
required: 2,
|
|
871
|
+
optional: 1,
|
|
872
|
+
splat: 0
|
|
873
|
+
}[part.kind];
|
|
874
|
+
};
|
|
875
|
+
var mixedSegmentWeight = (parts) => {
|
|
876
|
+
const hasSplat = parts.some((p) => {
|
|
877
|
+
return p.type === "param" ? p.kind === "splat" : false;
|
|
878
|
+
});
|
|
879
|
+
return hasSplat ? 0.5 : 3;
|
|
880
|
+
};
|
|
881
|
+
var segmentWeight = (token) => {
|
|
882
|
+
return {
|
|
883
|
+
static: 4,
|
|
884
|
+
mixed: mixedSegmentWeight(token.parts),
|
|
885
|
+
param: paramWeight(token.parts[0])
|
|
886
|
+
}[token.kind];
|
|
887
|
+
};
|
|
888
|
+
var routeSpecificity = (pathTokens) => {
|
|
889
|
+
return pathTokens.reduce((sum, token) => sum + segmentWeight(token), 0);
|
|
666
890
|
};
|
|
667
891
|
|
|
668
892
|
// src/routes-factory/templates/resolved-types.hbs
|
|
669
893
|
var resolved_types_default = "{{#each resolvedTypes}}\nexport type {{name}} = {{text}};\n{{/each}}\n";
|
|
670
894
|
|
|
671
895
|
// src/routes-factory/templates/types.hbs
|
|
672
|
-
var types_default = '{{#each typeDeclarations}}{{text}}\n{{/each}}\n\nexport type {{params.id}} = {\n {{#each paramsSchema}}\n "{{name}}"{{#unless isRequired}}?{{/unless}}:{{#if
|
|
896
|
+
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';
|
|
673
897
|
|
|
674
898
|
// src/routes-factory/resolve.ts
|
|
675
899
|
var API_INDEX_BASENAME = "index";
|
|
@@ -740,15 +964,18 @@ var createRouteEntry = (fileFullpath, {
|
|
|
740
964
|
return;
|
|
741
965
|
}
|
|
742
966
|
const [folder, file] = resolvedPaths;
|
|
743
|
-
const
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
folder,
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
967
|
+
const id = `${file.replace(/\W+/g, "_")}_${crc5(file)}`;
|
|
968
|
+
const name = dirname3(file);
|
|
969
|
+
try {
|
|
970
|
+
const [pathTokens, pathPattern] = pathTokensFactory(dirname3(file));
|
|
971
|
+
return { id, name, folder, file, fileFullpath, pathTokens, pathPattern };
|
|
972
|
+
} catch (error) {
|
|
973
|
+
console.error(
|
|
974
|
+
`\u2757${styleText2("red", "ERROR")}: Failed parsing path for "${styleText2("cyan", file)}"`
|
|
975
|
+
);
|
|
976
|
+
console.error(error);
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
752
979
|
};
|
|
753
980
|
var pageLayoutResolverFactory = () => {
|
|
754
981
|
return (entry) => {
|
|
@@ -764,14 +991,17 @@ var pageLayoutResolverFactory = () => {
|
|
|
764
991
|
};
|
|
765
992
|
var pageRouteResolverFactory = () => {
|
|
766
993
|
return (entry) => {
|
|
767
|
-
const { id, name, folder, file, fileFullpath, pathTokens } = entry;
|
|
994
|
+
const { id, name, folder, file, fileFullpath, pathTokens, pathPattern } = entry;
|
|
768
995
|
const handler = async () => {
|
|
769
996
|
const entry2 = {
|
|
770
997
|
id,
|
|
771
998
|
name,
|
|
772
999
|
pathTokens,
|
|
1000
|
+
pathPattern,
|
|
773
1001
|
params: {
|
|
774
|
-
schema: pathTokens.flatMap((e) =>
|
|
1002
|
+
schema: pathTokens.flatMap((e) => {
|
|
1003
|
+
return e.parts.filter((p) => p.type === "param");
|
|
1004
|
+
})
|
|
775
1005
|
},
|
|
776
1006
|
folder,
|
|
777
1007
|
file,
|
|
@@ -802,28 +1032,33 @@ var apiRouteResolverFactory = (pluginOptions) => {
|
|
|
802
1032
|
appRoot,
|
|
803
1033
|
sourceFolder,
|
|
804
1034
|
generators = [],
|
|
805
|
-
formatters = [],
|
|
806
1035
|
refineTypeName
|
|
807
1036
|
} = pluginOptions;
|
|
808
|
-
|
|
809
|
-
for (const { options } of generators) {
|
|
810
|
-
if (options?.resolveTypes) {
|
|
811
|
-
resolveTypes = true;
|
|
812
|
-
}
|
|
813
|
-
}
|
|
1037
|
+
const resolveTypes = generators.some((e) => e.options?.resolveTypes);
|
|
814
1038
|
const {
|
|
815
1039
|
//
|
|
816
1040
|
literalTypesResolver,
|
|
817
1041
|
getSourceFile,
|
|
818
1042
|
refreshSourceFile
|
|
819
1043
|
} = typeResolverFactory(pluginOptions);
|
|
820
|
-
return (
|
|
821
|
-
|
|
1044
|
+
return ({
|
|
1045
|
+
id,
|
|
1046
|
+
name,
|
|
1047
|
+
file,
|
|
1048
|
+
folder,
|
|
1049
|
+
fileFullpath,
|
|
1050
|
+
pathTokens,
|
|
1051
|
+
pathPattern
|
|
1052
|
+
}) => {
|
|
822
1053
|
const handler = async (updatedFile) => {
|
|
823
|
-
const paramsSchema = pathTokens.flatMap(
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
1054
|
+
const paramsSchema = pathTokens.flatMap(
|
|
1055
|
+
(e) => {
|
|
1056
|
+
return e.parts.flatMap((p) => {
|
|
1057
|
+
return p.type === "param" ? [p] : [];
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
);
|
|
1061
|
+
const optionalParams = paramsSchema.length ? paramsSchema.filter((e) => e.kind === "required").length === 0 : true;
|
|
827
1062
|
const { getCache, persistCache } = cacheFactory(
|
|
828
1063
|
{ id, file, fileFullpath },
|
|
829
1064
|
{
|
|
@@ -841,11 +1076,10 @@ var apiRouteResolverFactory = (pluginOptions) => {
|
|
|
841
1076
|
typeDeclarations,
|
|
842
1077
|
paramsRefinements,
|
|
843
1078
|
methods,
|
|
844
|
-
|
|
845
|
-
responseTypes,
|
|
1079
|
+
validationDefinitions: validationDefinitions2,
|
|
846
1080
|
referencedFiles = []
|
|
847
1081
|
} = await resolveRouteSignature(
|
|
848
|
-
{ id, fileFullpath, optionalParams },
|
|
1082
|
+
{ id, name, fileFullpath, optionalParams },
|
|
849
1083
|
{
|
|
850
1084
|
withReferencedFiles: true,
|
|
851
1085
|
sourceFile: getSourceFile(fileFullpath),
|
|
@@ -854,6 +1088,11 @@ var apiRouteResolverFactory = (pluginOptions) => {
|
|
|
854
1088
|
}
|
|
855
1089
|
}
|
|
856
1090
|
);
|
|
1091
|
+
const validationTypes = validationDefinitions2.flatMap((def) => {
|
|
1092
|
+
return def.target === "response" ? def.variants.flatMap(({ id: id2, body }) => {
|
|
1093
|
+
return body ? [{ id: id2, text: body }] : [];
|
|
1094
|
+
}) : [def.schema];
|
|
1095
|
+
});
|
|
857
1096
|
const numericParams = paramsRefinements ? paramsRefinements.flatMap(({ text, index }) => {
|
|
858
1097
|
if (text === "number") {
|
|
859
1098
|
const param = paramsSchema.at(index);
|
|
@@ -875,25 +1114,21 @@ var apiRouteResolverFactory = (pluginOptions) => {
|
|
|
875
1114
|
paramsSchema: paramsSchema.map((param, index) => {
|
|
876
1115
|
return {
|
|
877
1116
|
...param,
|
|
1117
|
+
isRequired: param.kind === "required",
|
|
1118
|
+
isSplat: param.kind === "splat",
|
|
878
1119
|
refinement: paramsRefinements?.at(index)
|
|
879
1120
|
};
|
|
880
1121
|
}),
|
|
881
1122
|
typeDeclarations,
|
|
882
|
-
|
|
883
|
-
responseTypes
|
|
1123
|
+
validationTypes
|
|
884
1124
|
});
|
|
885
1125
|
const resolvedTypes = resolveTypes ? literalTypesResolver(typesFileContent, {
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
},
|
|
893
|
-
{ [refineTypeName]: refineTypeName }
|
|
894
|
-
),
|
|
895
|
-
withProperties: [params.id, ...payloadTypes.map((e) => e.id)],
|
|
896
|
-
formatters
|
|
1126
|
+
stripComments: true,
|
|
1127
|
+
overrides: { [refineTypeName]: refineTypeName },
|
|
1128
|
+
withProperties: [
|
|
1129
|
+
params.id,
|
|
1130
|
+
...validationTypes.flatMap(({ id: id2 }) => id2)
|
|
1131
|
+
]
|
|
897
1132
|
}) : void 0;
|
|
898
1133
|
await renderToFile(
|
|
899
1134
|
typesFile,
|
|
@@ -906,26 +1141,94 @@ var apiRouteResolverFactory = (pluginOptions) => {
|
|
|
906
1141
|
methods,
|
|
907
1142
|
typeDeclarations,
|
|
908
1143
|
numericParams,
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
return {
|
|
912
|
-
...rest,
|
|
913
|
-
resolvedType: resolvedTypes?.find((e) => e.name === rest.id)
|
|
914
|
-
};
|
|
915
|
-
}),
|
|
916
|
-
responseTypes: responseTypes.map(({ text, ...rest }) => {
|
|
1144
|
+
referencedFiles,
|
|
1145
|
+
validationDefinitions: validationDefinitions2.map((def) => {
|
|
917
1146
|
return {
|
|
918
|
-
...
|
|
919
|
-
|
|
1147
|
+
...def,
|
|
1148
|
+
...def.target === "response" ? {
|
|
1149
|
+
variants: def.variants.map((variant) => {
|
|
1150
|
+
return {
|
|
1151
|
+
...variant,
|
|
1152
|
+
resolvedType: resolvedTypes?.find(
|
|
1153
|
+
(e) => e.name === variant.id
|
|
1154
|
+
)
|
|
1155
|
+
};
|
|
1156
|
+
})
|
|
1157
|
+
} : {
|
|
1158
|
+
schema: {
|
|
1159
|
+
...def.schema,
|
|
1160
|
+
resolvedType: resolvedTypes?.find(
|
|
1161
|
+
(e) => e.name === def.schema.id
|
|
1162
|
+
)
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
920
1165
|
};
|
|
921
|
-
})
|
|
922
|
-
referencedFiles
|
|
1166
|
+
})
|
|
923
1167
|
});
|
|
924
1168
|
}
|
|
925
|
-
const
|
|
1169
|
+
const validationDefinitions = cache.validationDefinitions.flatMap(
|
|
1170
|
+
(def) => {
|
|
1171
|
+
let augmentedDef = def;
|
|
1172
|
+
if (def.target === "response") {
|
|
1173
|
+
augmentedDef = {
|
|
1174
|
+
...def,
|
|
1175
|
+
variants: def.variants.flatMap((variant, i) => {
|
|
1176
|
+
if (typeof variant.contentType !== "string") {
|
|
1177
|
+
return [variant];
|
|
1178
|
+
}
|
|
1179
|
+
if (variant.contentType.includes("/")) {
|
|
1180
|
+
return [variant];
|
|
1181
|
+
}
|
|
1182
|
+
const contentType = mimeTypes.lookup(variant.contentType);
|
|
1183
|
+
if (contentType === false) {
|
|
1184
|
+
console.warn(
|
|
1185
|
+
styleText2(
|
|
1186
|
+
["bold", "red"],
|
|
1187
|
+
"\u2717 Failed resolving Response Content Type"
|
|
1188
|
+
)
|
|
1189
|
+
);
|
|
1190
|
+
console.warn(
|
|
1191
|
+
` Invalid value provided for mime-types lookup - ${variant.contentType}`
|
|
1192
|
+
);
|
|
1193
|
+
console.warn(
|
|
1194
|
+
styleText2(
|
|
1195
|
+
["cyan"],
|
|
1196
|
+
` Response variant #${i} excluded from route schemas`
|
|
1197
|
+
)
|
|
1198
|
+
);
|
|
1199
|
+
console.warn(` Route: ${name}; Method: ${def.method}`);
|
|
1200
|
+
console.warn();
|
|
1201
|
+
return [];
|
|
1202
|
+
}
|
|
1203
|
+
return [{ ...variant, contentType }];
|
|
1204
|
+
})
|
|
1205
|
+
};
|
|
1206
|
+
} else if (def.contentType && !def.contentType.includes("/")) {
|
|
1207
|
+
const contentType = mimeTypes.lookup(def.contentType);
|
|
1208
|
+
if (contentType === false) {
|
|
1209
|
+
console.warn(
|
|
1210
|
+
styleText2(
|
|
1211
|
+
["bold", "red"],
|
|
1212
|
+
"\u2717 Failed resolving Response Content Type"
|
|
1213
|
+
)
|
|
1214
|
+
);
|
|
1215
|
+
console.warn(
|
|
1216
|
+
` Invalid value provided for mime-types lookup - ${def.contentType}`
|
|
1217
|
+
);
|
|
1218
|
+
console.warn(` Route: ${name}; Method: ${def.method}`);
|
|
1219
|
+
console.warn();
|
|
1220
|
+
} else {
|
|
1221
|
+
augmentedDef = { ...def, contentType };
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
return augmentedDef ? [augmentedDef] : [];
|
|
1225
|
+
}
|
|
1226
|
+
);
|
|
1227
|
+
const entry = {
|
|
926
1228
|
id,
|
|
927
1229
|
name,
|
|
928
1230
|
pathTokens,
|
|
1231
|
+
pathPattern,
|
|
929
1232
|
params: cache.params,
|
|
930
1233
|
numericParams: cache.numericParams,
|
|
931
1234
|
optionalParams,
|
|
@@ -934,8 +1237,7 @@ var apiRouteResolverFactory = (pluginOptions) => {
|
|
|
934
1237
|
fileFullpath,
|
|
935
1238
|
methods: cache.methods,
|
|
936
1239
|
typeDeclarations: cache.typeDeclarations,
|
|
937
|
-
|
|
938
|
-
responseTypes: cache.responseTypes,
|
|
1240
|
+
validationDefinitions,
|
|
939
1241
|
referencedFiles: Object.keys(cache.referencedFiles).map(
|
|
940
1242
|
// expand referenced files path,
|
|
941
1243
|
// they are stored as relative in cache
|
|
@@ -944,7 +1246,7 @@ var apiRouteResolverFactory = (pluginOptions) => {
|
|
|
944
1246
|
};
|
|
945
1247
|
return {
|
|
946
1248
|
kind: "apiRoute",
|
|
947
|
-
entry
|
|
1249
|
+
entry
|
|
948
1250
|
};
|
|
949
1251
|
};
|
|
950
1252
|
return { name, handler };
|
|
@@ -1075,32 +1377,29 @@ var routesFactory = async (pluginOptions) => {
|
|
|
1075
1377
|
|
|
1076
1378
|
// src/base-plugin/api-handler.ts
|
|
1077
1379
|
import { join as join4, resolve as resolve4 } from "node:path";
|
|
1078
|
-
import { styleText } from "node:util";
|
|
1380
|
+
import { styleText as styleText3 } from "node:util";
|
|
1079
1381
|
import { context } from "esbuild";
|
|
1080
1382
|
var api_handler_default = async (options) => {
|
|
1081
1383
|
const { appRoot, sourceFolder, baseurl, apiurl } = options;
|
|
1082
1384
|
const { createPath } = pathResolver({ appRoot, sourceFolder });
|
|
1083
1385
|
const outDir = join4(options.outDir, defaults.apiDir);
|
|
1084
1386
|
const esbuildOptions = await import(resolve4(appRoot, "esbuild.json"), { with: { type: "json" } }).then((e) => e.default);
|
|
1085
|
-
let
|
|
1086
|
-
let devMiddlewareFactory;
|
|
1087
|
-
let teardownHandler;
|
|
1387
|
+
let devSetup;
|
|
1088
1388
|
const watcher = async () => {
|
|
1089
1389
|
const rebuildPlugin = {
|
|
1090
1390
|
name: "rebuild",
|
|
1091
1391
|
setup(build) {
|
|
1092
1392
|
build.onEnd(async () => {
|
|
1093
|
-
if (
|
|
1094
|
-
await teardownHandler?.(
|
|
1393
|
+
if (devSetup) {
|
|
1394
|
+
await devSetup.teardownHandler?.();
|
|
1095
1395
|
}
|
|
1096
1396
|
try {
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
console.debug(`${styleText("green", "\u279C")} Api handler ready`);
|
|
1397
|
+
await import(`${outDir}/dev.js?${Date.now()}`).then((e) => {
|
|
1398
|
+
devSetup = e.default;
|
|
1399
|
+
});
|
|
1400
|
+
console.debug(`${styleText3("green", "\u279C")} Api handler ready`);
|
|
1102
1401
|
} catch (error) {
|
|
1103
|
-
console.error(`${
|
|
1402
|
+
console.error(`${styleText3("red", "\u2717")} Api handler error`);
|
|
1104
1403
|
console.error(error);
|
|
1105
1404
|
}
|
|
1106
1405
|
});
|
|
@@ -1108,9 +1407,13 @@ var api_handler_default = async (options) => {
|
|
|
1108
1407
|
};
|
|
1109
1408
|
const ctx = await context({
|
|
1110
1409
|
...esbuildOptions,
|
|
1410
|
+
define: {
|
|
1411
|
+
...esbuildOptions.define,
|
|
1412
|
+
PRODUCTION_BUILD: "false"
|
|
1413
|
+
},
|
|
1111
1414
|
logLevel: "error",
|
|
1112
1415
|
bundle: true,
|
|
1113
|
-
entryPoints: [createPath.api("
|
|
1416
|
+
entryPoints: [createPath.api("dev.ts")],
|
|
1114
1417
|
plugins: [rebuildPlugin],
|
|
1115
1418
|
outdir: outDir
|
|
1116
1419
|
});
|
|
@@ -1126,16 +1429,20 @@ var api_handler_default = async (options) => {
|
|
|
1126
1429
|
}
|
|
1127
1430
|
};
|
|
1128
1431
|
};
|
|
1129
|
-
const devMiddleware = async (req, res,
|
|
1130
|
-
const
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1432
|
+
const devMiddleware = async (req, res, next) => {
|
|
1433
|
+
const {
|
|
1434
|
+
requestMatcher = () => {
|
|
1435
|
+
return new RegExp(`^${join4(baseurl, apiurl)}($|/)`).test(
|
|
1436
|
+
req.url
|
|
1437
|
+
);
|
|
1438
|
+
},
|
|
1439
|
+
requestHandler
|
|
1440
|
+
} = { ...devSetup };
|
|
1441
|
+
if (!requestMatcher(req)) {
|
|
1442
|
+
return next();
|
|
1138
1443
|
}
|
|
1444
|
+
const handler = requestHandler?.();
|
|
1445
|
+
return handler ? handler(req, res) : next();
|
|
1139
1446
|
};
|
|
1140
1447
|
return {
|
|
1141
1448
|
watcher,
|
|
@@ -1144,9 +1451,9 @@ var api_handler_default = async (options) => {
|
|
|
1144
1451
|
};
|
|
1145
1452
|
|
|
1146
1453
|
// src/base-plugin/spinner.ts
|
|
1147
|
-
import
|
|
1454
|
+
import { Spinner } from "@topcli/spinner";
|
|
1148
1455
|
var spinnerFactory = (startText) => {
|
|
1149
|
-
const spinner =
|
|
1456
|
+
const spinner = new Spinner().start(startText);
|
|
1150
1457
|
let _text = startText;
|
|
1151
1458
|
return {
|
|
1152
1459
|
text(text) {
|
|
@@ -1168,7 +1475,7 @@ var spinnerFactory = (startText) => {
|
|
|
1168
1475
|
if (text) {
|
|
1169
1476
|
this.text([_text, text].join("\n"));
|
|
1170
1477
|
}
|
|
1171
|
-
spinner.
|
|
1478
|
+
spinner.failed();
|
|
1172
1479
|
}
|
|
1173
1480
|
};
|
|
1174
1481
|
};
|
|
@@ -1179,19 +1486,13 @@ var base_plugin_default = (apiurl, pluginOptions) => {
|
|
|
1179
1486
|
const outDirSuffix = "client";
|
|
1180
1487
|
const store = {};
|
|
1181
1488
|
const createWorker = () => {
|
|
1182
|
-
const {
|
|
1183
|
-
generators = [],
|
|
1184
|
-
formatters = [],
|
|
1185
|
-
...restOptions
|
|
1186
|
-
} = store.resolvedOptions;
|
|
1489
|
+
const { generators = [], ...restOptions } = store.resolvedOptions;
|
|
1187
1490
|
const generatorModules = generators.map(
|
|
1188
1491
|
(e) => [e.moduleImport, e.moduleConfig]
|
|
1189
1492
|
);
|
|
1190
|
-
const formatterModules = pluginOptions?.formatters ? pluginOptions.formatters.map((e) => [e.moduleImport, e.moduleConfig]) : [];
|
|
1191
1493
|
const workerData = {
|
|
1192
1494
|
...restOptions,
|
|
1193
|
-
generatorModules
|
|
1194
|
-
formatterModules
|
|
1495
|
+
generatorModules
|
|
1195
1496
|
};
|
|
1196
1497
|
return new Worker(resolve5(import.meta.dirname, "base-plugin/worker.js"), {
|
|
1197
1498
|
workerData,
|
|
@@ -1230,10 +1531,10 @@ var base_plugin_default = (apiurl, pluginOptions) => {
|
|
|
1230
1531
|
const { error } = msg;
|
|
1231
1532
|
if (error.stack) {
|
|
1232
1533
|
const [message, ...stack] = error.stack.split("\n");
|
|
1233
|
-
console.error(
|
|
1534
|
+
console.error(styleText4("red", message));
|
|
1234
1535
|
console.error(stack.join("\n"));
|
|
1235
1536
|
} else if (error?.message) {
|
|
1236
|
-
console.error(`${
|
|
1537
|
+
console.error(`${styleText4("red", error?.name)}: ${error.message}`);
|
|
1237
1538
|
} else {
|
|
1238
1539
|
console.error(error);
|
|
1239
1540
|
}
|
|
@@ -1275,19 +1576,12 @@ var base_plugin_default = (apiurl, pluginOptions) => {
|
|
|
1275
1576
|
...store.config.server.watch ? { options: store.config.server.watch } : {}
|
|
1276
1577
|
};
|
|
1277
1578
|
{
|
|
1278
|
-
const {
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
const
|
|
1284
|
-
const fetchGenerator = generators.find((e) => e.kind === "fetch");
|
|
1285
|
-
const ssrGenerator = generators.find((e) => e.kind === "ssr");
|
|
1286
|
-
if (!apiGenerator || !fetchGenerator) {
|
|
1287
|
-
throw new Error(
|
|
1288
|
-
"Some of required generators missing, make sure both `api` and `fetch` generators configured properly"
|
|
1289
|
-
);
|
|
1290
|
-
}
|
|
1579
|
+
const { generators = [], refineTypeName = "TRefine" } = {
|
|
1580
|
+
...pluginOptions
|
|
1581
|
+
};
|
|
1582
|
+
const apiGenerator = generators.find((e) => e.slot === "api");
|
|
1583
|
+
const fetchGenerator = generators.find((e) => e.slot === "fetch");
|
|
1584
|
+
const ssrGenerator = generators.find((e) => e.slot === "ssr");
|
|
1291
1585
|
store.resolvedOptions = {
|
|
1292
1586
|
...pluginOptions,
|
|
1293
1587
|
command: store.config.command,
|
|
@@ -1296,17 +1590,16 @@ var base_plugin_default = (apiurl, pluginOptions) => {
|
|
|
1296
1590
|
// 1. stub generator should run first
|
|
1297
1591
|
stubGenerator(),
|
|
1298
1592
|
// 2. then api generator
|
|
1299
|
-
apiGenerator,
|
|
1300
|
-
// 3. then fetch generator
|
|
1301
|
-
fetchGenerator,
|
|
1593
|
+
...apiGenerator ? [apiGenerator] : [],
|
|
1594
|
+
// 3. then fetch generator, only if api generator also enabled
|
|
1595
|
+
...fetchGenerator && apiGenerator ? [fetchGenerator] : [],
|
|
1302
1596
|
// 4. user generators in the order they were added
|
|
1303
1597
|
...generators.filter((e) => {
|
|
1304
|
-
return e.
|
|
1598
|
+
return e.slot ? !["api", "fetch", "ssr"].includes(e.slot) : true;
|
|
1305
1599
|
}),
|
|
1306
1600
|
// 5. ssr generator should run last
|
|
1307
1601
|
...ssrGenerator ? [ssrGenerator] : []
|
|
1308
1602
|
],
|
|
1309
|
-
formatters: formatters.map((e) => e.formatter),
|
|
1310
1603
|
refineTypeName,
|
|
1311
1604
|
baseurl: store.config.base,
|
|
1312
1605
|
apiurl,
|
|
@@ -1315,6 +1608,52 @@ var base_plugin_default = (apiurl, pluginOptions) => {
|
|
|
1315
1608
|
outDir
|
|
1316
1609
|
};
|
|
1317
1610
|
}
|
|
1611
|
+
const packageJsonFile = resolve5(appRoot, "package.json");
|
|
1612
|
+
const packageJson = await import(packageJsonFile, {
|
|
1613
|
+
with: { type: "json" }
|
|
1614
|
+
}).then((e) => e.default);
|
|
1615
|
+
const newDependencies = [];
|
|
1616
|
+
for (const generator of store.resolvedOptions.generators) {
|
|
1617
|
+
for (const key of ["dependencies", "devDependencies"]) {
|
|
1618
|
+
for (const [pkg, ver] of Object.entries(generator[key] || {})) {
|
|
1619
|
+
if (!packageJson[key]?.[pkg]) {
|
|
1620
|
+
newDependencies.push([key, pkg, ver]);
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
if (newDependencies.length) {
|
|
1626
|
+
console.warn();
|
|
1627
|
+
console.warn(
|
|
1628
|
+
[
|
|
1629
|
+
"\u{1F4A1} ",
|
|
1630
|
+
styleText4(["bold", "italic", "red"], "New dependencies added: "),
|
|
1631
|
+
styleText4("dim", newDependencies.map(([, pkg]) => pkg).join(", "))
|
|
1632
|
+
].join("")
|
|
1633
|
+
);
|
|
1634
|
+
console.warn(
|
|
1635
|
+
"\u{1F4E6}",
|
|
1636
|
+
[
|
|
1637
|
+
styleText4(
|
|
1638
|
+
["bold", "blueBright"],
|
|
1639
|
+
store.config.command === "build" ? "Install them and run a new build: " : "Install them and restart dev server: "
|
|
1640
|
+
),
|
|
1641
|
+
styleText4(
|
|
1642
|
+
"dim",
|
|
1643
|
+
["npm", "pnpm", "yarn"].map((e) => `\`${e} install\``).join(" / ")
|
|
1644
|
+
)
|
|
1645
|
+
].join("")
|
|
1646
|
+
);
|
|
1647
|
+
console.warn();
|
|
1648
|
+
for (const [key, pkg, ver] of newDependencies) {
|
|
1649
|
+
packageJson[key] = { ...packageJson[key], [pkg]: ver };
|
|
1650
|
+
}
|
|
1651
|
+
await writeFile3(
|
|
1652
|
+
packageJsonFile,
|
|
1653
|
+
JSON.stringify(packageJson, null, 2),
|
|
1654
|
+
"utf8"
|
|
1655
|
+
);
|
|
1656
|
+
}
|
|
1318
1657
|
if (store.config.command === "build") {
|
|
1319
1658
|
const { resolvers } = await routesFactory(store.resolvedOptions);
|
|
1320
1659
|
const resolvedEntries = [];
|
|
@@ -1343,6 +1682,10 @@ var base_plugin_default = (apiurl, pluginOptions) => {
|
|
|
1343
1682
|
if (store.config.command !== "serve") {
|
|
1344
1683
|
return;
|
|
1345
1684
|
}
|
|
1685
|
+
if (!store.resolvedOptions.generators.find((e) => e.slot === "api")) {
|
|
1686
|
+
const stopWorker2 = workerHandler(() => stopWorker2());
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1346
1689
|
const apiHandler = await api_handler_default(store.resolvedOptions);
|
|
1347
1690
|
const apiWatcher = await apiHandler.watcher();
|
|
1348
1691
|
const stopWorker = workerHandler(
|
|
@@ -1421,13 +1764,14 @@ export {
|
|
|
1421
1764
|
isPageRoute,
|
|
1422
1765
|
isRouteFile,
|
|
1423
1766
|
nestedRoutesFactory,
|
|
1767
|
+
normalizeStaticValue,
|
|
1424
1768
|
pageLayoutResolverFactory,
|
|
1425
1769
|
pageRouteResolverFactory,
|
|
1426
1770
|
pathResolver,
|
|
1427
1771
|
pathTokensFactory,
|
|
1428
1772
|
render,
|
|
1429
|
-
renderAsFile,
|
|
1430
1773
|
renderFactory,
|
|
1774
|
+
renderHelpers,
|
|
1431
1775
|
renderToFile,
|
|
1432
1776
|
routesFactory,
|
|
1433
1777
|
scanRoutes,
|