@kosmojs/fetch-generator 0.0.11 → 0.0.21

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-present, Slee Woo and KosmoJS contributors.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@kosmojs/fetch-generator",
4
- "version": "0.0.11",
4
+ "version": "0.0.21",
5
5
  "author": "Slee Woo",
6
6
  "license": "MIT",
7
7
  "publishConfig": {
@@ -12,17 +12,27 @@
12
12
  ],
13
13
  "exports": {
14
14
  ".": {
15
- "types": "./pkg/src/index.d.ts",
15
+ "types": "./pkg/index.d.ts",
16
16
  "default": "./pkg/index.js"
17
17
  }
18
18
  },
19
19
  "dependencies": {
20
- "@kosmojs/devlib": "^0.0.11"
20
+ "@kosmojs/dev": "^0.0.21"
21
21
  },
22
22
  "devDependencies": {
23
- "@kosmojs/config": "^0.0.11"
23
+ "@types/mime-types": "^3.0.1",
24
+ "@types/qs": "^6.15.0",
25
+ "mime-types": "^3.0.2",
26
+ "path-to-regexp": "^8.3.0",
27
+ "qs": "^6.15.0",
28
+ "typebox": "^1.1.6",
29
+ "@kosmojs/api": "^0.0.21",
30
+ "@kosmojs/fetch": "^0.0.21",
31
+ "@kosmojs/koa-generator": "^0.0.21",
32
+ "@kosmojs/typebox-generator": "^0.0.21"
24
33
  },
25
34
  "scripts": {
26
- "build": "esbuilder src/index.ts"
35
+ "build": "esbuilder src/index.ts",
36
+ "test": "vitest --root ../../.. --project generators/fetch-generator"
27
37
  }
28
38
  }
@@ -0,0 +1,2 @@
1
+ import { type GeneratorFactory } from "@kosmojs/dev";
2
+ export declare const factory: GeneratorFactory;
@@ -1,3 +1,3 @@
1
- import type { GeneratorConstructor } from "@kosmojs/devlib";
1
+ import type { GeneratorConstructor } from "@kosmojs/dev";
2
2
  declare const _default: () => GeneratorConstructor;
3
3
  export default _default;
package/pkg/index.js CHANGED
@@ -1,126 +1,184 @@
1
+ // package.json
2
+ var package_default = {
3
+ type: "module",
4
+ name: "@kosmojs/fetch-generator",
5
+ version: "0.0.20",
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/dev": "workspace:^"
26
+ },
27
+ devDependencies: {
28
+ "@kosmojs/api": "workspace:^",
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
+ };
40
+
1
41
  // src/factory.ts
2
- import { dirname, join } from "node:path";
42
+ import { RequestValidationTargets } from "@kosmojs/api";
3
43
  import {
4
- defaults,
5
44
  pathResolver,
6
- renderToFile
7
- } from "@kosmojs/devlib";
45
+ renderFactory,
46
+ renderHelpers,
47
+ sortRoutes
48
+ } from "@kosmojs/dev";
8
49
 
