linter-bundle 2.22.0 → 2.24.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/CHANGELOG.md +23 -1
- package/README.md +1 -1
- package/eslint/index.js +1 -1
- package/eslint/overrides-gatsby.js +3 -3
- package/eslint/overrides-javascript.js +41 -41
- package/eslint/overrides-jest.js +1 -1
- package/eslint/rules/no-unnecessary-typeof.js +79 -64
- package/helper/find-missing-overrides.js +48 -0
- package/helper/is-npm-or-yarn.js +48 -0
- package/lint.js +56 -17
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -6,7 +6,29 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
-
[Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v2.
|
|
9
|
+
[Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v2.24.0...HEAD)
|
|
10
|
+
|
|
11
|
+
## [2.24.0] - 2022-09-23
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- [eslint/overrides-javascript] Replace [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node) by the fork [eslint-plugin-n](https://github.com/eslint-community/eslint-plugin-n)
|
|
16
|
+
|
|
17
|
+
[Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v2.23.0...v2.24.0)
|
|
18
|
+
|
|
19
|
+
## [2.23.0] - 2022-09-21
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- [general] Add functionality to ensure that the installed dependencies match to the required dependency of the linter-bundle
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- [eslint] Updated `eslint-plugin-functional` from `4.3.2` to `4.4.0`
|
|
28
|
+
- [stylelint] Updated `stylelint` from `14.12.0` to `14.12.1`
|
|
29
|
+
- [eslint] Improved [`no-unnecessary-typeof`](./eslint/rules/no-unnecessary-typeof.md) to cover even more cases and fix false-positives
|
|
30
|
+
|
|
31
|
+
[Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v2.22.0...v2.23.0)
|
|
10
32
|
|
|
11
33
|
## [2.22.0] - 2022-09-19
|
|
12
34
|
|
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ This setup is using the following additional plugins:
|
|
|
29
29
|
- [eslint-plugin-jest](https://www.npmjs.com/package/eslint-plugin-jest)
|
|
30
30
|
- [eslint-plugin-jsdoc](https://www.npmjs.com/package/eslint-plugin-jsdoc)
|
|
31
31
|
- [eslint-plugin-jsx-a11y](https://www.npmjs.com/package/eslint-plugin-jsx-a11y)
|
|
32
|
-
- [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node)
|
|
32
|
+
- [eslint-plugin-n](https://github.com/eslint-community/eslint-plugin-n) (fork of [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node))
|
|
33
33
|
- [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise)
|
|
34
34
|
- [eslint-plugin-react-hooks](https://www.npmjs.com/package/eslint-plugin-react-hooks)
|
|
35
35
|
- [eslint-plugin-react](https://www.npmjs.com/package/eslint-plugin-react)
|
package/eslint/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
/* eslint-disable max-lines -- The rules can be easier managed if they are all in one file */
|
|
6
|
-
/* eslint-disable
|
|
6
|
+
/* eslint-disable n/no-process-env -- `process.env` is required to inject configuration adjustments */
|
|
7
7
|
|
|
8
8
|
const fs = require('fs');
|
|
9
9
|
const path = require('path');
|
|
@@ -105,11 +105,11 @@ module.exports = {
|
|
|
105
105
|
files: ['gatsby-browser.js'],
|
|
106
106
|
rules: {
|
|
107
107
|
/**
|
|
108
|
-
* eslint-plugin-
|
|
108
|
+
* eslint-plugin-n
|
|
109
109
|
*
|
|
110
|
-
* @see https://github.com/
|
|
110
|
+
* @see https://github.com/eslint-community/eslint-plugin-n
|
|
111
111
|
*/
|
|
112
|
-
'
|
|
112
|
+
'n/no-unsupported-features/es-syntax': 'off'
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
]
|
|
@@ -10,7 +10,7 @@ module.exports = {
|
|
|
10
10
|
node: true,
|
|
11
11
|
es6: true
|
|
12
12
|
},
|
|
13
|
-
plugins: ['
|
|
13
|
+
plugins: ['n'],
|
|
14
14
|
rules: {
|
|
15
15
|
/**
|
|
16
16
|
* eslint
|
|
@@ -47,53 +47,53 @@ module.exports = {
|
|
|
47
47
|
'import/no-nodejs-modules': 'off',
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
* eslint-plugin-
|
|
50
|
+
* eslint-plugin-n
|
|
51
51
|
*
|
|
52
|
-
* @see https://github.com/
|
|
52
|
+
* @see https://github.com/eslint-community/eslint-plugin-n
|
|
53
53
|
*/
|
|
54
54
|
|
|
55
55
|
// Possible Errors
|
|
56
|
-
'
|
|
57
|
-
'
|
|
58
|
-
'
|
|
59
|
-
'
|
|
60
|
-
'
|
|
61
|
-
'
|
|
62
|
-
'
|
|
63
|
-
'
|
|
64
|
-
'
|
|
65
|
-
'
|
|
66
|
-
'
|
|
67
|
-
'
|
|
68
|
-
'
|
|
69
|
-
'
|
|
70
|
-
'
|
|
71
|
-
'
|
|
72
|
-
'
|
|
73
|
-
'
|
|
56
|
+
'n/handle-callback-err': 'error',
|
|
57
|
+
'n/no-callback-literal': 'error',
|
|
58
|
+
'n/no-exports-assign': 'error',
|
|
59
|
+
'n/no-extraneous-import': 'error',
|
|
60
|
+
'n/no-extraneous-require': 'error',
|
|
61
|
+
'n/no-missing-import': 'error',
|
|
62
|
+
'n/no-missing-require': 'error',
|
|
63
|
+
'n/no-new-require': 'error',
|
|
64
|
+
'n/no-path-concat': 'error',
|
|
65
|
+
'n/no-process-exit': 'error',
|
|
66
|
+
'n/no-unpublished-bin': 'error',
|
|
67
|
+
'n/no-unpublished-import': 'error',
|
|
68
|
+
'n/no-unpublished-require': 'off', // Since we use .js files only for the dev-environment, we don't need this rule
|
|
69
|
+
'n/no-unsupported-features/es-builtins': 'error',
|
|
70
|
+
'n/no-unsupported-features/es-syntax': 'error',
|
|
71
|
+
'n/no-unsupported-features/node-builtins': 'error',
|
|
72
|
+
'n/process-exit-as-throw': 'error',
|
|
73
|
+
'n/shebang': 'error',
|
|
74
74
|
|
|
75
75
|
// Best Practices
|
|
76
|
-
'
|
|
76
|
+
'n/no-deprecated-api': 'error',
|
|
77
77
|
|
|
78
78
|
// Stylistic Issues
|
|
79
|
-
'
|
|
80
|
-
'
|
|
81
|
-
'
|
|
82
|
-
'
|
|
83
|
-
'
|
|
84
|
-
'
|
|
85
|
-
'
|
|
86
|
-
'
|
|
87
|
-
'
|
|
88
|
-
'
|
|
89
|
-
'
|
|
90
|
-
'
|
|
91
|
-
'
|
|
92
|
-
'
|
|
93
|
-
'
|
|
94
|
-
'
|
|
95
|
-
'
|
|
96
|
-
'
|
|
79
|
+
'n/callback-return': 'error',
|
|
80
|
+
'n/exports-style': 'error',
|
|
81
|
+
'n/file-extension-in-import': 'error',
|
|
82
|
+
'n/global-require': 'off',
|
|
83
|
+
'n/no-mixed-requires': 'error',
|
|
84
|
+
'n/no-process-env': 'error',
|
|
85
|
+
'n/no-restricted-import': 'error',
|
|
86
|
+
'n/no-restricted-require': 'error',
|
|
87
|
+
'n/no-sync': 'off', // Since the .js files are used in the CLI, preventing the use of sync functions is not required
|
|
88
|
+
'n/prefer-global/buffer': 'error',
|
|
89
|
+
'n/prefer-global/console': 'error',
|
|
90
|
+
'n/prefer-global/process': 'error',
|
|
91
|
+
'n/prefer-global/text-decoder': 'error',
|
|
92
|
+
'n/prefer-global/text-encoder': 'error',
|
|
93
|
+
'n/prefer-global/url-search-params': 'error',
|
|
94
|
+
'n/prefer-global/url': 'error',
|
|
95
|
+
'n/prefer-promises/dns': 'error',
|
|
96
|
+
'n/prefer-promises/fs': 'error',
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
99
|
* eslint-plugin-unicorn
|
|
@@ -105,7 +105,7 @@ module.exports = {
|
|
|
105
105
|
kebabCase: true
|
|
106
106
|
}
|
|
107
107
|
}],
|
|
108
|
-
'unicorn/no-process-exit': 'off', //
|
|
108
|
+
'unicorn/no-process-exit': 'off', // n/no-process-exit
|
|
109
109
|
'unicorn/prefer-module': 'off', // @todo Requires Node.js v13.2. Activate in 2023
|
|
110
110
|
'unicorn/prefer-node-protocol': 'off', // @todo Requires Node.js v16. Activate in 2025
|
|
111
111
|
'unicorn/prevent-abbreviations': ['error', { ignore: ['args', 'dev', 'env', 'i', 'j', 'i18n', 'pkg', 'ref', 'Ref', 'req', 'res', 'setupDevServerMiddleware'] }],
|
package/eslint/overrides-jest.js
CHANGED
|
@@ -13,7 +13,7 @@ module.exports = {
|
|
|
13
13
|
jest: {
|
|
14
14
|
version: (() => {
|
|
15
15
|
try {
|
|
16
|
-
// eslint-disable-next-line
|
|
16
|
+
// eslint-disable-next-line n/no-missing-require, import/no-dynamic-require -- If "overrides-jest" is used, "jest" should be installed, and it should be searched in the working directory of the process.
|
|
17
17
|
const jestVersion = require(require.resolve('jest', { paths: [process.cwd()] })).getVersion().split('.')[0];
|
|
18
18
|
|
|
19
19
|
process.stdout.write(`Detected Jest version: ${jestVersion}\n\n`);
|
|
@@ -18,14 +18,13 @@ module.exports = {
|
|
|
18
18
|
recommended: true
|
|
19
19
|
},
|
|
20
20
|
messages: {
|
|
21
|
-
|
|
22
|
-
textWithoutType: 'Unnecessary `typeof`, because there is only one possible type of `{{ name }}`.'
|
|
21
|
+
text: 'Unnecessary `typeof`, because the only possible type of {{ variableName }} is `{{ typeName }}`.'
|
|
23
22
|
}
|
|
24
23
|
},
|
|
25
24
|
create (context) {
|
|
26
25
|
return {
|
|
27
26
|
UnaryExpression (node) {
|
|
28
|
-
if (node.operator !== 'typeof'
|
|
27
|
+
if (node.operator !== 'typeof') {
|
|
29
28
|
return;
|
|
30
29
|
}
|
|
31
30
|
|
|
@@ -39,26 +38,18 @@ module.exports = {
|
|
|
39
38
|
/** @type {Type} */
|
|
40
39
|
const nodeType = checker.getTypeAtLocation(originalNode);
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
context.report({
|
|
55
|
-
node,
|
|
56
|
-
messageId: 'textWithoutType',
|
|
57
|
-
data: {
|
|
58
|
-
name: node.argument.name
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
}
|
|
41
|
+
const variableName = checker.getSymbolAtLocation(originalNode)?.getName();
|
|
42
|
+
const typeName = getSingleType(checker, nodeType);
|
|
43
|
+
|
|
44
|
+
if (typeName !== null) {
|
|
45
|
+
context.report({
|
|
46
|
+
node,
|
|
47
|
+
messageId: 'text',
|
|
48
|
+
data: {
|
|
49
|
+
variableName: (variableName ? `\`${variableName}\`` : `the ${node.argument.type.replace(/[A-Z]/gu, (substring) => ` ${substring.toLowerCase()}`).trim()}`),
|
|
50
|
+
typeName
|
|
51
|
+
}
|
|
52
|
+
});
|
|
62
53
|
}
|
|
63
54
|
}
|
|
64
55
|
};
|
|
@@ -66,33 +57,64 @@ module.exports = {
|
|
|
66
57
|
};
|
|
67
58
|
|
|
68
59
|
/**
|
|
69
|
-
* Check if the number of types equals one.
|
|
60
|
+
* Check if the number of types equals one, and returns the type.
|
|
70
61
|
*
|
|
62
|
+
* @param {ts.TypeChecker} checker - TypeScript type checker.
|
|
71
63
|
* @param {Type} type - TypeScript type node.
|
|
72
|
-
* @returns {
|
|
64
|
+
* @returns {string | null} Type as string match the `typeof` string, or `null` if it's not a primitive type.
|
|
73
65
|
*/
|
|
74
|
-
function
|
|
66
|
+
function getSingleType (checker, type) {
|
|
75
67
|
if (isAnyOrUnknown(type)) {
|
|
76
|
-
return
|
|
68
|
+
return null;
|
|
77
69
|
}
|
|
78
70
|
|
|
79
71
|
if (!type.types) {
|
|
80
|
-
return
|
|
72
|
+
return getTypeString(checker, type);
|
|
81
73
|
}
|
|
82
74
|
|
|
83
|
-
const firstType = type.types[0];
|
|
75
|
+
const firstType = getTypeString(checker, type.types[0]);
|
|
84
76
|
|
|
85
|
-
if (
|
|
86
|
-
return
|
|
77
|
+
if (firstType === null) {
|
|
78
|
+
return null;
|
|
87
79
|
}
|
|
88
80
|
|
|
89
81
|
for (let i = 1; i < type.types.length; i++) {
|
|
90
|
-
if (
|
|
91
|
-
return
|
|
82
|
+
if (getTypeString(checker, type.types[i]) !== firstType) {
|
|
83
|
+
return null;
|
|
92
84
|
}
|
|
93
85
|
}
|
|
94
86
|
|
|
95
|
-
return
|
|
87
|
+
return firstType;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Converts a TypeScript type into a `typeof` compatible string, or `null` if it's not a primitive type.
|
|
92
|
+
*
|
|
93
|
+
* @param {ts.TypeChecker} checker - TypeScript type checker.
|
|
94
|
+
* @param {Type} type - TypeScript type node.
|
|
95
|
+
* @returns {string | null} Type as string match the `typeof` string, or `null` if it's not a primitive type.
|
|
96
|
+
*/
|
|
97
|
+
function getTypeString (checker, type) {
|
|
98
|
+
if (isAnyOrUnknown(type)) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const typeString = checker.typeToString(type);
|
|
103
|
+
|
|
104
|
+
if (['undefined', 'boolean', 'number', 'bigint', 'string', 'symbol', 'function', 'object'].includes(typeString)) {
|
|
105
|
+
return typeString;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (isUndefined(type)) { return 'undefined'; }
|
|
109
|
+
if (isBoolean(type)) { return 'boolean'; }
|
|
110
|
+
if (isNumber(type)) { return 'number'; }
|
|
111
|
+
if (isBigInt(type)) { return 'bigint'; }
|
|
112
|
+
if (isString(type)) { return 'string'; }
|
|
113
|
+
if (isSymbol(type)) { return 'symbol'; }
|
|
114
|
+
if (isFunction(type)) { return 'function'; }
|
|
115
|
+
if (isObject(type)) { return 'object'; }
|
|
116
|
+
|
|
117
|
+
return null;
|
|
96
118
|
}
|
|
97
119
|
|
|
98
120
|
/**
|
|
@@ -106,35 +128,6 @@ function isAnyOrUnknown (type) {
|
|
|
106
128
|
return (type.flags === ts.TypeFlags.Any || type.flags === ts.TypeFlags.Unknown || (type.flags === ts.TypeFlags.Object && type.symbol === undefined));
|
|
107
129
|
}
|
|
108
130
|
|
|
109
|
-
/**
|
|
110
|
-
* Check if two types are identical.
|
|
111
|
-
*
|
|
112
|
-
* @param {Type} type1 - TypeScript type node.
|
|
113
|
-
* @param {Type} type2 - TypeScript type node.
|
|
114
|
-
* @returns {boolean} Returns `true` if both types are identical.
|
|
115
|
-
*/
|
|
116
|
-
function isDifferentType (type1, type2) {
|
|
117
|
-
if (isString(type1) && isString(type2)) { return false; }
|
|
118
|
-
if (isNumber(type1) && isNumber(type2)) { return false; }
|
|
119
|
-
if (isBigInt(type1) && isBigInt(type2)) { return false; }
|
|
120
|
-
if (isBoolean(type1) && isBoolean(type2)) { return false; }
|
|
121
|
-
if (isSymbol(type1) && isSymbol(type2)) { return false; }
|
|
122
|
-
|
|
123
|
-
if (type1.flags !== type2.flags) {
|
|
124
|
-
return true;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (type1.flags === ts.TypeFlags.Object) {
|
|
128
|
-
if (isFunction(type1)) {
|
|
129
|
-
return !isFunction(type2);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return isFunction(type2);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
131
|
/**
|
|
139
132
|
* Checks if the given `type` is a `string`.
|
|
140
133
|
*
|
|
@@ -192,5 +185,27 @@ function isSymbol (type) {
|
|
|
192
185
|
* @returns {boolean} Returns `true` if the type is a `function`.
|
|
193
186
|
*/
|
|
194
187
|
function isFunction (type) {
|
|
195
|
-
return (type.objectFlags === ts.ObjectFlags.Anonymous);
|
|
188
|
+
return (type.flags === ts.TypeFlags.Object && type.objectFlags === ts.ObjectFlags.Anonymous);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Checks if the given `type` is a `undefined`.
|
|
193
|
+
*
|
|
194
|
+
* @param {Type} type - TypeScript type node.
|
|
195
|
+
* @returns {boolean} Returns `true` if the type is `undefined`.
|
|
196
|
+
*/
|
|
197
|
+
function isUndefined (type) {
|
|
198
|
+
return [ts.TypeFlags.Undefined].includes(type.flags);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Checks if the given `type` is a `object`.
|
|
203
|
+
*
|
|
204
|
+
* We don't check `ts.TypeFlags.Object`, because for TypeScript Object seems to be the fallback for everything - even unknown types.
|
|
205
|
+
*
|
|
206
|
+
* @param {Type} type - TypeScript type node.
|
|
207
|
+
* @returns {boolean} Returns `true` if the type is an `object`.
|
|
208
|
+
*/
|
|
209
|
+
function isObject (type) {
|
|
210
|
+
return [ts.TypeFlags.Null].includes(type.flags);
|
|
196
211
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Ensures that the installed dependencies of the project matches to the versions used by the linter-bundle.
|
|
3
|
+
*
|
|
4
|
+
* @see https://docs.npmjs.com/cli/v8/configuring-npm/package-json#overrides
|
|
5
|
+
* @see https://classic.yarnpkg.com/en/docs/selective-version-resolutions/
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
/** @typedef {{ name: string; configuredVersion: string; expectedVersion: string; }} Dependency */
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Detects if installed versions of dependencies don't match to the required dependencies.
|
|
15
|
+
*
|
|
16
|
+
* @returns {Dependency[]} An array of missing overrides (=wrong versions).
|
|
17
|
+
*/
|
|
18
|
+
function findMissingOverrides () {
|
|
19
|
+
const linterBundleDependencies = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf8')).dependencies;
|
|
20
|
+
|
|
21
|
+
const result = [];
|
|
22
|
+
|
|
23
|
+
for (const [name, expectedVersion] of Object.entries(linterBundleDependencies)) {
|
|
24
|
+
let dependenyPackageJson;
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
dependenyPackageJson = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'node_modules', name, 'package.json'), 'utf8'));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// If the file does not exist, we ignore it, because in this case it's most likely a linter-bundle-only dependency.
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (dependenyPackageJson.version !== expectedVersion) {
|
|
35
|
+
result.push({
|
|
36
|
+
name,
|
|
37
|
+
configuredVersion: dependenyPackageJson.version,
|
|
38
|
+
expectedVersion
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = {
|
|
47
|
+
findMissingOverrides
|
|
48
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Check if the project is using npm or yarn by checking the existance of a `package-lock.json` or a `yarn.lock`.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns if the project is using npm or yarn.
|
|
10
|
+
*
|
|
11
|
+
* @returns {'none' | 'npm' | 'yarn' | 'both'} Returns which package manager name.
|
|
12
|
+
*/
|
|
13
|
+
function isNpmOrYarn () {
|
|
14
|
+
let npm = false;
|
|
15
|
+
let yarn = false;
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
fs.accessSync(path.join(process.cwd(), 'package-lock.json'), fs.constants.R_OK);
|
|
19
|
+
|
|
20
|
+
npm = true;
|
|
21
|
+
}
|
|
22
|
+
catch { /* `package-lock.json` cannot be accessed. */ }
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
fs.accessSync(path.join(process.cwd(), 'yarn.lock'), fs.constants.R_OK);
|
|
26
|
+
|
|
27
|
+
yarn = true;
|
|
28
|
+
}
|
|
29
|
+
catch { /* `yarn.lock` cannot be accessed. */ }
|
|
30
|
+
|
|
31
|
+
if (npm && yarn) {
|
|
32
|
+
return 'both';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (npm) {
|
|
36
|
+
return 'npm';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (yarn) {
|
|
40
|
+
return 'yarn';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return 'none';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = {
|
|
47
|
+
isNpmOrYarn
|
|
48
|
+
};
|
package/lint.js
CHANGED
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
* @file Entry point of the linter-bundle.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const fs = require('fs');
|
|
8
7
|
const path = require('path');
|
|
9
8
|
const tty = require('tty');
|
|
10
9
|
|
|
11
10
|
const micromatch = require('micromatch');
|
|
12
11
|
|
|
12
|
+
const { findMissingOverrides } = require('./helper/find-missing-overrides.js');
|
|
13
|
+
const { isNpmOrYarn } = require('./helper/is-npm-or-yarn.js');
|
|
13
14
|
const { runProcess } = require('./helper/run-process.js');
|
|
14
15
|
const { validatePackageOverrides } = require('./helper/validate-package-overrides.js');
|
|
15
16
|
|
|
@@ -21,21 +22,9 @@ const { validatePackageOverrides } = require('./helper/validate-package-override
|
|
|
21
22
|
const isTerminal = tty.isatty(1);
|
|
22
23
|
|
|
23
24
|
void (async () => {
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
if (outdatedOverrides.overrides.length > 0 || outdatedOverrides.resolutions.length > 0) {
|
|
27
|
-
if (outdatedOverrides.overrides.length > 0) {
|
|
28
|
-
process.stderr.write(`Outdated "overrides" in package.json detected:\n- ${outdatedOverrides.overrides.map((dependency) => `${dependency.name}: ${dependency.configuredVersion} is configured, but ${dependency.expectedVersion} is expected`).join('\n- ')}\n\n`);
|
|
29
|
-
}
|
|
25
|
+
const npmOrYarn = isNpmOrYarn();
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
process.stderr.write(`Outdated "resolutions" in package.json detected:\n- ${outdatedOverrides.resolutions.map((dependency) => `${dependency.name}: ${dependency.configuredVersion} is configured, but ${dependency.expectedVersion} is expected`).join('\n- ')}\n\n`);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
process.exitCode = 1;
|
|
36
|
-
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
27
|
+
validateEnvironment(npmOrYarn);
|
|
39
28
|
|
|
40
29
|
/** @type {{ diff: Promise<ProcessResult>; modified: Promise<ProcessResult>; deleted: Promise<ProcessResult>; } | undefined} */
|
|
41
30
|
let gitFilesProcessPromise;
|
|
@@ -151,7 +140,7 @@ void (async () => {
|
|
|
151
140
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- This is not a valid `audit` property, so we need to remove it.
|
|
152
141
|
delete config['git'];
|
|
153
142
|
|
|
154
|
-
if (
|
|
143
|
+
if (npmOrYarn === 'npm') {
|
|
155
144
|
return runTask({
|
|
156
145
|
taskName,
|
|
157
146
|
config,
|
|
@@ -167,7 +156,7 @@ void (async () => {
|
|
|
167
156
|
].filter((argument) => Boolean(argument)).join(' ')
|
|
168
157
|
});
|
|
169
158
|
}
|
|
170
|
-
else if (
|
|
159
|
+
else if (npmOrYarn === 'yarn') {
|
|
171
160
|
return runTask({
|
|
172
161
|
taskName,
|
|
173
162
|
config,
|
|
@@ -246,6 +235,56 @@ void (async () => {
|
|
|
246
235
|
process.stdout.write('\n');
|
|
247
236
|
})();
|
|
248
237
|
|
|
238
|
+
/**
|
|
239
|
+
* Ensures that the environment in which the linter is running has the correct versions of the required dependencies.
|
|
240
|
+
*
|
|
241
|
+
* @param {ReturnType<isNpmOrYarn>} npmOrYarn - This should be the return value of `isNpmOrYarn()`.
|
|
242
|
+
* @returns {void}
|
|
243
|
+
*/
|
|
244
|
+
function validateEnvironment (npmOrYarn) {
|
|
245
|
+
const outdatedOverrides = validatePackageOverrides();
|
|
246
|
+
|
|
247
|
+
if (outdatedOverrides.overrides.length > 0 || outdatedOverrides.resolutions.length > 0) {
|
|
248
|
+
if (outdatedOverrides.overrides.length > 0) {
|
|
249
|
+
process.stderr.write(`Outdated "overrides" in package.json detected:\n- ${outdatedOverrides.overrides.map((dependency) => `${dependency.name}: ${dependency.configuredVersion} is configured, but ${dependency.expectedVersion} is expected`).join('\n- ')}\n\n`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (outdatedOverrides.resolutions.length > 0) {
|
|
253
|
+
process.stderr.write(`Outdated "resolutions" in package.json detected:\n- ${outdatedOverrides.resolutions.map((dependency) => `${dependency.name}: ${dependency.configuredVersion} is configured, but ${dependency.expectedVersion} is expected`).join('\n- ')}\n\n`);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
process.exitCode = 1;
|
|
257
|
+
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const missingOverrides = findMissingOverrides().filter(({ name }) => !(npmOrYarn === 'npm' && outdatedOverrides.overrides.some((override) => name === override.name)) && !(npmOrYarn === 'yarn' && outdatedOverrides.resolutions.some((override) => name === override.name)));
|
|
262
|
+
|
|
263
|
+
if (missingOverrides.length > 0) {
|
|
264
|
+
let installCommand;
|
|
265
|
+
let propertyName;
|
|
266
|
+
|
|
267
|
+
if (npmOrYarn === 'yarn') {
|
|
268
|
+
installCommand = 'yarn install';
|
|
269
|
+
propertyName = 'resolutions';
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
installCommand = 'npm install';
|
|
273
|
+
propertyName = 'overrides';
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
process.stderr.write(`The installed version of ${missingOverrides.length === 1 ? 'one dependency' : `${missingOverrides.length} dependencies`} does not match to the version required by the linter-bundle:\n`);
|
|
277
|
+
process.stderr.write(`- ${missingOverrides.map((dependency) => `${dependency.name}: ${dependency.configuredVersion} is installed, but ${dependency.expectedVersion} is expected`).join('\n- ')}\n\n`);
|
|
278
|
+
process.stderr.write(`This could be caused by forgetting to execute \`${installCommand}\` after changing a version number in the package.json, or by some other package shipping outdated versions of the ${missingOverrides.length === 1 ? 'dependency' : 'dependencies'}.\n`);
|
|
279
|
+
process.stderr.write('If another package is causing this problem, you can fix it by adding the following entry to your package.json:\n');
|
|
280
|
+
process.stderr.write(`{\n "${propertyName}: {\n ${missingOverrides.map((dependency) => `"${dependency.name}": "${dependency.expectedVersion}"`).join(',\n ')}\n }\n}\n\n`);
|
|
281
|
+
|
|
282
|
+
process.exitCode = 1;
|
|
283
|
+
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
249
288
|
/**
|
|
250
289
|
* Extracts the tasks which should be run from the command-line arguments passed in.
|
|
251
290
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "linter-bundle",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.24.0",
|
|
4
4
|
"description": "Ready-to use bundle of linting tools, containing configurations for ESLint, stylelint and markdownlint.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eslint",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
"eslint-import-resolver-typescript": "3.5.1",
|
|
48
48
|
"eslint-import-resolver-webpack": "0.13.2",
|
|
49
49
|
"eslint-plugin-eslint-comments": "3.2.0",
|
|
50
|
-
"eslint-plugin-functional": "4.
|
|
50
|
+
"eslint-plugin-functional": "4.4.0",
|
|
51
51
|
"eslint-plugin-import": "2.26.0",
|
|
52
52
|
"eslint-plugin-jest": "27.0.4",
|
|
53
53
|
"eslint-plugin-jsdoc": "39.3.6",
|
|
54
54
|
"eslint-plugin-jsx-a11y": "6.6.1",
|
|
55
|
-
"eslint-plugin-
|
|
55
|
+
"eslint-plugin-n": "15.3.0",
|
|
56
56
|
"eslint-plugin-promise": "6.0.1",
|
|
57
57
|
"eslint-plugin-react": "7.31.8",
|
|
58
58
|
"eslint-plugin-react-hooks": "4.6.0",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"markdownlint-cli": "0.32.2",
|
|
61
61
|
"micromatch": "4.0.5",
|
|
62
62
|
"postcss-scss": "4.0.5",
|
|
63
|
-
"stylelint": "14.12.
|
|
63
|
+
"stylelint": "14.12.1",
|
|
64
64
|
"stylelint-declaration-block-no-ignored-properties": "2.5.0",
|
|
65
65
|
"stylelint-order": "5.0.0",
|
|
66
66
|
"stylelint-scss": "4.3.0",
|