nuxt-openapi-hyperfetch 0.2.7-alpha.1 → 0.3.0-beta

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 (68) 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 +309 -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 +68 -19
  16. package/dist/generators/shared/runtime/useFormConnector.js +8 -1
  17. package/dist/generators/shared/runtime/useListConnector.js +13 -6
  18. package/dist/generators/use-async-data/generator.js +4 -0
  19. package/dist/generators/use-async-data/runtime/useApiAsyncData.js +4 -4
  20. package/dist/generators/use-async-data/runtime/useApiAsyncDataRaw.js +4 -4
  21. package/dist/generators/use-async-data/templates.js +17 -17
  22. package/dist/generators/use-fetch/generator.js +4 -0
  23. package/dist/generators/use-fetch/templates.js +14 -14
  24. package/dist/index.js +40 -27
  25. package/dist/module/index.js +19 -0
  26. package/dist/module/types.d.ts +7 -0
  27. package/docs/API-REFERENCE.md +886 -886
  28. package/docs/generated-components.md +615 -615
  29. package/docs/headless-composables-ui.md +569 -569
  30. package/eslint.config.js +85 -85
  31. package/package.json +1 -1
  32. package/src/cli/config.ts +147 -140
  33. package/src/cli/logger.ts +124 -124
  34. package/src/cli/logo.ts +25 -25
  35. package/src/cli/messages.ts +4 -0
  36. package/src/cli/prompts.ts +14 -1
  37. package/src/cli/types.ts +50 -50
  38. package/src/generators/components/connector-generator/generator.ts +138 -138
  39. package/src/generators/components/connector-generator/templates.ts +307 -254
  40. package/src/generators/components/connector-generator/types.ts +34 -34
  41. package/src/generators/components/schema-analyzer/index.ts +44 -44
  42. package/src/generators/components/schema-analyzer/intent-detector.ts +187 -187
  43. package/src/generators/components/schema-analyzer/openapi-reader.ts +96 -96
  44. package/src/generators/components/schema-analyzer/resource-grouper.ts +166 -166
  45. package/src/generators/components/schema-analyzer/schema-field-mapper.ts +268 -268
  46. package/src/generators/components/schema-analyzer/types.ts +177 -177
  47. package/src/generators/nuxt-server/generator.ts +272 -272
  48. package/src/generators/shared/runtime/apiHelpers.ts +535 -535
  49. package/src/generators/shared/runtime/pagination.ts +323 -323
  50. package/src/generators/shared/runtime/useDeleteConnector.ts +109 -109
  51. package/src/generators/shared/runtime/useDetailConnector.ts +64 -64
  52. package/src/generators/shared/runtime/useFormConnector.ts +147 -139
  53. package/src/generators/shared/runtime/useListConnector.ts +158 -148
  54. package/src/generators/shared/runtime/zod-error-merger.ts +119 -119
  55. package/src/generators/shared/templates/api-callbacks-plugin.ts +399 -399
  56. package/src/generators/shared/templates/api-pagination-plugin.ts +158 -158
  57. package/src/generators/use-async-data/generator.ts +213 -205
  58. package/src/generators/use-async-data/runtime/useApiAsyncData.ts +329 -329
  59. package/src/generators/use-async-data/runtime/useApiAsyncDataRaw.ts +324 -324
  60. package/src/generators/use-async-data/templates.ts +257 -257
  61. package/src/generators/use-fetch/generator.ts +178 -170
  62. package/src/generators/use-fetch/runtime/useApiRequest.ts +354 -354
  63. package/src/generators/use-fetch/templates.ts +214 -214
  64. package/src/index.ts +306 -303
  65. package/src/module/index.ts +158 -133
  66. package/src/module/types.ts +39 -31
  67. package/dist/generators/tanstack-query/generator.d.ts +0 -5
  68. package/dist/generators/tanstack-query/generator.js +0 -11
@@ -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
+ }
@@ -1,5 +0,0 @@
1
- /**
2
- * Placeholder for TanStack Query composables generator
3
- * TODO: Implement TanStack Query generation
4
- */
5
- export declare function generateTanstackQueryComposables(inputDir: string, outputDir: string): void;
@@ -1,11 +0,0 @@
1
- /**
2
- * Placeholder for TanStack Query composables generator
3
- * TODO: Implement TanStack Query generation
4
- */
5
- export function generateTanstackQueryComposables(inputDir, outputDir) {
6
- console.log('\n📦 @tanstack/vue-query generator\n');
7
- console.log(` Input: ${inputDir}`);
8
- console.log(` Output: ${outputDir}`);
9
- console.log('\n⚠️ This generator is not yet implemented.');
10
- console.log(' Coming soon!\n');
11
- }