Shopify Theme Check Custom Rule - Example?

Hi,

I was wondering if anybody has a javascript example to share on how to add a custom rule to Shopify theme check.

I have read the documentation and based on the following I presume that you can add custom rules in Javascript. However I am unable to find an actual “Hello world” like example of a custom check.

If somebody has a snippet to share that would be appreciated. And if possible any documentation pointing where this was defined.

Paths to custom checks

require:

./path/to/my_custom_check.js # path to file or module

‘/my-custom-checks’     # for node_modules checks


Here’s a minimal “Hello world” custom check that you can drop into your theme to get going. The docs are pretty bare on this but the source under @shopify/theme-check-common is the actual reference.

// .theme-check/checks/no-todo-comments.js
module.exports = {
  meta: {
    code: 'NoTodoComments',
    name: 'No TODO Comments',
    docs: { description: 'Disallow TODO comments in Liquid' },
    severity: 1, // 0=error, 1=warn, 2=info
    schema: {},
    targets: [],
    type: 'LiquidHtml'
  },
  create(context) {
    return {
      async LiquidRawTag(node) {
        if (node.name === 'comment' && /TODO/i.test(node.body)) {
          context.report({ message: 'Avoid TODO in Liquid comments', node });
        }
      }
    };
  }
};

Then in .theme-check.yml:

require:
  - ./.theme-check/checks/no-todo-comments.js
NoTodoComments:
  enabled: true

The visitor keys (LiquidRawTag, LiquidTag, HtmlElement, TextNode, etc) come from the AST node types in @shopify/liquid-html-parser. Run the parser once on a sample template and console.log the tree to discover what to hook. The context object also exposes file, getFileSize, relativePath if you need cross-file analysis.

For LiquidHtml-specific (templates) vs JSON (settings_schema, locales), set type to LiquidHtml, Json, or LiquidScript. CLI runs them automatically when you point require at the file.

What kind of rule are you trying to write? Stylelint-on-styles or something deeper like metafield-key linting?

Hi, thank you for the example. After running your script and then the `–list` command. I saw your example being listed (after making the adjustments below)

What I did have to change were two things in your example to make it work:

  • The module.exports needs to contain a check array. module.exports = { checks: [ { … } ]
    -And I had to change the check into: /TODO/i.test(node.body.value)