genoc 0.2.0 → 0.4.0

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.
Files changed (72) hide show
  1. package/README.md +30 -163
  2. package/dist/analyzer/analyze.d.ts +18 -0
  3. package/dist/analyzer/analyze.js +534 -0
  4. package/dist/analyzer/naming.js +3 -2
  5. package/dist/analyzer/path-analyzer.d.ts +45 -6
  6. package/dist/analyzer/path-analyzer.js +82 -81
  7. package/dist/analyzer/schema-mapper.d.ts +3 -2
  8. package/dist/analyzer/schema-mapper.js +16 -8
  9. package/dist/analyzer/types.d.ts +119 -0
  10. package/dist/cli/app.d.ts +5 -2
  11. package/dist/cli/app.js +30 -4
  12. package/dist/cli/config-loader.d.ts +20 -0
  13. package/dist/cli/config-loader.js +186 -0
  14. package/dist/cli/config-schema.d.ts +105 -0
  15. package/dist/cli/config-schema.js +183 -0
  16. package/dist/cli/impl.d.ts +9 -1
  17. package/dist/cli/impl.js +190 -31
  18. package/dist/generator/client-generator.d.ts +13 -14
  19. package/dist/generator/client-generator.js +45 -77
  20. package/dist/generator/contracts-generator.d.ts +11 -9
  21. package/dist/generator/contracts-generator.js +45 -482
  22. package/dist/generator/method-generator.d.ts +1 -1
  23. package/dist/generator/method-generator.js +10 -150
  24. package/dist/parser/ref-resolver.d.ts +1 -1
  25. package/dist/parser/ref-resolver.js +1 -2
  26. package/dist/parser/spec-reader.d.ts +3 -2
  27. package/dist/parser/spec-reader.js +5 -4
  28. package/dist/parser/version/index.d.ts +4 -16
  29. package/dist/parser/version/index.js +3 -14
  30. package/dist/parser/version/v3.0/validator.d.ts +1 -1
  31. package/dist/parser/version/v3.1/validator.d.ts +17 -0
  32. package/dist/parser/version/v3.1/validator.js +126 -0
  33. package/dist/parser/version/validate.d.ts +9 -0
  34. package/dist/parser/version/validate.js +12 -0
  35. package/dist/parser/version/version-detector.d.ts +21 -0
  36. package/dist/parser/version/version-detector.js +19 -0
  37. package/dist/pipeline.d.ts +13 -0
  38. package/dist/pipeline.js +24 -0
  39. package/dist/types/client.d.ts +1 -12
  40. package/dist/utils/generator-helpers.d.ts +23 -25
  41. package/dist/utils/generator-helpers.js +144 -76
  42. package/dist/utils/operation-naming.d.ts +84 -0
  43. package/dist/utils/operation-naming.js +178 -0
  44. package/dist/utils/proxy.d.ts +6 -0
  45. package/dist/utils/proxy.js +81 -0
  46. package/package.json +5 -8
  47. package/dist/generator/error-types.d.ts +0 -13
  48. package/dist/generator/error-types.js +0 -67
  49. package/dist/index.d.ts +0 -8
  50. package/dist/index.js +0 -8
  51. package/dist/parser/validators.d.ts +0 -7
  52. package/dist/parser/validators.js +0 -79
  53. package/dist/parser/version/normalized-spec.d.ts +0 -199
  54. package/dist/parser/version/registry.d.ts +0 -28
  55. package/dist/parser/version/registry.js +0 -44
  56. package/dist/parser/version/v3.0/index.d.ts +0 -3
  57. package/dist/parser/version/v3.0/index.js +0 -3
  58. package/dist/parser/version/v3.0/normalizer.d.ts +0 -15
  59. package/dist/parser/version/v3.0/normalizer.js +0 -389
  60. package/dist/parser/version/v3.0/strategy.d.ts +0 -27
  61. package/dist/parser/version/v3.0/strategy.js +0 -96
  62. package/dist/parser/version/v3.1/index.d.ts +0 -1
  63. package/dist/parser/version/v3.1/index.js +0 -1
  64. package/dist/parser/version/v3.1/strategy.d.ts +0 -42
  65. package/dist/parser/version/v3.1/strategy.js +0 -513
  66. package/dist/parser/version/v3.2/index.d.ts +0 -4
  67. package/dist/parser/version/v3.2/index.js +0 -4
  68. package/dist/parser/version/v3.2/strategy.d.ts +0 -39
  69. package/dist/parser/version/v3.2/strategy.js +0 -57
  70. package/dist/parser/version/version-strategy.d.ts +0 -31
  71. package/dist/parser/version/version-strategy.js +0 -1
  72. /package/dist/{parser/version/normalized-spec.js → analyzer/types.js} +0 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # genoc
