@openapi-qraft/tanstack-query-react-plugin 1.8.0

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 (55) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1 -0
  3. package/dist/__snapshots__/create-api-client.ts.snapshot.d.ts +1 -0
  4. package/dist/__snapshots__/create-api-client.ts.snapshot.js +88 -0
  5. package/dist/__snapshots__/create-api-client.ts.snapshot.js.map +1 -0
  6. package/dist/__snapshots__/index.ts.snapshot.d.ts +1 -0
  7. package/dist/__snapshots__/index.ts.snapshot.js +13 -0
  8. package/dist/__snapshots__/index.ts.snapshot.js.map +1 -0
  9. package/dist/__snapshots__/services/ApprovalPoliciesService.ts.snapshot.d.ts +1 -0
  10. package/dist/__snapshots__/services/ApprovalPoliciesService.ts.snapshot.js +62 -0
  11. package/dist/__snapshots__/services/ApprovalPoliciesService.ts.snapshot.js.map +1 -0
  12. package/dist/__snapshots__/services/FilesService.ts.snapshot.d.ts +1 -0
  13. package/dist/__snapshots__/services/FilesService.ts.snapshot.js +57 -0
  14. package/dist/__snapshots__/services/FilesService.ts.snapshot.js.map +1 -0
  15. package/dist/__snapshots__/services/index.ts.snapshot.d.ts +1 -0
  16. package/dist/__snapshots__/services/index.ts.snapshot.js +24 -0
  17. package/dist/__snapshots__/services/index.ts.snapshot.js.map +1 -0
  18. package/dist/generateCode.d.ts +18 -0
  19. package/dist/generateCode.js +116 -0
  20. package/dist/generateCode.js.map +1 -0
  21. package/dist/index.d.ts +2 -0
  22. package/dist/index.js +3 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/plugin.d.ts +2 -0
  25. package/dist/plugin.js +30 -0
  26. package/dist/plugin.js.map +1 -0
  27. package/dist/ts-factory/astToString.d.ts +8 -0
  28. package/dist/ts-factory/astToString.js +14 -0
  29. package/dist/ts-factory/astToString.js.map +1 -0
  30. package/dist/ts-factory/getClientFactory.d.ts +7 -0
  31. package/dist/ts-factory/getClientFactory.js +84 -0
  32. package/dist/ts-factory/getClientFactory.js.map +1 -0
  33. package/dist/ts-factory/getIndexFactory.d.ts +5 -0
  34. package/dist/ts-factory/getIndexFactory.js +17 -0
  35. package/dist/ts-factory/getIndexFactory.js.map +1 -0
  36. package/dist/ts-factory/getServiceFactory.d.ts +10 -0
  37. package/dist/ts-factory/getServiceFactory.js +120 -0
  38. package/dist/ts-factory/getServiceFactory.js.map +1 -0
  39. package/dist/ts-factory/getServiceIndexFactory.d.ts +7 -0
  40. package/dist/ts-factory/getServiceIndexFactory.js +26 -0
  41. package/dist/ts-factory/getServiceIndexFactory.js.map +1 -0
  42. package/package.json +48 -0
  43. package/src/__snapshots__/create-api-client.ts.snapshot.ts +88 -0
  44. package/src/__snapshots__/index.ts.snapshot.ts +13 -0
  45. package/src/__snapshots__/services/ApprovalPoliciesService.ts.snapshot.ts +64 -0
  46. package/src/__snapshots__/services/FilesService.ts.snapshot.ts +57 -0
  47. package/src/__snapshots__/services/index.ts.snapshot.ts +24 -0
  48. package/src/generateCode.ts +201 -0
  49. package/src/index.ts +3 -0
  50. package/src/plugin.ts +45 -0
  51. package/src/ts-factory/astToString.ts +34 -0
  52. package/src/ts-factory/getClientFactory.ts +207 -0
  53. package/src/ts-factory/getIndexFactory.ts +58 -0
  54. package/src/ts-factory/getServiceFactory.ts +410 -0
  55. package/src/ts-factory/getServiceIndexFactory.ts +104 -0
