Skip to content

Commit b8cc8a3

Browse files
committed
More
1 parent 918bafe commit b8cc8a3

File tree

6 files changed

+477
-179
lines changed

6 files changed

+477
-179
lines changed

src/formatDTS.ts

Lines changed: 0 additions & 19 deletions
This file was deleted.

src/serviceFile.ts

Lines changed: 76 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
22

33
import * as graphql from "graphql"
4-
import ts from "typescript"
54

65
import { AppContext } from "./context.js"
7-
import { formatDTS } from "./formatDTS.js"
86
import { getCodeFactsForJSTSFileAtPath } from "./serviceFile.codefacts.js"
97
import { CodeFacts, ModelResolverFacts, ResolverFuncFact } from "./typeFacts.js"
108
import { TypeMapper, typeMapper } from "./typeMap.js"
@@ -29,6 +27,7 @@ export const lookAtServiceFile = async (file: string, context: AppContext) => {
2927

3028
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
3129
const mutationType = gql.getMutationType()!
30+
3231
if (!mutationType) throw new Error("No mutation type")
3332

3433
const externalMapper = typeMapper(context, { preferPrismaModels: true })
@@ -43,13 +42,11 @@ export const lookAtServiceFile = async (file: string, context: AppContext) => {
4342
const extraSharedFileImportReferences = new Set<{ import: string; name?: string }>()
4443

4544
// 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 })
4746

4847
// Basically if a top level resolver reference Query or Mutation
4948
const knownSpecialCasesForGraphQL = new Set<string>()
5049

51-
const statements: ts.Statement[] = []
52-
5350
// Add the root function declarations
5451
const rootResolvers = fileFacts.maybe_query_mutation?.resolvers
5552
if (rootResolvers)
@@ -61,14 +58,7 @@ export const lookAtServiceFile = async (file: string, context: AppContext) => {
6158
addDefinitionsForTopLevelResolvers(parentName, v)
6259
} else {
6360
// 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`)
7262
}
7363
})
7464

@@ -87,9 +77,12 @@ export const lookAtServiceFile = async (file: string, context: AppContext) => {
8777
const sharedInternalGraphQLObjectsReferenced = returnTypeMapper.getReferencedGraphQLThingsInMapping()
8878

8979
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+
}))
9386
)
9487
}
9588

@@ -101,99 +94,70 @@ export const lookAtServiceFile = async (file: string, context: AppContext) => {
10194
]),
10295
]
10396

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-
11697
const validPrismaObjs = prismases.filter((p) => prisma.has(p))
11798
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+
})
126112
}
127113

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+
}
143121

144122
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+
})
161131
}
162132

163133
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+
})
176139
}
177140

178141
serviceFacts.set(fileKey, thisFact)
179142

180143
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)
182145

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`)
186151

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
191154

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
197161

198162
function addDefinitionsForTopLevelResolvers(parentName: string, config: ResolverFuncFact) {
199163
const { name } = config
@@ -202,14 +166,17 @@ export const lookAtServiceFile = async (file: string, context: AppContext) => {
202166
field = mutationType.getFields()[name]
203167
}
204168

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+
})
209176

210177
const args = createAndReferOrInlineArgsForField(field, {
211-
name: resolverName,
212-
file: fileDTS,
178+
name: interfaceDeclaration.getName(),
179+
file: {} as any,
213180
mapper: externalMapper.map,
214181
})
215182

@@ -220,40 +187,17 @@ export const lookAtServiceFile = async (file: string, context: AppContext) => {
220187
const qForInfos = config.infoParamType === "just_root_destructured" ? "?" : ""
221188
const returnType = returnTypeForResolver(returnTypeMapper, field, config)
222189

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+
})
257201
}
258202

259203
/** Ideally, we want to be able to write the type for just the object */

0 commit comments

Comments
 (0)