2
2
 
3
- Generate TypeScript HTTP clients from OpenAPI 3.0 / 3.1 specifications.
3
+ Generate TypeScript HTTP clients from OpenAPI 3.0 or 3.1 specifications.
4
4
  Generated code depends only on the tiny `genoc/runtime` module. Full type safety. Bring your own HTTP client.
5
5
 
6
6
  [![npm version](https://img.shields.io/npm/v/genoc)](https://www.npmjs.com/package/genoc)
@@ -11,13 +11,12 @@ Generated code depends only on the tiny `genoc/runtime` module. Full type safety
11
11
  ## Features
12
12
 
13
13
  - Full OpenAPI 3.0 and 3.1 specification support with automatic version detection
14
- - End-to-end type safety — requests, responses, and errors are fully typed
15
- - HTTP-client agnostic — adapter pattern lets you plug in fetch, axios, or anything else
16
- - Shared runtime contract — `genoc/runtime` exports the `Requester` type and response/error classes, so one requester implementation works with every generated client
14
+ - End-to-end type safety: requests, responses, and errors are fully typed
15
+ - Works with any HTTP client: plug in fetch, axios, or anything else
16
+ - Shared runtime contract: `genoc/runtime` exports the `Requester` type and response and error classes, so one requester implementation works with every generated client
17
17
  - Error types with per-status-code narrowing and type guards
18
- - File and binary upload/download with stream handling
18
+ - File and binary uploads and downloads with stream handling
19
19
  - Flexible method naming strategies (path-based, operationId, operationId-with-fallback)
20
- - CLI and programmatic API
21
20
 
22
21
  ## Quick Start
23
22
 
@@ -36,15 +35,18 @@ Generate:
36
35
  genoc ./path/to/spec.yaml --output-dir ./src/api
37
36
  ```
38
37
 
39
- This creates two files in `./src/api`:
38
+ This creates three files in `./src/api`:
40
39
 
41
- - `contracts.ts` — Type definitions, error classes, and helper types
42
- - `client.ts` — Typed client with `createClient(requester)` factory
40
+ - `contracts.ts`: type definitions, error classes, and helper types
41
+ - `client.ts`: typed client with the `createClient(requester)` factory
42
+ - `index.ts`: barrel that re-exports both files, so you can import directly from the output directory
43
+
44
+ The barrel means `import { createClient } from './index.js'` works too.
43
45
 
44
46
  ## Usage
45
47
 
46
- The generated client requires a `Requester` implementation — a function that
47
- performs the actual HTTP call and returns the result. The type lives in
48
+ The generated client requires a `Requester` implementation: a function that
49
+ performs the HTTP call and returns the result. The type lives in
48
50
  `genoc/runtime`, so you can write and compile a requester before generating
49
51
  anything:
50
52
 
@@ -52,20 +54,7 @@ anything:
52
54
  import type { Requester } from 'genoc/runtime';
53
55
  ```
54
56
 
55
- ```typescript
56
- type Requester = <TResponse>(
57
- method: string,
58
- path: string,
59
- options: {
60
- query?: Record<string, unknown>;
61
- body?: unknown;
62
- headers?: Record<string, string>;
63
- expectStream?: true;
64
- }
65
- ) => Promise<TResponse | StreamResponse | ErrorResponse>;
66
- ```
67
-
68
- ### Basic Example with `fetch`
57
+ For the full `Requester` type signature and binary and stream handling, see [Usage](./docs/usage.md).
69
58
 
70
59
  ```typescript
71
60
  import { createClient } from './client.js';
@@ -105,159 +94,37 @@ const requester: Requester = async (method, path, options) => {
105
94
 
106
95
  const client = createClient(requester);
107
96
 
108
- // Typed call — response type is inferred from the spec
97
+ // Typed call: response type is inferred from the spec
109
98
  const pets = await client.getPets({ limit: 10 });
110
99
  ```
111
100
 
112
- See [Binary / File Responses](#binary--file-responses) for handling `expectStream: true`.
113
-
114
- ## Shared Runtime (`genoc/runtime`)
115
-
116
- Generated clients import their response and error classes from `genoc/runtime`
117
- instead of declaring inline copies (the generated `contracts.ts` re-exports
118
- them, so existing imports keep working). This gives every generated client the
119
- same class identity — `instanceof` checks work across clients, and you can
120
- implement **one shared requester** typed against the package:
121
-
122
- ```typescript
123
- // common-requester.ts — reusable across all generated clients,
124
- // no generated imports needed
125
- import type { Requester } from 'genoc/runtime';
126
-
127
- export const requester: Requester = async (method, path, options) => {
128
- // ...your fetch/axios/etc. implementation
129
- };
130
- ```
131
-
132
- To pin a specific version or point at a mirror, override the import specifier
133
- via `--runtime-import-path` (CLI) or `runtimeImportPath` (programmatic config).
134
-
135
- ## Binary / File Responses
136
-
137
- When your spec defines binary responses (e.g. `format: binary`,
138
- `application/octet-stream`, `image/*`), the generated client sends
139
- `expectStream: true` in options. Your `Requester` should return a
140
- `StreamResponse` in that case:
141
-
142
- ```typescript
143
- import { StreamResponse } from 'genoc/runtime';
144
-
145
- // Inside your Requester implementation:
146
- if (options.expectStream === true) {
147
- return new StreamResponse(
148
- response.body as ReadableStream<Uint8Array>,
149
- getFilename(response.headers), // extract from Content-Disposition
150
- Object.fromEntries(response.headers.entries())
151
- );
152
- }
153
- ```
154
-
155
- `StreamResponse` is a simple container:
156
-
157
- ```typescript
158
- class StreamResponse {
159
- data: ReadableStream<Uint8Array>;
160
- filename?: string;
161
- headers: Record<string, string>;
162
- }
163
- ```
101
+ For handling `expectStream: true`, see [Binary and file responses](./docs/usage.md#binary-and-file-responses).
164
102
 
165
- ## CLI Reference
166
-
167
- ```bash
168
- genoc <spec> [flags]
169
- ```
170
-
171
- `<spec>` — Path or URL to an OpenAPI 3.0 / 3.1 spec (JSON or YAML).
172
-
173
- | Flag | Default | Description |
174
- | ------------------------ | --------------- | ------------------------------------------------------------ |
175
- | `--output-dir` | (required) | Output directory for generated files |
176
- | `--method-name-strategy` | `path-based` | Method naming strategy |
177
- | `--spec-version` | auto-detect | Override version detection (`"3.0"` or `"3.1"`) |
178
- | `--strict-version` | `true` | Warn if `--spec-version` mismatches detected version |
179
- | `--runtime-import-path` | `genoc/runtime` | Module specifier generated code imports runtime classes from |
180
-
181
- ## Method Naming Strategies
182
-
183
- - **`path-based`** (default) — HTTP method + path segments in PascalCase.
184
- `GET /pets` → `getPets`, `GET /api/v1/products` → `getApiV1Products`
185
-
186
- - **`operationId`** — Use the `operationId` field from the spec.
187
- `GET /pets` → `findPets` (if `operationId` is `"findPets"`)
188
-
189
- - **`operationId-with-fallback`** — Use `operationId` if present, otherwise
190
- fall back to path-based naming.
191
-
192
- ## JSDoc Documentation Output
193
-
194
- `description`, `deprecated`, `default`, `example`/`examples`, and `title`
195
- fields from your spec become JSDoc comments in the generated code — on object
196
- type properties, named schemas, and client methods. Object types are always
197
- emitted multi-line, so per-property JSDoc stays aligned at each nesting depth.
198
- `@deprecated` tags give you editor strikethrough on deprecated fields and
199
- methods for free.
200
-
201
- ## Programmatic API
202
-
203
- ```typescript
204
- import { generateClient } from 'genoc';
205
-
206
- await generateClient({
207
- input: './openapi.yaml',
208
- outputDir: './src/api',
209
- methodNameStrategy: 'path-based',
210
- specVersion: '3.1',
211
- strictVersion: true,
212
- });
213
- ```
214
-
215
- ## Error Handling
103
+ ## Error handling
216
104
 
217
105
  The generated client throws typed errors. Each method carries its own error
218
106
  union, and `isDefinedError` narrows a caught error to that union:
219
107
 
220
- - **`ApiError<TStatus, TData>`** — Error for a specific status code defined in the spec
221
- - **`UnspecifiedApiError`** — Error for a status code not defined in the spec
222
- - **`RequesterFailError`** — Wraps unexpected failures in your `Requester`
223
- - **`isDefinedError(err, client.method)`** — Type guard that narrows to the method's defined error union
224
-
225
- ```typescript
226
- import { UnspecifiedApiError, RequesterFailError } from './contracts.js';
227
- import { isDefinedError } from 'genoc/runtime';
228
-
229
- try {
230
- const result = await client.getPets();
231
- } catch (error) {
232
- if (isDefinedError(error, client.getPets)) {
233
- // error is narrowed to GetPetsErrors (ApiError<400, ...> | ApiError<500, ...>)
234
- if (error.status === 400) {
235
- console.error('Bad request:', error.data);
236
- }
237
- }
238
-
239
- if (error instanceof UnspecifiedApiError) {
240
- console.error('Unexpected status:', error.status, error.data);
241
- }
242
-
243
- if (error instanceof RequesterFailError) {
244
- console.error('Requester failed:', error.cause);
245
- }
246
- }
247
- ```
108
+ - **`ApiError<TStatus, TData>`**: error for a specific status code defined in the spec
109
+ - **`UnspecifiedApiError`**: error for a status code not defined in the spec
110
+ - **`RequesterFailError`**: wraps unexpected failures in your `Requester`
111
+ - **`isDefinedError(err, client.method)`**: type guard that narrows to the method's defined error union
248
112
 
249
- ## Feature Support
113
+ For the full example of catching and narrowing errors, see [Error handling](./docs/error-handling.md).
250
114
 
251
- Check the detailed feature support tables to see if your OpenAPI spec features are covered:
115
+ ## Documentation
252
116
 
253
- - **[OpenAPI 3.0 Support](./docs/openapi-3.0-support.md)** — Data types, schema keywords, parameters, request bodies, file uploads, responses, error handling, `$ref` resolution, components, security schemes, servers, and path operations.
254
- - **[OpenAPI 3.1 Support](./docs/openapi-3.1-support.md)** — All 3.0 features plus type arrays, `$ref` siblings, webhooks, JSON Schema 2020-12 alignment, and a [3.0 → 3.1 diff](./docs/openapi-3.1-support.md#differences-from-openapi-30).
117
+ - [Configuration](./docs/configuration.md): CLI flags, `.genocrc` config files, method naming strategies, and proxy support
118
+ - [Usage](./docs/usage.md): the `Requester` contract, shared runtime, binary and file responses, and JSDoc output
119
+ - [Error handling](./docs/error-handling.md): typed errors, `isDefinedError`, and the catching example
120
+ - [OpenAPI 3.0 support](./docs/openapi-3.0-support.md): data types, schema keywords, parameters, bodies, uploads, responses, errors, `$ref`, components, security, servers, and operations
121
+ - [OpenAPI 3.1 support](./docs/openapi-3.1-support.md): all 3.0 features plus webhooks and JSON Schema 2020-12 alignment, with a diff against 3.0
255
122
 
256
123
  ## Requirements
257
124
 
258
- - Node.js >= 18
125
+ - Node.js 18 or later
259
126
  - OpenAPI 3.0.x or 3.1.x specification (JSON or YAML, file path or URL)
260
127
 
261
128
  ## License
262
129
 
263
- [MIT](./LICENSE) — Copyright © Andrey Kiselev
130
+ [MIT](./LICENSE). Copyright © Andrey Kiselev
@@ -0,0 +1,18 @@
1
+ import type { OpenAPIDocument } from '../types/openapi.js';
2
+ import type { AnalyzedSpec, AnalyzeOptions } from './types.js';
3
+ /**
4
+ * Build a description-only type-level JSDoc comment for operation-derived
5
+ * types (body / response). Returns '' when the description is absent or
6
+ * whitespace-only so callers can skip emission entirely.
7
+ */
8
+ export declare function buildDescriptionJsDoc(description: string | undefined): string;
9
+ /**
10
+ * Analyze an OpenAPI document into the finished model every renderer consumes:
11
+ * schema→TS-type translation (rename machinery, discriminator discovery, the
12
+ * schema mapper) runs here exactly once, producing render-ready type text.
13
+ *
14
+ * @param doc - The parsed and validated OpenAPI document
15
+ * @param opts - Optional resolver override and method naming strategy
16
+ * @returns The AnalyzedSpec model consumed by all generators
17
+ */
18
+ export declare function analyze(doc: OpenAPIDocument, opts?: AnalyzeOptions): AnalyzedSpec;