nuxt-openapi-hyperfetch 0.2.7-alpha.1 → 0.2.8-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/.editorconfig +26 -26
  2. package/.prettierignore +17 -17
  3. package/CONTRIBUTING.md +291 -291
  4. package/INSTRUCTIONS.md +327 -327
  5. package/LICENSE +202 -202
  6. package/README.md +231 -231
  7. package/dist/cli/config.d.ts +9 -2
  8. package/dist/cli/config.js +1 -1
  9. package/dist/cli/logo.js +5 -5
  10. package/dist/cli/messages.d.ts +1 -0
  11. package/dist/cli/messages.js +2 -0
  12. package/dist/cli/prompts.d.ts +5 -0
  13. package/dist/cli/prompts.js +12 -0
  14. package/dist/cli/types.d.ts +1 -1
  15. package/dist/generators/components/connector-generator/templates.js +12 -12
  16. package/dist/generators/use-async-data/templates.js +17 -17
  17. package/dist/generators/use-fetch/templates.js +14 -14
  18. package/dist/index.js +39 -27
  19. package/dist/module/index.js +19 -0
  20. package/dist/module/types.d.ts +7 -0
  21. package/docs/API-REFERENCE.md +886 -886
  22. package/docs/generated-components.md +615 -615
  23. package/docs/headless-composables-ui.md +569 -569
  24. package/eslint.config.js +85 -85
  25. package/package.json +1 -1
  26. package/src/cli/config.ts +147 -140
  27. package/src/cli/logger.ts +124 -124
  28. package/src/cli/logo.ts +25 -25
  29. package/src/cli/messages.ts +4 -0
  30. package/src/cli/prompts.ts +14 -1
  31. package/src/cli/types.ts +50 -50
  32. package/src/generators/components/connector-generator/generator.ts +138 -138
  33. package/src/generators/components/connector-generator/templates.ts +254 -254
  34. package/src/generators/components/connector-generator/types.ts +34 -34
  35. package/src/generators/components/schema-analyzer/index.ts +44 -44
  36. package/src/generators/components/schema-analyzer/intent-detector.ts +187 -187
  37. package/src/generators/components/schema-analyzer/openapi-reader.ts +96 -96
  38. package/src/generators/components/schema-analyzer/resource-grouper.ts +166 -166
  39. package/src/generators/components/schema-analyzer/schema-field-mapper.ts +268 -268
  40. package/src/generators/components/schema-analyzer/types.ts +177 -177
  41. package/src/generators/nuxt-server/generator.ts +272 -272
  42. package/src/generators/shared/runtime/apiHelpers.ts +535 -535
  43. package/src/generators/shared/runtime/pagination.ts +323 -323
  44. package/src/generators/shared/runtime/useDeleteConnector.ts +109 -109
  45. package/src/generators/shared/runtime/useDetailConnector.ts +64 -64
  46. package/src/generators/shared/runtime/useFormConnector.ts +139 -139
  47. package/src/generators/shared/runtime/useListConnector.ts +148 -148
  48. package/src/generators/shared/runtime/zod-error-merger.ts +119 -119
  49. package/src/generators/shared/templates/api-callbacks-plugin.ts +399 -399
  50. package/src/generators/shared/templates/api-pagination-plugin.ts +158 -158
  51. package/src/generators/use-async-data/generator.ts +205 -205
  52. package/src/generators/use-async-data/runtime/useApiAsyncData.ts +329 -329
  53. package/src/generators/use-async-data/runtime/useApiAsyncDataRaw.ts +324 -324
  54. package/src/generators/use-async-data/templates.ts +257 -257
  55. package/src/generators/use-fetch/generator.ts +170 -170
  56. package/src/generators/use-fetch/runtime/useApiRequest.ts +354 -354
  57. package/src/generators/use-fetch/templates.ts +214 -214
  58. package/src/index.ts +305 -303
  59. package/src/module/index.ts +158 -133
  60. package/src/module/types.ts +39 -31
