@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
|
@@ -53,9 +53,6 @@ var pathResolver = ({
|
|
|
53
53
|
},
|
|
54
54
|
libEntry(...a) {
|
|
55
55
|
return this.lib(defaults.entryDir, ...a);
|
|
56
|
-
},
|
|
57
|
-
fetch(...a) {
|
|
58
|
-
return this.lib(defaults.fetchDir, ...a);
|
|
59
56
|
}
|
|
60
57
|
};
|
|
61
58
|
return {
|
|
@@ -89,9 +86,6 @@ var pathResolver = ({
|
|
|
89
86
|
},
|
|
90
87
|
libPages(...a) {
|
|
91
88
|
return this.lib(defaults.pagesDir, ...a);
|
|
92
|
-
},
|
|
93
|
-
fetch(...a) {
|
|
94
|
-
return this.lib(defaults.fetchDir, ...a);
|
|
95
89
|
}
|
|
96
90
|
},
|
|
97
91
|
createImport,
|
|
@@ -103,65 +97,25 @@ var pathResolver = ({
|
|
|
103
97
|
|
|
104
98
|
// src/routes-factory/resolve.ts
|
|
105
99
|
import { dirname as dirname3, join as join3, resolve as resolve3 } from "node:path";
|
|
100
|
+
import { styleText as styleText2 } from "node:util";
|
|
106
101
|
import crc5 from "crc/crc32";
|
|
102
|
+
import mimeTypes from "mime-types";
|
|
107
103
|
import picomatch from "picomatch";
|
|
108
104
|
import { glob } from "tinyglobby";
|
|
109
105
|
|
|
110
|
-
// src/render.ts
|
|
111
|
-
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
112
|
-
import { dirname, join as join2 } from "node:path";
|
|
113
|
-
import crc from "crc/crc32";
|
|
114
|
-
import handlebars from "handlebars";
|
|
115
|
-
|
|
116
|
-
// src/fs.ts
|
|
117
|
-
import { access, constants } from "node:fs/promises";
|
|
118
|
-
var pathExists = async (path) => {
|
|
119
|
-
try {
|
|
120
|
-
await access(path, constants.F_OK);
|
|
121
|
-
return true;
|
|
122
|
-
} catch {
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
// src/render.ts
|
|
128
|
-
var render = (template, context, options) => {
|
|
129
|
-
const { noEscape = true, renderer = handlebars } = { ...options };
|
|
130
|
-
return renderer.compile(template, { noEscape })(context);
|
|
131
|
-
};
|
|
132
|
-
var renderAsFile = (file, template, context, options) => {
|
|
133
|
-
const { formatters: formatters2, ...renderOpts } = { ...options };
|
|
134
|
-
const content = render(template, context, renderOpts);
|
|
135
|
-
return Array.isArray(formatters2) ? formatters2.reduce((c, f) => f(c, file), content) : content;
|
|
136
|
-
};
|
|
137
|
-
var renderToFile = async (file, template, context, options) => {
|
|
138
|
-
const content = renderAsFile(file, template, context, options);
|
|
139
|
-
if (await pathExists(file)) {
|
|
140
|
-
const { overwrite = true } = { ...options };
|
|
141
|
-
if (overwrite === false) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
const fileContent = await readFile(file, "utf8");
|
|
145
|
-
if (typeof overwrite === "function" && !overwrite(fileContent)) {
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
if (crc(content) === crc(fileContent)) {
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
await mkdir(dirname(file), { recursive: true });
|
|
153
|
-
await writeFile(file, content, "utf8");
|
|
154
|
-
};
|
|
155
|
-
|
|
156
106
|
// src/ast.ts
|
|
157
107
|
import { resolve } from "node:path";
|
|
158
|
-
import
|
|
108
|
+
import { styleText } from "node:util";
|
|
109
|
+
import crc from "crc/crc32";
|
|
159
110
|
import { flattener } from "tfusion";
|
|
160
111
|
import {
|
|
161
112
|
Project,
|
|
162
113
|
SyntaxKind
|
|
163
114
|
} from "ts-morph";
|
|
164
|
-
import {
|
|
115
|
+
import {
|
|
116
|
+
HTTPMethods,
|
|
117
|
+
RequestValidationTargets
|
|
118
|
+
} from "@kosmojs/api";
|
|
165
119
|
var createProject = (opts) => new Project(opts);
|
|
166
120
|
var resolveRouteSignature = async (route, opts) => {
|
|
167
121
|
const {
|
|
@@ -173,19 +127,12 @@ var resolveRouteSignature = async (route, opts) => {
|
|
|
173
127
|
);
|
|
174
128
|
const defaultExport = extractDefaultExport(sourceFile);
|
|
175
129
|
const paramsRefinements = defaultExport ? extractParamsRefinements(defaultExport) : void 0;
|
|
176
|
-
const methods = defaultExport ? extractRouteMethods(
|
|
177
|
-
const payloadTypes = methods.flatMap((e) => {
|
|
178
|
-
return e.payloadType ? [e.payloadType] : [];
|
|
179
|
-
});
|
|
180
|
-
const responseTypes = methods.flatMap((e) => {
|
|
181
|
-
return e.responseType ? [e.responseType] : [];
|
|
182
|
-
});
|
|
130
|
+
const methods = defaultExport ? extractRouteMethods(route, defaultExport) : [];
|
|
183
131
|
return {
|
|
184
132
|
typeDeclarations,
|
|
185
133
|
paramsRefinements,
|
|
186
134
|
methods: methods.map((e) => e.method),
|
|
187
|
-
|
|
188
|
-
responseTypes,
|
|
135
|
+
validationDefinitions: methods.flatMap((e) => e.validationDefinitions),
|
|
189
136
|
referencedFiles
|
|
190
137
|
};
|
|
191
138
|
};
|
|
@@ -200,22 +147,23 @@ var extractDefaultExport = (sourceFile) => {
|
|
|
200
147
|
return defaultExport;
|
|
201
148
|
};
|
|
202
149
|
var extractParamsRefinements = (callExpression) => {
|
|
203
|
-
const [
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
150
|
+
const [
|
|
151
|
+
_routeName,
|
|
152
|
+
// first generic - the route name
|
|
153
|
+
paramsGeneric
|
|
154
|
+
// second generic - params refinements
|
|
155
|
+
] = extractGenerics(callExpression);
|
|
156
|
+
if (!paramsGeneric?.isKind(SyntaxKind.TupleType)) {
|
|
209
157
|
return;
|
|
210
158
|
}
|
|
211
|
-
return
|
|
159
|
+
return paramsGeneric.getElements().map((node, index) => {
|
|
212
160
|
return {
|
|
213
161
|
index,
|
|
214
162
|
text: node.getText()
|
|
215
163
|
};
|
|
216
164
|
});
|
|
217
165
|
};
|
|
218
|
-
var extractRouteMethods = (
|
|
166
|
+
var extractRouteMethods = (route, callExpression) => {
|
|
219
167
|
const funcDeclaration = callExpression.getFirstChildByKind(SyntaxKind.ArrowFunction) || callExpression.getFirstChildByKind(SyntaxKind.FunctionExpression);
|
|
220
168
|
if (!funcDeclaration) {
|
|
221
169
|
return [];
|
|
@@ -236,35 +184,173 @@ var extractRouteMethods = (callExpression, route) => {
|
|
|
236
184
|
}
|
|
237
185
|
}
|
|
238
186
|
const methods = [];
|
|
239
|
-
const skipValidationFilter = (e) => /@skip-validation/.test(e);
|
|
240
187
|
for (const [callExpression2, method] of callExpressions) {
|
|
241
|
-
const [
|
|
242
|
-
const payloadText = payloadGeneric?.node ? payloadGeneric.node.getChildren().length === 0 ? "{}" : payloadGeneric.node.getFullText() : void 0;
|
|
243
|
-
const responseText = responseGeneric?.node.getText();
|
|
244
|
-
const responseType = responseText ? {
|
|
245
|
-
id: ["ResponseT", crc2(route.id + method)].join(""),
|
|
246
|
-
method,
|
|
247
|
-
skipValidation: responseGeneric?.comments ? responseGeneric.comments.some(skipValidationFilter) : false,
|
|
248
|
-
text: ["never", "object"].includes(responseText) ? "{}" : responseText,
|
|
249
|
-
resolvedType: void 0
|
|
250
|
-
} : void 0;
|
|
251
|
-
const payloadType = payloadText ? {
|
|
252
|
-
id: ["PayloadT", crc2(route.id + method)].join(""),
|
|
253
|
-
responseTypeId: responseType?.id,
|
|
254
|
-
method,
|
|
255
|
-
skipValidation: payloadGeneric?.comments ? payloadGeneric.comments.some(skipValidationFilter) : false,
|
|
256
|
-
isOptional: payloadText ? payloadText === "{}" || route.optionalParams : true,
|
|
257
|
-
text: payloadText,
|
|
258
|
-
resolvedType: void 0
|
|
259
|
-
} : void 0;
|
|
188
|
+
const [vDefs, vOpts] = extractGenerics(callExpression2);
|
|
260
189
|
methods.push({
|
|
261
190
|
method,
|
|
262
|
-
|
|
263
|
-
|
|
191
|
+
validationDefinitions: extractValidationDefinitions(
|
|
192
|
+
route,
|
|
193
|
+
method,
|
|
194
|
+
vDefs,
|
|
195
|
+
vOpts
|
|
196
|
+
)
|
|
264
197
|
});
|
|
265
198
|
}
|
|
266
199
|
return methods;
|
|
267
200
|
};
|
|
201
|
+
var parseRuntimeValidation = (typeNode) => {
|
|
202
|
+
if (typeNode.isKind(SyntaxKind.LiteralType)) {
|
|
203
|
+
const literal = typeNode.getFirstChild();
|
|
204
|
+
if (literal?.isKind(SyntaxKind.TrueKeyword)) {
|
|
205
|
+
return true;
|
|
206
|
+
} else if (literal?.isKind(SyntaxKind.FalseKeyword)) {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return void 0;
|
|
211
|
+
};
|
|
212
|
+
var extractResponseVariant = (typeNode) => {
|
|
213
|
+
if (!typeNode.isKind(SyntaxKind.TupleType)) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
let status = 200;
|
|
217
|
+
let contentType;
|
|
218
|
+
let body;
|
|
219
|
+
const [statusNode, contentTypeNode, bodyNode] = typeNode.getElements();
|
|
220
|
+
if (statusNode?.isKind(SyntaxKind.LiteralType)) {
|
|
221
|
+
const literal = statusNode.getFirstChildByKind(SyntaxKind.NumericLiteral);
|
|
222
|
+
if (literal) {
|
|
223
|
+
status = Number(literal.getText());
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (contentTypeNode) {
|
|
227
|
+
contentType = extractStringLiteral(contentTypeNode);
|
|
228
|
+
}
|
|
229
|
+
if (bodyNode) {
|
|
230
|
+
body = bodyNode.getText();
|
|
231
|
+
if (["object"].includes(body)) {
|
|
232
|
+
body = "{}";
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return { status, contentType, body };
|
|
236
|
+
};
|
|
237
|
+
var parseValidationOptions = (typeNode) => {
|
|
238
|
+
const opts = {};
|
|
239
|
+
if (!typeNode?.isKind(SyntaxKind.TypeLiteral)) {
|
|
240
|
+
return opts;
|
|
241
|
+
}
|
|
242
|
+
for (const prop of typeNode.getMembers()) {
|
|
243
|
+
if (!prop.isKind(SyntaxKind.PropertySignature)) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
const target = prop.getName();
|
|
247
|
+
const typeNode2 = prop.getTypeNodeOrThrow();
|
|
248
|
+
if (!typeNode2.isKind(SyntaxKind.TypeLiteral)) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
let contentType;
|
|
252
|
+
let runtimeValidation;
|
|
253
|
+
const customErrors = {};
|
|
254
|
+
for (const member of typeNode2.getMembers()) {
|
|
255
|
+
if (!member.isKind(SyntaxKind.PropertySignature)) {
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
const nameNode = member.getNameNode();
|
|
259
|
+
const valueNode = member.getTypeNodeOrThrow();
|
|
260
|
+
const name = nameNode.isKind(SyntaxKind.StringLiteral) ? nameNode.getLiteralText() : nameNode.getText();
|
|
261
|
+
if (name === "contentType") {
|
|
262
|
+
contentType = extractStringLiteral(valueNode);
|
|
263
|
+
} else if (name === "runtimeValidation") {
|
|
264
|
+
runtimeValidation = parseRuntimeValidation(valueNode);
|
|
265
|
+
} else if (name.startsWith("error")) {
|
|
266
|
+
const literal = extractStringLiteral(valueNode);
|
|
267
|
+
if (literal) {
|
|
268
|
+
customErrors[name] = literal;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
opts[target] = {
|
|
273
|
+
contentType,
|
|
274
|
+
runtimeValidation,
|
|
275
|
+
customErrors
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
return opts;
|
|
279
|
+
};
|
|
280
|
+
var extractStringLiteral = (typeNode) => {
|
|
281
|
+
const literal = typeNode.isKind(SyntaxKind.LiteralType) ? typeNode.getFirstChildByKind(SyntaxKind.StringLiteral) : void 0;
|
|
282
|
+
return literal ? literal.getLiteralText() : void 0;
|
|
283
|
+
};
|
|
284
|
+
var extractValidationDefinitions = (route, method, defsNode, optsNode) => {
|
|
285
|
+
const definitions = [];
|
|
286
|
+
if (!defsNode?.isKind(SyntaxKind.TypeLiteral)) {
|
|
287
|
+
return definitions;
|
|
288
|
+
}
|
|
289
|
+
const optsMap = parseValidationOptions(optsNode);
|
|
290
|
+
const createId = (target, hash) => {
|
|
291
|
+
return [
|
|
292
|
+
target.replace(/^./, (c) => c.toUpperCase()),
|
|
293
|
+
"T",
|
|
294
|
+
method,
|
|
295
|
+
crc(route.id + hash)
|
|
296
|
+
].join("");
|
|
297
|
+
};
|
|
298
|
+
for (const prop of defsNode.getMembers()) {
|
|
299
|
+
if (!prop.isKind(SyntaxKind.PropertySignature)) {
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
const target = prop.getName();
|
|
303
|
+
const typeNode = prop.getTypeNodeOrThrow();
|
|
304
|
+
if (target === "response") {
|
|
305
|
+
const variants = typeNode.isKind(SyntaxKind.UnionType) ? typeNode.getChildrenOfKind(SyntaxKind.TupleType) : [typeNode];
|
|
306
|
+
definitions.push({
|
|
307
|
+
...optsMap[target],
|
|
308
|
+
method,
|
|
309
|
+
target,
|
|
310
|
+
variants: variants.flatMap((e, i) => {
|
|
311
|
+
const { status, contentType, body } = extractResponseVariant(e) || {};
|
|
312
|
+
if (!status) {
|
|
313
|
+
return [];
|
|
314
|
+
}
|
|
315
|
+
if (contentType && typeof contentType !== "string") {
|
|
316
|
+
console.warn(
|
|
317
|
+
styleText(
|
|
318
|
+
["bold", "red"],
|
|
319
|
+
`\u2717 The second element of a response variant should specify the Response Content Type`
|
|
320
|
+
)
|
|
321
|
+
);
|
|
322
|
+
console.warn(
|
|
323
|
+
styleText(["blue"], ` Example: [200, "json", Schema]`)
|
|
324
|
+
);
|
|
325
|
+
console.warn(
|
|
326
|
+
` Route: ${route.name}; Method: ${method}; Response Variant: #${i}`
|
|
327
|
+
);
|
|
328
|
+
console.warn();
|
|
329
|
+
}
|
|
330
|
+
return [
|
|
331
|
+
{
|
|
332
|
+
id: createId(target, JSON.stringify([status, contentType, body])),
|
|
333
|
+
status,
|
|
334
|
+
contentType,
|
|
335
|
+
body
|
|
336
|
+
}
|
|
337
|
+
];
|
|
338
|
+
})
|
|
339
|
+
});
|
|
340
|
+
} else if (Object.keys(RequestValidationTargets).includes(target)) {
|
|
341
|
+
definitions.push({
|
|
342
|
+
...optsMap[target],
|
|
343
|
+
method,
|
|
344
|
+
target,
|
|
345
|
+
schema: {
|
|
346
|
+
id: createId(target),
|
|
347
|
+
text: typeNode.getText()
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return definitions;
|
|
353
|
+
};
|
|
268
354
|
var extractTypeDeclarations = (sourceFile, opts) => {
|
|
269
355
|
const declarations = [];
|
|
270
356
|
const referencedFiles = opts?.withReferencedFiles ? [] : void 0;
|
|
@@ -369,12 +455,7 @@ var getReferencedFiles = (importIdentifier) => {
|
|
|
369
455
|
});
|
|
370
456
|
};
|
|
371
457
|
var extractGenerics = (callExpression) => {
|
|
372
|
-
return callExpression.getTypeArguments()
|
|
373
|
-
return {
|
|
374
|
-
node,
|
|
375
|
-
comments: node.getLeadingCommentRanges().map((range) => range.getText().trim())
|
|
376
|
-
};
|
|
377
|
-
});
|
|
458
|
+
return callExpression.getTypeArguments();
|
|
378
459
|
};
|
|
379
460
|
var typeResolverFactory = ({ appRoot: appRoot2 }) => {
|
|
380
461
|
const project = createProject({
|
|
@@ -383,7 +464,7 @@ var typeResolverFactory = ({ appRoot: appRoot2 }) => {
|
|
|
383
464
|
});
|
|
384
465
|
const literalTypesResolver = (literalTypes, options) => {
|
|
385
466
|
const sourceFile = project.createSourceFile(
|
|
386
|
-
`${
|
|
467
|
+
`${crc(literalTypes)}-${Date.now()}.ts`,
|
|
387
468
|
literalTypes,
|
|
388
469
|
{ overwrite: true }
|
|
389
470
|
);
|
|
@@ -409,10 +490,23 @@ var typeResolverFactory = ({ appRoot: appRoot2 }) => {
|
|
|
409
490
|
};
|
|
410
491
|
|
|
411
492
|
// src/cache.ts
|
|
412
|
-
import { mkdir
|
|
413
|
-
import { dirname
|
|
414
|
-
import
|
|
493
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
494
|
+
import { dirname, resolve as resolve2 } from "node:path";
|
|
495
|
+
import crc2 from "crc/crc32";
|
|
415
496
|
import self from "@kosmojs/dev/package.json" with { type: "json" };
|
|
497
|
+
|
|
498
|
+
// src/fs.ts
|
|
499
|
+
import { access, constants } from "node:fs/promises";
|
|
500
|
+
var pathExists = async (path) => {
|
|
501
|
+
try {
|
|
502
|
+
await access(path, constants.F_OK);
|
|
503
|
+
return true;
|
|
504
|
+
} catch {
|
|
505
|
+
return false;
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
// src/cache.ts
|
|
416
510
|
var cacheFactory = (route, {
|
|
417
511
|
appRoot: appRoot2,
|
|
418
512
|
sourceFolder: sourceFolder2,
|
|
@@ -421,11 +515,11 @@ var cacheFactory = (route, {
|
|
|
421
515
|
const cacheFile = pathResolver({
|
|
422
516
|
appRoot: appRoot2,
|
|
423
517
|
sourceFolder: sourceFolder2
|
|
424
|
-
}).createPath.libApi(
|
|
518
|
+
}).createPath.libApi(dirname(route.file), "cache.json");
|
|
425
519
|
const getCache = async (opt) => {
|
|
426
520
|
if (await pathExists(cacheFile)) {
|
|
427
521
|
try {
|
|
428
|
-
const cache = JSON.parse(await
|
|
522
|
+
const cache = JSON.parse(await readFile(cacheFile, "utf8"));
|
|
429
523
|
return opt?.validate ? validateCache(cache) : cache;
|
|
430
524
|
} catch (_e) {
|
|
431
525
|
}
|
|
@@ -448,8 +542,8 @@ var cacheFactory = (route, {
|
|
|
448
542
|
] = await generateFileHash(file);
|
|
449
543
|
}
|
|
450
544
|
const cache = { ...rest, hash, referencedFiles };
|
|
451
|
-
await
|
|
452
|
-
await
|
|
545
|
+
await mkdir(dirname(cacheFile), { recursive: true });
|
|
546
|
+
await writeFile(cacheFile, JSON.stringify(cache, null, 2), "utf8");
|
|
453
547
|
return cache;
|
|
454
548
|
};
|
|
455
549
|
const validateCache = async (cache) => {
|
|
@@ -481,11 +575,11 @@ var cacheFactory = (route, {
|
|
|
481
575
|
var generateFileHash = async (file, extraContext) => {
|
|
482
576
|
let fileContent;
|
|
483
577
|
try {
|
|
484
|
-
fileContent = await
|
|
578
|
+
fileContent = await readFile(file, "utf8");
|
|
485
579
|
} catch (_e) {
|
|
486
580
|
return 0;
|
|
487
581
|
}
|
|
488
|
-
return fileContent ?
|
|
582
|
+
return fileContent ? crc2(
|
|
489
583
|
JSON.stringify({
|
|
490
584
|
...extraContext,
|
|
491
585
|
[self.cacheVersion]: fileContent
|
|
@@ -496,61 +590,167 @@ var identicalHashSum = (a, b) => {
|
|
|
496
590
|
return a === b;
|
|
497
591
|
};
|
|
498
592
|
|
|
593
|
+
// src/render.ts
|
|
594
|
+
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
595
|
+
import { dirname as dirname2, join as join2 } from "node:path";
|
|
596
|
+
import crc3 from "crc/crc32";
|
|
597
|
+
import handlebars from "handlebars";
|
|
598
|
+
var render = (template, context, options) => {
|
|
599
|
+
const { noEscape = true, renderer = handlebars } = { ...options };
|
|
600
|
+
return renderer.compile(template, { noEscape })(context);
|
|
601
|
+
};
|
|
602
|
+
var renderToFile = async (file, template, context, options) => {
|
|
603
|
+
const content = render(template, context, options);
|
|
604
|
+
if (await pathExists(file)) {
|
|
605
|
+
const { overwrite = true } = { ...options };
|
|
606
|
+
if (overwrite === false) {
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
const fileContent = await readFile2(file, "utf8");
|
|
610
|
+
if (typeof overwrite === "function" && !overwrite(fileContent)) {
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
if (crc3(content) === crc3(fileContent)) {
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
await mkdir2(dirname2(file), { recursive: true });
|
|
618
|
+
await writeFile2(file, content, "utf8");
|
|
619
|
+
};
|
|
620
|
+
|
|
499
621
|
// src/routes-factory/base.ts
|
|
500
622
|
import crc4 from "crc/crc32";
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
const
|
|
507
|
-
const
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
param
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
};
|
|
623
|
+
import { parse } from "path-to-regexp";
|
|
624
|
+
var pathTokensFactory = (path, {
|
|
625
|
+
transformStaticValue = normalizeStaticValue
|
|
626
|
+
} = {}) => {
|
|
627
|
+
const extractParts = (tokens2, createConst, insideGroup = false) => {
|
|
628
|
+
const parts = [];
|
|
629
|
+
for (const token of tokens2) {
|
|
630
|
+
switch (token.type) {
|
|
631
|
+
case "text":
|
|
632
|
+
if (token.value !== "/") {
|
|
633
|
+
parts.push({
|
|
634
|
+
type: "static",
|
|
635
|
+
value: transformStaticValue(token.value)
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
break;
|
|
639
|
+
case "param":
|
|
640
|
+
parts.push({
|
|
641
|
+
type: "param",
|
|
642
|
+
kind: insideGroup ? "optional" : "required",
|
|
643
|
+
name: token.name,
|
|
644
|
+
const: createConst(token.name)
|
|
645
|
+
});
|
|
646
|
+
break;
|
|
647
|
+
case "wildcard":
|
|
648
|
+
parts.push({
|
|
649
|
+
type: "param",
|
|
650
|
+
kind: "splat",
|
|
651
|
+
name: token.name,
|
|
652
|
+
const: createConst(token.name)
|
|
653
|
+
});
|
|
654
|
+
break;
|
|
655
|
+
case "group":
|
|
656
|
+
parts.push(...extractParts(token.tokens, createConst, true));
|
|
657
|
+
break;
|
|
537
658
|
}
|
|
538
659
|
}
|
|
539
|
-
return
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
660
|
+
return parts;
|
|
661
|
+
};
|
|
662
|
+
const patternTransforms = [
|
|
663
|
+
// Transform required params: [id] => :id
|
|
664
|
+
// Only pure \w param names,
|
|
665
|
+
// [some-id] used as is, not treated as param,
|
|
666
|
+
// use [some_id] instead.
|
|
667
|
+
(s) => s.replace(/\[(\w+)\]/g, ":$1"),
|
|
668
|
+
// Transform optional params: {id} => {:id}
|
|
669
|
+
// Only pure \w param names,
|
|
670
|
+
// anything else treated as a path-to-regexp pattern and used as is.
|
|
671
|
+
// {some-id} treated as an optional static segment.
|
|
672
|
+
// use {some_id} for simple param syntax
|
|
673
|
+
// or {:some-id} pattern where :some is the param name and -id is a static segment.
|
|
674
|
+
(s) => s.replace(/\{(\w+)\}/g, "{:$1}"),
|
|
675
|
+
// Transform splat params: {...param} => {*param}
|
|
676
|
+
(s) => s.replace(/\{\.\.\./g, "{*"),
|
|
677
|
+
// Insert leading slash inside optional/splat groups.
|
|
678
|
+
// {:name} => {/:name}
|
|
679
|
+
// {*name} => {/*name}
|
|
680
|
+
(s) => {
|
|
681
|
+
return s.startsWith("{") ? s.replace(/^\{/, "{/") : s;
|
|
682
|
+
}
|
|
683
|
+
];
|
|
684
|
+
const detectBareParams = (s) => {
|
|
685
|
+
let depth = 0;
|
|
686
|
+
for (const [i, ch] of [...s].entries()) {
|
|
687
|
+
if (ch === "{") {
|
|
688
|
+
depth += 1;
|
|
689
|
+
} else if (ch === "}") {
|
|
690
|
+
depth -= 1;
|
|
691
|
+
} else if (ch === ":" && depth === 0) {
|
|
692
|
+
const match = s.slice(i + 1).match(/^\w+/);
|
|
693
|
+
return match?.[0] || ":";
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
return;
|
|
697
|
+
};
|
|
698
|
+
const tokens = path.replace(/^index\/?/, "").split("/").flatMap((orig) => {
|
|
699
|
+
if (!orig.length) {
|
|
700
|
+
return [];
|
|
701
|
+
}
|
|
702
|
+
const bareParam = detectBareParams(orig);
|
|
703
|
+
if (bareParam === ":") {
|
|
704
|
+
throw new Error(
|
|
705
|
+
`${path} contains colons outside braces, use : only within {}`
|
|
706
|
+
);
|
|
707
|
+
} else if (bareParam) {
|
|
708
|
+
throw new Error(
|
|
709
|
+
`${path} contains bare params, use [${bareParam}] instead of :${bareParam}`
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
const pattern = patternTransforms.reduce((src, fn) => fn(src), orig);
|
|
713
|
+
const { tokens: tokens2 } = parse(pattern);
|
|
714
|
+
const parts = extractParts(tokens2, (val) => {
|
|
715
|
+
return /\W/.test(val) || /^\d/.test(val) ? [val.replace(/^\d+|\W/g, "_"), crc4(orig)].join("_") : val;
|
|
716
|
+
});
|
|
717
|
+
const isStatic = parts.length === 1 ? parts[0].type === "static" : false;
|
|
718
|
+
const isParam = parts.length === 1 ? parts[0].type === "param" : false;
|
|
719
|
+
const kind = isStatic ? "static" : isParam ? "param" : "mixed";
|
|
720
|
+
return [
|
|
721
|
+
{
|
|
722
|
+
kind,
|
|
723
|
+
orig,
|
|
724
|
+
pattern,
|
|
725
|
+
parts
|
|
726
|
+
}
|
|
727
|
+
];
|
|
546
728
|
});
|
|
729
|
+
return [
|
|
730
|
+
tokens,
|
|
731
|
+
tokens.map(({ pattern }, i) => {
|
|
732
|
+
const next = tokens[i + 1];
|
|
733
|
+
if (!next || next.pattern.includes("/")) {
|
|
734
|
+
return pattern;
|
|
735
|
+
}
|
|
736
|
+
const slashRequired = tokens.slice(i + 1).some((e) => {
|
|
737
|
+
return e.parts.some((e2) => {
|
|
738
|
+
return e2.type === "static" || e2.kind === "required";
|
|
739
|
+
});
|
|
740
|
+
});
|
|
741
|
+
return slashRequired ? `${pattern}/` : pattern;
|
|
742
|
+
}).join("")
|
|
743
|
+
];
|
|
744
|
+
};
|
|
745
|
+
var normalizeStaticValue = (value) => {
|
|
746
|
+
return value.replace(/\+/g, "\\\\+");
|
|
547
747
|
};
|
|
548
748
|
|
|
549
749
|
// src/routes-factory/templates/resolved-types.hbs
|
|
550
750
|
var resolved_types_default = "{{#each resolvedTypes}}\nexport type {{name}} = {{text}};\n{{/each}}\n";
|
|
551
751
|
|
|
552
752
|
// src/routes-factory/templates/types.hbs
|
|
553
|
-
var types_default = '{{#each typeDeclarations}}{{text}}\n{{/each}}\n\nexport type {{params.id}} = {\n {{#each paramsSchema}}\n "{{name}}"{{#unless isRequired}}?{{/unless}}:{{#if
|
|
753
|
+
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';
|
|
554
754
|
|
|
555
755
|
// src/routes-factory/resolve.ts
|
|
556
756
|
var API_INDEX_BASENAME = "index";
|
|
@@ -621,15 +821,18 @@ var createRouteEntry = (fileFullpath, {
|
|
|
621
821
|
return;
|
|
622
822
|
}
|
|
623
823
|
const [folder, file] = resolvedPaths;
|
|
624
|
-
const
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
folder,
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
824
|
+
const id = `${file.replace(/\W+/g, "_")}_${crc5(file)}`;
|
|
825
|
+
const name = dirname3(file);
|
|
826
|
+
try {
|
|
827
|
+
const [pathTokens, pathPattern] = pathTokensFactory(dirname3(file));
|
|
828
|
+
return { id, name, folder, file, fileFullpath, pathTokens, pathPattern };
|
|
829
|
+
} catch (error) {
|
|
830
|
+
console.error(
|
|
831
|
+
`\u2757${styleText2("red", "ERROR")}: Failed parsing path for "${styleText2("cyan", file)}"`
|
|
832
|
+
);
|
|
833
|
+
console.error(error);
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
633
836
|
};
|
|
634
837
|
var pageLayoutResolverFactory = () => {
|
|
635
838
|
return (entry) => {
|
|
@@ -645,14 +848,17 @@ var pageLayoutResolverFactory = () => {
|
|
|
645
848
|
};
|
|
646
849
|
var pageRouteResolverFactory = () => {
|
|
647
850
|
return (entry) => {
|
|
648
|
-
const { id, name, folder, file, fileFullpath, pathTokens } = entry;
|
|
851
|
+
const { id, name, folder, file, fileFullpath, pathTokens, pathPattern } = entry;
|
|
649
852
|
const handler = async () => {
|
|
650
853
|
const entry2 = {
|
|
651
854
|
id,
|
|
652
855
|
name,
|
|
653
856
|
pathTokens,
|
|
857
|
+
pathPattern,
|
|
654
858
|
params: {
|
|
655
|
-
schema: pathTokens.flatMap((e) =>
|
|
859
|
+
schema: pathTokens.flatMap((e) => {
|
|
860
|
+
return e.parts.filter((p) => p.type === "param");
|
|
861
|
+
})
|
|
656
862
|
},
|
|
657
863
|
folder,
|
|
658
864
|
file,
|
|
@@ -683,28 +889,33 @@ var apiRouteResolverFactory = (pluginOptions) => {
|
|
|
683
889
|
appRoot: appRoot2,
|
|
684
890
|
sourceFolder: sourceFolder2,
|
|
685
891
|
generators: generators2 = [],
|
|
686
|
-
formatters: formatters2 = [],
|
|
687
892
|
refineTypeName
|
|
688
893
|
} = pluginOptions;
|
|
689
|
-
|
|
690
|
-
for (const { options } of generators2) {
|
|
691
|
-
if (options?.resolveTypes) {
|
|
692
|
-
resolveTypes = true;
|
|
693
|
-
}
|
|
694
|
-
}
|
|
894
|
+
const resolveTypes = generators2.some((e) => e.options?.resolveTypes);
|
|
695
895
|
const {
|
|
696
896
|
//
|
|
697
897
|
literalTypesResolver,
|
|
698
898
|
getSourceFile,
|
|
699
899
|
refreshSourceFile
|
|
700
900
|
} = typeResolverFactory(pluginOptions);
|
|
701
|
-
return (
|
|
702
|
-
|
|
901
|
+
return ({
|
|
902
|
+
id,
|
|
903
|
+
name,
|
|
904
|
+
file,
|
|
905
|
+
folder,
|
|
906
|
+
fileFullpath,
|
|
907
|
+
pathTokens,
|
|
908
|
+
pathPattern
|
|
909
|
+
}) => {
|
|
703
910
|
const handler = async (updatedFile) => {
|
|
704
|
-
const paramsSchema = pathTokens.flatMap(
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
911
|
+
const paramsSchema = pathTokens.flatMap(
|
|
912
|
+
(e) => {
|
|
913
|
+
return e.parts.flatMap((p) => {
|
|
914
|
+
return p.type === "param" ? [p] : [];
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
);
|
|
918
|
+
const optionalParams = paramsSchema.length ? paramsSchema.filter((e) => e.kind === "required").length === 0 : true;
|
|
708
919
|
const { getCache, persistCache } = cacheFactory(
|
|
709
920
|
{ id, file, fileFullpath },
|
|
710
921
|
{
|
|
@@ -722,11 +933,10 @@ var apiRouteResolverFactory = (pluginOptions) => {
|
|
|
722
933
|
typeDeclarations,
|
|
723
934
|
paramsRefinements,
|
|
724
935
|
methods,
|
|
725
|
-
|
|
726
|
-
responseTypes,
|
|
936
|
+
validationDefinitions: validationDefinitions2,
|
|
727
937
|
referencedFiles = []
|
|
728
938
|
} = await resolveRouteSignature(
|
|
729
|
-
{ id, fileFullpath, optionalParams },
|
|
939
|
+
{ id, name, fileFullpath, optionalParams },
|
|
730
940
|
{
|
|
731
941
|
withReferencedFiles: true,
|
|
732
942
|
sourceFile: getSourceFile(fileFullpath),
|
|
@@ -735,6 +945,11 @@ var apiRouteResolverFactory = (pluginOptions) => {
|
|
|
735
945
|
}
|
|
736
946
|
}
|
|
737
947
|
);
|
|
948
|
+
const validationTypes = validationDefinitions2.flatMap((def) => {
|
|
949
|
+
return def.target === "response" ? def.variants.flatMap(({ id: id2, body }) => {
|
|
950
|
+
return body ? [{ id: id2, text: body }] : [];
|
|
951
|
+
}) : [def.schema];
|
|
952
|
+
});
|
|
738
953
|
const numericParams = paramsRefinements ? paramsRefinements.flatMap(({ text, index }) => {
|
|
739
954
|
if (text === "number") {
|
|
740
955
|
const param = paramsSchema.at(index);
|
|
@@ -756,25 +971,21 @@ var apiRouteResolverFactory = (pluginOptions) => {
|
|
|
756
971
|
paramsSchema: paramsSchema.map((param, index) => {
|
|
757
972
|
return {
|
|
758
973
|
...param,
|
|
974
|
+
isRequired: param.kind === "required",
|
|
975
|
+
isSplat: param.kind === "splat",
|
|
759
976
|
refinement: paramsRefinements?.at(index)
|
|
760
977
|
};
|
|
761
978
|
}),
|
|
762
979
|
typeDeclarations,
|
|
763
|
-
|
|
764
|
-
responseTypes
|
|
980
|
+
validationTypes
|
|
765
981
|
});
|
|
766
982
|
const resolvedTypes = resolveTypes ? literalTypesResolver(typesFileContent, {
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
},
|
|
774
|
-
{ [refineTypeName]: refineTypeName }
|
|
775
|
-
),
|
|
776
|
-
withProperties: [params.id, ...payloadTypes.map((e) => e.id)],
|
|
777
|
-
formatters: formatters2
|
|
983
|
+
stripComments: true,
|
|
984
|
+
overrides: { [refineTypeName]: refineTypeName },
|
|
985
|
+
withProperties: [
|
|
986
|
+
params.id,
|
|
987
|
+
...validationTypes.flatMap(({ id: id2 }) => id2)
|
|
988
|
+
]
|
|
778
989
|
}) : void 0;
|
|
779
990
|
await renderToFile(
|
|
780
991
|
typesFile,
|
|
@@ -787,26 +998,94 @@ var apiRouteResolverFactory = (pluginOptions) => {
|
|
|
787
998
|
methods,
|
|
788
999
|
typeDeclarations,
|
|
789
1000
|
numericParams,
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
return {
|
|
793
|
-
...rest,
|
|
794
|
-
resolvedType: resolvedTypes?.find((e) => e.name === rest.id)
|
|
795
|
-
};
|
|
796
|
-
}),
|
|
797
|
-
responseTypes: responseTypes.map(({ text, ...rest }) => {
|
|
1001
|
+
referencedFiles,
|
|
1002
|
+
validationDefinitions: validationDefinitions2.map((def) => {
|
|
798
1003
|
return {
|
|
799
|
-
...
|
|
800
|
-
|
|
1004
|
+
...def,
|
|
1005
|
+
...def.target === "response" ? {
|
|
1006
|
+
variants: def.variants.map((variant) => {
|
|
1007
|
+
return {
|
|
1008
|
+
...variant,
|
|
1009
|
+
resolvedType: resolvedTypes?.find(
|
|
1010
|
+
(e) => e.name === variant.id
|
|
1011
|
+
)
|
|
1012
|
+
};
|
|
1013
|
+
})
|
|
1014
|
+
} : {
|
|
1015
|
+
schema: {
|
|
1016
|
+
...def.schema,
|
|
1017
|
+
resolvedType: resolvedTypes?.find(
|
|
1018
|
+
(e) => e.name === def.schema.id
|
|
1019
|
+
)
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
801
1022
|
};
|
|
802
|
-
})
|
|
803
|
-
referencedFiles
|
|
1023
|
+
})
|
|
804
1024
|
});
|
|
805
1025
|
}
|
|
806
|
-
const
|
|
1026
|
+
const validationDefinitions = cache.validationDefinitions.flatMap(
|
|
1027
|
+
(def) => {
|
|
1028
|
+
let augmentedDef = def;
|
|
1029
|
+
if (def.target === "response") {
|
|
1030
|
+
augmentedDef = {
|
|
1031
|
+
...def,
|
|
1032
|
+
variants: def.variants.flatMap((variant, i) => {
|
|
1033
|
+
if (typeof variant.contentType !== "string") {
|
|
1034
|
+
return [variant];
|
|
1035
|
+
}
|
|
1036
|
+
if (variant.contentType.includes("/")) {
|
|
1037
|
+
return [variant];
|
|
1038
|
+
}
|
|
1039
|
+
const contentType = mimeTypes.lookup(variant.contentType);
|
|
1040
|
+
if (contentType === false) {
|
|
1041
|
+
console.warn(
|
|
1042
|
+
styleText2(
|
|
1043
|
+
["bold", "red"],
|
|
1044
|
+
"\u2717 Failed resolving Response Content Type"
|
|
1045
|
+
)
|
|
1046
|
+
);
|
|
1047
|
+
console.warn(
|
|
1048
|
+
` Invalid value provided for mime-types lookup - ${variant.contentType}`
|
|
1049
|
+
);
|
|
1050
|
+
console.warn(
|
|
1051
|
+
styleText2(
|
|
1052
|
+
["cyan"],
|
|
1053
|
+
` Response variant #${i} excluded from route schemas`
|
|
1054
|
+
)
|
|
1055
|
+
);
|
|
1056
|
+
console.warn(` Route: ${name}; Method: ${def.method}`);
|
|
1057
|
+
console.warn();
|
|
1058
|
+
return [];
|
|
1059
|
+
}
|
|
1060
|
+
return [{ ...variant, contentType }];
|
|
1061
|
+
})
|
|
1062
|
+
};
|
|
1063
|
+
} else if (def.contentType && !def.contentType.includes("/")) {
|
|
1064
|
+
const contentType = mimeTypes.lookup(def.contentType);
|
|
1065
|
+
if (contentType === false) {
|
|
1066
|
+
console.warn(
|
|
1067
|
+
styleText2(
|
|
1068
|
+
["bold", "red"],
|
|
1069
|
+
"\u2717 Failed resolving Response Content Type"
|
|
1070
|
+
)
|
|
1071
|
+
);
|
|
1072
|
+
console.warn(
|
|
1073
|
+
` Invalid value provided for mime-types lookup - ${def.contentType}`
|
|
1074
|
+
);
|
|
1075
|
+
console.warn(` Route: ${name}; Method: ${def.method}`);
|
|
1076
|
+
console.warn();
|
|
1077
|
+
} else {
|
|
1078
|
+
augmentedDef = { ...def, contentType };
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
return augmentedDef ? [augmentedDef] : [];
|
|
1082
|
+
}
|
|
1083
|
+
);
|
|
1084
|
+
const entry = {
|
|
807
1085
|
id,
|
|
808
1086
|
name,
|
|
809
1087
|
pathTokens,
|
|
1088
|
+
pathPattern,
|
|
810
1089
|
params: cache.params,
|
|
811
1090
|
numericParams: cache.numericParams,
|
|
812
1091
|
optionalParams,
|
|
@@ -815,8 +1094,7 @@ var apiRouteResolverFactory = (pluginOptions) => {
|
|
|
815
1094
|
fileFullpath,
|
|
816
1095
|
methods: cache.methods,
|
|
817
1096
|
typeDeclarations: cache.typeDeclarations,
|
|
818
|
-
|
|
819
|
-
responseTypes: cache.responseTypes,
|
|
1097
|
+
validationDefinitions,
|
|
820
1098
|
referencedFiles: Object.keys(cache.referencedFiles).map(
|
|
821
1099
|
// expand referenced files path,
|
|
822
1100
|
// they are stored as relative in cache
|
|
@@ -825,7 +1103,7 @@ var apiRouteResolverFactory = (pluginOptions) => {
|
|
|
825
1103
|
};
|
|
826
1104
|
return {
|
|
827
1105
|
kind: "apiRoute",
|
|
828
|
-
entry
|
|
1106
|
+
entry
|
|
829
1107
|
};
|
|
830
1108
|
};
|
|
831
1109
|
return { name, handler };
|
|
@@ -870,24 +1148,14 @@ var routesFactory = async (pluginOptions) => {
|
|
|
870
1148
|
};
|
|
871
1149
|
|
|
872
1150
|
// src/base-plugin/worker.ts
|
|
873
|
-
var {
|
|
874
|
-
//
|
|
875
|
-
generatorModules,
|
|
876
|
-
formatterModules,
|
|
877
|
-
...restOptions
|
|
878
|
-
} = workerData;
|
|
1151
|
+
var { generatorModules, ...restOptions } = workerData;
|
|
879
1152
|
var generators = [];
|
|
880
|
-
var formatters = [];
|
|
881
1153
|
for (const [path, opts] of generatorModules) {
|
|
882
1154
|
generators.push(await import(path).then((m) => m.default(opts)));
|
|
883
1155
|
}
|
|
884
|
-
for (const [path, opts] of formatterModules) {
|
|
885
|
-
formatters.push(await import(path).then((m) => m.default(opts).formatter));
|
|
886
|
-
}
|
|
887
1156
|
var resolvedOptions = {
|
|
888
1157
|
...restOptions,
|
|
889
|
-
generators
|
|
890
|
-
formatters
|
|
1158
|
+
generators
|
|
891
1159
|
};
|
|
892
1160
|
var { appRoot, sourceFolder } = resolvedOptions;
|
|
893
1161
|
var watchHandlers = [];
|