@graphql-eslint/eslint-plugin
Version:
GraphQL plugin for ESLint
136 lines (135 loc) • 4.45 kB
JavaScript
import {
Kind
} from "graphql";
const schema = {
type: "array",
maxItems: 1,
items: {
type: "object",
additionalProperties: !1,
properties: {
checkInputType: {
type: "boolean",
default: !1,
description: "Check that the input type name follows the convention \\<mutationName>Input"
},
caseSensitiveInputType: {
type: "boolean",
default: !0,
description: "Allow for case discrepancies in the input type name"
},
checkQueries: {
type: "boolean",
default: !1,
description: "Apply the rule to Queries"
},
checkMutations: {
type: "boolean",
default: !0,
description: "Apply the rule to Mutations"
}
}
}
}, isObjectType = (node) => (
// TODO: remove `as any` when drop support of graphql@15
[Kind.OBJECT_TYPE_DEFINITION, Kind.OBJECT_TYPE_EXTENSION].includes(node.type)
), isQueryType = (node) => isObjectType(node) && node.name.value === "Query", isMutationType = (node) => isObjectType(node) && node.name.value === "Mutation", rule = {
meta: {
type: "suggestion",
hasSuggestions: !0,
docs: {
description: `Require mutation argument to be always called "input" and input type to be called Mutation name + "Input".
Using the same name for all input parameters will make your schemas easier to consume and more predictable. Using the same name as mutation for InputType will make it easier to find mutations that InputType belongs to.`,
category: "Schema",
url: "https://the-guild.dev/graphql/eslint/rules/input-name",
examples: [
{
title: "Incorrect",
usage: [{ checkInputType: !0 }],
code: (
/* GraphQL */
`
type Mutation {
SetMessage(message: InputMessage): String
}
`
)
},
{
title: "Correct (with `checkInputType`)",
usage: [{ checkInputType: !0 }],
code: (
/* GraphQL */
`
type Mutation {
SetMessage(input: SetMessageInput): String
}
`
)
},
{
title: "Correct (without `checkInputType`)",
usage: [{ checkInputType: !1 }],
code: (
/* GraphQL */
`
type Mutation {
SetMessage(input: AnyInputTypeName): String
}
`
)
}
]
},
schema
},
create(context) {
const options = {
checkInputType: !1,
caseSensitiveInputType: !0,
checkMutations: !0,
...context.options[0]
}, shouldCheckType = (node) => options.checkMutations && isMutationType(node) || options.checkQueries && isQueryType(node) || !1, listeners = {
"FieldDefinition > InputValueDefinition[name.value!=input] > Name"(node) {
const fieldDef = node.parent.parent;
if (shouldCheckType(fieldDef.parent)) {
const inputName = node.value;
context.report({
node,
message: `Input "${inputName}" should be named "input" for "${fieldDef.parent.name.value}.${fieldDef.name.value}"`,
suggest: [
{
desc: "Rename to `input`",
fix: (fixer) => fixer.replaceText(node, "input")
}
]
});
}
}
};
return options.checkInputType && (listeners["FieldDefinition > InputValueDefinition NamedType"] = (node) => {
const inputValueNode = ((item) => {
let currentNode = item;
for (; currentNode.type !== Kind.INPUT_VALUE_DEFINITION; )
currentNode = currentNode.parent;
return currentNode;
})(node);
if (shouldCheckType(inputValueNode.parent.parent)) {
const mutationName = `${inputValueNode.parent.name.value}Input`, name = node.name.value;
(options.caseSensitiveInputType && node.name.value !== mutationName || name.toLowerCase() !== mutationName.toLowerCase()) && context.report({
node: node.name,
message: `Input type \`${name}\` name should be \`${mutationName}\`.`,
suggest: [
{
desc: `Rename to \`${mutationName}\``,
fix: (fixer) => fixer.replaceText(node, mutationName)
}
]
});
}
}), listeners;
}
};
export {
rule
};