react-query-lightbase-codegen 1.6.3 → 2.0.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 (52) hide show
  1. package/dist/config/loadConfig.d.ts +2 -0
  2. package/dist/config/loadConfig.js +24 -0
  3. package/dist/generator/clientGenerator.d.ts +13 -0
  4. package/dist/generator/clientGenerator.js +199 -0
  5. package/dist/generator/instanceGenerator.d.ts +1 -0
  6. package/dist/generator/instanceGenerator.js +21 -0
  7. package/dist/generator/reactQueryGenerator.d.ts +2 -0
  8. package/dist/generator/reactQueryGenerator.js +82 -0
  9. package/dist/generator/schemaGenerator.d.ts +5 -0
  10. package/dist/generator/schemaGenerator.js +116 -0
  11. package/dist/index.d.ts +5 -3
  12. package/dist/index.js +106 -4
  13. package/dist/types/config.d.ts +11 -0
  14. package/dist/types/config.js +2 -0
  15. package/dist/types.d.ts +5 -0
  16. package/dist/types.js +2 -0
  17. package/dist/utils.d.ts +31 -20
  18. package/dist/utils.js +57 -179
  19. package/package.json +54 -82
  20. package/readme.md +94 -0
  21. package/src/config/loadConfig.ts +25 -0
  22. package/src/generator/clientGenerator.ts +234 -0
  23. package/src/generator/instanceGenerator.ts +20 -0
  24. package/src/generator/reactQueryGenerator.ts +92 -0
  25. package/src/generator/schemaGenerator.ts +139 -0
  26. package/src/index.ts +78 -3
  27. package/src/types/config.ts +12 -0
  28. package/src/types.ts +5 -0
  29. package/src/utils.ts +56 -213
  30. package/README.md +0 -77
  31. package/dist/convertSwaggerFile.d.ts +0 -5
  32. package/dist/convertSwaggerFile.js +0 -26
  33. package/dist/convertSwaggerFile.js.map +0 -1
  34. package/dist/generateHooks.d.ts +0 -18
  35. package/dist/generateHooks.js +0 -444
  36. package/dist/generateHooks.js.map +0 -1
  37. package/dist/generateImports.d.ts +0 -6
  38. package/dist/generateImports.js +0 -21
  39. package/dist/generateImports.js.map +0 -1
  40. package/dist/generateSchemas.d.ts +0 -7
  41. package/dist/generateSchemas.js +0 -100
  42. package/dist/generateSchemas.js.map +0 -1
  43. package/dist/importSpecs.d.ts +0 -10
  44. package/dist/importSpecs.js +0 -127
  45. package/dist/importSpecs.js.map +0 -1
  46. package/dist/index.js.map +0 -1
  47. package/dist/utils.js.map +0 -1
  48. package/src/convertSwaggerFile.ts +0 -25
  49. package/src/generateHooks.ts +0 -538
  50. package/src/generateImports.ts +0 -32
  51. package/src/generateSchemas.ts +0 -117
  52. package/src/importSpecs.ts +0 -168