9
- // src/templates/fetch.hbs
10
- var fetch_default = 'import useFetch from "@kosmojs/fetch";\n\nimport { baseurl, apiurl } from "{{importPathmap.config}}";\nimport { validationSchemas } from "./schemas";\n\nimport {\n type MaybeWrapped,\n type HostOpt,\n unwrap,\n join,\n stringify,\n createHost,\n} from "{{importPathmap.fetchLib}}";\n\nexport { ValidationError } from "@kosmojs/api";\n\nexport type ParamsT = [\n {{#each route.params.schema}}\n {{#if isRest}}\n ...{{const}}: Array<string | number>\n {{else}}\n {{const}}{{#unless isRequired}}?{{/unless}}: import("./types").{{../route.params.id}}["{{name}}"],\n {{/if}}\n {{/each}}\n];\n\nexport type PayloadT = {\n {{#each route.payloadTypes}}\n {{method}}: import("./types").{{id}};\n {{/each}}\n}\n\nexport type ResponseT = {\n {{#each route.responseTypes}}\n {{method}}: import("./types").{{id}};\n {{/each}}\n}\n\nconst paramsMapper = (params: ParamsT) => {\n return {\n {{#each paramsMapper}}\n "{{name}}": params[{{idx}}],\n {{/each}}\n }\n}\n\nconst pathTokens: Array<[ path: string, param?: { isRest: boolean } ]> = [\n {{#each route.pathTokens}}\n [\n "{{path}}",{{#if param}}\n { isRest: {{#if param.isRest}}true{{else}}false{{/if}} }{{/if}}\n ],\n {{/each}}\n];\n\nconst parametrize = (params: ParamsT) => {\n const paramsClone = structuredClone(params);\n return pathTokens\n .flatMap(([ path, param ]) => {\n if (param?.isRest) {\n return paramsClone;\n }\n if (param) {\n return paramsClone.splice(0, 1);\n }\n return [path];\n })\n .join("/");\n}\n\nconst fetchApi = useFetch(join(baseurl, apiurl), { stringify });\n\n{{#each routeMethods}}\nexport const {{method}} = (\n _params{{#if ../route.optionalParams}}?{{/if}}: MaybeWrapped<ParamsT>,\n {{#if payloadType}}\n _payload{{#if payloadType.isOptional}}?{{/if}}: MaybeWrapped<\n PayloadT["{{method}}"]\n >,\n {{else}}\n _payload?: unknown,\n {{/if}}\n): Promise<\n {{#if responseType}}\n ResponseT["{{method}}"]\n {{else}}\n unknown\n {{/if}}\n> => {\n const [params, payload] = [unwrap(_params || []), unwrap(_payload || {})];\n if (validationSchemas.params) {\n validationSchemas.params.validate(paramsMapper(params as never));\n }\n if (validationSchemas.payload?.{{method}}) {\n validationSchemas.payload.{{method}}.validate(payload);\n }\n return fetchApi.{{method}}(\n parametrize(params as never),\n payload,\n )\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 validationSchemas,\n};\n';
11
-
12
- // src/templates/index.hbs
13
- var templates_default = '{{#each routes}}\nimport {{importName}} from "{{importPathmap.fetchApi}}";\n{{/each}}\n\nexport { ValidationError } from "@kosmojs/api";\n\nexport default {\n{{#each routes}} "{{name}}": {{importName}},\n{{#each alias }} "{{this}}": {{../importName}},\n{{/each}}\n{{/each}}\n}\n';
50
+ // load-as-text:/volumes/studio/OpenSource/KosmoJS/Kosmo/packages/generators/fetch-generator/src/templates/@fetch/lib.ts
51
+ 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';
14
52
 
15
- // src/templates/lib.hbs
16
- var lib_default = 'export { stringify } from "@kosmojs/fetch";\n\nexport * from "./unwrap";\n\nexport type HostOpt =\n | string\n | { hostname: string; port?: number; secure?: boolean };\n\nexport const createHost = (host: HostOpt): string => {\n if (typeof host === "string") {\n return host;\n }\n\n if (typeof host === "object") {\n return [\n host.secure ? "https://" : "http://",\n host.hostname,\n host.port ? `:${host.port}` : "",\n ]\n .join("")\n .replace(/\\/+$/, "");\n }\n\n throw new Error(\n "Expected host to be a string or an object similar to { hostname: string; port?: number; secure?: boolean }",\n );\n};\n\nexport const join = (...args: Array<unknown>): string => {\n for (const a of args) {\n if (typeof a === "string" || typeof a === "number") {\n continue;\n }\n throw new Error(\n `The "path" argument must be of type string or number. Received type ${typeof a} (${JSON.stringify(a)})`,\n );\n }\n return args.join("/").replace(/\\/+/g, "/");\n};\n';
53
+ // src/templates/fetch.hbs
54
+ var fetch_default = '{{#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';
17
55
 
18
- // src/templates/types.hbs
19
- var types_default = 'export type PayloadT = {\n {{#each routes}}\n "{{name}}": import("{{importPathmap.fetchApi}}").PayloadT;\n {{/each}}\n}\n\nexport type ResponseT = {\n {{#each routes}}\n "{{name}}": import("{{importPathmap.fetchApi}}").ResponseT;\n {{/each}}\n}\n';
56
+ // src/templates/route.hbs
57
+ var route_default = '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';
20
58
 
21
59
  // src/templates/unwrap.hbs
22
60
  var unwrap_default = "export type MaybeWrapped<T> = T;\nexport const unwrap = <T>(data: T) => data;\n";
23
61
 
24
62
  // src/factory.ts
25
- var factory = async ({
26
- appRoot,
27
- sourceFolder,
28
- formatters
29
- }) => {
30
- const { resolve } = pathResolver({ appRoot, sourceFolder });
31
- for (const [file, template] of [
32
- // These files supposed to be replaced by specialized generators,
33
- // so write them only during initialization.
34
- ["unwrap.ts", unwrap_default]
35
- ]) {
36
- await renderToFile(
37
- resolve("fetchLibDir", file),
38
- template,
39
- {},
40
- { formatters }
41
- );
42
- }
43
- const generateLibFiles = async (entries) => {
44
- for (const { kind, entry } of entries) {
45
- if (kind !== "apiRoute") {
46
- continue;
47
- }
48
- await renderToFile(
49
- resolve("apiLibDir", dirname(entry.file), "fetch.ts"),
50
- fetch_default,
51
- {
52
- route: entry,
53
- routeMethods: entry.methods.map((method) => {
54
- const payloadType = entry.payloadTypes.find(
55
- (e) => e.method === method
56
- );
57
- const responseType = entry.responseTypes.find(
58
- (e) => e.method === method
59
- );
60
- return {
61
- method,
62
- payloadType,
63
- responseType
64
- };
65
- }),
66
- paramsMapper: entry.params.schema.map(({ name }, idx) => ({
67
- name,
68
- idx
69
- })),
70
- importPathmap: {
71
- core: join(defaults.appPrefix, defaults.coreDir),
72
- config: join(sourceFolder, defaults.configDir),
73
- fetchLib: join(sourceFolder, defaults.fetchLibDir, "lib")
74
- }
75
- },
76
- { formatters }
77
- );
63
+ var factory = async ({ appRoot, sourceFolder }) => {
64
+ const { createPath, createImportHelper } = pathResolver({
65
+ appRoot,
66
+ sourceFolder
67
+ });
68
+ const { renderToFile } = renderFactory({
69
+ helpers: {
70
+ createImport: createImportHelper,
71
+ createParamsLiteral: renderHelpers.createParamsLiteral
78
72
  }
79
- };
80
- const generateIndexFiles = async (entries) => {
81
- const routes = entries.flatMap(({ kind, entry }) => kind === "apiRoute" ? [entry] : []).sort((a, b) => a.name.localeCompare(b.name));
73
+ });
74
+ await renderToFile(createPath.lib("unwrap.ts"), unwrap_default, {});
75
+ const generateLibFiles = async (entries, updatedEntries) => {
76
+ const routes = entries.flatMap(({ kind, entry }) => kind === "apiRoute" ? [entry] : []).sort(sortRoutes);
82
77
  for (const [file, template] of [
83
- ["index.ts", templates_default],
84
- ["lib.ts", lib_default],
85
- ["types.ts", types_default]
78
+ ["fetch.ts", fetch_default],
79
+ ["@fetch/lib.ts", lib_default]
86
80
  ]) {
87
- await renderToFile(
88
- resolve("fetchLibDir", file),
89
- template,
90
- {
91
- routes: routes.map((route) => {
92
- return {
93
- ...route,
94
- importPathmap: {
95
- fetchApi: join(
96
- sourceFolder,
97
- defaults.apiLibDir,
98
- dirname(route.file),
99
- "fetch"
100
- )
81
+ await renderToFile(createPath.lib(file), template, {
82
+ routes
83
+ });
84
+ }
85
+ for (const { kind, entry } of updatedEntries) {
86
+ if (kind === "apiRoute") {
87
+ const validationTypes = [];
88
+ for (const def of entry.validationDefinitions) {
89
+ if (def.target === "response") {
90
+ for (const { id, body, resolvedType } of def.variants) {
91
+ if (body) {
92
+ validationTypes.push({
93
+ id,
94
+ target: def.target,
95
+ method: def.method,
96
+ resolvedType
97
+ });
101
98
  }
99
+ }
100
+ } else {
101
+ const { id, resolvedType } = def.schema;
102
+ validationTypes.push({
103
+ id,
104
+ target: def.target,
105
+ method: def.method,
106
+ resolvedType
107
+ });
108
+ }
109
+ }
110
+ const routeMethods = entry.methods.map((method) => {
111
+ return {
112
+ method,
113
+ responseType: validationTypes.find((e) => {
114
+ return e.target === "response" ? e.method === method : false;
115
+ })
116
+ };
117
+ });
118
+ const payloadTypes = Object.entries(
119
+ validationTypes.reduce((map, { id, target, method, resolvedType }) => {
120
+ if (target !== "response") {
121
+ const key = `${target.replace(/^./, (c) => c.toUpperCase())}T`;
122
+ if (!map[key]) {
123
+ map[key] = [];
124
+ }
125
+ map[key].push({ id, target, method, resolvedType });
126
+ }
127
+ return map;
128
+ }, {})
129
+ ).map(([name, types]) => {
130
+ return { name, types, target: types[0].target };
131
+ });
132
+ const payloadTargets = Object.keys(RequestValidationTargets).map(
133
+ (target) => {
134
+ const payloadType = payloadTypes.find((e) => e.target === target);
135
+ return {
136
+ target,
137
+ payloadType
102
138
  };
103
- })
104
- },
105
- { formatters }
106
- );
139
+ }
140
+ );
141
+ const responseTypes = Object.values(
142
+ validationTypes.reduce((map, { id, target, method, resolvedType }) => {
143
+ if (target === "response") {
144
+ if (!map[method]) {
145
+ map[method] = { method, types: [] };
146
+ }
147
+ map[method].types.push({ id, target, method, resolvedType });
148
+ }
149
+ return map;
150
+ }, {})
151
+ );
152
+ await renderToFile(
153
+ createPath.libApi(entry.name, "fetch.ts"),
154
+ route_default,
155
+ {
156
+ route: entry,
157
+ validationTypes,
158
+ routeMethods,
159
+ payloadTypes,
160
+ payloadTargets,
161
+ responseTypes
162
+ }
163
+ );
164
+ }
107
165
  }
108
166
  };
109
167
  return {
110
- async watchHandler(entries, event) {
111
- if (event) {
112
- if (event.kind === "update") {
113
- await generateLibFiles(
114
- entries.filter(({ kind, entry }) => {
115
- return kind === "apiRoute" ? entry.fileFullpath === event.file || entry.referencedFiles?.includes(event.file) : false;
116
- })
117
- );
118
- }
119
- } else {
120
- await generateLibFiles(entries);
121
- }
122
- await generateIndexFiles(entries);
123
- return void 0;
168
+ async watch(entries, event) {
169
+ await generateLibFiles(
170
+ entries,
171
+ // create/overwrite lib files with proper content.
172
+ // handle 2 cases:
173
+ // - event is undefined (means initial call): process all routes
174
+ // - `update` event given: process updated route
175
+ event ? entries.filter(({ kind, entry }) => {
176
+ return event.kind === "update" ? kind === "apiRoute" ? entry.fileFullpath === event.file : false : false;
177
+ }) : entries
178
+ );
179
+ },
180
+ async build(entries) {
181
+ await generateLibFiles(entries, entries);
124
182
  }
125
183
  };
126
184
  };
@@ -129,9 +187,13 @@ var factory = async ({
129
187
  var index_default = () => {
130
188
  return {
131
189
  name: "Fetch",
190
+ slot: "fetch",
132
191
  moduleImport: import.meta.filename,
133
192
  moduleConfig: void 0,
134
- factory
193
+ factory,
194
+ dependencies: {
195
+ "path-to-regexp": package_default.devDependencies["path-to-regexp"]
196
+ }
135
197
  };
136
198
  };
137
199
  export {
package/pkg/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/factory.ts", "../src/templates/fetch.hbs", "../src/templates/index.hbs", "../src/templates/lib.hbs", "../src/templates/types.hbs", "../src/templates/unwrap.hbs", "../src/index.ts"],
4
- "sourcesContent": ["import { dirname, join } from \"node:path\";\n\nimport {\n defaults,\n type GeneratorFactory,\n pathResolver,\n type ResolvedEntry,\n renderToFile,\n} from \"@kosmojs/devlib\";\n\nimport fetchTpl from \"./templates/fetch.hbs\";\nimport indexTpl from \"./templates/index.hbs\";\nimport libTpl from \"./templates/lib.hbs\";\nimport typesTpl from \"./templates/types.hbs\";\nimport unwrapTpl from \"./templates/unwrap.hbs\";\n\nexport const factory: GeneratorFactory = async ({\n appRoot,\n sourceFolder,\n formatters,\n}) => {\n const { resolve } = pathResolver({ appRoot, sourceFolder });\n\n for (const [file, template] of [\n // These files supposed to be replaced by specialized generators,\n // so write them only during initialization.\n [\"unwrap.ts\", unwrapTpl],\n ]) {\n await renderToFile(\n resolve(\"fetchLibDir\", file),\n template,\n {},\n { formatters },\n );\n }\n\n const generateLibFiles = async (entries: Array<ResolvedEntry>) => {\n for (const { kind, entry } of entries) {\n if (kind !== \"apiRoute\") {\n continue;\n }\n\n await renderToFile(\n resolve(\"apiLibDir\", dirname(entry.file), \"fetch.ts\"),\n fetchTpl,\n {\n route: entry,\n routeMethods: entry.methods.map((method) => {\n const payloadType = entry.payloadTypes.find(\n (e) => e.method === method,\n );\n const responseType = entry.responseTypes.find(\n (e) => e.method === method,\n );\n return {\n method,\n payloadType,\n responseType,\n };\n }),\n paramsMapper: entry.params.schema.map(({ name }, idx) => ({\n name,\n idx,\n })),\n importPathmap: {\n core: join(defaults.appPrefix, defaults.coreDir),\n config: join(sourceFolder, defaults.configDir),\n fetchLib: join(sourceFolder, defaults.fetchLibDir, \"lib\"),\n },\n },\n { formatters },\n );\n }\n };\n\n const generateIndexFiles = async (entries: Array<ResolvedEntry>) => {\n const routes = entries\n .flatMap(({ kind, entry }) => (kind === \"apiRoute\" ? [entry] : []))\n .sort((a, b) => a.name.localeCompare(b.name));\n\n for (const [file, template] of [\n [\"index.ts\", indexTpl],\n [\"lib.ts\", libTpl],\n [\"types.ts\", typesTpl],\n ]) {\n await renderToFile(\n resolve(\"fetchLibDir\", file),\n template,\n {\n routes: routes.map((route) => {\n return {\n ...route,\n importPathmap: {\n fetchApi: join(\n sourceFolder,\n defaults.apiLibDir,\n dirname(route.file),\n \"fetch\",\n ),\n },\n };\n }),\n },\n { formatters },\n );\n }\n };\n\n return {\n async watchHandler(entries, event) {\n if (event) {\n if (event.kind === \"update\") {\n await generateLibFiles(\n entries.filter(({ kind, entry }) => {\n return kind === \"apiRoute\"\n ? entry.fileFullpath === event.file ||\n entry.referencedFiles?.includes(event.file)\n : false;\n }),\n );\n }\n } else {\n // no event means initial call\n await generateLibFiles(entries);\n }\n\n await generateIndexFiles(entries);\n\n return undefined;\n },\n };\n};\n", "import useFetch from \"@kosmojs/fetch\";\n\nimport { baseurl, apiurl } from \"{{importPathmap.config}}\";\nimport { validationSchemas } from \"./schemas\";\n\nimport {\n type MaybeWrapped,\n type HostOpt,\n unwrap,\n join,\n stringify,\n createHost,\n} from \"{{importPathmap.fetchLib}}\";\n\nexport { ValidationError } from \"@kosmojs/api\";\n\nexport type ParamsT = [\n {{#each route.params.schema}}\n {{#if isRest}}\n ...{{const}}: Array<string | number>\n {{else}}\n {{const}}{{#unless isRequired}}?{{/unless}}: import(\"./types\").{{../route.params.id}}[\"{{name}}\"],\n {{/if}}\n {{/each}}\n];\n\nexport type PayloadT = {\n {{#each route.payloadTypes}}\n {{method}}: import(\"./types\").{{id}};\n {{/each}}\n}\n\nexport type ResponseT = {\n {{#each route.responseTypes}}\n {{method}}: import(\"./types\").{{id}};\n {{/each}}\n}\n\nconst paramsMapper = (params: ParamsT) => {\n return {\n {{#each paramsMapper}}\n \"{{name}}\": params[{{idx}}],\n {{/each}}\n }\n}\n\nconst pathTokens: Array<[ path: string, param?: { isRest: boolean } ]> = [\n {{#each route.pathTokens}}\n [\n \"{{path}}\",{{#if param}}\n { isRest: {{#if param.isRest}}true{{else}}false{{/if}} }{{/if}}\n ],\n {{/each}}\n];\n\nconst parametrize = (params: ParamsT) => {\n const paramsClone = structuredClone(params);\n return pathTokens\n .flatMap(([ path, param ]) => {\n if (param?.isRest) {\n return paramsClone;\n }\n if (param) {\n return paramsClone.splice(0, 1);\n }\n return [path];\n })\n .join(\"/\");\n}\n\nconst fetchApi = useFetch(join(baseurl, apiurl), { stringify });\n\n{{#each routeMethods}}\nexport const {{method}} = (\n _params{{#if ../route.optionalParams}}?{{/if}}: MaybeWrapped<ParamsT>,\n {{#if payloadType}}\n _payload{{#if payloadType.isOptional}}?{{/if}}: MaybeWrapped<\n PayloadT[\"{{method}}\"]\n >,\n {{else}}\n _payload?: unknown,\n {{/if}}\n): Promise<\n {{#if responseType}}\n ResponseT[\"{{method}}\"]\n {{else}}\n unknown\n {{/if}}\n> => {\n const [params, payload] = [unwrap(_params || []), unwrap(_payload || {})];\n if (validationSchemas.params) {\n validationSchemas.params.validate(paramsMapper(params as never));\n }\n if (validationSchemas.payload?.{{method}}) {\n validationSchemas.payload.{{method}}.validate(payload);\n }\n return fetchApi.{{method}}(\n parametrize(params as never),\n payload,\n )\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 validationSchemas,\n};\n", "{{#each routes}}\nimport {{importName}} from \"{{importPathmap.fetchApi}}\";\n{{/each}}\n\nexport { ValidationError } from \"@kosmojs/api\";\n\nexport default {\n{{#each routes}} \"{{name}}\": {{importName}},\n{{#each alias }} \"{{this}}\": {{../importName}},\n{{/each}}\n{{/each}}\n}\n", "export { stringify } from \"@kosmojs/fetch\";\n\nexport * from \"./unwrap\";\n\nexport type HostOpt =\n | string\n | { hostname: string; port?: number; secure?: boolean };\n\nexport const createHost = (host: HostOpt): string => {\n if (typeof host === \"string\") {\n return host;\n }\n\n if (typeof host === \"object\") {\n return [\n host.secure ? \"https://\" : \"http://\",\n host.hostname,\n host.port ? `:${host.port}` : \"\",\n ]\n .join(\"\")\n .replace(/\\/+$/, \"\");\n }\n\n throw new Error(\n \"Expected host to be a string or an object similar to { hostname: string; port?: number; secure?: boolean }\",\n );\n};\n\nexport const join = (...args: Array<unknown>): string => {\n for (const a of args) {\n if (typeof a === \"string\" || typeof a === \"number\") {\n continue;\n }\n throw new Error(\n `The \"path\" argument must be of type string or number. Received type ${typeof a} (${JSON.stringify(a)})`,\n );\n }\n return args.join(\"/\").replace(/\\/+/g, \"/\");\n};\n", "export type PayloadT = {\n {{#each routes}}\n \"{{name}}\": import(\"{{importPathmap.fetchApi}}\").PayloadT;\n {{/each}}\n}\n\nexport type ResponseT = {\n {{#each routes}}\n \"{{name}}\": import(\"{{importPathmap.fetchApi}}\").ResponseT;\n {{/each}}\n}\n", "export type MaybeWrapped<T> = T;\nexport const unwrap = <T>(data: T) => data;\n", "import type { GeneratorConstructor } from \"@kosmojs/devlib\";\n\nimport { factory } from \"./factory\";\n\nexport default (): GeneratorConstructor => {\n return {\n name: \"Fetch\",\n moduleImport: import.meta.filename,\n moduleConfig: undefined,\n factory,\n };\n};\n"],
5
- "mappings": "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",
3
+ "sources": ["../package.json", "../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", "../src/index.ts"],
4
+ "sourcesContent": ["{\n \"type\": \"module\",\n \"name\": \"@kosmojs/fetch-generator\",\n \"version\": \"0.0.20\",\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/dev\": \"workspace:^\"\n },\n \"devDependencies\": {\n \"@kosmojs/api\": \"workspace:^\",\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": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,5 @@
1
+ export declare const fetchClientFactory: <ParamsT extends Array<unknown>>(routeName: string, pathPattern: string, paramsMap: Array<[name: string, kind: string]>, numericParams: Array<string>) => {
2
+ paramsMapper: (params: ParamsT) => Record<string, unknown>;
3
+ parametrize(params: ParamsT): string;
4
+ resolvePayload(payload: unknown, target: string): unknown;
5
+ };
@@ -1,2 +0,0 @@
1
- import { type GeneratorFactory } from "@kosmojs/devlib";
2
- export declare const factory: GeneratorFactory;