nuxt-openapi-hyperfetch 0.1.7-alpha.1 → 0.2.7-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.
- package/CONTRIBUTING.md +291 -292
- package/INSTRUCTIONS.md +327 -327
- package/LICENSE +202 -202
- package/README.md +231 -227
- package/dist/cli/logger.d.ts +26 -0
- package/dist/cli/logger.js +36 -0
- package/dist/cli/logo.js +5 -5
- package/dist/generators/components/connector-generator/generator.d.ts +12 -0
- package/dist/generators/components/connector-generator/generator.js +116 -0
- package/dist/generators/components/connector-generator/templates.d.ts +18 -0
- package/dist/generators/components/connector-generator/templates.js +222 -0
- package/dist/generators/components/connector-generator/types.d.ts +32 -0
- package/dist/generators/components/connector-generator/types.js +7 -0
- package/dist/generators/components/schema-analyzer/index.d.ts +17 -0
- package/dist/generators/components/schema-analyzer/index.js +20 -0
- package/dist/generators/components/schema-analyzer/intent-detector.d.ts +17 -0
- package/dist/generators/components/schema-analyzer/intent-detector.js +143 -0
- package/dist/generators/components/schema-analyzer/openapi-reader.d.ts +11 -0
- package/dist/generators/components/schema-analyzer/openapi-reader.js +76 -0
- package/dist/generators/components/schema-analyzer/resource-grouper.d.ts +6 -0
- package/dist/generators/components/schema-analyzer/resource-grouper.js +132 -0
- package/dist/generators/components/schema-analyzer/schema-field-mapper.d.ts +35 -0
- package/dist/generators/components/schema-analyzer/schema-field-mapper.js +220 -0
- package/dist/generators/components/schema-analyzer/types.d.ts +156 -0
- package/dist/generators/components/schema-analyzer/types.js +7 -0
- package/dist/generators/nuxt-server/generator.d.ts +2 -1
- package/dist/generators/nuxt-server/generator.js +21 -21
- package/dist/generators/shared/runtime/apiHelpers.d.ts +81 -41
- package/dist/generators/shared/runtime/apiHelpers.js +97 -104
- package/dist/generators/shared/runtime/pagination.d.ts +168 -0
- package/dist/generators/shared/runtime/pagination.js +179 -0
- package/dist/generators/shared/runtime/useDeleteConnector.d.ts +16 -0
- package/dist/generators/shared/runtime/useDeleteConnector.js +93 -0
- package/dist/generators/shared/runtime/useDetailConnector.d.ts +14 -0
- package/dist/generators/shared/runtime/useDetailConnector.js +50 -0
- package/dist/generators/shared/runtime/useFormConnector.d.ts +19 -0
- package/dist/generators/shared/runtime/useFormConnector.js +113 -0
- package/dist/generators/shared/runtime/useListConnector.d.ts +25 -0
- package/dist/generators/shared/runtime/useListConnector.js +125 -0
- package/dist/generators/shared/runtime/zod-error-merger.d.ts +23 -0
- package/dist/generators/shared/runtime/zod-error-merger.js +106 -0
- package/dist/generators/shared/templates/api-callbacks-plugin.js +54 -11
- package/dist/generators/shared/templates/api-pagination-plugin.d.ts +51 -0
- package/dist/generators/shared/templates/api-pagination-plugin.js +152 -0
- package/dist/generators/use-async-data/generator.d.ts +2 -1
- package/dist/generators/use-async-data/generator.js +14 -14
- package/dist/generators/use-async-data/runtime/useApiAsyncData.js +114 -13
- package/dist/generators/use-async-data/runtime/useApiAsyncDataRaw.js +88 -10
- package/dist/generators/use-async-data/templates.js +17 -17
- package/dist/generators/use-fetch/generator.d.ts +2 -1
- package/dist/generators/use-fetch/generator.js +12 -12
- package/dist/generators/use-fetch/runtime/useApiRequest.js +149 -40
- package/dist/generators/use-fetch/templates.js +14 -14
- package/dist/index.js +25 -0
- package/dist/module/index.d.ts +4 -0
- package/dist/module/index.js +93 -0
- package/dist/module/types.d.ts +27 -0
- package/dist/module/types.js +1 -0
- package/docs/API-REFERENCE.md +886 -887
- package/docs/generated-components.md +615 -0
- package/docs/headless-composables-ui.md +569 -0
- package/eslint.config.js +13 -0
- package/package.json +29 -2
- package/src/cli/config.ts +140 -140
- package/src/cli/logger.ts +124 -66
- package/src/cli/logo.ts +25 -25
- package/src/cli/types.ts +50 -50
- package/src/generators/components/connector-generator/generator.ts +138 -0
- package/src/generators/components/connector-generator/templates.ts +254 -0
- package/src/generators/components/connector-generator/types.ts +34 -0
- package/src/generators/components/schema-analyzer/index.ts +44 -0
- package/src/generators/components/schema-analyzer/intent-detector.ts +187 -0
- package/src/generators/components/schema-analyzer/openapi-reader.ts +96 -0
- package/src/generators/components/schema-analyzer/resource-grouper.ts +166 -0
- package/src/generators/components/schema-analyzer/schema-field-mapper.ts +268 -0
- package/src/generators/components/schema-analyzer/types.ts +177 -0
- package/src/generators/nuxt-server/generator.ts +272 -270
- package/src/generators/shared/runtime/apiHelpers.ts +535 -507
- package/src/generators/shared/runtime/pagination.ts +323 -0
- package/src/generators/shared/runtime/useDeleteConnector.ts +109 -0
- package/src/generators/shared/runtime/useDetailConnector.ts +64 -0
- package/src/generators/shared/runtime/useFormConnector.ts +139 -0
- package/src/generators/shared/runtime/useListConnector.ts +148 -0
- package/src/generators/shared/runtime/zod-error-merger.ts +119 -0
- package/src/generators/shared/templates/api-callbacks-plugin.ts +399 -352
- package/src/generators/shared/templates/api-pagination-plugin.ts +158 -0
- package/src/generators/use-async-data/generator.ts +205 -204
- package/src/generators/use-async-data/runtime/useApiAsyncData.ts +329 -229
- package/src/generators/use-async-data/runtime/useApiAsyncDataRaw.ts +324 -245
- package/src/generators/use-async-data/templates.ts +257 -257
- package/src/generators/use-fetch/generator.ts +170 -169
- package/src/generators/use-fetch/runtime/useApiRequest.ts +354 -234
- package/src/generators/use-fetch/templates.ts +214 -214
- package/src/index.ts +303 -265
- package/src/module/index.ts +133 -0
- package/src/module/types.ts +31 -0
- package/src/generators/tanstack-query/generator.ts +0 -11
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* Nuxt Runtime Helper - This file is copied to the generated output
|
|
4
|
+
* It requires Nuxt 3 to be installed in the target project
|
|
5
|
+
*/
|
|
6
|
+
import { ref, computed } from 'vue';
|
|
1
7
|
import { getGlobalHeaders, getGlobalBaseUrl, applyPick, mergeCallbacks, } from '../../shared/runtime/apiHelpers.js';
|
|
8
|
+
import { getGlobalApiPagination, buildPaginationRequest, extractPaginationMetaFromBody, extractPaginationMetaFromHeaders, unwrapDataKey, } from '../../shared/runtime/pagination.js';
|
|
2
9
|
/**
|
|
3
10
|
* Generic wrapper for API calls using Nuxt's useAsyncData
|
|
4
11
|
* Supports:
|
|
@@ -9,7 +16,19 @@ import { getGlobalHeaders, getGlobalBaseUrl, applyPick, mergeCallbacks, } from '
|
|
|
9
16
|
* - Watch pattern for reactive parameters
|
|
10
17
|
*/
|
|
11
18
|
export function useApiAsyncData(key, url, options) {
|
|
12
|
-
const { method = 'GET', body, headers = {}, params, baseURL, cacheKey, transform, pick, onRequest, onSuccess, onError, onFinish, skipGlobalCallbacks, immediate = true, lazy = false, server = true, dedupe = 'cancel', watch: watchOption = true, ...restOptions } = options || {};
|
|
19
|
+
const { method = 'GET', body, headers = {}, params, baseURL, cacheKey, transform, pick, onRequest, onSuccess, onError, onFinish, skipGlobalCallbacks, immediate = true, lazy = false, server = true, dedupe = 'cancel', watch: watchOption = true, paginated, initialPage, initialPerPage, paginationConfig, ...restOptions } = options || {};
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Pagination setup
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
const activePaginationConfig = paginationConfig ?? (paginated ? getGlobalApiPagination() : null);
|
|
24
|
+
const page = ref(initialPage ?? activePaginationConfig?.request.defaults.page ?? 1);
|
|
25
|
+
const perPage = ref(initialPerPage ?? activePaginationConfig?.request.defaults.perPage ?? 20);
|
|
26
|
+
const paginationState = ref({
|
|
27
|
+
currentPage: page.value,
|
|
28
|
+
totalPages: 0,
|
|
29
|
+
total: 0,
|
|
30
|
+
perPage: perPage.value,
|
|
31
|
+
});
|
|
13
32
|
// Resolve base URL once at setup time (not inside fetchFn to avoid warning on every request)
|
|
14
33
|
const resolvedBaseURL = baseURL || getGlobalBaseUrl();
|
|
15
34
|
if (!resolvedBaseURL) {
|
|
@@ -29,6 +48,8 @@ export function useApiAsyncData(key, url, options) {
|
|
|
29
48
|
? [() => params]
|
|
30
49
|
: []
|
|
31
50
|
: []),
|
|
51
|
+
// Add pagination refs so page/perPage changes trigger re-fetch
|
|
52
|
+
...(paginated ? [page, perPage] : []),
|
|
32
53
|
];
|
|
33
54
|
// Build a reactive cache key: composableName + resolved URL + serialized query params
|
|
34
55
|
// This ensures distinct params produce distinct keys — preventing cache collisions
|
|
@@ -47,7 +68,7 @@ export function useApiAsyncData(key, url, options) {
|
|
|
47
68
|
// Get URL value for merging callbacks
|
|
48
69
|
const finalUrl = typeof url === 'function' ? url() : url;
|
|
49
70
|
// Merge local and global callbacks
|
|
50
|
-
const mergedCallbacks = mergeCallbacks(finalUrl, { onRequest, onSuccess, onError, onFinish }, skipGlobalCallbacks);
|
|
71
|
+
const mergedCallbacks = mergeCallbacks(finalUrl, method, { onRequest, onSuccess, onError, onFinish }, skipGlobalCallbacks);
|
|
51
72
|
try {
|
|
52
73
|
// Get global headers
|
|
53
74
|
const globalHeaders = getGlobalHeaders();
|
|
@@ -75,23 +96,81 @@ export function useApiAsyncData(key, url, options) {
|
|
|
75
96
|
...modifications.headers,
|
|
76
97
|
};
|
|
77
98
|
}
|
|
78
|
-
if (modifications.
|
|
99
|
+
if (modifications.query !== undefined) {
|
|
79
100
|
modifiedContext.params = {
|
|
80
101
|
...modifiedContext.params,
|
|
81
|
-
...modifications.
|
|
102
|
+
...modifications.query,
|
|
82
103
|
};
|
|
83
104
|
}
|
|
84
105
|
}
|
|
85
106
|
}
|
|
86
107
|
// Make the request with $fetch — toValue() unrefs any Ref/ComputedRef
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
108
|
+
// For paginated requests with metaSource:'headers', use $fetch.raw for header access
|
|
109
|
+
let data;
|
|
110
|
+
if (paginated && activePaginationConfig) {
|
|
111
|
+
// Inject pagination params into the correct location
|
|
112
|
+
const paginationPayload = buildPaginationRequest(page.value, perPage.value, activePaginationConfig);
|
|
113
|
+
const paginatedQuery = { ...toValue(modifiedContext.params), ...paginationPayload.query };
|
|
114
|
+
const paginatedBody = paginationPayload.body
|
|
115
|
+
? { ...(toValue(modifiedContext.body) ?? {}), ...paginationPayload.body }
|
|
116
|
+
: toValue(modifiedContext.body);
|
|
117
|
+
const paginatedHeaders = paginationPayload.headers
|
|
118
|
+
? { ...modifiedContext.headers, ...paginationPayload.headers }
|
|
119
|
+
: modifiedContext.headers;
|
|
120
|
+
if (activePaginationConfig.meta.metaSource === 'headers') {
|
|
121
|
+
// Need raw fetch to access response headers
|
|
122
|
+
const response = await $fetch.raw(modifiedContext.url, {
|
|
123
|
+
method: modifiedContext.method,
|
|
124
|
+
headers: paginatedHeaders,
|
|
125
|
+
body: paginatedBody,
|
|
126
|
+
params: paginatedQuery,
|
|
127
|
+
...(resolvedBaseURL ? { baseURL: resolvedBaseURL } : {}),
|
|
128
|
+
...restOptions,
|
|
129
|
+
});
|
|
130
|
+
// Extract pagination meta from headers
|
|
131
|
+
const meta = extractPaginationMetaFromHeaders(response.headers, activePaginationConfig);
|
|
132
|
+
if (meta.total !== undefined)
|
|
133
|
+
paginationState.value.total = meta.total;
|
|
134
|
+
if (meta.totalPages !== undefined)
|
|
135
|
+
paginationState.value.totalPages = meta.totalPages;
|
|
136
|
+
if (meta.currentPage !== undefined)
|
|
137
|
+
paginationState.value.currentPage = meta.currentPage;
|
|
138
|
+
if (meta.perPage !== undefined)
|
|
139
|
+
paginationState.value.perPage = meta.perPage;
|
|
140
|
+
data = unwrapDataKey(response._data, activePaginationConfig);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
// metaSource: 'body' — extract after receiving the data
|
|
144
|
+
const rawData = await $fetch(modifiedContext.url, {
|
|
145
|
+
method: modifiedContext.method,
|
|
146
|
+
headers: paginatedHeaders,
|
|
147
|
+
body: paginatedBody,
|
|
148
|
+
params: paginatedQuery,
|
|
149
|
+
...(resolvedBaseURL ? { baseURL: resolvedBaseURL } : {}),
|
|
150
|
+
...restOptions,
|
|
151
|
+
});
|
|
152
|
+
const meta = extractPaginationMetaFromBody(rawData, activePaginationConfig);
|
|
153
|
+
if (meta.total !== undefined)
|
|
154
|
+
paginationState.value.total = meta.total;
|
|
155
|
+
if (meta.totalPages !== undefined)
|
|
156
|
+
paginationState.value.totalPages = meta.totalPages;
|
|
157
|
+
if (meta.currentPage !== undefined)
|
|
158
|
+
paginationState.value.currentPage = meta.currentPage;
|
|
159
|
+
if (meta.perPage !== undefined)
|
|
160
|
+
paginationState.value.perPage = meta.perPage;
|
|
161
|
+
data = unwrapDataKey(rawData, activePaginationConfig);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
data = await $fetch(modifiedContext.url, {
|
|
166
|
+
method: modifiedContext.method,
|
|
167
|
+
headers: modifiedContext.headers,
|
|
168
|
+
body: toValue(modifiedContext.body),
|
|
169
|
+
params: toValue(modifiedContext.params),
|
|
170
|
+
...(resolvedBaseURL ? { baseURL: resolvedBaseURL } : {}),
|
|
171
|
+
...restOptions,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
95
174
|
// Apply pick if provided
|
|
96
175
|
if (pick) {
|
|
97
176
|
data = applyPick(data, pick);
|
|
@@ -136,5 +215,27 @@ export function useApiAsyncData(key, url, options) {
|
|
|
136
215
|
dedupe,
|
|
137
216
|
watch: watchOption === false ? [] : watchSources,
|
|
138
217
|
});
|
|
139
|
-
|
|
218
|
+
if (!paginated)
|
|
219
|
+
return result;
|
|
220
|
+
// Pagination computed helpers
|
|
221
|
+
const hasNextPage = computed(() => paginationState.value.currentPage < paginationState.value.totalPages);
|
|
222
|
+
const hasPrevPage = computed(() => paginationState.value.currentPage > 1);
|
|
223
|
+
const goToPage = (n) => { page.value = n; };
|
|
224
|
+
const nextPage = () => { if (hasNextPage.value)
|
|
225
|
+
goToPage(page.value + 1); };
|
|
226
|
+
const prevPage = () => { if (hasPrevPage.value)
|
|
227
|
+
goToPage(page.value - 1); };
|
|
228
|
+
const setPerPage = (n) => { perPage.value = n; page.value = 1; };
|
|
229
|
+
return {
|
|
230
|
+
...result,
|
|
231
|
+
pagination: computed(() => ({
|
|
232
|
+
...paginationState.value,
|
|
233
|
+
hasNextPage: hasNextPage.value,
|
|
234
|
+
hasPrevPage: hasPrevPage.value,
|
|
235
|
+
})),
|
|
236
|
+
goToPage,
|
|
237
|
+
nextPage,
|
|
238
|
+
prevPage,
|
|
239
|
+
setPerPage,
|
|
240
|
+
};
|
|
140
241
|
}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* Nuxt Runtime Helper - This file is copied to the generated output
|
|
4
|
+
* It requires Nuxt 3 to be installed in the target project
|
|
5
|
+
*
|
|
6
|
+
* RAW VERSION: Returns full response including headers, status, and statusText
|
|
7
|
+
*/
|
|
8
|
+
import { ref, computed } from 'vue';
|
|
1
9
|
import { getGlobalHeaders, getGlobalBaseUrl, applyPick, mergeCallbacks, } from '../../shared/runtime/apiHelpers.js';
|
|
10
|
+
import { getGlobalApiPagination, buildPaginationRequest, extractPaginationMetaFromBody, extractPaginationMetaFromHeaders, unwrapDataKey, } from '../../shared/runtime/pagination.js';
|
|
2
11
|
/**
|
|
3
12
|
* Generic wrapper for API calls using Nuxt's useAsyncData - RAW VERSION
|
|
4
13
|
* Returns full response with headers and status information
|
|
@@ -12,7 +21,19 @@ import { getGlobalHeaders, getGlobalBaseUrl, applyPick, mergeCallbacks, } from '
|
|
|
12
21
|
* - Watch pattern for reactive parameters
|
|
13
22
|
*/
|
|
14
23
|
export function useApiAsyncDataRaw(key, url, options) {
|
|
15
|
-
const { method = 'GET', body, headers = {}, params, baseURL, cacheKey, transform, pick, onRequest, onSuccess, onError, onFinish, skipGlobalCallbacks, immediate = true, lazy = false, server = true, dedupe = 'cancel', ...restOptions } = options || {};
|
|
24
|
+
const { method = 'GET', body, headers = {}, params, baseURL, cacheKey, transform, pick, onRequest, onSuccess, onError, onFinish, skipGlobalCallbacks, immediate = true, lazy = false, server = true, dedupe = 'cancel', paginated, initialPage, initialPerPage, paginationConfig, ...restOptions } = options || {};
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Pagination setup
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
const activePaginationConfig = paginationConfig ?? (paginated ? getGlobalApiPagination() : null);
|
|
29
|
+
const page = ref(initialPage ?? activePaginationConfig?.request.defaults.page ?? 1);
|
|
30
|
+
const perPage = ref(initialPerPage ?? activePaginationConfig?.request.defaults.perPage ?? 20);
|
|
31
|
+
const paginationState = ref({
|
|
32
|
+
currentPage: page.value,
|
|
33
|
+
totalPages: 0,
|
|
34
|
+
total: 0,
|
|
35
|
+
perPage: perPage.value,
|
|
36
|
+
});
|
|
16
37
|
// Resolve base URL once at setup time (not inside fetchFn to avoid warning on every request)
|
|
17
38
|
const resolvedBaseURL = baseURL || getGlobalBaseUrl();
|
|
18
39
|
if (!resolvedBaseURL) {
|
|
@@ -23,6 +44,8 @@ export function useApiAsyncDataRaw(key, url, options) {
|
|
|
23
44
|
...(typeof url === 'function' ? [url] : []),
|
|
24
45
|
...(body && typeof body === 'object' ? [() => body] : []),
|
|
25
46
|
...(params && typeof params === 'object' ? [() => params] : []),
|
|
47
|
+
// Add pagination refs so page/perPage changes trigger re-fetch
|
|
48
|
+
...(paginated ? [page, perPage] : []),
|
|
26
49
|
];
|
|
27
50
|
// Build a reactive cache key: composableName + resolved URL + serialized query params
|
|
28
51
|
// This ensures distinct params produce distinct keys — preventing cache collisions
|
|
@@ -41,7 +64,7 @@ export function useApiAsyncDataRaw(key, url, options) {
|
|
|
41
64
|
// Get URL value for merging callbacks
|
|
42
65
|
const finalUrl = typeof url === 'function' ? url() : url;
|
|
43
66
|
// Merge local and global callbacks
|
|
44
|
-
const mergedCallbacks = mergeCallbacks(finalUrl, { onRequest, onSuccess, onError, onFinish }, skipGlobalCallbacks);
|
|
67
|
+
const mergedCallbacks = mergeCallbacks(finalUrl, method, { onRequest, onSuccess, onError, onFinish }, skipGlobalCallbacks);
|
|
45
68
|
try {
|
|
46
69
|
// Get global headers
|
|
47
70
|
const globalHeaders = getGlobalHeaders();
|
|
@@ -69,25 +92,58 @@ export function useApiAsyncDataRaw(key, url, options) {
|
|
|
69
92
|
...modifications.headers,
|
|
70
93
|
};
|
|
71
94
|
}
|
|
72
|
-
if (modifications.
|
|
95
|
+
if (modifications.query !== undefined) {
|
|
73
96
|
modifiedContext.params = {
|
|
74
97
|
...modifiedContext.params,
|
|
75
|
-
...modifications.
|
|
98
|
+
...modifications.query,
|
|
76
99
|
};
|
|
77
100
|
}
|
|
78
101
|
}
|
|
79
102
|
}
|
|
103
|
+
// Build final request params, injecting pagination if enabled
|
|
104
|
+
let finalQuery = modifiedContext.params;
|
|
105
|
+
let finalBody = modifiedContext.body;
|
|
106
|
+
let finalHeaders = modifiedContext.headers;
|
|
107
|
+
if (paginated && activePaginationConfig) {
|
|
108
|
+
const paginationPayload = buildPaginationRequest(page.value, perPage.value, activePaginationConfig);
|
|
109
|
+
if (paginationPayload.query)
|
|
110
|
+
finalQuery = { ...finalQuery, ...paginationPayload.query };
|
|
111
|
+
if (paginationPayload.body)
|
|
112
|
+
finalBody = { ...(finalBody ?? {}), ...paginationPayload.body };
|
|
113
|
+
if (paginationPayload.headers)
|
|
114
|
+
finalHeaders = { ...finalHeaders, ...paginationPayload.headers };
|
|
115
|
+
}
|
|
80
116
|
// Make the request with $fetch.raw to get full response
|
|
81
117
|
const response = await $fetch.raw(modifiedContext.url, {
|
|
82
118
|
method: modifiedContext.method,
|
|
83
|
-
headers:
|
|
84
|
-
body:
|
|
85
|
-
params:
|
|
119
|
+
headers: finalHeaders,
|
|
120
|
+
body: finalBody,
|
|
121
|
+
params: finalQuery,
|
|
86
122
|
...(resolvedBaseURL ? { baseURL: resolvedBaseURL } : {}),
|
|
87
123
|
...restOptions,
|
|
88
124
|
});
|
|
89
|
-
// Extract
|
|
90
|
-
|
|
125
|
+
// Extract pagination meta from headers or body
|
|
126
|
+
if (paginated && activePaginationConfig) {
|
|
127
|
+
let meta;
|
|
128
|
+
if (activePaginationConfig.meta.metaSource === 'headers') {
|
|
129
|
+
meta = extractPaginationMetaFromHeaders(response.headers, activePaginationConfig);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
meta = extractPaginationMetaFromBody(response._data, activePaginationConfig);
|
|
133
|
+
}
|
|
134
|
+
if (meta.total !== undefined)
|
|
135
|
+
paginationState.value.total = meta.total;
|
|
136
|
+
if (meta.totalPages !== undefined)
|
|
137
|
+
paginationState.value.totalPages = meta.totalPages;
|
|
138
|
+
if (meta.currentPage !== undefined)
|
|
139
|
+
paginationState.value.currentPage = meta.currentPage;
|
|
140
|
+
if (meta.perPage !== undefined)
|
|
141
|
+
paginationState.value.perPage = meta.perPage;
|
|
142
|
+
}
|
|
143
|
+
// Extract data from response (unwrap dataKey for paginated responses)
|
|
144
|
+
let data = paginated && activePaginationConfig
|
|
145
|
+
? unwrapDataKey(response._data, activePaginationConfig)
|
|
146
|
+
: response._data;
|
|
91
147
|
// Apply pick if provided (only to data)
|
|
92
148
|
if (pick) {
|
|
93
149
|
data = applyPick(data, pick);
|
|
@@ -140,5 +196,27 @@ export function useApiAsyncDataRaw(key, url, options) {
|
|
|
140
196
|
dedupe,
|
|
141
197
|
watch: watchSources.length > 0 ? watchSources : undefined,
|
|
142
198
|
});
|
|
143
|
-
|
|
199
|
+
if (!paginated)
|
|
200
|
+
return result;
|
|
201
|
+
// Pagination computed helpers
|
|
202
|
+
const hasNextPage = computed(() => paginationState.value.currentPage < paginationState.value.totalPages);
|
|
203
|
+
const hasPrevPage = computed(() => paginationState.value.currentPage > 1);
|
|
204
|
+
const goToPage = (n) => { page.value = n; };
|
|
205
|
+
const nextPage = () => { if (hasNextPage.value)
|
|
206
|
+
goToPage(page.value + 1); };
|
|
207
|
+
const prevPage = () => { if (hasPrevPage.value)
|
|
208
|
+
goToPage(page.value - 1); };
|
|
209
|
+
const setPerPage = (n) => { perPage.value = n; page.value = 1; };
|
|
210
|
+
return {
|
|
211
|
+
...result,
|
|
212
|
+
pagination: computed(() => ({
|
|
213
|
+
...paginationState.value,
|
|
214
|
+
hasNextPage: hasNextPage.value,
|
|
215
|
+
hasPrevPage: hasPrevPage.value,
|
|
216
|
+
})),
|
|
217
|
+
goToPage,
|
|
218
|
+
nextPage,
|
|
219
|
+
prevPage,
|
|
220
|
+
setPerPage,
|
|
221
|
+
};
|
|
144
222
|
}
|
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
* Generate file header with auto-generation warning
|
|
3
3
|
*/
|
|
4
4
|
function generateFileHeader() {
|
|
5
|
-
return `/**
|
|
6
|
-
* ⚠️ AUTO-GENERATED FILE - DO NOT EDIT MANUALLY
|
|
7
|
-
*
|
|
8
|
-
* This file was automatically generated by nuxt-openapi-generator.
|
|
9
|
-
* Any manual changes will be overwritten on the next generation.
|
|
10
|
-
*
|
|
11
|
-
* @generated by nuxt-openapi-generator
|
|
12
|
-
* @see https://github.com/dmartindiaz/nuxt-openapi-hyperfetch
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/* eslint-disable */
|
|
16
|
-
// @ts-nocheck
|
|
5
|
+
return `/**
|
|
6
|
+
* ⚠️ AUTO-GENERATED FILE - DO NOT EDIT MANUALLY
|
|
7
|
+
*
|
|
8
|
+
* This file was automatically generated by nuxt-openapi-generator.
|
|
9
|
+
* Any manual changes will be overwritten on the next generation.
|
|
10
|
+
*
|
|
11
|
+
* @generated by nuxt-openapi-generator
|
|
12
|
+
* @see https://github.com/dmartindiaz/nuxt-openapi-hyperfetch
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/* eslint-disable */
|
|
16
|
+
// @ts-nocheck
|
|
17
17
|
`;
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
@@ -120,11 +120,11 @@ function generateFunctionBody(method, isRaw, generateOptions) {
|
|
|
120
120
|
const argsExtraction = hasParams
|
|
121
121
|
? ` const _hasKey = typeof args[0] === 'string'\n const params = _hasKey ? args[1] : args[0]\n const options = _hasKey ? { cacheKey: args[0], ...args[2] } : args[1]`
|
|
122
122
|
: ` const _hasKey = typeof args[0] === 'string'\n const options = _hasKey ? { cacheKey: args[0], ...args[1] } : args[0]`;
|
|
123
|
-
return `${description}export function ${composableName}(key: string, ${args})
|
|
124
|
-
export function ${composableName}(${args})
|
|
125
|
-
export function ${composableName}(...args: any[]) {
|
|
126
|
-
${argsExtraction}${pInit}
|
|
127
|
-
return ${wrapperFunction}${responseTypeGeneric}(${key}, ${url}, ${fetchOptions})
|
|
123
|
+
return `${description}export function ${composableName}(key: string, ${args})
|
|
124
|
+
export function ${composableName}(${args})
|
|
125
|
+
export function ${composableName}(...args: any[]) {
|
|
126
|
+
${argsExtraction}${pInit}
|
|
127
|
+
return ${wrapperFunction}${responseTypeGeneric}(${key}, ${url}, ${fetchOptions})
|
|
128
128
|
}`;
|
|
129
129
|
}
|
|
130
130
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type GenerateOptions } from './templates.js';
|
|
2
|
+
import { type Logger } from '../../cli/logger.js';
|
|
2
3
|
/**
|
|
3
4
|
* Main function to generate useFetch composables
|
|
4
5
|
*/
|
|
5
|
-
export declare function generateUseFetchComposables(inputDir: string, outputDir: string, options?: GenerateOptions): Promise<void>;
|
|
6
|
+
export declare function generateUseFetchComposables(inputDir: string, outputDir: string, options?: GenerateOptions, logger?: Logger): Promise<void>;
|
|
@@ -5,12 +5,12 @@ import { format } from 'prettier';
|
|
|
5
5
|
import { getApiFiles as getApiFilesOfficial, parseApiFile as parseApiFileOfficial, } from './parser.js';
|
|
6
6
|
import { getApiFiles as getApiFilesHeyApi, parseApiFile as parseApiFileHeyApi, } from '../shared/parsers/heyapi-parser.js';
|
|
7
7
|
import { generateComposableFile, generateIndexFile } from './templates.js';
|
|
8
|
-
import {
|
|
8
|
+
import { createClackLogger } from '../../cli/logger.js';
|
|
9
9
|
/**
|
|
10
10
|
* Main function to generate useFetch composables
|
|
11
11
|
*/
|
|
12
|
-
export async function generateUseFetchComposables(inputDir, outputDir, options) {
|
|
13
|
-
const mainSpinner =
|
|
12
|
+
export async function generateUseFetchComposables(inputDir, outputDir, options, logger = createClackLogger()) {
|
|
13
|
+
const mainSpinner = logger.spinner();
|
|
14
14
|
// Select parser based on chosen backend
|
|
15
15
|
const getApiFiles = options?.backend === 'heyapi' ? getApiFilesHeyApi : getApiFilesOfficial;
|
|
16
16
|
const parseApiFile = options?.backend === 'heyapi' ? parseApiFileHeyApi : parseApiFileOfficial;
|
|
@@ -31,12 +31,12 @@ export async function generateUseFetchComposables(inputDir, outputDir, options)
|
|
|
31
31
|
allMethods.push(...apiInfo.methods);
|
|
32
32
|
}
|
|
33
33
|
catch (error) {
|
|
34
|
-
|
|
34
|
+
logger.log.error(`Error parsing ${fileName}: ${String(error)}`);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
mainSpinner.stop(`Found ${allMethods.length} methods to generate`);
|
|
38
38
|
if (allMethods.length === 0) {
|
|
39
|
-
|
|
39
|
+
logger.log.warn('No methods found to generate');
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
42
|
// 3. Clean and create output directories
|
|
@@ -72,27 +72,27 @@ export async function generateUseFetchComposables(inputDir, outputDir, options)
|
|
|
72
72
|
for (const method of allMethods) {
|
|
73
73
|
try {
|
|
74
74
|
const code = generateComposableFile(method, relativePath, options);
|
|
75
|
-
const formattedCode = await formatCode(code);
|
|
75
|
+
const formattedCode = await formatCode(code, logger);
|
|
76
76
|
const fileName = `${method.composableName}.ts`;
|
|
77
77
|
const filePath = path.join(composablesDir, fileName);
|
|
78
78
|
await fs.writeFile(filePath, formattedCode, 'utf-8');
|
|
79
79
|
successCount++;
|
|
80
80
|
}
|
|
81
81
|
catch (error) {
|
|
82
|
-
|
|
82
|
+
logger.log.error(`Error generating ${method.composableName}: ${String(error)}`);
|
|
83
83
|
errorCount++;
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
// 7. Generate index.ts
|
|
87
87
|
const indexCode = generateIndexFile(allMethods.map((m) => m.composableName));
|
|
88
|
-
const formattedIndex = await formatCode(indexCode);
|
|
88
|
+
const formattedIndex = await formatCode(indexCode, logger);
|
|
89
89
|
await fs.writeFile(path.join(outputDir, 'index.ts'), formattedIndex, 'utf-8');
|
|
90
90
|
mainSpinner.stop(`Generated ${successCount} composables`);
|
|
91
91
|
// 8. Summary
|
|
92
92
|
if (errorCount > 0) {
|
|
93
|
-
|
|
93
|
+
logger.log.warn(`Completed with ${errorCount} error(s)`);
|
|
94
94
|
}
|
|
95
|
-
|
|
95
|
+
logger.log.success(`Generated ${successCount} useFetch composable(s) in ${outputDir}`);
|
|
96
96
|
}
|
|
97
97
|
/**
|
|
98
98
|
* Calculate relative import path from composables to APIs
|
|
@@ -113,7 +113,7 @@ function calculateRelativeImportPath(composablesDir, inputDir) {
|
|
|
113
113
|
/**
|
|
114
114
|
* Format code with Prettier
|
|
115
115
|
*/
|
|
116
|
-
async function formatCode(code) {
|
|
116
|
+
async function formatCode(code, logger) {
|
|
117
117
|
try {
|
|
118
118
|
return await format(code, {
|
|
119
119
|
parser: 'typescript',
|
|
@@ -125,7 +125,7 @@ async function formatCode(code) {
|
|
|
125
125
|
});
|
|
126
126
|
}
|
|
127
127
|
catch {
|
|
128
|
-
|
|
128
|
+
logger.log.warn('Could not format code with Prettier');
|
|
129
129
|
return code;
|
|
130
130
|
}
|
|
131
131
|
}
|