Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support "Flat Config" (ESLint 9) #2178

Open
JoshuaKGoldberg opened this issue Feb 13, 2024 · 15 comments · Fixed by #2458
Open

Support "Flat Config" (ESLint 9) #2178

JoshuaKGoldberg opened this issue Feb 13, 2024 · 15 comments · Fixed by #2458
Labels
stage/5-alpha-release-testing The pull request is merged, an alpha release is available, to be tested

Comments

@JoshuaKGoldberg
Copy link

JoshuaKGoldberg commented Feb 13, 2024

👋 Coming over from eslint/eslint#18093: ESLint is migrating to a new "flat config" format that will be the default in ESLint v9.

It doesn't look like @graphql-eslint/eslint-plugin has support yet. I'm posting this issue here as a reference & cross-linking it to the table in eslint/eslint#18093. If there's anything technical blocking the extension from supporting flat configs, please let us know - we'd be happy to try to help! 💜

Additional resources:

@avaly
Copy link

avaly commented Mar 12, 2024

While this plugin mentions it has support for Flat Config, it does work OK, until you run eslint --cache:

Oops! Something went wrong! :(

ESLint: 8.57.0

Error: Could not serialize processor object (missing 'meta' object).
    at Object.value (/home/user/eslint-bug/node_modules/eslint/lib/config/flat-config-array.js:243:27)
    at stringify (/home/user/eslint-bug/node_modules/json-stable-stringify-without-jsonify/index.js:25:25)
    at module.exports (/home/user/eslint-bug/node_modules/json-stable-stringify-without-jsonify/index.js:68:7)
    at hashOfConfigFor (/home/user/eslint-bug/node_modules/eslint/lib/cli-engine/lint-result-cache.js:50:75)
    at LintResultCache.getCachedLintResults (/home/user/eslint-bug/node_modules/eslint/lib/cli-engine/lint-result-cache.js:116:30)
    at /home/user/eslint-bug/node_modules/eslint/lib/eslint/flat-eslint.js:821:41
    at Array.map (<anonymous>)
    at FlatESLint.lintFiles (/home/user/eslint-bug/node_modules/eslint/lib/eslint/flat-eslint.js:793:23)
    at async Object.execute (/home/user/eslint-bug/node_modules/eslint/lib/cli.js:421:23)
    at async main (/home/user/eslint-bug/node_modules/eslint/bin/eslint.js:152:22)

@kamleshFC
Copy link

Is there any update on this? Even I am getting the same error as the above

@marceloverdijk
Copy link

I'm also trying to setup the GraphQL eslint but noticing some issues as well...

From the examples repo I e.g. tried:

import * as graphqlESLint from '@graphql-eslint/eslint-plugin';

  {
    files: ['**/*.graphql'],
    ...graphqlESLint.flatConfigs['schema-recommended'],
  },

but that gives:

> eslint .

Oops! Something went wrong! :(

ESLint: 8.57.0

TypeError: Key "rules": Key "@graphql-eslint/description-style": Could not find plugin "@graphql-eslint".

although "@graphql-eslint/eslint-plugin": "^3.20.1", is installed...

and when I try instead:

{
    files: ['**/*.graphql'],
    languageOptions: {
      parser: graphqlESLint,
    },
    plugins: {
      '@graphql-eslint': graphqlESLint,
    },
    // rules: {
    //   'prettier/prettier': 'error',
    // },
  },

but that gives:

> eslint .

Oops! Something went wrong! :(

ESLint: 8.57.0

Error: Error while loading rule '@typescript-eslint/await-thenable': You have used a rule which requires parserServices to be generated. You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.
Parser: undefined
Note: detected a parser other than @typescript-eslint/parser. Make sure the parser is configured to forward "parserOptions.project" to @typescript-eslint/parser.

Note my eslint.config.mjs contains more than only graphql lint options:

export default tseslint.config(
  {
    ignores: [
      'dist/',
      'public/',
      'src/**/*.generated.*',
    ],
  },
  eslint.configs.recommended,
  ...tseslint.configs.recommendedTypeChecked,
  {
    languageOptions: {
      parserOptions: {
        project: true,
        tsconfigRootDir: import.meta.dirname,
      },
    },
  },
  stylistic.configs.customize({
    arrowParens: true,
    semi: true,
  }),
  {
    plugins: {
      '@stylistic': stylistic,
    },
    rules: {
      '@stylistic/padding-line-between-statements': [
        'error',
        { blankLine: 'always', prev: 'import', next: '*' },
        { blankLine: 'any', prev: 'import', next: 'import' },
      ],
    },
    .. <the graphql lint config>
  },

@benasher44
Copy link

if you set parser as the following, it seems to work as a workaround:

      parser: {
        ...graphqlEslint,
        meta: {
          name: "@graphql-eslint",
        }
      }

@JavaScriptBach
Copy link

I also can't get this working, despite claimed flat config support. Any attempt by me to set parserOptions.documents fails with

error  Parsing error: [graphql-eslint] 
Unable to find any GraphQL type definitions for the following pointers:
- ./src/**/*.{ts}

I also couldn't find any examples or documentation on parserOptions.documents, for example it isn't in https://the-guild.dev/graphql/eslint/docs/getting-started/parser-options

@meierw
Copy link

meierw commented Jun 16, 2024

For those interested here is an example of a config that ended up working for our project.

We are only using schema linting at the moment, so no idea how well this works for query linting.

// eslint.config.mjs

import { fixupPluginRules } from "@eslint/compat"

import * as graphqlEslint from "@graphql-eslint/eslint-plugin"

export default [
  // other configs here

  {
    files: ["**/*.gqls"],
    languageOptions: {
      ecmaVersion: 5,
      sourceType: "script",
      parser: { ...graphqlEslint, meta: { name: "@graphql-eslint" } },
      parserOptions: { schema: "./path/to/schema/**/*.gqls" },
    },
    plugins: { "@graphql-eslint": fixupPluginRules(graphqlEslint) },

    rules: {
      ...graphqlEslint.flatConfigs["schema-recommended"].rules,
      // other rule overrides here
    },
  },
]

@dimaMachina
Copy link
Owner

meta object was added for parser and processor in @graphql-eslint/[email protected] https://github.com/dimaMachina/graphql-eslint/releases/tag/release-1722466173246

And ESLint's --cache flag now works

use examples https://github.com/dimaMachina/graphql-eslint/tree/master/examples as reference

v4 will be released once I polish documentation to include new changes

@dimaMachina dimaMachina added the stage/5-alpha-release-testing The pull request is merged, an alpha release is available, to be tested label Jul 31, 2024
@bmulholland
Copy link
Contributor

I couldn't find an example of using a set of rules from this plugin, so in case anyone is looking too: it goes in the rules part of the config. You'll need to configure the rest of the eslint config block as if you were doing a manual list of rules.

(HOWEVER, note that I wasn't able to get this working. When I add graphql-eslint, eslint seems to get stuck in an infinite loop or something. Or at least, it goes from taking <10s to over a couple minutes. --debug shows GraphQL template literals cannot be plucked from a Vue template code without having the "@vue/compiler-sfc" package installed. even though I have that in my package.json & installed. I'm out of time for digging into this today.)

Something like:

  {
    // Extract GraphQL from files for linting -- this creates .graphql files that are then linted
    // below
    // While we use the .gql extension for our files, under the hood the graphql-eslint plugin
    // scans all files (using the processor entry, below) and outputs a file with the
    // text that is then parsed and generates the errors we see. That file has a fixed .graphql
    // extension, so we need to include that extension below or .ts etc files won't be linted.
    // NOTE: Order matters! First, Vue processes, then GraphQL parses, THEN the linting can take
    // place.
    files: ["**/*.js", "**/*.ts", "**/*.vue"],
    processor: graphqlESLint.processors.graphql,
  },


  {
    // Setup GraphQL Parser
    files: ["**/*.graphql", "**/*.gql"],
    languageOptions: { parser: graphqlESLint.parser },
    // https://github.com/B2o5T/graphql-eslint/tree/master/packages/plugin/src/configs/operations-recommended.ts
    plugins: { "@graphql-eslint": { rules: graphqlESLint.rules } },
    rules: {
      ...graphqlESLint.configs["flat/operations-recommended"],
      // overrides here, such as
      "@graphql-eslint/naming-convention": ["off"],
    },
  },

@dimaMachina dimaMachina reopened this Aug 5, 2024
@michaelfaith
Copy link

@dimaMachina I notice this was re-opened. Is there still more work to do on this? Happy to help.

@bmulholland
Copy link
Contributor

@dimaMachina I dug in a bit more. I got past the compiler-sfc issue using the latest alpha (not sure if I didn't have that installed before?). However, I'm now seeing a bug with the alpha: it's not correctly loading my graphql-config, so it throws e.g. no-deprecated requires a schema.

Specifically, this line seems to pass in the current file's path as the root of the project; graphql-config seems to therefore only look in the subdir the file is in, not the root. If I change the rootDir line to be my project's root dir, the config is correctly picked up. I could be wrong in my exact diagnosis here, but something's off for sure. Note that the graphql-config example in examples dir probably works because all files are in the root.

ALSO, it wasn't apparent from the Vue instructions that it was critical for the GraphQL Vue parsing to happen before other Vue parsers. Without that, all my lint errors in Vue files turned into a message simply saying "clear." I'd call that out specifically, both in the instructions and in the example.

@dimaMachina
Copy link
Owner

dimaMachina commented Oct 1, 2024

@bmulholland I think the bug with graphql-config is related to this PR merge kamilkisiela/graphql-config#1480 ,can you try to pin graphql-config to this version ? And try if it helps?

@bmulholland
Copy link
Contributor

@dimaMachina Good guess! My above testing was on graphql-config 5.1.2. 5.1.0 works fine; 5.1.1 is the first broken version.

This means:

And so we're back to your last statement :)

v4 will be released once I polish documentation to include new changes

As I've just gone through this, I'm happy to share any parts of my setup process if it would help you with the docs. Let me know if there's a particular blind spot or question you might have.

For starters, as I mentioned, including the importance of ordering -- probably in the form of recommending the graphql parsing of code files to go VERY FIRST in graphql.config.js -- would save others time.

@dimaMachina
Copy link
Owner

Amazing, would be awesome if you create a PR to point into this base branch https://github.com/dimaMachina/graphql-eslint/tree/more-new-docs with updates your Vue setup 🙏

here is the file to update

<Cards.Card icon={<VueIcon />} title="Usage with `.vue` files" href="/usage/vue" arrow />
(you need to create him)

@mat813
Copy link

mat813 commented Nov 22, 2024

I am trying to figure out how to migrate my config to flat file, and, i think I finally figured out how to do this.

Before, I had this in my package.conf:

  "eslintConfig": {
    "overrides": [
      {
        "files": ["*.ts"],
        "extends": ["plugin:@internal/default"],
      },
      {
        "files": ["*.graphql"],
        "extends": "plugin:@graphql-eslint/schema-all",
        "parserOptions": {
          "schema": "./graphql/schema.graphql"
        },
      },
      {
        "files": ["tests/**/*.ts"],
        "processor": "@graphql-eslint/graphql"
      },
      {
        "files": ["tests/**/*.graphql"],
        "extends": "plugin:@graphql-eslint/operations-all",
        "parser": "@graphql-eslint/eslint-plugin",
        "parserOptions": {
          "schema": "./graphql/schema.graphql",
          "operations": "tests/**/*.graphql"
        },
      }
    ]
  }

With flat config, after much hours of head scratching, the important bit is to forcefully add files to all the js/ts configs so that they don't match "everything".

export default [
  ...internalPlugin.configs.default.map((config) => ({ ...config, files: ['**/*.ts'] })),
  {
    files: ['**/*.graphql'],

    plugins: {
      '@graphql-eslint': graphqlPlugin,
    },

    languageOptions: {
      parser: graphqlPlugin.parser,
    },

    rules: {
      ...graphqlPlugin.configs['flat/schema-all'].rules,
    },
  },
  {
    files: ['tests/**/*.spec.ts'],

    processor: graphqlPlugin.processor,
  },
  {
    files: ['tests/**/*.spec.ts/*.graphql'],

    plugins: {
      '@graphql-eslint': graphqlPlugin,
    },

    rules: {
      ...graphqlPlugin.configs['flat/operations-all'].rules,
    },
  },
];

I think it works, I'll edit the comment if something is not quite right.

@dimaMachina
Copy link
Owner

dimaMachina commented Nov 22, 2024

It’s wrong your operations files are extended with schema rules, which is not needed, there is official example for monorepo https://github.com/dimaMachina/graphql-eslint/blob/master/examples/monorepo/eslint.config.js

Also you specify 2 times

plugins: {
'@graphql-eslint': graphqlPlugin,
},

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stage/5-alpha-release-testing The pull request is merged, an alpha release is available, to be tested
Projects
None yet