@apdesign/code-style-react 1.0.3 → 1.0.5
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 +0 -1
- package/cli.js +11 -0
- package/index.js +1 -1
- package/package.json +6 -4
- package/scripts/buildEslint.sh +14 -6
- package/scripts/buildStylelint.sh +13 -9
- package/scripts/initConfigs.js +2 -2
- package/{.stylelintrc.js → stylelint/.stylelintrc.js} +19 -2
- package/stylelint/rules/color-must-use-variable.js +124 -0
- /package/{.eslintrc.build.js → eslint/.eslintrc.build.js} +0 -0
- /package/{.eslintrc.js → eslint/.eslintrc.js} +0 -0
package/.prettierrc.js
CHANGED
package/cli.js
ADDED
package/index.js
CHANGED
package/package.json
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
{
|
2
2
|
"name": "@apdesign/code-style-react",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.0.5",
|
4
4
|
"scripts": {},
|
5
|
+
"bin": {
|
6
|
+
"apdesign-code-style": "cli.js"
|
7
|
+
},
|
5
8
|
"files": [
|
6
9
|
"index.js",
|
7
10
|
".prettierrc.js",
|
8
|
-
"
|
9
|
-
"
|
10
|
-
".stylelintrc.js",
|
11
|
+
"eslint",
|
12
|
+
"stylelint",
|
11
13
|
"husky",
|
12
14
|
"scripts"
|
13
15
|
],
|
package/scripts/buildEslint.sh
CHANGED
@@ -27,14 +27,22 @@ fi
|
|
27
27
|
echo "📂 Changed files:"
|
28
28
|
echo "$DIFF_FILES"
|
29
29
|
|
30
|
-
FILE_COUNT=$(echo "$DIFF_FILES" | wc -
|
30
|
+
FILE_COUNT=$(echo "$DIFF_FILES" | wc -l)
|
31
31
|
echo "🧾 Total changed files: $FILE_COUNT"
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
ESLINT_CONFIG_FILE="$PROJECT_ROOT/.eslintrc.build.cjs"
|
34
|
+
|
35
|
+
ESLINT_CMD_ARGS="--no-error-on-unmatched-pattern --report-unused-disable-directives"
|
36
|
+
|
37
|
+
if [ -f "$ESLINT_CONFIG_FILE" ]; then
|
38
|
+
echo "🔧 Using ESLint config file: $ESLINT_CONFIG_FILE"
|
39
|
+
ESLINT_CMD_ARGS="--config $ESLINT_CONFIG_FILE $ESLINT_CMD_ARGS"
|
40
|
+
else
|
41
|
+
echo "⚠️ ESLint config file not found, using default ESLint config resolution."
|
42
|
+
fi
|
43
|
+
|
44
|
+
echo "$DIFF_FILES" | tr -d '\r' | \
|
45
|
+
xargs -d '\n' -P 4 -n 30 npx --no-install eslint $ESLINT_CMD_ARGS
|
38
46
|
|
39
47
|
if [ $? -ne 0 ]; then
|
40
48
|
echo "❌ ESLint check failed. Aborting build process"
|
@@ -1,7 +1,6 @@
|
|
1
1
|
#!/usr/bin/env sh
|
2
2
|
echo "🔍 Starting Stylelint check (Git diff files only)..."
|
3
3
|
|
4
|
-
# 切换到 Git 仓库根目录
|
5
4
|
PROJECT_ROOT=$(git rev-parse --show-toplevel)
|
6
5
|
cd "$PROJECT_ROOT" || exit 1
|
7
6
|
|
@@ -27,16 +26,21 @@ fi
|
|
27
26
|
echo "📂 Changed files:"
|
28
27
|
echo "$DIFF_FILES"
|
29
28
|
|
30
|
-
FILE_COUNT=$(echo "$DIFF_FILES" | wc -
|
29
|
+
FILE_COUNT=$(echo "$DIFF_FILES" | wc -l)
|
31
30
|
echo "🧾 Total changed files: $FILE_COUNT"
|
32
31
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
32
|
+
STYLELINT_CONFIG_FILE="$PROJECT_ROOT/.stylelintrc.build.cjs"
|
33
|
+
STYLELINT_CMD_ARGS="--allow-empty-input --report-needless-disables --report-invalid-scope-disables"
|
34
|
+
|
35
|
+
if [ -f "$STYLELINT_CONFIG_FILE" ]; then
|
36
|
+
echo "🔧 Using Stylelint config file: $STYLELINT_CONFIG_FILE"
|
37
|
+
STYLELINT_CMD_ARGS="--config $STYLELINT_CONFIG_FILE $STYLELINT_CMD_ARGS"
|
38
|
+
else
|
39
|
+
echo "⚠️ Stylelint config file not found, using default Stylelint config resolution."
|
40
|
+
fi
|
41
|
+
|
42
|
+
echo "$DIFF_FILES" | tr -d '\r' | \
|
43
|
+
xargs -d '\n' -P 4 -n 30 npx --no-install stylelint $STYLELINT_CMD_ARGS
|
40
44
|
|
41
45
|
if [ $? -ne 0 ]; then
|
42
46
|
echo "❌ Stylelint check failed. Aborting build process"
|
package/scripts/initConfigs.js
CHANGED
@@ -62,7 +62,7 @@ function initConfigs() {
|
|
62
62
|
|
63
63
|
try {
|
64
64
|
if (!hasAnyFileExist(eslintConfigFiles)) {
|
65
|
-
const eslintContent = `const baseConfig = require('@apdesign/code-style-react/.eslintrc.js');
|
65
|
+
const eslintContent = `const baseConfig = require('@apdesign/code-style-react/eslint/.eslintrc.js');
|
66
66
|
module.exports = {
|
67
67
|
...baseConfig,
|
68
68
|
rules: {
|
@@ -73,7 +73,7 @@ module.exports = {
|
|
73
73
|
}
|
74
74
|
|
75
75
|
if (!hasAnyFileExist(stylelintConfigFiles)) {
|
76
|
-
const stylelintContent = `const baseConfig = require('@apdesign/code-style-react/.stylelintrc.js');
|
76
|
+
const stylelintContent = `const baseConfig = require('@apdesign/code-style-react/stylelint/.stylelintrc.js');
|
77
77
|
module.exports = {
|
78
78
|
...baseConfig,
|
79
79
|
rules: {
|
@@ -1,6 +1,16 @@
|
|
1
|
+
const colorMustUseVariable = require('./rules/color-must-use-variable');
|
2
|
+
|
1
3
|
module.exports = {
|
2
4
|
extends: ['stylelint-config-standard'],
|
3
|
-
plugins: [
|
5
|
+
plugins: [
|
6
|
+
'stylelint-less',
|
7
|
+
'stylelint-scss',
|
8
|
+
{
|
9
|
+
rules: {
|
10
|
+
[colorMustUseVariable.ruleName]: colorMustUseVariable,
|
11
|
+
},
|
12
|
+
},
|
13
|
+
],
|
4
14
|
overrides: [
|
5
15
|
{
|
6
16
|
files: ['**/*.less'],
|
@@ -8,7 +18,7 @@ module.exports = {
|
|
8
18
|
},
|
9
19
|
{
|
10
20
|
files: ['**/*.scss', '**/*.sass'],
|
11
|
-
customSyntax: 'postcss-
|
21
|
+
customSyntax: 'postcss-scss',
|
12
22
|
},
|
13
23
|
],
|
14
24
|
rules: {
|
@@ -22,5 +32,12 @@ module.exports = {
|
|
22
32
|
|
23
33
|
'media-feature-range-notation': null,
|
24
34
|
'property-no-vendor-prefix': null,
|
35
|
+
|
36
|
+
'custom/color-must-use-variable': [
|
37
|
+
true,
|
38
|
+
{
|
39
|
+
severity: 'warning',
|
40
|
+
},
|
41
|
+
],
|
25
42
|
},
|
26
43
|
};
|
@@ -0,0 +1,124 @@
|
|
1
|
+
const stylelint = require('stylelint');
|
2
|
+
const valueParser = require('postcss-value-parser');
|
3
|
+
|
4
|
+
const ruleName = 'custom/color-must-use-variable';
|
5
|
+
const messages = stylelint.utils.ruleMessages(ruleName, {
|
6
|
+
expected: (val) => `Expected color "${val}" to be a color variable`,
|
7
|
+
});
|
8
|
+
|
9
|
+
// 默认颜色关键字
|
10
|
+
const defaultCssColorKeywords = [
|
11
|
+
'red',
|
12
|
+
'blue',
|
13
|
+
'green',
|
14
|
+
'black',
|
15
|
+
'white',
|
16
|
+
'gray',
|
17
|
+
'aqua',
|
18
|
+
'fuchsia',
|
19
|
+
'lime',
|
20
|
+
'maroon',
|
21
|
+
'navy',
|
22
|
+
'olive',
|
23
|
+
'purple',
|
24
|
+
'silver',
|
25
|
+
'teal',
|
26
|
+
'yellow',
|
27
|
+
'orange',
|
28
|
+
'pink',
|
29
|
+
'brown',
|
30
|
+
'cyan',
|
31
|
+
'magenta',
|
32
|
+
'gold',
|
33
|
+
'azure',
|
34
|
+
];
|
35
|
+
|
36
|
+
// 默认检查的属性
|
37
|
+
const defaultPropsToCheck = [
|
38
|
+
'color',
|
39
|
+
'background',
|
40
|
+
'background-color',
|
41
|
+
'border',
|
42
|
+
'border-color',
|
43
|
+
'border-top-color',
|
44
|
+
'border-right-color',
|
45
|
+
'border-bottom-color',
|
46
|
+
'border-left-color',
|
47
|
+
'outline',
|
48
|
+
'outline-color',
|
49
|
+
'text-decoration-color',
|
50
|
+
'box-shadow',
|
51
|
+
'text-shadow',
|
52
|
+
'column-rule-color',
|
53
|
+
'caret-color',
|
54
|
+
'fill',
|
55
|
+
'stroke',
|
56
|
+
'stop-color',
|
57
|
+
];
|
58
|
+
|
59
|
+
const containsVarFunction = (node) => {
|
60
|
+
if (node.type === 'function' && node.value === 'var') return true;
|
61
|
+
if (node.nodes && node.nodes.length) {
|
62
|
+
return node.nodes.some(containsVarFunction);
|
63
|
+
}
|
64
|
+
return false;
|
65
|
+
};
|
66
|
+
|
67
|
+
module.exports = stylelint.createPlugin(ruleName, (primaryOption, secondaryOptions = {}) => {
|
68
|
+
// 合并自定义颜色关键字和默认颜色关键字(去重)
|
69
|
+
const cssColorKeywords = Array.from(
|
70
|
+
new Set([...(secondaryOptions.cssColorKeywords || []), ...defaultCssColorKeywords]),
|
71
|
+
);
|
72
|
+
|
73
|
+
// 生成颜色匹配正则
|
74
|
+
const colorWordRegex = new RegExp(
|
75
|
+
`^(#(?:[0-9a-fA-F]{3,8})|(?:${cssColorKeywords.join('|')}))$`,
|
76
|
+
'i',
|
77
|
+
);
|
78
|
+
|
79
|
+
// 判断是否为硬编码颜色文字,如 #fff 或 red
|
80
|
+
const isColorWord = (node) => node.type === 'word' && colorWordRegex.test(node.value);
|
81
|
+
|
82
|
+
// 判断是否为硬编码颜色函数,如 rgb(), hsl() 等
|
83
|
+
const isHardcodedFunctionColor = (node) =>
|
84
|
+
node.type === 'function' && /^(rgb|rgba|hsl|hsla|lab|lch)$/i.test(node.value);
|
85
|
+
|
86
|
+
// 合并自定义属性和默认属性(去重)
|
87
|
+
const propsToCheck = Array.from(
|
88
|
+
new Set([...(secondaryOptions.properties || []), ...defaultPropsToCheck]),
|
89
|
+
);
|
90
|
+
|
91
|
+
return (root, result) => {
|
92
|
+
root.walkDecls((decl) => {
|
93
|
+
if (!propsToCheck.includes(decl.prop)) return;
|
94
|
+
|
95
|
+
let parsedValue;
|
96
|
+
try {
|
97
|
+
parsedValue = valueParser(decl.value);
|
98
|
+
} catch (e) {
|
99
|
+
return; // 解析失败跳过
|
100
|
+
}
|
101
|
+
|
102
|
+
parsedValue.walk((node) => {
|
103
|
+
const nodeStr = valueParser.stringify(node);
|
104
|
+
if (containsVarFunction(node)) return; // 跳过包含 var() 的
|
105
|
+
|
106
|
+
if (isColorWord(node) || isHardcodedFunctionColor(node)) {
|
107
|
+
stylelint.utils.report({
|
108
|
+
ruleName,
|
109
|
+
result,
|
110
|
+
node: decl,
|
111
|
+
message: messages.expected(nodeStr),
|
112
|
+
word: nodeStr,
|
113
|
+
index: decl.value.indexOf(nodeStr),
|
114
|
+
endIndex: decl.value.indexOf(nodeStr) + nodeStr.length,
|
115
|
+
severity: secondaryOptions.severity || 'error',
|
116
|
+
});
|
117
|
+
}
|
118
|
+
});
|
119
|
+
});
|
120
|
+
};
|
121
|
+
});
|
122
|
+
|
123
|
+
module.exports.ruleName = ruleName;
|
124
|
+
module.exports.messages = messages;
|
File without changes
|
File without changes
|