Skip to content

ESLint Flat Configuration #422

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

Closed
2 tasks done
JP-Ellis opened this issue Mar 26, 2023 · 8 comments · Fixed by #423
Closed
2 tasks done

ESLint Flat Configuration #422

JP-Ellis opened this issue Mar 26, 2023 · 8 comments · Fixed by #423

Comments

@JP-Ellis
Copy link
Contributor

JP-Ellis commented Mar 26, 2023

Before You File a Bug Report Please Confirm You Have Done The Following...

  • I have tried restarting my IDE and the issue persists.
  • I have updated to the latest version of the packages.

What version of ESLint are you using?

8.36.0

What version of eslint-plugin-svelte are you using?

4.2.1

What did you do?

Trying to get linting to work for both TypeScript files and Svelte using the new ESLint flat config. So far, I can get the ESLint config to work for either TypeScript file or Svelte files, but not both due to an issue relating to tsconfig.ts. I don't know whether this is a bug in my configuration, or whether it is an issue with this plugin and/or the TypeScript plugin.

While I understand the flat config is still very new and not fully released, ESLint does plan for the new configuration file to replace the existing .eslintrc.cjs files.

eslint.config.js
import js from "@eslint/js";
import typescriptPlugin from "@typescript-eslint/eslint-plugin";
import typescriptParser from "@typescript-eslint/parser";
import sveltePlugin from "eslint-plugin-svelte";
import svelteParser from "svelte-eslint-parser";

export default [
  {
    ignores: [".svelte-kit/**/*"],
  },

  // Load predefined config
  js.configs.recommended,

  // JavaScript
  {
    files: ["**/*.js", "**/*.cjs"],
  },

  // TypeScript
  {
    files: ["**/*.ts"],
    ignores: ["playwright.config.ts"],
    languageOptions: {
      parser: typescriptParser,
      parserOptions: {
        project: "./tsconfig.json",
      },
    },
    plugins: {
      "@typescript-eslint": typescriptPlugin,
    },
    rules: {
      ...typescriptPlugin.configs.recommended.rules,
    },
  },

  // Svelte
  {
    files: ["**/*.svelte"],
    languageOptions: {
      parser: svelteParser,
      parserOptions: {
        parser: typescriptParser,
        project: "./tsconfig.json",
        extraFileExtensions: [".svelte"],
      },
    },
    plugins: {
      svelte: sveltePlugin,
      "@typescript-eslint": typescriptPlugin,
    },
    rules: {
      ...typescriptPlugin.configs.recommended.rules,
      ...sveltePlugin.configs.recommended.rules,
    },
  },
];
src/routes/+pages.svelte
<!-- Welcome to eslint-plugin-svelte -->
<script lang="ts">
  let a = 1;
  let b = 2;
  // let c = 2;
  let string = `this string contains some <strong>HTML!!!</strong>`;
  let user = {
    firstname: 'Ada',
    lastname: 'Lovelace'
  };
    let current = 'foo';
  let color = 'red';
  let active = true;
</script>

<input
  type="number"
  bind:value={a}>
<input
    type="number"
  bind:value={b}>
<input
  type="number"
  bind:value={c}>
<p>{a} + {b} + {c} = {a + b + c}</p>

<p>{@html string}</p>

<input bind:value={user.firstname}>
<input bind:value={user.lastname}>

{@debug user}

<h1>Hello {user.firstname}!</h1>

