@d-zero/stylelint-rules 5.0.0-alpha.76 → 5.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/dist/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import component from './rules/component/index.js';
|
|
2
|
+
import componentRootDisallowedProperties from './rules/component-root-disallowed-properties/index.js';
|
|
2
3
|
import declarationValueTypeDisallowedList from './rules/declaration-value-type-disallowed-list/index.js';
|
|
3
4
|
import preferIndividualTransformProperties from './rules/prefer-individual-transform-properties/index.js';
|
|
4
5
|
import shorthandPropertyUseLogical from './rules/shorthand-property-use-logical/index.js';
|
|
5
6
|
export default [
|
|
6
7
|
component,
|
|
8
|
+
componentRootDisallowedProperties,
|
|
7
9
|
declarationValueTypeDisallowedList,
|
|
8
10
|
preferIndividualTransformProperties,
|
|
9
11
|
shorthandPropertyUseLogical,
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import selectorParser from 'postcss-selector-parser';
|
|
3
|
+
import stylelint from 'stylelint';
|
|
4
|
+
import { createRule } from '../../utils/create-rule.js';
|
|
5
|
+
// 禁止プロパティのリスト
|
|
6
|
+
// string: プロパティ名のみ(例: 'width', 'margin')
|
|
7
|
+
// { [propName: string]: string }: プロパティ名と値のペア(例: { position: 'absolute' })
|
|
8
|
+
const DISALLOWED_PROPERTIES = [
|
|
9
|
+
'width',
|
|
10
|
+
'inline-size',
|
|
11
|
+
'margin',
|
|
12
|
+
'margin-top',
|
|
13
|
+
'margin-right',
|
|
14
|
+
'margin-bottom',
|
|
15
|
+
'margin-left',
|
|
16
|
+
'margin-block',
|
|
17
|
+
'margin-inline',
|
|
18
|
+
'margin-block-start',
|
|
19
|
+
'margin-block-end',
|
|
20
|
+
'margin-inline-start',
|
|
21
|
+
'margin-inline-end',
|
|
22
|
+
'height',
|
|
23
|
+
'block-size',
|
|
24
|
+
'inset',
|
|
25
|
+
'inset-block',
|
|
26
|
+
'inset-inline',
|
|
27
|
+
'top',
|
|
28
|
+
'right',
|
|
29
|
+
'bottom',
|
|
30
|
+
'left',
|
|
31
|
+
'justify-self',
|
|
32
|
+
'align-self',
|
|
33
|
+
'place-self',
|
|
34
|
+
'flex',
|
|
35
|
+
'flex-grow',
|
|
36
|
+
'flex-shrink',
|
|
37
|
+
'flex-basis',
|
|
38
|
+
'grid-area',
|
|
39
|
+
'float',
|
|
40
|
+
'clear',
|
|
41
|
+
{ position: 'absolute' },
|
|
42
|
+
{ position: 'fixed' },
|
|
43
|
+
{ position: 'sticky' },
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* プロパティが禁止されているかチェック
|
|
47
|
+
* @param prop
|
|
48
|
+
*/
|
|
49
|
+
function isDisallowedProperty(prop) {
|
|
50
|
+
const normalizedProp = prop.toLowerCase();
|
|
51
|
+
return DISALLOWED_PROPERTIES.some((item) => {
|
|
52
|
+
if (typeof item === 'string') {
|
|
53
|
+
return item === normalizedProp;
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* プロパティと値の組み合わせが禁止されているかチェック
|
|
60
|
+
* @param prop
|
|
61
|
+
* @param value
|
|
62
|
+
*/
|
|
63
|
+
function isDisallowedPropertyValue(prop, value) {
|
|
64
|
+
const normalizedProp = prop.toLowerCase();
|
|
65
|
+
const normalizedValue = value.toLowerCase().trim();
|
|
66
|
+
return DISALLOWED_PROPERTIES.some((item) => {
|
|
67
|
+
if (typeof item === 'object') {
|
|
68
|
+
return (normalizedProp in item && item[normalizedProp]?.toLowerCase() === normalizedValue);
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* ルールがコンポーネントルートかどうかを判定
|
|
75
|
+
* @param rule
|
|
76
|
+
* @param basename
|
|
77
|
+
*/
|
|
78
|
+
function isComponentRoot(rule, basename) {
|
|
79
|
+
const ruleSelectors = [];
|
|
80
|
+
selectorParser((parsedRoot) => {
|
|
81
|
+
for (const node of parsedRoot.nodes) {
|
|
82
|
+
ruleSelectors.push(node);
|
|
83
|
+
}
|
|
84
|
+
}).processSync(rule.selector);
|
|
85
|
+
const [ruleFirstSelector] = ruleSelectors;
|
|
86
|
+
if (!ruleFirstSelector) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
for (const node of ruleFirstSelector.nodes) {
|
|
90
|
+
if (node.type === 'class') {
|
|
91
|
+
const className = node.value;
|
|
92
|
+
// ファイル名と完全一致するクラス名のみがコンポーネントルート
|
|
93
|
+
// CSSファイルの場合は __ で始まるクラスは子要素なので除外
|
|
94
|
+
if (className === basename) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* ルールのセレクタに疑似クラスが含まれているか判定
|
|
103
|
+
* @param rule
|
|
104
|
+
*/
|
|
105
|
+
function hasPseudoClass(rule) {
|
|
106
|
+
let hasPseudo = false;
|
|
107
|
+
selectorParser((parsedRoot) => {
|
|
108
|
+
parsedRoot.walkPseudos((pseudo) => {
|
|
109
|
+
// 疑似クラスは : で始まる(疑似要素は :: で始まる)
|
|
110
|
+
if (pseudo.value.startsWith(':')) {
|
|
111
|
+
hasPseudo = true;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}).processSync(rule.selector);
|
|
115
|
+
return hasPseudo;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* ルールのセレクタに疑似要素が含まれているか判定
|
|
119
|
+
* @param rule
|
|
120
|
+
*/
|
|
121
|
+
function hasPseudoElement(rule) {
|
|
122
|
+
let hasPseudo = false;
|
|
123
|
+
selectorParser((parsedRoot) => {
|
|
124
|
+
parsedRoot.walkPseudos((pseudo) => {
|
|
125
|
+
// 疑似要素は :: で始まる
|
|
126
|
+
if (pseudo.value.startsWith('::')) {
|
|
127
|
+
hasPseudo = true;
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}).processSync(rule.selector);
|
|
131
|
+
return hasPseudo;
|
|
132
|
+
}
|
|
133
|
+
export default createRule({
|
|
134
|
+
name: 'component-root-disallowed-properties',
|
|
135
|
+
rejected: (property) => `コンポーネントルートで "${property}" プロパティは禁止されています`,
|
|
136
|
+
rule: (ruleName, messages) => () => {
|
|
137
|
+
return (root, result) => {
|
|
138
|
+
const fileName = root.source?.input.file;
|
|
139
|
+
if (!fileName) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const ext = path.extname(fileName);
|
|
143
|
+
const originalBasename = path.basename(fileName, ext);
|
|
144
|
+
const basename = ['.scss', '.sass'].includes(ext)
|
|
145
|
+
? originalBasename.replace(/^_/, '')
|
|
146
|
+
: originalBasename;
|
|
147
|
+
const rules = root.nodes.filter((node) => node.type === 'rule');
|
|
148
|
+
/**
|
|
149
|
+
* ルール内の宣言をチェックする関数
|
|
150
|
+
* @param rule
|
|
151
|
+
*/
|
|
152
|
+
const checkDeclarations = (rule) => {
|
|
153
|
+
for (const node of rule.nodes) {
|
|
154
|
+
if (node.type === 'decl') {
|
|
155
|
+
const prop = node.prop;
|
|
156
|
+
const value = node.value;
|
|
157
|
+
// プロパティと値の組み合わせが禁止されているかチェック
|
|
158
|
+
if (isDisallowedPropertyValue(prop, value)) {
|
|
159
|
+
const normalizedValue = value.toLowerCase().trim();
|
|
160
|
+
stylelint.utils.report({
|
|
161
|
+
result,
|
|
162
|
+
ruleName,
|
|
163
|
+
message: messages.rejected(`${prop}: ${normalizedValue}`),
|
|
164
|
+
node,
|
|
165
|
+
});
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
// その他の禁止プロパティのチェック
|
|
169
|
+
if (isDisallowedProperty(prop)) {
|
|
170
|
+
stylelint.utils.report({
|
|
171
|
+
result,
|
|
172
|
+
ruleName,
|
|
173
|
+
message: messages.rejected(prop),
|
|
174
|
+
node,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else if (node.type === 'rule') {
|
|
179
|
+
// ネストされたルールをチェック
|
|
180
|
+
// 疑似要素を含むルールはチェック対象から除外
|
|
181
|
+
if (hasPseudoElement(node)) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
// 疑似クラスを含むルールはチェック対象
|
|
185
|
+
if (hasPseudoClass(node)) {
|
|
186
|
+
checkDeclarations(node);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
// 各ルールをチェック
|
|
192
|
+
for (const rule of rules) {
|
|
193
|
+
// コンポーネントルートかどうかを判定
|
|
194
|
+
if (!isComponentRoot(rule, basename)) {
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
// コンポーネントルート内の直接の子ノード(宣言)と疑似クラスを含むネストされたルールをチェック
|
|
198
|
+
checkDeclarations(rule);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
},
|
|
202
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@d-zero/stylelint-rules",
|
|
3
|
-
"version": "5.0.0
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Rules of Stylelint for D-ZERO",
|
|
5
5
|
"repository": "https://github.com/d-zero-dev/linters.git",
|
|
6
6
|
"author": "D-ZERO Co., Ltd.",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"build": "tsc"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@d-zero/csstree-scss-syntax": "5.0.0
|
|
25
|
+
"@d-zero/csstree-scss-syntax": "5.0.0",
|
|
26
26
|
"css-tree": "3.1.0",
|
|
27
27
|
"postcss-selector-parser": "7.1.1",
|
|
28
28
|
"postcss-value-parser": "4.2.0",
|
|
@@ -31,5 +31,5 @@
|
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"postcss": "8.5.6"
|
|
33
33
|
},
|
|
34
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "7f635ad8bbb1455d0d362fe00478a2f7bd216924"
|
|
35
35
|
}
|