@putout/eslint 4.0.0 β†’ 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,7 +29,7 @@ NO_ESLINT_WARNINGS=1 putout --fix lib
29
29
  **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:
30
30
 
31
31
  ```js
32
- import eslint from '@putout/eslint';
32
+ import {eslint} from '@putout/eslint';
33
33
  ````
34
34
 
35
35
  To use it simply write:
@@ -50,27 +50,27 @@ Isn't it looks similar to 🐊**Putout** way? It definitely is! But... It has a
50
50
  And you can even override any of **ESLint** βš™οΈ options with help of `config` property:
51
51
 
52
52
  ```js
53
+ import {safeAlign} from 'eslint-plugin-putout';
54
+
53
55
  const [source, places] = await eslint({
54
56
  name: 'hello.js',
55
57
  code: `const t = 'hi'\n`,
56
58
  fix: false,
57
- config: {
58
- extends: ['plugin:putout/recommended'],
59
- },
59
+ config: [safeAlign],
60
60
  });
61
61
  ```
62
62
 
63
63
  If you want to apply 🐊**Putout** transformations using [`putout/putout`](https://github.com/coderaiser/putout/tree/master/packages/eslint-plugin-putout#readme) **ESLint** rule, enable 🐊**Putout** with the same called but lowercased flag:
64
64
 
65
65
  ```js
66
+ import {safeAlign} from 'eslint-plugin-putout';
67
+
66
68
  const [source, places] = await eslint({
67
69
  name: 'hello.js',
68
70
  code: `const t = 'hi'\n`,
69
71
  fix: true,
70
72
  putout: true,
71
- config: {
72
- extends: ['plugin:putout/recommended'],
73
- },
73
+ config: [safeAlign],
74
74
  });
75
75
  ```
76
76
 
@@ -84,17 +84,17 @@ You can also simplify creating of plugins for **ESLint** with help of `createPlu
84
84
  So it must contain classic `4` methods:
85
85
 
86
86
  ```js
87
- module.exports.report = () => 'debugger statement should not be used';
87
+ export const report = () => 'debugger statement should not be used';
88
88
 
89
- module.exports.fix = (path) => {
89
+ export const fix = (path) => {
90
90
  return '';
91
91
  };
92
92
 
93
- module.exports.include = () => [
93
+ export const include = () => [
94
94
  'DebuggerStatement',
95
95
  ];
96
96
 
97
- module.exports.filter = (path) => {
97
+ export const filter = (path) => {
98
98
  return true;
99
99
  };
100
100
  ```
