Skip to content

[@typescript-eslint/camelcase] Use config of ESLint built-in "camelcase" rule when no config exists for typescript counterpart #265

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
evangalen opened this issue Feb 13, 2019 · 8 comments
Labels
package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin question Questions! (i.e. not a bug / enhancment / documentation) wontfix This will not be worked on

Comments

@evangalen
Copy link

In our .eslintrc.js we use the configuration of 'airbnb-base' that enables and configures the ESLint built-in rules of "camelcase", "indent", "no-array-constructor" and "no-unused-vars".

To ensure that we don't get double rule violations (on for the ESLint build-in and the TypeScript counterpart),
we deliberately place 'plugin:@typescript-eslint/recommended' after 'airbnb-base':

module.exports = {
  extends: [
    'eslint:recommended',
    'airbnb-base',

    // placed after 'airbnb-base' so that enabled rules are replaced with TypeScript specific ones
    'plugin:@typescript-eslint/recommended',
  ],
  // ...
};

Problem with this approach is that @typescript-eslint/eslint-plugin will use a different configuration as the for the ESLint built-in rules of "camelcase", "indent", "no-array-constructor" and "no-unused-vars".

So I was wondering if it wouldn't be possible that @typescript-eslint/eslint-plugin uses the configuration of ESLint built-in rules in case no explicit configuration exists for the TypeScript counterparts.

Right now, we had to work around the problem by explicitlty require-ing the rules of the "eslint-config-airbnb-base" module and then re-configure them using the imported rule config:

const airbnbImportsRules = require('eslint-config-airbnb-base/rules/imports').rules;
const airbnbStyleRules = require('eslint-config-airbnb-base/rules/style').rules;
const airbnbVariablesRules = require('eslint-config-airbnb-base/rules/variables').rules;

module.exports = {
  extends: [
    'eslint:recommended',
    'airbnb-base',

    // placed after 'airbnb-base' so that enabled rules are replaced with TypeScript specific ones
    'plugin:@typescript-eslint/recommended',
  ],
  plugins: ['@typescript-eslint'],
  settings: {
    'import/resolver': {
      'webpack': {
        config: path.join(__dirname, 'webpack.config.prod.js'),
      }
    },
  },
  env: {
    browser: true,
    es6: true,
  },
  parser: '@typescript-eslint/parser',
  parserOptions: {
    'project': './tsconfig.json'
  },
  rules: {
    // ...

    // configure TypeScript counterpart rules with the original airbnb rule configuration
    '@typescript-eslint/camelcase': airbnbStyleRules.camelcase,
    '@typescript-eslint/indent': airbnbStyleRules.indent,
    '@typescript-eslint/no-array-constructor': airbnbStyleRules['no-array-constructor'],
    '@typescript-eslint/no-unused-vars': airbnbVariablesRules['no-unused-vars'],

    // ...
  },
};
@evangalen evangalen added package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin triage Waiting for team members to take a look labels Feb 13, 2019
@bradzacher bradzacher added question Questions! (i.e. not a bug / enhancment / documentation) wontfix This will not be worked on and removed triage Waiting for team members to take a look labels Feb 13, 2019
@bradzacher
Copy link
Member

AFAIK this is not possible.
Someone from @typescript-eslint/core-team / @typescript-eslint/eslint-team - please correct me if I'm wrong here.

