@openmirai/typeforge 0.1.8 → 0.2.1
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 -5
- package/dist/adapters/axios/index.d.ts +13 -2
- package/dist/adapters/axios/index.js +1 -43
- package/dist/adapters/fetch/index.d.ts +17 -2
- package/dist/adapters/fetch/index.js +1 -77
- package/dist/cli.d.ts +1 -2
- package/dist/cli.js +5 -168
- package/dist/http/types.d.ts +12 -2
- package/dist/http/types.js +1 -2
- package/dist/http/validate.d.ts +1 -2
- package/dist/http/validate.js +1 -21
- package/dist/index.d.ts +133 -5
- package/dist/index.js +1 -13
- package/dist/init-CqBQsEHz.js +134 -0
- package/dist/routes/index.d.ts +1 -2
- package/dist/routes/index.js +1 -38
- package/dist/validation/zod.d.ts +1 -2
- package/dist/validation/zod.js +1 -8
- package/package.json +3 -4
- package/assets/typeforge-logo.png +0 -0
- package/dist/adapters/axios/index.d.ts.map +0 -1
- package/dist/adapters/axios/index.js.map +0 -1
- package/dist/adapters/fetch/index.d.ts.map +0 -1
- package/dist/adapters/fetch/index.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/http/types.d.ts.map +0 -1
- package/dist/http/validate.d.ts.map +0 -1
- package/dist/http/validate.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/init-BBNO0SYd.js +0 -2029
- package/dist/init-BBNO0SYd.js.map +0 -1
- package/dist/routes/index.d.ts.map +0 -1
- package/dist/routes/index.js.map +0 -1
- package/dist/validation/zod.d.ts.map +0 -1
- package/dist/validation/zod.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="
|
|
2
|
+
<img src="https://raw.githubusercontent.com/openmirai/typeforge/HEAD/assets/typeforge-logo.png" alt="Typeforge logo" width="280" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
# @openmirai/typeforge
|
|
@@ -11,10 +11,6 @@ Headless **OpenAPI / Swagger → TypeScript** codegen. The CLI is `typeforge`. I
|
|
|
11
11
|
|
|
12
12
|
You own `http.ts` (the `HTTPFetch` adapter). Generated files import that adapter — they do not invent axios/fetch calls inline.
|
|
13
13
|
|
|
14
|
-
## Migrating from `@openmirai/openapi-codegen`
|
|
15
|
-
|
|
16
|
-
Install `@openmirai/typeforge` and update package imports and scripts to use the canonical `typeforge` name. During migration, the package also exposes the legacy `openapi-codegen` binary and reads `openapi-codegen.json`, `openapi-codegen.local.json`, and the `openapiCodegen` package.json key. New projects created by `typeforge init` use the Typeforge names.
|
|
17
|
-
|
|
18
14
|
## What it generates
|
|
19
15
|
|
|
20
16
|
For each **source** (a named API, e.g. `atlas`), under `<apiRoot>/<source>/generated/`:
|
|
@@ -7,32 +7,43 @@ type QueryParams = Record<string, QueryParamValue>;
|
|
|
7
7
|
type ResponseValidator<T> = (value: unknown) => T;
|
|
8
8
|
//#endregion
|
|
9
9
|
//#region src/http/types.d.ts
|
|
10
|
+
/** Per-request options accepted by every Typeforge HTTP adapter method. */
|
|
10
11
|
interface HTTPFetchConfig<TParams extends object = QueryParams, TResponse = unknown> {
|
|
12
|
+
/** Abort signal forwarded to the underlying HTTP client. */
|
|
11
13
|
signal?: AbortSignal;
|
|
14
|
+
/** Query parameters serialized by the HTTP adapter. */
|
|
12
15
|
params?: TParams;
|
|
16
|
+
/** Request headers merged with adapter-level defaults. */
|
|
13
17
|
headers?: Record<string, string>;
|
|
18
|
+
/** Optional runtime validator applied to the response payload. */
|
|
14
19
|
validateResponse?: ResponseValidator<TResponse>;
|
|
15
20
|
}
|
|
21
|
+
/** Transport contract consumed by Typeforge-generated API callers. */
|
|
16
22
|
interface HTTPFetch {
|
|
23
|
+
/** Send a GET request and return its typed response payload. */
|
|
17
24
|
get<TResponse, TParams extends object = QueryParams>(route: string, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
18
25
|
data: TResponse;
|
|
19
26
|
}>;
|
|
27
|
+
/** Send a POST request with a typed body and return its typed response payload. */
|
|
20
28
|
post<TResponse, TBody = unknown, TParams extends object = QueryParams>(route: string, body: TBody, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
21
29
|
data: TResponse;
|
|
22
30
|
}>;
|
|
31
|
+
/** Send a PUT request with a typed body and return its typed response payload. */
|
|
23
32
|
put<TResponse, TBody = unknown, TParams extends object = QueryParams>(route: string, body: TBody, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
24
33
|
data: TResponse;
|
|
25
34
|
}>;
|
|
35
|
+
/** Send a PATCH request with a typed body and return its typed response payload. */
|
|
26
36
|
patch<TResponse, TBody = unknown, TParams extends object = QueryParams>(route: string, body: TBody, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
27
37
|
data: TResponse;
|
|
28
38
|
}>;
|
|
39
|
+
/** Send a DELETE request and return its typed response payload. */
|
|
29
40
|
delete<TResponse, TParams extends object = QueryParams>(route: string, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
30
41
|
data: TResponse;
|
|
31
42
|
}>;
|
|
32
43
|
}
|
|
33
44
|
//#endregion
|
|
34
45
|
//#region src/adapters/axios/index.d.ts
|
|
46
|
+
/** Create an `HTTPFetch` implementation backed by an Axios instance. */
|
|
35
47
|
declare function createAxiosAdapter(instance: AxiosInstance): HTTPFetch;
|
|
36
48
|
//#endregion
|
|
37
|
-
export { type HTTPFetch, type HTTPFetchConfig, createAxiosAdapter };
|
|
38
|
-
//# sourceMappingURL=index.d.ts.map
|
|
49
|
+
export { type HTTPFetch, type HTTPFetchConfig, createAxiosAdapter };
|
|
@@ -1,43 +1 @@
|
|
|
1
|
-
|
|
2
|
-
var ResponseValidationError = class extends Error {
|
|
3
|
-
cause;
|
|
4
|
-
constructor(message, cause) {
|
|
5
|
-
super(message);
|
|
6
|
-
this.name = "ResponseValidationError";
|
|
7
|
-
this.cause = cause;
|
|
8
|
-
}
|
|
9
|
-
};
|
|
10
|
-
function coerceResponseData(value, validator) {
|
|
11
|
-
if (validator === void 0) return value;
|
|
12
|
-
try {
|
|
13
|
-
return validator(value);
|
|
14
|
-
} catch (error) {
|
|
15
|
-
throw new ResponseValidationError("Response validation failed", error);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
//#endregion
|
|
19
|
-
//#region src/adapters/axios/index.ts
|
|
20
|
-
function toAxiosConfig(config) {
|
|
21
|
-
if (config === void 0) return;
|
|
22
|
-
const axiosConfig = {};
|
|
23
|
-
if (config.signal !== void 0) axiosConfig.signal = config.signal;
|
|
24
|
-
if (config.params !== void 0) axiosConfig.params = config.params;
|
|
25
|
-
if (config.headers !== void 0) axiosConfig.headers = config.headers;
|
|
26
|
-
return axiosConfig;
|
|
27
|
-
}
|
|
28
|
-
function mapResponse(data, config) {
|
|
29
|
-
return { data: coerceResponseData(data, config?.validateResponse) };
|
|
30
|
-
}
|
|
31
|
-
function createAxiosAdapter(instance) {
|
|
32
|
-
return {
|
|
33
|
-
delete: (route, config) => instance.delete(route, toAxiosConfig(config)).then((response) => mapResponse(response.data, config)),
|
|
34
|
-
get: (route, config) => instance.get(route, toAxiosConfig(config)).then((response) => mapResponse(response.data, config)),
|
|
35
|
-
patch: (route, body, config) => instance.patch(route, body, toAxiosConfig(config)).then((response) => mapResponse(response.data, config)),
|
|
36
|
-
post: (route, body, config) => instance.post(route, body, toAxiosConfig(config)).then((response) => mapResponse(response.data, config)),
|
|
37
|
-
put: (route, body, config) => instance.put(route, body, toAxiosConfig(config)).then((response) => mapResponse(response.data, config))
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
//#endregion
|
|
41
|
-
export { createAxiosAdapter };
|
|
42
|
-
|
|
43
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
var e=class extends Error{cause;constructor(e,t){super(e),this.name=`ResponseValidationError`,this.cause=t}};function t(t,n){if(n===void 0)return t;try{return n(t)}catch(t){throw new e(`Response validation failed`,t)}}function n(e){if(e===void 0)return;let t={};return e.signal!==void 0&&(t.signal=e.signal),e.params!==void 0&&(t.params=e.params),e.headers!==void 0&&(t.headers=e.headers),t}function r(e,n){return{data:t(e,n?.validateResponse)}}function i(e){return{delete:(t,i)=>e.delete(t,n(i)).then(e=>r(e.data,i)),get:(t,i)=>e.get(t,n(i)).then(e=>r(e.data,i)),patch:(t,i,a)=>e.patch(t,i,n(a)).then(e=>r(e.data,a)),post:(t,i,a)=>e.post(t,i,n(a)).then(e=>r(e.data,a)),put:(t,i,a)=>e.put(t,i,n(a)).then(e=>r(e.data,a))}}export{i as createAxiosAdapter};
|
|
@@ -6,37 +6,52 @@ type QueryParams = Record<string, QueryParamValue>;
|
|
|
6
6
|
type ResponseValidator<T> = (value: unknown) => T;
|
|
7
7
|
//#endregion
|
|
8
8
|
//#region src/http/types.d.ts
|
|
9
|
+
/** Per-request options accepted by every Typeforge HTTP adapter method. */
|
|
9
10
|
interface HTTPFetchConfig<TParams extends object = QueryParams, TResponse = unknown> {
|
|
11
|
+
/** Abort signal forwarded to the underlying HTTP client. */
|
|
10
12
|
signal?: AbortSignal;
|
|
13
|
+
/** Query parameters serialized by the HTTP adapter. */
|
|
11
14
|
params?: TParams;
|
|
15
|
+
/** Request headers merged with adapter-level defaults. */
|
|
12
16
|
headers?: Record<string, string>;
|
|
17
|
+
/** Optional runtime validator applied to the response payload. */
|
|
13
18
|
validateResponse?: ResponseValidator<TResponse>;
|
|
14
19
|
}
|
|
20
|
+
/** Transport contract consumed by Typeforge-generated API callers. */
|
|
15
21
|
interface HTTPFetch {
|
|
22
|
+
/** Send a GET request and return its typed response payload. */
|
|
16
23
|
get<TResponse, TParams extends object = QueryParams>(route: string, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
17
24
|
data: TResponse;
|
|
18
25
|
}>;
|
|
26
|
+
/** Send a POST request with a typed body and return its typed response payload. */
|
|
19
27
|
post<TResponse, TBody = unknown, TParams extends object = QueryParams>(route: string, body: TBody, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
20
28
|
data: TResponse;
|
|
21
29
|
}>;
|
|
30
|
+
/** Send a PUT request with a typed body and return its typed response payload. */
|
|
22
31
|
put<TResponse, TBody = unknown, TParams extends object = QueryParams>(route: string, body: TBody, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
23
32
|
data: TResponse;
|
|
24
33
|
}>;
|
|
34
|
+
/** Send a PATCH request with a typed body and return its typed response payload. */
|
|
25
35
|
patch<TResponse, TBody = unknown, TParams extends object = QueryParams>(route: string, body: TBody, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
26
36
|
data: TResponse;
|
|
27
37
|
}>;
|
|
38
|
+
/** Send a DELETE request and return its typed response payload. */
|
|
28
39
|
delete<TResponse, TParams extends object = QueryParams>(route: string, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
29
40
|
data: TResponse;
|
|
30
41
|
}>;
|
|
31
42
|
}
|
|
32
43
|
//#endregion
|
|
33
44
|
//#region src/adapters/fetch/index.d.ts
|
|
45
|
+
/** Options for the Fetch-based `HTTPFetch` adapter. */
|
|
34
46
|
interface FetchAdapterOptions {
|
|
47
|
+
/** Base URL prepended to every generated route. */
|
|
35
48
|
baseURL?: string;
|
|
49
|
+
/** Headers included with every request unless overridden per request. */
|
|
36
50
|
headers?: Record<string, string>;
|
|
51
|
+
/** Fetch implementation to use, such as a test double or platform polyfill. */
|
|
37
52
|
fetch?: typeof fetch;
|
|
38
53
|
}
|
|
54
|
+
/** Create an `HTTPFetch` implementation backed by the Fetch API. */
|
|
39
55
|
declare function createFetchAdapter(options?: FetchAdapterOptions): HTTPFetch;
|
|
40
56
|
//#endregion
|
|
41
|
-
export { FetchAdapterOptions, type HTTPFetch, type HTTPFetchConfig, createFetchAdapter };
|
|
42
|
-
//# sourceMappingURL=index.d.ts.map
|
|
57
|
+
export { FetchAdapterOptions, type HTTPFetch, type HTTPFetchConfig, createFetchAdapter };
|
|
@@ -1,77 +1 @@
|
|
|
1
|
-
|
|
2
|
-
function isJsonValue(value) {
|
|
3
|
-
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return true;
|
|
4
|
-
if (Array.isArray(value)) return value.every(isJsonValue);
|
|
5
|
-
if (typeof value === "object" && value !== null) return Object.values(value).every(isJsonValue);
|
|
6
|
-
return false;
|
|
7
|
-
}
|
|
8
|
-
function parseJson(text) {
|
|
9
|
-
const parsed = JSON.parse(text);
|
|
10
|
-
if (!isJsonValue(parsed)) throw new TypeError("JSON text did not parse to a valid JSON value");
|
|
11
|
-
return parsed;
|
|
12
|
-
}
|
|
13
|
-
//#endregion
|
|
14
|
-
//#region src/http/validate.ts
|
|
15
|
-
var ResponseValidationError = class extends Error {
|
|
16
|
-
cause;
|
|
17
|
-
constructor(message, cause) {
|
|
18
|
-
super(message);
|
|
19
|
-
this.name = "ResponseValidationError";
|
|
20
|
-
this.cause = cause;
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
function coerceResponseData(value, validator) {
|
|
24
|
-
if (validator === void 0) return value;
|
|
25
|
-
try {
|
|
26
|
-
return validator(value);
|
|
27
|
-
} catch (error) {
|
|
28
|
-
throw new ResponseValidationError("Response validation failed", error);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
//#endregion
|
|
32
|
-
//#region src/adapters/fetch/index.ts
|
|
33
|
-
function appendQuery(url, params) {
|
|
34
|
-
if (params === void 0 || Object.keys(params).length === 0) return url;
|
|
35
|
-
const search = new URLSearchParams();
|
|
36
|
-
for (const [key, value] of Object.entries(params)) search.append(key, String(value));
|
|
37
|
-
const query = search.toString();
|
|
38
|
-
if (query.length === 0) return url;
|
|
39
|
-
return `${url}${url.includes("?") ? "&" : "?"}${query}`;
|
|
40
|
-
}
|
|
41
|
-
function readResponseBody(text) {
|
|
42
|
-
if (text.length === 0) return;
|
|
43
|
-
return parseJson(text);
|
|
44
|
-
}
|
|
45
|
-
async function request(method, route, options, body, config) {
|
|
46
|
-
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
47
|
-
const url = appendQuery(`${options.baseURL ?? ""}${route}`, config?.params);
|
|
48
|
-
const headers = {
|
|
49
|
-
...options.headers,
|
|
50
|
-
...config?.headers
|
|
51
|
-
};
|
|
52
|
-
const init = {
|
|
53
|
-
headers,
|
|
54
|
-
method
|
|
55
|
-
};
|
|
56
|
-
if (config?.signal !== void 0) init.signal = config.signal;
|
|
57
|
-
if (body !== void 0) {
|
|
58
|
-
headers["Content-Type"] ??= "application/json";
|
|
59
|
-
init.body = JSON.stringify(body);
|
|
60
|
-
}
|
|
61
|
-
const response = await fetchImpl(url, init);
|
|
62
|
-
if (!response.ok) throw new Error(`HTTP ${response.status} ${response.statusText}`);
|
|
63
|
-
return { data: coerceResponseData(readResponseBody(await response.text()), config?.validateResponse) };
|
|
64
|
-
}
|
|
65
|
-
function createFetchAdapter(options = {}) {
|
|
66
|
-
return {
|
|
67
|
-
delete: (route, config) => request("DELETE", route, options, void 0, config),
|
|
68
|
-
get: (route, config) => request("GET", route, options, void 0, config),
|
|
69
|
-
patch: (route, body, config) => request("PATCH", route, options, body, config),
|
|
70
|
-
post: (route, body, config) => request("POST", route, options, body, config),
|
|
71
|
-
put: (route, body, config) => request("PUT", route, options, body, config)
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
//#endregion
|
|
75
|
-
export { createFetchAdapter };
|
|
76
|
-
|
|
77
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
function e(t){return t===null||typeof t==`string`||typeof t==`number`||typeof t==`boolean`?!0:Array.isArray(t)?t.every(e):typeof t==`object`&&t?Object.values(t).every(e):!1}function t(t){let n=JSON.parse(t);if(!e(n))throw TypeError(`JSON text did not parse to a valid JSON value`);return n}var n=class extends Error{cause;constructor(e,t){super(e),this.name=`ResponseValidationError`,this.cause=t}};function r(e,t){if(t===void 0)return e;try{return t(e)}catch(e){throw new n(`Response validation failed`,e)}}function i(e,t){if(t===void 0||Object.keys(t).length===0)return e;let n=new URLSearchParams;for(let[e,r]of Object.entries(t))n.append(e,String(r));let r=n.toString();return r.length===0?e:`${e}${e.includes(`?`)?`&`:`?`}${r}`}function a(e){if(e.length!==0)return t(e)}async function o(e,t,n,o,s){let c=n.fetch??globalThis.fetch,l=i(`${n.baseURL??``}${t}`,s?.params),u={...n.headers,...s?.headers},d={headers:u,method:e};s?.signal!==void 0&&(d.signal=s.signal),o!==void 0&&(u[`Content-Type`]??=`application/json`,d.body=JSON.stringify(o));let f=await c(l,d);if(!f.ok)throw Error(`HTTP ${f.status} ${f.statusText}`);return{data:r(a(await f.text()),s?.validateResponse)}}function s(e={}){return{delete:(t,n)=>o(`DELETE`,t,e,void 0,n),get:(t,n)=>o(`GET`,t,e,void 0,n),patch:(t,n,r)=>o(`PATCH`,t,e,n,r),post:(t,n,r)=>o(`POST`,t,e,n,r),put:(t,n,r)=>o(`PUT`,t,e,n,r)}}export{s as createFetchAdapter};
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -1,87 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import { realpathSync } from "node:fs";
|
|
4
|
-
import { pathToFileURL } from "node:url";
|
|
5
|
-
//#region src/cli.ts
|
|
6
|
-
function parseArgs(argv) {
|
|
7
|
-
const parsed = { sources: [] };
|
|
8
|
-
const positional = [];
|
|
9
|
-
for (let index = 0; index < argv.length; index += 1) {
|
|
10
|
-
const arg = argv[index];
|
|
11
|
-
if (arg === void 0) continue;
|
|
12
|
-
if (arg === "--check") {
|
|
13
|
-
parsed.check = true;
|
|
14
|
-
continue;
|
|
15
|
-
}
|
|
16
|
-
if (arg === "--accept-base") {
|
|
17
|
-
parsed.acceptBase = true;
|
|
18
|
-
continue;
|
|
19
|
-
}
|
|
20
|
-
if (arg === "--all") {
|
|
21
|
-
parsed.all = true;
|
|
22
|
-
continue;
|
|
23
|
-
}
|
|
24
|
-
if (arg.startsWith("--source=")) {
|
|
25
|
-
const value = arg.slice(9);
|
|
26
|
-
parsed.sources.push(value);
|
|
27
|
-
if (parsed.source === void 0) parsed.source = value;
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
if (arg === "--source") {
|
|
31
|
-
const value = argv[index + 1];
|
|
32
|
-
if (value !== void 0) {
|
|
33
|
-
parsed.sources.push(value);
|
|
34
|
-
if (parsed.source === void 0) parsed.source = value;
|
|
35
|
-
index += 1;
|
|
36
|
-
}
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
if (arg.startsWith("--spec=")) {
|
|
40
|
-
parsed.spec = arg.slice(7);
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
if (arg === "--spec") {
|
|
44
|
-
const value = argv[index + 1];
|
|
45
|
-
if (value !== void 0) {
|
|
46
|
-
parsed.spec = value;
|
|
47
|
-
index += 1;
|
|
48
|
-
}
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
if (arg.startsWith("--client=")) {
|
|
52
|
-
const value = arg.slice(9);
|
|
53
|
-
if (value === "axios" || value === "fetch" || value === "custom") parsed.client = value;
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
if (arg === "--client") {
|
|
57
|
-
const value = argv[index + 1];
|
|
58
|
-
if (value === "axios" || value === "fetch" || value === "custom") {
|
|
59
|
-
parsed.client = value;
|
|
60
|
-
index += 1;
|
|
61
|
-
}
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
if (arg.startsWith("--layout=")) {
|
|
65
|
-
const value = arg.slice(9);
|
|
66
|
-
if (value === "monolith" || value === "packages") parsed.layout = value;
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
if (arg === "--layout") {
|
|
70
|
-
const value = argv[index + 1];
|
|
71
|
-
if (value === "monolith" || value === "packages") {
|
|
72
|
-
parsed.layout = value;
|
|
73
|
-
index += 1;
|
|
74
|
-
}
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
if (!arg.startsWith("-")) positional.push(arg);
|
|
78
|
-
}
|
|
79
|
-
const command = positional[0];
|
|
80
|
-
if (command !== void 0) parsed.command = command;
|
|
81
|
-
return parsed;
|
|
82
|
-
}
|
|
83
|
-
function printHelp() {
|
|
84
|
-
process.stdout.write(`typeforge — headless OpenAPI TypeScript codegen
|
|
2
|
+
import{g as e,h as t,r as n,t as r}from"./init-CqBQsEHz.js";import{realpathSync as i}from"node:fs";import{pathToFileURL as a}from"node:url";function o(e){let t={sources:[]},n=[];for(let r=0;r<e.length;r+=1){let i=e[r];if(i!==void 0){if(i===`--check`){t.check=!0;continue}if(i===`--accept-base`){t.acceptBase=!0;continue}if(i===`--all`){t.all=!0;continue}if(i.startsWith(`--source=`)){let e=i.slice(9);t.sources.push(e),t.source===void 0&&(t.source=e);continue}if(i===`--source`){let n=e[r+1];n!==void 0&&(t.sources.push(n),t.source===void 0&&(t.source=n),r+=1);continue}if(i.startsWith(`--spec=`)){t.spec=i.slice(7);continue}if(i===`--spec`){let n=e[r+1];n!==void 0&&(t.spec=n,r+=1);continue}if(i.startsWith(`--client=`)){let e=i.slice(9);(e===`axios`||e===`fetch`||e===`custom`)&&(t.client=e);continue}if(i===`--client`){let n=e[r+1];(n===`axios`||n===`fetch`||n===`custom`)&&(t.client=n,r+=1);continue}if(i.startsWith(`--layout=`)){let e=i.slice(9);(e===`monolith`||e===`packages`)&&(t.layout=e);continue}if(i===`--layout`){let n=e[r+1];(n===`monolith`||n===`packages`)&&(t.layout=n,r+=1);continue}i.startsWith(`-`)||n.push(i)}}let r=n[0];return r!==void 0&&(t.command=r),t}function s(){process.stdout.write(`typeforge — headless OpenAPI TypeScript codegen
|
|
85
3
|
|
|
86
4
|
Usage:
|
|
87
5
|
typeforge init --source <key> --client axios|fetch|custom [--layout monolith|packages]
|
|
@@ -95,88 +13,7 @@ Multi-source generate:
|
|
|
95
13
|
Configure per-source spec paths in each source.ts:
|
|
96
14
|
import { defineSourceConfig } from "@openmirai/typeforge";
|
|
97
15
|
export default defineSourceConfig({ spec: "./specs/acme.json", ... });
|
|
98
|
-
`)
|
|
99
|
-
|
|
100
|
-
async function
|
|
101
|
-
|
|
102
|
-
process.stderr.write("typeforge: --accept-base is not allowed with --check\n");
|
|
103
|
-
return 1;
|
|
104
|
-
}
|
|
105
|
-
const cwd = process.cwd();
|
|
106
|
-
const apiRoot = loadProjectConfig(cwd).apiRoot ?? "src/api";
|
|
107
|
-
let sources;
|
|
108
|
-
if (args.all === true) sources = listSourceKeys(cwd, apiRoot);
|
|
109
|
-
else if (args.sources.length > 0) sources = args.sources;
|
|
110
|
-
else sources = [];
|
|
111
|
-
if (sources.length === 0) {
|
|
112
|
-
process.stderr.write("typeforge: --source <key> or --all is required\n");
|
|
113
|
-
return 1;
|
|
114
|
-
}
|
|
115
|
-
let exitCode = 0;
|
|
116
|
-
for (const sourceKey of sources) try {
|
|
117
|
-
const generateOptions = { sourceKey };
|
|
118
|
-
if (args.acceptBase === true) generateOptions.acceptBase = true;
|
|
119
|
-
if (args.check === true) generateOptions.check = true;
|
|
120
|
-
if (args.spec !== void 0) generateOptions.specFlag = args.spec;
|
|
121
|
-
const result = await generateForSource(generateOptions);
|
|
122
|
-
if (args.check === true) {
|
|
123
|
-
if (result.changed.length > 0) {
|
|
124
|
-
process.stderr.write(`typeforge: stale generated files for "${sourceKey}":\n`);
|
|
125
|
-
for (const file of result.changed) process.stderr.write(` ${file}\n`);
|
|
126
|
-
exitCode = 1;
|
|
127
|
-
} else process.stdout.write(`typeforge: "${sourceKey}" is up to date\n`);
|
|
128
|
-
} else process.stdout.write(`typeforge: generated ${result.files} files for "${sourceKey}" (${result.changed.length} changed)\n`);
|
|
129
|
-
} catch (error) {
|
|
130
|
-
exitCode = 1;
|
|
131
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
132
|
-
process.stderr.write(`${message}\n`);
|
|
133
|
-
}
|
|
134
|
-
return exitCode;
|
|
135
|
-
}
|
|
136
|
-
async function main() {
|
|
137
|
-
const args = parseArgs(process.argv.slice(2));
|
|
138
|
-
if (args.command === void 0 || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
|
139
|
-
printHelp();
|
|
140
|
-
process.exit(0);
|
|
141
|
-
}
|
|
142
|
-
if (args.command === "init") {
|
|
143
|
-
if (args.source === void 0 || args.client === void 0) {
|
|
144
|
-
process.stderr.write("typeforge: init requires --source and --client\n");
|
|
145
|
-
process.exit(1);
|
|
146
|
-
}
|
|
147
|
-
const initOptions = {
|
|
148
|
-
client: args.client,
|
|
149
|
-
sourceKey: args.source
|
|
150
|
-
};
|
|
151
|
-
if (args.layout !== void 0) initOptions.layout = args.layout;
|
|
152
|
-
const result = initProject(initOptions);
|
|
153
|
-
for (const file of result.created) process.stdout.write(`created ${file}\n`);
|
|
154
|
-
for (const file of result.skipped) process.stdout.write(`skipped ${file} (already exists)\n`);
|
|
155
|
-
process.exit(0);
|
|
156
|
-
}
|
|
157
|
-
if (args.command === "generate" || args.command === "check" || args.command === "accept-base") {
|
|
158
|
-
if (args.command === "check") args.check = true;
|
|
159
|
-
if (args.command === "accept-base") args.acceptBase = true;
|
|
160
|
-
process.exit(await runGenerate(args));
|
|
161
|
-
}
|
|
162
|
-
process.stderr.write(`typeforge: unknown command "${args.command}"\n`);
|
|
163
|
-
printHelp();
|
|
164
|
-
process.exit(1);
|
|
165
|
-
}
|
|
166
|
-
if ((() => {
|
|
167
|
-
const entry = process.argv[1];
|
|
168
|
-
if (entry === void 0) return false;
|
|
169
|
-
try {
|
|
170
|
-
return import.meta.url === pathToFileURL(realpathSync(entry)).href;
|
|
171
|
-
} catch {
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
})()) main().catch((error) => {
|
|
175
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
176
|
-
process.stderr.write(`${message}\n`);
|
|
177
|
-
process.exit(1);
|
|
178
|
-
});
|
|
179
|
-
//#endregion
|
|
180
|
-
export { parseArgs };
|
|
181
|
-
|
|
182
|
-
//# sourceMappingURL=cli.js.map
|
|
16
|
+
`)}async function c(r){if(r.check===!0&&r.acceptBase===!0)return process.stderr.write(`typeforge: --accept-base is not allowed with --check
|
|
17
|
+
`),1;let i=process.cwd(),a=e(i).apiRoot??`src/api`,o;if(o=r.all===!0?t(i,a):r.sources.length>0?r.sources:[],o.length===0)return process.stderr.write(`typeforge: --source <key> or --all is required
|
|
18
|
+
`),1;let s=0;for(let e of o)try{let t={sourceKey:e};r.acceptBase===!0&&(t.acceptBase=!0),r.check===!0&&(t.check=!0),r.spec!==void 0&&(t.specFlag=r.spec);let i=await n(t);if(r.check===!0){if(i.changed.length>0){process.stderr.write(`typeforge: stale generated files for "${e}":\n`);for(let e of i.changed)process.stderr.write(` ${e}\n`);s=1}else process.stdout.write(`typeforge: "${e}" is up to date\n`)}else process.stdout.write(`typeforge: generated ${i.files} files for "${e}" (${i.changed.length} changed)\n`)}catch(e){s=1;let t=e instanceof Error?e.message:String(e);process.stderr.write(`${t}\n`)}return s}async function l(){let e=o(process.argv.slice(2));if((e.command===void 0||e.command===`help`||e.command===`--help`||e.command===`-h`)&&(s(),process.exit(0)),e.command===`init`){(e.source===void 0||e.client===void 0)&&(process.stderr.write(`typeforge: init requires --source and --client
|
|
19
|
+
`),process.exit(1));let t={client:e.client,sourceKey:e.source};e.layout!==void 0&&(t.layout=e.layout);let n=r(t);for(let e of n.created)process.stdout.write(`created ${e}\n`);for(let e of n.skipped)process.stdout.write(`skipped ${e} (already exists)\n`);process.exit(0)}(e.command===`generate`||e.command===`check`||e.command===`accept-base`)&&(e.command===`check`&&(e.check=!0),e.command===`accept-base`&&(e.acceptBase=!0),process.exit(await c(e))),process.stderr.write(`typeforge: unknown command "${e.command}"\n`),s(),process.exit(1)}(()=>{let e=process.argv[1];if(e===void 0)return!1;try{return import.meta.url===a(i(e)).href}catch{return!1}})()&&l().catch(e=>{let t=e instanceof Error?e.message:String(e);process.stderr.write(`${t}\n`),process.exit(1)});export{o as parseArgs};
|
package/dist/http/types.d.ts
CHANGED
|
@@ -4,29 +4,39 @@ type QueryParamValue = string | number | boolean | null | undefined;
|
|
|
4
4
|
type QueryParams = Record<string, QueryParamValue>;
|
|
5
5
|
//#endregion
|
|
6
6
|
//#region src/http/types.d.ts
|
|
7
|
+
/** Per-request options accepted by every Typeforge HTTP adapter method. */
|
|
7
8
|
interface HTTPFetchConfig<TParams extends object = QueryParams, TResponse = unknown> {
|
|
9
|
+
/** Abort signal forwarded to the underlying HTTP client. */
|
|
8
10
|
signal?: AbortSignal;
|
|
11
|
+
/** Query parameters serialized by the HTTP adapter. */
|
|
9
12
|
params?: TParams;
|
|
13
|
+
/** Request headers merged with adapter-level defaults. */
|
|
10
14
|
headers?: Record<string, string>;
|
|
15
|
+
/** Optional runtime validator applied to the response payload. */
|
|
11
16
|
validateResponse?: ResponseValidator<TResponse>;
|
|
12
17
|
}
|
|
18
|
+
/** Transport contract consumed by Typeforge-generated API callers. */
|
|
13
19
|
interface HTTPFetch {
|
|
20
|
+
/** Send a GET request and return its typed response payload. */
|
|
14
21
|
get<TResponse, TParams extends object = QueryParams>(route: string, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
15
22
|
data: TResponse;
|
|
16
23
|
}>;
|
|
24
|
+
/** Send a POST request with a typed body and return its typed response payload. */
|
|
17
25
|
post<TResponse, TBody = unknown, TParams extends object = QueryParams>(route: string, body: TBody, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
18
26
|
data: TResponse;
|
|
19
27
|
}>;
|
|
28
|
+
/** Send a PUT request with a typed body and return its typed response payload. */
|
|
20
29
|
put<TResponse, TBody = unknown, TParams extends object = QueryParams>(route: string, body: TBody, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
21
30
|
data: TResponse;
|
|
22
31
|
}>;
|
|
32
|
+
/** Send a PATCH request with a typed body and return its typed response payload. */
|
|
23
33
|
patch<TResponse, TBody = unknown, TParams extends object = QueryParams>(route: string, body: TBody, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
24
34
|
data: TResponse;
|
|
25
35
|
}>;
|
|
36
|
+
/** Send a DELETE request and return its typed response payload. */
|
|
26
37
|
delete<TResponse, TParams extends object = QueryParams>(route: string, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
27
38
|
data: TResponse;
|
|
28
39
|
}>;
|
|
29
40
|
}
|
|
30
41
|
//#endregion
|
|
31
|
-
export { HTTPFetch, HTTPFetchConfig, type QueryParamValue, type QueryParams, ResponseValidationError, type ResponseValidator, coerceResponseData };
|
|
32
|
-
//# sourceMappingURL=types.d.ts.map
|
|
42
|
+
export { HTTPFetch, HTTPFetchConfig, type QueryParamValue, type QueryParams, ResponseValidationError, type ResponseValidator, coerceResponseData };
|
package/dist/http/types.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
export { ResponseValidationError, coerceResponseData };
|
|
1
|
+
import{ResponseValidationError as e,coerceResponseData as t}from"./validate.js";export{e as ResponseValidationError,t as coerceResponseData};
|
package/dist/http/validate.d.ts
CHANGED
|
@@ -6,5 +6,4 @@ declare class ResponseValidationError extends Error {
|
|
|
6
6
|
}
|
|
7
7
|
declare function coerceResponseData<T>(value: unknown, validator?: ResponseValidator<T>): T;
|
|
8
8
|
//#endregion
|
|
9
|
-
export { ResponseValidationError, ResponseValidator, coerceResponseData };
|
|
10
|
-
//# sourceMappingURL=validate.d.ts.map
|
|
9
|
+
export { ResponseValidationError, ResponseValidator, coerceResponseData };
|
package/dist/http/validate.js
CHANGED
|
@@ -1,21 +1 @@
|
|
|
1
|
-
|
|
2
|
-
var ResponseValidationError = class extends Error {
|
|
3
|
-
cause;
|
|
4
|
-
constructor(message, cause) {
|
|
5
|
-
super(message);
|
|
6
|
-
this.name = "ResponseValidationError";
|
|
7
|
-
this.cause = cause;
|
|
8
|
-
}
|
|
9
|
-
};
|
|
10
|
-
function coerceResponseData(value, validator) {
|
|
11
|
-
if (validator === void 0) return value;
|
|
12
|
-
try {
|
|
13
|
-
return validator(value);
|
|
14
|
-
} catch (error) {
|
|
15
|
-
throw new ResponseValidationError("Response validation failed", error);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
//#endregion
|
|
19
|
-
export { ResponseValidationError, coerceResponseData };
|
|
20
|
-
|
|
21
|
-
//# sourceMappingURL=validate.js.map
|
|
1
|
+
var e=class extends Error{cause;constructor(e,t){super(e),this.name=`ResponseValidationError`,this.cause=t}};function t(t,n){if(n===void 0)return t;try{return n(t)}catch(t){throw new e(`Response validation failed`,t)}}export{e as ResponseValidationError,t as coerceResponseData};
|