Skip to content

Commit

Permalink
feat: add additional rule, NoDuplicateFieldName
Browse files Browse the repository at this point in the history
  • Loading branch information
rintoj committed Jun 29, 2024
1 parent 12d370c commit c9ad702
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 1 deletion.
7 changes: 6 additions & 1 deletion src/diagnostic/hook-diagnostic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { Position, Range } from '../diff'
import { GraphQLContext, createGraphQLContext, getGQLNodeLocationRange } from '../gql'
import { getGQLContent, getGraphQLQueryVariable, getTSNodeLocationRange } from '../ts'
import { Diagnostic, DiagnosticSeverity } from './diagnostic-type'
import { NoDuplicateFieldName } from './rules/NoDuplicateFieldName'

const additionalRules = [NoDuplicateFieldName]

function toError(error: gql.GraphQLError, context: Pick<GraphQLContext, 'offset' | 'sourceFile'>) {
const lineOffset = context?.offset?.line ?? 0
Expand Down Expand Up @@ -46,7 +49,9 @@ export function diagnoseGraphQLQuery(
): Diagnostic[] {
try {
const document = gql.parse(query)
const result = gql.validate(schema, document)
const result = gql
.validate(schema, document)
.concat(additionalRules.flatMap(rule => rule(document, schema)))
return result.flatMap(error => toError(error, context))
} catch (e) {
return [toError(e, context)].flat()
Expand Down
36 changes: 36 additions & 0 deletions src/diagnostic/rules/NoDuplicateFieldName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as gql from 'graphql'
import { isFieldNode, isInlineFragmentNode } from '../../gql'

export function NoDuplicateFieldName(document: gql.DocumentNode, schema: gql.GraphQLSchema) {
const errors: gql.GraphQLError[] = []
const typeInfo = new gql.TypeInfo(schema)
gql.visit(
document,
gql.visitWithTypeInfo(typeInfo, {
SelectionSet(node) {
const parent = typeInfo.getParentType()
const type = parent?.name
node.selections.reduce(
(a, node) => {
const name = isFieldNode(node)
? node.name.value
: isInlineFragmentNode(node)
? node.typeCondition?.name.value
: undefined
if (!name) return a
if (!!a[name]) {
errors.push(
new gql.GraphQLError(`Duplicate field "${name}" on type "${type}" `, {
nodes: [node],
}),
)
}
return { ...a, [name]: true }
},
{} as Record<string, boolean>,
)
},
}),
)
return errors
}
1 change: 1 addition & 0 deletions src/diagnostic/rules/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './NoDuplicateFieldName'

0 comments on commit c9ad702

Please sign in to comment.