@codewithagents/openapi-react-query 3.4.0 → 3.5.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.
@@ -17,7 +17,7 @@ describe('generateHooks — task-hooks.json fixture', () => {
17
17
 
18
18
  it('contains auto-generated header comment', () => {
19
19
  expect(content).toContain(
20
- '// This file is auto-generated by @codewithagents/openapi-react-query — do not edit',
20
+ '// This file is auto-generated by @codewithagents/openapi-react-query — do not edit'
21
21
  )
22
22
  })
23
23
 
@@ -40,8 +40,8 @@ describe('generateHooks — task-hooks.json fixture', () => {
40
40
  it('generates taskKeys factory with all(), list(), and detail() entries', () => {
41
41
  expect(content).toContain('export const taskKeys')
42
42
  expect(content).toContain("all: () => ['tasks'] as const")
43
- expect(content).toContain("list:")
44
- expect(content).toContain("detail:")
43
+ expect(content).toContain('list:')
44
+ expect(content).toContain('detail:')
45
45
  })
46
46
 
47
47
  it('useListTasks uses taskKeys.list(params) as queryKey', () => {
@@ -269,13 +269,19 @@ describe('generateHooks — Bug #53: key factory includes query params when oper
269
269
  })
270
270
 
271
271
  it('key factory detail entry includes required params when path + required query params', () => {
272
- const { content } = generateHooks(specWithPathAndRequiredQueryParams, { staleTime: 0, gcTime: 0 })
272
+ const { content } = generateHooks(specWithPathAndRequiredQueryParams, {
273
+ staleTime: 0,
274
+ gcTime: 0,
275
+ })
273
276
  // Key factory should accept required params (no ?)
274
277
  expect(content).toContain('(id: string, params: Parameters<typeof getReport>[1])')
275
278
  })
276
279
 
277
280
  it('hook marks params as required when path param + required query param', () => {
278
- const { content } = generateHooks(specWithPathAndRequiredQueryParams, { staleTime: 0, gcTime: 0 })
281
+ const { content } = generateHooks(specWithPathAndRequiredQueryParams, {
282
+ staleTime: 0,
283
+ gcTime: 0,
284
+ })
279
285
  expect(content).toContain('params: Parameters<typeof getReport>[1]')
280
286
  expect(content).not.toContain('params?: Parameters<typeof getReport>[1]')
281
287
  })
@@ -284,25 +290,43 @@ describe('generateHooks — Bug #53: key factory includes query params when oper
284
290
  // ── Bug #3: Mutation hook argument shapes ───────────────────────────────────────
285
291
 
286
292
  describe('generateHooks — Bug #54: mutation hook handles all argument shapes', () => {
287
- const makeSpec = (pathSegment: string, method: string, hasBody: boolean, queryParams: Array<{name: string; required?: boolean}>): OpenAPIV3_1.Document => ({
293
+ const makeSpec = (
294
+ pathSegment: string,
295
+ method: string,
296
+ hasBody: boolean,
297
+ queryParams: Array<{ name: string; required?: boolean }>
298
+ ): OpenAPIV3_1.Document => ({
288
299
  openapi: '3.1.0',
289
300
  info: { title: 'Test', version: '1.0.0' },
290
301
  paths: {
291
302
  [pathSegment]: {
292
303
  [method]: {
293
304
  operationId: `${method}Op`,
294
- parameters: queryParams.map((p) => ({ name: p.name, in: 'query' as const, required: p.required, schema: { type: 'string' as const } })),
295
- ...(hasBody ? {
296
- requestBody: {
297
- required: true,
298
- content: { 'application/json': { schema: { $ref: '#/components/schemas/Body' } } },
299
- },
300
- } : {}),
305
+ parameters: queryParams.map((p) => ({
306
+ name: p.name,
307
+ in: 'query' as const,
308
+ required: p.required,
309
+ schema: { type: 'string' as const },
310
+ })),
311
+ ...(hasBody
312
+ ? {
313
+ requestBody: {
314
+ required: true,
315
+ content: {
316
+ 'application/json': { schema: { $ref: '#/components/schemas/Body' } },
317
+ },
318
+ },
319
+ }
320
+ : {}),
301
321
  responses: { '200': { description: 'ok' } },
302
322
  },
303
323
  },
304
324
  },
305
- components: { schemas: { Body: { type: 'object' as const, properties: { name: { type: 'string' as const } } } } },
325
+ components: {
326
+ schemas: {
327
+ Body: { type: 'object' as const, properties: { name: { type: 'string' as const } } },
328
+ },
329
+ },
306
330
  })
307
331
 
308
332
  it('mutation with query params only (no body, no path): variables type is Parameters[0], mutationFn is (vars) => fn(vars)', () => {
@@ -344,7 +368,9 @@ describe('generateHooks — Bug #54: mutation hook handles all argument shapes',
344
368
  },
345
369
  },
346
370
  },
347
- components: { schemas: { Body: { type: 'object', properties: { name: { type: 'string' } } } } },
371
+ components: {
372
+ schemas: { Body: { type: 'object', properties: { name: { type: 'string' } } } },
373
+ },
348
374
  }
349
375
  const { content } = generateHooks(spec, { staleTime: 0, gcTime: 0 })
350
376
  // Variables includes id, body, and params
@@ -391,13 +417,17 @@ describe('generateHooks — Bug #54: mutation hook handles all argument shapes',
391
417
  operationId: 'createTask',
392
418
  requestBody: {
393
419
  required: true,
394
- content: { 'application/json': { schema: { $ref: '#/components/schemas/CreateTask' } } },
420
+ content: {
421
+ 'application/json': { schema: { $ref: '#/components/schemas/CreateTask' } },
422
+ },
395
423
  },
396
424
  responses: { '201': { description: 'created' } },
397
425
  },
398
426
  },
399
427
  },
400
- components: { schemas: { CreateTask: { type: 'object', properties: { title: { type: 'string' } } } } },
428
+ components: {
429
+ schemas: { CreateTask: { type: 'object', properties: { title: { type: 'string' } } } },
430
+ },
401
431
  }
402
432
  const { content } = generateHooks(spec, { staleTime: 0, gcTime: 0 })
403
433
  expect(content).toContain('Parameters<typeof createTask>[0]')
@@ -414,7 +444,14 @@ describe('generateHooks — tag name to camelCase key factory', () => {
414
444
  [`/${pathSegment}`]: {
415
445
  get: {
416
446
  operationId: `list${pathSegment}`,
417
- responses: { '200': { description: 'ok', content: { 'application/json': { schema: { type: 'array', items: { type: 'object' } } } } } },
447
+ responses: {
448
+ '200': {
449
+ description: 'ok',
450
+ content: {
451
+ 'application/json': { schema: { type: 'array', items: { type: 'object' } } },
452
+ },
453
+ },
454
+ },
418
455
  },
419
456
  },
420
457
  },
@@ -746,7 +783,11 @@ describe('generateHooks — Bug #75: auto-invalidation skips detail when multipl
746
783
  parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string' } }],
747
784
  requestBody: {
748
785
  required: true,
749
- content: { 'application/json': { schema: { type: 'object', properties: { name: { type: 'string' } } } } },
786
+ content: {
787
+ 'application/json': {
788
+ schema: { type: 'object', properties: { name: { type: 'string' } } },
789
+ },
790
+ },
750
791
  },
751
792
  responses: { '200': { description: 'ok' } },
752
793
  },
@@ -762,13 +803,21 @@ describe('generateHooks — Bug #75: auto-invalidation skips detail when multipl
762
803
  }
763
804
 
764
805
  it('key factory does NOT use "detail:" when there are multiple detail ops', () => {
765
- const { content } = generateHooks(multiDetailSpec, { staleTime: 0, gcTime: 0, autoInvalidate: true })
806
+ const { content } = generateHooks(multiDetailSpec, {
807
+ staleTime: 0,
808
+ gcTime: 0,
809
+ autoInvalidate: true,
810
+ })
766
811
  // With 2 detail ops (getItem + getItemSummary), the key factory uses operation-derived names
767
812
  expect(content).not.toContain('detail:')
768
813
  })
769
814
 
770
815
  it('mutation hook does NOT reference itemKeys.detail( when there are multiple detail ops', () => {
771
- const { content } = generateHooks(multiDetailSpec, { staleTime: 0, gcTime: 0, autoInvalidate: true })
816
+ const { content } = generateHooks(multiDetailSpec, {
817
+ staleTime: 0,
818
+ gcTime: 0,
819
+ autoInvalidate: true,
820
+ })
772
821
  const updateStart = content.indexOf('export function useUpdateItem')
773
822
  const updateEnd = content.indexOf('\n}', updateStart) + 2
774
823
  const updateContent = content.slice(updateStart, updateEnd)
@@ -776,7 +825,11 @@ describe('generateHooks — Bug #75: auto-invalidation skips detail when multipl
776
825
  })
777
826
 
778
827
  it('mutation hook DOES contain itemKeys.all() for broad invalidation', () => {
779
- const { content } = generateHooks(multiDetailSpec, { staleTime: 0, gcTime: 0, autoInvalidate: true })
828
+ const { content } = generateHooks(multiDetailSpec, {
829
+ staleTime: 0,
830
+ gcTime: 0,
831
+ autoInvalidate: true,
832
+ })
780
833
  const updateStart = content.indexOf('export function useUpdateItem')
781
834
  const updateEnd = content.indexOf('\n}', updateStart) + 2
782
835
  const updateContent = content.slice(updateStart, updateEnd)
@@ -892,7 +945,11 @@ describe('feature interactions', () => {
892
945
 
893
946
  describe('auto-invalidate mutations (#58)', () => {
894
947
  it('autoInvalidate: false — no useQueryClient or invalidateQueries in output', () => {
895
- const { content } = generateHooks(spec, { staleTime: 0, gcTime: 300_000, autoInvalidate: false })
948
+ const { content } = generateHooks(spec, {
949
+ staleTime: 0,
950
+ gcTime: 300_000,
951
+ autoInvalidate: false,
952
+ })
896
953
  expect(content).not.toContain('useQueryClient')
897
954
  expect(content).not.toContain('invalidateQueries')
898
955
  })
@@ -975,7 +1032,14 @@ describe('mutation hook variables type — all 12 shapes', () => {
975
1032
  operationId: 'postC',
976
1033
  requestBody: {
977
1034
  required: true,
978
- content: { 'application/json': { schema: { type: 'object' as const, properties: { name: { type: 'string' as const } } } } },
1035
+ content: {
1036
+ 'application/json': {
1037
+ schema: {
1038
+ type: 'object' as const,
1039
+ properties: { name: { type: 'string' as const } },
1040
+ },
1041
+ },
1042
+ },
979
1043
  },
980
1044
  responses: { '201': { description: 'created' } },
981
1045
  },
@@ -987,7 +1051,14 @@ describe('mutation hook variables type — all 12 shapes', () => {
987
1051
  parameters: [{ name: 'dryRun', in: 'query', schema: { type: 'string' } }],
988
1052
  requestBody: {
989
1053
  required: true,
990
- content: { 'application/json': { schema: { type: 'object' as const, properties: { name: { type: 'string' as const } } } } },
1054
+ content: {
1055
+ 'application/json': {
1056
+ schema: {
1057
+ type: 'object' as const,
1058
+ properties: { name: { type: 'string' as const } },
1059
+ },
1060
+ },
1061
+ },
991
1062
  },
992
1063
  responses: { '200': { description: 'ok' } },
993
1064
  },
@@ -1018,7 +1089,14 @@ describe('mutation hook variables type — all 12 shapes', () => {
1018
1089
  parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string' } }],
1019
1090
  requestBody: {
1020
1091
  required: true,
1021
- content: { 'application/json': { schema: { type: 'object' as const, properties: { name: { type: 'string' as const } } } } },
1092
+ content: {
1093
+ 'application/json': {
1094
+ schema: {
1095
+ type: 'object' as const,
1096
+ properties: { name: { type: 'string' as const } },
1097
+ },
1098
+ },
1099
+ },
1022
1100
  },
1023
1101
  responses: { '200': { description: 'ok' } },
1024
1102
  },
@@ -1033,7 +1111,14 @@ describe('mutation hook variables type — all 12 shapes', () => {
1033
1111
  ],
1034
1112
  requestBody: {
1035
1113
  required: true,
1036
- content: { 'application/json': { schema: { type: 'object' as const, properties: { name: { type: 'string' as const } } } } },
1114
+ content: {
1115
+ 'application/json': {
1116
+ schema: {
1117
+ type: 'object' as const,
1118
+ properties: { name: { type: 'string' as const } },
1119
+ },
1120
+ },
1121
+ },
1037
1122
  },
1038
1123
  responses: { '200': { description: 'ok' } },
1039
1124
  },
@@ -1071,7 +1156,14 @@ describe('mutation hook variables type — all 12 shapes', () => {
1071
1156
  ],
1072
1157
  requestBody: {
1073
1158
  required: true,
1074
- content: { 'application/json': { schema: { type: 'object' as const, properties: { name: { type: 'string' as const } } } } },
1159
+ content: {
1160
+ 'application/json': {
1161
+ schema: {
1162
+ type: 'object' as const,
1163
+ properties: { name: { type: 'string' as const } },
1164
+ },
1165
+ },
1166
+ },
1075
1167
  },
1076
1168
  responses: { '200': { description: 'ok' } },
1077
1169
  },
@@ -1087,7 +1179,14 @@ describe('mutation hook variables type — all 12 shapes', () => {
1087
1179
  ],
1088
1180
  requestBody: {
1089
1181
  required: true,
1090
- content: { 'application/json': { schema: { type: 'object' as const, properties: { name: { type: 'string' as const } } } } },
1182
+ content: {
1183
+ 'application/json': {
1184
+ schema: {
1185
+ type: 'object' as const,
1186
+ properties: { name: { type: 'string' as const } },
1187
+ },
1188
+ },
1189
+ },
1091
1190
  },
1092
1191
  responses: { '200': { description: 'ok' } },
1093
1192
  },
@@ -1099,28 +1198,38 @@ describe('mutation hook variables type — all 12 shapes', () => {
1099
1198
 
1100
1199
  it('case 1 (0 params, no body, no query): variablesType is void, mutationFn is () => fn()', () => {
1101
1200
  // UseMutationOptions<..., ApiError, void> — void is the variables type
1102
- expect(shapesContent).toContain('UseMutationOptions<Awaited<ReturnType<typeof deleteA>>, ApiError, void>')
1201
+ expect(shapesContent).toContain(
1202
+ 'UseMutationOptions<Awaited<ReturnType<typeof deleteA>>, ApiError, void>'
1203
+ )
1103
1204
  expect(shapesContent).toContain('mutationFn: () => deleteA()')
1104
1205
  })
1105
1206
 
1106
1207
  it('case 2 (0 params, no body, has query): variablesType is Parameters<typeof fn>[0], mutationFn is (vars) => fn(vars)', () => {
1107
- expect(shapesContent).toContain('UseMutationOptions<Awaited<ReturnType<typeof postB>>, ApiError, Parameters<typeof postB>[0]>')
1208
+ expect(shapesContent).toContain(
1209
+ 'UseMutationOptions<Awaited<ReturnType<typeof postB>>, ApiError, Parameters<typeof postB>[0]>'
1210
+ )
1108
1211
  expect(shapesContent).toContain('mutationFn: (vars) => postB(vars)')
1109
1212
  })
1110
1213
 
1111
1214
  it('case 3 (0 params, has body, no query): variablesType is Parameters<typeof fn>[0], mutationFn is (vars) => fn(vars)', () => {
1112
- expect(shapesContent).toContain('UseMutationOptions<Awaited<ReturnType<typeof postC>>, ApiError, Parameters<typeof postC>[0]>')
1215
+ expect(shapesContent).toContain(
1216
+ 'UseMutationOptions<Awaited<ReturnType<typeof postC>>, ApiError, Parameters<typeof postC>[0]>'
1217
+ )
1113
1218
  expect(shapesContent).toContain('mutationFn: (vars) => postC(vars)')
1114
1219
  })
1115
1220
 
1116
1221
  it('case 4 (0 params, has body, has query): variablesType is { body: ...[0]; params: ...[1] }, mutationFn destructures both', () => {
1117
- expect(shapesContent).toContain('body: Parameters<typeof postD>[0]; params: Parameters<typeof postD>[1]')
1222
+ expect(shapesContent).toContain(
1223
+ 'body: Parameters<typeof postD>[0]; params: Parameters<typeof postD>[1]'
1224
+ )
1118
1225
  expect(shapesContent).toContain('mutationFn: ({ body, params }) => postD(body, params)')
1119
1226
  })
1120
1227
 
1121
1228
  it('case 5 (1 path param, no body, no query): variablesType is string, mutationFn is (id) => fn(id)', () => {
1122
1229
  // string is the entire variables type — only case that uses literal 'string'
1123
- expect(shapesContent).toContain('UseMutationOptions<Awaited<ReturnType<typeof deleteE>>, ApiError, string>')
1230
+ expect(shapesContent).toContain(
1231
+ 'UseMutationOptions<Awaited<ReturnType<typeof deleteE>>, ApiError, string>'
1232
+ )
1124
1233
  expect(shapesContent).toContain('mutationFn: (id) => deleteE(id)')
1125
1234
  })
1126
1235
 
@@ -1135,28 +1244,44 @@ describe('mutation hook variables type — all 12 shapes', () => {
1135
1244
  })
1136
1245
 
1137
1246
  it('case 8 (1 path param, has body, has query): variablesType is { id: string; body: ...[1]; params: ...[2] }, mutationFn destructures all', () => {
1138
- expect(shapesContent).toContain('id: string; body: Parameters<typeof putH>[1]; params: Parameters<typeof putH>[2]')
1247
+ expect(shapesContent).toContain(
1248
+ 'id: string; body: Parameters<typeof putH>[1]; params: Parameters<typeof putH>[2]'
1249
+ )
1139
1250
  expect(shapesContent).toContain('mutationFn: ({ id, body, params }) => putH(id, body, params)')
1140
1251
  })
1141
1252
 
1142
1253
  it('case 9 (2+ params, no body, no query): variablesType is { projectId: string; taskId: string }, mutationFn destructures both path params', () => {
1143
1254
  expect(shapesContent).toContain('projectId: string; taskId: string }')
1144
- expect(shapesContent).toContain('mutationFn: ({ projectId, taskId }) => deleteI(projectId, taskId)')
1255
+ expect(shapesContent).toContain(
1256
+ 'mutationFn: ({ projectId, taskId }) => deleteI(projectId, taskId)'
1257
+ )
1145
1258
  })
1146
1259
 
1147
1260
  it('case 10 (2+ params, no body, has query): variablesType includes both path params and params, mutationFn passes all', () => {
1148
- expect(shapesContent).toContain('projectId: string; taskId: string; params: Parameters<typeof deleteJ>[2]')
1149
- expect(shapesContent).toContain('mutationFn: ({ projectId, taskId, params }) => deleteJ(projectId, taskId, params)')
1261
+ expect(shapesContent).toContain(
1262
+ 'projectId: string; taskId: string; params: Parameters<typeof deleteJ>[2]'
1263
+ )
1264
+ expect(shapesContent).toContain(
1265
+ 'mutationFn: ({ projectId, taskId, params }) => deleteJ(projectId, taskId, params)'
1266
+ )
1150
1267
  })
1151
1268
 
1152
1269
  it('case 11 (2+ params, has body, no query): variablesType includes both path params and body at index [2]', () => {
1153
- expect(shapesContent).toContain('projectId: string; taskId: string; body: Parameters<typeof putK>[2]')
1154
- expect(shapesContent).toContain('mutationFn: ({ projectId, taskId, body }) => putK(projectId, taskId, body)')
1270
+ expect(shapesContent).toContain(
1271
+ 'projectId: string; taskId: string; body: Parameters<typeof putK>[2]'
1272
+ )
1273
+ expect(shapesContent).toContain(
1274
+ 'mutationFn: ({ projectId, taskId, body }) => putK(projectId, taskId, body)'
1275
+ )
1155
1276
  })
1156
1277
 
1157
1278
  it('case 12 (2+ params, has body, has query): variablesType includes both path params, body at [2], params at [3]', () => {
1158
- expect(shapesContent).toContain('projectId: string; taskId: string; body: Parameters<typeof putL>[2]; params: Parameters<typeof putL>[3]')
1159
- expect(shapesContent).toContain('mutationFn: ({ projectId, taskId, body, params }) => putL(projectId, taskId, body, params)')
1279
+ expect(shapesContent).toContain(
1280
+ 'projectId: string; taskId: string; body: Parameters<typeof putL>[2]; params: Parameters<typeof putL>[3]'
1281
+ )
1282
+ expect(shapesContent).toContain(
1283
+ 'mutationFn: ({ projectId, taskId, body, params }) => putL(projectId, taskId, body, params)'
1284
+ )
1160
1285
  })
1161
1286
  })
1162
1287
 
@@ -1187,7 +1312,14 @@ describe('auto-invalidate: method-based detail invalidation', () => {
1187
1312
  parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string' } }],
1188
1313
  requestBody: {
1189
1314
  required: true,
1190
- content: { 'application/json': { schema: { type: 'object' as const, properties: { name: { type: 'string' as const } } } } },
1315
+ content: {
1316
+ 'application/json': {
1317
+ schema: {
1318
+ type: 'object' as const,
1319
+ properties: { name: { type: 'string' as const } },
1320
+ },
1321
+ },
1322
+ },
1191
1323
  },
1192
1324
  responses: { '200': { description: 'ok' } },
1193
1325
  },
@@ -1197,7 +1329,14 @@ describe('auto-invalidate: method-based detail invalidation', () => {
1197
1329
  parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string' } }],
1198
1330
  requestBody: {
1199
1331
  required: true,
1200
- content: { 'application/json': { schema: { type: 'object' as const, properties: { name: { type: 'string' as const } } } } },
1332
+ content: {
1333
+ 'application/json': {
1334
+ schema: {
1335
+ type: 'object' as const,
1336
+ properties: { name: { type: 'string' as const } },
1337
+ },
1338
+ },
1339
+ },
1201
1340
  },
1202
1341
  responses: { '200': { description: 'ok' } },
1203
1342
  },
@@ -1211,7 +1350,11 @@ describe('auto-invalidate: method-based detail invalidation', () => {
1211
1350
  },
1212
1351
  }
1213
1352
 
1214
- const { content: thingsContent } = generateHooks(thingsSpec, { staleTime: 0, gcTime: 0, autoInvalidate: true })
1353
+ const { content: thingsContent } = generateHooks(thingsSpec, {
1354
+ staleTime: 0,
1355
+ gcTime: 0,
1356
+ autoInvalidate: true,
1357
+ })
1215
1358
 
1216
1359
  it('thingKeys key factory has a detail entry (exactly one detail GET op)', () => {
1217
1360
  expect(thingsContent).toContain('export const thingKeys')
@@ -1285,7 +1428,10 @@ describe('query hook key builder — 2+ path params with query params', () => {
1285
1428
  },
1286
1429
  }
1287
1430
 
1288
- const { content: multiParamContent } = generateHooks(multiParamQuerySpec, { staleTime: 0, gcTime: 0 })
1431
+ const { content: multiParamContent } = generateHooks(multiParamQuerySpec, {
1432
+ staleTime: 0,
1433
+ gcTime: 0,
1434
+ })
1289
1435
 
1290
1436
  it('key factory detail entry accepts both path params as typed args', () => {
1291
1437
  expect(multiParamContent).toContain('(projectId: string, taskId: string,')
@@ -1297,7 +1443,9 @@ describe('query hook key builder — 2+ path params with query params', () => {
1297
1443
  })
1298
1444
 
1299
1445
  it('enabled guard ANDs both path params', () => {
1300
- expect(multiParamContent).toContain('enabled: projectId != null && taskId != null && (options?.enabled ?? true)')
1446
+ expect(multiParamContent).toContain(
1447
+ 'enabled: projectId != null && taskId != null && (options?.enabled ?? true)'
1448
+ )
1301
1449
  })
1302
1450
 
1303
1451
  it('queryKey call includes both path params with non-null assertions and query params', () => {
@@ -1317,7 +1465,10 @@ describe('generateHooks — edge cases', () => {
1317
1465
  post: {
1318
1466
  operationId: 'createPet',
1319
1467
  deprecated: true,
1320
- requestBody: { required: true, content: { 'application/json': { schema: { type: 'object' } } } },
1468
+ requestBody: {
1469
+ required: true,
1470
+ content: { 'application/json': { schema: { type: 'object' } } },
1471
+ },
1321
1472
  responses: { '201': { description: 'Created' } },
1322
1473
  },
1323
1474
  },
@@ -1367,14 +1518,28 @@ describe('generateHooks — edge cases', () => {
1367
1518
  '/items': {
1368
1519
  get: {
1369
1520
  operationId: 'listItems',
1370
- responses: { '200': { description: 'ok', content: { 'application/json': { schema: { type: 'array', items: { type: 'object' } } } } } },
1521
+ responses: {
1522
+ '200': {
1523
+ description: 'ok',
1524
+ content: {
1525
+ 'application/json': { schema: { type: 'array', items: { type: 'object' } } },
1526
+ },
1527
+ },
1528
+ },
1371
1529
  },
1372
1530
  },
1373
1531
  '/items/search': {
1374
1532
  get: {
1375
1533
  operationId: 'searchItems',
1376
1534
  parameters: [{ name: 'q', in: 'query', schema: { type: 'string' } }],
1377
- responses: { '200': { description: 'ok', content: { 'application/json': { schema: { type: 'array', items: { type: 'object' } } } } } },
1535
+ responses: {
1536
+ '200': {
1537
+ description: 'ok',
1538
+ content: {
1539
+ 'application/json': { schema: { type: 'array', items: { type: 'object' } } },
1540
+ },
1541
+ },
1542
+ },
1378
1543
  },
1379
1544
  },
1380
1545
  },
@@ -1413,7 +1578,10 @@ describe('Bug #105: cache key collision when multiple GET ops share same path pa
1413
1578
  },
1414
1579
  }
1415
1580
 
1416
- const { content: multiDetailResult } = generateHooks(specWithMultipleDetailOps, { staleTime: 0, gcTime: 0 })
1581
+ const { content: multiDetailResult } = generateHooks(specWithMultipleDetailOps, {
1582
+ staleTime: 0,
1583
+ gcTime: 0,
1584
+ })
1417
1585
 
1418
1586
  it('both operations have distinct named entries in the key factory', () => {
1419
1587
  expect(multiDetailResult).toContain('getItemById:')
@@ -1504,7 +1672,9 @@ describe('generateHooks — path segment sanitization in deriveOperationName', (
1504
1672
  paths: {
1505
1673
  '/api-keys/{api-key-id}': {
1506
1674
  get: {
1507
- parameters: [{ name: 'api-key-id', in: 'path', required: true, schema: { type: 'string' } }],
1675
+ parameters: [
1676
+ { name: 'api-key-id', in: 'path', required: true, schema: { type: 'string' } },
1677
+ ],
1508
1678
  responses: { '200': { description: 'ok' } },
1509
1679
  },
1510
1680
  },
@@ -1547,7 +1717,14 @@ describe('generateHooks — toKeyFactoryName sanitizes special chars', () => {
1547
1717
  '/attachments/{attachment-publicUUID}': {
1548
1718
  get: {
1549
1719
  operationId: 'getAttachment',
1550
- parameters: [{ name: 'attachment-publicUUID', in: 'path', required: true, schema: { type: 'string' } }],
1720
+ parameters: [
1721
+ {
1722
+ name: 'attachment-publicUUID',
1723
+ in: 'path',
1724
+ required: true,
1725
+ schema: { type: 'string' },
1726
+ },
1727
+ ],
1551
1728
  responses: { '200': { description: 'ok' } },
1552
1729
  },
1553
1730
  },
@@ -1576,7 +1753,10 @@ describe('Bug #106: ...options spread must not overwrite auto-invalidation onSuc
1576
1753
  },
1577
1754
  post: {
1578
1755
  operationId: 'createItem',
1579
- requestBody: { required: true, content: { 'application/json': { schema: { $ref: '#/components/schemas/Item' } } } },
1756
+ requestBody: {
1757
+ required: true,
1758
+ content: { 'application/json': { schema: { $ref: '#/components/schemas/Item' } } },
1759
+ },
1580
1760
  responses: { '201': { description: 'ok' } },
1581
1761
  },
1582
1762
  },
@@ -1615,7 +1795,11 @@ describe('Bug #106: ...options spread must not overwrite auto-invalidation onSuc
1615
1795
  })
1616
1796
 
1617
1797
  it('mutation hook without auto-invalidation is unaffected (no onSuccess generated)', () => {
1618
- const { content: plain } = generateHooks(specWithAutoInvalidate, { staleTime: 0, gcTime: 0, autoInvalidate: false })
1798
+ const { content: plain } = generateHooks(specWithAutoInvalidate, {
1799
+ staleTime: 0,
1800
+ gcTime: 0,
1801
+ autoInvalidate: false,
1802
+ })
1619
1803
  const hookStart = plain.indexOf('export function useCreateItem')
1620
1804
  const hookEnd = plain.indexOf('\n}', hookStart) + 2
1621
1805
  const hookContent = plain.slice(hookStart, hookEnd)
@@ -24,7 +24,7 @@ async function runGenerator(): Promise<string> {
24
24
  await writeFile(
25
25
  configPath,
26
26
  JSON.stringify({ input_openapi: taskHooksFixture, output: outDir }),
27
- 'utf-8',
27
+ 'utf-8'
28
28
  )
29
29
  await generate(tmpDir, configPath)
30
30
  return outDir
@@ -17,7 +17,7 @@ describe('generateTestUtils', () => {
17
17
 
18
18
  it('contains auto-generated header comment', () => {
19
19
  expect(content).toContain(
20
- '// This file is auto-generated by @codewithagents/openapi-react-query — do not edit',
20
+ '// This file is auto-generated by @codewithagents/openapi-react-query — do not edit'
21
21
  )
22
22
  })
23
23
 
package/src/config.ts CHANGED
@@ -19,15 +19,33 @@ export interface ReactQueryConfig {
19
19
  }
20
20
 
21
21
  const FORBIDDEN_OUTPUT_PREFIXES = [
22
- '/etc', '/usr', '/bin', '/sbin', '/lib', '/lib64',
23
- '/sys', '/proc', '/dev', '/boot', '/run',
24
- 'C:\\Windows', 'C:\\Program Files',
22
+ '/etc',
23
+ '/usr',
24
+ '/bin',
25
+ '/sbin',
26
+ '/lib',
27
+ '/lib64',
28
+ '/sys',
29
+ '/proc',
30
+ '/dev',
31
+ '/boot',
32
+ '/run',
33
+ 'C:\\Windows',
34
+ 'C:\\Program Files',
25
35
  ]
26
36
 
27
37
  const FORBIDDEN_INPUT_PREFIXES = [
28
- '/etc', '/usr', '/bin', '/sbin', '/lib', '/lib64',
29
- '/sys', '/proc', '/dev',
30
- 'C:\\Windows', 'C:\\Program Files',
38
+ '/etc',
39
+ '/usr',
40
+ '/bin',
41
+ '/sbin',
42
+ '/lib',
43
+ '/lib64',
44
+ '/sys',
45
+ '/proc',
46
+ '/dev',
47
+ 'C:\\Windows',
48
+ 'C:\\Program Files',
31
49
  ]
32
50
 
33
51
  export function validateConfigPath(configPath: string): void {
@@ -44,7 +62,7 @@ export function validateOutputPath(resolvedOutput: string): void {
44
62
  if (normalized === normalizedForbidden || normalized.startsWith(normalizedForbidden + '/')) {
45
63
  throw new Error(
46
64
  `Output path resolves to a system directory: "${resolvedOutput}". ` +
47
- `This looks like a misconfiguration — please check your config file.`
65
+ `This looks like a misconfiguration — please check your config file.`
48
66
  )
49
67
  }
50
68
  }
@@ -57,7 +75,7 @@ export function validateInputPath(resolvedInput: string): void {
57
75
  if (normalized === normalizedForbidden || normalized.startsWith(normalizedForbidden + '/')) {
58
76
  throw new Error(
59
77
  `Input spec path resolves to a system directory: "${resolvedInput}". ` +
60
- `This looks like a misconfiguration — please check your config file.`
78
+ `This looks like a misconfiguration — please check your config file.`
61
79
  )
62
80
  }
63
81
  }
@@ -110,10 +128,16 @@ export async function loadConfig(cwd: string, configPath?: string): Promise<Reac
110
128
  throw new Error('"auto_invalidate" must be a boolean')
111
129
  }
112
130
  if (config['overrides'] !== undefined) {
113
- if (typeof config['overrides'] !== 'object' || config['overrides'] === null || Array.isArray(config['overrides'])) {
131
+ if (
132
+ typeof config['overrides'] !== 'object' ||
133
+ config['overrides'] === null ||
134
+ Array.isArray(config['overrides'])
135
+ ) {
114
136
  throw new Error('"overrides" must be an object')
115
137
  }
116
- for (const [resource, timing] of Object.entries(config['overrides'] as Record<string, unknown>)) {
138
+ for (const [resource, timing] of Object.entries(
139
+ config['overrides'] as Record<string, unknown>
140
+ )) {
117
141
  if (typeof timing !== 'object' || timing === null) {
118
142
  throw new Error(`"overrides.${resource}" must be an object`)
119
143
  }
@@ -139,7 +163,9 @@ export async function loadConfig(cwd: string, configPath?: string): Promise<Reac
139
163
  stale_time: config['stale_time'] as number | undefined,
140
164
  gc_time: config['gc_time'] as number | undefined,
141
165
  suspense: config['suspense'] as boolean | undefined,
142
- overrides: config['overrides'] as Record<string, { stale_time?: number; gc_time?: number }> | undefined,
166
+ overrides: config['overrides'] as
167
+ | Record<string, { stale_time?: number; gc_time?: number }>
168
+ | undefined,
143
169
  auto_invalidate: config['auto_invalidate'] as boolean | undefined,
144
170
  }
145
171
  }