Eslint-plugin-react: react plugin rule is not executing autofix while running with eslint's CLIEngine

Created on 4 Jan 2020  路  6Comments  路  Source: yannickcr/eslint-plugin-react

It's nodejs project. Eslint is running as js function. I have code as text and pass that text to eslint function. This function uses eslint's CLIEngine to run eslint things. You can see full file below.

Other eslint rules are executing autofixes and changes the code. While react rule just provides information for fix but doesn't execute the fix. Why? Is it a bug? Any way to automatically execute the fixes?

[email protected]
[email protected]
node v12.6.0

the code before linting:

  • imports have extra whitespace
  • 1st import does not have a semicolon in the end
  • <Root/> does not have space before the close
import React from 'react'
     import ReactDOM from 'react-dom';
         import * as serviceWorker from './serviceWorker';
                import Root from 'components/Root';

ReactDOM.render(<Root/>, document.getElementById('root'));

/*
 * If you want your app to work offline and load faster, you can change
 * unregister() to register() below. Note this comes with some pitfalls.
 * Learn more about service workers: https://bit.ly/CRA-PWA
 */
serviceWorker.unregister();

Output of eslint:

{
  "results": [
    {
      "filePath": "<text>",
      "messages": [
        {
          "ruleId": "react/jsx-tag-spacing",
          "severity": 2,
          "message": "A space is required before closing bracket",
          "line": 6,
          "column": 22,
          "nodeType": "JSXOpeningElement",
          "fix": {
            "range": [
              169,
              169
            ],
            "text": " "
          }
        }
      ],
      "errorCount": 1,
      "warningCount": 0,
      "fixableErrorCount": 1,
      "fixableWarningCount": 0,
      "output": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport * as serviceWorker from './serviceWorker';\nimport Root from 'components/Root';\n\nReactDOM.render(<Root/>, document.getElementById('root'));\n\n/*\n * If you want your app to work offline and load faster, you can change\n * unregister() to register() below. Note this comes with some pitfalls.\n * Learn more about service workers: https://bit.ly/CRA-PWA\n */\nserviceWorker.unregister();\n"
    }
  ],
  "errorCount": 1,
  "warningCount": 0,
  "fixableErrorCount": 1,
  "fixableWarningCount": 0,
  "usedDeprecatedRules": [
    {
      "ruleId": "react/jsx-space-before-closing",
      "replacedBy": []
    }
  ]
}

Full eslint file. I run eslint as a function inside nodejs.

const CLIEngine = require('eslint').CLIEngine;

