Skip to content

no-duplicates fails for svelte packages with shared type definitions file #308

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

Open
sviripa opened this issue Apr 17, 2025 · 4 comments
Open

Comments

@sviripa
Copy link

sviripa commented Apr 17, 2025

Repro repo

ESLint config

import js from "@eslint/js";
import { includeIgnoreFile } from "@eslint/compat";
import svelte from "eslint-plugin-svelte";
import globals from "globals";
import { fileURLToPath } from "node:url";
import ts from "typescript-eslint";
import * as pluginImportX from "eslint-plugin-import-x";
import svelteConfig from "./svelte.config.js";

const gitignorePath = fileURLToPath(new URL("./.gitignore", import.meta.url));

export default ts.config(
  includeIgnoreFile(gitignorePath),
  js.configs.recommended,
  ...ts.configs.recommended,
  ...svelte.configs.recommended,
  pluginImportX.flatConfigs.recommended,
  {
    languageOptions: {
      globals: { ...globals.browser, ...globals.node },
    },
    rules: {
      // typescript-eslint strongly recommend that you do not use the no-undef lint rule on TypeScript projects.
      // see: https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors
      "no-undef": "off",
    },
  },
  {
    settings: {
      "import-x/parsers": {
        "@typescript-eslint/parser": [".ts", ".tsx", ".mts", ".mjs"],
      },
      "import-x/resolver": {
        typescript: true,
      },
    },
  },
  {
    files: ["**/*.svelte", "**/*.svelte.ts", "**/*.svelte.js"],
    languageOptions: {
      parserOptions: {
        projectService: true,
        extraFileExtensions: [".svelte"],
        parser: ts.parser,
        svelteConfig,
      },
    },
  }
);

Code:

<script lang="ts">
  import { onMount } from "svelte";
  import { fly } from 'svelte/transition'
</script>

Eslint output:

/Users/bohdan/Development/eslint-import-no-dup/src/routes/+page.svelte
  2:12  error    'onMount' is defined but never used                                                                                                             @typescript-eslint/no-unused-vars
  2:27  warning  '/Users/bohdan/Development/eslint-import-no-dup/node_modules/.pnpm/[email protected]/node_modules/svelte/types/index.d.ts' imported multiple times  import-x/no-duplicates
  3:12  error    'fly' is defined but never used                                                                                                                 @typescript-eslint/no-unused-vars
  3:23  warning  '/Users/bohdan/Development/eslint-import-no-dup/node_modules/.pnpm/[email protected]/node_modules/svelte/types/index.d.ts' imported multiple times  import-x/no-duplicates

Eslint autofix rewrites the imports to just import { onMount, fly } from "svelte"; however, svelte package does not export fly.

Is there any way to configure import-x plugin to not resolve by types for svelte and its subpackages?

@sviripa
Copy link
Author

sviripa commented Apr 17, 2025

svelte and svelte/transition use the same types file according to svelte's package.json:

{
  "name": "svelte",
  "description": "Cybernetically enhanced web apps",
  "license": "MIT",
  "version": "5.27.2",
  "type": "module",
  "types": "./types/index.d.ts",
  "engines": {
    "node": ">=18"
  },
  "files": [
    "*.d.ts",
    "src",
    "!src/**/*.test.*",
    "!src/**/*.d.ts",
    "types",
    "compiler",
    "README.md"
  ],
  "module": "src/index-client.js",
  "main": "src/index-client.js",
  "exports": {
    ".": {
      "types": "./types/index.d.ts",
      "worker": "./src/index-server.js",
      "browser": "./src/index-client.js",
      "default": "./src/index-server.js"
    },
    "./package.json": "./package.json",
    "./action": {
      "types": "./types/index.d.ts"
    },
    "./animate": {
      "types": "./types/index.d.ts",
      "default": "./src/animate/index.js"
    },
    "./compiler": {
      "types": "./types/index.d.ts",
      "require": "./compiler/index.js",
      "default": "./src/compiler/index.js"
    },
    "./easing": {
      "types": "./types/index.d.ts",
      "default": "./src/easing/index.js"
    },
    "./elements": {
      "types": "./elements.d.ts"
    },
    "./internal": {
      "default": "./src/internal/index.js"
    },
    "./internal/client": {
      "default": "./src/internal/client/index.js"
    },
    "./internal/disclose-version": {
      "default": "./src/internal/disclose-version.js"
    },
    "./internal/flags/legacy": {
      "default": "./src/internal/flags/legacy.js"
    },
    "./internal/flags/tracing": {
      "default": "./src/internal/flags/tracing.js"
    },
    "./internal/server": {
      "default": "./src/internal/server/index.js"
    },
    "./legacy": {
      "types": "./types/index.d.ts",
      "worker": "./src/legacy/legacy-server.js",
      "browser": "./src/legacy/legacy-client.js",
      "default": "./src/legacy/legacy-server.js"
    },
    "./motion": {
      "types": "./types/index.d.ts",
      "default": "./src/motion/index.js"
    },
    "./reactivity": {
      "types": "./types/index.d.ts",
      "worker": "./src/reactivity/index-server.js",
      "browser": "./src/reactivity/index-client.js",
      "default": "./src/reactivity/index-server.js"
    },
    "./reactivity/window": {
      "types": "./types/index.d.ts",
      "default": "./src/reactivity/window/index.js"
    },
    "./server": {
      "types": "./types/index.d.ts",
      "default": "./src/server/index.js"
    },
    "./store": {
      "types": "./types/index.d.ts",
      "worker": "./src/store/index-server.js",
      "browser": "./src/store/index-client.js",
      "default": "./src/store/index-server.js"
    },
    "./transition": {
      "types": "./types/index.d.ts",
      "default": "./src/transition/index.js"
    },
    "./events": {
      "types": "./types/index.d.ts",
      "default": "./src/events/index.js"
    }
  },
}

@JounQin
Copy link
Member

JounQin commented Apr 17, 2025

This is a known issue and we want to resolve this in next major:

import-js/eslint-plugin-import#1479

#235 (comment)

cc @SukkaW

@vladshcherbin
Copy link

Does it resolves if used with any next resolvers current version?

@JounQin
Copy link
Member

JounQin commented May 17, 2025

Does it resolves if used with any next resolvers current version?

Unless you don't use resolver-typescript which prefers .d.ts over .js. For example use createNodeResolver instead.

But this would have other issues, for example, if A is a type, import {A} from 'foo' will results A not found in exports for Node resolver but typescript resolver just works.

In the meantime, I think an ESLint disable comment is good enough.

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

No branches or pull requests

3 participants