1
1
import * as ts from 'typescript' ;
2
+ import * as fs from 'fs' ;
3
+ import chalk from 'chalk' ;
2
4
import { camelCase } from 'lodash' ;
3
5
import ApiGenerator , {
4
6
getOperationName ,
5
- supportDeepObjects ,
6
7
getReferenceName ,
7
8
isReference ,
9
+ supportDeepObjects ,
8
10
} from 'oazapfts/lib/codegen/generate' ;
9
- import { OpenAPIV3 } from 'openapi-types' ;
10
11
import { createQuestionToken , keywordType } from 'oazapfts/lib/codegen/tscodegen' ;
12
+ import { OpenAPIV3 } from 'openapi-types' ;
11
13
import { generateReactHooks } from './generators/react-hooks' ;
12
- import { capitalize , getOperationDefinitions , getV3Doc , isQuery } from './utils' ;
13
14
import { GenerationOptions , OperationDefinition } from './types' ;
15
+ import { capitalize , getOperationDefinitions , getV3Doc , isQuery , MESSAGES } from './utils' ;
14
16
15
17
const { factory } = ts ;
16
18
@@ -19,6 +21,9 @@ function defaultIsDataResponse(code: string) {
19
21
return ! Number . isNaN ( parsedCode ) && parsedCode >= 200 && parsedCode < 300 ;
20
22
}
21
23
24
+ let customBaseQueryNode : ts . ImportDeclaration | undefined ;
25
+ let baseQueryFn : string , filePath : string ;
26
+
22
27
export async function generateApi (
23
28
spec : string ,
24
29
{
@@ -60,14 +65,91 @@ export async function generateApi(
60
65
return declaration ;
61
66
}
62
67
63
- return printer . printNode (
68
+ /**
69
+ * --baseQuery handling
70
+ * 1. If baseQuery is specified, we confirm that the file exists
71
+ * 2. If there is a seperator in the path, file presence + named function existence is verified.
72
+ * 3. If there is a not a seperator, file presence + default export existence is verified.
73
+ */
74
+
75
+ function fnExportExists ( path : string , fnName : string ) {
76
+ const fileName = `${ process . cwd ( ) } /${ path } ` ;
77
+
78
+ const sourceFile = ts . createSourceFile (
79
+ fileName ,
80
+ fs . readFileSync ( fileName ) . toString ( ) ,
81
+ ts . ScriptTarget . ES2015 ,
82
+ /*setParentNodes */ true
83
+ ) ;
84
+
85
+ let found = false ;
86
+
87
+ ts . forEachChild ( sourceFile , ( node ) => {
88
+ const text = node . getText ( ) ;
89
+ if ( ts . isExportAssignment ( node ) ) {
90
+ if ( text . includes ( fnName ) ) {
91
+ found = true ;
92
+ }
93
+ } else if ( ts . isVariableStatement ( node ) || ts . isFunctionDeclaration ( node ) || ts . isExportDeclaration ( node ) ) {
94
+ if ( text . includes ( fnName ) && text . includes ( 'export' ) ) {
95
+ found = true ;
96
+ }
97
+ } else if ( ts . isExportAssignment ( node ) ) {
98
+ if ( text . includes ( `export ${ fnName } ` ) ) {
99
+ found = true ;
100
+ }
101
+ }
102
+ } ) ;
103
+
104
+ return found ;
105
+ }
106
+
107
+ // If a baseQuery was specified as an arg, we try to parse and resolve it. If not, fallback to `fetchBaseQuery` or throw when appropriate.
108
+ if ( baseQuery !== 'fetchBaseQuery' ) {
109
+ if ( baseQuery . includes ( ':' ) ) {
110
+ // User specified a named function
111
+ [ filePath , baseQueryFn ] = baseQuery . split ( ':' ) ;
112
+
113
+ if ( ! baseQueryFn || ! fnExportExists ( filePath , baseQueryFn ) ) {
114
+ throw new Error ( MESSAGES . NAMED_EXPORT_MISSING ) ;
115
+ } else if ( ! fs . existsSync ( filePath ) ) {
116
+ throw new Error ( MESSAGES . FILE_NOT_FOUND ) ;
117
+ }
118
+
119
+ customBaseQueryNode = generateImportNode ( filePath , {
120
+ [ baseQueryFn ] : baseQueryFn ,
121
+ } ) ;
122
+ } else {
123
+ filePath = baseQuery ;
124
+ baseQueryFn = 'fetchBaseQuery' ;
125
+
126
+ if ( ! fs . existsSync ( filePath ) ) {
127
+ throw new Error ( MESSAGES . FILE_NOT_FOUND ) ;
128
+ } else if ( ! fnExportExists ( filePath , 'default' ) ) {
129
+ throw new Error ( MESSAGES . DEFAULT_EXPORT_MISSING ) ;
130
+ }
131
+
132
+ console . warn ( chalk `
133
+ {yellow.bold A custom baseQuery was specified without a named function. We're going to import the default as {underline customBaseQuery}}
134
+ ` ) ;
135
+
136
+ baseQueryFn = 'customBaseQuery' ;
137
+
138
+ customBaseQueryNode = generateImportNode ( filePath , {
139
+ default : baseQueryFn ,
140
+ } ) ;
141
+ }
142
+ }
143
+
144
+ const sourceCode = printer . printNode (
64
145
ts . EmitHint . Unspecified ,
65
146
factory . createSourceFile (
66
147
[
67
148
generateImportNode ( '@rtk-incubator/rtk-query' , {
68
149
createApi : 'createApi' ,
69
- fetchBaseQuery : 'fetchBaseQuery' ,
150
+ ... ( baseQuery === ' fetchBaseQuery' ? { fetchBaseQuery : 'fetchBaseQuery' } : { } ) ,
70
151
} ) ,
152
+ ...( customBaseQueryNode ? [ customBaseQueryNode ] : [ ] ) ,
71
153
generateCreateApiCall ( ) ,
72
154
...Object . values ( interfaces ) ,
73
155
...apiGen [ 'aliases' ] ,
@@ -79,6 +161,8 @@ export async function generateApi(
79
161
resultFile
80
162
) ;
81
163
164
+ return sourceCode ;
165
+
82
166
function generateImportNode ( pkg : string , namedImports : Record < string , string > , defaultImportName ?: string ) {
83
167
return factory . createImportDeclaration (
84
168
undefined ,
@@ -87,12 +171,14 @@ export async function generateApi(
87
171
false ,
88
172
defaultImportName !== undefined ? factory . createIdentifier ( defaultImportName ) : undefined ,
89
173
factory . createNamedImports (
90
- Object . entries ( namedImports ) . map ( ( [ propertyName , name ] ) =>
91
- factory . createImportSpecifier (
92
- name === propertyName ? undefined : factory . createIdentifier ( propertyName ) ,
93
- factory . createIdentifier ( name )
174
+ Object . entries ( namedImports )
175
+ . filter ( ( args ) => args [ 1 ] )
176
+ . map ( ( [ propertyName , name ] ) =>
177
+ factory . createImportSpecifier (
178
+ name === propertyName ? undefined : factory . createIdentifier ( propertyName ) ,
179
+ factory . createIdentifier ( name as string )
180
+ )
94
181
)
95
- )
96
182
)
97
183
) ,
98
184
factory . createStringLiteral ( pkg )
@@ -119,7 +205,7 @@ export async function generateApi(
119
205
) ,
120
206
factory . createPropertyAssignment (
121
207
factory . createIdentifier ( 'baseQuery' ) ,
122
- factory . createCallExpression ( factory . createIdentifier ( baseQuery ) , undefined , [
208
+ factory . createCallExpression ( factory . createIdentifier ( baseQueryFn || baseQuery ) , undefined , [
123
209
factory . createObjectLiteralExpression (
124
210
[
125
211
factory . createPropertyAssignment (
@@ -355,17 +441,19 @@ export async function generateApi(
355
441
return factory . createArrowFunction (
356
442
undefined ,
357
443
undefined ,
358
- [
359
- factory . createParameterDeclaration (
360
- undefined ,
361
- undefined ,
362
- undefined ,
363
- rootObject ,
364
- undefined ,
365
- undefined ,
366
- undefined
367
- ) ,
368
- ] ,
444
+ Object . keys ( queryArg ) . length
445
+ ? [
446
+ factory . createParameterDeclaration (
447
+ undefined ,
448
+ undefined ,
449
+ undefined ,
450
+ rootObject ,
451
+ undefined ,
452
+ undefined ,
453
+ undefined
454
+ ) ,
455
+ ]
456
+ : [ ] ,
369
457
undefined ,
370
458
factory . createToken ( ts . SyntaxKind . EqualsGreaterThanToken ) ,
371
459
factory . createParenthesizedExpression (
0 commit comments