@apdesign/code-style-react 1.2.2 → 2.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/.prettierrc.js +10 -10
- package/CHANGELOG.md +157 -0
- package/MIGRATION.md +211 -0
- package/README.md +262 -0
- package/biome.jsonc +99 -0
- package/cli.js +49 -15
- package/index.js +13 -13
- package/lefthook.yml +19 -0
- package/package.json +67 -45
- package/scripts/buildEslint.sh +59 -59
- package/scripts/initConfigs.js +121 -98
- package/scripts/initHusky.js +36 -33
- package/scripts/initScripts.js +39 -36
- package/scripts/runEslint.js +189 -185
- package/scripts/runStylelint.js +137 -137
- package/stylelint/{.stylelintrc.js → rules/.stylelintrc.js} +39 -39
- package/stylelint/rules/color-must-use-variable.js +63 -61
- package/eslint/.eslintrc.build.js +0 -100
- package/eslint/.eslintrc.js +0 -100
package/scripts/runStylelint.js
CHANGED
@@ -1,137 +1,137 @@
|
|
1
|
-
#!/usr/bin/env node
|
2
|
-
|
3
|
-
let spawnSync;
|
4
|
-
let spawn;
|
5
|
-
let path;
|
6
|
-
let fs;
|
7
|
-
|
8
|
-
async function runStylelint(targetPathArg) {
|
9
|
-
try {
|
10
|
-
if (typeof require !== 'undefined') {
|
11
|
-
// CommonJS
|
12
|
-
({ spawnSync, spawn } = require('child_process'));
|
13
|
-
path = require('path');
|
14
|
-
fs = require('fs');
|
15
|
-
} else {
|
16
|
-
// ESM
|
17
|
-
({ spawnSync, spawn } = await import('node:child_process'));
|
18
|
-
path = await import('node:path');
|
19
|
-
fs = await import('node:fs');
|
20
|
-
}
|
21
|
-
|
22
|
-
const targetPath = targetPathArg || process.cwd();
|
23
|
-
let rootDir = path.resolve(targetPath);
|
24
|
-
|
25
|
-
// 如果传的是单个目录名且路径不存在,则在 packages/ 下查找
|
26
|
-
if (!fs.existsSync(rootDir) && targetPath !== process.cwd()) {
|
27
|
-
const baseDir = process.cwd(); // 当前项目根目录
|
28
|
-
const fullPath = path.join(baseDir, 'packages', targetPath);
|
29
|
-
if (fs.existsSync(fullPath)) {
|
30
|
-
rootDir = fullPath;
|
31
|
-
} else {
|
32
|
-
console.error(`找不到目录: packages/${targetPath}`);
|
33
|
-
process.exit(1);
|
34
|
-
}
|
35
|
-
}
|
36
|
-
|
37
|
-
console.log('目标路径:', rootDir);
|
38
|
-
|
39
|
-
const gitRootResult = spawnSync('git', ['rev-parse', '--show-toplevel'], {
|
40
|
-
cwd: rootDir,
|
41
|
-
encoding: 'utf-8',
|
42
|
-
shell: true,
|
43
|
-
});
|
44
|
-
|
45
|
-
if (gitRootResult.status !== 0 || !gitRootResult.stdout) {
|
46
|
-
console.error('无法获取 Git 根目录,请确保路径在 Git 仓库内');
|
47
|
-
process.exit(1);
|
48
|
-
}
|
49
|
-
|
50
|
-
const gitRoot = gitRootResult.stdout.trim();
|
51
|
-
console.log('Git 根目录:', gitRoot);
|
52
|
-
|
53
|
-
let targetBranch = 'master';
|
54
|
-
if (targetPath !== process.cwd()) {
|
55
|
-
const lastDir = path.basename(rootDir);
|
56
|
-
targetBranch = `master-${lastDir.split('-').pop()}`;
|
57
|
-
}
|
58
|
-
console.log('目标分支:', targetBranch);
|
59
|
-
|
60
|
-
// 获取当前分支
|
61
|
-
const currentBranchResult = spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
|
62
|
-
cwd: gitRoot,
|
63
|
-
encoding: 'utf-8',
|
64
|
-
shell: true,
|
65
|
-
});
|
66
|
-
|
67
|
-
if (currentBranchResult.status !== 0 || !currentBranchResult.stdout) {
|
68
|
-
console.error('无法获取当前 Git 分支');
|
69
|
-
process.exit(1);
|
70
|
-
}
|
71
|
-
|
72
|
-
const currentBranch = currentBranchResult.stdout.trim();
|
73
|
-
console.log('当前分支:', currentBranch);
|
74
|
-
|
75
|
-
// 切换分支并拉取最新代码
|
76
|
-
if (currentBranch !== targetBranch) {
|
77
|
-
console.log(`切换到分支 ${targetBranch} ...`);
|
78
|
-
const checkout = spawnSync('git', ['checkout', targetBranch], {
|
79
|
-
cwd: gitRoot,
|
80
|
-
stdio: 'inherit',
|
81
|
-
shell: true,
|
82
|
-
});
|
83
|
-
if (checkout.status !== 0) {
|
84
|
-
console.error(
|
85
|
-
process.exit(1);
|
86
|
-
}
|
87
|
-
}
|
88
|
-
|
89
|
-
console.log('拉取最新代码...');
|
90
|
-
const pull = spawnSync('git', ['pull'], {
|
91
|
-
cwd: gitRoot,
|
92
|
-
stdio: 'inherit',
|
93
|
-
shell: true,
|
94
|
-
});
|
95
|
-
if (pull.status !== 0) {
|
96
|
-
console.error('git pull 失败');
|
97
|
-
process.exit(1);
|
98
|
-
}
|
99
|
-
|
100
|
-
const srcPath = path.join(rootDir, 'src');
|
101
|
-
const stylelintTarget = fs.existsSync(srcPath)
|
102
|
-
? `${srcPath}/**/*.{css,scss,less}`
|
103
|
-
: './**/*.{css,scss,less}';
|
104
|
-
|
105
|
-
if (
|
106
|
-
console.
|
107
|
-
} else {
|
108
|
-
console.
|
109
|
-
}
|
110
|
-
|
111
|
-
console.log('执行 Stylelint...');
|
112
|
-
const stylelint = spawn(
|
113
|
-
'npx',
|
114
|
-
[
|
115
|
-
'stylelint',
|
116
|
-
stylelintTarget,
|
117
|
-
'--allow-empty-input',
|
118
|
-
'--report-needless-disables',
|
119
|
-
'--report-invalid-scope-disables',
|
120
|
-
],
|
121
|
-
{
|
122
|
-
cwd: rootDir,
|
123
|
-
stdio: 'inherit',
|
124
|
-
shell: true,
|
125
|
-
},
|
126
|
-
);
|
127
|
-
|
128
|
-
stylelint.on('close', (code) => {
|
129
|
-
process.exit(code);
|
130
|
-
});
|
131
|
-
} catch (err) {
|
132
|
-
console.error('脚本执行出错:', err);
|
133
|
-
process.exit(1);
|
134
|
-
}
|
135
|
-
}
|
136
|
-
|
137
|
-
module.exports = runStylelint;
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
let spawnSync;
|
4
|
+
let spawn;
|
5
|
+
let path;
|
6
|
+
let fs;
|
7
|
+
|
8
|
+
async function runStylelint(targetPathArg) {
|
9
|
+
try {
|
10
|
+
if (typeof require !== 'undefined') {
|
11
|
+
// CommonJS
|
12
|
+
({ spawnSync, spawn } = require('node:child_process'));
|
13
|
+
path = require('node:path');
|
14
|
+
fs = require('node:fs');
|
15
|
+
} else {
|
16
|
+
// ESM
|
17
|
+
({ spawnSync, spawn } = await import('node:child_process'));
|
18
|
+
path = await import('node:path');
|
19
|
+
fs = await import('node:fs');
|
20
|
+
}
|
21
|
+
|
22
|
+
const targetPath = targetPathArg || process.cwd();
|
23
|
+
let rootDir = path.resolve(targetPath);
|
24
|
+
|
25
|
+
// 如果传的是单个目录名且路径不存在,则在 packages/ 下查找
|
26
|
+
if (!fs.existsSync(rootDir) && targetPath !== process.cwd()) {
|
27
|
+
const baseDir = process.cwd(); // 当前项目根目录
|
28
|
+
const fullPath = path.join(baseDir, 'packages', targetPath);
|
29
|
+
if (fs.existsSync(fullPath)) {
|
30
|
+
rootDir = fullPath;
|
31
|
+
} else {
|
32
|
+
console.error(`找不到目录: packages/${targetPath}`);
|
33
|
+
process.exit(1);
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
console.log('目标路径:', rootDir);
|
38
|
+
|
39
|
+
const gitRootResult = spawnSync('git', ['rev-parse', '--show-toplevel'], {
|
40
|
+
cwd: rootDir,
|
41
|
+
encoding: 'utf-8',
|
42
|
+
shell: true,
|
43
|
+
});
|
44
|
+
|
45
|
+
if (gitRootResult.status !== 0 || !gitRootResult.stdout) {
|
46
|
+
console.error('无法获取 Git 根目录,请确保路径在 Git 仓库内');
|
47
|
+
process.exit(1);
|
48
|
+
}
|
49
|
+
|
50
|
+
const gitRoot = gitRootResult.stdout.trim();
|
51
|
+
console.log('Git 根目录:', gitRoot);
|
52
|
+
|
53
|
+
let targetBranch = 'master';
|
54
|
+
if (targetPath !== process.cwd()) {
|
55
|
+
const lastDir = path.basename(rootDir);
|
56
|
+
targetBranch = `master-${lastDir.split('-').pop()}`;
|
57
|
+
}
|
58
|
+
console.log('目标分支:', targetBranch);
|
59
|
+
|
60
|
+
// 获取当前分支
|
61
|
+
const currentBranchResult = spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
|
62
|
+
cwd: gitRoot,
|
63
|
+
encoding: 'utf-8',
|
64
|
+
shell: true,
|
65
|
+
});
|
66
|
+
|
67
|
+
if (currentBranchResult.status !== 0 || !currentBranchResult.stdout) {
|
68
|
+
console.error('无法获取当前 Git 分支');
|
69
|
+
process.exit(1);
|
70
|
+
}
|
71
|
+
|
72
|
+
const currentBranch = currentBranchResult.stdout.trim();
|
73
|
+
console.log('当前分支:', currentBranch);
|
74
|
+
|
75
|
+
// 切换分支并拉取最新代码
|
76
|
+
if (currentBranch !== targetBranch) {
|
77
|
+
console.log(`切换到分支 ${targetBranch} ...`);
|
78
|
+
const checkout = spawnSync('git', ['checkout', targetBranch], {
|
79
|
+
cwd: gitRoot,
|
80
|
+
stdio: 'inherit',
|
81
|
+
shell: true,
|
82
|
+
});
|
83
|
+
if (checkout.status !== 0) {
|
84
|
+
console.error('切换分支失败');
|
85
|
+
process.exit(1);
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
console.log('拉取最新代码...');
|
90
|
+
const pull = spawnSync('git', ['pull'], {
|
91
|
+
cwd: gitRoot,
|
92
|
+
stdio: 'inherit',
|
93
|
+
shell: true,
|
94
|
+
});
|
95
|
+
if (pull.status !== 0) {
|
96
|
+
console.error('git pull 失败');
|
97
|
+
process.exit(1);
|
98
|
+
}
|
99
|
+
|
100
|
+
const srcPath = path.join(rootDir, 'src');
|
101
|
+
const stylelintTarget = fs.existsSync(srcPath)
|
102
|
+
? `${srcPath}/**/*.{css,scss,less}`
|
103
|
+
: './**/*.{css,scss,less}';
|
104
|
+
|
105
|
+
if (fs.existsSync(srcPath)) {
|
106
|
+
console.log(`检查目录样式文件: ${stylelintTarget}`);
|
107
|
+
} else {
|
108
|
+
console.warn(`src 文件夹不存在,改为检查当前目录下样式文件: ${stylelintTarget}`);
|
109
|
+
}
|
110
|
+
|
111
|
+
console.log('执行 Stylelint...');
|
112
|
+
const stylelint = spawn(
|
113
|
+
'npx',
|
114
|
+
[
|
115
|
+
'stylelint',
|
116
|
+
stylelintTarget,
|
117
|
+
'--allow-empty-input',
|
118
|
+
'--report-needless-disables',
|
119
|
+
'--report-invalid-scope-disables',
|
120
|
+
],
|
121
|
+
{
|
122
|
+
cwd: rootDir,
|
123
|
+
stdio: 'inherit',
|
124
|
+
shell: true,
|
125
|
+
},
|
126
|
+
);
|
127
|
+
|
128
|
+
stylelint.on('close', (code) => {
|
129
|
+
process.exit(code);
|
130
|
+
});
|
131
|
+
} catch (err) {
|
132
|
+
console.error('脚本执行出错:', err);
|
133
|
+
process.exit(1);
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
module.exports = runStylelint;
|
@@ -1,39 +1,39 @@
|
|
1
|
-
const path = require('path');
|
2
|
-
|
3
|
-
module.exports = {
|
4
|
-
extends: ['stylelint-config-standard'],
|
5
|
-
plugins: [
|
6
|
-
'stylelint-less',
|
7
|
-
'stylelint-scss',
|
8
|
-
path.join(__dirname, 'rules/color-must-use-variable.js'),
|
9
|
-
],
|
10
|
-
overrides: [
|
11
|
-
{
|
12
|
-
files: ['**/*.less'],
|
13
|
-
customSyntax: 'postcss-less',
|
14
|
-
},
|
15
|
-
{
|
16
|
-
files: ['**/*.scss', '**/*.sass'],
|
17
|
-
customSyntax: 'postcss-scss',
|
18
|
-
},
|
19
|
-
],
|
20
|
-
rules: {
|
21
|
-
'selector-class-pattern': '^[a-z][a-zA-Z0-9-]*$',
|
22
|
-
'selector-pseudo-class-no-unknown': [
|
23
|
-
true,
|
24
|
-
{
|
25
|
-
ignorePseudoClasses: ['global'],
|
26
|
-
},
|
27
|
-
],
|
28
|
-
|
29
|
-
'media-feature-range-notation': null,
|
30
|
-
'property-no-vendor-prefix': null,
|
31
|
-
|
32
|
-
'custom/color-must-use-variable': [
|
33
|
-
true,
|
34
|
-
{
|
35
|
-
severity: 'warning',
|
36
|
-
},
|
37
|
-
],
|
38
|
-
},
|
39
|
-
};
|
1
|
+
const path = require('node:path');
|
2
|
+
|
3
|
+
module.exports = {
|
4
|
+
extends: ['stylelint-config-standard'],
|
5
|
+
plugins: [
|
6
|
+
'stylelint-less',
|
7
|
+
'stylelint-scss',
|
8
|
+
path.join(__dirname, 'rules/color-must-use-variable.js'),
|
9
|
+
],
|
10
|
+
overrides: [
|
11
|
+
{
|
12
|
+
files: ['**/*.less'],
|
13
|
+
customSyntax: 'postcss-less',
|
14
|
+
},
|
15
|
+
{
|
16
|
+
files: ['**/*.scss', '**/*.sass'],
|
17
|
+
customSyntax: 'postcss-scss',
|
18
|
+
},
|
19
|
+
],
|
20
|
+
rules: {
|
21
|
+
'selector-class-pattern': '^[a-z][a-zA-Z0-9-]*$',
|
22
|
+
'selector-pseudo-class-no-unknown': [
|
23
|
+
true,
|
24
|
+
{
|
25
|
+
ignorePseudoClasses: ['global'],
|
26
|
+
},
|
27
|
+
],
|
28
|
+
|
29
|
+
'media-feature-range-notation': null,
|
30
|
+
'property-no-vendor-prefix': null,
|
31
|
+
|
32
|
+
'custom/color-must-use-variable': [
|
33
|
+
true,
|
34
|
+
{
|
35
|
+
severity: 'warning',
|
36
|
+
},
|
37
|
+
],
|
38
|
+
},
|
39
|
+
};
|
@@ -1,61 +1,63 @@
|
|
1
|
-
const stylelint = require('stylelint');
|
2
|
-
const valueParser = require('postcss-value-parser');
|
3
|
-
const cssColorNames = require('css-color-names');
|
4
|
-
const cssColorKeywords = Object.keys(cssColorNames);
|
5
|
-
|
6
|
-
const ruleName = 'custom/color-must-use-variable';
|
7
|
-
const messages = stylelint.utils.ruleMessages(ruleName, {
|
8
|
-
expected: (val) => `Expected color "${val}" to be a color variable`,
|
9
|
-
});
|
10
|
-
|
11
|
-
const colorWordRegex = new RegExp(
|
12
|
-
`^(#(?:[0-9a-fA-F]{3,8})|(?:${cssColorKeywords.join('|')}))$`,
|
13
|
-
'i',
|
14
|
-
);
|
15
|
-
|
16
|
-
const
|
17
|
-
|
18
|
-
|
19
|
-
const
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
if (node.
|
24
|
-
return
|
25
|
-
|
26
|
-
|
27
|
-
}
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
}
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
if (
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
});
|
59
|
-
|
60
|
-
|
61
|
-
|
1
|
+
const stylelint = require('stylelint');
|
2
|
+
const valueParser = require('postcss-value-parser');
|
3
|
+
const cssColorNames = require('css-color-names');
|
4
|
+
const cssColorKeywords = Object.keys(cssColorNames);
|
5
|
+
|
6
|
+
const ruleName = 'custom/color-must-use-variable';
|
7
|
+
const messages = stylelint.utils.ruleMessages(ruleName, {
|
8
|
+
expected: (val) => `Expected color "${val}" to be a color variable`,
|
9
|
+
});
|
10
|
+
|
11
|
+
const colorWordRegex = new RegExp(
|
12
|
+
`^(#(?:[0-9a-fA-F]{3,8})|(?:${cssColorKeywords.join('|')}))$`,
|
13
|
+
'i',
|
14
|
+
);
|
15
|
+
|
16
|
+
const colorFunctionRegex = /^(rgb|rgba|hsl|hsla|lab|lch)$/i;
|
17
|
+
|
18
|
+
const isColorWord = (node) => node.type === 'word' && colorWordRegex.test(node.value);
|
19
|
+
const isHardcodedFunctionColor = (node) =>
|
20
|
+
node.type === 'function' && colorFunctionRegex.test(node.value);
|
21
|
+
const containsVar = (node) => {
|
22
|
+
if (node.type === 'function' && node.value === 'var') return true;
|
23
|
+
if (node.type === 'word' && (node.value.startsWith('@') || node.value.startsWith('$')))
|
24
|
+
return true;
|
25
|
+
if (node.nodes?.length) {
|
26
|
+
return node.nodes.some(containsVar);
|
27
|
+
}
|
28
|
+
return false;
|
29
|
+
};
|
30
|
+
|
31
|
+
module.exports = stylelint.createPlugin(ruleName, (_primaryOption, secondaryOptions = {}) => {
|
32
|
+
return (root, result) => {
|
33
|
+
root.walkDecls((decl) => {
|
34
|
+
let parsedValue;
|
35
|
+
try {
|
36
|
+
parsedValue = valueParser(decl.value);
|
37
|
+
} catch (_e) {
|
38
|
+
return; // 解析失败跳过
|
39
|
+
}
|
40
|
+
|
41
|
+
parsedValue.walk((node) => {
|
42
|
+
const nodeStr = valueParser.stringify(node);
|
43
|
+
if (containsVar(node)) return; // 跳过包含 var() 的
|
44
|
+
|
45
|
+
if (isColorWord(node) || isHardcodedFunctionColor(node)) {
|
46
|
+
stylelint.utils.report({
|
47
|
+
ruleName,
|
48
|
+
result,
|
49
|
+
node: decl,
|
50
|
+
message: messages.expected(nodeStr),
|
51
|
+
word: nodeStr,
|
52
|
+
index: decl.value.indexOf(nodeStr),
|
53
|
+
endIndex: decl.value.indexOf(nodeStr) + nodeStr.length,
|
54
|
+
severity: secondaryOptions.severity || 'error',
|
55
|
+
});
|
56
|
+
}
|
57
|
+
});
|
58
|
+
});
|
59
|
+
};
|
60
|
+
});
|
61
|
+
|
62
|
+
module.exports.ruleName = ruleName;
|
63
|
+
module.exports.messages = messages;
|
@@ -1,100 +0,0 @@
|
|
1
|
-
module.exports = {
|
2
|
-
root: true,
|
3
|
-
env: {
|
4
|
-
browser: true,
|
5
|
-
node: true,
|
6
|
-
es2021: true,
|
7
|
-
},
|
8
|
-
parser: '@typescript-eslint/parser',
|
9
|
-
extends: [
|
10
|
-
'airbnb',
|
11
|
-
'airbnb/hooks',
|
12
|
-
'plugin:@typescript-eslint/recommended',
|
13
|
-
'plugin:import/errors',
|
14
|
-
'plugin:import/warnings',
|
15
|
-
'prettier',
|
16
|
-
],
|
17
|
-
plugins: ['@typescript-eslint', 'import', 'jsx-a11y', 'react', 'react-hooks'],
|
18
|
-
rules: {
|
19
|
-
'arrow-body-style': 'off',
|
20
|
-
|
21
|
-
camelcase: 'off',
|
22
|
-
'class-methods-use-this': 'off',
|
23
|
-
|
24
|
-
'dot-notation': 'warn',
|
25
|
-
|
26
|
-
'import/order': 'warn',
|
27
|
-
'import/first': 'off',
|
28
|
-
'import/extensions': 'off',
|
29
|
-
'import/prefer-default-export': 'off',
|
30
|
-
|
31
|
-
'jsx-a11y/click-events-have-key-events': 'off',
|
32
|
-
'jsx-a11y/no-static-element-interactions': 'off',
|
33
|
-
'jsx-a11y/no-noninteractive-element-interactions': 'off',
|
34
|
-
|
35
|
-
'linebreak-style': 'off',
|
36
|
-
'lines-between-class-members': 'warn',
|
37
|
-
|
38
|
-
'max-classes-per-file': 'off',
|
39
|
-
|
40
|
-
'no-undef': 'off',
|
41
|
-
'no-plusplus': 'off',
|
42
|
-
|
43
|
-
'react/function-component-definition': 'off',
|
44
|
-
'react-hooks/exhaustive-deps': 'off',
|
45
|
-
'react/prop-types': 'off',
|
46
|
-
'react/react-in-jsx-scope': 'off',
|
47
|
-
'react/require-default-props': 'off',
|
48
|
-
'react/jsx-boolean-value': 'off',
|
49
|
-
'react/jsx-filename-extension': 'off',
|
50
|
-
'react/jsx-props-no-spreading': 'off',
|
51
|
-
'react/self-closing-comp': 'off',
|
52
|
-
'react/jsx-no-useless-fragment': 'off',
|
53
|
-
|
54
|
-
'@typescript-eslint/no-explicit-any': 'warn',
|
55
|
-
|
56
|
-
'no-use-before-define': 'off',
|
57
|
-
'@typescript-eslint/no-use-before-define': ['warn'],
|
58
|
-
|
59
|
-
'no-unused-vars': 'off',
|
60
|
-
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
|
61
|
-
|
62
|
-
'no-useless-constructor': 'off',
|
63
|
-
'@typescript-eslint/no-useless-constructor': 'warn',
|
64
|
-
|
65
|
-
'no-shadow': 'off',
|
66
|
-
'@typescript-eslint/no-shadow': 'warn',
|
67
|
-
|
68
|
-
'no-empty-function': ['warn', { allow: ['constructors', 'arrowFunctions'] }],
|
69
|
-
'no-param-reassign': ['warn', { props: true, ignorePropertyModificationsFor: ['draft'] }],
|
70
|
-
'no-restricted-syntax': [
|
71
|
-
'warn',
|
72
|
-
{
|
73
|
-
selector: "CallExpression[callee.name='useMemo']",
|
74
|
-
message: 'Avoid using useMemo unless caching a computed value improves performance.',
|
75
|
-
},
|
76
|
-
{
|
77
|
-
selector: "CallExpression[callee.name='useCallback']",
|
78
|
-
message:
|
79
|
-
'Avoid using useCallback unless you need to cache a function to prevent unnecessary re-renders.',
|
80
|
-
},
|
81
|
-
],
|
82
|
-
},
|
83
|
-
parserOptions: {
|
84
|
-
sourceType: 'module',
|
85
|
-
},
|
86
|
-
ignorePatterns: ['dist/', 'node_modules/', '*.d.ts', 'mock', '.eslintrc.cjs'],
|
87
|
-
settings: {
|
88
|
-
react: {
|
89
|
-
version: 'detect',
|
90
|
-
},
|
91
|
-
'import/resolver': {
|
92
|
-
alias: {
|
93
|
-
map: [
|
94
|
-
['@', './src'], // 将 '@' 映射到 'src' 目录
|
95
|
-
],
|
96
|
-
extensions: ['.ts', '.tsx', '.js', '.jsx', '.d.ts'],
|
97
|
-
},
|
98
|
-
},
|
99
|
-
},
|
100
|
-
};
|