@@ -1,133 +1,158 @@
1
- import { defineNuxtModule, addImportsDir } from '@nuxt/kit';
2
- import { execSync } from 'child_process';
3
- import * as path from 'path';
4
- import { checkJavaInstalled } from '../generate.js';
5
- import { generateUseFetchComposables } from '../generators/use-fetch/generator.js';
6
- import { generateUseAsyncDataComposables } from '../generators/use-async-data/generator.js';
7
- import { generateNuxtServerRoutes } from '../generators/nuxt-server/generator.js';
8
- import { createConsoleLogger } from '../cli/logger.js';
9
- import type { ModuleOptions } from './types.js';
10
-
11
- export default defineNuxtModule<ModuleOptions>({
12
- meta: {
13
- name: 'nuxt-openapi-hyperfetch',
14
- configKey: 'openApiHyperFetch',
15
- },
16
-
17
- defaults: {
18
- output: './composables/api',
19
- generators: ['useFetch', 'useAsyncData'],
20
- backend: 'heyapi',
21
- enableDevBuild: true,
22
- enableProductionBuild: true,
23
- enableAutoGeneration: false,
24
- enableAutoImport: true,
25
- },
26
-
27
- setup(options: ModuleOptions, nuxt) {
28
- // --- Guard: input is required ---
29
- if (!options.input) {
30
- console.warn(
31
- '[nuxt-openapi-hyperfetch] No input configured — skipping generation.\n' +
32
- "Add `openApiHyperFetch: { input: './swagger.yaml' }` to your nuxt.config.ts"
33
- );
34
- return;
35
- }
36
-
37
- const resolvedInput = path.resolve(nuxt.options.rootDir, options.input);
38
- const resolvedOutput = path.resolve(nuxt.options.rootDir, options.output!);
39
- const composablesOutputDir = path.join(resolvedOutput, 'composables');
40
- const selectedGenerators = options.generators ?? ['useFetch', 'useAsyncData'];
41
- const backend = options.backend ?? 'heyapi';
42
- const logger = createConsoleLogger();
43
-
44
- // --- Core generation function ---
45
- const runGeneration = async () => {
46
- logger.log.info('Generating OpenAPI composables...');
47
-
48
- // 1. Generate OpenAPI SDK files
49
- if (backend === 'official') {
50
- if (!checkJavaInstalled()) {
51
- throw new Error(
52
- '[nuxt-openapi-hyperfetch] Java not found. The official backend requires Java 11+.\n' +
53
- 'Install from: https://adoptium.net or set backend: "heyapi" in nuxt.config.ts'
54
- );
55
- }
56
- execSync(
57
- `npx @openapitools/openapi-generator-cli generate -i "${resolvedInput}" -g typescript-fetch -o "${resolvedOutput}"`,
58
- { stdio: 'inherit' }
59
- );
60
- } else {
61
- const { createClient } = await import('@hey-api/openapi-ts');
62
- await createClient({
63
- input: resolvedInput,
64
- output: resolvedOutput,
65
- plugins: ['@hey-api/typescript', '@hey-api/sdk'],
66
- });
67
- }
68
-
69
- // 2. Run selected composable generators
70
- const genOptions = { backend };
71
-
72
- if (selectedGenerators.includes('useFetch')) {
73
- await generateUseFetchComposables(
74
- resolvedOutput,
75
- path.join(composablesOutputDir, 'use-fetch'),
76
- genOptions,
77
- logger
78
- );
79
- }
80
-
81
- if (selectedGenerators.includes('useAsyncData')) {
82
- await generateUseAsyncDataComposables(
83
- resolvedOutput,
84
- path.join(composablesOutputDir, 'use-async-data'),
85
- genOptions,
86
- logger
87
- );
88
- }
89
-
90
- if (selectedGenerators.includes('nuxtServer')) {
91
- const serverRoutePath = path.resolve(
92
- nuxt.options.rootDir,
93
- options.serverRoutePath ?? 'server/routes/api'
94
- );
95
- await generateNuxtServerRoutes(
96
- resolvedOutput,
97
- serverRoutePath,
98
- { enableBff: options.enableBff, backend },
99
- logger
100
- );
101
- }
102
- };
103
-
104
- // --- Hooks: dev build / production build ---
105
- const isDev = nuxt.options.dev;
106
- if ((isDev && options.enableDevBuild) || (!isDev && options.enableProductionBuild)) {
107
- nuxt.hook('build:before', runGeneration);
108
- }
109
-
110
- // --- Hook: auto-regeneration on input file change (dev only) ---
111
- if (options.enableAutoGeneration) {
112
- nuxt.hook('builder:watch', async (event: string, watchedPath: string) => {
113
- const absWatchedPath = path.resolve(nuxt.options.rootDir, watchedPath);
114
- if (absWatchedPath === resolvedInput && (event === 'change' || event === 'add')) {
115
- logger.log.info(`Detected change in ${watchedPath}, regenerating composables...`);
116
- await runGeneration();
117
- }
118
- });
119
- }
120
-
121
- // --- Auto-import: register composable directories ---
122
- if (options.enableAutoImport !== false) {
123
- if (selectedGenerators.includes('useFetch')) {
124
- addImportsDir(path.join(composablesOutputDir, 'use-fetch', 'composables'));
125
- }
126
- if (selectedGenerators.includes('useAsyncData')) {
127
- addImportsDir(path.join(composablesOutputDir, 'use-async-data', 'composables'));
128
- }
129
- }
130
- },
131
- });
132
-
133
- export type { ModuleOptions };
1
+ import { defineNuxtModule, addImportsDir } from '@nuxt/kit';
2
+ import { execSync } from 'child_process';
3
+ import * as path from 'path';
4
+ import { checkJavaInstalled } from '../generate.js';
5
+ import { generateUseFetchComposables } from '../generators/use-fetch/generator.js';
6
+ import { generateUseAsyncDataComposables } from '../generators/use-async-data/generator.js';
7
+ import { generateNuxtServerRoutes } from '../generators/nuxt-server/generator.js';
8
+ import { generateConnectors } from '../generators/components/connector-generator/generator.js';
9
+ import { createConsoleLogger } from '../cli/logger.js';
10
+ import type { ModuleOptions } from './types.js';
11
+
12
+ export default defineNuxtModule<ModuleOptions>({
13
+ meta: {
14
+ name: 'nuxt-openapi-hyperfetch',
15
+ configKey: 'openApiHyperFetch',
16
+ },
17
+
18
+ defaults: {
19
+ output: './composables/api',
20
+ generators: ['useFetch', 'useAsyncData'],
21
+ backend: 'heyapi',
22
+ enableDevBuild: true,
23
+ enableProductionBuild: true,
24
+ enableAutoGeneration: false,
25
+ enableAutoImport: true,
26
+ createUseAsyncDataConnectors: false,
27
+ },
28
+
29
+ setup(options: ModuleOptions, nuxt) {
30
+ // --- Guard: input is required ---
31
+ if (!options.input) {
32
+ console.warn(
33
+ '[nuxt-openapi-hyperfetch] No input configured — skipping generation.\n' +
34
+ "Add `openApiHyperFetch: { input: './swagger.yaml' }` to your nuxt.config.ts"
35
+ );
36
+ return;
37
+ }
38
+
39
+ const resolvedInput = path.resolve(nuxt.options.rootDir, options.input);
40
+ const resolvedOutput = path.resolve(nuxt.options.rootDir, options.output!);
41
+ const composablesOutputDir = path.join(resolvedOutput, 'composables');
42
+ const selectedGenerators = options.generators ?? ['useFetch', 'useAsyncData'];
43
+ const backend = options.backend ?? 'heyapi';
44
+ const logger = createConsoleLogger();
45
+
46
+ // --- Core generation function ---
47
+ const runGeneration = async () => {
48
+ logger.log.info('Generating OpenAPI composables...');
49
+
50
+ // 1. Generate OpenAPI SDK files
51
+ if (backend === 'official') {
52
+ if (!checkJavaInstalled()) {
53
+ throw new Error(
54
+ '[nuxt-openapi-hyperfetch] Java not found. The official backend requires Java 11+.\n' +
55
+ 'Install from: https://adoptium.net or set backend: "heyapi" in nuxt.config.ts'
56
+ );
57
+ }
58
+ execSync(
59
+ `npx @openapitools/openapi-generator-cli generate -i "${resolvedInput}" -g typescript-fetch -o "${resolvedOutput}"`,
60
+ { stdio: 'inherit' }
61
+ );
62
+ } else {
63
+ const { createClient } = await import('@hey-api/openapi-ts');
64
+ await createClient({
65
+ input: resolvedInput,
66
+ output: resolvedOutput,
67
+ plugins: ['@hey-api/typescript', '@hey-api/sdk'],
68
+ });
69
+ }
70
+
71
+ // 2. Run selected composable generators
72
+ const genOptions = { backend };
73
+
74
+ if (selectedGenerators.includes('useFetch')) {
75
+ await generateUseFetchComposables(
76
+ resolvedOutput,
77
+ path.join(composablesOutputDir, 'use-fetch'),
78
+ genOptions,
79
+ logger
80
+ );
81
+ }
82
+
83
+ if (selectedGenerators.includes('useAsyncData')) {
84
+ await generateUseAsyncDataComposables(
85
+ resolvedOutput,
86
+ path.join(composablesOutputDir, 'use-async-data'),
87
+ genOptions,
88
+ logger
89
+ );
90
+ }
91
+
92
+ if (selectedGenerators.includes('nuxtServer')) {
93
+ const serverRoutePath = path.resolve(
94
+ nuxt.options.rootDir,
95
+ options.serverRoutePath ?? 'server/routes/api'
96
+ );
97
+ await generateNuxtServerRoutes(
98
+ resolvedOutput,
99
+ serverRoutePath,
100
+ { enableBff: options.enableBff, backend },
101
+ logger
102
+ );
103
+ }
104
+
105
+ // 3. Generate headless connectors if requested (requires useAsyncData)
106
+ if (
107
+ options.createUseAsyncDataConnectors &&
108
+ selectedGenerators.includes('useAsyncData')
109
+ ) {
110
+ const connectorsOutputDir = path.join(composablesOutputDir, 'connectors');
111
+ const runtimeDir = path.join(resolvedOutput, 'runtime');
112
+ await generateConnectors(
113
+ {
114
+ inputSpec: resolvedInput,
115
+ outputDir: connectorsOutputDir,
116
+ composablesRelDir: '../use-async-data',
117
+ runtimeRelDir: '../../runtime',
118
+ },
119
+ logger
120
+ );
121
+ // Register #nxh alias so generated connector imports resolve
122
+ nuxt.options.alias['#nxh'] = runtimeDir;
123
+ }
124
+ };
125
+
126
+ // --- Hooks: dev build / production build ---
127
+ const isDev = nuxt.options.dev;
128
+ if ((isDev && options.enableDevBuild) || (!isDev && options.enableProductionBuild)) {
129
+ nuxt.hook('build:before', runGeneration);
130
+ }
131
+
132
+ // --- Hook: auto-regeneration on input file change (dev only) ---
133
+ if (options.enableAutoGeneration) {
134
+ nuxt.hook('builder:watch', async (event: string, watchedPath: string) => {
135
+ const absWatchedPath = path.resolve(nuxt.options.rootDir, watchedPath);
136
+ if (absWatchedPath === resolvedInput && (event === 'change' || event === 'add')) {
137
+ logger.log.info(`Detected change in ${watchedPath}, regenerating composables...`);
138
+ await runGeneration();
139
+ }
140
+ });
141
+ }
142
+
143
+ // --- Auto-import: register composable directories ---
144
+ if (options.enableAutoImport !== false) {
145
+ if (selectedGenerators.includes('useFetch')) {
146
+ addImportsDir(path.join(composablesOutputDir, 'use-fetch', 'composables'));
147
+ }
148
+ if (selectedGenerators.includes('useAsyncData')) {
149
+ addImportsDir(path.join(composablesOutputDir, 'use-async-data', 'composables'));
150
+ }
151
+ if (options.createUseAsyncDataConnectors && selectedGenerators.includes('useAsyncData')) {
152
+ addImportsDir(path.join(composablesOutputDir, 'connectors'));
153
+ }
154
+ }
155
+ },
156
+ });
157
+
158
+ export type { ModuleOptions };
@@ -1,31 +1,39 @@
1
- import type { GeneratorConfig } from '../cli/config.js';
2
-
3
- /**
4
- * Configuration options for the nuxt-openapi-hyperfetch Nuxt module.
5
- * Extends the CLI GeneratorConfig so the same fields work in both nxh.config.js and nuxt.config.ts.
6
- */
7
- export interface ModuleOptions extends GeneratorConfig {
8
- /**
9
- * Generate composables before the dev server starts.
10
- * @default true
11
- */
12
- enableDevBuild?: boolean;
13
-
14
- /**
15
- * Generate composables before the production build.
16
- * @default true
17
- */
18
- enableProductionBuild?: boolean;
19
-
20
- /**
21
- * Watch the input file and regenerate composables on change (dev mode only).
22
- * @default false
23
- */
24
- enableAutoGeneration?: boolean;
25
-
26
- /**
27
- * Automatically import generated useFetch/useAsyncData composables project-wide.
28
- * @default true
29
- */
30
- enableAutoImport?: boolean;
31
- }
1
+ import type { GeneratorConfig } from '../cli/config.js';
2
+
3
+ /**
4
+ * Configuration options for the nuxt-openapi-hyperfetch Nuxt module.
5
+ * Extends the CLI GeneratorConfig so the same fields work in both nxh.config.js and nuxt.config.ts.
6
+ */
7
+ export interface ModuleOptions extends GeneratorConfig {
8
+ /**
9
+ * Generate composables before the dev server starts.
10
+ * @default true
11
+ */
12
+ enableDevBuild?: boolean;
13
+
14
+ /**
15
+ * Generate composables before the production build.
16
+ * @default true
17
+ */
18
+ enableProductionBuild?: boolean;
19
+
20
+ /**
21
+ * Watch the input file and regenerate composables on change (dev mode only).
22
+ * @default false
23
+ */
24
+ enableAutoGeneration?: boolean;
25
+
26
+ /**
27
+ * Automatically import generated useFetch/useAsyncData composables project-wide.
28
+ * @default true
29
+ */
30
+ enableAutoImport?: boolean;
31
+
32
+ /**
33
+ * Generate headless UI connector composables on top of useAsyncData.
34
+ * Connectors provide ready-made logic for tables, pagination, forms and delete actions.
35
+ * Requires useAsyncData to also be in generators.
36
+ * @default false
37
+ */
38
+ createUseAsyncDataConnectors?: boolean;
39
+ }