{#if a}
  <div>foo</div>
{:else if b}
  <div>bar</div>
{:else if b}
  <div>baz</div>
{/if}

<button
  type=button
  class="{active ? 'active' : ''} {current === 'foo' ? 'selected' : ''}"
  on:click="{() => current = 'foo'}"
>foo</button>

<div style="color: {color};">...</div>
src/test.ts
let myVar = 100;
myVar = "foo";
console.log(myVar);

const myConst = 100;
myConst += 1;
console.log(myConst);

export { };

What did you expect to happen?

Errors to be reported in both the TypeScript and the Svelte files.

What actually happened?

If I enable both the Svelte and TypeScript configurations in the ESLint flat configuration, the Svelte file produces the following error (noting that the TypeScript file works fine):

  0:0  error  Parsing error: ESLint was configured to run on `<tsconfigRootDir>/src/routes/+page.svelte` using `parserOptions.project`: <tsconfigRootDir>/tsconfig.json
However, that TSConfig does not include this file. Either:
- Change ESLint's list of included files to not include this file
- Change that TSConfig to include this file
- Create a new TSConfig that includes this file and include it in your parserOptions.project
See the typescript-eslint docs for more info: https://typescript-eslint.io/linting/troubleshooting#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file

If I disable the TypeScript section, the Svelte file produces the expected errors, but then the TypeScript file produces no lints (as it is no longer included).

Link to GitHub Repo with Minimal Reproducible Example

JP-Ellis/eslint-plugin-svelte-mwe

@ota-meshi
Copy link
Member

Thank you for posting issue.

But, I can't reproduce issue.

image

If I disable the TypeScript section, the Svelte file produces the expected errors, but then the TypeScript file produces no lints (as it is no longer included).

That is interesting. Can you explain in detail what you actually did?

@ota-meshi ota-meshi added the needs repro Need a repository that can reproduce the problem label Mar 26, 2023
@JP-Ellis
Copy link
Contributor Author

Yes, of course.

Firstly, I edited the repo slightly to hide the old .eslintrc.cjs file in case this was causing any issue with your debugging. New version of ESLint should prefer the new flat config if it is found, but there are settings to prefer the old version.

Now when I am talking about enabling/disabling the TypeScript section, I am referring to this part:

https://github.com/JP-Ellis/eslint-plugin-svelte-mwe/blob/f09107de3dcb59704a4e6d416b26eaa720f25c10/eslint.config.js#L20-L36

It is disabled at the moment, hence why you see the error with the Svelte file and no warnings about the TypeScript file. If you enable/uncomment these lines, you should see the error with the TypeScript file, and the error with the Svelte file.

@ota-meshi
Copy link
Member

Hmmm... If you add extraFileExtensions:[".svelte"], to the TypeScript section as well, will it check both files?

@JP-Ellis
Copy link
Contributor Author

Interestingly, that does fix the issue.

It would appear that the TypeScript parser configuration is shared between each entry of the ESLint config. I'm not sure this is the intended effect, and perhaps this is a bug with the TypeScript parser itself (I will raise this in their repo).

Not sure how you want to resolve this as far as this plugin is concerned. I think adding a segment to the README would be sufficient. Would you like to me to send through a PR later today?

@ota-meshi
Copy link
Member

perhaps this is a bug with the TypeScript parser itself

I agree. I think it's a bug with the @typescript-eslint/parser.

After asking in the typescript-eslint repo, if it is a @typescript-eslint/parser spec, I think we need to add a solution in the README of this repository.

@JP-Ellis
Copy link
Contributor Author

I have raised an issue with @typescript-eslint/parser: typescript-eslint/typescript-eslint#6778

@ota-meshi
Copy link
Member

Thanks!

@ota-meshi ota-meshi removed the needs repro Need a repository that can reproduce the problem label Mar 27, 2023
@JP-Ellis
Copy link
Contributor Author

JP-Ellis commented Mar 27, 2023

This has been closed upstream as "working as intended". Here's the response from @bradzacher:

We cache the program created for each tsconfig as a singleton for the duration of the lint.

It just so happens that the first file that ESLint asks us to parse is a .ts file (because it's closer to the project root than the svelte file). So we create a program for ./tsconfig.json with extraFileExtensions: []. Next ESLint asks svelte-eslint-parser to parse the svelte file. When it parses the script block, I assume it's like the vue parser - i.e. it calls into our parser again with the block contents, passing the options provided. Based on your config that means that it asks our parser to do a type-aware lint for ./tsconfig.json with extraFileExtensions: [".svelte"].

However - we've already got a cached program from before so we just return that - i.e. we ignore the extra config you've passed in.

The solution is to ensure the parser options are consistent for a given project path (which you have already found to work).


For us to support this style of inconsistent config we would need to keep two copies of the program around - one for each set of parser options you pass in. This is a non-starter because it would waste a lot of time (program creation is expensive) and waste a lot of memory (again, expensive).

Parsers like the svelte or vue parser are special cases that (TBH) hack around the ecosystem to add support for TS. Standard TS usage does not create scenarios in which you will have multiple sets of parser options for the same tsconfig files like this.


It's worth noting that I don't believe this has anything to do with flat config - you would hit the exact same problem with a classic config because it's an ordering problem.

In light of this, I will create a PR later today to mention this in the README.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants