[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: \"\"\nlabels: \"\"\nassignees: \"\"\n---\n\n# Please follow the general troubleshooting steps first:\n\nIf the issue is with something being marked wrongly as a unused import and therefore being removed. It is an issue with the imported package (`@typescript-eslint/eslint-plugin` for TS or `eslint` for JS) and its `no-unused-vars` rule. I cannot do anything about this except updating if a fix is made upstream.\n\nIf new rules are added `no-unused-vars` upstream which should be autofixed, mark your issue _rule addition_.\n\nNow if something is not marked an import and being removed by the autofixer, it is an issue I can do something about.\n\nPlease replace the above with a brief summary of your issue.\n\n### Features:\n\n**Please note by far the quickest way to get a new feature is to file a Pull Request.**\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\n\non:\n  push:\n    tags:\n      - 'v*'\n\njobs:\n  release:\n    uses: sxzz/workflows/.github/workflows/release.yml@v1\n    with:\n      publish: true\n    permissions:\n      contents: write\n      id-token: write\n"
  },
  {
    "path": ".github/workflows/run_test.yml",
    "content": "# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node\n# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs\n\nname: Node.js CI\n\non:\n  push:\n    branches: [ \"master\" ]\n  pull_request:\n    branches: [ \"master\" ]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        node-version: [18.x, 20.x]\n        # See supported Node.js release schedule at https://nodejs.org/en/about/releases/\n\n    steps:\n    - uses: actions/checkout@v4\n    - uses: pnpm/action-setup@v4\n    - name: Use Node.js ${{ matrix.node-version }}\n      uses: actions/setup-node@v4\n      with:\n        node-version: ${{ matrix.node-version }}\n    - run: pnpm install\n    - run: pnpm run build\n    - run: pnpm test\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\n.idea\ndist\n"
  },
  {
    "path": ".prettierrc.js",
    "content": "module.exports = {\n    tabWidth: 4,\n    semi: true, // Trailing semicolons\n    trailingComma: \"all\",\n    singleQuote: false,\n    quoteProps: \"as-needed\",\n    bracketSpacing: true,\n    printWidth: 100, // Line width (this fit my 1440p screen at a half-screen window)\n    arrowParens: \"always\",\n};\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n    // Use IntelliSense to learn about possible attributes.\n    // Hover to view descriptions of existing attributes.\n    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n    \"version\": \"0.1.0\",\n    \"configurations\": [\n        {\n            \"type\": \"node\",\n            \"request\": \"launch\",\n            \"name\": \"Debug current test file\",\n            \"runtimeExecutable\": \"npm\",\n            \"runtimeArgs\": [\"test\", \"--testPathPattern\", \"${file}\", \"--coverage\", \"false\"],\n            \"port\": 9229,\n            \"cwd\": \"${fileDirname}\",\n            \"timeout\": 10000,\n            \"console\": \"integratedTerminal\"\n        }\n    ]\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2022 Mikkel Holmer Pedersen\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# eslint-plugin-unused-imports\n\nFind and remove unused es6 module imports. It works by splitting up the `no-unused-vars` rule depending on it being an import statement in the AST and providing an autofix rule to remove the nodes if they are imports. This plugin composes the rule `no-unused-vars` of either the typescript or js plugin so be aware that the other plugins needs to be installed and reporting correctly for this to do so.\n\n## _Versions_\n\n-   Version 4.1.x is for eslint 9 with @typescript-eslint/eslint-plugin 5 - 8\n-   Version 4.0.x is for eslint 9 with @typescript-eslint/eslint-plugin 8\n-   Version 3.x.x is for eslint 8 with @typescript-eslint/eslint-plugin 6 - 7\n-   Version 2.x.x is for eslint 8 with @typescript-eslint/eslint-plugin 5\n-   Version 1.x.x is for eslint 6 and 7.\n\n## Typescript\n\nIf running typescript with [@typescript-eslint](https://github.com/typescript-eslint/typescript-eslint) make sure to use both `@typescript-eslint/eslint-plugin` and `@typescript-eslint/parser`.\n\n## React\n\nIf writing react code you need to install `eslint-plugin-react` and enable the two rules `react/jsx-uses-react` and `react/jsx-uses-vars`. Otherwise all imports for components will be reported unused.\n\n## Installation\n\nYou'll first need to install [ESLint](http://eslint.org) (and [@typescript-eslint](https://github.com/typescript-eslint/typescript-eslint) if using typescript):\n\n```bash\nnpm i eslint --save-dev\n```\n\nNext, install `eslint-plugin-unused-imports`:\n\n```bash\nnpm install eslint-plugin-unused-imports --save-dev\n```\n\n**Note:** If you installed ESLint globally (using the `-g` flag) then you must also install `eslint-plugin-unused-imports` globally.\n\n## Usage\n\nAdd `unused-imports` to the plugins section of your `eslint.config.js` configuration file.\n\n```js\nimport unusedImports from \"eslint-plugin-unused-imports\";\n\nexport default [{\n    plugins: {\n        \"unused-imports\": unusedImports,\n    },\n    rules: {\n        \"no-unused-vars\": \"off\", // or \"@typescript-eslint/no-unused-vars\": \"off\",\n        \"unused-imports/no-unused-imports\": \"error\",\n        \"unused-imports/no-unused-vars\": [\n            \"warn\",\n            {\n                \"vars\": \"all\",\n                \"varsIgnorePattern\": \"^_\",\n                \"args\": \"after-used\",\n                \"argsIgnorePattern\": \"^_\",\n            },\n        ]\n    }\n}];\n```\n\n## Supported Rules\n\n-   `no-unused-imports`\n-   `no-unused-vars`\n"
  },
  {
    "path": "docs/rules/no-unused-imports.md",
    "content": "# Do not allow unused imports (no-unused-imports)\n\nA rule to find unused-imports only, as well as an autofixer.\n"
  },
  {
    "path": "docs/rules/no-unused-vars.md",
    "content": "# Do not allow unused vars (no-unused-vars)\n\nThis is just a helper rule to filter out the things caught by\nthe `no-unused-imports` rule without double warnings. As\nwell as being able to set them at different warning levels.\n"
  },
  {
    "path": "package.json",
    "content": "{\n    \"name\": \"eslint-plugin-unused-imports\",\n    \"version\": \"4.4.1\",\n    \"type\": \"commonjs\",\n    \"packageManager\": \"pnpm@10.18.3\",\n    \"description\": \"Report and remove unused es6 modules\",\n    \"keywords\": [\n        \"eslint\",\n        \"eslintplugin\",\n        \"eslint-plugin\",\n        \"import\",\n        \"unused\",\n        \"modules\",\n        \"autofix\"\n    ],\n    \"author\": \"Mikkel Holmer Pedersen\",\n    \"main\": \"dist/index.js\",\n    \"types\": \"dist/index.d.ts\",\n    \"exports\": {\n        \".\": {\n            \"import\": \"./dist/index.mjs\",\n            \"require\": \"./dist/index.js\"\n        }\n    },\n    \"files\": [\n        \"dist\"\n    ],\n    \"scripts\": {\n        \"build\": \"tsup\",\n        \"test\": \"vitest\",\n        \"format\": \"prettier --write '**/*.[jt]s'\",\n        \"prepack\": \"npm run build\",\n        \"release\": \"bumpp\"\n    },\n    \"peerDependencies\": {\n        \"@typescript-eslint/eslint-plugin\": \"^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0\",\n        \"eslint\": \"^10.0.0 || ^9.0.0 || ^8.0.0\"\n    },\n    \"peerDependenciesMeta\": {\n        \"@typescript-eslint/eslint-plugin\": {\n            \"optional\": true\n        }\n    },\n    \"devDependencies\": {\n        \"@types/eslint\": \"^9.6.1\",\n        \"@typescript-eslint-v5/eslint-plugin\": \"npm:@typescript-eslint/eslint-plugin@^5.62.0\",\n        \"@typescript-eslint-v5/parser\": \"npm:@typescript-eslint/parser@^5.62.0\",\n        \"@typescript-eslint-v6/eslint-plugin\": \"npm:@typescript-eslint/eslint-plugin@^6.21.0\",\n        \"@typescript-eslint-v6/parser\": \"npm:@typescript-eslint/parser@^6.21.0\",\n        \"@typescript-eslint-v7/eslint-plugin\": \"npm:@typescript-eslint/eslint-plugin@^7.18.0\",\n        \"@typescript-eslint-v7/parser\": \"npm:@typescript-eslint/parser@^7.18.0\",\n        \"@typescript-eslint/eslint-plugin\": \"^8.46.1\",\n        \"@typescript-eslint/parser\": \"^8.46.1\",\n        \"@typescript-eslint/utils\": \"^8.46.1\",\n        \"bumpp\": \"^10.3.1\",\n        \"eslint\": \"^9.37.0\",\n        \"prettier\": \"^3.6.2\",\n        \"tsup\": \"^8.5.0\",\n        \"typescript\": \"^5.9.3\",\n        \"typescript-eslint\": \"^8.46.1\",\n        \"vitest\": \"^3.2.4\"\n    },\n    \"license\": \"MIT\",\n    \"repository\": {\n        \"type\": \"git\",\n        \"url\": \"git+https://github.com/sweepline/eslint-plugin-unused-imports.git\"\n    },\n    \"homepage\": \"https://github.com/sweepline/eslint-plugin-unused-imports\",\n    \"bugs\": \"https://github.com/sweepline/eslint-plugin-unused-imports/issues\"\n}\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "onlyBuiltDependencies:\n  - esbuild\n"
  },
  {
    "path": "src/__test__/cases-js.ts",
    "content": "export default {\n    valid: [\n        {\n            code: `\nimport x from \"package\";\nimport { a, b } from \"./utils\";\nimport y from \"package\";\n\nconst c = a() + b + x() + y();\n`,\n        },\n        {\n            code: `\nimport { NoAuthenticationGuard } from \"./no-authentication.guard\";\nimport { JwtAuthenticationGuard } from \"./jwt-authentication.guard\";\n\n/**\n * You can reference {@link NoAuthenticationGuard} instead.\n * It's recommended to use the {@link JwtAuthenticationGuard}.\n */\nconst LOCAL_ENVIRONMENT_AUTHENTICATION_GUARD = JwtAuthenticationGuard;\n`,\n        },\n        {\n            code: `\nimport { SomeClass } from \"./some-class\";\n\n/**\n * @see SomeClass\n */\nconst example = \"test\";\n`,\n        },\n        {\n            code: `\nimport { MyType } from \"./types\";\n\n/**\n * @type {MyType}\n */\nlet value;\n`,\n        },\n        {\n            code: `\nimport { Config } from \"./config\";\n\n/**\n * @param {Config} config - The configuration object\n */\nfunction setup(config) {}\n`,\n        },\n    ],\n\n    invalid: [\n        {\n            code: `\nimport x from \"package\";\nimport { a, b } from \"./utils\";\nimport y from \"package\";\n\nconst c = b(x, y);\n`,\n            errors: [\"'a' is defined but never used.\"],\n            output: `\nimport x from \"package\";\nimport { b } from \"./utils\";\nimport y from \"package\";\n\nconst c = b(x, y);\n`,\n        },\n        {\n            code: `\nimport { a, b } from \"./utils\";\nimport y from \"package\";\n\n/**\n * this is a jsdoc!\n */\nconst c = a(y);\n`,\n            errors: [\"'b' is defined but never used.\"],\n            output: `\nimport { a } from \"./utils\";\nimport y from \"package\";\n\n/**\n * this is a jsdoc!\n */\nconst c = a(y);\n`,\n        },\n        {\n            code: `\nimport { a } from \"./utils\";\nimport y from \"package\";\n\nconst c = 4;\nconsole.log(y);\n`,\n            errors: [\"'a' is defined but never used.\"],\n            output: `\nimport y from \"package\";\n\nconst c = 4;\nconsole.log(y);\n`,\n        },\n        {\n            code: `\nimport y from \"package\";\nimport { a } from \"./utils\";\n\n/**\n * c is the number 4\n */\nconst c = 4;\nconsole.log(y);\n`,\n            errors: [\"'a' is defined but never used.\"],\n            output: `\nimport y from \"package\";\n\n/**\n * c is the number 4\n */\nconst c = 4;\nconsole.log(y);\n`,\n        },\n        {\n            code: `\nimport { UnusedClass } from \"./unused\";\nimport { UsedInJSDoc } from \"./used\";\n\n/**\n * Reference to {@link UsedInJSDoc}\n */\nconst example = \"test\";\n`,\n            errors: [\"'UnusedClass' is defined but never used.\"],\n            output: `\nimport { UsedInJSDoc } from \"./used\";\n\n/**\n * Reference to {@link UsedInJSDoc}\n */\nconst example = \"test\";\n`,\n        },\n    ],\n};\n"
  },
  {
    "path": "src/__test__/cases-ts.ts",
    "content": "export default {\n    valid: [\n        {\n            code: `\nimport x from \"package\";\nimport { a, b } from \"./utils\";\nimport y from \"package\";\nimport TType from \"Package\";\n\nconst c: TType = a() + b + x() + y();\n`,\n        },\n        {\n            code: `\nimport { NoAuthenticationGuard } from \"./no-authentication.guard\";\nimport { JwtAuthenticationGuard } from \"./jwt-authentication.guard\";\n\n/**\n * You can reference {@link NoAuthenticationGuard} instead.\n * It's recommended to use the {@link JwtAuthenticationGuard}.\n */\nconst LOCAL_ENVIRONMENT_AUTHENTICATION_GUARD = JwtAuthenticationGuard;\n`,\n        },\n        {\n            code: `\nimport type { SomeType } from \"./types\";\n\n/**\n * @see SomeType for more details\n */\nconst example = \"test\";\n`,\n        },\n        {\n            code: `\nimport type { Config } from \"./config\";\n\n/**\n * @param {Config} config - The configuration object\n */\nfunction setup(config: any) {}\n`,\n        },\n    ],\n\n    invalid: [\n        {\n            code: `\nimport x from \"package\";\nimport { a, b } from \"./utils\";\nimport y from \"package\";\nimport TType from \"Package\";\n\nconst c = a() + b + x() + y();\n`,\n            errors: [\"'TType' is defined but never used.\"],\n            output: `\nimport x from \"package\";\nimport { a, b } from \"./utils\";\nimport y from \"package\";\n\nconst c = a() + b + x() + y();\n`,\n        },\n        {\n            code: `\nimport type { UnusedType } from \"./unused\";\nimport type { UsedInJSDoc } from \"./used\";\n\n/**\n * Reference to {@link UsedInJSDoc}\n */\nconst example = \"test\";\n`,\n            errors: [\"'UnusedType' is defined but never used.\"],\n            output: `\nimport type { UsedInJSDoc } from \"./used\";\n\n/**\n * Reference to {@link UsedInJSDoc}\n */\nconst example = \"test\";\n`,\n        },\n    ],\n};\n"
  },
  {
    "path": "src/__test__/no-unused-imports.test.ts",
    "content": "import { RuleTester } from \"eslint\";\nimport casesJS from \"./cases-js\";\nimport casesTS from \"./cases-ts\";\nimport { it, describe } from \"vitest\";\nimport { createRuleWithPredicate, unusedImportsPredicate } from \"../rules/predicates\";\nimport { getESLintBaseRule } from \"../rules/load-rule\";\n\nconst parsers = [\n    {\n        name: \"eslint\",\n        parser: undefined,\n        rule: getESLintBaseRule(),\n    },\n    {\n        name: \"typescript-eslint v8\",\n        parser: await import(\"@typescript-eslint/parser\").then((r) => r.default),\n        rule: await import(\"@typescript-eslint/eslint-plugin\").then(\n            (r) => r.rules[\"no-unused-vars\"],\n        ),\n    },\n    {\n        name: \"typescript-eslint v7\",\n        parser: await import(\"@typescript-eslint-v7/parser\").then((r) => r.default),\n        rule: await import(\"@typescript-eslint-v7/eslint-plugin\").then(\n            (r) => r.rules[\"no-unused-vars\"],\n        ),\n    },\n    {\n        name: \"typescript-eslint v6\",\n        parser: await import(\"@typescript-eslint-v6/parser\").then((r) => r.default),\n        rule: await import(\"@typescript-eslint-v6/eslint-plugin\").then(\n            (r) => r.rules[\"no-unused-vars\"],\n        ),\n    },\n    {\n        name: \"typescript-eslint v5\",\n        parser: await import(\"@typescript-eslint-v5/parser\").then((r) => r.default),\n        rule: await import(\"@typescript-eslint-v5/eslint-plugin\").then(\n            (r) => r.rules[\"no-unused-vars\"],\n        ),\n    },\n];\n\ndescribe(\"no-unused-imports\", () => {\n    for (const { name, parser, rule: baseRule } of parsers) {\n        it(`with ${name}`, () => {\n            const ruleTester = new RuleTester({\n                languageOptions: {\n                    parser,\n                    ecmaVersion: 2015,\n                    sourceType: \"module\",\n                },\n            });\n\n            const rule = createRuleWithPredicate(\n                \"no-unused-imports\",\n                baseRule,\n                unusedImportsPredicate,\n            );\n\n            ruleTester.run(\"no-unused-imports\", rule, casesJS);\n\n            if (name !== \"eslint\") {\n                ruleTester.run(\"no-unused-imports\", rule, casesTS);\n            }\n        });\n    }\n});\n"
  },
  {
    "path": "src/index.ts",
    "content": "/**\n * @fileoverview Find and remove unused es6 modules\n * @author Mikkel Holmer Pedersen\n */\nimport noUnusedVars from \"./rules/no-unused-vars\";\nimport noUnusedImports from \"./rules/no-unused-imports\";\nimport { ESLint } from \"eslint\";\n\nconst plugin: ESLint.Plugin = {\n    meta: {\n        name: \"unused-imports\",\n    },\n    rules: {\n        \"no-unused-vars\": noUnusedVars,\n        \"no-unused-imports\": noUnusedImports,\n    },\n};\n\nexport default plugin;\n"
  },
  {
    "path": "src/rules/load-rule.ts",
    "content": "import { Rule } from \"eslint\";\nimport { createRequire } from \"module\";\n\nlet rule: Rule.RuleModule | undefined;\n\nconst require = createRequire(import.meta.url);\n\nexport function getBaseRule(): Rule.RuleModule {\n    if (!rule) {\n        rule = getRuleFromTSLintPlugin() ?? getRuleFromTSLint() ?? getESLintBaseRule();\n    }\n    return rule!;\n}\n\nexport function getRuleFromTSLintPlugin() {\n    try {\n        const tslintPlugin = require(\"@typescript-eslint/eslint-plugin\");\n        return tslintPlugin.rules[\"no-unused-vars\"];\n    } catch (_) {\n        return null;\n    }\n}\n\nexport function getRuleFromTSLint() {\n    try {\n        const tslint = require(\"typescript-eslint\");\n        return tslint.plugin.rules[\"no-unused-vars\"];\n    } catch (_) {\n        return null;\n    }\n}\n\nexport function getESLintBaseRule() {\n    try {\n        const eslint = require(\"eslint\");\n        return new eslint.Linter({ configType: \"eslintrc\" }).getRules().get(\"no-unused-vars\");\n    } catch {\n        // since ESLint 10.0.0, new Linter({ configType: \"eslintrc\" }) will now throw an TypeError explicitly:\n        // https://github.com/eslint/eslint/blob/b69cfb32a16c5d5e9986390d484fae1d21e406f9/lib/linter/linter.js#L757\n        //\n        // This means we can catch the error and load the rule from an unsafe API:\n        const eslint_USE_AT_YOUR_OWN_RISK = require(\"eslint/use-at-your-own-risk\");\n        // builtinRules was added since ESLint 8.0.0 and was mentioned in ESLint's \"Migrate to ESLint 8.0.0\" guide:\n        // https://eslint.org/docs/latest/use/migrate-to-8.0.0#-the-cliengine-class-has-been-removed\n        //\n        // However, it's still considered an unstable API and may change without a major version bump. We need to guard the access.\n        if ('builtinRules' in eslint_USE_AT_YOUR_OWN_RISK && eslint_USE_AT_YOUR_OWN_RISK.builtinRules instanceof Map) {\n            return eslint_USE_AT_YOUR_OWN_RISK.builtinRules.get(\"no-unused-vars\");\n        }\n        throw new TypeError(\"[eslint-plugin-unused-imports] Cannot load 'no-unused-vars' rule from ESLint. This is most likely due to a breaking change in ESLint's internal API. Please report this issue to 'eslint-plugin-unused-imports'.\");\n    }\n}\n"
  },
  {
    "path": "src/rules/no-unused-imports.ts",
    "content": "/**\n * @fileoverview Add fixer to imports in no-unused-vars.\n * @author Mikkel Holmer Pedersen <mikkel@holmerp.dk>\n */\nimport { unusedImportsPredicate, createRuleWithPredicate } from \"./predicates\";\n\nimport { getBaseRule } from \"./load-rule\";\n\nexport default createRuleWithPredicate(\"no-unused-imports\", getBaseRule(), unusedImportsPredicate);\n"
  },
  {
    "path": "src/rules/no-unused-vars.ts",
    "content": "/**\n * @fileoverview Filter imports from no-unused-vars.\n * @author Mikkel Holmer Pedersen <mikkel@holmerp.dk>\n */\nimport { createRuleWithPredicate, unusedVarsPredicate } from \"./predicates\";\n\nimport { getBaseRule } from \"./load-rule\";\n\nexport default createRuleWithPredicate(\"no-unused-vars\", getBaseRule(), unusedVarsPredicate);\n"
  },
  {
    "path": "src/rules/predicates.ts",
    "content": "import { SourceCode, AST, Rule } from \"eslint\";\n\nexport type Predicate = (\n    problem: Rule.ReportDescriptor,\n    context: Rule.RuleContext,\n) => Rule.ReportDescriptor | false;\n\nconst commaFilter = { filter: (token: AST.Token) => token.value === \",\" };\nconst includeCommentsFilter = { includeComments: true };\n\n/**\n * Check if an identifier is referenced in JSDoc comments\n * Looks for JSDoc tags like @link, @see, @type, etc.\n */\nfunction isUsedInJSDoc(identifierName: string, sourceCode: SourceCode): boolean {\n    const comments = sourceCode.getAllComments();\n\n    // JSDoc tags that can reference identifiers\n    // Pattern matches: {@link Name}, {@see Name}, @type {Name}, etc.\n    const jsdocPattern = new RegExp(\n        // {@link Name} or @see Name\n        `(?:@(?:link|linkcode|linkplain|see)\\\\s+${identifierName}\\\\b)|` + \n        // {@link Name}\n        `(?:\\\\{@(?:link|linkcode|linkplain)\\\\s+${identifierName}\\\\b\\\\})|` + \n        // @type {Name}, @param {Name}, etc.\n        `(?:[@{](?:type|typedef|param|returns?|template|augments|extends|implements)\\\\s+[^}]*\\\\b${identifierName}\\\\b)`, \n    );\n\n    return comments.some((comment) => {\n        // Only check block comments (/* ... */) as JSDoc uses block comment syntax\n        if (comment.type !== \"Block\") {\n            return false;\n        }\n\n        return jsdocPattern.test(comment.value);\n    });\n}\n\nfunction makePredicate(\n    isImport: boolean,\n    addFixer?: (parent: any, sourceCode: SourceCode) => Partial<Rule.ReportDescriptor> | boolean,\n): Predicate {\n    return (problem, context) => {\n        const sourceCode = context.sourceCode || context.getSourceCode();\n\n        const node =\n            (problem as any).node ??\n            // typescript-eslint >= 7.8 sets a range instead of a node\n            sourceCode.getNodeByRangeIndex(sourceCode.getIndexFromLoc((problem as any).loc.start));\n\n        const { parent } = node;\n\n        // Check if this is an import and if it's used in JSDoc comments\n        if (parent && /^Import(|Default|Namespace)Specifier$/.test(parent.type) && isImport) {\n            const identifierName = node.name;\n            if (identifierName && isUsedInJSDoc(identifierName, sourceCode)) {\n                // Don't report if used in JSDoc\n                return false;\n            }\n        }\n\n        return parent\n            ? /^Import(|Default|Namespace)Specifier$/.test(parent.type) == isImport\n                ? Object.assign(problem, addFixer?.(parent, sourceCode))\n                : false\n            : isImport\n              ? false\n              : problem;\n    };\n}\n\nexport const unusedVarsPredicate = makePredicate(false);\n\nexport const unusedImportsPredicate = makePredicate(true, (parent, sourceCode) => ({\n    fix(fixer) {\n        const grandParent = parent.parent;\n\n        if (!grandParent) {\n            return null;\n        }\n\n        // Only one import\n        if (grandParent.specifiers.length === 1) {\n            const nextToken = sourceCode.getTokenAfter(grandParent, includeCommentsFilter);\n            const newLinesBetween = nextToken\n                ? nextToken.loc!.start.line - grandParent.loc.start.line\n                : 0;\n            const endOfReplaceRange = nextToken ? nextToken.range![0] : grandParent.range[1];\n            const count = Math.max(0, newLinesBetween - 1);\n\n            return [\n                fixer.remove(grandParent),\n                fixer.replaceTextRange(\n                    [grandParent.range[1], endOfReplaceRange],\n                    \"\\n\".repeat(count),\n                ),\n            ];\n        }\n\n        // Not last specifier\n        if (parent !== grandParent.specifiers[grandParent.specifiers.length - 1]) {\n            const comma = sourceCode.getTokenAfter(parent, commaFilter)!;\n            const prevNode = sourceCode.getTokenBefore(parent)!;\n\n            return [\n                fixer.removeRange([prevNode.range[1], parent.range![0]]),\n                fixer.remove(parent),\n                fixer.remove(comma),\n            ];\n        }\n\n        // Default export and a single normal left, ex. \"import default, { package1 } from 'module';\"\n        if (\n            grandParent.specifiers.filter((specifier) => specifier.type === \"ImportSpecifier\")\n                .length === 1\n        ) {\n            const start = sourceCode.getTokenBefore(parent, commaFilter)!;\n            const end = sourceCode.getTokenAfter(parent, {\n                filter: (token) => token.value === \"}\",\n            })!;\n\n            return fixer.removeRange([start.range[0], end.range[1]]);\n        }\n\n        return fixer.removeRange([\n            sourceCode.getTokenBefore(parent, commaFilter)!.range[0],\n            parent.range[1],\n        ]);\n    },\n}));\n\nexport function createRuleWithPredicate(\n    name: string,\n    baseRule: Rule.RuleModule,\n    predicate: Predicate,\n): Rule.RuleModule {\n    return {\n        ...baseRule,\n        meta: {\n            ...baseRule.meta,\n            fixable: \"code\",\n            docs: {\n                ...baseRule.meta?.docs,\n                url: `https://github.com/sweepline/eslint-plugin-unused-imports/blob/master/docs/rules/${name}.md`,\n            },\n        },\n        create(context) {\n            return baseRule.create(\n                Object.create(context, {\n                    report: {\n                        enumerable: true,\n                        value(problem: Rule.ReportDescriptor) {\n                            const result = predicate(problem, context);\n                            if (result) {\n                                context.report(result);\n                            }\n                        },\n                    },\n                }),\n            );\n        },\n    };\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Bundler\",\n    \"skipLibCheck\": true,\n    \"noEmit\": true,\n  }\n}\n"
  },
  {
    "path": "tsup.config.ts",
    "content": "import { defineConfig } from \"tsup\";\n\nexport default defineConfig({\n    entryPoints: [\"src/index.ts\"],\n    format: [\"cjs\", \"esm\"],\n    dts: true,\n    clean: true,\n    splitting: true,\n    shims: true,\n    cjsInterop: true,\n    external: [\"eslint\", \"@typescript-eslint/eslint-plugin\"],\n});\n"
  },
  {
    "path": "vitest.config.ts",
    "content": "import { defineConfig } from \"vitest/config\";\n\nexport default defineConfig({\n    test: {\n        globals: true,\n    },\n});\n"
  }
]