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

Bug: [flat config] Caching is not supported when parser is an object #16875

Closed
1 task
Tracked by #13481
liuweiGL opened this issue Feb 8, 2023 · 7 comments · Fixed by #16944
Closed
1 task
Tracked by #13481

Bug: [flat config] Caching is not supported when parser is an object #16875

liuweiGL opened this issue Feb 8, 2023 · 7 comments · Fixed by #16944
Assignees
Labels
accepted There is consensus among the team that this change meets the criteria for inclusion archived due to age This issue has been archived; please open a new issue for any further discussion bug ESLint is working incorrectly repro:yes

Comments

@liuweiGL
Copy link

liuweiGL commented Feb 8, 2023

Environment

Node version: v18.14.0
npm version: v9.3.1
Local ESLint version: v8.33.0 (Currently used)
Global ESLint version: Not found
Operating System: win32 10.0.19045

What parser are you using?

@babel/eslint-parser

What did you do?

eslint.config.js

import babelParser from '@babel/eslint-parser'

export default [
  {
    files: ['**/*.js', '**/*.mjs'],
    languageOptions: {
      parser: babelParser
    }
  }
]

What did you expect to happen?

Print the config detail

What actually happened?

PS C:\Users\liuwei\Desktop\gitlab\eastcoal-pc> pnpm eslint --print-config eslint.config.js

