nuxt-openapi-hyperfetch 0.3.2-beta → 0.3.3-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.
@@ -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 'z.record(z.unknown())';
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.2-beta",
3
+ "version": "0.3.3-beta",
4
4
  "description": "Nuxt useFetch, useAsyncData and Nuxt server OpenAPI generator",
5
5
  "type": "module",
6
6
  "author": "",
@@ -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 'z.record(z.unknown())';
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...');