PageSourceSearch

https://074c6ee9.graphql-eslint.pages.dev/_next/static/chunks/pages/docs/custom-rules-d7acf3857aec7c6a.js

js graphql-eslint.pages.dev collected 2026-10-03 05:12:16 UTC 33,295 bytes, 1 lines download raw bytes

1(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[4653],{94593:function(e,s,r){(window.__NEXT_P=window.__NEXT_P||[]).push(["/docs/custom-rules",function(){return r(29642)}])},29642:function(e,s,r){"use strict";r.r(s);var n=r(39324),l=r(71209),o=r(35250),i=r(16913),t=r(47160);function a(e){var s=Object.assign({h1:"h1",p:"p",a:"a",code:"code",h2:"h2",pre:"pre",span:"span",ol:"ol",li:"li",h3:"h3",h4:"h4"},(0,t.ah)(),e.components);return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(s.h1,{children:"Writing Custom Rules"}),"\n",(0,o.jsxs)(s.p,{children:["To get started with your own rules, start by understanding how\n",(0,o.jsx)(s.a,{href:"https://eslint.org/docs/developer-guide/working-with-rules",children:"ESLint custom rules works"}),"."]}),"\n",(0,o.jsxs)(s.p,{children:[(0,o.jsx)(s.code,{children:"graphql-eslint"})," converts the ",(0,o.jsx)(s.a,{href:"https://graphql.org/graphql-js/language",children:"GraphQL AST"})," into\n",(0,o.jsx)(s.a,{href:"https://github.com/estree/estree",children:"ESTree structure"}),", so it allows you to easily travel the GraphQL\nAST tree easily."]}),"\n",(0,o.jsxs)(s.p,{children:["You can visit any GraphQL AST node in your custom rules, and report this as error. You don't need to\nhave special handlers for code-files, since ",(0,o.jsx)(s.code,{children:"graphql-eslint"})," extracts usages of ",(0,o.jsx)(s.code,{children:"gql"})," and magic\n",(0,o.jsx)(s.code,{children:"/* GraphQL */"})," comments automatically, and runs it through the parser, and eventually it knows to\nadjust errors location to fit in your code files original location."]}),"\n",(0,o.jsxs)(s.p,{children:["You can explore the GraphQL AST for a given input on\n",(0,o.jsx)(s.a,{href:"https://astexplorer.net/#/gist/e72aaccc1e57cbba41659d73cabbf75c/f10ee29317a31ff8012a21762a382c4a03c34d40",children:"astexplorer.net"}),"."]}),"\n",(0,o.jsx)(s.h2,{id:"getting-started",children:"Getting Started"}),"\n",(0,o.jsxs)(s.p,{children:["Start by creating a\n",(0,o.jsx)(s.a,{href:"https://eslint.org/docs/developer-guide/working-with-rules",children:"simple ESLint rule file"}),", and choose\nthe AST nodes you wish to visit. It can either be a\n",(0,o.jsxs)(s.a,{href:"https://github.com/graphql/graphql-js/blob/master/src/language/kinds.d.ts",children:["simple AST node ",(0,o.jsx)(s.code,{children:"Kind"})]}),"\nor a complex ",(0,o.jsx)(s.a,{href:"https://eslint.org/docs/developer-guide/selectors",children:"ESLint selector"})," that allows you to\ntravel and filter AST nodes."]}),"\n",(0,o.jsxs)(s.p,{children:["We recommend you to read the ",(0,o.jsx)(s.a,{href:"/docs/getting-started/parser",children:"graphql-eslint parser documentation"}),"\nbefore getting started, to understand the differences between the AST structures."]}),"\n",(0,o.jsxs)(s.p,{children:["The ",(0,o.jsx)(s.code,{children:"graphql-eslint"})," comes with a TypeScript wrapper for ESLint rules, and provides a testkit to\nsimplify testing process with GraphQL schemas, so you can use that by importing ",(0,o.jsx)(s.code,{children:"GraphQLESLintRule"}),"\ntype. But if you wish to use JavaScript - that's fine :)"]}),"\n",(0,o.jsx)(s.p,{children:"Here's an example for a simple rule that reports on anonymous GraphQL operations:"}),"\n",(0,o.jsx)(s.pre,{"data-language":"ts","data-theme":"default",filename:"your-rule-name.ts",hasCopyCode:!0,children:(0,o.jsxs)(s.code,{"data-language":"ts","data-theme":"default",children:[(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" { GraphQLESLintRule } "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-string-expression)"},children:"'@graphql-eslint/eslint-plugin'"})]}),"\n",(0,o.jsx)(s.span,{className:"line",children:" "}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"const"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"rule"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"},children:"GraphQLESLintRule"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" {"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"  "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"},children:"create"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"(context) {"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"    "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"return"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" {"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"      "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"},children:"OperationDefinition"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"(node) {"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"        "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"if"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" ("}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"!"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"node"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"."}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"name"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"?.value) {"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"          "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"context"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"},children:".report"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"({"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"            node"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"            message"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-string-expression)"},children:"'Oops, name is required!'"})]}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"          })"})}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"        }"})}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"      }"})}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"    }"})}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"  }"})}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"}"})})]})}),"\n",(0,o.jsx)(s.p,{children:"So what happens here?"}),"\n",(0,o.jsxs)(s.ol,{children:["\n",(0,o.jsxs)(s.li,{children:[(0,o.jsx)(s.code,{children:"@graphql-eslint/eslint-plugin"})," handles the parsing process for your GraphQL content. It will\nload the GraphQL files (either from code files or from ",(0,o.jsx)(s.code,{children:".graphql"})," files with SDL), parse it using\nGraphQL parser, converts it to ESTree structure and let ESLint do the rest."]}),"\n",(0,o.jsx)(s.li,{children:"Your rule is being loaded by ESLint, and executes just like any other ESLint rule."}),"\n",(0,o.jsxs)(s.li,{children:["Our custom rule asks ESLint to run our function for every ",(0,o.jsx)(s.code,{children:"OperationDefinition"})," found."]}),"\n",(0,o.jsxs)(s.li,{children:["If the ",(0,o.jsx)(s.code,{children:"OperationDefinition"})," node doesn't have a valid ",(0,o.jsx)(s.code,{children:"name"})," - we report an error to ESLint."]}),"\n"]}),"\n",(0,o.jsx)(s.h3,{id:"more-examples",children:"More Examples"}),"\n",(0,o.jsxs)(s.p,{children:["You can scan the ",(0,o.jsx)(s.code,{children:"packages/plugin/src/rules"})," directory in this repo for references for implementing\nrules. It coverts most of the use-cases and concepts of rules."]}),"\n",(0,o.jsx)(s.h2,{id:"accessing-original-graphql-ast-nodes",children:"Accessing Original GraphQL AST Nodes"}),"\n",(0,o.jsxs)(s.p,{children:["Since our parser converts GraphQL AST to ESTree structure, there are some minor differences in the\nstructure of the objects. If you are using TypeScript, and you typed your rule with\n",(0,o.jsx)(s.code,{children:"GraphQLESLintRule"})," - you'll see that each ",(0,o.jsx)(s.code,{children:"node"})," is a bit different from the AST nodes of GraphQL\n(you can read more about that in\n",(0,o.jsx)(s.a,{href:"/docs/getting-started/parser",children:"graphql-eslint parser documentation"}),")."]}),"\n",(0,o.jsxs)(s.p,{children:["If you need access to the original GraphQL AST ",(0,o.jsx)(s.code,{children:"node"}),", you can use ",(0,o.jsx)(s.code,{children:".rawNode()"})," method on each node\nyou get from the AST structure of ESLint."]}),"\n",(0,o.jsx)(s.p,{children:"This is useful if you wish to use other GraphQL tools that works with the original GraphQL AST\nobjects."}),"\n",(0,o.jsxs)(s.p,{children:["Here's an example for using original ",(0,o.jsx)(s.code,{children:"graphql-js"})," validate method to validate ",(0,o.jsx)(s.code,{children:"OperationDefinition"}),":"]}),"\n",(0,o.jsx)(s.pre,{"data-language":"ts","data-theme":"default",filename:"your-rule-name.ts",hasCopyCode:!0,children:(0,o.jsxs)(s.code,{"data-language":"ts","data-theme":"default",children:[(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" { requireGraphQLSchemaFromContext } "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-string-expression)"},children:"'@graphql-eslint/eslint-plugin'"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" { validate } "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-string-expression)"},children:"'graphql'"})]}),"\n",(0,o.jsx)(s.span,{className:"line",children:" "}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"export"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"const"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"rule"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" {"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"  "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"},children:"create"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"(context) {"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"    "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"return"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" {"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"      "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"},children:"OperationDefinition"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"(node) {"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"        "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"const"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"schema"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"},children:"requireGraphQLSchemaFromContext"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"(context)"})]}),"\n",(0,o.jsx)(s.span,{className:"line",children:" "}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"        "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"}
1,children:"validate"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"(context"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" schema"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" {"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"          kind"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"Kind"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"."}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"DOCUMENT"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"          definitions"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" ["}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"node"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"},children:".rawNode"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"()]"})]}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"        })"})}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"      }"})}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"    }"})}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"  }"})}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"}"})})]})}),"\n",(0,o.jsxs)(s.h2,{id:"typeinfo--graphqlschema",children:[(0,o.jsx)(s.code,{children:"TypeInfo"})," / ",(0,o.jsx)(s.code,{children:"GraphQLSchema"})]}),"\n",(0,o.jsx)(s.p,{children:"If you provide GraphQL schema in your ESLint configuration, it will get loaded automatically, and\nbecome available in your rules in two ways:"}),"\n",(0,o.jsxs)(s.ol,{children:["\n",(0,o.jsxs)(s.li,{children:["You'll be able to access the loaded ",(0,o.jsx)(s.code,{children:"GraphQLSchema"})," object."]}),"\n",(0,o.jsxs)(s.li,{children:["In every visited node, you'll be able to use ",(0,o.jsx)(s.code,{children:".typeInfo()"})," method to get an object with complete\ntype information on your visited node (see\n",(0,o.jsx)(s.a,{href:"https://graphql.org/graphql-js/utilities/#typeinfo",children:"TypeInfo documentation"}),")."]}),"\n"]}),"\n",(0,o.jsxs)(s.h4,{id:"getting-graphqlschema",children:["Getting ",(0,o.jsx)(s.code,{children:"GraphQLSchema"})]}),"\n",(0,o.jsxs)(s.p,{children:["To mark your ESLint rules as a rule that needs access to GraphQL schema, start by running\n",(0,o.jsx)(s.code,{children:"requireGraphQLSchemaFromContext"})," from the plugin package, it will make sure to return a schema, or\nthrow an error for the user about the missing schema."]}),"\n",(0,o.jsx)(s.pre,{"data-language":"ts","data-theme":"default",hasCopyCode:!0,children:(0,o.jsx)(s.code,{"data-language":"ts","data-theme":"default",children:(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"const"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"schema"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"},children:"requireGraphQLSchemaFromContext"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"(context)"})]})})}),"\n",(0,o.jsx)(s.h4,{id:"accessing-typeinfo",children:"Accessing TypeInfo"}),"\n",(0,o.jsxs)(s.p,{children:["If schema is provided and loaded successfully, the ",(0,o.jsx)(s.code,{children:"typeInfo"})," will be available to use. Otherwise -\nit will be ",(0,o.jsx)(s.code,{children:"undefined"}),". If your plugin requires ",(0,o.jsx)(s.code,{children:"typeInfo"})," in order to operate and run, make sure to\ncall ",(0,o.jsx)(s.code,{children:"requireGraphQLSchemaFromContext"})," - it will validate that the schema is loaded."]}),"\n",(0,o.jsxs)(s.p,{children:[(0,o.jsx)(s.code,{children:"typeInfo"})," is provided on every node, based on the type of that node, for example, to access the\n",(0,o.jsx)(s.code,{children:"GraphQLOutputType"})," while you are visiting a ",(0,o.jsx)(s.code,{children:"SelectionSet"})," node, you can do:"]}),"\n",(0,o.jsx)(s.pre,{"data-language":"ts","data-theme":"default",filename:"your-rule-name.ts",hasCopyCode:!0,children:(0,o.jsxs)(s.code,{"data-language":"ts","data-theme":"default",children:[(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" { requireGraphQLSchemaFromContext } "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-string-expression)"},children:"'@graphql-eslint/eslint-plugin'"})]}),"\n",(0,o.jsx)(s.span,{className:"line",children:" "}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"export"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"const"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"rule"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" {"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"  "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"},children:"create"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"(context) {"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"    "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"},children:"requireGraphQLSchemaFromContext"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"("}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-string-expression)"},children:"'your-rule-name'"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" context)"})]}),"\n",(0,o.jsx)(s.span,{className:"line",children:" "}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"    "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"return"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" {"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"      "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"},children:"SelectionSet"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"(node) {"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"        "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"const"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"typeInfo"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"node"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"},children:".typeInfo"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"}
1,children:"()"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"        "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"if"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" ("}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"typeInfo"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:".gqlType) {"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"          "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"console"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"},children:".log"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"("}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-string-expression)"},children:"`The GraphQLOutputType is: "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"${"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"typeInfo"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:".gqlType"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"}"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-string-expression)"},children:"`"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:")"})]}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"        }"})}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"      }"})}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"    }"})}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"  }"})}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"}"})})]})}),"\n",(0,o.jsxs)(s.p,{children:["The structure of the return value of ",(0,o.jsx)(s.code,{children:".typeInfo()"})," is\n",(0,o.jsx)(s.a,{href:"https://github.com/B2o5T/graphql-eslint/blob/master/packages/plugin/src/estree-converter/converter.ts#L32-L40",children:"defined here"}),".\nSo based on the ",(0,o.jsx)(s.code,{children:"node"})," you are using, you'll get a different values on ",(0,o.jsx)(s.code,{children:".typeInfo()"})," result."]}),"\n",(0,o.jsx)(s.h2,{id:"testing-your-rules",children:"Testing Your Rules"}),"\n",(0,o.jsxs)(s.p,{children:["To test your rules, you can either use the wrapped ",(0,o.jsx)(s.code,{children:"GraphQLRuleTester"})," from this library, or use the\nbuilt-it ",(0,o.jsx)(s.a,{href:"https://eslint.org/docs/developer-guide/working-with-rules#rule-unit-tests",children:(0,o.jsx)(s.code,{children:"RuleTester"})}),"\nof ESLint."]}),"\n",(0,o.jsxs)(s.p,{children:["The wrapped ",(0,o.jsx)(s.code,{children:"GraphQLRuleTester"})," provides built-in configured parser, and a schema loader, if you\nneed to test your rule with a loaded schema."]}),"\n",(0,o.jsx)(s.pre,{"data-language":"ts","data-theme":"default",filename:"your-rule-name.spec.ts",hasCopyCode:!0,children:(0,o.jsxs)(s.code,{"data-language":"ts","data-theme":"default",children:[(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" { GraphQLRuleTester } "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-string-expression)"},children:"'@graphql-eslint/eslint-plugin'"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" { rule } "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-string-expression)"},children:"'./my-rule'"})]}),"\n",(0,o.jsx)(s.span,{className:"line",children:" "}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"const"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"ruleTester"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:"new"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"},children:"GraphQLRuleTester"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"}
1,children:"()"})]}),"\n",(0,o.jsx)(s.span,{className:"line",children:" "}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-constant)"},children:"ruleTester"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-function)"},children:".runGraphQLTests"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"("}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-string-expression)"},children:"'your-rule-name'"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" rule"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" {"})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"  valid"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" ["})]}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"    {"})}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"      code"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-string-expression)"},children:"'query something { foo }'"})]}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"    }"})}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"  ]"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"  invalid"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" ["})]}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"    {"})}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"      code"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-string-expression)"},children:"'query invalid { foo }'"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,o.jsxs)(s.span,{className:"line",children:[(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"      errors"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" [{ message"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-token-string-expression)"},children:"'Your error message.'"}),(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:" }]"})]}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"    }"})}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"  ]"})}),"\n",(0,o.jsx)(s.span,{className:"line",children:(0,o.jsx)(s.span,{style:{color:"var(--shiki-color-text)"},children:"})"})})]})})]})}r(8850),s.default=(0,i.j)({MDXContent:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},s=Object.assign({},(0,t.ah)(),e.components).wrapper;return s?(0,o.jsx)(s,(0,l._)((0,n._)({},e),{children:(0,o.jsx)(a,(0,n._)({},e))})):a(e)},pageOpts:{filePath:"src/pages/docs/custom-rules.mdx",route:"/docs/custom-rules",headings:[{depth:1,value:"Writing Custom Rules",id:"writing-custom-rules"},{depth:2,value:"Getting Started",id:"getting-started"},{depth:3,value:"More Examples",id:"more-examples"},{depth:2,value:"Accessing Original GraphQL AST Nodes",id:"accessing-original-graphql-ast-nodes"},{depth:2,value:"TypeInfo / GraphQLSchema",id:"typeinfo--graphqlschema"},{depth:4,value:"Getting GraphQLSchema",id:"getting-graphqlschema"},{depth:4,value:"Accessing TypeInfo",id:"accessing-typeinfo"},{depth:2,value:"Testing Your Rules",id:"testing-your-rules"}],timestamp:1673974295e3,title:"Writing Custom Rules"},pageNextRoute:"/docs/custom-rules"})}}
1,function(e){e.O(0,[6913,9774,2888,179],function(){return e(e.s=94593)}),_N_E=e.O()}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.