nuxt-openapi-hyperfetch 1.0.2 → 1.0.4
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 +106 -51
- package/dist/cli/config.d.ts +15 -49
- package/dist/cli/config.js +42 -6
- package/dist/config/connectors.d.ts +6 -0
- package/dist/config/connectors.js +26 -0
- package/dist/config/types.d.ts +62 -0
- package/dist/config/types.js +1 -0
- package/dist/generators/connectors/config-resolver.d.ts +3 -0
- package/dist/generators/connectors/config-resolver.js +207 -0
- package/dist/generators/connectors/generator.js +3 -1
- package/dist/generators/connectors/templates.js +6 -2
- package/dist/generators/connectors/types.d.ts +3 -0
- package/dist/index.js +27 -10
- package/dist/module/index.js +11 -3
- package/dist/module/types.d.ts +4 -4
- package/docs/QUICK-START.md +44 -4
- package/package.json +22 -3
- package/src/cli/config.ts +61 -57
- package/src/config/connectors.ts +48 -0
- package/src/config/types.ts +67 -0
- package/src/generators/connectors/config-resolver.ts +303 -0
- package/src/generators/connectors/generator.ts +3 -1
- package/src/generators/connectors/templates.ts +5 -2
- package/src/generators/connectors/types.ts +4 -0
- package/src/index.ts +41 -12
- package/src/module/index.ts +18 -3
- package/src/module/types.ts +4 -4
package/README.md
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
<p align="center">
|
|
1
|
+
<p align="center">
|
|
4
2
|
<img src="https://raw.githubusercontent.com/dmartindiaz/nuxt-openapi-hyperfetch/main/public/nuxt-openapi-hyperfetch-logo.png" alt="Nuxt OpenAPI Hyperfetch logo" width="260" />
|
|
5
3
|
</p>
|
|
6
4
|
|
|
@@ -51,10 +49,10 @@ One composable per endpoint, for when you need direct control:
|
|
|
51
49
|
|
|
52
50
|
```ts
|
|
53
51
|
// useFetch — reactive, bound to template lifecycle
|
|
54
|
-
const { data: pet, pending, error } = useFetchGetPetById({ petId: 123 })
|
|
52
|
+
const { data: pet, pending, error } = useFetchGetPetById({ petId: 123 });
|
|
55
53
|
|
|
56
54
|
// useAsyncData — SSR-compatible, awaitable
|
|
57
|
-
const { data: pets } = await useAsyncDataFindPets({ status: 'available' })
|
|
55
|
+
const { data: pets } = await useAsyncDataFindPets({ status: 'available' });
|
|
58
56
|
```
|
|
59
57
|
|
|
60
58
|
With callbacks and request modification:
|
|
@@ -66,13 +64,13 @@ const { data } = useFetchFindPets(
|
|
|
66
64
|
{
|
|
67
65
|
onRequest: (ctx) => {
|
|
68
66
|
// ctx: { url, method, headers, query, body }
|
|
69
|
-
return { headers: { 'X-Source': 'pets-page' } }
|
|
67
|
+
return { headers: { 'X-Source': 'pets-page' } };
|
|
70
68
|
},
|
|
71
69
|
onSuccess: (pets) => console.log(`${pets.length} pets loaded`),
|
|
72
70
|
onError: (err) => console.error(err.message),
|
|
73
71
|
onFinish: ({ success }) => console.log('Done:', success),
|
|
74
72
|
}
|
|
75
|
-
)
|
|
73
|
+
);
|
|
76
74
|
|
|
77
75
|
// useAsyncData — onSuccess and onError receive a second context argument
|
|
78
76
|
const { data: pets } = await useAsyncDataFindPets(
|
|
@@ -82,7 +80,7 @@ const { data: pets } = await useAsyncDataFindPets(
|
|
|
82
80
|
onSuccess: (pets, ctx) => console.log(`${pets.length} from ${ctx.url}`),
|
|
83
81
|
onError: (err, ctx) => console.error(err.message, ctx.url),
|
|
84
82
|
}
|
|
85
|
-
)
|
|
83
|
+
);
|
|
86
84
|
```
|
|
87
85
|
|
|
88
86
|
---
|
|
@@ -97,7 +95,7 @@ Client → Nuxt Server Route (generated) → External API
|
|
|
97
95
|
|
|
98
96
|
```ts
|
|
99
97
|
// Works automatically after generation
|
|
100
|
-
const { data } = useFetch('/api/pet/123')
|
|
98
|
+
const { data } = useFetch('/api/pet/123');
|
|
101
99
|
```
|
|
102
100
|
|
|
103
101
|
---
|
|
@@ -107,19 +105,19 @@ const { data } = useFetch('/api/pet/123')
|
|
|
107
105
|
A connector exposes five sub-composables for one resource. For a `pet` tag in your spec:
|
|
108
106
|
|
|
109
107
|
```ts
|
|
110
|
-
const { getAll, get, create, update, del } = usePetsConnector()
|
|
108
|
+
const { getAll, get, create, update, del } = usePetsConnector();
|
|
111
109
|
```
|
|
112
110
|
|
|
113
111
|
### Full CRUD page in one component
|
|
114
112
|
|
|
115
113
|
```vue
|
|
116
114
|
<script setup lang="ts">
|
|
117
|
-
const { getAll, create, update, del } = usePetsConnector()
|
|
115
|
+
const { getAll, create, update, del } = usePetsConnector();
|
|
118
116
|
|
|
119
117
|
// Reload the list after every mutation
|
|
120
|
-
create.onSuccess(() => getAll.load())
|
|
121
|
-
update.onSuccess(() => getAll.load())
|
|
122
|
-
del.onSuccess(()
|
|
118
|
+
create.onSuccess(() => getAll.load());
|
|
119
|
+
update.onSuccess(() => getAll.load());
|
|
120
|
+
del.onSuccess(() => getAll.load());
|
|
123
121
|
</script>
|
|
124
122
|
|
|
125
123
|
<template>
|
|
@@ -143,8 +141,7 @@ del.onSuccess(() => getAll.load())
|
|
|
143
141
|
<UInput v-model="create.model.value.name" />
|
|
144
142
|
</UFormField>
|
|
145
143
|
<UFormField label="Status">
|
|
146
|
-
<USelect v-model="create.model.value.status"
|
|
147
|
-
:options="['available','pending','sold']" />
|
|
144
|
+
<USelect v-model="create.model.value.status" :options="['available', 'pending', 'sold']" />
|
|
148
145
|
</UFormField>
|
|
149
146
|
<template #footer>
|
|
150
147
|
<UButton :loading="create.loading.value" @click="create.execute()">Save</UButton>
|
|
@@ -157,8 +154,9 @@ del.onSuccess(() => getAll.load())
|
|
|
157
154
|
<UCard>
|
|
158
155
|
<UInput v-model="update.model.value.name" />
|
|
159
156
|
<template #footer>
|
|
160
|
-
<UButton :loading="update.loading.value"
|
|
161
|
-
|
|
157
|
+
<UButton :loading="update.loading.value" @click="update.execute(update.model.value.id)"
|
|
158
|
+
>Save changes</UButton
|
|
159
|
+
>
|
|
162
160
|
</template>
|
|
163
161
|
</UCard>
|
|
164
162
|
</UModal>
|
|
@@ -166,7 +164,10 @@ del.onSuccess(() => getAll.load())
|
|
|
166
164
|
<!-- Delete confirmation -->
|
|
167
165
|
<UModal v-model:open="del.ui.isOpen.value">
|
|
168
166
|
<UCard>
|
|
169
|
-
<p>
|
|
167
|
+
<p>
|
|
168
|
+
Delete <strong>{{ del.staged.value?.name }}</strong
|
|
169
|
+
>?
|
|
170
|
+
</p>
|
|
170
171
|
<template #footer>
|
|
171
172
|
<UButton color="red" :loading="del.loading.value" @click="del.execute()">Delete</UButton>
|
|
172
173
|
<UButton variant="outline" @click="del.ui.close()">Cancel</UButton>
|
|
@@ -178,21 +179,21 @@ del.onSuccess(() => getAll.load())
|
|
|
178
179
|
|
|
179
180
|
### What each sub-connector provides
|
|
180
181
|
|
|
181
|
-
| Key
|
|
182
|
-
|
|
182
|
+
| Key | Transport | What you get |
|
|
183
|
+
| -------- | -------------- | -------------------------------------------------------------------------- |
|
|
183
184
|
| `getAll` | `useAsyncData` | `items`, `columns`, `loading`, `error`, `pagination`, `selected`, `load()` |
|
|
184
|
-
| `get`
|
|
185
|
-
| `create` | `$fetch`
|
|
186
|
-
| `update` | `$fetch`
|
|
187
|
-
| `del`
|
|
185
|
+
| `get` | `$fetch` | `data`, `loading`, `error`, `load(id)`, `clear()` |
|
|
186
|
+
| `create` | `$fetch` | `model`, `errors`, `isValid`, `execute()`, `reset()`, `ui.open/close` |
|
|
187
|
+
| `update` | `$fetch` | Same as create + `load(id)`, `ui.open(row)`, `targetId` |
|
|
188
|
+
| `del` | `$fetch` | `staged`, `hasStaged`, `execute()`, `ui.open(item)/close` |
|
|
188
189
|
|
|
189
190
|
### Reactive list parameters
|
|
190
191
|
|
|
191
192
|
```ts
|
|
192
|
-
const status = ref('available')
|
|
193
|
+
const status = ref('available');
|
|
193
194
|
|
|
194
195
|
// Re-fetches automatically when status changes
|
|
195
|
-
const { getAll } = usePetsConnector(() => ({ status: status.value }))
|
|
196
|
+
const { getAll } = usePetsConnector(() => ({ status: status.value }));
|
|
196
197
|
```
|
|
197
198
|
|
|
198
199
|
### Zod validation, out of the box
|
|
@@ -201,11 +202,15 @@ Schemas are generated from your OpenAPI `requestBody`. `create.execute()` valida
|
|
|
201
202
|
|
|
202
203
|
```ts
|
|
203
204
|
// Extend the generated schema for extra rules
|
|
204
|
-
const { create } = usePetsConnector(
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
205
|
+
const { create } = usePetsConnector(
|
|
206
|
+
{},
|
|
207
|
+
{
|
|
208
|
+
createSchema: (base) =>
|
|
209
|
+
base.extend({
|
|
210
|
+
name: z.string().min(2, 'At least 2 characters'),
|
|
211
|
+
}),
|
|
212
|
+
}
|
|
213
|
+
);
|
|
209
214
|
```
|
|
210
215
|
|
|
211
216
|
### Global callbacks
|
|
@@ -217,11 +222,11 @@ Register once, applies to every API call in the app:
|
|
|
217
222
|
defineGlobalApiCallbacks([
|
|
218
223
|
{
|
|
219
224
|
onRequest: (ctx) => ({
|
|
220
|
-
headers: { Authorization: `Bearer ${useAuthStore().token}` }
|
|
225
|
+
headers: { Authorization: `Bearer ${useAuthStore().token}` },
|
|
221
226
|
}),
|
|
222
227
|
onError: (err) => useToast().add({ title: err.message, color: 'red' }),
|
|
223
|
-
}
|
|
224
|
-
])
|
|
228
|
+
},
|
|
229
|
+
]);
|
|
225
230
|
```
|
|
226
231
|
|
|
227
232
|
Connector-level and per-operation callbacks are also available — see [Callbacks docs](./docs/connectors/callbacks.md).
|
|
@@ -244,6 +249,55 @@ nxh generate -i ./swagger.yaml -o ./composables/api
|
|
|
244
249
|
|
|
245
250
|
The CLI asks for your spec path, output folder, engine (`heyapi` or `official`), and which generators to run.
|
|
246
251
|
|
|
252
|
+
### Generators semantics (CLI + config)
|
|
253
|
+
|
|
254
|
+
`generators` now supports `connectors` as a declarative option.
|
|
255
|
+
|
|
256
|
+
- `['connectors']` → generates `useAsyncData` + `connectors`
|
|
257
|
+
- `['useAsyncData']` → generates only `useAsyncData`
|
|
258
|
+
- `['useAsyncData', 'connectors']` → generates both
|
|
259
|
+
|
|
260
|
+
`createUseAsyncDataConnectors` is still supported for backward compatibility, but `generators: ['connectors']` is the recommended setup.
|
|
261
|
+
|
|
262
|
+
### Typed `nxh.config.ts`
|
|
263
|
+
|
|
264
|
+
The CLI now supports `nxh.config.ts` (besides `.js`/`.mjs`).
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
// nxh.config.ts
|
|
268
|
+
import type { GeneratorConfig } from 'nuxt-openapi-hyperfetch';
|
|
269
|
+
|
|
270
|
+
const config: GeneratorConfig = {
|
|
271
|
+
input: './swagger.yaml',
|
|
272
|
+
output: './composables/api',
|
|
273
|
+
generators: ['useAsyncData', 'connectors'],
|
|
274
|
+
connectors: {
|
|
275
|
+
strategy: 'hybrid',
|
|
276
|
+
resources: {
|
|
277
|
+
pets: {
|
|
278
|
+
operations: {
|
|
279
|
+
getAll: { operationId: 'findPetsByStatus' },
|
|
280
|
+
get: { path: '/pet/{petId}' },
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
featuredPets: {
|
|
284
|
+
operations: {
|
|
285
|
+
getAll: { operationId: 'findPetsByTags' },
|
|
286
|
+
get: { operationId: 'getPetById' },
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
export default config;
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
`connectors.strategy` supports:
|
|
297
|
+
|
|
298
|
+
- `manual`: generate only resources defined by the user
|
|
299
|
+
- `hybrid`: start from inferred resources and apply user overrides/custom resources
|
|
300
|
+
|
|
247
301
|
### Nuxt module
|
|
248
302
|
|
|
249
303
|
```ts
|
|
@@ -254,11 +308,11 @@ export default defineNuxtConfig({
|
|
|
254
308
|
openApiHyperFetch: {
|
|
255
309
|
input: './swagger.yaml',
|
|
256
310
|
output: './composables/api',
|
|
257
|
-
generators: ['useFetch', '
|
|
311
|
+
generators: ['useFetch', 'connectors', 'nuxtServer'],
|
|
258
312
|
backend: 'heyapi',
|
|
259
313
|
enableAutoImport: true,
|
|
260
314
|
},
|
|
261
|
-
})
|
|
315
|
+
});
|
|
262
316
|
```
|
|
263
317
|
|
|
264
318
|
### Configure the base URL
|
|
@@ -266,7 +320,9 @@ export default defineNuxtConfig({
|
|
|
266
320
|
```ts
|
|
267
321
|
// nuxt.config.ts
|
|
268
322
|
runtimeConfig: {
|
|
269
|
-
public: {
|
|
323
|
+
public: {
|
|
324
|
+
apiBaseUrl: process.env.NUXT_PUBLIC_API_BASE_URL || 'https://api.example.com';
|
|
325
|
+
}
|
|
270
326
|
}
|
|
271
327
|
```
|
|
272
328
|
|
|
@@ -276,28 +332,28 @@ All generated composables and connectors pick up `apiBaseUrl` automatically.
|
|
|
276
332
|
|
|
277
333
|
## Two generation engines
|
|
278
334
|
|
|
279
|
-
| Engine
|
|
280
|
-
|
|
281
|
-
| `heyapi`
|
|
282
|
-
| `official` | Java 11+
|
|
335
|
+
| Engine | Requires | Best for |
|
|
336
|
+
| ---------- | --------- | -------------------------- |
|
|
337
|
+
| `heyapi` | Node only | Quick setup, CI/CD |
|
|
338
|
+
| `official` | Java 11+ | Maximum spec compatibility |
|
|
283
339
|
|
|
284
340
|
Pre-select in `nxh.config.js` to skip the prompt:
|
|
285
341
|
|
|
286
342
|
```js
|
|
287
|
-
export default { generator: 'heyapi', input: './swagger.yaml', output: './api' }
|
|
343
|
+
export default { generator: 'heyapi', input: './swagger.yaml', output: './api' };
|
|
288
344
|
```
|
|
289
345
|
|
|
290
346
|
---
|
|
291
347
|
|
|
292
348
|
## Documentation
|
|
293
349
|
|
|
294
|
-
|
|
|
295
|
-
|
|
296
|
-
| [Connectors](./docs/connectors/index.md)
|
|
297
|
-
| [Quick Start](./docs/QUICK-START.md)
|
|
298
|
-
| [API Reference](./docs/API-REFERENCE.md)
|
|
299
|
-
| [Architecture](./docs/ARCHITECTURE.md)
|
|
300
|
-
| [Troubleshooting](./docs/TROUBLESHOOTING.md) | Common errors and solutions
|
|
350
|
+
| | |
|
|
351
|
+
| -------------------------------------------- | --------------------------------------------- |
|
|
352
|
+
| [Connectors](./docs/connectors/index.md) | Full connector API reference and examples |
|
|
353
|
+
| [Quick Start](./docs/QUICK-START.md) | From zero to working composables in 5 minutes |
|
|
354
|
+
| [API Reference](./docs/API-REFERENCE.md) | All options and TypeScript types |
|
|
355
|
+
| [Architecture](./docs/ARCHITECTURE.md) | How the generator works internally |
|
|
356
|
+
| [Troubleshooting](./docs/TROUBLESHOOTING.md) | Common errors and solutions |
|
|
301
357
|
|
|
302
358
|
---
|
|
303
359
|
|
|
@@ -311,7 +367,6 @@ npm run validate # lint + type check
|
|
|
311
367
|
|
|
312
368
|
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
313
369
|
|
|
314
|
-
|
|
315
370
|
---
|
|
316
371
|
|
|
317
372
|
## License
|
package/dist/cli/config.d.ts
CHANGED
|
@@ -1,53 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
/** Path or URL to OpenAPI specification */
|
|
7
|
-
input?: string;
|
|
8
|
-
/** Output directory for generated files */
|
|
9
|
-
output?: string;
|
|
10
|
-
/** Base URL for API requests */
|
|
11
|
-
baseUrl?: string;
|
|
12
|
-
/** Generation mode: client or server */
|
|
13
|
-
mode?: 'client' | 'server';
|
|
14
|
-
/** Generate only specific tags */
|
|
15
|
-
tags?: string[];
|
|
16
|
-
/** Exclude specific tags */
|
|
17
|
-
excludeTags?: string[];
|
|
18
|
-
/** Overwrite existing files without prompting */
|
|
19
|
-
overwrite?: boolean;
|
|
20
|
-
/** Preview changes without writing files */
|
|
21
|
-
dryRun?: boolean;
|
|
22
|
-
/** Enable verbose logging */
|
|
23
|
-
verbose?: boolean;
|
|
24
|
-
/** Watch mode - regenerate on file changes */
|
|
25
|
-
watch?: boolean;
|
|
26
|
-
/** Generator types to use */
|
|
27
|
-
generators?: ('useFetch' | 'useAsyncData' | 'nuxtServer' | 'connectors')[];
|
|
28
|
-
/** Server route path (for nuxtServer mode) */
|
|
29
|
-
serverRoutePath?: string;
|
|
30
|
-
/** Enable BFF pattern (for nuxtServer mode) */
|
|
31
|
-
enableBff?: boolean;
|
|
32
|
-
/** Generator backend: official (Java) or heyapi (Node.js) */
|
|
33
|
-
backend?: GeneratorBackend;
|
|
34
|
-
/**
|
|
35
|
-
* Generation engine to use.
|
|
36
|
-
* - 'openapi': @openapitools/openapi-generator-cli (requires Java 11+)
|
|
37
|
-
* - 'heyapi': @hey-api/openapi-ts (Node.js native, no Java required)
|
|
38
|
-
* When set, the CLI will not ask which engine to use.
|
|
39
|
-
*/
|
|
40
|
-
generator?: ConfigGenerator;
|
|
41
|
-
/**
|
|
42
|
-
* Generate headless UI connector composables on top of useAsyncData.
|
|
43
|
-
* Connectors provide ready-made logic for tables, pagination, forms and delete actions.
|
|
44
|
-
* Requires useAsyncData to also be generated.
|
|
45
|
-
* @default false
|
|
46
|
-
*/
|
|
47
|
-
createUseAsyncDataConnectors?: boolean;
|
|
1
|
+
import type { GeneratorConfig, GeneratorType } from '../config/types.js';
|
|
2
|
+
export type ComposableGeneratorType = 'useFetch' | 'useAsyncData' | 'nuxtServer';
|
|
3
|
+
export interface NormalizedGenerators {
|
|
4
|
+
composables: ComposableGeneratorType[];
|
|
5
|
+
generateConnectors: boolean;
|
|
48
6
|
}
|
|
49
7
|
/**
|
|
50
|
-
* Load configuration from nxh.config.js, nuxt-openapi-
|
|
8
|
+
* Load configuration from nxh.config.{ts,js,mjs}, nuxt-openapi-hyperfetch.{ts,js,mjs}, or package.json
|
|
51
9
|
*/
|
|
52
10
|
export declare function loadConfig(cwd?: string): Promise<GeneratorConfig | null>;
|
|
53
11
|
/**
|
|
@@ -61,4 +19,12 @@ export declare function parseTags(tagsString?: string): string[] | undefined;
|
|
|
61
19
|
/**
|
|
62
20
|
* Parse generators string into array
|
|
63
21
|
*/
|
|
64
|
-
export declare function parseGenerators(generatorsString?: string):
|
|
22
|
+
export declare function parseGenerators(generatorsString?: string): GeneratorType[] | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Normalize generator selection so connectors can be requested declaratively.
|
|
25
|
+
* Rules:
|
|
26
|
+
* - If `connectors` is selected, `useAsyncData` is added automatically.
|
|
27
|
+
* - If `createUseAsyncDataConnectors` is true, connectors are enabled and
|
|
28
|
+
* `useAsyncData` is added automatically.
|
|
29
|
+
*/
|
|
30
|
+
export declare function normalizeGenerators(generators?: GeneratorType[], createUseAsyncDataConnectors?: boolean): NormalizedGenerators;
|
package/dist/cli/config.js
CHANGED
|
@@ -1,15 +1,38 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
2
|
import { join } from 'path';
|
|
3
|
+
import { pathToFileURL } from 'url';
|
|
3
4
|
import * as p from '@clack/prompts';
|
|
4
5
|
const { existsSync } = fs;
|
|
6
|
+
const COMPOSABLE_GENERATOR_ORDER = [
|
|
7
|
+
'useFetch',
|
|
8
|
+
'useAsyncData',
|
|
9
|
+
'nuxtServer',
|
|
10
|
+
];
|
|
11
|
+
async function importConfigModule(configPath) {
|
|
12
|
+
try {
|
|
13
|
+
const module = await import(pathToFileURL(configPath).href);
|
|
14
|
+
return module.default || module;
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (!configPath.endsWith('.ts')) {
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
const { createJiti } = await import('jiti');
|
|
21
|
+
const jiti = createJiti(import.meta.url, { interopDefault: true });
|
|
22
|
+
const module = jiti(configPath);
|
|
23
|
+
return module?.default || module;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
5
26
|
/**
|
|
6
|
-
* Load configuration from nxh.config.js, nuxt-openapi-
|
|
27
|
+
* Load configuration from nxh.config.{ts,js,mjs}, nuxt-openapi-hyperfetch.{ts,js,mjs}, or package.json
|
|
7
28
|
*/
|
|
8
29
|
export async function loadConfig(cwd = process.cwd()) {
|
|
9
30
|
// Try different config file names
|
|
10
31
|
const configFiles = [
|
|
32
|
+
'nxh.config.ts',
|
|
11
33
|
'nxh.config.js',
|
|
12
34
|
'nxh.config.mjs',
|
|
35
|
+
'nuxt-openapi-hyperfetch.ts',
|
|
13
36
|
'nuxt-openapi-hyperfetch.js',
|
|
14
37
|
'nuxt-openapi-hyperfetch.mjs',
|
|
15
38
|
];
|
|
@@ -17,11 +40,8 @@ export async function loadConfig(cwd = process.cwd()) {
|
|
|
17
40
|
const configPath = join(cwd, configFile);
|
|
18
41
|
if (existsSync(configPath)) {
|
|
19
42
|
try {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment
|
|
23
|
-
const exportedConfig = config.default || config;
|
|
24
|
-
return exportedConfig;
|
|
43
|
+
const config = await importConfigModule(configPath);
|
|
44
|
+
return config;
|
|
25
45
|
}
|
|
26
46
|
catch (error) {
|
|
27
47
|
p.log.warn(`Failed to load config from ${configFile}: ${String(error)}`);
|
|
@@ -83,3 +103,19 @@ export function parseGenerators(generatorsString) {
|
|
|
83
103
|
const parts = generatorsString.split(',').map((g) => g.trim());
|
|
84
104
|
return parts.filter((g) => ['useFetch', 'useAsyncData', 'nuxtServer', 'connectors'].includes(g));
|
|
85
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Normalize generator selection so connectors can be requested declaratively.
|
|
108
|
+
* Rules:
|
|
109
|
+
* - If `connectors` is selected, `useAsyncData` is added automatically.
|
|
110
|
+
* - If `createUseAsyncDataConnectors` is true, connectors are enabled and
|
|
111
|
+
* `useAsyncData` is added automatically.
|
|
112
|
+
*/
|
|
113
|
+
export function normalizeGenerators(generators, createUseAsyncDataConnectors) {
|
|
114
|
+
const requested = new Set(generators ?? []);
|
|
115
|
+
const generateConnectors = requested.has('connectors') || createUseAsyncDataConnectors === true;
|
|
116
|
+
const composables = COMPOSABLE_GENERATOR_ORDER.filter((generator) => requested.has(generator));
|
|
117
|
+
if (generateConnectors && !composables.includes('useAsyncData')) {
|
|
118
|
+
composables.push('useAsyncData');
|
|
119
|
+
}
|
|
120
|
+
return { composables, generateConnectors };
|
|
121
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ConnectorsConfig, GeneratorConfig, GeneratorType } from './types.js';
|
|
2
|
+
export type RuntimeComposableGenerator = 'useFetch' | 'useAsyncData' | 'nuxtServer';
|
|
3
|
+
export declare function hasConnectorsConfig(connectors?: ConnectorsConfig): boolean;
|
|
4
|
+
export declare function isConnectorsRequested(config: Pick<GeneratorConfig, 'generators' | 'createUseAsyncDataConnectors' | 'connectors'>): boolean;
|
|
5
|
+
export declare function toRuntimeComposableGenerators(generators?: GeneratorType[]): RuntimeComposableGenerator[];
|
|
6
|
+
export declare function ensureUseAsyncDataForConnectors(composables: RuntimeComposableGenerator[], connectorsRequested: boolean): RuntimeComposableGenerator[];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function hasConnectorsConfig(connectors) {
|
|
2
|
+
if (!connectors) {
|
|
3
|
+
return false;
|
|
4
|
+
}
|
|
5
|
+
if (connectors.enabled === true) {
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
if (connectors.strategy !== undefined) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
return Object.keys(connectors.resources ?? {}).length > 0;
|
|
12
|
+
}
|
|
13
|
+
export function isConnectorsRequested(config) {
|
|
14
|
+
return (config.createUseAsyncDataConnectors === true ||
|
|
15
|
+
(config.generators ?? []).includes('connectors') ||
|
|
16
|
+
hasConnectorsConfig(config.connectors));
|
|
17
|
+
}
|
|
18
|
+
export function toRuntimeComposableGenerators(generators) {
|
|
19
|
+
return (generators ?? []).filter((g) => g === 'useFetch' || g === 'useAsyncData' || g === 'nuxtServer');
|
|
20
|
+
}
|
|
21
|
+
export function ensureUseAsyncDataForConnectors(composables, connectorsRequested) {
|
|
22
|
+
if (!connectorsRequested || composables.includes('useAsyncData')) {
|
|
23
|
+
return composables;
|
|
24
|
+
}
|
|
25
|
+
return [...composables, 'useAsyncData'];
|
|
26
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { GeneratorBackend, ConfigGenerator } from '../cli/types.js';
|
|
2
|
+
export type GeneratorType = 'useFetch' | 'useAsyncData' | 'nuxtServer' | 'connectors';
|
|
3
|
+
export type ConnectorStrategy = 'manual' | 'hybrid';
|
|
4
|
+
export type ConnectorOperationName = 'getAll' | 'get' | 'create' | 'update' | 'delete';
|
|
5
|
+
export interface ConnectorOperationConfig {
|
|
6
|
+
operationId?: string;
|
|
7
|
+
path?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ConnectorResourceConfig {
|
|
10
|
+
operations?: Partial<Record<ConnectorOperationName, ConnectorOperationConfig>>;
|
|
11
|
+
}
|
|
12
|
+
export interface ConnectorsConfig {
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
strategy?: ConnectorStrategy;
|
|
15
|
+
resources?: Record<string, ConnectorResourceConfig>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Shared configuration contract used by both CLI (nxh.config.*) and Nuxt module (nuxt.config.ts).
|
|
19
|
+
*/
|
|
20
|
+
export interface GeneratorConfig {
|
|
21
|
+
/** Path or URL to OpenAPI specification */
|
|
22
|
+
input?: string;
|
|
23
|
+
/** Output directory for generated files */
|
|
24
|
+
output?: string;
|
|
25
|
+
/** Base URL for API requests */
|
|
26
|
+
baseUrl?: string;
|
|
27
|
+
/** Generation mode: client or server */
|
|
28
|
+
mode?: 'client' | 'server';
|
|
29
|
+
/** Generate only specific tags */
|
|
30
|
+
tags?: string[];
|
|
31
|
+
/** Exclude specific tags */
|
|
32
|
+
excludeTags?: string[];
|
|
33
|
+
/** Overwrite existing files without prompting */
|
|
34
|
+
overwrite?: boolean;
|
|
35
|
+
/** Preview changes without writing files */
|
|
36
|
+
dryRun?: boolean;
|
|
37
|
+
/** Enable verbose logging */
|
|
38
|
+
verbose?: boolean;
|
|
39
|
+
/** Watch mode - regenerate on file changes */
|
|
40
|
+
watch?: boolean;
|
|
41
|
+
/** Generator types to use */
|
|
42
|
+
generators?: GeneratorType[];
|
|
43
|
+
/** Server route path (for nuxtServer mode) */
|
|
44
|
+
serverRoutePath?: string;
|
|
45
|
+
/** Enable BFF pattern (for nuxtServer mode) */
|
|
46
|
+
enableBff?: boolean;
|
|
47
|
+
/** Generator backend: official (Java) or heyapi (Node.js) */
|
|
48
|
+
backend?: GeneratorBackend;
|
|
49
|
+
/**
|
|
50
|
+
* Generation engine to use.
|
|
51
|
+
* - 'openapi': @openapitools/openapi-generator-cli (requires Java 11+)
|
|
52
|
+
* - 'heyapi': @hey-api/openapi-ts (Node.js native, no Java required)
|
|
53
|
+
*/
|
|
54
|
+
generator?: ConfigGenerator;
|
|
55
|
+
/**
|
|
56
|
+
* Generate headless UI connector composables on top of useAsyncData.
|
|
57
|
+
* Requires useAsyncData to also be generated.
|
|
58
|
+
*/
|
|
59
|
+
createUseAsyncDataConnectors?: boolean;
|
|
60
|
+
/** Advanced connectors generation contract (manual/hybrid, custom resources, overloads). */
|
|
61
|
+
connectors?: ConnectorsConfig;
|
|
62
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|