@@ -110,19 +110,19 @@ Take a look at more sophisticated example, rule [`remove-duplicate-extensions`](
110
110
  ```js
111
111
  const getValue = ({source}) => source?.value;
112
112
 
113
- module.exports.report = () => 'Avoid duplicate extensions in relative imports';
114
- module.exports.include = () => [
113
+ export const report = () => 'Avoid duplicate extensions in relative imports';
114
+ export const include = () => [
115
115
  'ImportDeclaration',
116
116
  'ImportExpression',
117
117
  'ExportAllDeclaration',
118
118
  'ExportNamedDeclaration',
119
119
  ];
120
120
 
121
- module.exports.fix = ({text}) => {
121
+ export const fix = ({text}) => {
122
122
  return text.replace('.js.js', '.js');
123
123
  };
124
124
 
125
- module.exports.filter = ({node}) => {
125
+ export const filter = ({node}) => {
126
126
  const value = getValue(node);
127
127
  return /\.js\.js/.test(value);
128
128
  };
@@ -131,21 +131,19 @@ module.exports.filter = ({node}) => {
131
131
  To use it just add couple lines to your main plugin file:
132
132
 
133
133
  ```js
134
- const {createPlugin} = require('@putout/eslint/create-plugin');
134
+ import {createPlugin} from '@putout/eslint/create-plugin';
135
135
 
136
136
  const createRule = (a) => ({
137
137
  [a]: createPlugin(require(`./${a}`)),
138
138
  });
139
139
 
140
- module.exports.rules = {
141
- ...createRule('remove-duplicate-extensions'),
142
- };
140
+ module.exports.rules = createRule('remove-duplicate-extensions');
143
141
  ```
144
142
 
145
143
  Or just:
146
144
 
147
145
  ```js
148
- const {createPlugin} = require('@putout/eslint/create-plugin');
146
+ import {createPlugin} from '@putout/eslint/create-plugin';
149
147
 
150
148
  module.exports.rules = {
151
149
  'remove-duplicate-extensions': createPlugin(require('./remove-duplicate-extensions')),
@@ -157,9 +155,9 @@ module.exports.rules = {
157
155
  When you need to run **ESLint** with one plugin (*rule*), just use `lint` it will do the thing.
158
156
 
159
157
  ```js
160
- const lint = require('@putout/eslint/lint');
161
- const {createPlugin} = require('@putout/eslint/create-plugin');
162
- const removeDebugger = require('./remove-debugger');
158
+ import {lint} from '@putout/eslint/lint';
159
+ import {createPlugin} from '@putout/eslint/create-plugin';
160
+ import * as removeDebugger from 'remove-debugger';
163
161
 
164
162
  const [code, places] = lint('debugger', {
165
163
  fix: true, // default
@@ -172,7 +170,7 @@ const [code, places] = lint('debugger', {
172
170
  When you want to skip plugins, and just provide `options` and `filename` you can:
173
171
 
174
172
  ```js
175
- const lint = require('@putout/eslint/lint');
173
+ import {lint} from '@putout/eslint/lint';
176
174
 
177
175
  const [code, places] = lint('debugger', {
178
176
  filename: 'index.js',
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  const prepare = (plugin, context, options) => (node) => {
4
2
  const {filter, report} = plugin;
5
3
  const {sourceCode, filename} = context;
@@ -64,7 +62,7 @@ const prepareFix = (fix, {node, text, getText, filename}) => (fixer) => {
64
62
  ];
65
63
  };
66
64
 
67
- module.exports.createPlugin = (plugin) => {
65
+ export const createPlugin = (plugin) => {
68
66
  const meta = getMeta(plugin);
69
67
 
70
68
  return {
@@ -108,7 +106,7 @@ function getTraversers(names, plugin) {
108
106
  return traversers;
109
107
  }
110
108
 
111
- const createGetSpacesBeforeNode = ({getText}) => (node, text = getText(node)) => {
109
+ export const createGetSpacesBeforeNode = ({getText}) => (node, text = getText(node)) => {
112
110
  let spaces = '';
113
111
  let i = 0;
114
112
 
@@ -121,9 +119,7 @@ const createGetSpacesBeforeNode = ({getText}) => (node, text = getText(node)) =>
121
119
  return spaces.slice(1);
122
120
  };
123
121
 
124
- module.exports.createGetSpacesBeforeNode = createGetSpacesBeforeNode;
125
-
126
- const createGetSpacesAfterNode = ({getText}) => (node, text = getText(node)) => {
122
+ export const createGetSpacesAfterNode = ({getText}) => (node, text = getText(node)) => {
127
123
  const reg = /^[ \n;]+$/;
128
124
 
129
125
  if (isLastNodeInBody(node))
@@ -138,8 +134,6 @@ const createGetSpacesAfterNode = ({getText}) => (node, text = getText(node)) =>
138
134
  return spaces.slice(0, -1);
139
135
  };
140
136
 
141
- module.exports.createGetSpacesAfterNode = createGetSpacesAfterNode;
142
-
143
137
  function isLastNodeInBody(node) {
144
138
  if (node.parent.body) {
145
139
  const {length} = node.parent.body;
package/lib/eslint.js CHANGED
@@ -1,22 +1,18 @@
1
- 'use strict';
2
-
3
- const {join} = require('node:path');
4
- const process = require('node:process');
5
- const tryToCatch = require('try-to-catch');
6
- const once = require('once');
7
-
8
- const {simpleImport} = require('./simple-import.js');
9
- const {isIgnored} = require('./ignore');
1
+ import {join} from 'node:path';
2
+ import process from 'node:process';
3
+ import tryToCatch from 'try-to-catch';
4
+ import {simpleImport as _simpleImport} from './simple-import.js';
5
+ import {isIgnored} from './ignore.js';
10
6
 
11
7
  const {keys} = Object;
12
8
  const eslintId = ' (eslint)';
13
9
 
14
- const isNoESLint = once(() => process.env.NO_ESLINT);
15
- const noESLintWarnings = process.env.NO_ESLINT_WARNINGS;
16
- const {ESLINT_CONFIG_FILE} = process.env;
10
+ const {env} = process;
11
+ const isNoESLint = () => env.NO_ESLINT;
12
+ const isNoESLintWarnings = () => env.NO_ESLINT_WARNINGS;
17
13
 
18
14
  const dir = process.cwd();
19
- const overrideConfigFile = parseOverride(dir, ESLINT_CONFIG_FILE);
15
+ const overrideConfigFile = () => parseOverride(dir, env.ESLINT_CONFIG_FILE);
20
16
 
21
17
  const NO_FLAT_CONFIG_FOUND = 'Could not find config file.';
22
18
  const WARNING = 1;
@@ -40,11 +36,16 @@ const noConfigFound = (config, configError) => {
40
36
  return !keys(config.rules).length;
41
37
  };
42
38
 
43
- const cutNewLine = ({message}) => ({
44
- message: message.replace(/\n.*/, ''),
45
- });
46
-
47
- module.exports = async ({name, code, fix, config, putout = false}) => {
39
+ export const eslint = async (overrides = {}) => {
40
+ const {
41
+ name,
42
+ code,
43
+ fix,
44
+ config,
45
+ putout = false,
46
+ simpleImport = _simpleImport,
47
+ } = overrides;
48
+
48
49
  const noChanges = [
49
50
  code,
50
51
  [],
@@ -53,28 +54,20 @@ module.exports = async ({name, code, fix, config, putout = false}) => {
53
54
  if (isNoESLint())
54
55
  return noChanges;
55
56
 
56
- const [, ESLint] = await tryToCatch(simpleImport, './get-eslint.mjs');
57
+ const [, ESLint] = await tryToCatch(simpleImport, './get-eslint.js');
57
58
 
58
59
  if (!ESLint)
59
60
  return noChanges;
60
61
 
61
62
  const {getESLint} = ESLint;
62
63
 
63
- const [eslintError, eslint] = await tryToCatch(getESLint, {
64
+ const eslint = await getESLint({
64
65
  name,
65
66
  fix,
66
67
  config,
67
- overrideConfigFile,
68
+ overrideConfigFile: overrideConfigFile(),
68
69
  });
69
70
 
70
- if (eslintError) {
71
- const places = [
72
- convertToPlace(cutNewLine(eslintError)),
73
- ];
74
-
75
- return [code, places];
76
- }
77
-
78
71
  const [configError, finalConfig] = await tryToCatch(eslint.calculateConfigForFile, name);
79
72
 
80
73
  if (noConfigFound(finalConfig, configError))
@@ -102,23 +95,21 @@ module.exports = async ({name, code, fix, config, putout = false}) => {
102
95
  const [report] = results;
103
96
  const {output = code} = report;
104
97
 
105
- const places = report
106
- .messages
98
+ const places = report.messages
107
99
  .map(convertToPlace)
108
100
  .filter(Boolean);
109
101
 
110
102
  return [output, places];
111
103
  };
112
104
 
113
- module.exports._noConfigFound = noConfigFound;
105
+ export const _noConfigFound = noConfigFound;
114
106
 
115
107
  const parseRule = (rule) => rule || 'parser';
116
108
 
117
- module.exports.convertToPlace = convertToPlace;
118
- function convertToPlace({ruleId = 'parser', message, line = 0, column = 0, severity}) {
109
+ export function convertToPlace({ruleId = 'parser', message, line = 0, column = 0, severity}) {
119
110
  const rule = `${parseRule(ruleId)}${eslintId}`;
120
111
 
121
- if (severity === WARNING && noESLintWarnings)
112
+ if (severity === WARNING && isNoESLintWarnings())
122
113
  return null;
123
114
 
124
115
  if (isIgnored(message))
@@ -0,0 +1,33 @@
1
+ import {dirname} from 'node:path';
2
+ import process from 'node:process';
3
+ import {loadESLint} from 'eslint';
4
+
5
+ const {isArray} = Array;
6
+ const maybeArray = (a) => isArray(a) ? a : [a];
7
+ const CWD = process.cwd();
8
+
9
+ export const getESLint = async ({name, fix, config = [], overrideConfigFile, loadESLintOverride = loadESLint}) => {
10
+ const cwd = dirname(name).replace(/^\./, CWD);
11
+
12
+ const FlatESLint = await loadESLintOverride({
13
+ useFlatConfig: true,
14
+ });
15
+
16
+ const eslint = new FlatESLint({
17
+ cwd,
18
+ fix,
19
+ overrideConfig: [
20
+ ...maybeArray(config), {
21
+ ignores: ['!.*'],
22
+ },
23
+ ],
24
+ ...overrideConfigFile && {
25
+ overrideConfigFile,
26
+ },
27
+ });
28
+
29
+ return {
30
+ calculateConfigForFile: eslint.calculateConfigForFile.bind(eslint),
31
+ lintText: eslint.lintText.bind(eslint),
32
+ };
33
+ };
package/lib/ignore.js CHANGED
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  const MESSAGES = [
4
2
  `Parsing error: Cannot use keyword 'await' outside an async function`,
5
3
  `Parsing error: The keyword 'yield' is reserved`,
@@ -7,7 +5,7 @@ const MESSAGES = [
7
5
  `Parsing error: Unexpected reserved word 'yield'`,
8
6
  ];
9
7
 
10
- module.exports.isIgnored = (message) => {
8
+ export const isIgnored = (message) => {
11
9
  for (const current of MESSAGES) {
12
10
  if (message.includes(current))
13
11
  return true;
package/lib/lint/index.js CHANGED
@@ -1,9 +1,7 @@
1
- 'use strict';
1
+ import {Linter} from 'eslint';
2
+ import {convertToPlace} from '../eslint.js';
2
3
 
3
- const {Linter} = require('eslint');
4
- const {convertToPlace} = require('../eslint.js');
5
-
6
- module.exports.lint = (source, {fix = true, plugins, filename, options = []}) => {
4
+ export const lint = (source, {fix = true, plugins, filename, options = []}) => {
7
5
  const linter = new Linter({
8
6
  configType: 'flat',
9
7
  });
@@ -1,6 +1,4 @@
1
- 'use strict';
2
-
3
- module.exports.simpleImport = async (url) => {
1
+ export const simpleImport = async (url) => {
4
2
  const result = await import(url);
5
3
  return result.default || result;
6
4
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@putout/eslint",
3
- "version": "4.0.0",
4
- "type": "commonjs",
3
+ "version": "5.0.0",
4
+ "type": "module",
5
5
  "author": "coderaiser <mnemonic.enemy@gmail.com> (https://github.com/coderaiser)",
6
6
  "description": "Wrapper that simplifies ESLint API and makes it compatible with 🐊Putout",
7
7
  "homepage": "https://github.com/coderaiser/putout/tree/master/packages/eslint#readme",
@@ -29,7 +29,6 @@
29
29
  "report": "madrun report"
30
30
  },
31
31
  "dependencies": {
32
- "find-up": "^7.0.0",
33
32
  "once": "^1.4.0",
34
33
  "try-to-catch": "^3.0.1"
35
34
  },
@@ -38,26 +37,25 @@
38
37
  "eslint"
39
38
  ],
40
39
  "devDependencies": {
41
- "@putout/eslint-flat": "^2.0.0",
40
+ "@putout/eslint-flat": "^3.0.0",
42
41
  "@putout/plugin-eslint-plugin": "*",
43
42
  "c8": "^10.0.0",
44
- "eslint": "^9.0.0",
43
+ "eslint": "^10.0.0-alpha.0",
45
44
  "eslint-plugin-n": "^17.0.0",
46
- "eslint-plugin-putout": "^24.1.0",
47
- "madrun": "^10.0.0",
48
- "mock-require": "^3.0.3",
45
+ "eslint-plugin-putout": "^29.0.0",
46
+ "madrun": "^11.0.0",
49
47
  "montag": "^1.0.0",
50
48
  "nodemon": "^3.0.1",
51
49
  "putout": "*",
52
- "supertape": "^10.0.0",
50
+ "supertape": "^11.0.3",
53
51
  "try-catch": "^3.0.0"
54
52
  },
55
53
  "peerDependencies": {
56
- "eslint": ">=8"
54
+ "eslint": ">=9"
57
55
  },
58
56
  "license": "MIT",
59
57
  "engines": {
60
- "node": ">=18"
58
+ "node": ">=20"
61
59
  },
62
60
  "publishConfig": {
63
61
  "access": "public"
@@ -1,110 +0,0 @@
1
- import {dirname} from 'node:path';
2
- import process from 'node:process';
3
- import {loadESLint} from 'eslint';
4
- import {findUp} from 'find-up';
5
-
6
- const {isArray} = Array;
7
- const maybeArray = (a) => isArray(a) ? a : [a];
8
- const CWD = process.cwd();
9
-
10
- export const getESLint = async ({name, fix, config, overrideConfigFile, loadESLintOverride, find = findUp, findFlat = find, findRC = find}) => {
11
- const cwd = dirname(name).replace(/^\./, CWD);
12
- const eslint = await chooseESLint({
13
- fix,
14
- cwd,
15
- config,
16
- overrideConfigFile,
17
- loadESLintOverride,
18
- findFlat,
19
- findRC,
20
- });
21
-
22
- return {
23
- calculateConfigForFile: eslint.calculateConfigForFile.bind(eslint),
24
- lintText: eslint.lintText.bind(eslint),
25
- };
26
- };
27
-
28
- async function chooseESLint({cwd, config, fix, overrideConfigFile, loadESLintOverride, findFlat, findRC}) {
29
- const runESLint = await getESLintRunner({
30
- cwd,
31
- overrideConfigFile,
32
- findFlat,
33
- findRC,
34
- });
35
-
36
- return await runESLint({
37
- loadESLintOverride,
38
- cwd,
39
- config,
40
- overrideConfigFile,
41
- fix,
42
- });
43
- }
44
-
45
- async function getOldESLint({cwd, fix, config, overrideConfigFile, loadESLintOverride = loadESLint}) {
46
- const ESLint = await loadESLintOverride({
47
- useFlatConfig: false,
48
- });
49
-
50
- const eslint = new ESLint({
51
- cwd,
52
- fix,
53
- overrideConfig: {
54
- ignorePatterns: ['!.*'],
55
- ...config,
56
- },
57
- ...overrideConfigFile && {
58
- overrideConfigFile,
59
- useEslintrc: false,
60
- },
61
- });
62
-
63
- return eslint;
64
- }
65
-
66
- async function getFlatESLint({cwd, fix, config = [], overrideConfigFile, loadESLintOverride = loadESLint}) {
67
- const FlatESLint = await loadESLintOverride({
68
- useFlatConfig: true,
69
- });
70
-
71
- const eslint = new FlatESLint({
72
- cwd,
73
- fix,
74
- overrideConfig: [
75
- ...maybeArray(config), {
76
- ignores: ['!.*'],
77
- }
78
- ,
79
- ],
80
- ...overrideConfigFile && {
81
- overrideConfigFile,
82
- },
83
- });
84
-
85
- return eslint;
86
- }
87
-
88
- const isFlat = (a) => a?.includes('config');
89
-
90
- async function getESLintRunner({cwd, findFlat, findRC, overrideConfigFile}) {
91
- if (overrideConfigFile)
92
- return isFlat(overrideConfigFile) ? getFlatESLint : getOldESLint;
93
-
94
- const [rcConfig = '', flatConfig = ''] = await Promise.all([
95
- findRC(['.eslintrc.json', '.eslintrc.js'], {
96
- cwd,
97
- }),
98
- findFlat(['eslint.config.js', 'eslint.config.mjs', 'eslint.config.cjs'], {
99
- cwd,
100
- }),
101
- ]);
102
-
103
- const noConfigFound = !rcConfig && !flatConfig;
104
- const foundRConfig = rcConfig.length > flatConfig.length;
105
-
106
- if (noConfigFound || foundRConfig)
107
- return getOldESLint;
108
-
109
- return getFlatESLint;
110
- }