@@ -0,0 +1,410 @@
1
+ import { ServiceOperation } from '@openapi-qraft/plugin/lib/open-api/getServices';
2
+
3
+ import ts from 'typescript';
4
+
5
+ const SERVICE_OPERATION_QUERY = 'ServiceOperationQuery';
6
+ const SERVICE_OPERATION_MUTATION = 'ServiceOperationMutation';
7
+
8
+ const factory = ts.factory;
9
+
10
+ export type ServiceImportsFactoryOptions = {
11
+ openapiTypesImportPath: string;
12
+ operationGenericsImportPath: string;
13
+ };
14
+
15
+ export const getServiceFactory = (
16
+ service: { typeName: string; variableName: string },
17
+ operations: ServiceOperation[],
18
+ {
19
+ openapiTypesImportPath,
20
+ operationGenericsImportPath,
21
+ }: ServiceImportsFactoryOptions
22
+ ) => {
23
+ return [
24
+ getOpenAPISchemaImportsFactory(openapiTypesImportPath),
25
+ getServiceOperationGenericsPathImportsFactory(
26
+ operationGenericsImportPath,
27
+ operations
28
+ ),
29
+ getServiceInterfaceFactory(service, operations),
30
+ getServiceVariableFactory(service, operations),
31
+ ];
32
+ };
33
+
34
+ const getOpenAPISchemaImportsFactory = (schemaTypesPath: string) => {
35
+ const factory = ts.factory;
36
+
37
+ return factory.createImportDeclaration(
38
+ undefined,
39
+ factory.createImportClause(
40
+ true,
41
+ undefined,
42
+ factory.createNamedImports([
43
+ factory.createImportSpecifier(
44
+ false,
45
+ undefined,
46
+ factory.createIdentifier('paths')
47
+ ),
48
+ ])
49
+ ),
50
+ factory.createStringLiteral(schemaTypesPath)
51
+ );
52
+ };
53
+
54
+ const getServiceOperationGenericsPathImportsFactory = (
55
+ operationGenericsPath: string,
56
+ operations: ServiceOperation[]
57
+ ) => {
58
+ const factory = ts.factory;
59
+
60
+ const queryMethods = ['get', 'head', 'options'] as const; // todo::make it shared
61
+
62
+ return factory.createImportDeclaration(
63
+ undefined,
64
+ factory.createImportClause(
65
+ true,
66
+ undefined,
67
+ factory.createNamedImports(
68
+ [
69
+ operations.some((operation) =>
70
+ queryMethods.some((method) => method === operation.method)
71
+ )
72
+ ? factory.createImportSpecifier(
73
+ false,
74
+ undefined,
75
+ factory.createIdentifier('ServiceOperationQuery')
76
+ )
77
+ : null,
78
+ operations.some(
79
+ (operation) =>
80
+ !queryMethods.some((method) => method === operation.method)
81
+ )
82
+ ? factory.createImportSpecifier(
83
+ false,
84
+ undefined,
85
+ factory.createIdentifier('ServiceOperationMutation')
86
+ )
87
+ : null,
88
+ ].filter((node): node is NonNullable<typeof node> => Boolean(node))
89
+ )
90
+ ),
91
+ factory.createStringLiteral(operationGenericsPath)
92
+ );
93
+ };
94
+
95
+ const getServiceInterfaceFactory = (
96
+ { typeName }: { typeName: string },
97
+ operations: ServiceOperation[]
98
+ ) => {
99
+ return factory.createInterfaceDeclaration(
100
+ [factory.createToken(ts.SyntaxKind.ExportKeyword)],
101
+ factory.createIdentifier(typeName),
102
+ undefined,
103
+ undefined,
104
+ operations.map(getServiceInterfaceOperationFactory)
105
+ );
106
+ };
107
+
108
+ const getServiceInterfaceOperationFactory = (operation: ServiceOperation) => {
109
+ const node = factory.createPropertySignature(
110
+ undefined,
111
+ factory.createIdentifier(operation.name),
112
+ undefined,
113
+ factory.createTypeReferenceNode(
114
+ factory.createIdentifier(
115
+ operation.method === 'get'
116
+ ? SERVICE_OPERATION_QUERY
117
+ : SERVICE_OPERATION_MUTATION
118
+ ),
119
+ [
120
+ getOperationSchemaFactory(operation),
121
+
122
+ operation.method !== 'get' ? getOperationBodyFactory(operation) : null,
123
+
124
+ getOperationResponseFactory(operation, 'success'),
125
+
126
+ getOperationParametersFactory(operation),
127
+
128
+ getOperationResponseFactory(operation, 'errors'),
129
+ ].filter((node): node is NonNullable<typeof node> => Boolean(node))
130
+ )
131
+ );
132
+
133
+ const comment = createMultilineComment(
134
+ [
135
+ operation.deprecated ? '@deprecated' : null,
136
+ operation.summary ? `@summary ${operation.summary}` : null,
137
+ operation.description ? `@description ${operation.description}` : null,
138
+ ].filter((comment): comment is NonNullable<typeof comment> =>
139
+ Boolean(comment)
140
+ )
141
+ );
142
+
143
+ if (comment)
144
+ ts.addSyntheticLeadingComment(
145
+ node,
146
+ ts.SyntaxKind.MultiLineCommentTrivia,
147
+ comment,
148
+ true
149
+ );
150
+
151
+ return node;
152
+ };
153
+
154
+ const getOperationSchemaFactory = (operation: ServiceOperation) => {
155
+ return factory.createTypeLiteralNode(
156
+ [
157
+ factory.createPropertySignature(
158
+ undefined,
159
+ factory.createIdentifier('method'),
160
+ undefined,
161
+ factory.createLiteralTypeNode(
162
+ factory.createStringLiteral(operation.method)
163
+ )
164
+ ),
165
+
166
+ factory.createPropertySignature(
167
+ undefined,
168
+ factory.createIdentifier('url'),
169
+ undefined,
170
+ factory.createLiteralTypeNode(
171
+ factory.createStringLiteral(operation.path)
172
+ )
173
+ ),
174
+
175
+ operation.mediaType
176
+ ? factory.createPropertySignature(
177
+ undefined,
178
+ factory.createIdentifier('mediaType'),
179
+ undefined,
180
+ factory.createLiteralTypeNode(
181
+ factory.createStringLiteral(operation.mediaType)
182
+ )
183
+ )
184
+ : null,
185
+ ].filter((node): node is NonNullable<typeof node> => Boolean(node))
186
+ );
187
+ };
188
+
189
+ const getOperationResponseFactory = (
190
+ operation: ServiceOperation,
191
+ type: 'success' | 'errors'
192
+ ) => {
193
+ if (!operation[type])
194
+ return factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
195
+
196
+ const responses = Object.entries(operation[type]);
197
+
198
+ if (!responses.length)
199
+ return factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
200
+
201
+ return factory.createUnionTypeNode(
202
+ responses.map(([statusCode, mediaType]) => {
203
+ if (!mediaType)
204
+ return factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
205
+
206
+ return factory.createIndexedAccessTypeNode(
207
+ factory.createIndexedAccessTypeNode(
208
+ factory.createIndexedAccessTypeNode(
209
+ factory.createIndexedAccessTypeNode(
210
+ factory.createIndexedAccessTypeNode(
211
+ factory.createIndexedAccessTypeNode(
212
+ factory.createTypeReferenceNode(
213
+ factory.createIdentifier('paths'),
214
+ undefined
215
+ ),
216
+ factory.createLiteralTypeNode(
217
+ factory.createStringLiteral(operation.path)
218
+ )
219
+ ),
220
+ factory.createLiteralTypeNode(
221
+ factory.createStringLiteral(operation.method)
222
+ )
223
+ ),
224
+ factory.createLiteralTypeNode(
225
+ factory.createStringLiteral('responses')
226
+ )
227
+ ),
228
+ factory.createLiteralTypeNode(
229
+ factory.createStringLiteral(statusCode)
230
+ )
231
+ ),
232
+ factory.createLiteralTypeNode(factory.createStringLiteral('content'))
233
+ ),
234
+ factory.createLiteralTypeNode(factory.createStringLiteral(mediaType))
235
+ );
236
+ })
237
+ );
238
+ };
239
+
240
+ const getOperationBodyFactory = (operation: ServiceOperation) => {
241
+ if (!operation.mediaType)
242
+ return factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword);
243
+
244
+ return factory.createIndexedAccessTypeNode(
245
+ factory.createIndexedAccessTypeNode(
246
+ factory.createTypeReferenceNode(factory.createIdentifier('NonNullable'), [
247
+ factory.createIndexedAccessTypeNode(
248
+ factory.createIndexedAccessTypeNode(
249
+ factory.createIndexedAccessTypeNode(
250
+ factory.createTypeReferenceNode(
251
+ factory.createIdentifier('paths'),
252
+ undefined
253
+ ),
254
+ factory.createLiteralTypeNode(
255
+ factory.createStringLiteral(operation.path)
256
+ )
257
+ ),
258
+ factory.createLiteralTypeNode(
259
+ factory.createStringLiteral(operation.method)
260
+ )
261
+ ),
262
+ factory.createLiteralTypeNode(
263
+ factory.createStringLiteral('requestBody')
264
+ )
265
+ ),
266
+ ]),
267
+ // todo::Add optional NonNullable inference, see `POST /entities/{entity_id}/documents`
268
+ factory.createLiteralTypeNode(factory.createStringLiteral('content'))
269
+ ),
270
+ factory.createLiteralTypeNode(
271
+ factory.createStringLiteral(operation.mediaType)
272
+ )
273
+ );
274
+ };
275
+
276
+ const getOperationParametersFactory = (operation: ServiceOperation) => {
277
+ if (!operation.parameters)
278
+ return factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword);
279
+
280
+ return factory.createIndexedAccessTypeNode(
281
+ factory.createIndexedAccessTypeNode(
282
+ factory.createIndexedAccessTypeNode(
283
+ factory.createTypeReferenceNode(
284
+ factory.createIdentifier('paths'),
285
+ undefined
286
+ ),
287
+ factory.createLiteralTypeNode(
288
+ factory.createStringLiteral(operation.path)
289
+ )
290
+ ),
291
+ factory.createLiteralTypeNode(
292
+ factory.createStringLiteral(operation.method)
293
+ )
294
+ ),
295
+ factory.createLiteralTypeNode(factory.createStringLiteral('parameters'))
296
+ );
297
+ };
298
+
299
+ const getServiceVariableFactory = (
300
+ { typeName, variableName }: { typeName: string; variableName: string },
301
+ operations: ServiceOperation[]
302
+ ) => {
303
+ return factory.createVariableStatement(
304
+ [factory.createToken(ts.SyntaxKind.ExportKeyword)],
305
+ factory.createVariableDeclarationList(
306
+ [
307
+ factory.createVariableDeclaration(
308
+ factory.createIdentifier(variableName),
309
+ undefined,
310
+ getServiceVariableTypeFactory({ typeName }),
311
+ factory.createAsExpression(
312
+ factory.createObjectLiteralExpression(
313
+ operations.map(getServiceVariablePropertyFactory),
314
+ true
315
+ ),
316
+ factory.createTypeReferenceNode(
317
+ factory.createIdentifier('const'),
318
+ undefined
319
+ )
320
+ )
321
+ ),
322
+ ],
323
+ ts.NodeFlags.Const
324
+ )
325
+ );
326
+ };
327
+
328
+ const getServiceVariableTypeFactory = ({ typeName }: { typeName: string }) => {
329
+ return factory.createMappedTypeNode(
330
+ undefined,
331
+ factory.createTypeParameterDeclaration(
332
+ undefined,
333
+ factory.createIdentifier('key'),
334
+ factory.createTypeOperatorNode(
335
+ ts.SyntaxKind.KeyOfKeyword,
336
+ factory.createTypeReferenceNode(
337
+ factory.createIdentifier(typeName),
338
+ undefined
339
+ )
340
+ ),
341
+ undefined
342
+ ),
343
+ undefined,
344
+ undefined,
345
+ factory.createTypeReferenceNode(factory.createIdentifier('Pick'), [
346
+ factory.createIndexedAccessTypeNode(
347
+ factory.createTypeReferenceNode(
348
+ factory.createIdentifier(typeName),
349
+ undefined
350
+ ),
351
+ factory.createTypeReferenceNode(
352
+ factory.createIdentifier('key'),
353
+ undefined
354
+ )
355
+ ),
356
+ factory.createLiteralTypeNode(factory.createStringLiteral('schema')),
357
+ ]),
358
+ undefined
359
+ );
360
+ };
361
+
362
+ const getServiceVariablePropertyFactory = (operation: ServiceOperation) => {
363
+ return factory.createPropertyAssignment(
364
+ factory.createIdentifier(operation.name),
365
+ factory.createObjectLiteralExpression(
366
+ [
367
+ factory.createPropertyAssignment(
368
+ factory.createIdentifier('schema'),
369
+ factory.createObjectLiteralExpression(
370
+ [
371
+ factory.createPropertyAssignment(
372
+ factory.createIdentifier('method'),
373
+ factory.createStringLiteral(operation.method)
374
+ ),
375
+ factory.createPropertyAssignment(
376
+ factory.createIdentifier('url'),
377
+ factory.createStringLiteral(operation.path)
378
+ ),
379
+ operation.mediaType
380
+ ? factory.createPropertyAssignment(
381
+ factory.createIdentifier('mediaType'),
382
+ factory.createStringLiteral(operation.mediaType)
383
+ )
384
+ : null,
385
+ ].filter((node): node is NonNullable<typeof node> => Boolean(node)),
386
+ true
387
+ )
388
+ ),
389
+ ],
390
+ true
391
+ )
392
+ );
393
+ };
394
+
395
+ const createMultilineComment = (comment: string[]) => {
396
+ const output = comment.flatMap((line) =>
397
+ line.includes('\n') ? line.split('\n') : line
398
+ );
399
+
400
+ if (output.length) {
401
+ const text =
402
+ output.length === 1
403
+ ? `* ${output.join('\n')} `
404
+ : `*\n * ${output.join('\n * ')}\n `;
405
+
406
+ return text.replace(/\*\//g, '*\\/'); // prevent inner comments from leaking
407
+ }
408
+
409
+ return '';
410
+ };
@@ -0,0 +1,104 @@
1
+ import { Service } from '@openapi-qraft/plugin/lib/open-api/getServices';
2
+
3
+ import ts from 'typescript';
4
+
5
+ type Options = { explicitImportExtensions: boolean };
6
+
7
+ export const getServiceIndexFactory = (
8
+ services: Service[],
9
+ options: Options
10
+ ) => {
11
+ return [
12
+ ...getServicesImportsFactory(services, options),
13
+ getServiceIndexInterfaceFactory(services),
14
+ getServiceIndexVariableFactory(services),
15
+ ];
16
+ };
17
+
18
+ const getServiceIndexInterfaceFactory = (services: Service[]) => {
19
+ const factory = ts.factory;
20
+
21
+ return factory.createTypeAliasDeclaration(
22
+ [factory.createToken(ts.SyntaxKind.ExportKeyword)],
23
+ factory.createIdentifier('Services'),
24
+ undefined,
25
+ factory.createTypeLiteralNode(
26
+ services.map(({ name, typeName }) =>
27
+ factory.createPropertySignature(
28
+ undefined,
29
+ factory.createIdentifier(name),
30
+ undefined,
31
+ factory.createTypeReferenceNode(
32
+ factory.createIdentifier(typeName),
33
+ undefined
34
+ )
35
+ )
36
+ )
37
+ )
38
+ );
39
+ };
40
+
41
+ const getServiceIndexVariableFactory = (services: Service[]) => {
42
+ const factory = ts.factory;
43
+
44
+ return factory.createVariableStatement(
45
+ [factory.createToken(ts.SyntaxKind.ExportKeyword)],
46
+ factory.createVariableDeclarationList(
47
+ [
48
+ factory.createVariableDeclaration(
49
+ factory.createIdentifier('services'),
50
+ undefined,
51
+ undefined,
52
+ factory.createAsExpression(
53
+ factory.createObjectLiteralExpression(
54
+ services.map(({ name, variableName }) =>
55
+ factory.createPropertyAssignment(
56
+ factory.createIdentifier(name),
57
+ factory.createIdentifier(variableName)
58
+ )
59
+ ),
60
+ true
61
+ ),
62
+ factory.createTypeReferenceNode(
63
+ factory.createIdentifier('const'),
64
+ undefined
65
+ )
66
+ )
67
+ ),
68
+ ],
69
+ ts.NodeFlags.Const
70
+ )
71
+ );
72
+ };
73
+
74
+ const getServicesImportsFactory = (
75
+ services: Service[],
76
+ { explicitImportExtensions }: Options
77
+ ) => {
78
+ const factory = ts.factory;
79
+
80
+ return services.map(({ variableName, typeName, fileBaseName }) =>
81
+ factory.createImportDeclaration(
82
+ undefined,
83
+ factory.createImportClause(
84
+ false,
85
+ undefined,
86
+ factory.createNamedImports([
87
+ factory.createImportSpecifier(
88
+ false,
89
+ undefined,
90
+ factory.createIdentifier(typeName)
91
+ ),
92
+ factory.createImportSpecifier(
93
+ false,
94
+ undefined,
95
+ factory.createIdentifier(variableName)
96
+ ),
97
+ ])
98
+ ),
99
+ factory.createStringLiteral(
100
+ `./${fileBaseName}${explicitImportExtensions ? '.js' : ''}`
101
+ )
102
+ )
103
+ );
104
+ };