const cli = new CLIEngine({
  baseConfig: {
    plugins: [
      'react',
    ],
    extends: [
      'eslint:recommended',
      'plugin:react/recommended',
    ],
    parserOptions: {
      ecmaFeatures: {
        jsx: true,
        modules: true,
        spread: true,
        restParams: true,
      },
      sourceType: 'module',
    },
    settings: {
      'react': {
        'pragma': 'React',  // Pragma to use, default to "React"
        'version': '16.12',
      },
    },
  },
  fix: true,
  globals: ['process'],
  allowInlineConfig: true,
  envs: ['browser', 'es6'],
  useEslintrc: false,
  rules: {
    // https://eslint.org/docs/rules/
    'curly': 'error',
    'dot-location': ['error', 'property'],
    'eqeqeq': ['error', 'always'],
    'no-div-regex': 'error',
    'no-else-return': 'error',
    'no-extra-bind': 'error',
    'no-floating-decimal': 'error',
    'no-implicit-coercion': 'error',
    'no-multi-spaces': 'error',
    'no-useless-return': 'error',
    'wrap-iife': 'error',
    'yoda': 'error',
    'array-bracket-newline': ['error', {'multiline': true}],
    'array-bracket-spacing': ['error', 'never'],
    'array-element-newline': ['error', {'multiline': true}],
    'block-spacing': ['error', 'always'],
    'brace-style': ['error', '1tbs'],
    'comma-dangle': ['error', 'always'],
    'comma-spacing': ['error', {'before': false, 'after': true}],
    'comma-style': ['error', 'last'],
    'computed-property-spacing': ['error', 'never'],
    'eol-last': ['error', 'always'],
    'func-call-spacing': ['error', 'never'],
    'function-call-argument-newline': ['error', 'consistent'],
    'function-paren-newline': ['error', 'multiline'],
    'implicit-arrow-linebreak': ['error', 'beside'],
    'indent': ['error', 2],
    'jsx-quotes': ['error', 'prefer-single'],
    'key-spacing': 'error',
    'keyword-spacing': 'error',
    'linebreak-style': 'error',
    'lines-around-comment': 'error',
    'lines-between-class-members': 'error',
    'multiline-comment-style': 'error',
    'new-parens': 'error',
    'newline-per-chained-call': 'error',
    'no-lonely-if': 'error',
    'no-multiple-empty-lines': 'error',
    'no-trailing-spaces': 'error',
    'no-unneeded-ternary': 'error',
    'no-whitespace-before-property': 'error',
    'nonblock-statement-body-position': 'error',
    'object-curly-newline': 'error',
    'object-curly-spacing': 'error',
    'object-property-newline': 'error',
    'one-var': ['error', 'never'],
    'one-var-declaration-per-line': ['error', 'always'],
    'operator-assignment': ['error', 'never'],
    'operator-linebreak': ['error', 'after', {'overrides': {'?': 'before', ':': 'before'}}],
    'padded-blocks': ['error', 'never'],
    'padding-line-between-statements': ['error'],
    'prefer-object-spread': 'error',
    'quote-props': ['error', 'consistent-as-needed'],
    'quotes': ['error', 'single', {'avoidEscape': true}],
    'semi': ['error', 'always'],
    'semi-spacing': ['error', {'before': false, 'after': true}],
    'semi-style': ['error', 'last'],
    'sort-vars': ['error', {'ignoreCase': true}],
    'space-before-blocks': ['error', 'always'],
    'space-before-function-paren': ['error', {'anonymous': 'always', 'named': 'never', 'asyncArrow': 'always'}],
    'space-in-parens': ['error', 'never'],
    'space-infix-ops': ['error', {'int32Hint': false}],
    'space-unary-ops': ['error', {'words': true, 'nonwords': false}],
    'spaced-comment': ['error', 'always', {'exceptions': ['-', '+', '*']}],
    'switch-colon-spacing': ['error', {'after': true, 'before': false}],
    'template-tag-spacing': ['error', 'always'],
    'unicode-bom': ['error', 'always'],
    'wrap-regex': 'error',
    'arrow-body-style': ['error', 'as-needed'],
    'arrow-parens': ['error', 'always'],
    'arrow-spacing': ['error', {'before': true, 'after': true}],
    'generator-star-spacing': ['error', {'before': true, 'after': false}],
    'no-confusing-arrow': 'error',
    'no-useless-computed-key': 'error',
    'no-useless-rename': 'error',
    'no-var': 'error',
    'object-shorthand': ['error', 'consistent'],
    'prefer-arrow-callback': ['error'],
    'prefer-const': 'error',
    'prefer-destructuring': ['error', {'object': false, 'array': false}],
    'prefer-numeric-literals': 'error',
    'prefer-template': 'error',
    'rest-spread-spacing': ['error', 'never'],
    'template-curly-spacing': ['error', 'never'],
    'yield-star-spacing': ['error', {'before': true, 'after': false}],

    // ReactJS & JSX:
    // https://github.com/yannickcr/eslint-plugin-react
    'react/no-unknown-property': ['off'],
    'react/self-closing-comp': ['error', {'component': true, 'html': true}],
    'react/jsx-boolean-value': ['error', 'always'],
    'react/jsx-closing-bracket-location': ['error', {selfClosing: 'line-aligned', nonEmpty: 'line-aligned'}],
    'react/jsx-closing-tag-location': ['error'],
    'react/jsx-curly-newline': ['error', 'consistent'],
    'react/jsx-curly-spacing': ['error', {'when': 'never'}],
    'react/jsx-equals-spacing': ['error', 'never'],
    'react/jsx-first-prop-new-line': ['error', 'multiline-multiprop'],
    'react/jsx-indent': ['error', 2],
    'react/jsx-indent-props': ['error', 2],
    'react/jsx-max-props-per-line': ['error', {'maximum': 1, 'when': 'multiline'}],
    'react/jsx-no-useless-fragment': ['error'],
    'react/jsx-props-no-multi-spaces': ['error'],
    'react/jsx-sort-props': ['error', {
      'callbacksLast': false,
      'shorthandFirst': true,
      'ignoreCase': true,
      'noSortAlphabetically': false,
      'reservedFirst': true,
    }],
    'react/jsx-space-before-closing': ['error', 'never'],
    'react/jsx-tag-spacing': ['error', {
      'closingSlash': 'never',
      'beforeSelfClosing': 'always',
      'afterOpening': 'never',
      'beforeClosing': 'allow',
    }],
    'react/jsx-wrap-multilines': ['error', {
      'declaration': 'parens',
      'assignment': 'parens',
      'return': 'parens',
      'arrow': 'parens',
      'condition': 'ignore',
      'logical': 'ignore',
      'prop': 'ignore',
    }],

  },
});

function eslint({code}) {
  const result = cli.executeOnText(code);
  console.log(JSON.stringify(result));
}

module.exports = eslint;
invalid

All 6 comments

CLIEngine, unlike the actual eslint CLI, does not do multi-pass autofix. To get proper output, you have to run the autofix multiple times until there's no more diffs.

do I need to call the same executeOnText or there is some function that would do just the fixing part? while I ran executeOnText once and got the output with needed fixes. Don't want to re-run all rules again for no benefit.

I'm not really sure; I never use anything but the CLI for eslint (it's probably way easier for your project if you shell out to eslint rather than using the API, imo). eslint's docs might help tho.

the issue is that I need to generate quite a bit of files w/o writing them to disk, so I would need to do I/O to disk, execute all eslint there and do I/O back. And probably eslint would check links between file, which is not needed, while i know those are correct. And some parts would require to run babel too, which takes so much time. It seems to be much-lightweighted operation to call a js function and just execute the eslint code on raw code w/o ever touching the disk

the eslint CLI can take output via stdin, so I don't think you need to write anything to disk.

Up to you, of course :-) but as this isn't an issue with eslint-plugin-react, but rather with eslint itself, I'm going to close (but happy to keep discussing)

will try using CLI directly, it seems like this CLIEngine is not that popular and doesn't get much attention. Thanks for the help :)

Update. Switched to CLI now, works perfectly 馃挴

Was this page helpful?
0 / 5 - 0 ratings