@openmirai/typeforge 0.1.7
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 +268 -0
- package/assets/typeforge-logo.png +0 -0
- package/dist/adapters/axios/index.d.ts +38 -0
- package/dist/adapters/axios/index.d.ts.map +1 -0
- package/dist/adapters/axios/index.js +43 -0
- package/dist/adapters/axios/index.js.map +1 -0
- package/dist/adapters/fetch/index.d.ts +42 -0
- package/dist/adapters/fetch/index.d.ts.map +1 -0
- package/dist/adapters/fetch/index.js +77 -0
- package/dist/adapters/fetch/index.js.map +1 -0
- package/dist/cli.d.ts +18 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +182 -0
- package/dist/cli.js.map +1 -0
- package/dist/http/types.d.ts +32 -0
- package/dist/http/types.d.ts.map +1 -0
- package/dist/http/types.js +2 -0
- package/dist/http/validate.d.ts +10 -0
- package/dist/http/validate.d.ts.map +1 -0
- package/dist/http/validate.js +21 -0
- package/dist/http/validate.js.map +1 -0
- package/dist/index.d.ts +326 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/init-BBNO0SYd.js +2029 -0
- package/dist/init-BBNO0SYd.js.map +1 -0
- package/dist/routes/index.d.ts +33 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +38 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/validation/zod.d.ts +11 -0
- package/dist/validation/zod.d.ts.map +1 -0
- package/dist/validation/zod.js +8 -0
- package/dist/validation/zod.js.map +1 -0
- package/package.json +107 -0
package/README.md
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./assets/typeforge-logo.png" alt="Typeforge logo" width="280" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# @openmirai/typeforge
|
|
6
|
+
|
|
7
|
+
Headless **OpenAPI / Swagger → TypeScript** codegen. The CLI is `typeforge`. It reads a spec, writes typed route enums, request types, and HTTP caller functions, and never talks to a network.
|
|
8
|
+
|
|
9
|
+
- **npm:** [`@openmirai/typeforge`](https://www.npmjs.com/package/@openmirai/typeforge)
|
|
10
|
+
- **GitHub:** [openmirai/mirai-openapi-codegen](https://github.com/openmirai/mirai-openapi-codegen)
|
|
11
|
+
|
|
12
|
+
You own `http.ts` (the `HTTPFetch` adapter). Generated files import that adapter — they do not invent axios/fetch calls inline.
|
|
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
|
+
## What it generates
|
|
19
|
+
|
|
20
|
+
For each **source** (a named API, e.g. `atlas`), under `<apiRoot>/<source>/generated/`:
|
|
21
|
+
|
|
22
|
+
| Output | Role |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| `types/**/*.d.ts` | Params, body, and response types per operation |
|
|
25
|
+
| `functions/**/*.ts` | Typed callers (`getWidgets`, …) |
|
|
26
|
+
| `routes.ts` | `Routes` string map + `RouteTargets` enum (name configurable) |
|
|
27
|
+
| `runtime.ts` | Re-exports `HTTPFetch`, `httpFetch` (if singleton), routes |
|
|
28
|
+
| `base.ts` | `BaseResponse<T>` when the spec uses a response envelope (or `base.d.ts` for split declaration output) |
|
|
29
|
+
|
|
30
|
+
Optional:
|
|
31
|
+
|
|
32
|
+
- **TanStack Query** — set `tanstackQuery: true` in `source.ts` **and** add `<apiRoot>/query-scope.ts`.
|
|
33
|
+
- **Zod** — wrap a schema with `createZodValidator` from `@openmirai/typeforge/validation/zod` and pass it as `config.validateResponse`.
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
Requires **Node.js 20.11+** (LTS). Use any package manager.
|
|
38
|
+
|
|
39
|
+
| Package manager | Install |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| npm | `npm install --save-dev @openmirai/typeforge` |
|
|
42
|
+
| pnpm | `pnpm add -D @openmirai/typeforge` |
|
|
43
|
+
| yarn | `yarn add -D @openmirai/typeforge` |
|
|
44
|
+
| bun | `bun add -d @openmirai/typeforge` |
|
|
45
|
+
|
|
46
|
+
Axios is an **optional peer**. Install `axios` only if you use `--client axios`.
|
|
47
|
+
|
|
48
|
+
Add a script so every package manager resolves the CLI from `node_modules/.bin`:
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"scripts": {
|
|
53
|
+
"generate:types": "typeforge generate --all"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Then run `npm run generate:types`, `pnpm run generate:types`, `yarn generate:types`, or `bun run generate:types`.
|
|
59
|
+
|
|
60
|
+
## CLI usage
|
|
61
|
+
|
|
62
|
+
Prefer the `package.json` script above. To invoke the binary directly:
|
|
63
|
+
|
|
64
|
+
| Command | npm | pnpm | yarn | bun |
|
|
65
|
+
| --- | --- | --- | --- | --- |
|
|
66
|
+
| Init a source | `npx typeforge init --source atlas --client axios` | `pnpm exec typeforge init --source atlas --client axios` | `yarn typeforge init --source atlas --client axios` | `bunx typeforge init --source atlas --client axios` |
|
|
67
|
+
| Generate one source | `npx typeforge generate --source atlas` | `pnpm exec typeforge generate --source atlas` | `yarn typeforge generate --source atlas` | `bunx typeforge generate --source atlas` |
|
|
68
|
+
| Generate all sources | `npx typeforge generate --all` | `pnpm exec typeforge generate --all` | `yarn typeforge generate --all` | `bunx typeforge generate --all` |
|
|
69
|
+
| Drift check (CI) | `npx typeforge generate --all --check` | `pnpm exec typeforge generate --all --check` | `yarn typeforge generate --all --check` | `bunx typeforge generate --all --check` |
|
|
70
|
+
|
|
71
|
+
| Subcommand | Purpose |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| `init` | Scaffold `http.ts`, `source.ts`, `known-types.ts` |
|
|
74
|
+
| `generate` | Write generated files |
|
|
75
|
+
| `check` | Same as `generate --check` — exit 1 if output would change |
|
|
76
|
+
| `accept-base` | Update generated `base.ts` (`base.d.ts` for split declaration output) and patch `models.ts` `BaseResponse` |
|
|
77
|
+
|
|
78
|
+
`--check` and `--accept-base` cannot be combined. See [docs/cli.md](docs/cli.md) for the full command reference.
|
|
79
|
+
|
|
80
|
+
## How the flow works
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
init → source.ts + http.ts → resolve spec → generate → typed callers
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 1. Init a source
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
typeforge init --source atlas --client axios
|
|
90
|
+
typeforge init --source orbit --client fetch --layout packages
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`--client` is `axios` | `fetch` | `custom`. `--layout` is `monolith` (default, `apiRoot` = `src/api`) or `packages` (`apiRoot` = `packages/utils/src/api`).
|
|
94
|
+
|
|
95
|
+
Init creates (if missing):
|
|
96
|
+
|
|
97
|
+
- `typeforge.json` with `apiRoot`
|
|
98
|
+
- `<apiRoot>/http.ts` — your `HTTPFetch` implementation
|
|
99
|
+
- `<apiRoot>/known-types.ts` — optional schema → local type mapping
|
|
100
|
+
- `<apiRoot>/<source>/source.ts` — per-API config (type-safe template)
|
|
101
|
+
- `<apiRoot>/<source>/generated/` directory
|
|
102
|
+
|
|
103
|
+
Existing files are skipped.
|
|
104
|
+
|
|
105
|
+
### 2. Configure `source.ts`
|
|
106
|
+
|
|
107
|
+
Use `defineSourceConfig` for autocomplete and compile-time checks:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { defineSourceConfig } from "@openmirai/typeforge";
|
|
111
|
+
|
|
112
|
+
export default defineSourceConfig({
|
|
113
|
+
spec: "./specs/acme.json",
|
|
114
|
+
functionsDir: "packages/utils/src/api/routes/atlas",
|
|
115
|
+
typesDir: "packages/types/src/api/atlas",
|
|
116
|
+
pathPrefix: "/api/acme/v3",
|
|
117
|
+
stripApiPrefix: true,
|
|
118
|
+
routeEnumName: "RouteTargets",
|
|
119
|
+
generationMode: "authoritative",
|
|
120
|
+
naming: "path",
|
|
121
|
+
ignorePaths: [],
|
|
122
|
+
maxRenderDepth: 50,
|
|
123
|
+
resolveMapKeyRefs: true,
|
|
124
|
+
tanstackQuery: false,
|
|
125
|
+
queryExtends: {
|
|
126
|
+
page: "page",
|
|
127
|
+
limit: "limit",
|
|
128
|
+
sortBy: "sortBy",
|
|
129
|
+
sortOrder: "sortOrder",
|
|
130
|
+
paginationTypeName: "OffsetLimitQuery",
|
|
131
|
+
paginationImportPath: "./pagination",
|
|
132
|
+
sortTypeName: "SortParams",
|
|
133
|
+
sortImportPath: "./pagination",
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Plain `export default { ... }` still works; the CLI reads config fields from the file at generate time.
|
|
139
|
+
|
|
140
|
+
Re-exported types from the package root:
|
|
141
|
+
|
|
142
|
+
- `SourceConfig`, `QueryExtendsConfig`, `GenerationMode`, `NamingStrategy`
|
|
143
|
+
- `defineSourceConfig(config)` — identity helper for typed `source.ts`
|
|
144
|
+
|
|
145
|
+
| Field | Meaning |
|
|
146
|
+
| --- | --- |
|
|
147
|
+
| `spec` | Project-relative spec path (used when no `--spec` / env override) |
|
|
148
|
+
| `functionsDir` | Project-relative function output directory (defaults to the source's `generated/functions`) |
|
|
149
|
+
| `typesDir` | Project-relative type output directory (defaults to the source's `generated/types`; a generated `base.d.ts` is placed beside this directory when customized) |
|
|
150
|
+
| `pathPrefix` | Only generate operations under this prefix (e.g. `/api/acme/v3`) |
|
|
151
|
+
| `ignorePaths` | Extra paths to skip |
|
|
152
|
+
| `stripApiPrefix` | Strip a leading `/api` segment from route enum member names |
|
|
153
|
+
| `routeEnumName` | Enum name (default `RouteTargets`) |
|
|
154
|
+
| `generationMode` | `authoritative` (overwrite routes) or `merge` (keep extra enum members) |
|
|
155
|
+
| `naming` | `path` or `operationId` for function names |
|
|
156
|
+
| `queryExtends` | Fold page/limit/sort query params into shared pagination types |
|
|
157
|
+
| `tanstackQuery` | Emit Query helpers when `query-scope.ts` exists |
|
|
158
|
+
| `importBase` | Force import prefix for generated function files (overrides tsconfig aliases) |
|
|
159
|
+
| `maxRenderDepth` / `resolveMapKeyRefs` | Schema renderer limits |
|
|
160
|
+
| `unwrapResponseData` | Emit an envelope's `data` schema as the operation response type when the project's `HTTPFetch` already unwraps envelopes |
|
|
161
|
+
|
|
162
|
+
### 3. Spec resolution (first match wins)
|
|
163
|
+
|
|
164
|
+
1. `--spec <path>`
|
|
165
|
+
2. Env `OPENAPI_SPEC_<KEY>` — source key uppercased, hyphens → underscores
|
|
166
|
+
3. `spec` in that source’s `source.ts`
|
|
167
|
+
4. `typeforge.local.json` (gitignored) map of `{ "<source>": "<path>" }`
|
|
168
|
+
5. Committed snapshot `<apiRoot>/<source>/spec.json`
|
|
169
|
+
|
|
170
|
+
### 4. Envelope modes
|
|
171
|
+
|
|
172
|
+
Inferred from success response schemas. Details: [docs/envelope.md](docs/envelope.md).
|
|
173
|
+
|
|
174
|
+
| Mode | When | Types |
|
|
175
|
+
| --- | --- | --- |
|
|
176
|
+
| **shared** | One envelope shape (`data` / `success` / `message`) | `BaseResponse<Unwrapped>` |
|
|
177
|
+
| **raw** | No shared envelope | Spec schema as-is |
|
|
178
|
+
| **mixed** | Some ops have `data`, others do not | Unwrap **per operation** when `data` exists |
|
|
179
|
+
|
|
180
|
+
Set `unwrapResponseData: true` when the project's injected `HTTPFetch`
|
|
181
|
+
normalizes successful envelope bodies before returning `{ data }`. Every
|
|
182
|
+
operation whose success schema is recognized as an API envelope then receives
|
|
183
|
+
its `data` payload type. Data-only objects and business payloads that also
|
|
184
|
+
contain `success` remain raw. Metadata-only envelopes without a `data` field
|
|
185
|
+
receive the `null` type,
|
|
186
|
+
matching clients that normalize an omitted payload to `null`.
|
|
187
|
+
The default remains envelope-preserving and is compatible with the bundled
|
|
188
|
+
Axios and Fetch adapters.
|
|
189
|
+
|
|
190
|
+
### 5. HTTPFetch (`http.ts`)
|
|
191
|
+
|
|
192
|
+
Adapters implement `HTTPFetch` from `@openmirai/typeforge/http` (or the axios/fetch adapter packages). Methods return `Promise<{ data: TResponse }>`.
|
|
193
|
+
|
|
194
|
+
- If `http.ts` **exports `httpFetch`**, generated functions call that singleton.
|
|
195
|
+
- Otherwise they take `props.http: HTTPFetch` (injected).
|
|
196
|
+
|
|
197
|
+
### 6. Path-alias aware imports
|
|
198
|
+
|
|
199
|
+
Generated function files import types and `runtime`, and generated response
|
|
200
|
+
types import the generated base declaration (`base.ts` in monolith output, or
|
|
201
|
+
`base.d.ts` for split declaration output), using:
|
|
202
|
+
|
|
203
|
+
1. `importBase` in `source.ts`, if set
|
|
204
|
+
2. Else `compilerOptions.paths` from the nearest ancestor `tsconfig.json` with path aliases, starting at the corresponding `functionsDir` or `typesDir`
|
|
205
|
+
3. Else relative paths (`../../runtime`)
|
|
206
|
+
|
|
207
|
+
## Where files go
|
|
208
|
+
|
|
209
|
+
`typeforge.json`:
|
|
210
|
+
|
|
211
|
+
```json
|
|
212
|
+
{ "apiRoot": "packages/utils/src/api" }
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
You can also set `"typeforge": { "apiRoot": "..." }` in `package.json`. The JSON file wins.
|
|
216
|
+
|
|
217
|
+
**Monolith** (`--layout monolith`, default):
|
|
218
|
+
|
|
219
|
+
```text
|
|
220
|
+
src/api/http.ts
|
|
221
|
+
src/api/known-types.ts
|
|
222
|
+
src/api/models.ts # optional BaseResponse drift check
|
|
223
|
+
src/api/query-scope.ts # optional TanStack
|
|
224
|
+
src/api/atlas/source.ts
|
|
225
|
+
src/api/atlas/spec.json # optional snapshot
|
|
226
|
+
src/api/atlas/generated/…
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**Packages layout** (`--layout packages`): typical placement is `packages/utils/src/api/<source>/`.
|
|
230
|
+
|
|
231
|
+
Set `functionsDir` and `typesDir` when callers and declarations belong in
|
|
232
|
+
different packages. Relative imports continue to work without aliases; when a
|
|
233
|
+
nearby `tsconfig.json` maps both output roots, deep generated imports use those
|
|
234
|
+
aliases automatically.
|
|
235
|
+
|
|
236
|
+
## Zod (optional)
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
import { createZodValidator } from "@openmirai/typeforge/validation/zod";
|
|
240
|
+
import { widgetListSchema } from "./widget-list";
|
|
241
|
+
|
|
242
|
+
await getWidgets({
|
|
243
|
+
params: { page: 1, limit: 20 },
|
|
244
|
+
config: { validateResponse: createZodValidator(widgetListSchema) },
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Releasing
|
|
249
|
+
|
|
250
|
+
Publishes go through [npm Trusted Publishing](https://docs.npmjs.com/trusted-publishers/) (GitHub Actions OIDC). Do not `npm publish` from a laptop.
|
|
251
|
+
|
|
252
|
+
| | Value |
|
|
253
|
+
| --- | --- |
|
|
254
|
+
| npm package | `@openmirai/typeforge` |
|
|
255
|
+
| GitHub repo | `openmirai/mirai-openapi-codegen` |
|
|
256
|
+
| Workflow | `.github/workflows/publish.yml` |
|
|
257
|
+
| Tag | `v*` (e.g. `v0.1.3`) |
|
|
258
|
+
|
|
259
|
+
## Develop this repo
|
|
260
|
+
|
|
261
|
+
This repository uses **pnpm** for its own CI. Consumers are not required to use pnpm.
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
pnpm install
|
|
265
|
+
pnpm verify # format, lint, typecheck, build, coverage
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Test layout: [test/README.md](test/README.md).
|
|
Binary file
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { AxiosInstance } from "axios";
|
|
2
|
+
//#region src/json/types.d.ts
|
|
3
|
+
type QueryParamValue = string | number | boolean | null | undefined;
|
|
4
|
+
type QueryParams = Record<string, QueryParamValue>;
|
|
5
|
+
//#endregion
|
|
6
|
+
//#region src/http/validate.d.ts
|
|
7
|
+
type ResponseValidator<T> = (value: unknown) => T;
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/http/types.d.ts
|
|
10
|
+
interface HTTPFetchConfig<TParams extends object = QueryParams, TResponse = unknown> {
|
|
11
|
+
signal?: AbortSignal;
|
|
12
|
+
params?: TParams;
|
|
13
|
+
headers?: Record<string, string>;
|
|
14
|
+
validateResponse?: ResponseValidator<TResponse>;
|
|
15
|
+
}
|
|
16
|
+
interface HTTPFetch {
|
|
17
|
+
get<TResponse, TParams extends object = QueryParams>(route: string, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
18
|
+
data: TResponse;
|
|
19
|
+
}>;
|
|
20
|
+
post<TResponse, TBody = unknown, TParams extends object = QueryParams>(route: string, body: TBody, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
21
|
+
data: TResponse;
|
|
22
|
+
}>;
|
|
23
|
+
put<TResponse, TBody = unknown, TParams extends object = QueryParams>(route: string, body: TBody, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
24
|
+
data: TResponse;
|
|
25
|
+
}>;
|
|
26
|
+
patch<TResponse, TBody = unknown, TParams extends object = QueryParams>(route: string, body: TBody, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
27
|
+
data: TResponse;
|
|
28
|
+
}>;
|
|
29
|
+
delete<TResponse, TParams extends object = QueryParams>(route: string, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
30
|
+
data: TResponse;
|
|
31
|
+
}>;
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/adapters/axios/index.d.ts
|
|
35
|
+
declare function createAxiosAdapter(instance: AxiosInstance): HTTPFetch;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { type HTTPFetch, type HTTPFetchConfig, createAxiosAdapter };
|
|
38
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/json/types.ts","../../../src/http/validate.ts","../../../src/http/types.ts","../../../src/adapters/axios/index.ts"],"mappings":";;KAUY;KAEA,cAAc,eAAe;;;KCZ7B,kBAAkB,MAAM,mBAAmB;;;UCOtC,gBACf,yBAAyB,aACzB;EAEA,SAAS;EACT,SAAS;EACT,UAAU;EACV,mBAAmB,kBAAkB;;UAGtB;EACf,IAAI,WAAW,yBAAyB,aACtC,eACA,SAAS,gBAAgB,SAAS,aACjC;IAAU,MAAM;;EACnB,KAAK,WAAW,iBAAiB,yBAAyB,aACxD,eACA,MAAM,OACN,SAAS,gBAAgB,SAAS,aACjC;IAAU,MAAM;;EACnB,IAAI,WAAW,iBAAiB,yBAAyB,aACvD,eACA,MAAM,OACN,SAAS,gBAAgB,SAAS,aACjC;IAAU,MAAM;;EACnB,MAAM,WAAW,iBAAiB,yBAAyB,aACzD,eACA,MAAM,OACN,SAAS,gBAAgB,SAAS,aACjC;IAAU,MAAM;;EACnB,OAAO,WAAW,yBAAyB,aACzC,eACA,SAAS,gBAAgB,SAAS,aACjC;IAAU,MAAM;;;;;iBCLL,mBAAmB,UAAU,gBAAgB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//#region src/http/validate.ts
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/http/validate.ts","../../../src/adapters/axios/index.ts"],"sourcesContent":["export type ResponseValidator<T> = (value: unknown) => T;\n\nexport class ResponseValidationError extends Error {\n override readonly cause: unknown;\n\n constructor(message: string, cause: unknown) {\n super(message);\n this.name = \"ResponseValidationError\";\n this.cause = cause;\n }\n}\n\nexport function coerceResponseData<T>(\n value: unknown,\n validator?: ResponseValidator<T>\n): T {\n if (validator === undefined) {\n return value as T;\n }\n\n try {\n return validator(value);\n } catch (error) {\n throw new ResponseValidationError(\"Response validation failed\", error);\n }\n}\n","import type { AxiosInstance, AxiosRequestConfig } from \"axios\";\n\nimport { coerceResponseData } from \"../../http/validate\";\nimport type { HTTPFetch, HTTPFetchConfig } from \"../../http/types\";\nimport type { QueryParams } from \"../../json/types\";\n\nfunction toAxiosConfig<TParams extends object>(\n config?: HTTPFetchConfig<TParams, unknown>\n): AxiosRequestConfig | undefined {\n if (config === undefined) {\n return undefined;\n }\n\n const axiosConfig: AxiosRequestConfig = {};\n if (config.signal !== undefined) {\n axiosConfig.signal = config.signal;\n }\n if (config.params !== undefined) {\n axiosConfig.params = config.params;\n }\n if (config.headers !== undefined) {\n axiosConfig.headers = config.headers;\n }\n return axiosConfig;\n}\n\nfunction mapResponse<TResponse, TParams extends object>(\n data: unknown,\n config?: HTTPFetchConfig<TParams, TResponse>\n): { data: TResponse } {\n return {\n data: coerceResponseData<TResponse>(data, config?.validateResponse),\n };\n}\n\nexport function createAxiosAdapter(instance: AxiosInstance): HTTPFetch {\n return {\n delete: <TResponse, TParams extends object = QueryParams>(\n route: string,\n config?: HTTPFetchConfig<TParams, TResponse>\n ) =>\n instance\n .delete<TResponse>(route, toAxiosConfig(config))\n .then((response) => mapResponse(response.data, config)),\n get: <TResponse, TParams extends object = QueryParams>(\n route: string,\n config?: HTTPFetchConfig<TParams, TResponse>\n ) =>\n instance\n .get<TResponse>(route, toAxiosConfig(config))\n .then((response) => mapResponse(response.data, config)),\n patch: <TResponse, TBody = unknown, TParams extends object = QueryParams>(\n route: string,\n body: TBody,\n config?: HTTPFetchConfig<TParams, TResponse>\n ) =>\n instance\n .patch<TResponse>(route, body, toAxiosConfig(config))\n .then((response) => mapResponse(response.data, config)),\n post: <TResponse, TBody = unknown, TParams extends object = QueryParams>(\n route: string,\n body: TBody,\n config?: HTTPFetchConfig<TParams, TResponse>\n ) =>\n instance\n .post<TResponse>(route, body, toAxiosConfig(config))\n .then((response) => mapResponse(response.data, config)),\n put: <TResponse, TBody = unknown, TParams extends object = QueryParams>(\n route: string,\n body: TBody,\n config?: HTTPFetchConfig<TParams, TResponse>\n ) =>\n instance\n .put<TResponse>(route, body, toAxiosConfig(config))\n .then((response) => mapResponse(response.data, config)),\n };\n}\n\nexport type { HTTPFetch, HTTPFetchConfig } from \"../../http/types\";\n"],"mappings":";AAEA,IAAa,0BAAb,cAA6C,MAAM;CACjD;CAEA,YAAY,SAAiB,OAAgB;EAC3C,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,QAAQ;CACf;AACF;AAEA,SAAgB,mBACd,OACA,WACG;CACH,IAAI,cAAc,KAAA,GAChB,OAAO;CAGT,IAAI;EACF,OAAO,UAAU,KAAK;CACxB,SAAS,OAAO;EACd,MAAM,IAAI,wBAAwB,8BAA8B,KAAK;CACvE;AACF;;;ACnBA,SAAS,cACP,QACgC;CAChC,IAAI,WAAW,KAAA,GACb;CAGF,MAAM,cAAkC,CAAC;CACzC,IAAI,OAAO,WAAW,KAAA,GACpB,YAAY,SAAS,OAAO;CAE9B,IAAI,OAAO,WAAW,KAAA,GACpB,YAAY,SAAS,OAAO;CAE9B,IAAI,OAAO,YAAY,KAAA,GACrB,YAAY,UAAU,OAAO;CAE/B,OAAO;AACT;AAEA,SAAS,YACP,MACA,QACqB;CACrB,OAAO,EACL,MAAM,mBAA8B,MAAM,QAAQ,gBAAgB,EACpE;AACF;AAEA,SAAgB,mBAAmB,UAAoC;CACrE,OAAO;EACL,SACE,OACA,WAEA,SACG,OAAkB,OAAO,cAAc,MAAM,CAAC,CAAC,CAC/C,MAAM,aAAa,YAAY,SAAS,MAAM,MAAM,CAAC;EAC1D,MACE,OACA,WAEA,SACG,IAAe,OAAO,cAAc,MAAM,CAAC,CAAC,CAC5C,MAAM,aAAa,YAAY,SAAS,MAAM,MAAM,CAAC;EAC1D,QACE,OACA,MACA,WAEA,SACG,MAAiB,OAAO,MAAM,cAAc,MAAM,CAAC,CAAC,CACpD,MAAM,aAAa,YAAY,SAAS,MAAM,MAAM,CAAC;EAC1D,OACE,OACA,MACA,WAEA,SACG,KAAgB,OAAO,MAAM,cAAc,MAAM,CAAC,CAAC,CACnD,MAAM,aAAa,YAAY,SAAS,MAAM,MAAM,CAAC;EAC1D,MACE,OACA,MACA,WAEA,SACG,IAAe,OAAO,MAAM,cAAc,MAAM,CAAC,CAAC,CAClD,MAAM,aAAa,YAAY,SAAS,MAAM,MAAM,CAAC;CAC5D;AACF"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/json/types.d.ts
|
|
2
|
+
type QueryParamValue = string | number | boolean | null | undefined;
|
|
3
|
+
type QueryParams = Record<string, QueryParamValue>;
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region src/http/validate.d.ts
|
|
6
|
+
type ResponseValidator<T> = (value: unknown) => T;
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region src/http/types.d.ts
|
|
9
|
+
interface HTTPFetchConfig<TParams extends object = QueryParams, TResponse = unknown> {
|
|
10
|
+
signal?: AbortSignal;
|
|
11
|
+
params?: TParams;
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
validateResponse?: ResponseValidator<TResponse>;
|
|
14
|
+
}
|
|
15
|
+
interface HTTPFetch {
|
|
16
|
+
get<TResponse, TParams extends object = QueryParams>(route: string, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
17
|
+
data: TResponse;
|
|
18
|
+
}>;
|
|
19
|
+
post<TResponse, TBody = unknown, TParams extends object = QueryParams>(route: string, body: TBody, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
20
|
+
data: TResponse;
|
|
21
|
+
}>;
|
|
22
|
+
put<TResponse, TBody = unknown, TParams extends object = QueryParams>(route: string, body: TBody, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
23
|
+
data: TResponse;
|
|
24
|
+
}>;
|
|
25
|
+
patch<TResponse, TBody = unknown, TParams extends object = QueryParams>(route: string, body: TBody, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
26
|
+
data: TResponse;
|
|
27
|
+
}>;
|
|
28
|
+
delete<TResponse, TParams extends object = QueryParams>(route: string, config?: HTTPFetchConfig<TParams, TResponse>): Promise<{
|
|
29
|
+
data: TResponse;
|
|
30
|
+
}>;
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/adapters/fetch/index.d.ts
|
|
34
|
+
interface FetchAdapterOptions {
|
|
35
|
+
baseURL?: string;
|
|
36
|
+
headers?: Record<string, string>;
|
|
37
|
+
fetch?: typeof fetch;
|
|
38
|
+
}
|
|
39
|
+
declare function createFetchAdapter(options?: FetchAdapterOptions): HTTPFetch;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { FetchAdapterOptions, type HTTPFetch, type HTTPFetchConfig, createFetchAdapter };
|
|
42
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/json/types.ts","../../../src/http/validate.ts","../../../src/http/types.ts","../../../src/adapters/fetch/index.ts"],"mappings":";KAUY;KAEA,cAAc,eAAe;;;KCZ7B,kBAAkB,MAAM,mBAAmB;;;UCOtC,gBACf,yBAAyB,aACzB;EAEA,SAAS;EACT,SAAS;EACT,UAAU;EACV,mBAAmB,kBAAkB;;UAGtB;EACf,IAAI,WAAW,yBAAyB,aACtC,eACA,SAAS,gBAAgB,SAAS,aACjC;IAAU,MAAM;;EACnB,KAAK,WAAW,iBAAiB,yBAAyB,aACxD,eACA,MAAM,OACN,SAAS,gBAAgB,SAAS,aACjC;IAAU,MAAM;;EACnB,IAAI,WAAW,iBAAiB,yBAAyB,aACvD,eACA,MAAM,OACN,SAAS,gBAAgB,SAAS,aACjC;IAAU,MAAM;;EACnB,MAAM,WAAW,iBAAiB,yBAAyB,aACzD,eACA,MAAM,OACN,SAAS,gBAAgB,SAAS,aACjC;IAAU,MAAM;;EACnB,OAAO,WAAW,yBAAyB,aACzC,eACA,SAAS,gBAAgB,SAAS,aACjC;IAAU,MAAM;;;;;UCnCJ;EACf;EACA,UAAU;EACV,eAAe;;iBAqED,mBACd,UAAS,sBACR"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
//#region src/json/types.ts
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/json/types.ts","../../../src/http/validate.ts","../../../src/adapters/fetch/index.ts"],"sourcesContent":["export type JsonPrimitive = string | number | boolean | null;\n\nexport interface JsonObject {\n [key: string]: JsonValue;\n}\n\nexport type JsonArray = Array<JsonValue>;\n\nexport type JsonValue = JsonPrimitive | JsonObject | JsonArray;\n\nexport type QueryParamValue = string | number | boolean | null | undefined;\n\nexport type QueryParams = Record<string, QueryParamValue>;\n\nexport function isJsonPrimitive(value: JsonValue): value is JsonPrimitive {\n return (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n );\n}\n\nexport function isJsonValue(value: unknown): value is JsonValue {\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return true;\n }\n\n if (Array.isArray(value)) {\n return value.every(isJsonValue);\n }\n\n if (typeof value === \"object\" && value !== null) {\n return Object.values(value).every(isJsonValue);\n }\n\n return false;\n}\n\nexport function isJsonObject(value: unknown): value is JsonObject {\n return (\n isJsonValue(value) &&\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value)\n );\n}\n\nexport function isJsonArray(value: unknown): value is JsonArray {\n return Array.isArray(value) && value.every(isJsonValue);\n}\n\nexport function parseJson(text: string): JsonValue {\n const parsed: unknown = JSON.parse(text);\n if (!isJsonValue(parsed)) {\n throw new TypeError(\"JSON text did not parse to a valid JSON value\");\n }\n return parsed;\n}\n\nexport function readJsonObject(text: string): JsonObject {\n const parsed = parseJson(text);\n if (!isJsonObject(parsed)) {\n throw new TypeError(\"JSON text did not parse to a JSON object\");\n }\n return parsed;\n}\n\nexport function readJsonPrimitives(\n values: JsonValue | undefined\n): Array<JsonPrimitive> {\n if (!isJsonArray(values)) {\n return [];\n }\n\n return values.filter(isJsonPrimitive);\n}\n","export type ResponseValidator<T> = (value: unknown) => T;\n\nexport class ResponseValidationError extends Error {\n override readonly cause: unknown;\n\n constructor(message: string, cause: unknown) {\n super(message);\n this.name = \"ResponseValidationError\";\n this.cause = cause;\n }\n}\n\nexport function coerceResponseData<T>(\n value: unknown,\n validator?: ResponseValidator<T>\n): T {\n if (validator === undefined) {\n return value as T;\n }\n\n try {\n return validator(value);\n } catch (error) {\n throw new ResponseValidationError(\"Response validation failed\", error);\n }\n}\n","import type { JsonValue, QueryParams } from \"../../json/types\";\nimport { parseJson } from \"../../json/types\";\nimport { coerceResponseData } from \"../../http/validate\";\nimport type { HTTPFetch, HTTPFetchConfig } from \"../../http/types\";\n\nexport interface FetchAdapterOptions {\n baseURL?: string;\n headers?: Record<string, string>;\n fetch?: typeof fetch;\n}\n\nfunction appendQuery(url: string, params?: object): string {\n if (params === undefined || Object.keys(params).length === 0) {\n return url;\n }\n\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) {\n search.append(key, String(value));\n }\n\n const query = search.toString();\n if (query.length === 0) {\n return url;\n }\n\n return `${url}${url.includes(\"?\") ? \"&\" : \"?\"}${query}`;\n}\n\nfunction readResponseBody(text: string): JsonValue | undefined {\n if (text.length === 0) {\n return undefined;\n }\n return parseJson(text);\n}\n\nasync function request<TResponse, TParams extends object>(\n method: string,\n route: string,\n options: FetchAdapterOptions,\n body?: unknown,\n config?: HTTPFetchConfig<TParams, TResponse>\n): Promise<{ data: TResponse }> {\n const fetchImpl = options.fetch ?? globalThis.fetch;\n const baseURL = options.baseURL ?? \"\";\n const url = appendQuery(`${baseURL}${route}`, config?.params);\n\n const headers: Record<string, string> = {\n ...options.headers,\n ...config?.headers,\n };\n\n const init: RequestInit = {\n headers,\n method,\n };\n if (config?.signal !== undefined) {\n init.signal = config.signal;\n }\n\n if (body !== undefined) {\n headers[\"Content-Type\"] ??= \"application/json\";\n init.body = JSON.stringify(body);\n }\n\n const response = await fetchImpl(url, init);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status} ${response.statusText}`);\n }\n\n const text = await response.text();\n const parsed = readResponseBody(text);\n return {\n data: coerceResponseData<TResponse>(parsed, config?.validateResponse),\n };\n}\n\nexport function createFetchAdapter(\n options: FetchAdapterOptions = {}\n): HTTPFetch {\n return {\n delete: <TResponse, TParams extends object = QueryParams>(\n route: string,\n config?: HTTPFetchConfig<TParams, TResponse>\n ) =>\n request<TResponse, TParams>(\"DELETE\", route, options, undefined, config),\n get: <TResponse, TParams extends object = QueryParams>(\n route: string,\n config?: HTTPFetchConfig<TParams, TResponse>\n ) => request<TResponse, TParams>(\"GET\", route, options, undefined, config),\n patch: <TResponse, TBody = unknown, TParams extends object = QueryParams>(\n route: string,\n body: TBody,\n config?: HTTPFetchConfig<TParams, TResponse>\n ) => request<TResponse, TParams>(\"PATCH\", route, options, body, config),\n post: <TResponse, TBody = unknown, TParams extends object = QueryParams>(\n route: string,\n body: TBody,\n config?: HTTPFetchConfig<TParams, TResponse>\n ) => request<TResponse, TParams>(\"POST\", route, options, body, config),\n put: <TResponse, TBody = unknown, TParams extends object = QueryParams>(\n route: string,\n body: TBody,\n config?: HTTPFetchConfig<TParams, TResponse>\n ) => request<TResponse, TParams>(\"PUT\", route, options, body, config),\n };\n}\n\nexport type { HTTPFetch, HTTPFetchConfig } from \"../../http/types\";\n"],"mappings":";AAuBA,SAAgB,YAAY,OAAoC;CAC9D,IACE,UAAU,QACV,OAAO,UAAU,YACjB,OAAO,UAAU,YACjB,OAAO,UAAU,WAEjB,OAAO;CAGT,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO,MAAM,MAAM,WAAW;CAGhC,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,OAAO,OAAO,OAAO,KAAK,CAAC,CAAC,MAAM,WAAW;CAG/C,OAAO;AACT;AAeA,SAAgB,UAAU,MAAyB;CACjD,MAAM,SAAkB,KAAK,MAAM,IAAI;CACvC,IAAI,CAAC,YAAY,MAAM,GACrB,MAAM,IAAI,UAAU,+CAA+C;CAErE,OAAO;AACT;;;AC7DA,IAAa,0BAAb,cAA6C,MAAM;CACjD;CAEA,YAAY,SAAiB,OAAgB;EAC3C,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,QAAQ;CACf;AACF;AAEA,SAAgB,mBACd,OACA,WACG;CACH,IAAI,cAAc,KAAA,GAChB,OAAO;CAGT,IAAI;EACF,OAAO,UAAU,KAAK;CACxB,SAAS,OAAO;EACd,MAAM,IAAI,wBAAwB,8BAA8B,KAAK;CACvE;AACF;;;ACdA,SAAS,YAAY,KAAa,QAAyB;CACzD,IAAI,WAAW,KAAA,KAAa,OAAO,KAAK,MAAM,CAAC,CAAC,WAAW,GACzD,OAAO;CAGT,MAAM,SAAS,IAAI,gBAAgB;CACnC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,GAC9C,OAAO,OAAO,KAAK,OAAO,KAAK,CAAC;CAGlC,MAAM,QAAQ,OAAO,SAAS;CAC9B,IAAI,MAAM,WAAW,GACnB,OAAO;CAGT,OAAO,GAAG,MAAM,IAAI,SAAS,GAAG,IAAI,MAAM,MAAM;AAClD;AAEA,SAAS,iBAAiB,MAAqC;CAC7D,IAAI,KAAK,WAAW,GAClB;CAEF,OAAO,UAAU,IAAI;AACvB;AAEA,eAAe,QACb,QACA,OACA,SACA,MACA,QAC8B;CAC9B,MAAM,YAAY,QAAQ,SAAS,WAAW;CAE9C,MAAM,MAAM,YAAY,GADR,QAAQ,WAAW,KACE,SAAS,QAAQ,MAAM;CAE5D,MAAM,UAAkC;EACtC,GAAG,QAAQ;EACX,GAAG,QAAQ;CACb;CAEA,MAAM,OAAoB;EACxB;EACA;CACF;CACA,IAAI,QAAQ,WAAW,KAAA,GACrB,KAAK,SAAS,OAAO;CAGvB,IAAI,SAAS,KAAA,GAAW;EACtB,QAAQ,oBAAoB;EAC5B,KAAK,OAAO,KAAK,UAAU,IAAI;CACjC;CAEA,MAAM,WAAW,MAAM,UAAU,KAAK,IAAI;CAC1C,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,QAAQ,SAAS,OAAO,GAAG,SAAS,YAAY;CAKlE,OAAO,EACL,MAAM,mBAFO,iBAAiB,MADb,SAAS,KAAK,CAGK,GAAQ,QAAQ,gBAAgB,EACtE;AACF;AAEA,SAAgB,mBACd,UAA+B,CAAC,GACrB;CACX,OAAO;EACL,SACE,OACA,WAEA,QAA4B,UAAU,OAAO,SAAS,KAAA,GAAW,MAAM;EACzE,MACE,OACA,WACG,QAA4B,OAAO,OAAO,SAAS,KAAA,GAAW,MAAM;EACzE,QACE,OACA,MACA,WACG,QAA4B,SAAS,OAAO,SAAS,MAAM,MAAM;EACtE,OACE,OACA,MACA,WACG,QAA4B,QAAQ,OAAO,SAAS,MAAM,MAAM;EACrE,MACE,OACA,MACA,WACG,QAA4B,OAAO,OAAO,SAAS,MAAM,MAAM;CACtE;AACF"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/cli.d.ts
|
|
2
|
+
interface ParsedArgs {
|
|
3
|
+
command?: string;
|
|
4
|
+
/** Populated by the first --source value; kept for init (single-source) compat. */
|
|
5
|
+
source?: string;
|
|
6
|
+
/** All --source values collected for multi-source generate. */
|
|
7
|
+
sources: Array<string>;
|
|
8
|
+
spec?: string;
|
|
9
|
+
client?: "axios" | "fetch" | "custom";
|
|
10
|
+
layout?: "monolith" | "packages";
|
|
11
|
+
check?: boolean;
|
|
12
|
+
acceptBase?: boolean;
|
|
13
|
+
all?: boolean;
|
|
14
|
+
}
|
|
15
|
+
declare function parseArgs(argv: Array<string>): ParsedArgs;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { parseArgs };
|
|
18
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","names":[],"sources":["../src/cli.ts"],"mappings":";UASU;EACR;;EAEA;;EAEA,SAAS;EACT;EACA;EACA;EACA;EACA;EACA;;iBAGc,UAAU,MAAM,gBAAgB"}
|