package/src/utils.ts CHANGED
@@ -1,213 +1,56 @@
1
- import lodash from 'lodash';
2
- const { uniq, isEmpty } = lodash;
3
- import pasCase from 'case';
4
- import chalk from 'chalk';
5
-
6
- const { pascal } = pasCase;
7
-
8
- import type { ReferenceObject, RequestBodyObject, ResponseObject, SchemaObject } from 'openapi3-ts';
9
- import { imports } from './generateHooks.js';
10
-
11
- export const getDocs = (data: ReferenceObject | { description?: string }) =>
12
- isReference(data) ? '' : formatDescription(data.description);
13
- /**
14
- * Discriminator helper for `ReferenceObject`
15
- */
16
- export const isReference = (property: any): property is ReferenceObject => {
17
- return Boolean(property.$ref);
18
- };
19
-
20
- /**
21
- * Return the typescript equivalent of open-api data type
22
- */
23
- export const getScalar = (item: SchemaObject) => {
24
- const nullable = item.nullable ? ' | null' : '';
25
-
26
- switch (item.type) {
27
- case 'number':
28
- case 'integer':
29
- return 'number' + nullable;
30
-
31
- case 'boolean':
32
- return 'boolean' + nullable;
33
-
34
- case 'array':
35
- return getArray(item) + nullable;
36
-
37
- case 'string':
38
- if (item.format === 'binary') {
39
- return 'string | { name?: string; type?: string; uri: string }' + nullable;
40
- }
41
- if (item.enum) {
42
- return `"${item.enum.join(`" | "`)}"` + nullable;
43
- }
44
- return 'string' + nullable;
45
-
46
- case 'object':
47
- return getObject(item) + nullable;
48
-
49
- default:
50
- return getObject(item) + nullable;
51
- }
52
- };
53
-
54
- /**
55
- * Return the output type from the $ref
56
- */
57
- const getRef = ($ref: ReferenceObject['$ref']) => {
58
- if ($ref.startsWith('#/components/schemas')) {
59
- return pascal($ref.replace('#/components/schemas/', ''));
60
- } else if ($ref.startsWith('#/components/responses')) {
61
- return pascal($ref.replace('#/components/responses/', '')) + 'Response';
62
- } else if ($ref.startsWith('#/components/parameters')) {
63
- return pascal($ref.replace('#/components/parameters/', '')) + 'Parameter';
64
- } else if ($ref.startsWith('#/components/requestBodies')) {
65
- return pascal($ref.replace('#/components/requestBodies/', '')) + 'RequestBody';
66
- } else {
67
- throw new Error('This library only resolve $ref that are include into `#/components/*` for now');
68
- }
69
- };
70
-
71
- /**
72
- * Return the output type from an array
73
- */
74
- const getArray = (item: SchemaObject): string | undefined => {
75
- if (item.items) {
76
- if (!isReference(item.items) && (item.items.oneOf || item.items.allOf || item.items.enum)) {
77
- return `(${resolveValue(item.items)})[]`;
78
- } else {
79
- return `${resolveValue(item.items)}[]`;
80
- }
81
- }
82
- console.log(chalk.red(`Skipped(${item.title}): All arrays must have an 'items' key define`));
83
- return 'unknown[]';
84
- };
85
-
86
- /**
87
- * Return the output type from an object
88
- */
89
- const getObject = (item: SchemaObject): string => {
90
- if (isReference(item)) {
91
- return getRef(item.$ref);
92
- }
93
-
94
- if (item.allOf) {
95
- return item.allOf.map(resolveValue).join(' & ');
96
- }
97
-
98
- if (item.oneOf) {
99
- return item.oneOf.map(resolveValue).join(' | ');
100
- }
101
-
102
- if (item.anyOf) {
103
- return item.anyOf.map(resolveValue).join(' | ');
104
- }
105
-
106
- if (!item.type && !item.properties && !item.additionalProperties) {
107
- return '{}';
108
- }
109
-
110
- // Free form object (https://swagger.io/docs/specification/data-models/data-types/#free-form)
111
- if (
112
- item.type === 'object' &&
113
- !item.properties &&
114
- (!item.additionalProperties || item.additionalProperties === true || isEmpty(item.additionalProperties))
115
- ) {
116
- return '{[key: string]: any}';
117
- }
118
-
119
- const IdentifierRegexp = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
120
- // Consolidation of item.properties & item.additionalProperties
121
- let output = '{';
122
- if (item.properties) {
123
- output += Object.entries(item.properties)
124
- .map(([key, prop]: [string, ReferenceObject | SchemaObject]) => {
125
- const doc = getDocs(prop);
126
- const isRequired = (item.required || []).includes(key);
127
- const processedKey = IdentifierRegexp.test(key) ? key : `"${key}"`;
128
- return `${doc}\n${processedKey}${isRequired ? '' : '?'}: ${resolveValue(prop)}`;
129
- })
130
- .join('');
131
- }
132
-
133
- if (item.additionalProperties) {
134
- if (item.properties) {
135
- output += '\n';
136
- }
137
- output += `} & { [key: string]: ${
138
- item.additionalProperties === true ? 'any' : resolveValue(item.additionalProperties)
139
- }`;
140
- }
141
-
142
- if (item.properties || item.additionalProperties) {
143
- if (output === '{\n') {
144
- return '{}';
145
- }
146
- return output + '\n}';
147
- }
148
-
149
- return item.type === 'object' ? '{[key: string]: any}' : 'any';
150
- };
151
-
152
- /**
153
- * Resolve the value of a schema object to a proper type definition.
154
- */
155
- export const resolveValue = (schema: SchemaObject) => {
156
- if (isReference(schema)) {
157
- const ref = getRef(schema.$ref);
158
- imports?.push(ref);
159
- return ref;
160
- }
161
- return getScalar(schema);
162
- };
163
-
164
- /**
165
- * Format a description to code documentation.
166
- */
167
- export const formatDescription = (description?: string) => {
168
- if (!description) {
169
- return '';
170
- }
171
- return `\n/**\n${description
172
- .split('\n')
173
- .map((i) => `* ${i}`)
174
- .join('\n')}\n */`;
175
- };
176
-
177
- /**
178
- * Extract responses / request types from open-api specs
179
- */
180
- export const getResReqTypes = (
181
- responsesOrRequests: Array<[string, ResponseObject | ReferenceObject | RequestBodyObject]>
182
- ) => {
183
- return uniq(
184
- responsesOrRequests.map(([_, res]) => {
185
- if (!res) {
186
- return;
187
- }
188
-
189
- if (isReference(res)) {
190
- const ref = getRef(res.$ref);
191
- imports.push(ref);
192
- return ref;
193
- }
194
-
195
- if (res.content) {
196
- for (const contentType of Object.keys(res.content)) {
197
- if (
198
- contentType.startsWith('application/json') ||
199
- contentType.startsWith('application/ld+json') ||
200
- contentType.startsWith('application/octet-stream') ||
201
- contentType.startsWith('multipart/form-data')
202
- ) {
203
- const schema = res.content[contentType].schema!;
204
- return resolveValue(schema);
205
- }
206
- }
207
- return;
208
- }
209
-
210
- return;
211
- })
212
- ).join(' | ');
213
- };
1
+ import type { OpenAPIV3 } from "openapi-types";
2
+
3
+ export function camelCase(str: string): string {
4
+ return str
5
+ .toLowerCase()
6
+ .replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase())
7
+ .replace(/^[A-Z]/, (c) => c.toLowerCase());
8
+ }
9
+
10
+ export function pascalCase(str: string): string {
11
+ return str
12
+ .toLowerCase()
13
+ .replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase())
14
+ .replace(/^[a-z]/, (c) => c.toUpperCase());
15
+ }
16
+
17
+ /**
18
+ * Sanitizes a property name to ensure it's a valid JavaScript identifier.
19
+ * If the name is already a valid identifier (starts with letter/underscore/$ and contains only letters/numbers/underscore/$),
20
+ * returns it as-is. Otherwise wraps it in quotes to make it a valid property accessor.
21
+ *
22
+ * For example:
23
+ * - sanitizePropertyName("validName") => "validName"
24
+ * - sanitizePropertyName("invalid-name") => "'invalid-name'"
25
+ * - sanitizePropertyName("123invalid") => "'123invalid'"
26
+ *
27
+ * @param name The property name to sanitize
28
+ * @returns The sanitized property name, quoted if needed
29
+ */
30
+ export function sanitizePropertyName(name: string): string {
31
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `'${name}'`;
32
+ }
33
+
34
+ /**
35
+ * Sanitizes a type name to ensure it's a valid TypeScript type identifier.
36
+ * Replaces any characters that aren't alphanumeric or underscore with an underscore.
37
+ *
38
+ * For example:
39
+ * - sanitizeTypeName("ValidType") => "ValidType"
40
+ * - sanitizeTypeName("invalid-type") => "invalid_type"
41
+ * - sanitizeTypeName("type.name") => "type_name"
42
+ * - sanitizeTypeName("type/name") => "type_name"
43
+ *
44
+ * This is used to convert operation IDs and response names from the OpenAPI spec
45
+ * into valid TypeScript type names.
46
+ *
47
+ * @param name The type name to sanitize
48
+ * @returns The sanitized type name with invalid characters replaced by underscores
49
+ */
50
+ export function sanitizeTypeName(name: string): string {
51
+ return name.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+$/, "");
52
+ }
53
+
54
+ export function specTitle(spec: OpenAPIV3.Document): string {
55
+ return camelCase(spec.info.title.toLowerCase().replace(/\s+/g, "-"));
56
+ }
package/README.md DELETED
@@ -1,77 +0,0 @@
1
- # React Query Code Generation
2
-
3
- Generate fully typed react query hooks from OpenAPI specifications.
4
-
5
- - GET requests will automatically generate `useQuery` hooks together with helper functions
6
- - getQueryState
7
- - getQueryData
8
- - prefetch
9
- - cancelQueries
10
- - invalidate
11
- - refetchStale
12
-
13
- - Override default generation forcing query, mutation or infiniteQuery output
14
-
15
- ## Installation
16
-
17
- You can install react-query-lightbase-codegen with NPM or Yarn.
18
-
19
- Using NPM:
20
-
21
- ```bash
22
- $ npm i -D react-query-lightbase-codegen
23
- ```
24
-
25
- Using Yarn:
26
-
27
- ```
28
- $ yarn add -D react-query-lightbase-codegen
29
- ```
30
-
31
- ## Configuration
32
-
33
- create a generateQueries.mjs file in project root folder
34
-
35
- ```javascript
36
- // generateQueries.mjs
37
- import { importSpecs } from 'react-query-lightbase-codegen';
38
-
39
- importSpecs({
40
- // folder location of the openapi/swagger documents (yaml or JSON)
41
- sourceDirectory: './specs',
42
- // export folder for hooks and schema code generated files
43
- exportDirectory: './src/generated',
44
- // api client - as named export labelled 'api'
45
- apiDirectory: './src/api',
46
- // React query client directory - names export 'queryClient'
47
- queryClientDir: './src/api',
48
- });
49
- ```
50
-
51
- ## Code generation
52
-
53
- To generate the code generated scheme and react query hooks run the above script
54
-
55
- ```bash
56
- node scripts/generateQueries.mjs
57
- ```
58
-
59
- ## Configuration Options
60
-
61
- ```javascript
62
- // generateQueries.mjs
63
- import { importSpecs } from 'react-query-lightbase-codegen';
64
-
65
- importSpecs({
66
- ...
67
- // Filter out any headers from individual queries (these might be applied globally in the axios instance)
68
- headerFilters: ['X-Session-Token'],
69
- overrides: {
70
- // operationId listed in the openApi spec
71
- findPetsByStatus: {
72
- // Override the default query code generation type ('query' | 'mutation' | 'infiniteQuery')
73
- type: 'query',
74
- },
75
- },
76
- });
77
- ```
@@ -1,5 +0,0 @@
1
- import { OpenAPIObject } from 'openapi3-ts';
2
- /**
3
- * Import and parse the openapi spec from a yaml/json
4
- */
5
- export declare const convertSwaggerFile: (data: string, extension: 'yaml' | 'json') => Promise<OpenAPIObject>;
@@ -1,26 +0,0 @@
1
- import swagger2openapi from 'swagger2openapi';
2
- import yaml from 'js-yaml';
3
- /**
4
- * Import and parse the openapi spec from a yaml/json
5
- */
6
- export const convertSwaggerFile = (data, extension) => {
7
- const schema = extension === 'yaml' ? yaml.load(data) : JSON.parse(data);
8
- return new Promise((resolve, reject) => {
9
- if (!schema.openapi || !schema.openapi.startsWith('3.')) {
10
- swagger2openapi.convertObj(schema, {}, (err, convertedObj) => {
11
- if (err) {
12
- reject(err);
13
- }
14
- else {
15
- // @ts-ignore
16
- convertedObj.openapi.basePath = convertedObj.original.basePath;
17
- resolve(convertedObj.openapi);
18
- }
19
- });
20
- }
21
- else {
22
- resolve(schema);
23
- }
24
- });
25
- };
26
- //# sourceMappingURL=convertSwaggerFile.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"convertSwaggerFile.js","sourceRoot":"","sources":["../src/convertSwaggerFile.ts"],"names":[],"mappings":"AACA,OAAO,eAAe,MAAM,iBAAiB,CAAC;AAC9C,OAAO,IAAI,MAAM,SAAS,CAAC;AAE3B;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAY,EAAE,SAA0B,EAA0B,EAAE;IACrG,MAAM,MAAM,GAAG,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACzE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACxD,eAAe,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE;gBAC3D,IAAI,GAAG,EAAE,CAAC;oBACR,MAAM,CAAC,GAAG,CAAC,CAAC;gBACd,CAAC;qBAAM,CAAC;oBACN,aAAa;oBACb,YAAY,CAAC,OAAO,CAAC,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC;oBAC/D,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
@@ -1,18 +0,0 @@
1
- import { ComponentsObject, OperationObject, ParameterObject, ReferenceObject } from 'openapi3-ts';
2
- export declare let imports: string[];
3
- /**
4
- * Generate a react-query component from openapi operation specs
5
- */
6
- export declare const createHook: ({ operation, verb, route, operationIds, parameters, schemasComponents, headerFilters, }: {
7
- operation: OperationObject;
8
- verb: string;
9
- route: string;
10
- operationIds: string[];
11
- parameters: (ReferenceObject | ParameterObject)[] | undefined;
12
- schemasComponents?: ComponentsObject | undefined;
13
- headerFilters?: string[] | undefined;
14
- }) => {
15
- implementation: string;
16
- imports: string[];
17
- queryImports: ("mutation" | "query" | "infiniteQuery")[];
18
- };