nuxt-openapi-hyperfetch 0.3.2-beta → 0.3.4-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.
- package/dist/generators/components/schema-analyzer/intent-detector.js +12 -0
- package/dist/generators/components/schema-analyzer/schema-field-mapper.js +22 -1
- package/dist/index.js +13 -0
- package/package.json +3 -2
- package/src/generators/components/schema-analyzer/intent-detector.ts +16 -0
- package/src/generators/components/schema-analyzer/schema-field-mapper.ts +26 -1
- package/src/index.ts +15 -0
|
@@ -36,6 +36,13 @@ function getSuccessResponseSchema(operation) {
|
|
|
36
36
|
function isArraySchema(schema) {
|
|
37
37
|
return schema.type === 'array' || schema.items !== undefined;
|
|
38
38
|
}
|
|
39
|
+
/** True when schema is a primitive scalar (string, number, integer, boolean) — not a resource */
|
|
40
|
+
function isPrimitiveSchema(schema) {
|
|
41
|
+
return (schema.type === 'string' ||
|
|
42
|
+
schema.type === 'number' ||
|
|
43
|
+
schema.type === 'integer' ||
|
|
44
|
+
schema.type === 'boolean');
|
|
45
|
+
}
|
|
39
46
|
// ─── Request body schema ──────────────────────────────────────────────────────
|
|
40
47
|
function getRequestBodySchema(operation) {
|
|
41
48
|
if (!operation.requestBody?.content) {
|
|
@@ -84,6 +91,11 @@ export function detectIntent(method, path, operation) {
|
|
|
84
91
|
if (isArraySchema(responseSchema)) {
|
|
85
92
|
return 'list';
|
|
86
93
|
}
|
|
94
|
+
// Primitive response (string, number, boolean) → not a CRUD resource
|
|
95
|
+
// e.g. GET /user/login returns a string token — not a list or detail
|
|
96
|
+
if (isPrimitiveSchema(responseSchema)) {
|
|
97
|
+
return 'unknown';
|
|
98
|
+
}
|
|
87
99
|
// Object response — distinguish list vs detail by path structure:
|
|
88
100
|
// GET /pets/{id} → has path param → detail (single item fetch)
|
|
89
101
|
// GET /pets → no path param → list (likely paginated envelope: { data: [], total: n })
|
|
@@ -132,7 +132,7 @@ function baseZodExpr(prop) {
|
|
|
132
132
|
case 'array':
|
|
133
133
|
return arrayZodExpr(prop);
|
|
134
134
|
case 'object':
|
|
135
|
-
return
|
|
135
|
+
return objectZodExpr(prop);
|
|
136
136
|
default:
|
|
137
137
|
// $ref already resolved, unknown type → permissive
|
|
138
138
|
return 'z.unknown()';
|
|
@@ -181,6 +181,27 @@ function numberZodExpr(prop) {
|
|
|
181
181
|
}
|
|
182
182
|
return expr;
|
|
183
183
|
}
|
|
184
|
+
function objectZodExpr(prop) {
|
|
185
|
+
const { additionalProperties } = prop;
|
|
186
|
+
// additionalProperties: false or undefined → plain object
|
|
187
|
+
if (!additionalProperties || additionalProperties === true) {
|
|
188
|
+
return 'z.record(z.unknown())';
|
|
189
|
+
}
|
|
190
|
+
// additionalProperties has a known primitive type → typed record
|
|
191
|
+
const valueExpr = additionalPropsZodExpr(additionalProperties);
|
|
192
|
+
return `z.record(${valueExpr})`;
|
|
193
|
+
}
|
|
194
|
+
function additionalPropsZodExpr(schema) {
|
|
195
|
+
switch (schema.type) {
|
|
196
|
+
case 'string': return stringZodExpr(schema);
|
|
197
|
+
case 'integer': return integerZodExpr(schema);
|
|
198
|
+
case 'number': return numberZodExpr(schema);
|
|
199
|
+
case 'boolean': return 'z.boolean()';
|
|
200
|
+
case 'array': return arrayZodExpr(schema);
|
|
201
|
+
case 'object': return objectZodExpr(schema);
|
|
202
|
+
default: return 'z.unknown()';
|
|
203
|
+
}
|
|
204
|
+
}
|
|
184
205
|
function arrayZodExpr(prop) {
|
|
185
206
|
const itemExpr = prop.items ? baseZodExpr(prop.items) : 'z.unknown()';
|
|
186
207
|
let expr = `z.array(${itemExpr})`;
|
package/dist/index.js
CHANGED
|
@@ -196,6 +196,19 @@ program
|
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
// Generate headless connectors if requested (requires useAsyncData)
|
|
199
|
+
if (generateConnectorsFlag) {
|
|
200
|
+
// Check zod is available in the user's project before attempting generation
|
|
201
|
+
try {
|
|
202
|
+
// Use a variable to prevent TypeScript from resolving the module at compile time
|
|
203
|
+
const zodId = 'zod';
|
|
204
|
+
await import(zodId);
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
p.log.warn('Skipping connectors: "zod" is not installed in this project.\n' +
|
|
208
|
+
' Run: npm install zod');
|
|
209
|
+
generateConnectorsFlag = false;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
199
212
|
if (generateConnectorsFlag) {
|
|
200
213
|
const spinner = p.spinner();
|
|
201
214
|
spinner.start('Generating headless UI connectors...');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-openapi-hyperfetch",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4-beta",
|
|
4
4
|
"description": "Nuxt useFetch, useAsyncData and Nuxt server OpenAPI generator",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "",
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
"format": "prettier --write \"**/*.{ts,json,md,yaml,yml}\"",
|
|
41
41
|
"format:check": "prettier --check \"**/*.{ts,json,md,yaml,yml}\"",
|
|
42
42
|
"type-check": "tsc --noEmit",
|
|
43
|
-
"validate": "npm run type-check && npm run lint && npm run format:check"
|
|
43
|
+
"validate": "npm run type-check && npm run lint && npm run format:check",
|
|
44
|
+
"prepublishOnly": "npm run build"
|
|
44
45
|
},
|
|
45
46
|
"peerDependencies": {
|
|
46
47
|
"@nuxt/kit": "^3.0.0 || ^4.0.0",
|
|
@@ -49,6 +49,16 @@ function isArraySchema(schema: OpenApiPropertySchema): boolean {
|
|
|
49
49
|
return schema.type === 'array' || schema.items !== undefined;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/** True when schema is a primitive scalar (string, number, integer, boolean) — not a resource */
|
|
53
|
+
function isPrimitiveSchema(schema: OpenApiPropertySchema): boolean {
|
|
54
|
+
return (
|
|
55
|
+
schema.type === 'string' ||
|
|
56
|
+
schema.type === 'number' ||
|
|
57
|
+
schema.type === 'integer' ||
|
|
58
|
+
schema.type === 'boolean'
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
52
62
|
// ─── Request body schema ──────────────────────────────────────────────────────
|
|
53
63
|
|
|
54
64
|
function getRequestBodySchema(operation: OpenApiOperation): OpenApiPropertySchema | undefined {
|
|
@@ -113,6 +123,12 @@ export function detectIntent(
|
|
|
113
123
|
return 'list';
|
|
114
124
|
}
|
|
115
125
|
|
|
126
|
+
// Primitive response (string, number, boolean) → not a CRUD resource
|
|
127
|
+
// e.g. GET /user/login returns a string token — not a list or detail
|
|
128
|
+
if (isPrimitiveSchema(responseSchema)) {
|
|
129
|
+
return 'unknown';
|
|
130
|
+
}
|
|
131
|
+
|
|
116
132
|
// Object response — distinguish list vs detail by path structure:
|
|
117
133
|
// GET /pets/{id} → has path param → detail (single item fetch)
|
|
118
134
|
// GET /pets → no path param → list (likely paginated envelope: { data: [], total: n })
|
|
@@ -167,7 +167,7 @@ function baseZodExpr(prop: OpenApiPropertySchema): string {
|
|
|
167
167
|
return arrayZodExpr(prop);
|
|
168
168
|
|
|
169
169
|
case 'object':
|
|
170
|
-
return
|
|
170
|
+
return objectZodExpr(prop);
|
|
171
171
|
|
|
172
172
|
default:
|
|
173
173
|
// $ref already resolved, unknown type → permissive
|
|
@@ -224,6 +224,31 @@ function numberZodExpr(prop: OpenApiPropertySchema): string {
|
|
|
224
224
|
return expr;
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
+
function objectZodExpr(prop: OpenApiPropertySchema): string {
|
|
228
|
+
const { additionalProperties } = prop;
|
|
229
|
+
|
|
230
|
+
// additionalProperties: false or undefined → plain object
|
|
231
|
+
if (!additionalProperties || additionalProperties === true) {
|
|
232
|
+
return 'z.record(z.unknown())';
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// additionalProperties has a known primitive type → typed record
|
|
236
|
+
const valueExpr = additionalPropsZodExpr(additionalProperties);
|
|
237
|
+
return `z.record(${valueExpr})`;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function additionalPropsZodExpr(schema: OpenApiPropertySchema): string {
|
|
241
|
+
switch (schema.type) {
|
|
242
|
+
case 'string': return stringZodExpr(schema);
|
|
243
|
+
case 'integer': return integerZodExpr(schema);
|
|
244
|
+
case 'number': return numberZodExpr(schema);
|
|
245
|
+
case 'boolean': return 'z.boolean()';
|
|
246
|
+
case 'array': return arrayZodExpr(schema);
|
|
247
|
+
case 'object': return objectZodExpr(schema);
|
|
248
|
+
default: return 'z.unknown()';
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
227
252
|
function arrayZodExpr(prop: OpenApiPropertySchema): string {
|
|
228
253
|
const itemExpr = prop.items ? baseZodExpr(prop.items) : 'z.unknown()';
|
|
229
254
|
let expr = `z.array(${itemExpr})`;
|
package/src/index.ts
CHANGED
|
@@ -253,6 +253,21 @@ program
|
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
// Generate headless connectors if requested (requires useAsyncData)
|
|
256
|
+
if (generateConnectorsFlag) {
|
|
257
|
+
// Check zod is available in the user's project before attempting generation
|
|
258
|
+
try {
|
|
259
|
+
// Use a variable to prevent TypeScript from resolving the module at compile time
|
|
260
|
+
const zodId = 'zod';
|
|
261
|
+
await import(zodId);
|
|
262
|
+
} catch {
|
|
263
|
+
p.log.warn(
|
|
264
|
+
'Skipping connectors: "zod" is not installed in this project.\n' +
|
|
265
|
+
' Run: npm install zod'
|
|
266
|
+
);
|
|
267
|
+
generateConnectorsFlag = false;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
256
271
|
if (generateConnectorsFlag) {
|
|
257
272
|
const spinner = p.spinner();
|
|
258
273
|
spinner.start('Generating headless UI connectors...');
|