1
1
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
2
2
3
3
import * as graphql from "graphql"
4
- import ts from "typescript"
5
4
6
5
import { AppContext } from "./context.js"
7
- import { formatDTS } from "./formatDTS.js"
8
6
import { getCodeFactsForJSTSFileAtPath } from "./serviceFile.codefacts.js"
9
7
import { CodeFacts , ModelResolverFacts , ResolverFuncFact } from "./typeFacts.js"
10
8
import { TypeMapper , typeMapper } from "./typeMap.js"
@@ -29,6 +27,7 @@ export const lookAtServiceFile = async (file: string, context: AppContext) => {
29
27
30
28
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
31
29
const mutationType = gql . getMutationType ( ) !
30
+
32
31
if ( ! mutationType ) throw new Error ( "No mutation type" )
33
32
34
33
const externalMapper = typeMapper ( context , { preferPrismaModels : true } )
@@ -43,13 +42,11 @@ export const lookAtServiceFile = async (file: string, context: AppContext) => {
43
42
const extraSharedFileImportReferences = new Set < { import : string ; name ?: string } > ( )
44
43
45
44
// The file we'll be creating in-memory throughout this fn
46
- // const fileDTS = context.tsProject.createSourceFile(`source/${fileKey}.d.ts`, "", { overwrite: true })
45
+ const fileDTS = context . tsProject . createSourceFile ( `source/${ fileKey } .d.ts` , "" , { overwrite : true } )
47
46
48
47
// Basically if a top level resolver reference Query or Mutation
49
48
const knownSpecialCasesForGraphQL = new Set < string > ( )
50
49
51
- const statements : ts . Statement [ ] = [ ]
52
-
53
50
// Add the root function declarations
54
51
const rootResolvers = fileFacts . maybe_query_mutation ?. resolvers
55
52
if ( rootResolvers )
@@ -61,14 +58,7 @@ export const lookAtServiceFile = async (file: string, context: AppContext) => {
61
58
addDefinitionsForTopLevelResolvers ( parentName , v )
62
59
} else {
63
60
// Add warning about unused resolver
64
- statements . push (
65
- ts . addSyntheticLeadingComment (
66
- ts . factory . createEmptyStatement ( ) ,
67
- ts . SyntaxKind . MultiLineCommentTrivia ,
68
- ` ${ v . name } does not exist on Query or Mutation ` ,
69
- true
70
- )
71
- )
61
+ fileDTS . addStatements ( `\n// ${ v . name } does not exist on Query or Mutation` )
72
62
}
73
63
} )
74
64
@@ -87,9 +77,12 @@ export const lookAtServiceFile = async (file: string, context: AppContext) => {
87
77
const sharedInternalGraphQLObjectsReferenced = returnTypeMapper . getReferencedGraphQLThingsInMapping ( )
88
78
89
79
const aliases = [ ...new Set ( [ ...sharedGraphQLObjectsReferenced . scalars , ...sharedInternalGraphQLObjectsReferenced . scalars ] ) ]
90
- for ( const alias of aliases ) {
91
- statements . push (
92
- ts . factory . createTypeAliasDeclaration ( undefined , alias , undefined , ts . factory . createKeywordTypeNode ( ts . SyntaxKind . AnyKeyword ) )
80
+ if ( aliases . length ) {
81
+ fileDTS . addTypeAliases (
82
+ aliases . map ( ( s ) => ( {
83
+ name : s ,
84
+ type : "any" ,
85
+ } ) )
93
86
)
94
87
}
95
88
@@ -101,99 +94,70 @@ export const lookAtServiceFile = async (file: string, context: AppContext) => {
101
94
] ) ,
102
95
]
103
96
104
- const addImportToStatements = ( importName : string , specifiers : ts . NamedImportBindings ) => {
105
- statements . splice (
106
- 0 ,
107
- 0 ,
108
- ts . factory . createImportDeclaration (
109
- [ ] ,
110
- ts . factory . createImportClause ( true , undefined , specifiers ) ,
111
- ts . factory . createStringLiteral ( importName )
112
- )
113
- )
114
- }
115
-
116
97
const validPrismaObjs = prismases . filter ( ( p ) => prisma . has ( p ) )
117
98
if ( validPrismaObjs . length ) {
118
- addImportToStatements (
119
- "@prisma/client" ,
120
- ts . factory . createNamedImports (
121
- validPrismaObjs . map ( ( p ) =>
122
- ts . factory . createImportSpecifier ( true , ts . factory . createIdentifier ( `P${ p } ` ) , ts . factory . createIdentifier ( p ) )
123
- )
124
- )
125
- )
99
+ fileDTS . addImportDeclaration ( {
100
+ isTypeOnly : true ,
101
+ moduleSpecifier : "@prisma/client" ,
102
+ namedImports : validPrismaObjs . map ( ( p ) => `${ p } as P${ p } ` ) ,
103
+ } )
104
+ }
105
+
106
+ if ( fileDTS . getText ( ) . includes ( "GraphQLResolveInfo" ) ) {
107
+ fileDTS . addImportDeclaration ( {
108
+ isTypeOnly : true ,
109
+ moduleSpecifier : "graphql" ,
110
+ namedImports : [ "GraphQLResolveInfo" ] ,
111
+ } )
126
112
}
127
113
128
- // if (fileDTS.getText().includes("GraphQLResolveInfo")) {
129
- // addImportToStatements(
130
- // "graphql",
131
- // ts.factory.createNamedImports([ts.factory.createImportSpecifier(true, undefined, ts.factory.createIdentifier("GraphQLResolveInfo"))])
132
- // )
133
- // }
134
-
135
- // if (fileDTS.getText().includes("RedwoodGraphQLContext")) {
136
- // addImportToStatements(
137
- // "@redwoodjs/graphql-server/dist/types",
138
- // ts.factory.createNamedImports([
139
- // ts.factory.createImportSpecifier(true, undefined, ts.factory.createIdentifier("RedwoodGraphQLContext")),
140
- // ])
141
- // )
142
- // }
114
+ if ( fileDTS . getText ( ) . includes ( "RedwoodGraphQLContext" ) ) {
115
+ fileDTS . addImportDeclaration ( {
116
+ isTypeOnly : true ,
117
+ moduleSpecifier : "@redwoodjs/graphql-server/dist/types" ,
118
+ namedImports : [ "RedwoodGraphQLContext" ] ,
119
+ } )
120
+ }
143
121
144
122
if ( sharedInternalGraphQLObjectsReferenced . types . length || extraSharedFileImportReferences . size ) {
145
- const path = `./${ settings . sharedInternalFilename . replace ( ".d.ts" , "" ) } `
146
- addImportToStatements (
147
- path ,
148
- ts . factory . createNamedImports ( [
149
- ...sharedInternalGraphQLObjectsReferenced . types . map ( ( t ) =>
150
- ts . factory . createImportSpecifier ( true , undefined , ts . factory . createIdentifier ( `RT${ t } ` ) )
151
- ) ,
152
- ...[ ...extraSharedFileImportReferences . values ( ) ] . map ( ( t ) => {
153
- if ( "name" in t && t . name ) {
154
- return ts . factory . createImportSpecifier ( true , undefined , ts . factory . createIdentifier ( t . name ) )
155
- } else {
156
- return ts . factory . createImportSpecifier ( true , undefined , ts . factory . createIdentifier ( t . import ) )
157
- }
158
- } ) ,
159
- ] )
160
- )
123
+ fileDTS . addImportDeclaration ( {
124
+ isTypeOnly : true ,
125
+ moduleSpecifier : `./${ settings . sharedInternalFilename . replace ( ".d.ts" , "" ) } ` ,
126
+ namedImports : [
127
+ ...sharedInternalGraphQLObjectsReferenced . types . map ( ( t ) => `${ t } as RT${ t } ` ) ,
128
+ ...[ ...extraSharedFileImportReferences . values ( ) ] . map ( ( t ) => ( "name" in t && t . name ? `${ t . import } as ${ t . name } ` : t . import ) ) ,
129
+ ] ,
130
+ } )
161
131
}
162
132
163
133
if ( sharedGraphQLObjectsReferencedTypes . length ) {
164
- addImportToStatements (
165
- `./${ settings . sharedFilename . replace ( ".d.ts" , "" ) } ` ,
166
- ts . factory . createNamedImports (
167
- sharedGraphQLObjectsReferencedTypes . map ( ( t ) => ts . factory . createImportSpecifier ( true , undefined , ts . factory . createIdentifier ( t ) ) )
168
- )
169
- )
170
-
171
- // fileDTS.addImportDeclaration({
172
- // isTypeOnly: true,
173
- // moduleSpecifier: `./${settings.sharedFilename.replace(".d.ts", "")}`,
174
- // namedImports: sharedGraphQLObjectsReferencedTypes,
175
- // })
134
+ fileDTS . addImportDeclaration ( {
135
+ isTypeOnly : true ,
136
+ moduleSpecifier : `./${ settings . sharedFilename . replace ( ".d.ts" , "" ) } ` ,
137
+ namedImports : sharedGraphQLObjectsReferencedTypes ,
138
+ } )
176
139
}
177
140
178
141
serviceFacts . set ( fileKey , thisFact )
179
142
180
143
const dtsFilename = filename . endsWith ( ".ts" ) ? filename . replace ( ".ts" , ".d.ts" ) : filename . replace ( ".js" , ".d.ts" )
181
- const fullPath = context . join ( context . pathSettings . typesFolderRoot , dtsFilename )
144
+ const dtsFilepath = context . join ( context . pathSettings . typesFolderRoot , dtsFilename )
182
145
183
- const sourceFile = ts . factory . createSourceFile ( statements , ts . factory . createToken ( ts . SyntaxKind . EndOfFileToken ) , ts . NodeFlags . None )
184
- const printer = ts . createPrinter ( { } )
185
- const result = printer . printNode ( ts . EmitHint . Unspecified , sourceFile , sourceFile )
146
+ // Some manual formatting tweaks so we align with Redwood's setup more
147
+ const dts = fileDTS
148
+ . getText ( )
149
+ . replace ( `from "graphql";` , `from "graphql";\n` )
150
+ . replace ( `from "@redwoodjs/graphql-server/dist/types";` , `from "@redwoodjs/graphql-server/dist/types";\n` )
186
151
187
- const prior = context . sys . readFile ( fullPath )
188
- if ( prior === result ) return
189
- context . sys . writeFile ( fullPath , result )
190
- return fullPath
152
+ const shouldWriteDTS = ! ! dts . trim ( ) . length
153
+ if ( ! shouldWriteDTS ) return
191
154
192
- // Some manual formatting tweaks so we align with Redwood's setup more
193
- // const dts = fileDTS
194
- // .getText()
195
- // .replace(`from "graphql";`, `from "graphql";\n`)
196
- // .replace(`from "@redwoodjs/graphql-server/dist/types";`, `from "@redwoodjs/graphql-server/dist/types";\n`)
155
+ // Don't make a file write if the content is the same
156
+ const priorContent = context . sys . readFile ( dtsFilename )
157
+ if ( priorContent === dts ) return
158
+
159
+ context . sys . writeFile ( dtsFilepath , dts )
160
+ return dtsFilepath
197
161
198
162
function addDefinitionsForTopLevelResolvers ( parentName : string , config : ResolverFuncFact ) {
199
163
const { name } = config
@@ -202,14 +166,17 @@ export const lookAtServiceFile = async (file: string, context: AppContext) => {
202
166
field = mutationType . getFields ( ) [ name ]
203
167
}
204
168
205
- const resolverName = `${ capitalizeFirstLetter ( config . name ) } Resolver`
206
- const comment = field . astNode
207
- ? `SDL: ${ graphql . print ( field . astNode ) } `
208
- : `@deprecated: Could not find this field in the schema for Mutation or Query`
169
+ const interfaceDeclaration = fileDTS . addInterface ( {
170
+ name : `${ capitalizeFirstLetter ( config . name ) } Resolver` ,
171
+ isExported : true ,
172
+ docs : field . astNode
173
+ ? [ "SDL: " + graphql . print ( field . astNode ) ]
174
+ : [ "@deprecated: Could not find this field in the schema for Mutation or Query" ] ,
175
+ } )
209
176
210
177
const args = createAndReferOrInlineArgsForField ( field , {
211
- name : resolverName ,
212
- file : fileDTS ,
178
+ name : interfaceDeclaration . getName ( ) ,
179
+ file : { } as any ,
213
180
mapper : externalMapper . map ,
214
181
} )
215
182
@@ -220,40 +187,17 @@ export const lookAtServiceFile = async (file: string, context: AppContext) => {
220
187
const qForInfos = config . infoParamType === "just_root_destructured" ? "?" : ""
221
188
const returnType = returnTypeForResolver ( returnTypeMapper , field , config )
222
189
223
- const interfaceDec = ts . factory . createInterfaceDeclaration (
224
- [ ts . factory . createModifier ( ts . SyntaxKind . ExportKeyword ) ] ,
225
- ts . factory . createIdentifier ( `${ capitalizeFirstLetter ( config . name ) } Resolver` ) ,
226
- undefined ,
227
- undefined ,
228
- [
229
- // This is the default args for a resolver
230
- ts . factory . createCallSignature (
231
- undefined ,
232
- [
233
- ts . factory . createParameterDeclaration (
234
- undefined ,
235
- undefined ,
236
- "args" ,
237
- undefined ,
238
- ts . factory . createTypeReferenceNode ( argsParam , undefined )
239
- ) ,
240
- ts . factory . createParameterDeclaration (
241
- [ ] ,
242
- undefined ,
243
- "obj" ,
244
- config . funcArgCount < 2 ? ts . factory . createToken ( ts . SyntaxKind . QuestionToken ) : undefined ,
245
- ts . factory . createTypeReferenceNode (
246
- `{ root: ${ parentName } , context${ qForInfos } : RedwoodGraphQLContext, info${ qForInfos } : GraphQLResolveInfo }`
247
- )
248
- ) ,
249
- ] ,
250
-
251
- ts . factory . createTypeReferenceNode ( returnType , undefined )
252
- ) ,
253
- ]
254
- )
255
-
256
- statements . push ( ts . addSyntheticLeadingComment ( interfaceDec , ts . SyntaxKind . SingleLineCommentTrivia , comment , true ) )
190
+ interfaceDeclaration . addCallSignature ( {
191
+ parameters : [
192
+ { name : "args" , type : argsParam , hasQuestionToken : config . funcArgCount < 1 } ,
193
+ {
194
+ name : "obj" ,
195
+ type : `{ root: ${ parentName } , context${ qForInfos } : RedwoodGraphQLContext, info${ qForInfos } : GraphQLResolveInfo }` ,
196
+ hasQuestionToken : config . funcArgCount < 2 ,
197
+ } ,
198
+ ] ,
199
+ returnType,
200
+ } )
257
201
}
258
202
259
203
/** Ideally, we want to be able to write the type for just the object */
0 commit comments