JSPM

  • Created
  • Published
  • Downloads 9593
  • Score
    100M100P100Q130228F
  • License MIT

Wrapper that simplifies ESLint API and makes it compatible with 🐊Putout

Package Exports

  • @putout/eslint
  • @putout/eslint/create-plugin
  • @putout/eslint/lint

Readme

@putout/eslint NPM version

Wrapper that simplifies ESLint API and makes it compatible with 🐊Putout.

☝️ FlatConfig supported from the box.

Install

npm i @putout/eslint

API

eslint(options)

ESLint begins his work as a formatter when 🐊Putout done his transformations. That's why it used a lot in different parts of application, for testing purpose and using API in a simplest possible way. You can access it with:

import eslint from '@putout/eslint';

To use it simply write:

const [source, places] = await eslint({
    name: 'hello.js',
    code: `const t = 'hi'\n`,
    fix: false,
});

Isn't it looks similar to 🐊Putout way? It definitely is! But... It has a couple differences you should remember:

And you can even override any of ESLint βš™οΈ options with help of config property:

const [source, places] = await eslint({
    name: 'hello.js',
    code: `const t = 'hi'\n`,
    fix: false,
    config: {
        extends: [
            'plugin:putout/recommended',
        ],
    },
});

If you want to apply 🐊Putout transformations using putout/putout ESLint rule, enable 🐊Putout with the same called flag lowercased:

const [source, places] = await eslint({
    name: 'hello.js',
    code: `const t = 'hi'\n`,
    fix: true,
    putout: true,
    config: {
        extends: [
            'plugin:putout/recommended',
        ],
    },
});

It is disabled by default, because ESLint always runs after 🐊Putout transformations, so there is no need to traverse tree again.

createPlugin(options)

You can also simplify creating of plugins for ESLint with help of createPlugin. 🐊Putout-based ESLint plugin are highly inspired by Putout Plugins API of Includer.

So it must contain classic 4 methods:

module.exports.report = () => 'debugger statement should not be used';

module.exports.fix = (path) => {
    return '';
};

module.exports.include = () => [
    'DebuggerStatement',
];

module.exports.filter = (path) => {
    return true;
};

The main difference with Includer is:

  • fix works with text;
  • include does not support 🦎PutoutScript;
  • there is no exclude;

Take a look at more sophisticated example, rule remove-duplicate-extensions:

const getValue = ({source}) => source?.value;

module.exports.report = () => 'Avoid duplicate extensions in relative imports';
module.exports.include = () => [
    'ImportDeclaration',
    'ImportExpression',
    'ExportAllDeclaration',
    'ExportNamedDeclaration',
];

module.exports.fix = ({text}) => {
    return text.replace('.js.js', '.js');
};

module.exports.filter = ({node}) => {
    const value = getValue(node);
    return /\.js\.js/.test(value);
};

To use it just add couple lines to your main plugin file:

const {createPlugin} = require('@putout/eslint/create-plugin');

const createRule = (a) => ({
    [a]: createPlugin(require(`./${a}`)),
});

module.exports.rules = {
    ...createRule('remove-duplicate-extensions'),
};

Or just:

const {createPlugin} = require('@putout/eslint/create-plugin');

module.exports.rules = {
    'remove-duplicate-extensions': createPlugin(require('./remove-duplicate-extensions')),
};

lint(source, {fix, plugins, options, filename})

When you need to run ESLint with one plugin (rule), just use lint it will do the thing.

const lint = require('@putout/eslint/lint');
const removeDebugger = require('./remove-debugger');

const [code, places] = lint('debugger', {
    fix: true, // default
    plugins: [
        ['remove-debugger', createPlugin(removeDebugger)],
    ],
});

When you want to skip plugins, and just provide options and filename you can:

const lint = require('@putout/eslint/lint');

const [code, places] = lint('debugger', {
    filename: 'index.js',
    options: [{
        rules: {
            semi: 'error',
        },
    }],
});

License

MIT