Skip to content

linter: react/jsx-filename-extension doesn't include the filename in the diagnostic #19171

@GauthierPLM

Description

@GauthierPLM

What version of Oxlint are you using?

1.43.0

What command did you run?

oxlint --type-aware

What does your .oxlintrc.json config file look like?

import { defineConfig, type OxlintConfig, type OxlintEnv } from "oxlint";

const baseEnv: OxlintEnv = {
  builtin: true,
  "shared-node-browser": true,
  es2024: true,
};

export default defineConfig({
  plugins: [
    "oxc",
    "eslint",
    "import",
    "node",
    "promise",
    "react",
    "react-perf",
    "typescript",
    "unicorn",
    "vitest",
  ],
  /*categories: {
    correctness: "error",
    perf: "warn",
    suspicious: "warn",
    restriction: "warn",
  },*/
  env: baseEnv,
  ignorePatterns: [
    // IDE files
    ".idea/",
    // Linter / formater config files
    "**/prettier.config.mjs",
    "**/eslint.config.mjs",
    "packages/config/eslint/**/*.mjs",
    // Generated directories
    "**/dist/",
    "**/generated/",
    "**/node_modules/",
    // Other files
    "**/.storybook/",
    "apps/*/codegen.ts",
    "packages/shared-ui/schema.graphql",
    "packages/database/prisma/seeds/**/*.json",
    "packages/shared-ui/codegen-base.ts",
  ],
  rules: {
    // Eslint rules
    "no-unused-vars": [
      "error",
      {
        argsIgnorePattern: "^_",
        caughtErrors: "none",
      },
    ],

    // Import rules
    "import/default": "error",
    "import/extensions": ["error", { checkTypeImports: true }],
    "import/first": "error",
    "import/named": "error",
    "import/namespace": "error",
    "import/no-absolute-path": "error",
    "import/no-amd": "error",
    "import/no-commonjs": "error",
    "import/no-cycle": "error",
    "import/no-default-export": "error",
    "import/no-duplicates": ["error", { preferInline: true }],
    "import/no-dynamic-require": "error",
    "import/no-empty-named-blocks": "error",
    "import/no-mutable-exports": "error",
    "import/no-named-as-default": "error",
    "import/no-named-as-default-member": "error",
    "import/no-named-default": "error",
    //"import/no-namespace": "error",
    "import/no-self-import": "error",
    "import/no-unassigned-import": ["error", { allow: ["**/*.css"] }],
    "import/no-webpack-loader-syntax": "error",
    //"import/unambiguous": "error",

    // Node rules
    "node/no-process-env": "error",

    // Oxc rules
    "oxc/approx-constant": "error",
    "oxc/bad-bitwise-operator": "error",
    "oxc/branches-sharing-code": "warn",
    "oxc/misrefactored-assign-op": "error",
    "oxc/no-accumulating-spread": "error",
    //"oxc/no-barrel-file": "error",
    "oxc/no-const-enum": "error",
    //"oxc/no-map-spread": ["error", { ignoreRereads: true }],
    "oxc/no-this-in-exported-function": "error",

    // React rules
    "react/display-name": "error",
    "react/exhaustive-deps": "off",
    "react/forward-ref-uses-ref": "error",
    "react/rules-of-hooks": "error",
    "react/iframe-missing-sandbox": "error",
    "react/jsx-boolean-value": ["error", "never"],
    "react/jsx-filename-extension": [
      "error",
      { allow: "as-needed", extensions: [".tsx"] },
    ],

    // Typescript rules
    "typescript/adjacent-overload-signatures": "error",
    "typescript/array-type": ["error", { default: "array" }],
    "typescript/ban-ts-comment": "error",
    "typescript/ban-tslint-comment": "error",
    "typescript/ban-types": "error",
    "typescript/consistent-generic-constructors": "error",
    "typescript/consistent-indexed-object-style": ["error", "record"],
    "typescript/consistent-type-definitions": "error",
    //"typescript/consistent-type-imports": "error",
    //"typescript/explicit-function-return-type": "error",
    //"typescript/explicit-module-boundary-types": "error",
    "typescript/no-confusing-non-null-assertion": "error",
    "typescript/no-confusing-void-expression": [
      "error",
      {
        ignoreArrowShorthand: true,
        ignoreVoidReturningFunctions: true,
      },
    ],
    "typescript/no-deprecated": "error",
    "typescript/no-dynamic-delete": "error",
    "typescript/no-empty-interface": "error",
    "typescript/no-empty-object-type": "error",
    //"typescript/no-explicit-any": "error",
    "typescript/no-extraneous-class": "error",
    "typescript/no-floating-promises": [
      "off",
      {
        ignoreIIFE: true,
        ignoreVoid: true,
      },
    ],
    "typescript/no-import-type-side-effects": "error",
    "typescript/no-inferrable-types": "error",
    //"typescript/no-misused-promises": "error",
    "typescript/no-mixed-enums": "error",
    "typescript/no-namespace": "error",
    "typescript/no-non-null-asserted-nullish-coalescing": "error",
    //"typescript/no-non-null-assertion": "error",
    "typescript/no-require-imports": "error",
    "typescript/no-unnecessary-boolean-literal-compare": "error",
    "typescript/no-unnecessary-template-expression": "error",
    "typescript/no-unnecessary-type-arguments": "error",
    "typescript/no-unnecessary-type-assertion": [
      "error",
      {
        checkLiteralConstAssertions: true,
      },
    ],
    "typescript/no-unnecessary-type-constraint": "error",
    //"typescript/no-unsafe-argument": "error",
    //"typescript/no-unsafe-assignment": "error",
    //"typescript/no-unsafe-call": "error",
    //"typescript/no-unsafe-enum-comparison": "error",
    "typescript/no-unsafe-function-type": "error",
    //"typescript/no-unsafe-member-access": "error",
    //"typescript/no-unsafe-return": "error",
    //"typescript/no-unsafe-type-assertion": "error",
    "typescript/no-unsafe-unary-minus": "error",
    "typescript/no-useless-empty-export": "error",
    "typescript/non-nullable-type-assertion-style": "error",
    "typescript/only-throw-error": "error",
    "typescript/prefer-enum-initializers": "error",
    "typescript/prefer-for-of": "error",
    "typescript/prefer-function-type": "error",
    "typescript/prefer-includes": "error",
    "typescript/prefer-literal-enum-member": "error",
    //"typescript/prefer-nullish-coalescing": "error",
    //"typescript/prefer-optional-chain": "error",
    "typescript/prefer-promise-reject-errors": "error",
    "typescript/prefer-reduce-type-parameter": "error",
    "typescript/prefer-return-this-type": "error",
    "typescript/promise-function-async": "error",
    "typescript/related-getter-setter-pairs": "error",
    //"typescript/require-await": "error",
    "typescript/restrict-plus-operands": "error",
    //"typescript/return-await": "error",
    //"typescript/strict-boolean-expressions": "error",
    //"typescript/switch-exhaustiveness-check": "error",
    //"typescript/use-unknown-in-catch-callback-variable": "error",

    // Vitest rules
    "vitest/consistent-vitest-vi": ["error", { fn: "vi" }],
    "vitest/consistent-test-filename": ["error"],
    "vitest/hoisted-apis-on-top": "error",
    "vitest/no-conditional-tests": "error",
    "vitest/no-import-node-test": "error",
    "vitest/prefer-called-once": "error",
    "vitest/prefer-describe-function-title": "error",
    "vitest/prefer-to-be-falsy": "error",
    "vitest/prefer-to-be-object": "error",
    "vitest/prefer-to-be-truthy": "error",
    "vitest/require-local-test-context-for-concurrent-snapshots": "error",
    "vitest/warn-todo": "error",
  },
  overrides: [
    // Node packages
    {
      files: ["apps/api/**/*.ts", "packages/database/**/*.ts"],
      env: {
        ...baseEnv,
        node: true,
      },
      rules: {
        "typescript/no-extraneous-class": [
          "error",
          {
            // Required for NestJS module declarations
            allowWithDecorator: true,
          },
        ],
      },
    },
    {
      files: [
        "apps/api/src/app.module.ts",
        "apps/api/src/utils/telemetry/sentry.ts",
        "apps/api/tests/setup/*.ts",
        "apps/api/tests/utils/db.ts",
        "packages/typesense/src/scripts/utils.ts",
      ],
      env: {
        ...baseEnv,
        node: true,
      },
      rules: {
        // process.env is needed as there is no service to load environment variables
        "node/no-process-env": "off",
      },
    },
    {
      files: ["apps/api/src/**/*.test.ts", "apps/api/tests/**/*.ts"],
      rules: {
        "typescript/no-misused-spread": "off",
        "typescript/unbound-method": "off",
      },
    },
    // React packages
    {
      files: [
        "apps/admin-ui/**/*.{ts,tsx}",
        "apps/editor-ui/**/*.{ts,tsx}",
        "apps/ui/**/*.{ts,tsx}",
        "packages/shared-ui/**/*.{ts,tsx}",
      ],
      env: {
        ...baseEnv,
        browser: true,
      },
    },
    // Config files
    {
      files: [
        "commitlint.config.ts",
        "oxlint.config.ts",
        "prisma.config.ts",
        "tsdown.config.mts",
        "**/vite.config.ts",
        "**/vitest.config.ts",
      ],
      env: {
        ...baseEnv,
        node: true,
      },
      rules: {
        // Config files are not meant to have a default export to load the defined configuration
        "import/no-default-export": "off",
        // Config files often use process.env to load environment variables
        "node/no-process-env": "off",
      },
    },
    // Storybook files
    {
      files: ["**/*.stories.tsx"],
      env: {
        ...baseEnv,
        browser: true,
      },
      rules: {
        // Storybook requires a default export
        "import/no-default-export": "off",
      },
    },
  ],
} satisfies OxlintConfig);

What happened?

When rule react/jsx-filename-extension finds a .jsx file without JSX in it, the warning/error message does not contain the name of said file. After enabling the rule, we have 50 errors but no way to know which file is misnamed.

  × eslint-plugin-react(jsx-filename-extension): Only files containing JSX may use the extension '.tsx'
  help: Rename the file with a good extension.

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions