@kosmojs/fetch-generator 0.0.25 → 0.0.26
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/README.md +1 -1
- package/package.json +8 -7
- package/pkg/factory.d.ts +6 -2
- package/pkg/index.d.ts +1 -2
- package/pkg/index.js +18 -58
- package/pkg/index.js.map +3 -3
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@kosmojs/fetch-generator",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.26",
|
|
5
5
|
"author": "Slee Woo",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"publishConfig": {
|
|
@@ -14,11 +14,12 @@
|
|
|
14
14
|
".": {
|
|
15
15
|
"types": "./pkg/index.d.ts",
|
|
16
16
|
"default": "./pkg/index.js"
|
|
17
|
-
}
|
|
17
|
+
},
|
|
18
|
+
"./package.json": "./package.json"
|
|
18
19
|
},
|
|
19
20
|
"dependencies": {
|
|
20
|
-
"@kosmojs/api": "^0.0.
|
|
21
|
-
"@kosmojs/
|
|
21
|
+
"@kosmojs/api": "^0.0.26",
|
|
22
|
+
"@kosmojs/lib": "^0.0.26"
|
|
22
23
|
},
|
|
23
24
|
"devDependencies": {
|
|
24
25
|
"@types/mime-types": "^3.0.1",
|
|
@@ -27,9 +28,9 @@
|
|
|
27
28
|
"path-to-regexp": "^8.3.0",
|
|
28
29
|
"qs": "^6.15.0",
|
|
29
30
|
"typebox": "^1.1.6",
|
|
30
|
-
"@kosmojs/fetch": "^0.0.
|
|
31
|
-
"@kosmojs/koa-generator": "^0.0.
|
|
32
|
-
"@kosmojs/typebox-generator": "^0.0.
|
|
31
|
+
"@kosmojs/fetch": "^0.0.26",
|
|
32
|
+
"@kosmojs/koa-generator": "^0.0.26",
|
|
33
|
+
"@kosmojs/typebox-generator": "^0.0.26"
|
|
33
34
|
},
|
|
34
35
|
"scripts": {
|
|
35
36
|
"build": "esbuilder src/index.ts",
|
package/pkg/factory.d.ts
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
|
|
1
|
+
import { type ResolvedEntry } from "@kosmojs/lib";
|
|
2
|
+
declare const _default: (f: import("@kosmojs/lib").SourceFolder) => Promise<{
|
|
3
|
+
watch: import("@kosmojs/lib").WatchHandler;
|
|
4
|
+
build: (entries: Array<ResolvedEntry>) => Promise<void>;
|
|
5
|
+
}>;
|
|
6
|
+
export default _default;
|
package/pkg/index.d.ts
CHANGED
package/pkg/index.js
CHANGED
|
@@ -1,51 +1,16 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
name: "@kosmojs/fetch-generator",
|
|
5
|
-
version: "0.0.24",
|
|
6
|
-
author: "Slee Woo",
|
|
7
|
-
license: "MIT",
|
|
8
|
-
publishConfig: {
|
|
9
|
-
access: "public"
|
|
10
|
-
},
|
|
11
|
-
files: [
|
|
12
|
-
"pkg/*"
|
|
13
|
-
],
|
|
14
|
-
exports: {
|
|
15
|
-
".": {
|
|
16
|
-
types: "./pkg/index.d.ts",
|
|
17
|
-
default: "./pkg/index.js"
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
scripts: {
|
|
21
|
-
build: "esbuilder src/index.ts",
|
|
22
|
-
test: "vitest --root ../../.. --project generators/fetch-generator"
|
|
23
|
-
},
|
|
24
|
-
dependencies: {
|
|
25
|
-
"@kosmojs/api": "workspace:^",
|
|
26
|
-
"@kosmojs/dev": "workspace:^"
|
|
27
|
-
},
|
|
28
|
-
devDependencies: {
|
|
29
|
-
"@kosmojs/fetch": "workspace:^",
|
|
30
|
-
"@kosmojs/koa-generator": "workspace:^",
|
|
31
|
-
"@kosmojs/typebox-generator": "workspace:^",
|
|
32
|
-
"@types/mime-types": "^3.0.1",
|
|
33
|
-
"@types/qs": "^6.15.0",
|
|
34
|
-
"mime-types": "^3.0.2",
|
|
35
|
-
"path-to-regexp": "^8.3.0",
|
|
36
|
-
qs: "^6.15.0",
|
|
37
|
-
typebox: "^1.1.6"
|
|
38
|
-
}
|
|
39
|
-
};
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import self from "@kosmojs/fetch-generator/package.json" with { type: "json" };
|
|
3
|
+
import { defineGenerator } from "@kosmojs/lib";
|
|
40
4
|
|
|
41
5
|
// src/factory.ts
|
|
42
6
|
import { RequestValidationTargets } from "@kosmojs/api";
|
|
43
7
|
import {
|
|
8
|
+
defineGeneratorFactory,
|
|
44
9
|
pathResolver,
|
|
45
10
|
renderFactory,
|
|
46
11
|
renderHelpers,
|
|
47
12
|
sortRoutes
|
|
48
|
-
} from "@kosmojs/
|
|
13
|
+
} from "@kosmojs/lib";
|
|
49
14
|
|
|
50
15
|
// load-as-text:/volumes/studio/OpenSource/KosmoJS/Kosmo/packages/generators/fetch-generator/src/templates/@fetch/lib.ts
|
|
51
16
|
var lib_default = 'import { compile } from "path-to-regexp";\n\nexport const fetchClientFactory = <ParamsT extends Array<unknown>>(\n routeName: string,\n pathPattern: string,\n paramsMap: Array<[name: string, kind: string]>,\n numericParams: Array<string>,\n) => {\n const toPath = compile(pathPattern);\n\n const paramsMapper = (params: ParamsT) => {\n return paramsMap.reduce<Record<string, unknown>>((map, [name, kind], i) => {\n if (kind === "splat") {\n if (Array.isArray(params[i]) && params[i].length) {\n map[name] = numericParams.includes(name)\n ? params[i].map(Number)\n : params[i].map(String);\n }\n } else if (params[i] !== undefined) {\n map[name] = numericParams.includes(name)\n ? Number(params[i])\n : String(params[i]);\n }\n return map;\n }, {});\n };\n\n return {\n paramsMapper,\n parametrize(params: ParamsT) {\n try {\n return toPath(paramsMapper(params) as never);\n } catch (error: any) {\n console.error(`\u2757ERROR: Failed building path for ${routeName}`);\n console.error(error);\n return "";\n }\n },\n resolvePayload(payload: unknown, target: string) {\n const data = payload?.[target as never] as unknown;\n if (!data) {\n return data;\n }\n if (data instanceof FormData) {\n const obj: Record<\n string,\n FormDataEntryValue | Array<FormDataEntryValue>\n > = {};\n for (const [key, value] of data.entries()) {\n if (key in obj) {\n obj[key] = [obj[key]].flat().concat(value);\n } else {\n obj[key] = value;\n }\n }\n return obj;\n }\n return data;\n },\n };\n};\n';
|
|
@@ -60,11 +25,8 @@ var route_default = 'import fetchFactory, {\n type HostOpt,\n join,\n stringi
|
|
|
60
25
|
var unwrap_default = "export type MaybeWrapped<T> = T;\nexport const unwrap = <T>(data: T) => data;\n";
|
|
61
26
|
|
|
62
27
|
// src/factory.ts
|
|
63
|
-
var
|
|
64
|
-
const { createPath, createImportHelper } = pathResolver(
|
|
65
|
-
appRoot,
|
|
66
|
-
sourceFolder
|
|
67
|
-
});
|
|
28
|
+
var factory_default = defineGeneratorFactory(async (sourceFolder) => {
|
|
29
|
+
const { createPath, createImportHelper } = pathResolver(sourceFolder);
|
|
68
30
|
const { renderToFile } = renderFactory({
|
|
69
31
|
helpers: {
|
|
70
32
|
createImport: createImportHelper,
|
|
@@ -181,21 +143,19 @@ var factory = async ({ appRoot, sourceFolder }) => {
|
|
|
181
143
|
await generateLibFiles(entries, entries);
|
|
182
144
|
}
|
|
183
145
|
};
|
|
184
|
-
};
|
|
146
|
+
});
|
|
185
147
|
|
|
186
148
|
// src/index.ts
|
|
187
|
-
var index_default = () => {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
};
|
|
198
|
-
};
|
|
149
|
+
var index_default = defineGenerator(() => factory_default, {
|
|
150
|
+
name: "Fetch",
|
|
151
|
+
slot: "fetch",
|
|
152
|
+
dependencies: {
|
|
153
|
+
"path-to-regexp": self.devDependencies["path-to-regexp"]
|
|
154
|
+
},
|
|
155
|
+
devDependencies: {
|
|
156
|
+
"@kosmojs/fetch": self.version
|
|
157
|
+
}
|
|
158
|
+
});
|
|
199
159
|
export {
|
|
200
160
|
index_default as default
|
|
201
161
|
};
|
package/pkg/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../
|
|
4
|
-
"sourcesContent": ["{\n \"type\": \"module\",\n \"name\": \"@kosmojs/fetch-generator\",\n \"version\": \"0.0.24\",\n \"author\": \"Slee Woo\",\n \"license\": \"MIT\",\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"files\": [\n \"pkg/*\"\n ],\n \"exports\": {\n \".\": {\n \"types\": \"./pkg/index.d.ts\",\n \"default\": \"./pkg/index.js\"\n }\n },\n \"scripts\": {\n \"build\": \"esbuilder src/index.ts\",\n \"test\": \"vitest --root ../../.. --project generators/fetch-generator\"\n },\n \"dependencies\": {\n \"@kosmojs/api\": \"workspace:^\",\n \"@kosmojs/dev\": \"workspace:^\"\n },\n \"devDependencies\": {\n \"@kosmojs/fetch\": \"workspace:^\",\n \"@kosmojs/koa-generator\": \"workspace:^\",\n \"@kosmojs/typebox-generator\": \"workspace:^\",\n \"@types/mime-types\": \"^3.0.1\",\n \"@types/qs\": \"^6.15.0\",\n \"mime-types\": \"^3.0.2\",\n \"path-to-regexp\": \"^8.3.0\",\n \"qs\": \"^6.15.0\",\n \"typebox\": \"^1.1.6\"\n }\n}\n", "import { RequestValidationTargets, type ValidationTarget } from \"@kosmojs/api\";\nimport {\n type GeneratorFactory,\n pathResolver,\n type ResolvedEntry,\n renderFactory,\n renderHelpers,\n sortRoutes,\n} from \"@kosmojs/dev\";\n\nimport fetchLibTpl from \"./templates/@fetch/lib.ts?as=text\";\nimport fetchTpl from \"./templates/fetch.hbs\";\nimport routeTpl from \"./templates/route.hbs\";\nimport unwrapTpl from \"./templates/unwrap.hbs\";\n\nexport const factory: GeneratorFactory = async ({ appRoot, sourceFolder }) => {\n const { createPath, createImportHelper } = pathResolver({\n appRoot,\n sourceFolder,\n });\n\n const { renderToFile } = renderFactory({\n helpers: {\n createImport: createImportHelper,\n createParamsLiteral: renderHelpers.createParamsLiteral,\n },\n });\n\n // supposed to be replaced by specialized generators, write it only at initialization.\n // fetch generator always runs before other generators\n // so it is safe to re-initialize this file before specialized generators update it.\n await renderToFile(createPath.lib(\"unwrap.ts\"), unwrapTpl, {});\n\n const generateLibFiles = async (\n entries: Array<ResolvedEntry>,\n updatedEntries: Array<ResolvedEntry>,\n ) => {\n const routes = entries\n .flatMap(({ kind, entry }) => (kind === \"apiRoute\" ? [entry] : []))\n .sort(sortRoutes);\n\n for (const [file, template] of [\n [\"fetch.ts\", fetchTpl],\n [\"@fetch/lib.ts\", fetchLibTpl],\n ]) {\n await renderToFile(createPath.lib(file), template, {\n routes,\n });\n }\n\n for (const { kind, entry } of updatedEntries) {\n if (kind === \"apiRoute\") {\n const validationTypes: Array<{\n id: string;\n target: ValidationTarget;\n method: string;\n resolvedType: unknown;\n }> = [];\n\n for (const def of entry.validationDefinitions) {\n if (def.target === \"response\") {\n for (const { id, body, resolvedType } of def.variants) {\n if (body) {\n validationTypes.push({\n id,\n target: def.target,\n method: def.method,\n resolvedType,\n });\n }\n }\n } else {\n const { id, resolvedType } = def.schema;\n validationTypes.push({\n id,\n target: def.target,\n method: def.method,\n resolvedType,\n });\n }\n }\n\n const routeMethods = entry.methods.map((method) => {\n return {\n method,\n responseType: validationTypes.find((e) => {\n return e.target === \"response\" ? e.method === method : false;\n }),\n };\n });\n\n const payloadTypes = Object.entries(\n validationTypes.reduce<\n Record<string, Array<(typeof validationTypes)[number]>>\n >((map, { id, target, method, resolvedType }) => {\n if (target !== \"response\") {\n const key = `${target.replace(/^./, (c) => c.toUpperCase())}T`;\n if (!map[key]) {\n map[key] = [];\n }\n map[key].push({ id, target, method, resolvedType });\n }\n return map;\n }, {}),\n ).map(([name, types]) => {\n return { name, types, target: types[0].target };\n });\n\n const payloadTargets = Object.keys(RequestValidationTargets).map(\n (target) => {\n const payloadType = payloadTypes.find((e) => e.target === target);\n return {\n target,\n payloadType,\n };\n },\n );\n\n const responseTypes = Object.values(\n validationTypes.reduce<\n Record<\n string,\n { method: string; types: Array<(typeof validationTypes)[number]> }\n >\n >((map, { id, target, method, resolvedType }) => {\n if (target === \"response\") {\n if (!map[method]) {\n map[method] = { method, types: [] };\n }\n map[method].types.push({ id, target, method, resolvedType });\n }\n return map;\n }, {}),\n );\n\n await renderToFile(\n createPath.libApi(entry.name, \"fetch.ts\"),\n routeTpl,\n {\n route: entry,\n validationTypes,\n routeMethods,\n payloadTypes,\n payloadTargets,\n responseTypes,\n },\n );\n }\n }\n };\n\n return {\n async watch(entries, event) {\n await generateLibFiles(\n entries,\n // create/overwrite lib files with proper content.\n // handle 2 cases:\n // - event is undefined (means initial call): process all routes\n // - `update` event given: process updated route\n event\n ? entries.filter(({ kind, entry }) => {\n return event.kind === \"update\"\n ? kind === \"apiRoute\"\n ? entry.fileFullpath === event.file\n : false\n : false;\n })\n : entries,\n );\n\n // TODO: handle `delete` event, cleanup lib files\n },\n async build(entries) {\n await generateLibFiles(entries, entries);\n },\n };\n};\n", "import { compile } from \"path-to-regexp\";\n\nexport const fetchClientFactory = <ParamsT extends Array<unknown>>(\n routeName: string,\n pathPattern: string,\n paramsMap: Array<[name: string, kind: string]>,\n numericParams: Array<string>,\n) => {\n const toPath = compile(pathPattern);\n\n const paramsMapper = (params: ParamsT) => {\n return paramsMap.reduce<Record<string, unknown>>((map, [name, kind], i) => {\n if (kind === \"splat\") {\n if (Array.isArray(params[i]) && params[i].length) {\n map[name] = numericParams.includes(name)\n ? params[i].map(Number)\n : params[i].map(String);\n }\n } else if (params[i] !== undefined) {\n map[name] = numericParams.includes(name)\n ? Number(params[i])\n : String(params[i]);\n }\n return map;\n }, {});\n };\n\n return {\n paramsMapper,\n parametrize(params: ParamsT) {\n try {\n return toPath(paramsMapper(params) as never);\n } catch (error: any) {\n console.error(`\u2757ERROR: Failed building path for ${routeName}`);\n console.error(error);\n return \"\";\n }\n },\n resolvePayload(payload: unknown, target: string) {\n const data = payload?.[target as never] as unknown;\n if (!data) {\n return data;\n }\n if (data instanceof FormData) {\n const obj: Record<\n string,\n FormDataEntryValue | Array<FormDataEntryValue>\n > = {};\n for (const [key, value] of data.entries()) {\n if (key in obj) {\n obj[key] = [obj[key]].flat().concat(value);\n } else {\n obj[key] = value;\n }\n }\n return obj;\n }\n return data;\n },\n };\n};\n", "{{#each routes}}\nimport * as {{id}} from \"{{ createImport \"libApi\" name \"fetch\" }}\";\n{{/each}}\n\nexport { ValidationError } from \"@kosmojs/api/errors\";\n\nexport type ResponseT = {\n{{#each routes}} \"{{name}}\": {{id}}.ResponseT;\n{{/each}}\n}\n\nexport default {\n{{#each routes}} \"{{name}}\": {{id}},\n{{#each alias }} \"{{this}}\": {{../id}},\n{{/each}}\n{{/each}}\n}\n", "import fetchFactory, {\n type HostOpt,\n join,\n stringify,\n createHost,\n} from \"@kosmojs/fetch\";\n\nimport { baseurl, apiurl } from \"{{ createImport \"config\" }}\";\n\nimport {\n type MaybeWrapped,\n unwrap,\n} from \"{{ createImport \"lib\" \"unwrap\" }}\";\n\nimport { fetchClientFactory } from \"{{ createImport \"lib\" \"@fetch/lib\" }}\";\n\n{{#each validationTypes}}\nimport type { {{id}} } from \"./types\";\n{{/each}}\n\nimport { validationSchemas } from \"./schemas\";\n\nexport { ValidationError } from \"@kosmojs/api/errors\";\n\nexport { validationSchemas };\n\nexport type ParamsT = [\n {{createParamsLiteral route.params}}\n];\n\n{{#each payloadTypes}}\nexport type {{name}} = {\n {{#each types}}{{method}}: {{id}};\n {{/each}}\n}\n{{/each}}\n\nexport type ResponseT = {\n {{#each responseTypes}}\n {{method}}: {{#each types}}{{#unless @first}}|{{/unless}} {{id}}{{/each}};\n {{/each}}\n}\n\nconst {\n paramsMapper,\n parametrize,\n resolvePayload,\n} = fetchClientFactory(\n \"{{route.name}}\",\n \"{{route.pathPattern}}\",\n [{{#each route.params.schema}}[\"{{name}}\", \"{{kind}}\"], {{/each}}],\n [{{#each route.numericParams}}\"{{.}}\", {{/each}}],\n);\n\nconst fetchApi = fetchFactory(join(baseurl, apiurl), { stringify });\n\n{{#each routeMethods}}\nexport const {{method}} = (\n _params{{#if ../route.optionalParams}}?{{/if}}: MaybeWrapped<ParamsT>,\n _payload?: {\n {{#each ../payloadTargets}}\n {{#if payloadType}}\n {{target}}: {{payloadType.name}} extends { {{../method}}: unknown }\n ? MaybeWrapped<{{payloadType.name}}[\"{{../method}}\"]>\n : unknown,\n {{else}}\n {{target}}?: unknown;\n {{/if}}\n {{/each}}\n },\n opt?: {\n unwrap?: <T>(data: MaybeWrapped<T>) => T;\n },\n): Promise<\n {{#if responseType}}\n ResponseT[\"{{method}}\"]\n {{else}}\n unknown\n {{/if}}\n> => {\n const [params, payload] = [_params, _payload].map((data) => {\n return typeof opt?.unwrap === \"function\" ? opt.unwrap(data) : unwrap(data);\n })\n if (validationSchemas.params) {\n validationSchemas.params.validate(paramsMapper(params as never));\n }\n {{#each ../payloadTypes}}\n if (validationSchemas.{{target}}?.{{../method}}) {\n validationSchemas.{{target}}.{{../method}}.validate(\n resolvePayload(payload, \"{{target}}\")\n );\n }\n {{/each}}\n return fetchApi.{{method}}(parametrize(params as never), payload as never);\n};\n{{/each}}\n\nexport const path = (\n params: ParamsT,\n query?: Record<string, unknown>,\n) => {\n const path = join(\n baseurl,\n {{#if route.base}}\"{{route.base}}\"{{else}}apiurl{{/if}},\n parametrize(params)\n );\n return query\n ? [ path, stringify(query) ].join(\"?\")\n : path;\n}\n\nexport const href = (\n host: HostOpt,\n params: ParamsT,\n query?: Record<string, unknown>,\n) => createHost(host) + path(params, query);\n\nexport default {\n {{#each routeMethods}}\n {{method}},\n {{/each}}\n path,\n href,\n {{#if runtimeValidation}}\n validationSchemas,\n {{/if}}\n};\n", "export type MaybeWrapped<T> = T;\nexport const unwrap = <T>(data: T) => data;\n", "import type { GeneratorConstructor } from \"@kosmojs/dev\";\n\nimport self from \"../package.json\" with { type: \"json\" };\nimport { factory } from \"./factory\";\n\nexport default (): GeneratorConstructor => {\n return {\n name: \"Fetch\",\n slot: \"fetch\",\n moduleImport: import.meta.filename,\n moduleConfig: undefined,\n factory,\n dependencies: {\n \"path-to-regexp\": self.devDependencies[\"path-to-regexp\"],\n },\n };\n};\n"],
|
|
5
|
-
"mappings": ";
|
|
3
|
+
"sources": ["../src/index.ts", "../src/factory.ts", "load-as-text:/volumes/studio/OpenSource/KosmoJS/Kosmo/packages/generators/fetch-generator/src/templates/@fetch/lib.ts", "../src/templates/fetch.hbs", "../src/templates/route.hbs", "../src/templates/unwrap.hbs"],
|
|
4
|
+
"sourcesContent": ["/**\n * Import from published package to ensure correct version at runtime.\n * Local import would be bundled with pre-bump version.\n * */\nimport self from \"@kosmojs/fetch-generator/package.json\" with { type: \"json\" };\nimport { defineGenerator } from \"@kosmojs/lib\";\n\nimport factory from \"./factory\";\n\nexport default defineGenerator(() => factory, {\n name: \"Fetch\",\n slot: \"fetch\",\n dependencies: {\n \"path-to-regexp\": self.devDependencies[\"path-to-regexp\"],\n },\n devDependencies: {\n \"@kosmojs/fetch\": self.version,\n },\n});\n", "import { RequestValidationTargets, type ValidationTarget } from \"@kosmojs/api\";\nimport {\n defineGeneratorFactory,\n pathResolver,\n type ResolvedEntry,\n renderFactory,\n renderHelpers,\n sortRoutes,\n} from \"@kosmojs/lib\";\n\nimport fetchLibTpl from \"./templates/@fetch/lib.ts?as=text\";\nimport fetchTpl from \"./templates/fetch.hbs\";\nimport routeTpl from \"./templates/route.hbs\";\nimport unwrapTpl from \"./templates/unwrap.hbs\";\n\nexport default defineGeneratorFactory(async (sourceFolder) => {\n const { createPath, createImportHelper } = pathResolver(sourceFolder);\n\n const { renderToFile } = renderFactory({\n helpers: {\n createImport: createImportHelper,\n createParamsLiteral: renderHelpers.createParamsLiteral,\n },\n });\n\n // supposed to be replaced by specialized generators, write it only at initialization.\n // fetch generator always runs before other generators\n // so it is safe to re-initialize this file before specialized generators update it.\n await renderToFile(createPath.lib(\"unwrap.ts\"), unwrapTpl, {});\n\n const generateLibFiles = async (\n entries: Array<ResolvedEntry>,\n updatedEntries: Array<ResolvedEntry>,\n ) => {\n const routes = entries\n .flatMap(({ kind, entry }) => (kind === \"apiRoute\" ? [entry] : []))\n .sort(sortRoutes);\n\n for (const [file, template] of [\n [\"fetch.ts\", fetchTpl],\n [\"@fetch/lib.ts\", fetchLibTpl],\n ]) {\n await renderToFile(createPath.lib(file), template, {\n routes,\n });\n }\n\n for (const { kind, entry } of updatedEntries) {\n if (kind === \"apiRoute\") {\n const validationTypes: Array<{\n id: string;\n target: ValidationTarget;\n method: string;\n resolvedType: unknown;\n }> = [];\n\n for (const def of entry.validationDefinitions) {\n if (def.target === \"response\") {\n for (const { id, body, resolvedType } of def.variants) {\n if (body) {\n validationTypes.push({\n id,\n target: def.target,\n method: def.method,\n resolvedType,\n });\n }\n }\n } else {\n const { id, resolvedType } = def.schema;\n validationTypes.push({\n id,\n target: def.target,\n method: def.method,\n resolvedType,\n });\n }\n }\n\n const routeMethods = entry.methods.map((method) => {\n return {\n method,\n responseType: validationTypes.find((e) => {\n return e.target === \"response\" ? e.method === method : false;\n }),\n };\n });\n\n const payloadTypes = Object.entries(\n validationTypes.reduce<\n Record<string, Array<(typeof validationTypes)[number]>>\n >((map, { id, target, method, resolvedType }) => {\n if (target !== \"response\") {\n const key = `${target.replace(/^./, (c) => c.toUpperCase())}T`;\n if (!map[key]) {\n map[key] = [];\n }\n map[key].push({ id, target, method, resolvedType });\n }\n return map;\n }, {}),\n ).map(([name, types]) => {\n return { name, types, target: types[0].target };\n });\n\n const payloadTargets = Object.keys(RequestValidationTargets).map(\n (target) => {\n const payloadType = payloadTypes.find((e) => e.target === target);\n return {\n target,\n payloadType,\n };\n },\n );\n\n const responseTypes = Object.values(\n validationTypes.reduce<\n Record<\n string,\n { method: string; types: Array<(typeof validationTypes)[number]> }\n >\n >((map, { id, target, method, resolvedType }) => {\n if (target === \"response\") {\n if (!map[method]) {\n map[method] = { method, types: [] };\n }\n map[method].types.push({ id, target, method, resolvedType });\n }\n return map;\n }, {}),\n );\n\n await renderToFile(\n createPath.libApi(entry.name, \"fetch.ts\"),\n routeTpl,\n {\n route: entry,\n validationTypes,\n routeMethods,\n payloadTypes,\n payloadTargets,\n responseTypes,\n },\n );\n }\n }\n };\n\n return {\n async watch(entries, event) {\n await generateLibFiles(\n entries,\n // create/overwrite lib files with proper content.\n // handle 2 cases:\n // - event is undefined (means initial call): process all routes\n // - `update` event given: process updated route\n event\n ? entries.filter(({ kind, entry }) => {\n return event.kind === \"update\"\n ? kind === \"apiRoute\"\n ? entry.fileFullpath === event.file\n : false\n : false;\n })\n : entries,\n );\n\n // TODO: handle `delete` event, cleanup lib files\n },\n async build(entries) {\n await generateLibFiles(entries, entries);\n },\n };\n});\n", "import { compile } from \"path-to-regexp\";\n\nexport const fetchClientFactory = <ParamsT extends Array<unknown>>(\n routeName: string,\n pathPattern: string,\n paramsMap: Array<[name: string, kind: string]>,\n numericParams: Array<string>,\n) => {\n const toPath = compile(pathPattern);\n\n const paramsMapper = (params: ParamsT) => {\n return paramsMap.reduce<Record<string, unknown>>((map, [name, kind], i) => {\n if (kind === \"splat\") {\n if (Array.isArray(params[i]) && params[i].length) {\n map[name] = numericParams.includes(name)\n ? params[i].map(Number)\n : params[i].map(String);\n }\n } else if (params[i] !== undefined) {\n map[name] = numericParams.includes(name)\n ? Number(params[i])\n : String(params[i]);\n }\n return map;\n }, {});\n };\n\n return {\n paramsMapper,\n parametrize(params: ParamsT) {\n try {\n return toPath(paramsMapper(params) as never);\n } catch (error: any) {\n console.error(`\u2757ERROR: Failed building path for ${routeName}`);\n console.error(error);\n return \"\";\n }\n },\n resolvePayload(payload: unknown, target: string) {\n const data = payload?.[target as never] as unknown;\n if (!data) {\n return data;\n }\n if (data instanceof FormData) {\n const obj: Record<\n string,\n FormDataEntryValue | Array<FormDataEntryValue>\n > = {};\n for (const [key, value] of data.entries()) {\n if (key in obj) {\n obj[key] = [obj[key]].flat().concat(value);\n } else {\n obj[key] = value;\n }\n }\n return obj;\n }\n return data;\n },\n };\n};\n", "{{#each routes}}\nimport * as {{id}} from \"{{ createImport \"libApi\" name \"fetch\" }}\";\n{{/each}}\n\nexport { ValidationError } from \"@kosmojs/api/errors\";\n\nexport type ResponseT = {\n{{#each routes}} \"{{name}}\": {{id}}.ResponseT;\n{{/each}}\n}\n\nexport default {\n{{#each routes}} \"{{name}}\": {{id}},\n{{#each alias }} \"{{this}}\": {{../id}},\n{{/each}}\n{{/each}}\n}\n", "import fetchFactory, {\n type HostOpt,\n join,\n stringify,\n createHost,\n} from \"@kosmojs/fetch\";\n\nimport { baseurl, apiurl } from \"{{ createImport \"config\" }}\";\n\nimport {\n type MaybeWrapped,\n unwrap,\n} from \"{{ createImport \"lib\" \"unwrap\" }}\";\n\nimport { fetchClientFactory } from \"{{ createImport \"lib\" \"@fetch/lib\" }}\";\n\n{{#each validationTypes}}\nimport type { {{id}} } from \"./types\";\n{{/each}}\n\nimport { validationSchemas } from \"./schemas\";\n\nexport { ValidationError } from \"@kosmojs/api/errors\";\n\nexport { validationSchemas };\n\nexport type ParamsT = [\n {{createParamsLiteral route.params}}\n];\n\n{{#each payloadTypes}}\nexport type {{name}} = {\n {{#each types}}{{method}}: {{id}};\n {{/each}}\n}\n{{/each}}\n\nexport type ResponseT = {\n {{#each responseTypes}}\n {{method}}: {{#each types}}{{#unless @first}}|{{/unless}} {{id}}{{/each}};\n {{/each}}\n}\n\nconst {\n paramsMapper,\n parametrize,\n resolvePayload,\n} = fetchClientFactory(\n \"{{route.name}}\",\n \"{{route.pathPattern}}\",\n [{{#each route.params.schema}}[\"{{name}}\", \"{{kind}}\"], {{/each}}],\n [{{#each route.numericParams}}\"{{.}}\", {{/each}}],\n);\n\nconst fetchApi = fetchFactory(join(baseurl, apiurl), { stringify });\n\n{{#each routeMethods}}\nexport const {{method}} = (\n _params{{#if ../route.optionalParams}}?{{/if}}: MaybeWrapped<ParamsT>,\n _payload?: {\n {{#each ../payloadTargets}}\n {{#if payloadType}}\n {{target}}: {{payloadType.name}} extends { {{../method}}: unknown }\n ? MaybeWrapped<{{payloadType.name}}[\"{{../method}}\"]>\n : unknown,\n {{else}}\n {{target}}?: unknown;\n {{/if}}\n {{/each}}\n },\n opt?: {\n unwrap?: <T>(data: MaybeWrapped<T>) => T;\n },\n): Promise<\n {{#if responseType}}\n ResponseT[\"{{method}}\"]\n {{else}}\n unknown\n {{/if}}\n> => {\n const [params, payload] = [_params, _payload].map((data) => {\n return typeof opt?.unwrap === \"function\" ? opt.unwrap(data) : unwrap(data);\n })\n if (validationSchemas.params) {\n validationSchemas.params.validate(paramsMapper(params as never));\n }\n {{#each ../payloadTypes}}\n if (validationSchemas.{{target}}?.{{../method}}) {\n validationSchemas.{{target}}.{{../method}}.validate(\n resolvePayload(payload, \"{{target}}\")\n );\n }\n {{/each}}\n return fetchApi.{{method}}(parametrize(params as never), payload as never);\n};\n{{/each}}\n\nexport const path = (\n params: ParamsT,\n query?: Record<string, unknown>,\n) => {\n const path = join(\n baseurl,\n {{#if route.base}}\"{{route.base}}\"{{else}}apiurl{{/if}},\n parametrize(params)\n );\n return query\n ? [ path, stringify(query) ].join(\"?\")\n : path;\n}\n\nexport const href = (\n host: HostOpt,\n params: ParamsT,\n query?: Record<string, unknown>,\n) => createHost(host) + path(params, query);\n\nexport default {\n {{#each routeMethods}}\n {{method}},\n {{/each}}\n path,\n href,\n {{#if runtimeValidation}}\n validationSchemas,\n {{/if}}\n};\n", "export type MaybeWrapped<T> = T;\nexport const unwrap = <T>(data: T) => data;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|