eslint-plugin-pimsical-shopify-graphql
TypeScript icon, indicating that this package has built-in type declarations

0.0.4 • Public • Published

eslint-plugin-pimsical-shopify-graphql

This is an ESLint plugin to help check Shopify GraphQL queries follow best practice. Built by Pimsical, a Shopify Partner.

It is designed to work alongside @graphql-eslint/eslint-plugin

TLDR;

Installation

npm i -D eslint-plugin-pimsical-shopify-graphql @graphql-eslint/eslint-plugin

Usage

You need to be using eslint flat config files, then we will need to add some config to your eslint.config.js.

There are two ways to use this plugin, depending on where your GraphQL queries are located.

Queries in code

If you have GraphQL queries inside TypeScript or JavaScript files, you can use the graphql-eslint processor to allow us to lint them.

Here is an example for a TypeScript project like so (or change the file extensions to match your project):

import graphqlPlugin from '@graphql-eslint/eslint-plugin'
import shopifyGraphqlPlugin from 'eslint-plugin-pimsical-shopify-graphql';

export default [
  {
    files: ['**/*.ts'],
    processor: graphqlPlugin.processor
  },
  {
    files: ['**/*.graphql'],
    languageOptions: {
      parser: graphqlPlugin.parser
    },
    plugins: {
      '@graphql-eslint': graphqlPlugin,
      'pimsical-shopify-graphql': shopifyGraphqlPlugin,
    },
    rules: {
      ...graphqlPlugin.configs['flat/operations-recommended'].rules,
      '@graphql-eslint/require-selections': 'off',
      ...shopifyGraphqlPlugin.configs['flat/recommended'].rules,
    },
  },
];

The graphql-eslint processor will pick up any GraphQL queries inside your TypeScript or JavaScript files, and convert them to .graphql files in memory only allowing us to lint them.

It will pick up any queries inside gql or graphql tagged template literals, or beginning with the comment /* GraphQL */ before the query by default.

To make the tools work more seamlessly and improve linting we recommend integrating with Shopify GraphQL Codegen below.

Queries in .graphql files

If you have GraphQL queries are in .graphql files already, you don't need the processor so your config can work like so:

import graphqlPlugin from '@graphql-eslint/eslint-plugin'
import shopifyGraphqlPlugin from 'eslint-plugin-pimsical-shopify-graphql';

export default [
  {
    files: ['**/*.graphql'],
    languageOptions: {
      parser: graphqlPlugin.parser
    },
    plugins: {
      '@graphql-eslint': graphqlPlugin,
      'pimsical-shopify-graphql': shopifyGraphqlPlugin,
    },
    rules: {
      ...graphqlPlugin.configs['flat/operations-recommended'].rules,
      '@graphql-eslint/require-selections': 'off',
      ...shopifyGraphqlPlugin.configs['flat/recommended'].rules,
    },
  },
];

Shopify GraphQL Schema

The linters work best combined with knowledge about Shopify GraphQL Schema, there are two ways to configure this:

If you are already using Shopify GraphQL Codegen, this does a lot of the work for us and is our recommended approach.

In your .graphqlrc.ts or equivalent JS file, ensure that pluckConfig is exposed in the default extensions object.

This will allow the linters to pick up the GraphQL code from your codebase using the same prefix as the codegen tools, it also uses the schemas from here as well.

import { shopifyApiProject, ApiType } from '@shopify/api-codegen-preset';

const apiVersion = '2025-04';
const config = shopifyApiProject({
  apiType: ApiType.Admin,
  apiVersion: apiVersion,
  documents: ['./**/*.{js,ts,jsx,tsx}'],
  outputDir: './shopify/types',
})

export default {
  schema: `https://shopify.dev/admin-graphql-direct-proxy/${apiVersion}`,
  documents: ['./**/*.{js,ts,jsx,tsx}'],
  projects: {
    default: {
      ...config,
      extensions: {
        ...config.extensions,
        pluckConfig: config.extensions?.codegen?.pluckConfig,
      },
    },
  },
};

Manually defined schema

If you are not using the codegen tools, you can manually define the schema in your eslint.config.js under parserOptions or add an equivalent Graphql Config file which will automatically get picked up.

import js from '@eslint/js';
import graphqlPlugin from '@graphql-eslint/eslint-plugin';

export default [
  {
    files: ['**/*.graphql'],
    languageOptions: {
      parser: graphqlPlugin.parser,
      parserOptions: {
        graphQLConfig: {
          schema: `https://shopify.dev/admin-graphql-direct-proxy/2025-04`,
          documents: [['./**/*.{js,ts,jsx,tsx,graphql}']],
        },
      },
    },
    plugins: {
      '@graphql-eslint': graphqlPlugin,
      'pimsical-shopify-graphql': shopifyGraphqlPlugin,
    },
    rules: {
      ...graphqlPlugin.configs['flat/operations-recommended'].rules,
      '@graphql-eslint/require-selections': 'off',
      ...shopifyGraphqlPlugin.configs['flat/recommended'].rules,
    },
  },
];

Rules

pimsical-shopify-graphql/max-first-argument

This rule checks that the first argument of a query is not greater than 250. This is to ensure that queries adhere to Shopify's maximum page size.

Examples

Correct
query getVariants($cursor: String) {
  productVariants(first: 100, after: $cursor) {
    pageInfo {
      hasNextPage
      endCursor
    }
    edges {
      node {
        id
      }
    }
  }
}
Incorrect
query getVariants($cursor: String) {
  productVariants(first: 300, after: $cursor) {
    pageInfo {
      hasNextPage
      endCursor
    }
    edges {
      node {
        id
      }
    }
  }
}

pimsical-shopify-graphql/require-mutation-user-errors

This rule checks that any mutations contain userErrors, this is how Shopify returns errors from your mutation input.

Examples

Correct
mutation inventoryAdjustQuantities($input: InventoryAdjustQuantitiesInput!) {
  inventoryAdjustQuantities(input: $input) {
    userErrors {
      field
      message
    }
    inventoryAdjustmentGroup {
      createdAt
      reason
    }
  }
}
Incorrect
mutation inventoryAdjustQuantities($input: InventoryAdjustQuantitiesInput!) {
  inventoryAdjustQuantities(input: $input) {
    inventoryAdjustmentGroup {
      createdAt
      reason
    }
  }
}

pimsical-shopify-graphql/require-query-page-info

This rule checks that if first or after arguments are used in a query, it also has a pageInfo block so you can check if there are more pages or paginate through the results.

Examples

Correct
query getVariants($cursor: String) {
  productVariants(first: 100, after: $cursor) {
    pageInfo {
      hasNextPage
      endCursor
    }
    edges {
      node {
        id
      }
    }
  }
}
Incorrect
query getVariants($cursor: String) {
  productVariants(first: 300, after: $cursor) {
    edges {
      node {
        id
      }
    }
  }
}

License

MIT

Package Sidebar

Install

npm i eslint-plugin-pimsical-shopify-graphql

Weekly Downloads

33

Version

0.0.4

License

ISC

Unpacked Size

18.3 kB

Total Files

19

Last publish

Collaborators

  • jordanfinners