Oops! Something went wrong! :(

ESLint: 8.33.0

Error: Caching is not supported when parser is an object.
    at Object.value (C:\Users\liuwei\Desktop\gitlab\eastcoal-pc\node_modules\.pnpm\eslint@8.33.0\node_modules\eslint\lib\config\flat-config-array.js:188:27)
    at JSON.stringify (<anonymous>)
    at Object.execute (C:\Users\liuwei\Desktop\gitlab\eastcoal-pc\node_modules\.pnpm\eslint@8.33.0\node_modules\eslint\lib\cli.js:387:27)
    at async main (C:\Users\liuwei\Desktop\gitlab\eastcoal-pc\node_modules\.pnpm\eslint@8.33.0\node_modules\eslint\bin\eslint.js:135:24)

Participation

  • I am willing to submit a pull request for this issue.

Additional comments

https://eslint.org/blog/2022/08/new-config-system-part-2/#custom-parsers-and-parser-options-are-mostly-the-same

@liuweiGL liuweiGL added bug ESLint is working incorrectly repro:needed labels Feb 8, 2023
@liuweiGL liuweiGL changed the title Bug: Caching is not supported when parser is an object Bug: [flat config] Caching is not supported when parser is an object Feb 8, 2023
@Rec0iL99
Copy link
Member

Rec0iL99 commented Feb 8, 2023

Hi @liuweiGL, thanks for opening this issue.
I was able to reproduce this on my machine.

I ran with the default ESLint languageOptions and it gave me the desired output.

// eslint.config.js

module.exports = [
  {
    files: ['**/*.js', '**/*.mjs'],
    rules: {
        "semi": "error",
        "no-unused-vars": "error"
    },
  }
]
npx eslint --print-config eslint.config.js

// output
{
  "languageOptions": {
    "ecmaVersion": "latest",
    "sourceType": "module",
    "parser": "@/espree",
    "parserOptions": {},
    "globals": {}
  },
  "plugins": [
    "@"
  ],
  "rules": {
    "semi": [
      2
    ],
    "no-unused-vars": [
      2
    ]
  }
}

But with language options with the babel parser I got an error.

const babelParser =  require('@babel/eslint-parser')

module.exports = [
  {
    files: ['**/*.js', '**/*.mjs'],
    rules: {
        "semi": "error",
        "no-unused-vars": "error"
    },
    languageOptions: {
        parser: babelParser
      }
  }
]
npx eslint --print-config eslint.config.js                                                                                        

// output
Oops! Something went wrong! :(

ESLint: 8.33.0

Error: Caching is not supported when parser is an object.
    at Object.value (/Users/joelmathew/WebProjects/experimenting-with-eslint/node_modules/eslint/lib/config/flat-config-array.js:188:27)
    at JSON.stringify (<anonymous>)
    at Object.execute (/Users/joelmathew/WebProjects/experimenting-with-eslint/node_modules/eslint/lib/cli.js:387:27)
    at async main (/Users/joelmathew/WebProjects/experimenting-with-eslint/node_modules/eslint/bin/eslint.js:135:24)

This error might have something to do with the @babel/eslint-parser, I'm not quite sure. Let's wait for someone from the core team to help us out here.

@liuweiGL
Copy link
Author

liuweiGL commented Feb 8, 2023

Currently eslint seems to only support string parser

if (languageOptions && languageOptions.parser) {
if (typeof languageOptions.parser === "string") {
const { pluginName, objectName: localParserName } = splitPluginIdentifier(languageOptions.parser);
parserName = languageOptions.parser;
if (!plugins || !plugins[pluginName] || !plugins[pluginName].parsers || !plugins[pluginName].parsers[localParserName]) {
throw new TypeError(`Key "parser": Could not find "${localParserName}" in plugin "${pluginName}".`);
}
languageOptions.parser = plugins[pluginName].parsers[localParserName];
} else {
invalidParser = true;
}
}

Object.defineProperty(config, "toJSON", {
value: function() {
if (invalidParser) {
throw new Error("Caching is not supported when parser is an object.");
}
if (invalidProcessor) {
throw new Error("Caching is not supported when processor is an object.");
}
return {

@nzakas
Copy link
Member

nzakas commented Feb 8, 2023

Yes, this is a known limitation of the flat config format right now. We just need to decide how to implement caching for objects.

The most obvious choice is to ask parsers to implement some form of naming, perhaps like this:

parser = {
   meta: {
       name: "foo",
       version: "1.1.1",
   }
};

@nzakas nzakas added the tsc agenda This issue will be discussed by ESLint's TSC at the next meeting label Feb 8, 2023
@nzakas
Copy link
Member

nzakas commented Feb 8, 2023

TSC Summary: We haven't yet implemented caching for object parsers or processors. To do this, we need a way to identify these objects uniquely. The proposal is to ask parsers to implement some identifying properties, such as:

parser = {
   meta: {
       name: "foo",
       version: "1.1.1",
   }
};

TSC Question: How do we want to identify object parsers and processors for caching?

@nzakas nzakas added the accepted There is consensus among the team that this change meets the criteria for inclusion label Feb 8, 2023
@exodus4d
Copy link
Contributor

I came across the same issue with eslint-plugin-jsonc. I could work around the issue with a runtime plugin.
The initial problem:

// Prior (non flat config) -----------------------------------
module.exports = {
  extends: ["plugin:jsonc/recommended-with-jsonc"],
  parser: "@babel/eslint-parser",
  overrides: [
    {
      files: ["*.json", "*.json5", "*.jsonc"],
      parser: "jsonc-eslint-parser",
    },
  ],
};

// Flat config ------------------------------------------------
import jsonc from "eslint-plugin-jsonc";

export default [{
  files:   ["**/*.json", "**/*.jsonc", "**/*.json5"],
  plugins: {
    jsonc
  },
  languageOptions: {
     parser: 'jsonc/jsonc-eslint-parser' // <- Error because jsonc.parsers['jsonc-eslint-parser'] does not exists
  },
  rules: {...}
}];

The initial idea to bypass the parser as object failed because of this issue:

  languageOptions: {
     parser: await import('jsonc-eslint-parser') // <- Error must be string. Object not implemented yet
  }

To work aroud this, I defined a runtime plugin of the same name 'jsonc' and made the parser available under the 'parsers' prop: [Plugin_Name].parsers.[Parser_Name]. No need to change languageOptions.parser to an object any more:

import {default as jsonc, parseForESLint, configs} from "eslint-plugin-jsonc";

const parsers = {
  'jsonc-eslint-parser': {
    parseForESLint
  }
}

export default [{
  files:   ["**/*.json", "**/*.jsonc", "**/*.json5"],
  plugins: {
    jsonc: { ...jsonc, parsers}
    /* same as
    jsonc: {
      parsers: {
        'jsonc-eslint-parser': {
          parseForESLint
        }
      }
    } */
  },
  languageOptions: {
     parser: 'jsonc/jsonc-eslint-parser'
  },
  rules: {...}
}];

Not sure if this is a valid approach, but it seems to work so far.

@btmills btmills removed the tsc agenda This issue will be discussed by ESLint's TSC at the next meeting label Feb 20, 2023
@btmills
Copy link
Member

btmills commented Feb 20, 2023

Great that you found a workaround! We discussed the meta cache key proposal in the 2023-02-09 TSC meeting, and all were in favor, so there will be a built-in solution to this once that's implemented.

@nzakas nzakas self-assigned this Feb 22, 2023
@nzakas
Copy link
Member

nzakas commented Feb 22, 2023

Working on this.

@nzakas nzakas mentioned this issue Feb 22, 2023
69 tasks
nzakas added a commit that referenced this issue Feb 27, 2023
This implements a check for a 'meta' key on parsers and processors that
contains information to help flat config serialize these objects for use
with caching and also --print-config on the command line.

Fixes #16875
aladdin-add added a commit to eslint/espree that referenced this issue Mar 1, 2023
mdjermanovic pushed a commit that referenced this issue Mar 8, 2023
* feat: Serialize parsers/processors in flat config

This implements a check for a 'meta' key on parsers and processors that
contains information to help flat config serialize these objects for use
with caching and also --print-config on the command line.

Fixes #16875

* Add support for non-meta properties

* Fix edge case
@eslint-github-bot eslint-github-bot bot locked and limited conversation to collaborators Sep 5, 2023
@eslint-github-bot eslint-github-bot bot added the archived due to age This issue has been archived; please open a new issue for any further discussion label Sep 5, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
accepted There is consensus among the team that this change meets the criteria for inclusion archived due to age This issue has been archived; please open a new issue for any further discussion bug ESLint is working incorrectly repro:yes
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

5 participants