Skip to content

Commit 1e1d659

Browse files
heiskrCopilot
andauthored
Remove any types from GraphQL lib and schema helpers (#61493)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 62e5b7d commit 1e1d659

6 files changed

Lines changed: 94 additions & 99 deletions

File tree

eslint.config.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,6 @@ export default [
248248
'src/frame/lib/page-data.ts',
249249
'src/frame/tests/page.ts',
250250
'src/frame/tests/server.ts',
251-
'src/graphql/lib/index.ts',
252-
'src/graphql/pages/reference.tsx',
253-
'src/graphql/scripts/utils/process-schemas.ts',
254-
'src/graphql/scripts/utils/schema-helpers.ts',
255-
'src/graphql/tests/validate-schema.ts',
256251
'src/landings/components/CookBookFilter.tsx',
257252
'src/languages/lib/correct-translation-content.ts',
258253
'src/languages/lib/render-with-fallback.ts',

src/graphql/lib/index.ts

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,40 @@ import {
22
readCompressedJsonFileFallbackLazily,
33
readCompressedJsonFileFallback,
44
} from '@/frame/lib/read-json-file'
5-
import { getAutomatedPageMiniTocItems } from '@/frame/lib/get-mini-toc-items'
5+
import { getAutomatedPageMiniTocItems, type MiniTocItem } from '@/frame/lib/get-mini-toc-items'
66
import languages from '@/languages/lib/languages-server'
77
import { allVersions } from '@/versions/lib/all-versions'
8+
import type {
9+
GraphqlT,
10+
PreviewT,
11+
ChangelogItemT,
12+
BreakingChangesT,
13+
} from '@/graphql/components/types'
814
import { ALL_KIND_KEYS, CATEGORIES, isValidCategory, type SchemaKindKey } from './categories'
915

10-
interface GraphqlContext {
16+
// GraphqlContext describes the per-request context object that getMiniToc and
17+
// getGraphqlSchema read language/version from.
18+
export interface GraphqlContext {
1119
currentLanguage: string
1220
currentVersion: string
13-
[key: string]: any
21+
[key: string]: unknown
1422
}
1523

24+
// The GraphQL schema JSON is keyed by member type (e.g. "queries", "objects",
25+
// "enums"), each holding a list of schema members.
26+
type GraphqlSchemaData = Record<string, GraphqlT[]>
27+
1628
export const GRAPHQL_DATA_DIR = 'src/graphql/data'
1729
/* ADD LANGUAGE KEY */
18-
const previews = new Map<string, any>()
19-
const upcomingChanges = new Map<string, any>()
20-
const changelog = new Map<string, any>()
30+
const previews = new Map<string, PreviewT[]>()
31+
const upcomingChanges = new Map<string, BreakingChangesT>()
32+
const changelog = new Map<string, ChangelogItemT[]>()
33+
const changelogMiniTocs = new Map<string, MiniTocItem[]>()
2134
// Per-category schema files. Key: `${graphqlVersion}:${category}` → bucket.
22-
const graphqlCategorySchemas = new Map<string, any>()
35+
const graphqlCategorySchemas = new Map<string, GraphqlSchemaData>()
2336
// All objects across categories (for interface implementer lookup).
24-
const allObjectsByVersion = new Map<string, any[]>()
25-
const miniTocs = new Map<string, Map<string, Map<string, any[]>>>()
37+
const allObjectsByVersion = new Map<string, GraphqlT[]>()
38+
const miniTocs = new Map<string, Map<string, Map<string, MiniTocItem[]>>>()
2639

2740
for (const language of Object.keys(languages)) {
2841
miniTocs.set(language, new Map())
@@ -31,34 +44,34 @@ for (const language of Object.keys(languages)) {
3144
// Returns the per-category schema bucket `{queries, mutations, ...}` for a
3245
// given category slug (e.g. 'repos', 'issues'). Throws via the loader if the
3346
// category slug is not valid for this version.
34-
export function getGraphqlSchema(version: string, category: string): any {
47+
export function getGraphqlSchema(version: string, category: string): GraphqlSchemaData {
3548
if (!isValidCategory(category)) {
3649
throw new Error(`Invalid GraphQL category: ${category}`)
3750
}
3851
const graphqlVersion: string = getGraphqlVersion(version)
3952
return getGraphqlSchemaByCategory(graphqlVersion, category)
4053
}
4154

42-
function getGraphqlSchemaByCategory(graphqlVersion: string, category: string): any {
55+
function getGraphqlSchemaByCategory(graphqlVersion: string, category: string): GraphqlSchemaData {
4356
const key = `${graphqlVersion}:${category}`
4457
if (!graphqlCategorySchemas.has(key)) {
4558
graphqlCategorySchemas.set(
4659
key,
4760
readCompressedJsonFileFallback(
4861
`${GRAPHQL_DATA_DIR}/${graphqlVersion}/schema-${category}.json`,
49-
),
62+
) as GraphqlSchemaData,
5063
)
5164
}
52-
return graphqlCategorySchemas.get(key)
65+
return graphqlCategorySchemas.get(key)!
5366
}
5467

5568
// Returns all object-kind items across every category for the given version.
5669
// Used by the interface renderer to list implementers regardless of which
5770
// category page is being rendered.
58-
export function getAllGraphqlObjects(version: string): any[] {
71+
export function getAllGraphqlObjects(version: string): GraphqlT[] {
5972
const graphqlVersion: string = getGraphqlVersion(version)
6073
if (!allObjectsByVersion.has(graphqlVersion)) {
61-
const all: any[] = []
74+
const all: GraphqlT[] = []
6275
for (const category of CATEGORIES) {
6376
const bucket = getGraphqlSchemaByCategory(graphqlVersion, category)
6477
if (bucket?.objects) all.push(...bucket.objects)
@@ -73,65 +86,60 @@ export function getKindOrder(): SchemaKindKey[] {
7386
return ALL_KIND_KEYS
7487
}
7588

76-
// Using any for return type as the changelog structure is dynamically loaded from JSON
77-
export function getGraphqlChangelog(version: string): any {
89+
export function getGraphqlChangelog(version: string): ChangelogItemT[] {
7890
const graphqlVersion: string = getGraphqlVersion(version)
7991
if (!changelog.has(graphqlVersion)) {
8092
changelog.set(
8193
graphqlVersion,
8294
readCompressedJsonFileFallbackLazily(
8395
`${GRAPHQL_DATA_DIR}/${graphqlVersion}/changelog.json`,
84-
)(),
96+
)() as ChangelogItemT[],
8597
)
8698
}
8799

88-
return changelog.get(graphqlVersion)
100+
return changelog.get(graphqlVersion)!
89101
}
90102

91103
/**
92104
* Return changelog entries filtered by year.
93105
*/
94-
export function getGraphqlChangelogByYear(version: string, year: number): any[] {
95-
const all = getGraphqlChangelog(version) as Array<{ date: string }>
106+
export function getGraphqlChangelogByYear(version: string, year: number): ChangelogItemT[] {
107+
const all = getGraphqlChangelog(version)
96108
return all.filter((entry) => entry.date.startsWith(String(year)))
97109
}
98110

99111
/**
100112
* Return the distinct years present in the changelog, sorted descending (newest first).
101113
*/
102114
export function getGraphqlChangelogYears(version: string): number[] {
103-
const all = getGraphqlChangelog(version) as Array<{ date: string }>
115+
const all = getGraphqlChangelog(version)
104116
const years = new Set<number>()
105117
for (const entry of all) {
106118
years.add(Number(entry.date.slice(0, 4)))
107119
}
108120
return [...years].sort((a, b) => b - a)
109121
}
110122

111-
// Using any for return type as the breaking changes structure is dynamically loaded from JSON
112-
export function getGraphqlBreakingChanges(version: string): any {
123+
export function getGraphqlBreakingChanges(version: string): BreakingChangesT {
113124
const graphqlVersion: string = getGraphqlVersion(version)
114125
if (!upcomingChanges.has(graphqlVersion)) {
115-
// Using any as the JSON structure is not typed
116-
const data: any = readCompressedJsonFileFallbackLazily(
126+
const data = readCompressedJsonFileFallbackLazily(
117127
`${GRAPHQL_DATA_DIR}/${graphqlVersion}/upcoming-changes.json`,
118-
)()
128+
)() as BreakingChangesT
119129
upcomingChanges.set(graphqlVersion, data)
120130
}
121-
return upcomingChanges.get(graphqlVersion)
131+
return upcomingChanges.get(graphqlVersion)!
122132
}
123133

124-
// Using any for return type as the previews structure is dynamically loaded from JSON
125-
export function getPreviews(version: string): any {
134+
export function getPreviews(version: string): PreviewT[] {
126135
const graphqlVersion: string = getGraphqlVersion(version)
127136
if (!previews.has(graphqlVersion)) {
128-
// Using any as the JSON structure is not typed
129-
const data: any = readCompressedJsonFileFallbackLazily(
137+
const data = readCompressedJsonFileFallbackLazily(
130138
`${GRAPHQL_DATA_DIR}/${graphqlVersion}/previews.json`,
131-
)()
139+
)() as PreviewT[]
132140
previews.set(graphqlVersion, data)
133141
}
134-
return previews.get(graphqlVersion)
142+
return previews.get(graphqlVersion)!
135143
}
136144

137145
export async function getMiniToc(
@@ -140,7 +148,7 @@ export async function getMiniToc(
140148
items: string[],
141149
depth: number = 2,
142150
markdownHeading: string = '',
143-
): Promise<any[]> {
151+
): Promise<MiniTocItem[]> {
144152
const { currentLanguage, currentVersion } = context
145153
const graphqlVersion: string = getGraphqlVersion(currentVersion)
146154
const languageMap = miniTocs.get(currentLanguage)
@@ -152,8 +160,7 @@ export async function getMiniToc(
152160
}
153161
const versionMap = languageMap.get(graphqlVersion)!
154162
if (!versionMap.has(type)) {
155-
// Using any[] as the mini TOC item structure is not yet typed in the codebase
156-
const graphqlMiniTocItems: any[] = await getAutomatedPageMiniTocItems(
163+
const graphqlMiniTocItems = await getAutomatedPageMiniTocItems(
157164
items,
158165
context,
159166
depth,
@@ -169,11 +176,14 @@ export async function getChangelogMiniTocs(
169176
context: GraphqlContext,
170177
depth: number = 2,
171178
markdownHeading: string = '',
172-
): Promise<any[]> {
173-
if (!changelog.has('toc')) {
174-
changelog.set('toc', await getAutomatedPageMiniTocItems(items, context, depth, markdownHeading))
179+
): Promise<MiniTocItem[]> {
180+
if (!changelogMiniTocs.has('toc')) {
181+
changelogMiniTocs.set(
182+
'toc',
183+
await getAutomatedPageMiniTocItems(items, context, depth, markdownHeading),
184+
)
175185
}
176-
return changelog.get('toc')
186+
return changelogMiniTocs.get('toc')!
177187
}
178188

179189
function getGraphqlVersion(version: string): string {

src/graphql/pages/reference.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
addUINamespaces,
99
} from '@/frame/components/context/MainContext'
1010
import type { ObjectT } from '@/graphql/components/types'
11+
import type { ExtendedRequest } from '@/types/types'
1112
import { AutomatedPage } from '@/automated-pipelines/components/AutomatedPage'
1213
import {
1314
AutomatedPageContext,
@@ -55,10 +56,14 @@ export default function GraphqlReferencePage({
5556
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
5657
const { getGraphqlSchema, getAllGraphqlObjects } = await import('@/graphql/lib/index')
5758

58-
const req = context.req as any
59-
const res = context.res as any
60-
const language = req.context.currentLanguage as string
61-
const currentVersion = req.context.currentVersion as string
59+
const req = context.req as unknown as ExtendedRequest
60+
const res = context.res
61+
const ctx = req.context
62+
if (!ctx?.currentLanguage || !ctx?.currentVersion) {
63+
throw new Error('Request is missing currentLanguage or currentVersion in context')
64+
}
65+
const language: string = ctx.currentLanguage
66+
const currentVersion: string = ctx.currentVersion
6267
const page = context.query.page as string
6368

6469
if (!isValidCategory(page)) {

src/graphql/scripts/utils/process-schemas.ts

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
InputValueDefinitionNode,
99
ConstDirectiveNode,
1010
DefinitionNode,
11+
TypeNode,
1112
} from 'graphql/language'
1213
import helpers from './schema-helpers'
1314
import { OTHER_CATEGORY, isValidCategory } from '@/graphql/lib/categories'
@@ -21,7 +22,8 @@ interface PreviewInfo {
2122
// Interface for arguments returned by helpers.getArguments()
2223
interface FieldArgumentInfo {
2324
name: string
24-
defaultValue?: any // GraphQL default values can be any JSON-serializable type
25+
// GraphQL scalar default values come through the AST as a string or boolean.
26+
defaultValue?: string | boolean
2527
description: string
2628
type: {
2729
name: string
@@ -42,7 +44,8 @@ interface ScalarInfo {
4244

4345
interface QueryArgumentInfo {
4446
name: string
45-
defaultValue?: any // GraphQL default values can be any JSON-serializable type
47+
// GraphQL scalar default values come through the AST as a string or boolean.
48+
defaultValue?: string | boolean
4649
type: string
4750
id: string
4851
href: string
@@ -322,10 +325,10 @@ export default async function processSchemas(
322325
mutationFieldCategoryMap.get(mutFieldName) ?? fallbackMutationMap[mutFieldName.toLowerCase()]
323326

324327
// Walk through a TypeNode chain (NonNull/List wrappers) to the NamedType.
325-
const namedTypeName = (typeNode: any): string | undefined => {
326-
let t = typeNode
327-
while (t && t.type) t = t.type
328-
return t?.name?.value
328+
const namedTypeName = (typeNode: TypeNode): string | undefined => {
329+
let t: TypeNode = typeNode
330+
while ('type' in t) t = t.type
331+
return t.kind === 'NamedType' ? t.name.value : undefined
329332
}
330333

331334
// (a) input objects from mutation field args
@@ -459,12 +462,11 @@ export default async function processSchemas(
459462
(field.arguments || []).map(async (arg: InputValueDefinitionNode) => {
460463
const queryArg: Partial<QueryArgumentInfo> = {}
461464
queryArg.name = arg.name.value
462-
// ConstValueNode is a complex union; accessing value property generically
463-
queryArg.defaultValue = arg.defaultValue
464-
? (arg.defaultValue as any).value
465-
: undefined
466-
// InputValueDefinitionNode.type is compatible with getType's expected structure
467-
const argType = helpers.getType(arg as any)
465+
queryArg.defaultValue =
466+
arg.defaultValue && 'value' in arg.defaultValue
467+
? arg.defaultValue.value
468+
: undefined
469+
const argType = helpers.getType(arg)
468470
if (!argType) return
469471
queryArg.type = argType
470472
queryArg.id = helpers.getId(queryArg.type)
@@ -539,8 +541,7 @@ export default async function processSchemas(
539541
(field.arguments || []).map(async (arg: InputValueDefinitionNode) => {
540542
const inputField: Partial<InputFieldInfo> = {}
541543
inputField.name = arg.name.value
542-
// InputValueDefinitionNode.type is compatible with getType's expected structure
543-
const argType = helpers.getType(arg as any)
544+
const argType = helpers.getType(arg)
544545
if (!argType) return
545546
inputField.type = argType
546547
inputField.id = helpers.getId(inputField.type)
@@ -663,11 +664,7 @@ export default async function processSchemas(
663664
const fieldKind = helpers.getTypeKind(objectField.type, schema)
664665
if (!fieldKind) return
665666
objectField.href = linkTo(fieldKind, objectField.id)
666-
// InputValueDefinitionNode structure is compatible with ArgumentNode expected by getArguments
667-
objectField.arguments = await helpers.getArguments(
668-
(field.arguments || []) as any,
669-
schema,
670-
)
667+
objectField.arguments = await helpers.getArguments(field.arguments || [], schema)
671668
objectField.isDeprecated = helpers.getDeprecationStatus(
672669
(field.directives || []) as readonly ConstDirectiveNode[],
673670
)
@@ -732,11 +729,7 @@ export default async function processSchemas(
732729
const fieldKind = helpers.getTypeKind(interfaceField.type, schema)
733730
if (!fieldKind) return
734731
interfaceField.href = linkTo(fieldKind, interfaceField.id)
735-
// InputValueDefinitionNode structure is compatible with ArgumentNode expected by getArguments
736-
interfaceField.arguments = await helpers.getArguments(
737-
(field.arguments || []) as any,
738-
schema,
739-
)
732+
interfaceField.arguments = await helpers.getArguments(field.arguments || [], schema)
740733
interfaceField.isDeprecated = helpers.getDeprecationStatus(
741734
(field.directives || []) as readonly ConstDirectiveNode[],
742735
)
@@ -874,8 +867,7 @@ export default async function processSchemas(
874867

875868
inputField.name = field.name.value
876869
inputField.description = await helpers.getDescription(field.description?.value || '')
877-
// InputValueDefinitionNode.type is compatible with getType's expected structure
878-
const fieldType = helpers.getType(field as any)
870+
const fieldType = helpers.getType(field)
879871
if (!fieldType) return
880872
inputField.type = fieldType
881873
inputField.id = helpers.getId(inputField.type)

0 commit comments

Comments
 (0)