@agilebot/eslint-plugin 0.2.2 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- package/LICENSE +9 -9
- package/dist/index.d.ts +30 -0
- package/{lib/rules/react/better-exhaustive-deps.js → dist/index.js} +1063 -402
- package/package.json +11 -6
- package/lib/index.js +0 -43
- package/lib/rules/import/enforce-icon-alias.js +0 -42
- package/lib/rules/import/monorepo.js +0 -49
- package/lib/rules/intl/id-missing.js +0 -111
- package/lib/rules/intl/id-prefix.js +0 -103
- package/lib/rules/intl/id-unused.js +0 -123
- package/lib/rules/intl/no-default.js +0 -63
- package/lib/rules/others/no-unnecessary-template-literals.js +0 -38
- package/lib/rules/react/hook-use-ref.js +0 -35
- package/lib/rules/react/no-inline-styles.js +0 -87
- package/lib/rules/react/prefer-named-property-access.js +0 -105
- package/lib/rules/tss/class-naming.js +0 -43
- package/lib/rules/tss/no-color-value.js +0 -58
- package/lib/rules/tss/unused-classes.js +0 -108
- package/lib/util/intl.js +0 -127
- package/lib/util/settings.js +0 -14
- package/lib/util/translations.js +0 -66
- package/lib/util/tss.js +0 -109
package/package.json
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
{
|
2
2
|
"name": "@agilebot/eslint-plugin",
|
3
|
-
"version": "0.2.
|
3
|
+
"version": "0.2.4",
|
4
4
|
"description": "Agilebot's ESLint plugin",
|
5
|
-
"main": "
|
5
|
+
"main": "dist/index.js",
|
6
|
+
"types": "dist/index.d.ts",
|
6
7
|
"license": "MIT",
|
7
8
|
"keywords": [
|
8
9
|
"eslint",
|
@@ -19,16 +20,20 @@
|
|
19
20
|
"dependencies": {
|
20
21
|
"@typescript-eslint/utils": "^7.6.0",
|
21
22
|
"eslint-plugin-react": "^7.34.1",
|
22
|
-
"
|
23
|
-
"@agilebot/eslint-utils": "0.2.2"
|
23
|
+
"@agilebot/eslint-utils": "0.2.4"
|
24
24
|
},
|
25
25
|
"peerDependencies": {
|
26
26
|
"eslint": "^7.0.0 || ^8.0.0"
|
27
27
|
},
|
28
28
|
"files": [
|
29
|
-
"
|
29
|
+
"dist"
|
30
30
|
],
|
31
|
+
"devDependencies": {
|
32
|
+
"@types/estree": "^1.0.5"
|
33
|
+
},
|
31
34
|
"scripts": {
|
32
|
-
"
|
35
|
+
"build": "rollup -c rollup.config.mjs && nr dts",
|
36
|
+
"dts": "tsc -p tsconfig.dts.json",
|
37
|
+
"lint": "eslint src --fix"
|
33
38
|
}
|
34
39
|
}
|
package/lib/index.js
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
// @ts-check
|
2
|
-
const path = require('node:path');
|
3
|
-
const { globSync } = require('fast-glob');
|
4
|
-
|
5
|
-
// List all rules in rules folder
|
6
|
-
const rulesPath = path.join(__dirname, 'rules');
|
7
|
-
const ruleFiles = globSync('**/*.js', {
|
8
|
-
cwd: rulesPath
|
9
|
-
});
|
10
|
-
|
11
|
-
/**
|
12
|
-
* @type {import('eslint').Linter.RulesRecord}
|
13
|
-
*/
|
14
|
-
const rules = {};
|
15
|
-
ruleFiles.forEach(file => {
|
16
|
-
const { dir, name } = path.parse(file);
|
17
|
-
const ruleName = `${dir}/${name}`;
|
18
|
-
rules[ruleName] = require(path.join(rulesPath, file));
|
19
|
-
});
|
20
|
-
|
21
|
-
module.exports.rules = rules;
|
22
|
-
|
23
|
-
module.exports.configs = {
|
24
|
-
recommended: {
|
25
|
-
plugins: ['@agilebot'],
|
26
|
-
rules: {
|
27
|
-
'@agilebot/react/prefer-named-property-access': 'error',
|
28
|
-
'@agilebot/react/hook-use-ref': 'warn',
|
29
|
-
'@agilebot/react/no-inline-styles': 'error',
|
30
|
-
'@agilebot/tss/unused-classes': 'warn',
|
31
|
-
'@agilebot/tss/no-color-value': 'error',
|
32
|
-
'@agilebot/tss/class-naming': 'error',
|
33
|
-
'@agilebot/import/enforce-icon-alias': 'error',
|
34
|
-
'@agilebot/import/monorepo': 'error',
|
35
|
-
'@agilebot/others/no-unnecessary-template-literals': 'error'
|
36
|
-
},
|
37
|
-
settings: {
|
38
|
-
react: {
|
39
|
-
version: '18.0.0'
|
40
|
-
}
|
41
|
-
}
|
42
|
-
}
|
43
|
-
};
|
@@ -1,42 +0,0 @@
|
|
1
|
-
module.exports = {
|
2
|
-
meta: {
|
3
|
-
type: 'problem', // `problem`, `suggestion`, or `layout`
|
4
|
-
docs: {
|
5
|
-
description: 'Enforce alias for @mui/icons-material imports',
|
6
|
-
recommended: true
|
7
|
-
},
|
8
|
-
fixable: 'code', // Or `code` or `whitespace`
|
9
|
-
schema: [] // Add a schema if the rule has options
|
10
|
-
},
|
11
|
-
|
12
|
-
create(context) {
|
13
|
-
return {
|
14
|
-
ImportDeclaration(node) {
|
15
|
-
if (
|
16
|
-
node.source.value !== '@mui/icons-material' &&
|
17
|
-
node.source.value !== 'mdi-material-ui'
|
18
|
-
) {
|
19
|
-
return;
|
20
|
-
}
|
21
|
-
|
22
|
-
for (const specifier of node.specifiers) {
|
23
|
-
if (specifier.type !== 'ImportSpecifier') {
|
24
|
-
return;
|
25
|
-
}
|
26
|
-
|
27
|
-
if (specifier.imported.name === specifier.local.name) {
|
28
|
-
context.report({
|
29
|
-
node,
|
30
|
-
message: `Import for ${node.source.value} should be aliased.`,
|
31
|
-
fix: fixer =>
|
32
|
-
fixer.replaceText(
|
33
|
-
specifier,
|
34
|
-
`${specifier.imported.name} as ${specifier.imported.name}Icon`
|
35
|
-
)
|
36
|
-
});
|
37
|
-
}
|
38
|
-
}
|
39
|
-
}
|
40
|
-
};
|
41
|
-
}
|
42
|
-
};
|
@@ -1,49 +0,0 @@
|
|
1
|
-
const { getSetting } = require('../../util/settings');
|
2
|
-
|
3
|
-
let warnedForMissingPrefix = false;
|
4
|
-
|
5
|
-
module.exports = {
|
6
|
-
meta: {
|
7
|
-
type: 'problem', // `problem`, `suggestion`, or `layout`
|
8
|
-
docs: {
|
9
|
-
description: 'Enforce import styles for monorepo',
|
10
|
-
recommended: true
|
11
|
-
},
|
12
|
-
fixable: 'code', // Or `code` or `whitespace`
|
13
|
-
schema: [] // Add a schema if the rule has options
|
14
|
-
},
|
15
|
-
|
16
|
-
create(context) {
|
17
|
-
return {
|
18
|
-
ImportDeclaration(node) {
|
19
|
-
const prefix = getSetting(context, 'monorepo-prefix');
|
20
|
-
if (!prefix) {
|
21
|
-
if (!warnedForMissingPrefix) {
|
22
|
-
// eslint-disable-next-line no-console -- this is a CLI tool
|
23
|
-
console.error('Warning: agilebot/monorepo-prefix is not set.');
|
24
|
-
warnedForMissingPrefix = true;
|
25
|
-
}
|
26
|
-
return;
|
27
|
-
}
|
28
|
-
|
29
|
-
if (!node.source.value.startsWith(prefix)) {
|
30
|
-
return;
|
31
|
-
}
|
32
|
-
const values = node.source.value.split('/');
|
33
|
-
|
34
|
-
if (values[2] === 'src') {
|
35
|
-
context.report({
|
36
|
-
node,
|
37
|
-
message: `Import for ${node.source.value} should not contains src folder.`,
|
38
|
-
fix: fixer => {
|
39
|
-
const correctedPath = values
|
40
|
-
.filter((_, index) => index !== 2)
|
41
|
-
.join('/');
|
42
|
-
return fixer.replaceText(node.source, `'${correctedPath}'`);
|
43
|
-
}
|
44
|
-
});
|
45
|
-
}
|
46
|
-
}
|
47
|
-
};
|
48
|
-
}
|
49
|
-
};
|
@@ -1,111 +0,0 @@
|
|
1
|
-
const {
|
2
|
-
sortedTemplateElements,
|
3
|
-
templateLiteralDisplayStr,
|
4
|
-
findFormatMessageAttrNode,
|
5
|
-
findFormattedMessageAttrNode,
|
6
|
-
findAttrNodeInDefineMessages,
|
7
|
-
findAttrNodeInDefineMessage
|
8
|
-
} = require('../../util/intl');
|
9
|
-
const { getIntlIds } = require('../../util/translations');
|
10
|
-
|
11
|
-
// ------------------------------------------------------------------------------
|
12
|
-
// Rule Definition
|
13
|
-
// ------------------------------------------------------------------------------
|
14
|
-
|
15
|
-
module.exports = {
|
16
|
-
meta: {
|
17
|
-
docs: {
|
18
|
-
description: 'Validates intl message ids are in locale file',
|
19
|
-
category: 'Intl',
|
20
|
-
recommended: true
|
21
|
-
},
|
22
|
-
fixable: null,
|
23
|
-
schema: []
|
24
|
-
},
|
25
|
-
|
26
|
-
create: function (context) {
|
27
|
-
const translatedIds = getIntlIds(context);
|
28
|
-
const translatedIdSet = new Set(translatedIds);
|
29
|
-
|
30
|
-
// ----------------------------------------------------------------------
|
31
|
-
// Helpers
|
32
|
-
// ----------------------------------------------------------------------
|
33
|
-
|
34
|
-
function isLiteralTranslated(id) {
|
35
|
-
return translatedIdSet.has(id);
|
36
|
-
}
|
37
|
-
|
38
|
-
function isTemplateTranslated(re) {
|
39
|
-
return translatedIds.some(k => re.test(k));
|
40
|
-
}
|
41
|
-
|
42
|
-
function processLiteral(node) {
|
43
|
-
if (!isLiteralTranslated(node.value)) {
|
44
|
-
context.report({
|
45
|
-
node: node,
|
46
|
-
message: 'Missing id: ' + node.value
|
47
|
-
});
|
48
|
-
}
|
49
|
-
}
|
50
|
-
|
51
|
-
function processTemplateLiteral(node) {
|
52
|
-
const exStr = sortedTemplateElements(node)
|
53
|
-
.map(e => (!e.value ? '.*' : e.value.raw))
|
54
|
-
.join('');
|
55
|
-
const re = new RegExp(exStr);
|
56
|
-
|
57
|
-
if (!isTemplateTranslated(re)) {
|
58
|
-
context.report({
|
59
|
-
node: node,
|
60
|
-
message: 'Missing id pattern: ' + templateLiteralDisplayStr(node)
|
61
|
-
});
|
62
|
-
}
|
63
|
-
}
|
64
|
-
|
65
|
-
function processAttrNode(node) {
|
66
|
-
if (node.value.type === 'Literal') {
|
67
|
-
return processLiteral(node.value);
|
68
|
-
}
|
69
|
-
if (
|
70
|
-
node.value.type === 'JSXExpressionContainer' &&
|
71
|
-
node.value.expression.type === 'TemplateLiteral'
|
72
|
-
) {
|
73
|
-
return processTemplateLiteral(node.value.expression);
|
74
|
-
}
|
75
|
-
if (node.value.type === 'TemplateLiteral') {
|
76
|
-
return processTemplateLiteral(node.value);
|
77
|
-
}
|
78
|
-
context.report({
|
79
|
-
node: node,
|
80
|
-
message: 'Do not invoke intl by ' + node.value.type
|
81
|
-
});
|
82
|
-
}
|
83
|
-
|
84
|
-
// ----------------------------------------------------------------------
|
85
|
-
// Public
|
86
|
-
// ----------------------------------------------------------------------
|
87
|
-
|
88
|
-
return {
|
89
|
-
JSXIdentifier: function (node) {
|
90
|
-
const attrNode = findFormattedMessageAttrNode(node, 'id');
|
91
|
-
if (attrNode) {
|
92
|
-
return processAttrNode(attrNode);
|
93
|
-
}
|
94
|
-
},
|
95
|
-
CallExpression: function (node) {
|
96
|
-
const attrNode = findFormatMessageAttrNode(node, 'id');
|
97
|
-
if (attrNode) {
|
98
|
-
return processAttrNode(attrNode);
|
99
|
-
}
|
100
|
-
},
|
101
|
-
Property: function (node) {
|
102
|
-
const attrNode =
|
103
|
-
findAttrNodeInDefineMessages(node, 'id') ||
|
104
|
-
findAttrNodeInDefineMessage(node, 'id');
|
105
|
-
if (attrNode) {
|
106
|
-
return processAttrNode(attrNode);
|
107
|
-
}
|
108
|
-
}
|
109
|
-
};
|
110
|
-
}
|
111
|
-
};
|
@@ -1,103 +0,0 @@
|
|
1
|
-
const {
|
2
|
-
findFormatMessageAttrNode,
|
3
|
-
findFormattedMessageAttrNode,
|
4
|
-
findAttrNodeInDefineMessages,
|
5
|
-
findAttrNodeInDefineMessage,
|
6
|
-
templateLiteralDisplayStr
|
7
|
-
} = require('../../util/intl');
|
8
|
-
|
9
|
-
// ------------------------------------------------------------------------------
|
10
|
-
// Rule Definition
|
11
|
-
// ------------------------------------------------------------------------------
|
12
|
-
|
13
|
-
module.exports = {
|
14
|
-
meta: {
|
15
|
-
docs: {
|
16
|
-
description: 'Validates intl message ids has correct prefixes',
|
17
|
-
category: 'Intl',
|
18
|
-
recommended: true
|
19
|
-
},
|
20
|
-
fixable: null,
|
21
|
-
schema: [
|
22
|
-
{
|
23
|
-
type: 'array',
|
24
|
-
items: {
|
25
|
-
type: 'string'
|
26
|
-
}
|
27
|
-
}
|
28
|
-
]
|
29
|
-
},
|
30
|
-
|
31
|
-
create: function (context) {
|
32
|
-
if (context.options[0].length === 0) {
|
33
|
-
throw new Error('Prefixes are required in settings');
|
34
|
-
}
|
35
|
-
|
36
|
-
// ----------------------------------------------------------------------
|
37
|
-
// Helpers
|
38
|
-
// ----------------------------------------------------------------------
|
39
|
-
|
40
|
-
const hasPrefix = value =>
|
41
|
-
context.options[0].some(p => value.startsWith(p));
|
42
|
-
|
43
|
-
function report(node, value) {
|
44
|
-
if (!hasPrefix(value)) {
|
45
|
-
context.report({
|
46
|
-
node: node,
|
47
|
-
message: `Invalid id prefix: ${value}`
|
48
|
-
});
|
49
|
-
}
|
50
|
-
}
|
51
|
-
|
52
|
-
function processLiteral(node) {
|
53
|
-
report(node, node.value);
|
54
|
-
}
|
55
|
-
|
56
|
-
function processTemplateLiteral(node) {
|
57
|
-
const displayStr = templateLiteralDisplayStr(node);
|
58
|
-
report(node, displayStr);
|
59
|
-
}
|
60
|
-
|
61
|
-
function processAttrNode(node) {
|
62
|
-
if (node.value.type === 'Literal') {
|
63
|
-
return processLiteral(node.value);
|
64
|
-
}
|
65
|
-
if (
|
66
|
-
node.value.type === 'JSXExpressionContainer' &&
|
67
|
-
node.value.expression.type === 'TemplateLiteral'
|
68
|
-
) {
|
69
|
-
return processTemplateLiteral(node.value.expression);
|
70
|
-
}
|
71
|
-
if (node.value.type === 'TemplateLiteral') {
|
72
|
-
return processTemplateLiteral(node.value);
|
73
|
-
}
|
74
|
-
}
|
75
|
-
|
76
|
-
// ----------------------------------------------------------------------
|
77
|
-
// Public
|
78
|
-
// ----------------------------------------------------------------------
|
79
|
-
|
80
|
-
return {
|
81
|
-
JSXIdentifier: function (node) {
|
82
|
-
const attrNode = findFormattedMessageAttrNode(node, 'id');
|
83
|
-
if (attrNode) {
|
84
|
-
return processAttrNode(attrNode);
|
85
|
-
}
|
86
|
-
},
|
87
|
-
CallExpression: function (node) {
|
88
|
-
const attrNode = findFormatMessageAttrNode(node, 'id');
|
89
|
-
if (attrNode) {
|
90
|
-
return processAttrNode(attrNode);
|
91
|
-
}
|
92
|
-
},
|
93
|
-
Property: function (node) {
|
94
|
-
const attrNode =
|
95
|
-
findAttrNodeInDefineMessages(node, 'id') ||
|
96
|
-
findAttrNodeInDefineMessage(node, 'id');
|
97
|
-
if (attrNode) {
|
98
|
-
return processAttrNode(attrNode);
|
99
|
-
}
|
100
|
-
}
|
101
|
-
};
|
102
|
-
}
|
103
|
-
};
|
@@ -1,123 +0,0 @@
|
|
1
|
-
const path = require('node:path');
|
2
|
-
const fs = require('node:fs');
|
3
|
-
const {
|
4
|
-
sortedTemplateElements,
|
5
|
-
findFormatMessageAttrNode,
|
6
|
-
findFormattedMessageAttrNode,
|
7
|
-
findAttrNodeInDefineMessages,
|
8
|
-
findAttrNodeInDefineMessage
|
9
|
-
} = require('../../util/intl');
|
10
|
-
const { getIntlIds } = require('../../util/translations');
|
11
|
-
const { getSetting } = require('../../util/settings');
|
12
|
-
|
13
|
-
// 已经使用的id集合 key为项目目录,value为id集合Set
|
14
|
-
const usedIds = new Map();
|
15
|
-
|
16
|
-
// ------------------------------------------------------------------------------
|
17
|
-
// Rule Definition
|
18
|
-
// ------------------------------------------------------------------------------
|
19
|
-
|
20
|
-
module.exports = {
|
21
|
-
meta: {
|
22
|
-
docs: {
|
23
|
-
description: 'Finds unused intl message ids in locale file',
|
24
|
-
category: 'Intl',
|
25
|
-
recommended: true
|
26
|
-
},
|
27
|
-
fixable: null,
|
28
|
-
schema: []
|
29
|
-
},
|
30
|
-
|
31
|
-
create: function (context) {
|
32
|
-
const projectRoot = getSetting(context, 'project-root');
|
33
|
-
if (!projectRoot) {
|
34
|
-
throw new Error('projectRoot must be set in this rule');
|
35
|
-
}
|
36
|
-
if (!usedIds.has(projectRoot)) {
|
37
|
-
usedIds.set(projectRoot, new Set());
|
38
|
-
}
|
39
|
-
const usedIdSet = usedIds.get(projectRoot);
|
40
|
-
|
41
|
-
const translatedIds = getIntlIds(context);
|
42
|
-
const translatedIdSet = new Set(translatedIds);
|
43
|
-
|
44
|
-
// ----------------------------------------------------------------------
|
45
|
-
// Helpers
|
46
|
-
// ----------------------------------------------------------------------
|
47
|
-
|
48
|
-
function isLiteralTranslated(id) {
|
49
|
-
return translatedIdSet.has(id);
|
50
|
-
}
|
51
|
-
|
52
|
-
function isTemplateTranslated(re) {
|
53
|
-
return translatedIds.some(k => re.test(k));
|
54
|
-
}
|
55
|
-
|
56
|
-
function processLiteral(node) {
|
57
|
-
if (isLiteralTranslated(node.value)) {
|
58
|
-
// 将已使用的id加入usedIdSet
|
59
|
-
usedIdSet.add(node.value);
|
60
|
-
}
|
61
|
-
}
|
62
|
-
|
63
|
-
function processTemplateLiteral(node) {
|
64
|
-
const exStr = sortedTemplateElements(node)
|
65
|
-
.map(e => (!e.value ? '.*' : e.value.raw))
|
66
|
-
.join('');
|
67
|
-
const re = new RegExp(exStr);
|
68
|
-
|
69
|
-
if (isTemplateTranslated(re)) {
|
70
|
-
// TODO: 暂时没有这种情况
|
71
|
-
}
|
72
|
-
}
|
73
|
-
|
74
|
-
function processAttrNode(node) {
|
75
|
-
if (node.value.type === 'Literal') {
|
76
|
-
return processLiteral(node.value);
|
77
|
-
}
|
78
|
-
if (
|
79
|
-
node.value.type === 'JSXExpressionContainer' &&
|
80
|
-
node.value.expression.type === 'TemplateLiteral'
|
81
|
-
) {
|
82
|
-
return processTemplateLiteral(node.value.expression);
|
83
|
-
}
|
84
|
-
if (node.value.type === 'TemplateLiteral') {
|
85
|
-
return processTemplateLiteral(node.value);
|
86
|
-
}
|
87
|
-
}
|
88
|
-
|
89
|
-
// ----------------------------------------------------------------------
|
90
|
-
// Public
|
91
|
-
// ----------------------------------------------------------------------
|
92
|
-
|
93
|
-
return {
|
94
|
-
JSXIdentifier: function (node) {
|
95
|
-
const attrNode = findFormattedMessageAttrNode(node, 'id');
|
96
|
-
if (attrNode) {
|
97
|
-
return processAttrNode(attrNode);
|
98
|
-
}
|
99
|
-
},
|
100
|
-
CallExpression: function (node) {
|
101
|
-
const attrNode = findFormatMessageAttrNode(node, 'id');
|
102
|
-
if (attrNode) {
|
103
|
-
return processAttrNode(attrNode);
|
104
|
-
}
|
105
|
-
},
|
106
|
-
Property: function (node) {
|
107
|
-
const attrNode =
|
108
|
-
findAttrNodeInDefineMessages(node, 'id') ||
|
109
|
-
findAttrNodeInDefineMessage(node, 'id');
|
110
|
-
if (attrNode) {
|
111
|
-
return processAttrNode(attrNode);
|
112
|
-
}
|
113
|
-
},
|
114
|
-
'Program:exit': function () {
|
115
|
-
// 将usedIdSet转为数组,然后与translatedIds取差集,即为未使用的id
|
116
|
-
const unusedIds = [...translatedIdSet].filter(id => !usedIdSet.has(id));
|
117
|
-
// 在项目目录下生成intl-unused.json
|
118
|
-
const jsonPath = path.join(projectRoot, 'intl-unused.json');
|
119
|
-
fs.writeFileSync(jsonPath, JSON.stringify(unusedIds, null, 2));
|
120
|
-
}
|
121
|
-
};
|
122
|
-
}
|
123
|
-
};
|
@@ -1,63 +0,0 @@
|
|
1
|
-
const {
|
2
|
-
findFormatMessageAttrNode,
|
3
|
-
findFormattedMessageAttrNode,
|
4
|
-
findAttrNodeInDefineMessages,
|
5
|
-
findAttrNodeInDefineMessage
|
6
|
-
} = require('../../util/intl');
|
7
|
-
|
8
|
-
// ------------------------------------------------------------------------------
|
9
|
-
// Rule Definition
|
10
|
-
// ------------------------------------------------------------------------------
|
11
|
-
|
12
|
-
module.exports = {
|
13
|
-
meta: {
|
14
|
-
docs: {
|
15
|
-
description: 'Validates defaultMessage is not used with react-intl',
|
16
|
-
category: 'Intl',
|
17
|
-
recommended: true
|
18
|
-
},
|
19
|
-
fixable: null,
|
20
|
-
schema: []
|
21
|
-
},
|
22
|
-
|
23
|
-
create: function (context) {
|
24
|
-
// ----------------------------------------------------------------------
|
25
|
-
// Helpers
|
26
|
-
// ----------------------------------------------------------------------
|
27
|
-
|
28
|
-
function processAttrNode(node) {
|
29
|
-
context.report({
|
30
|
-
node: node,
|
31
|
-
message: 'Do not use defaultMessage'
|
32
|
-
});
|
33
|
-
}
|
34
|
-
|
35
|
-
// ----------------------------------------------------------------------
|
36
|
-
// Public
|
37
|
-
// ----------------------------------------------------------------------
|
38
|
-
|
39
|
-
return {
|
40
|
-
JSXIdentifier: function (node) {
|
41
|
-
const attrNode = findFormattedMessageAttrNode(node, 'defaultMessage');
|
42
|
-
if (attrNode) {
|
43
|
-
return processAttrNode(attrNode);
|
44
|
-
}
|
45
|
-
},
|
46
|
-
CallExpression: function (node) {
|
47
|
-
const attrNode = findFormatMessageAttrNode(node, 'defaultMessage');
|
48
|
-
if (attrNode) {
|
49
|
-
return processAttrNode(attrNode);
|
50
|
-
}
|
51
|
-
},
|
52
|
-
Property: function (node) {
|
53
|
-
const attrNode =
|
54
|
-
findAttrNodeInDefineMessages(node, 'defaultMessage') ||
|
55
|
-
findAttrNodeInDefineMessage(node, 'defaultMessage');
|
56
|
-
|
57
|
-
if (attrNode) {
|
58
|
-
return processAttrNode(attrNode);
|
59
|
-
}
|
60
|
-
}
|
61
|
-
};
|
62
|
-
}
|
63
|
-
};
|
@@ -1,38 +0,0 @@
|
|
1
|
-
module.exports = {
|
2
|
-
meta: {
|
3
|
-
type: 'problem',
|
4
|
-
docs: {
|
5
|
-
description: 'Check if a template string contains only one ${}',
|
6
|
-
recommended: true
|
7
|
-
},
|
8
|
-
fixable: 'code', // Or `code` or `whitespace`
|
9
|
-
schema: [] // Add a schema if the rule has options
|
10
|
-
},
|
11
|
-
|
12
|
-
create(context) {
|
13
|
-
return {
|
14
|
-
TemplateLiteral(node) {
|
15
|
-
// Get the entire source code of the template string
|
16
|
-
const code = context.getSourceCode().getText(node);
|
17
|
-
// Check if the template string contains only one `${}`
|
18
|
-
if (
|
19
|
-
code.startsWith('`${') &&
|
20
|
-
code.endsWith('}`') &&
|
21
|
-
code.split('${').length === 2
|
22
|
-
) {
|
23
|
-
context.report({
|
24
|
-
node,
|
25
|
-
message: 'Unnecessary template string with only one ${}.',
|
26
|
-
fix(fixer) {
|
27
|
-
// Replace the entire template string with the content inside ${}
|
28
|
-
return fixer.replaceText(
|
29
|
-
node,
|
30
|
-
code.substring(3, code.length - 2)
|
31
|
-
);
|
32
|
-
}
|
33
|
-
});
|
34
|
-
}
|
35
|
-
}
|
36
|
-
};
|
37
|
-
}
|
38
|
-
};
|
@@ -1,35 +0,0 @@
|
|
1
|
-
const Components = require('eslint-plugin-react/lib/util/Components');
|
2
|
-
|
3
|
-
module.exports = {
|
4
|
-
meta: {
|
5
|
-
docs: {
|
6
|
-
description: 'Ensure naming of useRef hook value.',
|
7
|
-
recommended: false
|
8
|
-
},
|
9
|
-
schema: [],
|
10
|
-
type: 'suggestion',
|
11
|
-
hasSuggestions: true
|
12
|
-
},
|
13
|
-
|
14
|
-
create: Components.detect((context, component, util) => ({
|
15
|
-
CallExpression(node) {
|
16
|
-
const isImmediateReturn =
|
17
|
-
node.parent && node.parent.type === 'ReturnStatement';
|
18
|
-
|
19
|
-
if (isImmediateReturn || !util.isReactHookCall(node, ['useRef'])) {
|
20
|
-
return;
|
21
|
-
}
|
22
|
-
if (node.parent.id.type !== 'Identifier') {
|
23
|
-
return;
|
24
|
-
}
|
25
|
-
const variable = node.parent.id.name;
|
26
|
-
|
27
|
-
if (!variable.endsWith('Ref')) {
|
28
|
-
context.report({
|
29
|
-
node: node,
|
30
|
-
message: 'useRef call is not end with "Ref"'
|
31
|
-
});
|
32
|
-
}
|
33
|
-
}
|
34
|
-
}))
|
35
|
-
};
|