@constantant/openapi-resource-gen 1.1.3 → 1.2.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.
- package/CHANGELOG.md +34 -0
- package/README.md +160 -29
- package/package.json +2 -2
- package/src/generators/api-resource/endpoint-model.d.ts +13 -0
- package/src/generators/api-resource/generator.js +10 -6
- package/src/generators/api-resource/generator.js.map +1 -1
- package/src/generators/api-resource/parse-spec.d.ts +2 -1
- package/src/generators/api-resource/parse-spec.js +40 -0
- package/src/generators/api-resource/parse-spec.js.map +1 -1
- package/src/generators/api-resource/render-token.d.ts +3 -2
- package/src/generators/api-resource/render-token.js +118 -14
- package/src/generators/api-resource/render-token.js.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,37 @@
|
|
|
1
|
+
## 1.2.0 (2026-06-07)
|
|
2
|
+
|
|
3
|
+
### 🚀 Features
|
|
4
|
+
|
|
5
|
+
- **generator:** add Digest auth security scheme support ([a31e1b9](https://github.com/constantant/angular-openapi-gen/commit/a31e1b9))
|
|
6
|
+
|
|
7
|
+
### 📖 Documentation
|
|
8
|
+
|
|
9
|
+
- document Digest auth security scheme support ([5265b0a](https://github.com/constantant/angular-openapi-gen/commit/5265b0a))
|
|
10
|
+
|
|
11
|
+
### ❤️ Thank You
|
|
12
|
+
|
|
13
|
+
- Claude Sonnet 4.6
|
|
14
|
+
- kk
|
|
15
|
+
|
|
16
|
+
## 1.1.4 (2026-06-07)
|
|
17
|
+
|
|
18
|
+
### 🚀 Features
|
|
19
|
+
|
|
20
|
+
- **api-explorer:** add YouTube page with reactive auth token ([adba6b2](https://github.com/constantant/angular-openapi-gen/commit/adba6b2))
|
|
21
|
+
- **generator:** make security tokens reactive via Signal<string | null> ([52484e7](https://github.com/constantant/angular-openapi-gen/commit/52484e7))
|
|
22
|
+
- **youtube:** add youtube-data-access lib and fix dotted operationId support ([64ef851](https://github.com/constantant/angular-openapi-gen/commit/64ef851))
|
|
23
|
+
- **generator:** add security scheme support ([b3c7629](https://github.com/constantant/angular-openapi-gen/commit/b3c7629))
|
|
24
|
+
|
|
25
|
+
### 🩹 Fixes
|
|
26
|
+
|
|
27
|
+
- **generator:** suppress httpResource when params thunk returns undefined ([8cb9782](https://github.com/constantant/angular-openapi-gen/commit/8cb9782))
|
|
28
|
+
- **generator:** remove redundant non-null assertions in security headers ([5ffe9bb](https://github.com/constantant/angular-openapi-gen/commit/5ffe9bb))
|
|
29
|
+
|
|
30
|
+
### ❤️ Thank You
|
|
31
|
+
|
|
32
|
+
- Claude Sonnet 4.6
|
|
33
|
+
- kk
|
|
34
|
+
|
|
1
35
|
## 1.1.3 (2026-06-06)
|
|
2
36
|
|
|
3
37
|
This was a version bump only for openapi-resource-gen to align it with other projects, there were no code changes.
|
package/README.md
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
# openapi-resource-gen
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@constantant/openapi-resource-gen)
|
|
4
|
+
|
|
3
5
|
Nx generator that reads an OpenAPI 3.x spec and emits one `InjectionToken` per
|
|
4
6
|
endpoint, each in its own `.ts` file. The result is a tree-shakeable Angular
|
|
5
7
|
data-access library: only tokens that are actually injected end up in the bundle.
|
|
6
8
|
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -D @constantant/openapi-resource-gen
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Then use it directly:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx nx g @constantant/openapi-resource-gen:api-resource --specPath=specs/myapi.yaml --outputDir=libs/myapi-data-access/src
|
|
19
|
+
```
|
|
20
|
+
|
|
7
21
|
## Concept
|
|
8
22
|
|
|
9
23
|
Each endpoint becomes a typed `InjectionToken` whose value is a factory function.
|
|
@@ -14,6 +28,8 @@ signal-native HTTP wrapper.
|
|
|
14
28
|
OpenAPI spec → generator → one .token.ts per endpoint
|
|
15
29
|
└─ InjectionToken + typed factory function
|
|
16
30
|
└─ export type Params / Body / Response
|
|
31
|
+
→ one .security-token.ts per security scheme
|
|
32
|
+
└─ InjectionToken<Signal<string | null>>
|
|
17
33
|
```
|
|
18
34
|
|
|
19
35
|
All types are derived from the generated `schema.d.ts` (via `openapi-typescript`)
|
|
@@ -34,7 +50,7 @@ Bundling all endpoints into a single file would prevent this.
|
|
|
34
50
|
| `'root'` | Yes — self-registers | Just `inject()` it anywhere; Angular handles registration |
|
|
35
51
|
|
|
36
52
|
`'none'` is the default because it lets you inject the same token with different
|
|
37
|
-
|
|
53
|
+
base URL values in different route sub-trees (e.g. staging vs production,
|
|
38
54
|
or different micro-frontends). `'root'` is simpler but prevents per-scope
|
|
39
55
|
base URL overrides.
|
|
40
56
|
|
|
@@ -43,9 +59,10 @@ base URL overrides.
|
|
|
43
59
|
## Running the generator
|
|
44
60
|
|
|
45
61
|
```bash
|
|
46
|
-
npx nx g openapi-resource-gen:api-resource \
|
|
62
|
+
npx nx g @constantant/openapi-resource-gen:api-resource \
|
|
47
63
|
--specPath=specs/petstore.yaml \
|
|
48
|
-
--outputDir=libs/petstore-data-access/src
|
|
64
|
+
--outputDir=libs/petstore-data-access/src \
|
|
65
|
+
--baseUrlToken=PETSTORE_BASE_URL
|
|
49
66
|
```
|
|
50
67
|
|
|
51
68
|
### Options
|
|
@@ -65,12 +82,13 @@ npx nx g openapi-resource-gen:api-resource \
|
|
|
65
82
|
|
|
66
83
|
```
|
|
67
84
|
{outputDir}/
|
|
68
|
-
schema.d.ts
|
|
69
|
-
api-base-url.token.ts
|
|
70
|
-
|
|
85
|
+
schema.d.ts # openapi-typescript output, never edit manually
|
|
86
|
+
api-base-url.token.ts # InjectionToken<string> for the API root URL
|
|
87
|
+
{scheme}.security-token.ts # one per security scheme (if any)
|
|
88
|
+
index.ts # re-exports all tag barrels + base-url + security tokens
|
|
71
89
|
{tag}/
|
|
72
|
-
index.ts
|
|
73
|
-
{operation-id}.token.ts
|
|
90
|
+
index.ts # re-exports all token files in this tag folder
|
|
91
|
+
{operation-id}.token.ts # one file per endpoint
|
|
74
92
|
```
|
|
75
93
|
|
|
76
94
|
Tags map to subfolders; untagged operations go into `default/`.
|
|
@@ -79,7 +97,10 @@ Tags map to subfolders; untagged operations go into `default/`.
|
|
|
79
97
|
|
|
80
98
|
## Generated token anatomy
|
|
81
99
|
|
|
82
|
-
### GET with query params
|
|
100
|
+
### GET with query params
|
|
101
|
+
|
|
102
|
+
For GET endpoints with query params, the reactive lambda uses a **block-body form** so it can
|
|
103
|
+
return `undefined` to suppress the request when a thunk returns `undefined`.
|
|
83
104
|
|
|
84
105
|
```typescript
|
|
85
106
|
import { InjectionToken, inject, FactoryProvider } from '@angular/core';
|
|
@@ -89,7 +110,6 @@ import { PETSTORE_BASE_URL } from '../api-base-url.token';
|
|
|
89
110
|
|
|
90
111
|
export type FindPetsByStatusParams =
|
|
91
112
|
paths['/pet/findByStatus']['get']['parameters']['query'];
|
|
92
|
-
|
|
93
113
|
export type FindPetsByStatusResponse =
|
|
94
114
|
paths['/pet/findByStatus']['get']['responses']['200']['content']['application/json'];
|
|
95
115
|
|
|
@@ -104,16 +124,23 @@ export function provideFindPetsByStatus(): FactoryProvider {
|
|
|
104
124
|
useFactory: () => {
|
|
105
125
|
const base = inject(PETSTORE_BASE_URL);
|
|
106
126
|
return (params?) =>
|
|
107
|
-
httpResource<FindPetsByStatusResponse>(() =>
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
127
|
+
httpResource<FindPetsByStatusResponse>(() => {
|
|
128
|
+
const _params = typeof params === 'function' ? params() : params;
|
|
129
|
+
if (typeof params === 'function' && _params === undefined) return undefined;
|
|
130
|
+
return {
|
|
131
|
+
url: `${base}/pet/findByStatus`,
|
|
132
|
+
params: _params as unknown as Record<string, string | number | boolean | readonly (string | number | boolean)[]>,
|
|
133
|
+
};
|
|
134
|
+
});
|
|
111
135
|
},
|
|
112
136
|
};
|
|
113
137
|
}
|
|
114
138
|
```
|
|
115
139
|
|
|
116
|
-
|
|
140
|
+
Why block-body? `httpResource(() => ({ url }))` always returns an object → always fires.
|
|
141
|
+
`httpResource(() => { ...; return undefined; })` → resource stays idle when `undefined` is returned.
|
|
142
|
+
|
|
143
|
+
### GET with path params
|
|
117
144
|
|
|
118
145
|
Path params (`/repos/{owner}/{repo}`) become required positional arguments on
|
|
119
146
|
the returned function and are interpolated into the URL template:
|
|
@@ -127,7 +154,99 @@ export const REPOS_GET = new InjectionToken<
|
|
|
127
154
|
### Mutation (POST/PUT/PATCH/DELETE)
|
|
128
155
|
|
|
129
156
|
The factory returns `(body: BodyType | Signal<BodyType>) => httpResource(...)`.
|
|
130
|
-
The resource config receives `method: 'POST'` and `body` automatically.
|
|
157
|
+
The resource config receives `method: 'POST'` (etc.) and `body` automatically.
|
|
158
|
+
|
|
159
|
+
### Security schemes
|
|
160
|
+
|
|
161
|
+
The generator emits one file per security scheme. Two patterns are used depending on the
|
|
162
|
+
scheme kind.
|
|
163
|
+
|
|
164
|
+
#### Signal-based schemes
|
|
165
|
+
|
|
166
|
+
`bearer`, `oauth2`, `openIdConnect`, `basic`, `apiKey-header`, `apiKey-query` — emit
|
|
167
|
+
`InjectionToken<Signal<string | null>>`. Endpoint tokens inject these optionally and merge
|
|
168
|
+
auth into the request as headers or query params. Reading the signal inside the `httpResource`
|
|
169
|
+
lambda creates a reactive dependency — the request re-fires automatically when the token value
|
|
170
|
+
changes:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
// oauth2.security-token.ts
|
|
174
|
+
import { InjectionToken, Signal } from '@angular/core';
|
|
175
|
+
export const OAUTH2 = new InjectionToken<Signal<string | null>>('OAUTH2');
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
const oauth2 = inject(OAUTH2, { optional: true }); // Signal<string | null> | null
|
|
180
|
+
// In the reactive lambda:
|
|
181
|
+
headers: {
|
|
182
|
+
...(oauth2?.() != null ? { Authorization: `Bearer ${oauth2()}` } : {}),
|
|
183
|
+
},
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
| Kind | Auth mechanism |
|
|
187
|
+
|------|---------------|
|
|
188
|
+
| `bearer` / `oauth2` / `openIdConnect` | `Authorization: Bearer <token>` |
|
|
189
|
+
| `basic` | `Authorization: Basic <token>` |
|
|
190
|
+
| `apiKey-header` | Custom header (e.g. `X-API-Key: <token>`) |
|
|
191
|
+
| `apiKey-query` | Query param (e.g. `?apiKey=<token>`) |
|
|
192
|
+
|
|
193
|
+
Wire up in `app.config.ts`:
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
export const MY_API_KEY = new InjectionToken<WritableSignal<string | null>>(
|
|
197
|
+
'MY_API_KEY', { providedIn: 'root', factory: () => signal(null) }
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
{ provide: OAUTH2, useFactory: () => inject(MY_API_KEY) }
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### Interceptor-based schemes
|
|
204
|
+
|
|
205
|
+
`digest` — HTTP Digest is a challenge-response protocol: the Authorization header value
|
|
206
|
+
depends on the request URL, method, and a server-issued nonce, so it cannot be computed
|
|
207
|
+
as a static signal value. The generator emits `InjectionToken<HttpInterceptorFn>` plus a
|
|
208
|
+
**named, host-scoped interceptor wrapper**:
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
// digest-auth.security-token.ts (generated for MYAPI_BASE_URL)
|
|
212
|
+
import { InjectionToken, inject } from '@angular/core';
|
|
213
|
+
import { HttpInterceptorFn } from '@angular/common/http';
|
|
214
|
+
import { MYAPI_BASE_URL } from './api-base-url.token';
|
|
215
|
+
|
|
216
|
+
export const DIGEST_AUTH = new InjectionToken<HttpInterceptorFn>('DIGEST_AUTH');
|
|
217
|
+
|
|
218
|
+
export const myapiDigestAuthInterceptor: HttpInterceptorFn = (req, next) => {
|
|
219
|
+
const base = inject(MYAPI_BASE_URL);
|
|
220
|
+
if (!req.url.startsWith(base)) return next(req); // scoped to this API only
|
|
221
|
+
const fn = inject(DIGEST_AUTH, { optional: true });
|
|
222
|
+
if (!fn) return next(req);
|
|
223
|
+
return fn(req, next);
|
|
224
|
+
};
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
The interceptor name is derived from the base URL token name (`MYAPI_BASE_URL` → `myapi`)
|
|
228
|
+
and the scheme name. This makes it unique per API — if two APIs both use Digest, they emit
|
|
229
|
+
distinct interceptors with distinct host guards and never interfere with each other.
|
|
230
|
+
|
|
231
|
+
The consumer's implementation receives the full `HttpRequest`, which carries
|
|
232
|
+
`req.urlWithParams`, `req.method`, and `req.body` — everything needed to compute the
|
|
233
|
+
RFC 7616 hash with no reconstruction:
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
import { myapiDigestAuthInterceptor, DIGEST_AUTH } from '@angular-openapi-gen/myapi-data-access';
|
|
237
|
+
|
|
238
|
+
export const appConfig: ApplicationConfig = {
|
|
239
|
+
providers: [
|
|
240
|
+
provideHttpClient(
|
|
241
|
+
withInterceptors([myapiDigestAuthInterceptor])
|
|
242
|
+
),
|
|
243
|
+
{ provide: DIGEST_AUTH, useValue: myDigestInterceptorFn },
|
|
244
|
+
],
|
|
245
|
+
};
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Digest endpoint tokens do not inject the `DIGEST_AUTH` token directly — auth is applied
|
|
249
|
+
transparently by the interceptor at the HTTP layer.
|
|
131
250
|
|
|
132
251
|
---
|
|
133
252
|
|
|
@@ -168,12 +287,21 @@ export class PetsPageComponent {
|
|
|
168
287
|
}
|
|
169
288
|
```
|
|
170
289
|
|
|
171
|
-
###
|
|
290
|
+
### Conditional requests (thunk returning undefined)
|
|
172
291
|
|
|
173
292
|
The `params` argument accepts either a plain object or a **thunk**
|
|
174
|
-
`() => ParamsType`. When a thunk
|
|
175
|
-
|
|
176
|
-
|
|
293
|
+
`() => ParamsType | undefined`. When a thunk returns `undefined`, the resource
|
|
294
|
+
stays idle (no HTTP request). When it returns a value, the resource fires and
|
|
295
|
+
re-fires on any signal change inside the thunk:
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
// No request fires until both conditions are met
|
|
299
|
+
readonly results = this.youtubeSearch(() =>
|
|
300
|
+
this.apiKey() && this.query()
|
|
301
|
+
? { q: this.query(), key: this.apiKey()! }
|
|
302
|
+
: undefined
|
|
303
|
+
);
|
|
304
|
+
```
|
|
177
305
|
|
|
178
306
|
---
|
|
179
307
|
|
|
@@ -199,14 +327,16 @@ type PetStatus = FindPetsByStatusParams['status']; // 'available' | 'pending' |
|
|
|
199
327
|
|
|
200
328
|
2. Run the generator:
|
|
201
329
|
```bash
|
|
202
|
-
npx nx g openapi-resource-gen:api-resource \
|
|
330
|
+
npx nx g @constantant/openapi-resource-gen:api-resource \
|
|
203
331
|
--specPath=specs/myapi.yaml \
|
|
204
|
-
--outputDir=libs/myapi-data-access/src
|
|
332
|
+
--outputDir=libs/myapi-data-access/src \
|
|
333
|
+
--baseUrlToken=MYAPI_BASE_URL
|
|
205
334
|
```
|
|
206
335
|
|
|
207
|
-
3.
|
|
208
|
-
|
|
209
|
-
|
|
336
|
+
3. Add a path alias to `tsconfig.base.json`:
|
|
337
|
+
```json
|
|
338
|
+
"@angular-openapi-gen/myapi-data-access": ["libs/myapi-data-access/src/index.ts"]
|
|
339
|
+
```
|
|
210
340
|
|
|
211
341
|
4. Add base URL provider and token providers to `app.config.ts`.
|
|
212
342
|
|
|
@@ -220,11 +350,12 @@ overwrites all files in `outputDir`.
|
|
|
220
350
|
| Step | Tool | Purpose |
|
|
221
351
|
|------|------|---------|
|
|
222
352
|
| Spec loading | `js-yaml` + custom `stripNonSchemaRefs()` | Handle YAML and remove non-spec `$ref` links (markdown, images) that would break parsing |
|
|
223
|
-
| Type generation | `openapi-typescript`
|
|
353
|
+
| Type generation | `openapi-typescript` programmatic API | Emit `schema.d.ts` — the single source of truth for all request/response types |
|
|
224
354
|
| Spec dereferencing | `@apidevtools/swagger-parser` | Resolve all `$ref` chains for endpoint extraction |
|
|
225
|
-
|
|
|
355
|
+
| Security parsing | `parseSecuritySchemes(api)` | Extract scheme definitions; resolve per-operation overrides |
|
|
356
|
+
| Code generation | `renderTokenFile()` / `renderSecurityTokenFile()` | Direct string assembly for all token files |
|
|
226
357
|
| Formatting | `@nx/devkit` `formatFiles()` | Runs Prettier over all written files |
|
|
227
358
|
|
|
228
359
|
Hyphenated path parameter names (e.g. `{enterprise-team}` in the GitHub spec)
|
|
229
|
-
|
|
230
|
-
`toCamelCase()` to produce valid JavaScript identifiers.
|
|
360
|
+
and dotted operationIds (e.g. `youtube.search.list`) are converted to camelCase /
|
|
361
|
+
PascalCase via `toCamelCase()` / `toPascalCase()` to produce valid JavaScript identifiers.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constantant/openapi-resource-gen",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Nx generator: one InjectionToken per OpenAPI endpoint — tree-shakeable Angular data-access libs via httpResource",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -31,4 +31,4 @@
|
|
|
31
31
|
"tslib": "^2.3.0"
|
|
32
32
|
},
|
|
33
33
|
"type": "commonjs"
|
|
34
|
-
}
|
|
34
|
+
}
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
export type SecurityKind = 'bearer' | 'basic' | 'digest' | 'apiKey-header' | 'apiKey-query' | 'oauth2' | 'openIdConnect';
|
|
2
|
+
export interface SecuritySchemeModel {
|
|
3
|
+
schemeName: string;
|
|
4
|
+
kind: SecurityKind;
|
|
5
|
+
/** Header name (apiKey-header) or query param name (apiKey-query). */
|
|
6
|
+
apiKeyParamName?: string;
|
|
7
|
+
/** SCREAMING_SNAKE constant exported from the security token file. */
|
|
8
|
+
tokenName: string;
|
|
9
|
+
/** Kebab file name without extension, e.g. `bearer-auth.security-token`. */
|
|
10
|
+
fileName: string;
|
|
11
|
+
}
|
|
1
12
|
export interface EndpointModel {
|
|
2
13
|
tag: string;
|
|
3
14
|
operationId: string;
|
|
@@ -11,4 +22,6 @@ export interface EndpointModel {
|
|
|
11
22
|
hasResponse: boolean;
|
|
12
23
|
responseStatus: string | null;
|
|
13
24
|
bodyContentType: string | null;
|
|
25
|
+
/** Names of security schemes that apply to this endpoint (resolved from global + operation level). */
|
|
26
|
+
securitySchemeNames: string[];
|
|
14
27
|
}
|
|
@@ -102,7 +102,12 @@ async function apiResourceGenerator(tree, options) {
|
|
|
102
102
|
baseUrlToken,
|
|
103
103
|
tmpl: '',
|
|
104
104
|
});
|
|
105
|
-
// 5.
|
|
105
|
+
// 5. Parse security schemes and build EndpointModels
|
|
106
|
+
const securitySchemes = (0, parse_spec_1.parseSecuritySchemes)(api);
|
|
107
|
+
const schemesByName = new Map(securitySchemes.map((s) => [s.schemeName, s]));
|
|
108
|
+
for (const scheme of securitySchemes) {
|
|
109
|
+
tree.write((0, devkit_1.joinPathFragments)(outputDir, `${scheme.fileName}.ts`), (0, render_token_1.renderSecurityTokenFile)(scheme, baseUrlToken));
|
|
110
|
+
}
|
|
106
111
|
const endpoints = (0, parse_spec_1.buildEndpoints)(api, allowedTags, namingConvention);
|
|
107
112
|
// 6. Group by tag
|
|
108
113
|
const byTag = new Map();
|
|
@@ -115,18 +120,17 @@ async function apiResourceGenerator(tree, options) {
|
|
|
115
120
|
for (const [tag, tagEndpoints] of byTag) {
|
|
116
121
|
const tagDir = (0, devkit_1.joinPathFragments)(outputDir, tag);
|
|
117
122
|
for (const ep of tagEndpoints) {
|
|
118
|
-
tree.write((0, devkit_1.joinPathFragments)(tagDir, `${ep.fileName}.token.ts`), (0, render_token_1.renderTokenFile)(ep, baseUrlToken, providedIn));
|
|
123
|
+
tree.write((0, devkit_1.joinPathFragments)(tagDir, `${ep.fileName}.token.ts`), (0, render_token_1.renderTokenFile)(ep, baseUrlToken, providedIn, schemesByName));
|
|
119
124
|
}
|
|
120
125
|
const tagBarrel = tagEndpoints
|
|
121
126
|
.map((ep) => `export * from './${ep.fileName}.token';`)
|
|
122
127
|
.join('\n') + '\n';
|
|
123
128
|
tree.write((0, devkit_1.joinPathFragments)(tagDir, 'index.ts'), tagBarrel);
|
|
124
129
|
}
|
|
125
|
-
// 8. Root barrel index
|
|
130
|
+
// 8. Root barrel index
|
|
126
131
|
const rootBarrel = `export * from './api-base-url.token';\n` +
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
.join('\n') + '\n';
|
|
132
|
+
securitySchemes.map((s) => `export * from './${s.fileName}';\n`).join('') +
|
|
133
|
+
[...byTag.keys()].map((tag) => `export * from './${tag}';\n`).join('');
|
|
130
134
|
tree.write((0, devkit_1.joinPathFragments)(outputDir, 'index.ts'), rootBarrel);
|
|
131
135
|
}
|
|
132
136
|
finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../../tools/openapi-resource-gen/src/generators/api-resource/generator.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../../tools/openapi-resource-gen/src/generators/api-resource/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { OpenAPIV3 } from 'openapi-types';
|
|
2
|
-
import type { EndpointModel } from './endpoint-model';
|
|
2
|
+
import type { EndpointModel, SecuritySchemeModel } from './endpoint-model';
|
|
3
3
|
export declare function toScreamingSnake(str: string): string;
|
|
4
4
|
export declare function toKebabCase(str: string): string;
|
|
5
|
+
export declare function parseSecuritySchemes(api: OpenAPIV3.Document): SecuritySchemeModel[];
|
|
5
6
|
export declare function buildEndpoints(api: OpenAPIV3.Document, allowedTags: string[] | null, namingConvention: 'camel' | 'kebab'): EndpointModel[];
|
|
6
7
|
/** Convenience wrapper that dereferences the spec before building endpoints. */
|
|
7
8
|
export declare function parseSpec(specPath: string, allowedTags: string[] | null, namingConvention: 'camel' | 'kebab'): Promise<EndpointModel[]>;
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.toScreamingSnake = toScreamingSnake;
|
|
7
7
|
exports.toKebabCase = toKebabCase;
|
|
8
|
+
exports.parseSecuritySchemes = parseSecuritySchemes;
|
|
8
9
|
exports.buildEndpoints = buildEndpoints;
|
|
9
10
|
exports.parseSpec = parseSpec;
|
|
10
11
|
const swagger_parser_1 = __importDefault(require("@apidevtools/swagger-parser"));
|
|
@@ -34,8 +35,40 @@ function toKebabCase(str) {
|
|
|
34
35
|
.replace(/-+/g, '-')
|
|
35
36
|
.replace(/^-|-$/g, '');
|
|
36
37
|
}
|
|
38
|
+
function parseSecuritySchemes(api) {
|
|
39
|
+
const rawSchemes = (api.components?.securitySchemes ?? {});
|
|
40
|
+
const result = [];
|
|
41
|
+
for (const [schemeName, scheme] of Object.entries(rawSchemes)) {
|
|
42
|
+
let kind;
|
|
43
|
+
let apiKeyParamName;
|
|
44
|
+
if (scheme.type === 'http') {
|
|
45
|
+
const httpScheme = scheme.scheme?.toLowerCase();
|
|
46
|
+
kind = httpScheme === 'bearer' ? 'bearer' : httpScheme === 'digest' ? 'digest' : 'basic';
|
|
47
|
+
}
|
|
48
|
+
else if (scheme.type === 'apiKey') {
|
|
49
|
+
const apiKey = scheme;
|
|
50
|
+
kind = apiKey.in === 'query' ? 'apiKey-query' : 'apiKey-header';
|
|
51
|
+
apiKeyParamName = apiKey.name;
|
|
52
|
+
}
|
|
53
|
+
else if (scheme.type === 'oauth2') {
|
|
54
|
+
kind = 'oauth2';
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
kind = 'openIdConnect';
|
|
58
|
+
}
|
|
59
|
+
result.push({
|
|
60
|
+
schemeName,
|
|
61
|
+
kind,
|
|
62
|
+
apiKeyParamName,
|
|
63
|
+
tokenName: toScreamingSnake(schemeName),
|
|
64
|
+
fileName: toKebabCase(schemeName) + '.security-token',
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
37
69
|
function buildEndpoints(api, allowedTags, namingConvention) {
|
|
38
70
|
const endpoints = [];
|
|
71
|
+
const globalSecurity = (api.security ?? []);
|
|
39
72
|
for (const [apiPath, pathItem] of Object.entries(api.paths ?? {})) {
|
|
40
73
|
if (!pathItem)
|
|
41
74
|
continue;
|
|
@@ -64,6 +97,12 @@ function buildEndpoints(api, allowedTags, namingConvention) {
|
|
|
64
97
|
.filter((p) => p.in === 'path')
|
|
65
98
|
.map((p) => p.name);
|
|
66
99
|
const hasQueryParams = allParams.some((p) => p.in === 'query');
|
|
100
|
+
// Operation-level security overrides global; [] means explicitly no security.
|
|
101
|
+
const operationSecurity = operation.security;
|
|
102
|
+
const resolvedSecurity = operationSecurity !== undefined ? operationSecurity : globalSecurity;
|
|
103
|
+
const securitySchemeNames = [
|
|
104
|
+
...new Set(resolvedSecurity.flatMap((req) => Object.keys(req))),
|
|
105
|
+
];
|
|
67
106
|
const requestBody = operation.requestBody;
|
|
68
107
|
const bodyContent = requestBody?.content ?? {};
|
|
69
108
|
const BODY_CONTENT_TYPES = [
|
|
@@ -100,6 +139,7 @@ function buildEndpoints(api, allowedTags, namingConvention) {
|
|
|
100
139
|
hasResponse,
|
|
101
140
|
responseStatus,
|
|
102
141
|
bodyContentType,
|
|
142
|
+
securitySchemeNames,
|
|
103
143
|
});
|
|
104
144
|
}
|
|
105
145
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-spec.js","sourceRoot":"","sources":["../../../../../../tools/openapi-resource-gen/src/generators/api-resource/parse-spec.ts"],"names":[],"mappings":";;;;;AAYA,4CAQC;AAED,kCAQC;AAED,
|
|
1
|
+
{"version":3,"file":"parse-spec.js","sourceRoot":"","sources":["../../../../../../tools/openapi-resource-gen/src/generators/api-resource/parse-spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import type { EndpointModel } from './endpoint-model';
|
|
2
|
-
export declare function
|
|
1
|
+
import type { EndpointModel, SecuritySchemeModel } from './endpoint-model';
|
|
2
|
+
export declare function renderSecurityTokenFile(scheme: SecuritySchemeModel, baseUrlToken: string): string;
|
|
3
|
+
export declare function renderTokenFile(ep: EndpointModel, baseUrlToken: string, providedIn?: 'root' | 'none', schemesByName?: Map<string, SecuritySchemeModel>): string;
|
|
@@ -1,23 +1,76 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderSecurityTokenFile = renderSecurityTokenFile;
|
|
3
4
|
exports.renderTokenFile = renderTokenFile;
|
|
4
5
|
function toPascalCase(str) {
|
|
5
6
|
return str
|
|
6
7
|
.replace(/\//g, '-')
|
|
7
|
-
.split(/[-_
|
|
8
|
+
.split(/[-_.\s]+/)
|
|
8
9
|
.filter(Boolean)
|
|
9
10
|
.map((s) => s.charAt(0).toUpperCase() + s.slice(1))
|
|
10
11
|
.join('');
|
|
11
12
|
}
|
|
12
13
|
function toCamelCase(str) {
|
|
13
|
-
const parts = str.split(/[-_]+/).filter(Boolean);
|
|
14
|
-
|
|
14
|
+
const parts = str.split(/[-_.]+/).filter(Boolean);
|
|
15
|
+
const first = parts[0].charAt(0).toLowerCase() + parts[0].slice(1);
|
|
16
|
+
return first + parts.slice(1).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join('');
|
|
15
17
|
}
|
|
16
|
-
function
|
|
18
|
+
function headerEntryForScheme(s, varName) {
|
|
19
|
+
const val = `${varName}()`;
|
|
20
|
+
switch (s.kind) {
|
|
21
|
+
case 'bearer':
|
|
22
|
+
case 'oauth2':
|
|
23
|
+
case 'openIdConnect':
|
|
24
|
+
return `{ Authorization: \`Bearer \${${val}}\` }`;
|
|
25
|
+
case 'basic':
|
|
26
|
+
return `{ Authorization: \`Basic \${${val}}\` }`;
|
|
27
|
+
case 'apiKey-header':
|
|
28
|
+
return `{ ${JSON.stringify(s.apiKeyParamName ?? 'X-Api-Key')}: \`\${${val}}\` }`;
|
|
29
|
+
default:
|
|
30
|
+
return '{}';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function apiPrefixFromBaseToken(baseUrlToken) {
|
|
34
|
+
const stripped = baseUrlToken.replace(/_BASE_URL$/i, '');
|
|
35
|
+
return toCamelCase(stripped.toLowerCase().replace(/_/g, '-'));
|
|
36
|
+
}
|
|
37
|
+
function renderSecurityTokenFile(scheme, baseUrlToken) {
|
|
38
|
+
if (scheme.kind === 'digest') {
|
|
39
|
+
const interceptorName = apiPrefixFromBaseToken(baseUrlToken) + toPascalCase(scheme.schemeName) + 'Interceptor';
|
|
40
|
+
return [
|
|
41
|
+
`import { InjectionToken, inject } from '@angular/core';`,
|
|
42
|
+
`import { HttpInterceptorFn } from '@angular/common/http';`,
|
|
43
|
+
`import { ${baseUrlToken} } from './api-base-url.token';`,
|
|
44
|
+
``,
|
|
45
|
+
`export const ${scheme.tokenName} = new InjectionToken<HttpInterceptorFn>('${scheme.tokenName}');`,
|
|
46
|
+
``,
|
|
47
|
+
`export const ${interceptorName}: HttpInterceptorFn = (req, next) => {`,
|
|
48
|
+
` const base = inject(${baseUrlToken});`,
|
|
49
|
+
` if (!req.url.startsWith(base)) return next(req);`,
|
|
50
|
+
` const fn = inject(${scheme.tokenName}, { optional: true });`,
|
|
51
|
+
` if (!fn) return next(req);`,
|
|
52
|
+
` return fn(req, next);`,
|
|
53
|
+
`};`,
|
|
54
|
+
``,
|
|
55
|
+
].join('\n');
|
|
56
|
+
}
|
|
57
|
+
return [
|
|
58
|
+
`import { InjectionToken, Signal } from '@angular/core';`,
|
|
59
|
+
``,
|
|
60
|
+
`export const ${scheme.tokenName} = new InjectionToken<Signal<string | null>>('${scheme.tokenName}');`,
|
|
61
|
+
``,
|
|
62
|
+
].join('\n');
|
|
63
|
+
}
|
|
64
|
+
function renderTokenFile(ep, baseUrlToken, providedIn = 'none', schemesByName = new Map()) {
|
|
17
65
|
const pascal = toPascalCase(ep.operationId);
|
|
18
66
|
const urlTemplate = ep.apiPath.replace(/\{([\w-]+)\}/g, (_, p) => `\${${toCamelCase(p)}}`);
|
|
19
67
|
const isGet = ep.method === 'get';
|
|
20
68
|
const { responseStatus } = ep;
|
|
69
|
+
const applicableSchemes = ep.securitySchemeNames
|
|
70
|
+
.map((name) => schemesByName.get(name))
|
|
71
|
+
.filter((s) => s !== undefined && s.kind !== 'digest');
|
|
72
|
+
const headerSchemes = applicableSchemes.filter((s) => s.kind !== 'apiKey-query');
|
|
73
|
+
const querySchemes = applicableSchemes.filter((s) => s.kind === 'apiKey-query');
|
|
21
74
|
const lines = [];
|
|
22
75
|
// Imports
|
|
23
76
|
const coreImports = ['InjectionToken', 'inject'];
|
|
@@ -29,6 +82,9 @@ function renderTokenFile(ep, baseUrlToken, providedIn = 'none') {
|
|
|
29
82
|
lines.push(`import { httpResource } from '@angular/common/http';`);
|
|
30
83
|
lines.push(`import type { paths } from '../schema.d';`);
|
|
31
84
|
lines.push(`import { ${baseUrlToken} } from '../api-base-url.token';`);
|
|
85
|
+
for (const scheme of applicableSchemes) {
|
|
86
|
+
lines.push(`import { ${scheme.tokenName} } from '../${scheme.fileName}';`);
|
|
87
|
+
}
|
|
32
88
|
lines.push('');
|
|
33
89
|
// Exported type aliases sourced directly from the generated paths type.
|
|
34
90
|
// NonNullable<> guards optional requestBody fields that are typed as T | undefined.
|
|
@@ -44,30 +100,78 @@ function renderTokenFile(ep, baseUrlToken, providedIn = 'none') {
|
|
|
44
100
|
const responseT = responseStatus ? `${pascal}Response` : 'unknown';
|
|
45
101
|
const fnArgs = buildFnArgs(ep, pascal, isGet);
|
|
46
102
|
lines.push(`export const ${ep.tokenName} = new InjectionToken<`, ` (${fnArgs}) => ReturnType<typeof httpResource<${responseT}>>`, `>('${ep.tokenName}'${providedIn === 'root' ? `, {` : ')'}`);
|
|
103
|
+
const securityInjects = (indent) => applicableSchemes
|
|
104
|
+
.map((s) => `${indent}const ${toCamelCase(s.schemeName)} = inject(${s.tokenName}, { optional: true });`)
|
|
105
|
+
.join('\n');
|
|
106
|
+
const needsBlockBody = isGet && ep.hasQueryParams;
|
|
47
107
|
if (providedIn === 'root') {
|
|
48
|
-
lines.push(` providedIn: 'root',`, ` factory: () => {`, ` const base = inject(${baseUrlToken})
|
|
49
|
-
|
|
50
|
-
|
|
108
|
+
lines.push(` providedIn: 'root',`, ` factory: () => {`, ` const base = inject(${baseUrlToken});`);
|
|
109
|
+
if (applicableSchemes.length > 0)
|
|
110
|
+
lines.push(securityInjects(' '));
|
|
111
|
+
if (needsBlockBody) {
|
|
112
|
+
lines.push(` return (${fnArgs}) =>`, ` httpResource<${responseT}>(() => {`, ` const _params = typeof params === 'function' ? params() : params;`, ` if (typeof params === 'function' && _params === undefined) return undefined;`, ` return {`, ` url: \`\${base}${urlTemplate}\`,`);
|
|
113
|
+
appendResourceOptions(lines, ep, isGet, ' ', headerSchemes, querySchemes, true);
|
|
114
|
+
lines.push(` };`, ` });`, ` },`, `});`, '');
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
lines.push(` return (${fnArgs}) =>`, ` httpResource<${responseT}>(() => ({`, ` url: \`\${base}${urlTemplate}\`,`);
|
|
118
|
+
appendResourceOptions(lines, ep, isGet, ' ', headerSchemes, querySchemes, false);
|
|
119
|
+
lines.push(` }));`, ` },`, `});`, '');
|
|
120
|
+
}
|
|
51
121
|
}
|
|
52
122
|
else {
|
|
53
|
-
// providedIn: 'none' — token has no factory; provide via the helper below
|
|
54
123
|
lines.push('');
|
|
55
|
-
lines.push(`export function provide${pascal}(): FactoryProvider {`, ` return {`, ` provide: ${ep.tokenName},`, ` useFactory: () => {`, ` const base = inject(${baseUrlToken})
|
|
56
|
-
|
|
57
|
-
|
|
124
|
+
lines.push(`export function provide${pascal}(): FactoryProvider {`, ` return {`, ` provide: ${ep.tokenName},`, ` useFactory: () => {`, ` const base = inject(${baseUrlToken});`);
|
|
125
|
+
if (applicableSchemes.length > 0)
|
|
126
|
+
lines.push(securityInjects(' '));
|
|
127
|
+
if (needsBlockBody) {
|
|
128
|
+
lines.push(` return (${fnArgs}) =>`, ` httpResource<${responseT}>(() => {`, ` const _params = typeof params === 'function' ? params() : params;`, ` if (typeof params === 'function' && _params === undefined) return undefined;`, ` return {`, ` url: \`\${base}${urlTemplate}\`,`);
|
|
129
|
+
appendResourceOptions(lines, ep, isGet, ' ', headerSchemes, querySchemes, true);
|
|
130
|
+
lines.push(` };`, ` });`, ` },`, ` };`, `}`, '');
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
lines.push(` return (${fnArgs}) =>`, ` httpResource<${responseT}>(() => ({`, ` url: \`\${base}${urlTemplate}\`,`);
|
|
134
|
+
appendResourceOptions(lines, ep, isGet, ' ', headerSchemes, querySchemes, false);
|
|
135
|
+
lines.push(` }));`, ` },`, ` };`, `}`, '');
|
|
136
|
+
}
|
|
58
137
|
}
|
|
59
138
|
return lines.join('\n');
|
|
60
139
|
}
|
|
61
|
-
function appendResourceOptions(lines, ep, isGet, indent) {
|
|
140
|
+
function appendResourceOptions(lines, ep, isGet, indent, headerSchemes, querySchemes, usePrecomputedParams = false) {
|
|
62
141
|
if (!isGet) {
|
|
63
142
|
lines.push(`${indent}method: '${ep.method.toUpperCase()}',`);
|
|
64
143
|
}
|
|
65
|
-
|
|
66
|
-
|
|
144
|
+
const hasRegularParams = isGet && ep.hasQueryParams;
|
|
145
|
+
const hasAuthQueryParams = querySchemes.length > 0;
|
|
146
|
+
if (hasRegularParams || hasAuthQueryParams) {
|
|
147
|
+
const authQueryParts = querySchemes
|
|
148
|
+
.map((s) => `...(${toCamelCase(s.schemeName)}?.() != null ? { ${JSON.stringify(s.apiKeyParamName ?? s.schemeName)}: \`\${${toCamelCase(s.schemeName)}()}\` } : {})`)
|
|
149
|
+
.join(', ');
|
|
150
|
+
const paramsExpr = usePrecomputedParams
|
|
151
|
+
? '_params'
|
|
152
|
+
: `(typeof params === 'function' ? params() : params)`;
|
|
153
|
+
const cast = ` as unknown as Record<string, string | number | boolean | readonly (string | number | boolean)[]>`;
|
|
154
|
+
if (hasRegularParams && hasAuthQueryParams) {
|
|
155
|
+
lines.push(`${indent}params: { ...${paramsExpr}, ${authQueryParts} }${cast},`);
|
|
156
|
+
}
|
|
157
|
+
else if (hasRegularParams) {
|
|
158
|
+
lines.push(`${indent}params: ${paramsExpr}${cast},`);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
lines.push(`${indent}params: { ${authQueryParts} }${cast},`);
|
|
162
|
+
}
|
|
67
163
|
}
|
|
68
164
|
if (!isGet && ep.hasBody) {
|
|
69
165
|
lines.push(`${indent}body,`);
|
|
70
166
|
}
|
|
167
|
+
if (headerSchemes.length > 0) {
|
|
168
|
+
lines.push(`${indent}headers: {`);
|
|
169
|
+
for (const s of headerSchemes) {
|
|
170
|
+
const varName = toCamelCase(s.schemeName);
|
|
171
|
+
lines.push(`${indent} ...(${varName}?.() != null ? ${headerEntryForScheme(s, varName)} : {}),`);
|
|
172
|
+
}
|
|
173
|
+
lines.push(`${indent}},`);
|
|
174
|
+
}
|
|
71
175
|
}
|
|
72
176
|
function buildFnArgs(ep, pascal, isGet) {
|
|
73
177
|
const args = ep.pathParams.map((p) => `${toCamelCase(p)}: string`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-token.js","sourceRoot":"","sources":["../../../../../../tools/openapi-resource-gen/src/generators/api-resource/render-token.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"render-token.js","sourceRoot":"","sources":["../../../../../../tools/openapi-resource-gen/src/generators/api-resource/render-token.ts"],"names":[],"mappings":"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"}
|