@vanta-inc/eslint-plugin-vanta
Version:
Custom ESLint rules for Vanta
82 lines (74 loc) • 2.47 kB
text/typescript
import { GraphQLESLintRule } from "@graphql-eslint/eslint-plugin";
import { GraphQLESTreeNode } from "@graphql-eslint/eslint-plugin/estree-converter";
import { TypeDefinitionNode } from "graphql/language/ast";
const rule: GraphQLESLintRule = {
meta: {
type: "suggestion",
docs: {
// @ts-ignore
description:
"Payloads are unions of a success type and one or more error types",
category: "Operations",
url: "https://github.com/VantaInc/eslint-plugin-vanta/blob/main/docs/rules/payloads-are-unions.md",
},
},
create(context) {
const validateDefinitionPayload = (
node: GraphQLESTreeNode<TypeDefinitionNode>
) => {
if (node.name.value.endsWith("Payload")) {
if (node.type !== "UnionTypeDefinition") {
context.report({
node,
message: "Types that end with 'Payload' must be unions",
});
return;
}
const successTypes =
node.types?.filter((type) => type.name.value.endsWith("Success")) ??
[];
if (successTypes.length !== 1) {
context.report({
node,
message:
"Payloads must include exactly one 'Success' type, found {{count}}",
data: {
count: `${successTypes.length}`,
},
});
}
if (!node.types?.some((type) => type.name.value === "BaseUserError")) {
context.report({
node,
message: "Payloads must include BaseUserError",
});
}
if (
!node.types?.every(
(type) =>
type.name.value.endsWith("Success") ||
type.name.value.endsWith("Error")
)
) {
context.report({
node,
message:
"Payloads should be unions of only Success and Error types",
});
}
}
};
// lint all kinds that fall under TypeDefinitionNode
// sadly TypeDefinitionNode: validateDefinitionPayload doesn't work
return {
ScalarTypeDefinition: validateDefinitionPayload,
ObjectTypeDefinition: validateDefinitionPayload,
InterfaceTypeDefinition: validateDefinitionPayload,
UnionTypeDefinition: validateDefinitionPayload,
EnumTypeDefinition: validateDefinitionPayload,
InputObjectTypeDefinition: validateDefinitionPayload,
};
},
};
module.exports = rule;
export default rule;