The base eslint rule camelcase is completely separate to our rule @typescript-eslint/camelcase. It may seem like because they share a name and we extend the base implementation that they are the same rule, but from eslint's POV, they are two separate rules.
This means that by design eslint doesn't provide a mechanism for us to use the other rule's config. (this is the use case of the settings field - it's shared across all rules).

Additionally, as part of the recommended config we disable the base eslint rule so that you don't get doubled errors. This means that even if eslint provided a mechanism for us to easily interrogate the entire workspace's config, we wouldn't be able to get the setting from airbnb's config, because it's been overwritten to be off.

@j-f1
Copy link
Contributor

j-f1 commented Feb 13, 2019

This could be resolved by Airbnb providing a special TypeScript config that disables the core rules and enables ours according to their standards.

@bartlangelaan
Copy link

bartlangelaan commented Feb 18, 2019

It would be awesome if this plugin would work for all ESLint shared configs, without any configuration required.

There are a lot of rules (okay, maybe not so many right now, but that can of course change in the future) that are a duplication of core rules (like camelcase). Instead of creating a separate rule, it would be nice if these rules would automatically 'switch' to their Typescript variants.

It doesn't look like it's possible to override a rule in ESLint right now, but maybe it can be made possible by including such a feature in ESLint core.

I think it would be most user friendly if you would only need to define a parser and plugin, and the plugin will handle the rest; as in, making sure that all the ESLint rules work, so by replacing them with a Typescript specific one if necessary.

@bradzacher
Copy link
Member

I'm going to close this as there's nothing we can do from within the plugin.
This is a limitation of eslint itself.

If you have possible solutions to this problem, feel free to raise them in https://github.com/eslint/rfcs.

Note that there's eslint/rfcs#9 which might help deal with this.

@chul-hyun
Copy link

chul-hyun commented Mar 5, 2019

I fixed it. (A temporary measure)

const airbnbBaseStyleRules = require('eslint-config-airbnb-base/rules/style').rules;
const airbnbBaseVariablesRules = require('eslint-config-airbnb-base/rules/variables').rules;

const airbnbBaseStyleRules = require('eslint-config-airbnb-base/rules/style').rules;
const airbnbBaseVariablesRules = require('eslint-config-airbnb-base/rules/variables').rules;

module.exports = {
  extends: ['airbnb'],
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  settings: {
    'import/resolver': {
      node: {
        extensions: ['.js', '.jsx', '.ts', '.tsx'],
      },
    },
  },
  parserOptions: {
    ecmaVersion: 6,
    sourceType: 'module',
  },
  env: {
    browser: true,
    es6: true,
    jest: true,
  },
  rules: {
    'react/jsx-filename-extension': [1, { extensions: ['.jsx', '.tsx'] }],
  },
  overrides: [
    {
      files: ['*.ts', '*.tsx'],
      rules: {
        // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/src/configs/recommended.json
        '@typescript-eslint/adjacent-overload-signatures': 'error',
        '@typescript-eslint/array-type': 'error',
        '@typescript-eslint/ban-types': 'error',
        camelcase: 'off',
        '@typescript-eslint/camelcase': airbnbBaseStyleRules.camelcase,
        '@typescript-eslint/class-name-casing': 'error',
        '@typescript-eslint/explicit-function-return-type': 'error',
        '@typescript-eslint/explicit-member-accessibility': 'error',
        indent: 'off',
        '@typescript-eslint/indent': airbnbBaseStyleRules.indent,
        '@typescript-eslint/interface-name-prefix': 'error',
        '@typescript-eslint/member-delimiter-style': 'error',
        '@typescript-eslint/no-angle-bracket-type-assertion': 'error',
        'no-array-constructor': 'off',
        '@typescript-eslint/no-array-constructor': airbnbBaseStyleRules['no-array-constructor'],
        '@typescript-eslint/no-empty-interface': 'error',
        '@typescript-eslint/no-explicit-any': 'warn',
        '@typescript-eslint/no-inferrable-types': 'error',
        '@typescript-eslint/no-misused-new': 'error',
        '@typescript-eslint/no-namespace': 'error',
        '@typescript-eslint/no-non-null-assertion': 'error',
        '@typescript-eslint/no-object-literal-type-assertion': 'error',
        '@typescript-eslint/no-parameter-properties': 'error',
        '@typescript-eslint/no-triple-slash-reference': 'error',
        'no-unused-vars': 'off',
        '@typescript-eslint/no-unused-vars': airbnbBaseVariablesRules['no-unused-vars'],
        '@typescript-eslint/no-use-before-define': 'error',
        '@typescript-eslint/no-var-requires': 'error',
        '@typescript-eslint/prefer-interface': 'error',
        '@typescript-eslint/prefer-namespace-keyword': 'error',
        '@typescript-eslint/type-annotation-spacing': 'error',
      },
    },
  ],
};

or

const airbnbBaseStyleRules = require('eslint-config-airbnb-base/rules/style').rules;
const airbnbBaseVariablesRules = require('eslint-config-airbnb-base/rules/variables').rules;

module.exports = {
  extends: ['airbnb', 'plugin:@typescript-eslint/recommended'],
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  settings: {
    'import/resolver': {
      node: {
        extensions: ['.js', '.jsx', '.ts', '.tsx'],
      },
    },
  },
  parserOptions: {
    ecmaVersion: 6,
    sourceType: 'module',
  },
  env: {
    browser: true,
    es6: true,
    jest: true,
  },
  rules: {
    'react/jsx-filename-extension': [1, { extensions: ['.jsx', '.tsx'] }],
  },
  overrides: [
    {
      files: ['*.ts', '*.tsx'],
      extends: ['airbnb', 'plugin:@typescript-eslint/recommended'],
      rules: {
         'react/jsx-filename-extension': [1, { extensions: ['.jsx', '.tsx'] }],
          complexity: ['error', { max: 10 }],
          'max-lines': ['error', { max: 100, skipBlankLines: true, skipComments: true }],
          'max-depth': ['error', 2],
          'import/no-extraneous-dependencies': 'off',
      
          // https://github.com/typescript-eslint/typescript-eslint/issues/265
          '@typescript-eslint/camelcase': airbnbBaseStyleRules.camelcase,
          '@typescript-eslint/indent': airbnbBaseStyleRules.indent,
          '@typescript-eslint/no-array-constructor': airbnbBaseStyleRules['no-array-constructor'],
          '@typescript-eslint/no-unused-vars': airbnbBaseVariablesRules['no-unused-vars'],
      },
    }
  ]
};

@evangalen
Copy link
Author

@vomvoru Good to hear you 'fixed' it.
But what makes your workaround any different than the workaround I posted when I created this issue?

@chul-hyun
Copy link

@vomvoru Good to hear you 'fixed' it.
But what makes your workaround any different than the workaround I posted when I created this issue?

Oh, I just found out that the code is the same.
I thought the code was omitted because of '// ...'. :)

@David-Else
Copy link

I had an idea about this problem in another thread #36 (comment)

kaicataldo pushed a commit to kaicataldo/typescript-eslint that referenced this issue Aug 27, 2019
@typescript-eslint typescript-eslint locked as resolved and limited conversation to collaborators Feb 21, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin question Questions! (i.e. not a bug / enhancment / documentation) wontfix This will not be worked on
Projects
None yet
Development

No branches or pull requests

6 participants