@blumintinc/eslint-plugin-blumint 1.0.2 → 1.0.4
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 +62 -283
- package/lib/index.d.ts +1 -0
- package/lib/index.js +69 -0
- package/lib/rules/array-methods-this-context.d.ts +3 -0
- package/lib/rules/array-methods-this-context.js +64 -0
- package/lib/rules/class-methods-read-top-to-bottom.d.ts +2 -0
- package/lib/rules/class-methods-read-top-to-bottom.js +72 -0
- package/lib/rules/dynamic-https-errors.d.ts +2 -0
- package/lib/rules/dynamic-https-errors.js +57 -0
- package/lib/rules/export-if-in-doubt.d.ts +2 -0
- package/lib/rules/export-if-in-doubt.js +69 -0
- package/lib/rules/extract-global-constants.d.ts +2 -0
- package/lib/rules/extract-global-constants.js +63 -0
- package/lib/rules/generic-starts-with-t.d.ts +2 -0
- package/lib/rules/generic-starts-with-t.js +35 -0
- package/lib/rules/no-async-array-filter.d.ts +2 -0
- package/lib/rules/no-async-array-filter.js +40 -0
- package/lib/rules/no-async-foreach.d.ts +2 -0
- package/lib/rules/no-async-foreach.js +37 -0
- package/lib/rules/no-conditional-literals-in-jsx.d.ts +2 -0
- package/lib/rules/no-conditional-literals-in-jsx.js +61 -0
- package/lib/rules/no-filter-without-return.d.ts +2 -0
- package/lib/rules/no-filter-without-return.js +41 -0
- package/lib/rules/no-misused-switch-case.d.ts +2 -0
- package/lib/rules/no-misused-switch-case.js +35 -0
- package/lib/rules/no-unpinned-dependencies.d.ts +2 -0
- package/lib/rules/no-unpinned-dependencies.js +65 -0
- package/lib/rules/no-useless-fragment.d.ts +2 -0
- package/lib/rules/no-useless-fragment.js +46 -0
- package/lib/rules/prefer-fragment-shorthand.d.ts +3 -0
- package/lib/rules/prefer-fragment-shorthand.js +40 -0
- package/lib/rules/prefer-type-over-interface.d.ts +2 -0
- package/lib/rules/prefer-type-over-interface.js +45 -0
- package/lib/rules/require-memo.d.ts +6 -0
- package/lib/rules/require-memo.js +166 -0
- package/lib/utils/ASTHelpers.d.ts +12 -0
- package/lib/utils/ASTHelpers.js +336 -0
- package/lib/utils/createRule.d.ts +2 -0
- package/lib/utils/createRule.js +6 -0
- package/lib/utils/graph/ClassGraphBuilder.d.ts +29 -0
- package/lib/utils/graph/ClassGraphBuilder.js +80 -0
- package/lib/utils/graph/ClassGraphSorter.d.ts +7 -0
- package/lib/utils/graph/ClassGraphSorter.js +10 -0
- package/lib/utils/graph/ClassGraphSorterReadability.d.ts +16 -0
- package/lib/utils/graph/ClassGraphSorterReadability.js +94 -0
- package/lib/utils/ruleTester.d.ts +5 -0
- package/lib/utils/ruleTester.js +23 -0
- package/package.json +33 -13
- package/CHANGELOG.md +0 -63
- package/assets/logo.svg +0 -26
- package/jest.config.js +0 -13
- package/plugin/README.md +0 -80
- package/plugin/docs/rules/array-methods-this-context.md +0 -30
- package/plugin/docs/rules/class-methods-read-top-to-bottom.md +0 -46
- package/plugin/docs/rules/dynamic-https-errors.md +0 -23
- package/plugin/docs/rules/export-if-in-doubt.md +0 -26
- package/plugin/docs/rules/extract-global-constants.md +0 -33
- package/plugin/docs/rules/generic-starts-with-t.md +0 -33
- package/plugin/docs/rules/no-async-array-filter.md +0 -32
- package/plugin/docs/rules/no-async-foreach.md +0 -41
- package/plugin/docs/rules/no-conditional-literals-in-jsx.md +0 -27
- package/plugin/docs/rules/no-filter-without-return.md +0 -43
- package/plugin/docs/rules/no-misused-switch-case.md +0 -38
- package/plugin/docs/rules/no-unpinned-dependencies.md +0 -34
- package/plugin/docs/rules/no-useless-fragment.md +0 -25
- package/plugin/docs/rules/prefer-fragment-shorthand.md +0 -25
- package/plugin/docs/rules/prefer-type-over-interface.md +0 -25
- package/plugin/docs/rules/require-memo.md +0 -36
- package/plugin/package-lock.json +0 -7662
- package/plugin/package.json +0 -45
- package/tsconfig.json +0 -79
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.exportIfInDoubt = void 0;
|
|
4
|
+
/* eslint-disable @blumintinc/blumint/extract-global-constants */
|
|
5
|
+
// import { ASTHelpers } from '../utils/ASTHelpers';
|
|
6
|
+
const createRule_1 = require("../utils/createRule");
|
|
7
|
+
exports.exportIfInDoubt = (0, createRule_1.createRule)({
|
|
8
|
+
name: 'export-if-in-doubt',
|
|
9
|
+
meta: {
|
|
10
|
+
type: 'suggestion',
|
|
11
|
+
docs: {
|
|
12
|
+
description: 'All top-level const definitions, type definitions, and functions should be exported',
|
|
13
|
+
recommended: 'warn',
|
|
14
|
+
},
|
|
15
|
+
schema: [],
|
|
16
|
+
messages: {
|
|
17
|
+
exportIfInDoubt: 'Top-level const definitions, type definitions, and functions should be exported.',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultOptions: [],
|
|
21
|
+
create(context) {
|
|
22
|
+
// List of top-level declarations
|
|
23
|
+
// List of exported identifiers
|
|
24
|
+
const topLevelDeclarations = [];
|
|
25
|
+
const exportedIdentifiers = [];
|
|
26
|
+
return {
|
|
27
|
+
'Program > VariableDeclaration > VariableDeclarator, Program > FunctionDeclaration, Program > TSTypeAliasDeclaration'(node) {
|
|
28
|
+
topLevelDeclarations.push(node);
|
|
29
|
+
},
|
|
30
|
+
ExportNamedDeclaration: (node) => {
|
|
31
|
+
if (node.specifiers) {
|
|
32
|
+
node.specifiers.forEach((specifier) => {
|
|
33
|
+
if (specifier.type === 'ExportSpecifier') {
|
|
34
|
+
// Handle both normal and default export
|
|
35
|
+
const exportedName = specifier.exported.name;
|
|
36
|
+
if (!exportedIdentifiers.includes(exportedName)) {
|
|
37
|
+
exportedIdentifiers.push(exportedName);
|
|
38
|
+
}
|
|
39
|
+
// If the specifier is a default export
|
|
40
|
+
if (specifier.local.name !== exportedName) {
|
|
41
|
+
const localName = specifier.local.name;
|
|
42
|
+
if (!exportedIdentifiers.includes(localName)) {
|
|
43
|
+
exportedIdentifiers.push(localName);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
'Program:exit': () => {
|
|
51
|
+
topLevelDeclarations.forEach((node) => {
|
|
52
|
+
if ('id' in node &&
|
|
53
|
+
node.id &&
|
|
54
|
+
(node.type === 'VariableDeclarator' ||
|
|
55
|
+
node.type === 'FunctionDeclaration' ||
|
|
56
|
+
node.type === 'TSTypeAliasDeclaration') &&
|
|
57
|
+
node.id.type === 'Identifier' &&
|
|
58
|
+
!exportedIdentifiers.includes(node.id.name)) {
|
|
59
|
+
context.report({
|
|
60
|
+
node,
|
|
61
|
+
messageId: 'exportIfInDoubt',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
//# sourceMappingURL=export-if-in-doubt.js.map
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractGlobalConstants = void 0;
|
|
4
|
+
const ASTHelpers_1 = require("../utils/ASTHelpers");
|
|
5
|
+
const createRule_1 = require("../utils/createRule");
|
|
6
|
+
exports.extractGlobalConstants = (0, createRule_1.createRule)({
|
|
7
|
+
create(context) {
|
|
8
|
+
return {
|
|
9
|
+
VariableDeclaration(node) {
|
|
10
|
+
if (node.kind !== 'const') {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const scope = context.getScope();
|
|
14
|
+
const hasDependencies = node.declarations.some((declaration) => declaration.init &&
|
|
15
|
+
ASTHelpers_1.ASTHelpers.declarationIncludesIdentifier(declaration.init));
|
|
16
|
+
if (!hasDependencies &&
|
|
17
|
+
(scope.type === 'function' || scope.type === 'block')) {
|
|
18
|
+
const constName = node.declarations[0].id.name;
|
|
19
|
+
context.report({
|
|
20
|
+
node,
|
|
21
|
+
messageId: 'extractGlobalConstants',
|
|
22
|
+
data: {
|
|
23
|
+
declarationName: constName,
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
FunctionDeclaration(node) {
|
|
29
|
+
if (node.parent &&
|
|
30
|
+
(node.parent.type === 'FunctionDeclaration' ||
|
|
31
|
+
node.parent.type === 'FunctionExpression' ||
|
|
32
|
+
node.parent.type === 'ArrowFunctionExpression')) {
|
|
33
|
+
const scope = context.getScope();
|
|
34
|
+
const hasDependencies = ASTHelpers_1.ASTHelpers.blockIncludesIdentifier(node.body);
|
|
35
|
+
if (!hasDependencies && scope.type === 'function') {
|
|
36
|
+
const funcName = node.id.name;
|
|
37
|
+
context.report({
|
|
38
|
+
node,
|
|
39
|
+
messageId: 'extractGlobalConstants',
|
|
40
|
+
data: {
|
|
41
|
+
declarationName: funcName,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
name: 'extract-global-constants',
|
|
50
|
+
meta: {
|
|
51
|
+
type: 'suggestion',
|
|
52
|
+
docs: {
|
|
53
|
+
description: 'Extract constants/functions to the global scope when possible',
|
|
54
|
+
recommended: 'error',
|
|
55
|
+
},
|
|
56
|
+
schema: [],
|
|
57
|
+
messages: {
|
|
58
|
+
extractGlobalConstants: 'Move this declaration {{ declarationName }} to the global scope and rename it to UPPER_SNAKE_CASE if necessary.',
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
defaultOptions: [],
|
|
62
|
+
});
|
|
63
|
+
//# sourceMappingURL=extract-global-constants.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.genericStartsWithT = void 0;
|
|
4
|
+
const createRule_1 = require("../utils/createRule");
|
|
5
|
+
exports.genericStartsWithT = (0, createRule_1.createRule)({
|
|
6
|
+
create(context) {
|
|
7
|
+
return {
|
|
8
|
+
TSTypeParameterDeclaration(node) {
|
|
9
|
+
for (const param of node.params) {
|
|
10
|
+
if (typeof param.name.name === 'string' &&
|
|
11
|
+
param.name.name[0] !== 'T') {
|
|
12
|
+
context.report({
|
|
13
|
+
node: param,
|
|
14
|
+
messageId: 'genericStartsWithT',
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
name: 'generic-starts-with-t',
|
|
22
|
+
meta: {
|
|
23
|
+
type: 'suggestion',
|
|
24
|
+
docs: {
|
|
25
|
+
description: 'Enforce TypeScript generic types to start with T',
|
|
26
|
+
recommended: 'error',
|
|
27
|
+
},
|
|
28
|
+
schema: [],
|
|
29
|
+
messages: {
|
|
30
|
+
genericStartsWithT: 'Generic type parameter should start with T.',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
defaultOptions: [],
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=generic-starts-with-t.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noAsyncArrayFilter = void 0;
|
|
4
|
+
const createRule_1 = require("../utils/createRule");
|
|
5
|
+
exports.noAsyncArrayFilter = (0, createRule_1.createRule)({
|
|
6
|
+
create(context) {
|
|
7
|
+
return {
|
|
8
|
+
CallExpression(node) {
|
|
9
|
+
if (node.callee.type === 'MemberExpression' &&
|
|
10
|
+
node.callee.property.type === 'Identifier' &&
|
|
11
|
+
node.callee.property.name === 'filter' &&
|
|
12
|
+
node.arguments.length > 0) {
|
|
13
|
+
const callback = node.arguments[0];
|
|
14
|
+
if ((callback.type === 'FunctionExpression' ||
|
|
15
|
+
callback.type === 'ArrowFunctionExpression') &&
|
|
16
|
+
callback.async === true) {
|
|
17
|
+
context.report({
|
|
18
|
+
node: callback,
|
|
19
|
+
messageId: 'unexpected',
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
name: 'no-async-array-filter',
|
|
27
|
+
meta: {
|
|
28
|
+
type: 'problem',
|
|
29
|
+
docs: {
|
|
30
|
+
description: 'Disallow async callbacks for Array.filter',
|
|
31
|
+
recommended: 'error',
|
|
32
|
+
},
|
|
33
|
+
schema: [],
|
|
34
|
+
messages: {
|
|
35
|
+
unexpected: 'Async array filter is dangerous as a Promise object will always be truthy. You should move the asynchronous logic elsewhere.',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
defaultOptions: [],
|
|
39
|
+
});
|
|
40
|
+
//# sourceMappingURL=no-async-array-filter.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noAsyncForEach = void 0;
|
|
4
|
+
exports.noAsyncForEach = {
|
|
5
|
+
create(context) {
|
|
6
|
+
return {
|
|
7
|
+
CallExpression(node) {
|
|
8
|
+
const callee = node.callee;
|
|
9
|
+
if (callee.type === 'MemberExpression' &&
|
|
10
|
+
callee.property.type === 'Identifier' &&
|
|
11
|
+
callee.property.name === 'forEach' &&
|
|
12
|
+
node.arguments[0] &&
|
|
13
|
+
(node.arguments[0].type === 'ArrowFunctionExpression' ||
|
|
14
|
+
node.arguments[0].type === 'FunctionExpression') &&
|
|
15
|
+
node.arguments[0].async) {
|
|
16
|
+
context.report({
|
|
17
|
+
node,
|
|
18
|
+
messageId: 'noAsyncForEach',
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
meta: {
|
|
25
|
+
type: 'problem',
|
|
26
|
+
docs: {
|
|
27
|
+
description: 'Disallow Array.forEach with an async callback function',
|
|
28
|
+
recommended: 'error',
|
|
29
|
+
},
|
|
30
|
+
messages: {
|
|
31
|
+
noAsyncForEach: 'Do not use async function as callback in Array.forEach. Use a standard for loop for sequential execution or Promise.all for concurrent execution.',
|
|
32
|
+
},
|
|
33
|
+
schema: [],
|
|
34
|
+
},
|
|
35
|
+
defaultOptions: [],
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=no-async-foreach.js.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noConditionalLiteralsInJsx = void 0;
|
|
4
|
+
/* eslint-disable @blumintinc/blumint/extract-global-constants */
|
|
5
|
+
// import { ASTHelpers } from '../utils/ASTHelpers';
|
|
6
|
+
const createRule_1 = require("../utils/createRule");
|
|
7
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
8
|
+
exports.noConditionalLiteralsInJsx = (0, createRule_1.createRule)({
|
|
9
|
+
name: 'no-conditional-literals-in-jsx',
|
|
10
|
+
meta: {
|
|
11
|
+
type: 'problem',
|
|
12
|
+
docs: {
|
|
13
|
+
description: 'Disallow use of conditional literals in JSX code',
|
|
14
|
+
recommended: 'error',
|
|
15
|
+
},
|
|
16
|
+
schema: [],
|
|
17
|
+
messages: {
|
|
18
|
+
unexpected: 'Conditional expression is a sibling of raw text and must be wrapped in <div> or <span>',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
defaultOptions: [],
|
|
22
|
+
create(context) {
|
|
23
|
+
return {
|
|
24
|
+
// Imagine evaluating <div>text {conditional && 'string'}</div>
|
|
25
|
+
JSXExpressionContainer(node) {
|
|
26
|
+
// We start at the expression {conditional && 'string'}
|
|
27
|
+
if (node.expression.type !== 'LogicalExpression') {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const parentChildren = node.parent && 'children' in node.parent ? node.parent.children : [];
|
|
31
|
+
// "text" is one of the siblingTextNodes.
|
|
32
|
+
const siblingTextNodes = parentChildren.filter((n) => {
|
|
33
|
+
if (n.type === utils_1.TSESTree.AST_NODE_TYPES.Literal ||
|
|
34
|
+
n.type === utils_1.TSESTree.AST_NODE_TYPES.JSXText) {
|
|
35
|
+
return !!('value' in n && !!n.value ? `${n.value}`.trim() : false);
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
});
|
|
39
|
+
// If we were evaluating
|
|
40
|
+
// <div>{property} {conditional && 'string'}</div>
|
|
41
|
+
// Then {property} would be one of the siblingExpressionNodes
|
|
42
|
+
const siblingExpressionNodes = parentChildren.filter((n) => n.type === 'JSXExpressionContainer' &&
|
|
43
|
+
'expression' in n &&
|
|
44
|
+
(n.expression.type === 'Identifier' ||
|
|
45
|
+
n.expression.type === 'MemberExpression'));
|
|
46
|
+
// Operands of {conditional && 'string'} -- the conditional and the
|
|
47
|
+
// literal. We want to make sure we have a text literal, otherwise we'd
|
|
48
|
+
// trigger this rule on the (safe) {conditional && <div>string</div>}.
|
|
49
|
+
const expressionOperandTypes = [
|
|
50
|
+
node.expression.left.type,
|
|
51
|
+
node.expression.right.type,
|
|
52
|
+
];
|
|
53
|
+
if (siblingTextNodes.concat(siblingExpressionNodes).length > 0 &&
|
|
54
|
+
expressionOperandTypes.includes(utils_1.TSESTree.AST_NODE_TYPES.Literal)) {
|
|
55
|
+
context.report({ node, messageId: 'unexpected' });
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
//# sourceMappingURL=no-conditional-literals-in-jsx.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noFilterWithoutReturn = void 0;
|
|
4
|
+
const ASTHelpers_1 = require("../utils/ASTHelpers");
|
|
5
|
+
const createRule_1 = require("../utils/createRule");
|
|
6
|
+
exports.noFilterWithoutReturn = (0, createRule_1.createRule)({
|
|
7
|
+
create(context) {
|
|
8
|
+
return {
|
|
9
|
+
'CallExpression[callee.property.name="filter"]'(node) {
|
|
10
|
+
const callback = node.arguments[0];
|
|
11
|
+
if (callback && callback.type === 'ArrowFunctionExpression') {
|
|
12
|
+
const { body } = callback;
|
|
13
|
+
if (body.type !== 'BlockStatement') {
|
|
14
|
+
// If the body is not a block statement, it's a direct return
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (!ASTHelpers_1.ASTHelpers.hasReturnStatement(body)) {
|
|
18
|
+
context.report({
|
|
19
|
+
node,
|
|
20
|
+
messageId: 'unexpected',
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
name: 'no-filter-without-return',
|
|
28
|
+
meta: {
|
|
29
|
+
type: 'problem',
|
|
30
|
+
docs: {
|
|
31
|
+
description: 'Disallow Array.filter callbacks without an explicit return (if part of a block statement)',
|
|
32
|
+
recommended: 'error',
|
|
33
|
+
},
|
|
34
|
+
schema: [],
|
|
35
|
+
messages: {
|
|
36
|
+
unexpected: 'An array filter callback with a block statement must contain a return statement',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
defaultOptions: [],
|
|
40
|
+
});
|
|
41
|
+
//# sourceMappingURL=no-filter-without-return.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noMisusedSwitchCase = void 0;
|
|
4
|
+
const createRule_1 = require("../utils/createRule");
|
|
5
|
+
exports.noMisusedSwitchCase = (0, createRule_1.createRule)({
|
|
6
|
+
name: 'no-misused-switch-case',
|
|
7
|
+
meta: {
|
|
8
|
+
type: 'problem',
|
|
9
|
+
docs: {
|
|
10
|
+
description: 'Prevent misuse of logical OR in switch case statements',
|
|
11
|
+
recommended: 'error',
|
|
12
|
+
},
|
|
13
|
+
schema: [],
|
|
14
|
+
messages: {
|
|
15
|
+
noMisusedSwitchCase: 'Avoid using logical OR in switch case. Use cascading cases instead.',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
defaultOptions: [],
|
|
19
|
+
create(context) {
|
|
20
|
+
return {
|
|
21
|
+
SwitchStatement(node) {
|
|
22
|
+
for (const switchCase of node.cases) {
|
|
23
|
+
if (switchCase.test?.type === 'LogicalExpression' &&
|
|
24
|
+
switchCase.test.operator === '||') {
|
|
25
|
+
context.report({
|
|
26
|
+
node: switchCase,
|
|
27
|
+
messageId: 'noMisusedSwitchCase',
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=no-misused-switch-case.js.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noUnpinnedDependencies = void 0;
|
|
4
|
+
const createRule_1 = require("../utils/createRule");
|
|
5
|
+
exports.noUnpinnedDependencies = (0, createRule_1.createRule)({
|
|
6
|
+
meta: {
|
|
7
|
+
type: 'problem',
|
|
8
|
+
docs: {
|
|
9
|
+
description: 'Enforces pinned dependencies',
|
|
10
|
+
recommended: 'error',
|
|
11
|
+
},
|
|
12
|
+
fixable: 'code',
|
|
13
|
+
schema: [],
|
|
14
|
+
messages: {
|
|
15
|
+
unexpected: "Dependency '{{ propertyName }}' should be pinned to a specific version, but '{{ version }}' was found.",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
defaultOptions: [],
|
|
19
|
+
name: 'no-unpinned-dependencies',
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
JSONLiteral(node) {
|
|
23
|
+
const property = node?.parent;
|
|
24
|
+
// const property = node.parent;
|
|
25
|
+
const configSection = node?.parent?.parent?.parent;
|
|
26
|
+
if (!property || !configSection) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const configKey = configSection?.key;
|
|
30
|
+
if (!configKey) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
// Check if we're in the "dependencies" or "devDependencies" section of package.json
|
|
34
|
+
if (node.type === 'JSONLiteral' &&
|
|
35
|
+
property?.type === 'JSONProperty' &&
|
|
36
|
+
(configKey.name === 'devDependencies' ||
|
|
37
|
+
configKey.value === 'devDependencies' ||
|
|
38
|
+
configKey.name === 'dependencies' ||
|
|
39
|
+
configKey.value === 'dependencies')) {
|
|
40
|
+
// Get the version string
|
|
41
|
+
const version = node.value;
|
|
42
|
+
const propertyName = property.key.name ||
|
|
43
|
+
property.key.value;
|
|
44
|
+
// Check if the version string starts with a caret (^) or tilde (~), indicating a non-pinned version
|
|
45
|
+
if (typeof version === 'string' &&
|
|
46
|
+
(version.includes('^') || version.includes('~'))) {
|
|
47
|
+
context.report({
|
|
48
|
+
node: node,
|
|
49
|
+
messageId: 'unexpected',
|
|
50
|
+
data: {
|
|
51
|
+
propertyName,
|
|
52
|
+
version,
|
|
53
|
+
},
|
|
54
|
+
fix: function (fixer) {
|
|
55
|
+
const fixed = version.replace('^', '').replace('~', '');
|
|
56
|
+
return fixer.replaceTextRange(node.range, `"${fixed}"`);
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=no-unpinned-dependencies.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noUselessFragment = void 0;
|
|
4
|
+
exports.noUselessFragment = {
|
|
5
|
+
create(context) {
|
|
6
|
+
return {
|
|
7
|
+
JSXFragment(node) {
|
|
8
|
+
if (node.children.length === 1) {
|
|
9
|
+
context.report({
|
|
10
|
+
node,
|
|
11
|
+
messageId: 'noUselessFragment',
|
|
12
|
+
fix(fixer) {
|
|
13
|
+
const sourceCode = context.getSourceCode();
|
|
14
|
+
const openingFragment = sourceCode.getFirstToken(node);
|
|
15
|
+
const closingFragment = sourceCode.getLastToken(node);
|
|
16
|
+
return [
|
|
17
|
+
fixer.removeRange([
|
|
18
|
+
openingFragment.range[0],
|
|
19
|
+
openingFragment.range[0] + 2,
|
|
20
|
+
]),
|
|
21
|
+
fixer.removeRange([
|
|
22
|
+
closingFragment.range[0] - 3,
|
|
23
|
+
closingFragment.range[0],
|
|
24
|
+
]),
|
|
25
|
+
];
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
meta: {
|
|
33
|
+
type: 'suggestion',
|
|
34
|
+
docs: {
|
|
35
|
+
description: 'Prevent unnecessary use of React fragments',
|
|
36
|
+
recommended: 'warn',
|
|
37
|
+
},
|
|
38
|
+
messages: {
|
|
39
|
+
noUselessFragment: 'React fragment is unnecessary when wrapping a single child',
|
|
40
|
+
},
|
|
41
|
+
schema: [],
|
|
42
|
+
fixable: 'code',
|
|
43
|
+
},
|
|
44
|
+
defaultOptions: [],
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=no-useless-fragment.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.preferFragmentShorthand = void 0;
|
|
4
|
+
exports.preferFragmentShorthand = {
|
|
5
|
+
create(context) {
|
|
6
|
+
return {
|
|
7
|
+
JSXElement(node) {
|
|
8
|
+
const openingElement = node.openingElement;
|
|
9
|
+
if (openingElement.name.type === 'JSXMemberExpression' &&
|
|
10
|
+
openingElement.name.object.type === 'JSXIdentifier' &&
|
|
11
|
+
openingElement.name.object.name === 'React' &&
|
|
12
|
+
openingElement.name.property.type === 'JSXIdentifier' &&
|
|
13
|
+
openingElement.name.property.name === 'Fragment') {
|
|
14
|
+
context.report({
|
|
15
|
+
node,
|
|
16
|
+
messageId: 'preferShorthand',
|
|
17
|
+
fix: (fixer) => [
|
|
18
|
+
fixer.replaceTextRange(openingElement.range, '<>'),
|
|
19
|
+
fixer.replaceTextRange(node.closingElement.range, '</>'),
|
|
20
|
+
],
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
meta: {
|
|
27
|
+
type: 'suggestion',
|
|
28
|
+
docs: {
|
|
29
|
+
description: 'Prefer <> shorthand for <React.Fragment>',
|
|
30
|
+
recommended: 'warn',
|
|
31
|
+
},
|
|
32
|
+
messages: {
|
|
33
|
+
preferShorthand: 'Use <> shorthand for <React.Fragment>, unless a key is required for an iterator',
|
|
34
|
+
},
|
|
35
|
+
schema: [],
|
|
36
|
+
fixable: 'code',
|
|
37
|
+
},
|
|
38
|
+
defaultOptions: [],
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=prefer-fragment-shorthand.js.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.preferTypeOverInterface = void 0;
|
|
4
|
+
const createRule_1 = require("../utils/createRule");
|
|
5
|
+
exports.preferTypeOverInterface = (0, createRule_1.createRule)({
|
|
6
|
+
name: 'prefer-type-over-interface',
|
|
7
|
+
meta: {
|
|
8
|
+
type: 'suggestion',
|
|
9
|
+
docs: {
|
|
10
|
+
description: 'Prefer using type alias over interface',
|
|
11
|
+
recommended: 'warn',
|
|
12
|
+
},
|
|
13
|
+
schema: [],
|
|
14
|
+
messages: {
|
|
15
|
+
preferType: 'Prefer using type alias over interface.',
|
|
16
|
+
},
|
|
17
|
+
fixable: 'code',
|
|
18
|
+
},
|
|
19
|
+
defaultOptions: [],
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
TSInterfaceDeclaration(node) {
|
|
23
|
+
context.report({
|
|
24
|
+
node,
|
|
25
|
+
messageId: 'preferType',
|
|
26
|
+
fix(fixer) {
|
|
27
|
+
const sourceCode = context.getSourceCode();
|
|
28
|
+
const openingBrace = sourceCode.getTokenAfter(node.id, {
|
|
29
|
+
filter: (token) => token.value === '{',
|
|
30
|
+
});
|
|
31
|
+
const fixes = [
|
|
32
|
+
fixer.replaceTextRange([node.range[0], node.id.range[1]], `type ${node.id.name} =`),
|
|
33
|
+
];
|
|
34
|
+
if (node.extends && node.extends.length > 0 && openingBrace) {
|
|
35
|
+
const extendsKeyword = sourceCode.getFirstTokenBetween(node.id, openingBrace, { filter: (token) => token.value === 'extends' });
|
|
36
|
+
fixes.push(fixer.remove(extendsKeyword), fixer.insertTextBefore(openingBrace, '& '));
|
|
37
|
+
}
|
|
38
|
+
return fixes;
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=prefer-type-over-interface.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { TSESLint, TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
export type NodeWithParent = TSESTree.Node & {
|
|
3
|
+
parent: NodeWithParent;
|
|
4
|
+
};
|
|
5
|
+
export type ComponentNode = TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression | TSESTree.FunctionDeclaration;
|
|
6
|
+
export declare const requireMemo: TSESLint.RuleModule<'requireMemo', []>;
|