@d-zero/stylelint-rules 5.0.0-alpha.73 → 5.0.0-alpha.74
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/package.json +4 -4
- package/dist/rules/component/index.spec.js +0 -220
- package/dist/rules/declaration-value-type-disallowed-list/index.spec.js +0 -66
- package/dist/rules/prefer-individual-transform-properties/index.spec.js +0 -137
- package/dist/rules/shorthand-property-use-logical/index.spec.js +0 -162
- package/dist/utils/get-value-type.spec.js +0 -44
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@d-zero/stylelint-rules",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.74",
|
|
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,14 +22,14 @@
|
|
|
22
22
|
"build": "tsc"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@d-zero/csstree-scss-syntax": "5.0.0-alpha.
|
|
25
|
+
"@d-zero/csstree-scss-syntax": "5.0.0-alpha.74",
|
|
26
26
|
"css-tree": "3.1.0",
|
|
27
27
|
"postcss-selector-parser": "7.1.0",
|
|
28
28
|
"postcss-value-parser": "4.2.0",
|
|
29
|
-
"stylelint": "16.
|
|
29
|
+
"stylelint": "16.26.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"postcss": "8.5.6"
|
|
33
33
|
},
|
|
34
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "d7cda25cdb3d897fb6a33b1e37f1179c2faf40ad"
|
|
35
35
|
}
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
import stylelint from 'stylelint';
|
|
2
|
-
import { describe, test, expect } from 'vitest';
|
|
3
|
-
import rule from './index.js';
|
|
4
|
-
const { lint } = stylelint;
|
|
5
|
-
const config = (settings = true) => ({
|
|
6
|
-
plugins: [rule],
|
|
7
|
-
rules: {
|
|
8
|
-
// @ts-ignore
|
|
9
|
-
[rule.ruleName]: settings,
|
|
10
|
-
},
|
|
11
|
-
});
|
|
12
|
-
describe('Exact Match', () => {
|
|
13
|
-
test('matched', async () => {
|
|
14
|
-
const {
|
|
15
|
-
// @ts-ignore
|
|
16
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
17
|
-
codeFilename: 'test.css',
|
|
18
|
-
code: '.test { color: currentColor; }',
|
|
19
|
-
config: config({}),
|
|
20
|
-
});
|
|
21
|
-
expect(parseErrors).toHaveLength(0);
|
|
22
|
-
expect(warnings).toHaveLength(0);
|
|
23
|
-
});
|
|
24
|
-
test('unmatched', async () => {
|
|
25
|
-
const {
|
|
26
|
-
// @ts-ignore
|
|
27
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
28
|
-
codeFilename: 'test.css',
|
|
29
|
-
code: '.text, *, div.test { color: currentColor; .test { color: inherit; } }',
|
|
30
|
-
config: config({}),
|
|
31
|
-
});
|
|
32
|
-
expect(parseErrors).toHaveLength(0);
|
|
33
|
-
expect(warnings).toStrictEqual([
|
|
34
|
-
{
|
|
35
|
-
column: 1,
|
|
36
|
-
endColumn: 70,
|
|
37
|
-
endLine: 1,
|
|
38
|
-
line: 1,
|
|
39
|
-
rule: '@d-zero/component',
|
|
40
|
-
severity: 'error',
|
|
41
|
-
text: 'クラス名がファイル名と一致しないか、コンポーネント命名規則(test__)で始まっていません',
|
|
42
|
-
url: undefined,
|
|
43
|
-
fix: undefined,
|
|
44
|
-
},
|
|
45
|
-
]);
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
describe('Component Naming Convention for CSS', () => {
|
|
49
|
-
test('exact match in CSS', async () => {
|
|
50
|
-
const {
|
|
51
|
-
// @ts-ignore
|
|
52
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
53
|
-
codeFilename: 'button.css',
|
|
54
|
-
code: '.button { color: currentColor; }',
|
|
55
|
-
config: config({}),
|
|
56
|
-
});
|
|
57
|
-
expect(parseErrors).toHaveLength(0);
|
|
58
|
-
expect(warnings).toHaveLength(0);
|
|
59
|
-
});
|
|
60
|
-
test('component element match in CSS', async () => {
|
|
61
|
-
const {
|
|
62
|
-
// @ts-ignore
|
|
63
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
64
|
-
codeFilename: 'button.css',
|
|
65
|
-
code: '.button__text { color: currentColor; }',
|
|
66
|
-
config: config({}),
|
|
67
|
-
});
|
|
68
|
-
expect(parseErrors).toHaveLength(0);
|
|
69
|
-
expect(warnings).toHaveLength(0);
|
|
70
|
-
});
|
|
71
|
-
test('multiple component elements in CSS (auto-allow)', async () => {
|
|
72
|
-
const {
|
|
73
|
-
// @ts-ignore
|
|
74
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
75
|
-
codeFilename: 'button.css',
|
|
76
|
-
code: '.button__text, .button__icon { color: currentColor; }',
|
|
77
|
-
config: config({}),
|
|
78
|
-
});
|
|
79
|
-
expect(parseErrors).toHaveLength(0);
|
|
80
|
-
expect(warnings).toHaveLength(0);
|
|
81
|
-
});
|
|
82
|
-
test('mixed component and component elements in CSS', async () => {
|
|
83
|
-
const {
|
|
84
|
-
// @ts-ignore
|
|
85
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
86
|
-
codeFilename: 'button.css',
|
|
87
|
-
code: '.button, .button__text, .button__icon { color: currentColor; }',
|
|
88
|
-
config: config({}),
|
|
89
|
-
});
|
|
90
|
-
expect(parseErrors).toHaveLength(0);
|
|
91
|
-
expect(warnings).toHaveLength(0);
|
|
92
|
-
});
|
|
93
|
-
test('invalid component naming convention in CSS', async () => {
|
|
94
|
-
const {
|
|
95
|
-
// @ts-ignore
|
|
96
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
97
|
-
codeFilename: 'button.css',
|
|
98
|
-
code: '.card__text { color: currentColor; }',
|
|
99
|
-
config: config({}),
|
|
100
|
-
});
|
|
101
|
-
expect(parseErrors).toHaveLength(0);
|
|
102
|
-
expect(warnings).toStrictEqual([
|
|
103
|
-
{
|
|
104
|
-
column: 1,
|
|
105
|
-
endColumn: 37,
|
|
106
|
-
endLine: 1,
|
|
107
|
-
line: 1,
|
|
108
|
-
rule: '@d-zero/component',
|
|
109
|
-
severity: 'error',
|
|
110
|
-
text: 'クラス名がファイル名と一致しないか、コンポーネント命名規則(button__)で始まっていません',
|
|
111
|
-
url: undefined,
|
|
112
|
-
fix: undefined,
|
|
113
|
-
},
|
|
114
|
-
]);
|
|
115
|
-
});
|
|
116
|
-
test('CSS with wrong component name', async () => {
|
|
117
|
-
const {
|
|
118
|
-
// @ts-ignore
|
|
119
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
120
|
-
codeFilename: 'button.css',
|
|
121
|
-
code: '.card { color: currentColor; }',
|
|
122
|
-
config: config({}),
|
|
123
|
-
});
|
|
124
|
-
expect(parseErrors).toHaveLength(0);
|
|
125
|
-
expect(warnings).toStrictEqual([
|
|
126
|
-
{
|
|
127
|
-
column: 1,
|
|
128
|
-
endColumn: 31,
|
|
129
|
-
endLine: 1,
|
|
130
|
-
line: 1,
|
|
131
|
-
rule: '@d-zero/component',
|
|
132
|
-
severity: 'error',
|
|
133
|
-
text: 'クラス名がファイル名と一致しないか、コンポーネント命名規則(button__)で始まっていません',
|
|
134
|
-
url: undefined,
|
|
135
|
-
fix: undefined,
|
|
136
|
-
},
|
|
137
|
-
]);
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
describe('Partial Name', () => {
|
|
141
|
-
test('match', async () => {
|
|
142
|
-
const {
|
|
143
|
-
// @ts-ignore
|
|
144
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
145
|
-
codeFilename: '_c-component.scss',
|
|
146
|
-
code: '.c-component { color: currentColor; }',
|
|
147
|
-
config: config({}),
|
|
148
|
-
});
|
|
149
|
-
expect(parseErrors).toHaveLength(0);
|
|
150
|
-
expect(warnings).toHaveLength(0);
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
describe('Options', () => {
|
|
154
|
-
test('allowMultipleSelectors: false in SCSS', async () => {
|
|
155
|
-
const {
|
|
156
|
-
// @ts-ignore
|
|
157
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
158
|
-
codeFilename: '_c-component.scss',
|
|
159
|
-
code: '.c-component, .x-specific-class-name { color: currentColor; }',
|
|
160
|
-
config: config({}),
|
|
161
|
-
});
|
|
162
|
-
expect(parseErrors).toHaveLength(0);
|
|
163
|
-
expect(warnings).toHaveLength(1);
|
|
164
|
-
});
|
|
165
|
-
test('allowMultipleSelectors: true in SCSS', async () => {
|
|
166
|
-
const {
|
|
167
|
-
// @ts-ignore
|
|
168
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
169
|
-
codeFilename: '_c-component.scss',
|
|
170
|
-
code: '.c-component, .x-specific-class-name { color: currentColor; }',
|
|
171
|
-
config: config({
|
|
172
|
-
allowMultipleSelectors: true,
|
|
173
|
-
}),
|
|
174
|
-
});
|
|
175
|
-
expect(parseErrors).toHaveLength(0);
|
|
176
|
-
expect(warnings).toHaveLength(0);
|
|
177
|
-
});
|
|
178
|
-
test('CSS files automatically allow multiple selectors', async () => {
|
|
179
|
-
const {
|
|
180
|
-
// @ts-ignore
|
|
181
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
182
|
-
codeFilename: 'button.css',
|
|
183
|
-
code: '.button, .button__text, .button__icon { color: currentColor; }',
|
|
184
|
-
config: config({
|
|
185
|
-
allowMultipleSelectors: false, // この設定は CSS では無視される
|
|
186
|
-
}),
|
|
187
|
-
});
|
|
188
|
-
expect(parseErrors).toHaveLength(0);
|
|
189
|
-
expect(warnings).toHaveLength(0);
|
|
190
|
-
});
|
|
191
|
-
test('CSS files allow multiple rules', async () => {
|
|
192
|
-
const {
|
|
193
|
-
// @ts-ignore
|
|
194
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
195
|
-
codeFilename: 'button.css',
|
|
196
|
-
code: `.button { color: currentColor; }
|
|
197
|
-
.button__text { font-size: 14px; }
|
|
198
|
-
.button__icon { width: 16px; }`,
|
|
199
|
-
config: config({}),
|
|
200
|
-
});
|
|
201
|
-
expect(parseErrors).toHaveLength(0);
|
|
202
|
-
expect(warnings).toHaveLength(0);
|
|
203
|
-
});
|
|
204
|
-
test('CSS files reject multiple components', async () => {
|
|
205
|
-
const {
|
|
206
|
-
// @ts-ignore
|
|
207
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
208
|
-
codeFilename: 'c-component.css',
|
|
209
|
-
code: `.c-component { --prop: value; }
|
|
210
|
-
.c-component__element { --prop: value; }
|
|
211
|
-
.c-component2 { --prop: value; }
|
|
212
|
-
.c-specific { --prop: value; }`,
|
|
213
|
-
config: config({}),
|
|
214
|
-
});
|
|
215
|
-
expect(parseErrors).toHaveLength(0);
|
|
216
|
-
expect(warnings).toHaveLength(2);
|
|
217
|
-
expect(warnings[0].text).toBe('クラス名がファイル名と一致しないか、コンポーネント命名規則(c-component__)で始まっていません');
|
|
218
|
-
expect(warnings[1].text).toBe('クラス名がファイル名と一致しないか、コンポーネント命名規則(c-component__)で始まっていません');
|
|
219
|
-
});
|
|
220
|
-
});
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import stylelint from 'stylelint';
|
|
2
|
-
import { describe, test, expect } from 'vitest';
|
|
3
|
-
import rule from './index.js';
|
|
4
|
-
const { lint } = stylelint;
|
|
5
|
-
const config = (settings = true) => ({
|
|
6
|
-
plugins: [rule],
|
|
7
|
-
rules: {
|
|
8
|
-
// @ts-ignore
|
|
9
|
-
[rule.ruleName]: settings,
|
|
10
|
-
},
|
|
11
|
-
});
|
|
12
|
-
describe('Parse Error', () => {
|
|
13
|
-
test('SCSS Syntax', async () => {
|
|
14
|
-
const {
|
|
15
|
-
// @ts-ignore
|
|
16
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
17
|
-
code: '* { background: url("a" + $b + "c") }',
|
|
18
|
-
config: config({
|
|
19
|
-
length: ['px'],
|
|
20
|
-
}),
|
|
21
|
-
});
|
|
22
|
-
expect(parseErrors).toHaveLength(0);
|
|
23
|
-
expect(warnings).toHaveLength(0);
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
describe('length-pattern', () => {
|
|
27
|
-
test('length in flex', async () => {
|
|
28
|
-
const {
|
|
29
|
-
// @ts-ignore
|
|
30
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
31
|
-
code: '* { flex: 1 1 10px }',
|
|
32
|
-
config: config({
|
|
33
|
-
length: ['/[0-9]{2,}px/'],
|
|
34
|
-
}),
|
|
35
|
-
});
|
|
36
|
-
expect(parseErrors).toHaveLength(0);
|
|
37
|
-
expect(warnings).toStrictEqual([
|
|
38
|
-
{
|
|
39
|
-
rule: '@d-zero/declaration-value-type-disallowed-list',
|
|
40
|
-
severity: 'error',
|
|
41
|
-
line: 1,
|
|
42
|
-
endLine: 1,
|
|
43
|
-
column: 15,
|
|
44
|
-
endColumn: 19,
|
|
45
|
-
text: 'Unexpected value "10px" for type "length" (@d-zero/declaration-value-type-disallowed-list)',
|
|
46
|
-
url: undefined,
|
|
47
|
-
fix: undefined,
|
|
48
|
-
},
|
|
49
|
-
]);
|
|
50
|
-
});
|
|
51
|
-
test('ignoreProperties options', async () => {
|
|
52
|
-
const {
|
|
53
|
-
// @ts-ignore
|
|
54
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
55
|
-
code: '* { flex: 1 1 10px }',
|
|
56
|
-
config: config({
|
|
57
|
-
length: {
|
|
58
|
-
ignoreProperties: ['flex'],
|
|
59
|
-
patterns: ['/[0-9]{2,}px/'],
|
|
60
|
-
},
|
|
61
|
-
}),
|
|
62
|
-
});
|
|
63
|
-
expect(parseErrors).toHaveLength(0);
|
|
64
|
-
expect(warnings).toHaveLength(0);
|
|
65
|
-
});
|
|
66
|
-
});
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import stylelint from 'stylelint';
|
|
2
|
-
import { describe, test, expect } from 'vitest';
|
|
3
|
-
import plugin from './index.js';
|
|
4
|
-
const ruleName = '@d-zero/prefer-individual-transform-properties';
|
|
5
|
-
/**
|
|
6
|
-
* Helper function to run stylelint with the plugin
|
|
7
|
-
* @param code
|
|
8
|
-
* @param options
|
|
9
|
-
*/
|
|
10
|
-
async function lint(code, options) {
|
|
11
|
-
const result = await stylelint.lint({
|
|
12
|
-
code,
|
|
13
|
-
config: {
|
|
14
|
-
plugins: [plugin],
|
|
15
|
-
rules: {
|
|
16
|
-
[ruleName]: options || true,
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
return result.results[0]?.warnings || [];
|
|
21
|
-
}
|
|
22
|
-
describe('prefer-individual-transform-properties', () => {
|
|
23
|
-
test('should flag simple translate function', async () => {
|
|
24
|
-
const warnings = await lint(`
|
|
25
|
-
.element {
|
|
26
|
-
transform: translate(10px, 20px);
|
|
27
|
-
}
|
|
28
|
-
`);
|
|
29
|
-
expect(warnings).toHaveLength(1);
|
|
30
|
-
expect(warnings[0]?.text).toContain('translate: 10px, 20px');
|
|
31
|
-
});
|
|
32
|
-
test('should flag simple rotate function', async () => {
|
|
33
|
-
const warnings = await lint(`
|
|
34
|
-
.element {
|
|
35
|
-
transform: rotate(45deg);
|
|
36
|
-
}
|
|
37
|
-
`);
|
|
38
|
-
expect(warnings).toHaveLength(1);
|
|
39
|
-
expect(warnings[0]?.text).toContain('rotate: 45deg');
|
|
40
|
-
});
|
|
41
|
-
test('should flag simple scale function', async () => {
|
|
42
|
-
const warnings = await lint(`
|
|
43
|
-
.element {
|
|
44
|
-
transform: scale(1.5);
|
|
45
|
-
}
|
|
46
|
-
`);
|
|
47
|
-
expect(warnings).toHaveLength(1);
|
|
48
|
-
expect(warnings[0]?.text).toContain('scale: 1.5');
|
|
49
|
-
});
|
|
50
|
-
test('should flag translateX function', async () => {
|
|
51
|
-
const warnings = await lint(`
|
|
52
|
-
.element {
|
|
53
|
-
transform: translateX(10px);
|
|
54
|
-
}
|
|
55
|
-
`);
|
|
56
|
-
expect(warnings).toHaveLength(1);
|
|
57
|
-
expect(warnings[0]?.text).toContain('translate: 10px');
|
|
58
|
-
});
|
|
59
|
-
test('should flag rotateY function', async () => {
|
|
60
|
-
const warnings = await lint(`
|
|
61
|
-
.element {
|
|
62
|
-
transform: rotateY(90deg);
|
|
63
|
-
}
|
|
64
|
-
`);
|
|
65
|
-
expect(warnings).toHaveLength(1);
|
|
66
|
-
expect(warnings[0]?.text).toContain('rotate: 90deg');
|
|
67
|
-
});
|
|
68
|
-
test('should flag scaleX function', async () => {
|
|
69
|
-
const warnings = await lint(`
|
|
70
|
-
.element {
|
|
71
|
-
transform: scaleX(2);
|
|
72
|
-
}
|
|
73
|
-
`);
|
|
74
|
-
expect(warnings).toHaveLength(1);
|
|
75
|
-
expect(warnings[0]?.text).toContain('scale: 2');
|
|
76
|
-
});
|
|
77
|
-
test('should not flag complex transforms with multiple different functions', async () => {
|
|
78
|
-
const warnings = await lint(`
|
|
79
|
-
.element {
|
|
80
|
-
transform: translate(10px, 20px) rotate(45deg) scale(1.5);
|
|
81
|
-
}
|
|
82
|
-
`);
|
|
83
|
-
// This contains multiple transform types, so it cannot be easily replaced
|
|
84
|
-
expect(warnings).toHaveLength(0);
|
|
85
|
-
});
|
|
86
|
-
test('should not flag transforms with matrix functions', async () => {
|
|
87
|
-
const warnings = await lint(`
|
|
88
|
-
.element {
|
|
89
|
-
transform: matrix(1, 0, 0, 1, 10, 20);
|
|
90
|
-
}
|
|
91
|
-
`);
|
|
92
|
-
expect(warnings).toHaveLength(0);
|
|
93
|
-
});
|
|
94
|
-
test('should not flag transforms with skew functions', async () => {
|
|
95
|
-
const warnings = await lint(`
|
|
96
|
-
.element {
|
|
97
|
-
transform: skew(20deg, 10deg);
|
|
98
|
-
}
|
|
99
|
-
`);
|
|
100
|
-
expect(warnings).toHaveLength(0);
|
|
101
|
-
});
|
|
102
|
-
test('should not flag transforms mixing replaceable and non-replaceable functions', async () => {
|
|
103
|
-
const warnings = await lint(`
|
|
104
|
-
.element {
|
|
105
|
-
transform: translate(10px, 20px) skew(20deg);
|
|
106
|
-
}
|
|
107
|
-
`);
|
|
108
|
-
expect(warnings).toHaveLength(0);
|
|
109
|
-
});
|
|
110
|
-
test('should not flag non-transform properties', async () => {
|
|
111
|
-
const warnings = await lint(`
|
|
112
|
-
.element {
|
|
113
|
-
transition: transform 0.3s ease;
|
|
114
|
-
will-change: transform;
|
|
115
|
-
}
|
|
116
|
-
`);
|
|
117
|
-
expect(warnings).toHaveLength(0);
|
|
118
|
-
});
|
|
119
|
-
test('should handle CSS variables in transform values', async () => {
|
|
120
|
-
const warnings = await lint(`
|
|
121
|
-
.element {
|
|
122
|
-
transform: translate(var(--x), var(--y));
|
|
123
|
-
}
|
|
124
|
-
`);
|
|
125
|
-
expect(warnings).toHaveLength(1);
|
|
126
|
-
expect(warnings[0]?.text).toContain('translate: var(--x), var(--y)');
|
|
127
|
-
});
|
|
128
|
-
test('should handle calc() in transform values', async () => {
|
|
129
|
-
const warnings = await lint(`
|
|
130
|
-
.element {
|
|
131
|
-
transform: translate(calc(100% - 20px), 0);
|
|
132
|
-
}
|
|
133
|
-
`);
|
|
134
|
-
expect(warnings).toHaveLength(1);
|
|
135
|
-
expect(warnings[0]?.text).toContain('translate: calc(100% - 20px), 0');
|
|
136
|
-
});
|
|
137
|
-
});
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import stylelint from 'stylelint';
|
|
2
|
-
import { describe, test, expect } from 'vitest';
|
|
3
|
-
import rule from './index.js';
|
|
4
|
-
const { lint } = stylelint;
|
|
5
|
-
const config = (settings = true) => ({
|
|
6
|
-
plugins: [rule],
|
|
7
|
-
rules: {
|
|
8
|
-
// @ts-ignore
|
|
9
|
-
[rule.ruleName]: settings,
|
|
10
|
-
},
|
|
11
|
-
});
|
|
12
|
-
describe('shorthand-property-use-logical', () => {
|
|
13
|
-
describe('padding', () => {
|
|
14
|
-
test('single value - should not warn', async () => {
|
|
15
|
-
const {
|
|
16
|
-
// @ts-ignore
|
|
17
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
18
|
-
code: '* { padding: 2rem }',
|
|
19
|
-
config: config(),
|
|
20
|
-
});
|
|
21
|
-
expect(parseErrors).toHaveLength(0);
|
|
22
|
-
expect(warnings).toHaveLength(0);
|
|
23
|
-
});
|
|
24
|
-
test('two values - should warn', async () => {
|
|
25
|
-
const {
|
|
26
|
-
// @ts-ignore
|
|
27
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
28
|
-
code: '* { padding: 2rem 1rem }',
|
|
29
|
-
config: config(),
|
|
30
|
-
});
|
|
31
|
-
expect(parseErrors).toHaveLength(0);
|
|
32
|
-
expect(warnings).toStrictEqual([
|
|
33
|
-
{
|
|
34
|
-
rule: '@d-zero/shorthand-property-use-logical',
|
|
35
|
-
severity: 'error',
|
|
36
|
-
line: 1,
|
|
37
|
-
endLine: 1,
|
|
38
|
-
column: 5,
|
|
39
|
-
endColumn: 23,
|
|
40
|
-
text: 'Unexpected shorthand property "padding" with multiple values. Consider using logical properties: padding-block, padding-inline (@d-zero/shorthand-property-use-logical)',
|
|
41
|
-
url: undefined,
|
|
42
|
-
fix: undefined,
|
|
43
|
-
},
|
|
44
|
-
]);
|
|
45
|
-
});
|
|
46
|
-
test('three values - should warn', async () => {
|
|
47
|
-
const {
|
|
48
|
-
// @ts-ignore
|
|
49
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
50
|
-
code: '* { padding: 2rem 0 0 }',
|
|
51
|
-
config: config(),
|
|
52
|
-
});
|
|
53
|
-
expect(parseErrors).toHaveLength(0);
|
|
54
|
-
expect(warnings).toHaveLength(1);
|
|
55
|
-
expect(warnings[0].text).toContain('Unexpected shorthand property "padding"');
|
|
56
|
-
});
|
|
57
|
-
test('four values - should warn', async () => {
|
|
58
|
-
const {
|
|
59
|
-
// @ts-ignore
|
|
60
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
61
|
-
code: '* { padding: 1rem 2rem 3rem 4rem }',
|
|
62
|
-
config: config(),
|
|
63
|
-
});
|
|
64
|
-
expect(parseErrors).toHaveLength(0);
|
|
65
|
-
expect(warnings).toHaveLength(1);
|
|
66
|
-
expect(warnings[0].text).toContain('Unexpected shorthand property "padding"');
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
describe('margin', () => {
|
|
70
|
-
test('single value - should not warn', async () => {
|
|
71
|
-
const {
|
|
72
|
-
// @ts-ignore
|
|
73
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
74
|
-
code: '* { margin: auto }',
|
|
75
|
-
config: config(),
|
|
76
|
-
});
|
|
77
|
-
expect(parseErrors).toHaveLength(0);
|
|
78
|
-
expect(warnings).toHaveLength(0);
|
|
79
|
-
});
|
|
80
|
-
test('two values - should warn', async () => {
|
|
81
|
-
const {
|
|
82
|
-
// @ts-ignore
|
|
83
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
84
|
-
code: '* { margin: 1rem 2rem }',
|
|
85
|
-
config: config(),
|
|
86
|
-
});
|
|
87
|
-
expect(parseErrors).toHaveLength(0);
|
|
88
|
-
expect(warnings).toHaveLength(1);
|
|
89
|
-
expect(warnings[0].text).toContain('margin-block, margin-inline');
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
describe('border-width', () => {
|
|
93
|
-
test('single value - should not warn', async () => {
|
|
94
|
-
const {
|
|
95
|
-
// @ts-ignore
|
|
96
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
97
|
-
code: '* { border-width: 1px }',
|
|
98
|
-
config: config(),
|
|
99
|
-
});
|
|
100
|
-
expect(parseErrors).toHaveLength(0);
|
|
101
|
-
expect(warnings).toHaveLength(0);
|
|
102
|
-
});
|
|
103
|
-
test('multiple values - should warn', async () => {
|
|
104
|
-
const {
|
|
105
|
-
// @ts-ignore
|
|
106
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
107
|
-
code: '* { border-width: 1px 2px }',
|
|
108
|
-
config: config(),
|
|
109
|
-
});
|
|
110
|
-
expect(parseErrors).toHaveLength(0);
|
|
111
|
-
expect(warnings).toHaveLength(1);
|
|
112
|
-
expect(warnings[0].text).toContain('border-block-width, border-inline-width');
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
describe('limited properties configuration', () => {
|
|
116
|
-
test('only check specified properties', async () => {
|
|
117
|
-
const {
|
|
118
|
-
// @ts-ignore
|
|
119
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
120
|
-
code: '* { padding: 1rem 2rem; margin: 1rem 2rem; }',
|
|
121
|
-
config: config({ properties: ['padding'] }),
|
|
122
|
-
});
|
|
123
|
-
expect(parseErrors).toHaveLength(0);
|
|
124
|
-
expect(warnings).toHaveLength(1);
|
|
125
|
-
expect(warnings[0].text).toContain('padding');
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
describe('unsupported properties', () => {
|
|
129
|
-
test('should not check properties not in the list', async () => {
|
|
130
|
-
const {
|
|
131
|
-
// @ts-ignore
|
|
132
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
133
|
-
code: '* { background: url(a.png) no-repeat }',
|
|
134
|
-
config: config(),
|
|
135
|
-
});
|
|
136
|
-
expect(parseErrors).toHaveLength(0);
|
|
137
|
-
expect(warnings).toHaveLength(0);
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
describe('complex values', () => {
|
|
141
|
-
test('calc() function with multiple values', async () => {
|
|
142
|
-
const {
|
|
143
|
-
// @ts-ignore
|
|
144
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
145
|
-
code: '* { padding: calc(1rem + 2px) 1rem }',
|
|
146
|
-
config: config(),
|
|
147
|
-
});
|
|
148
|
-
expect(parseErrors).toHaveLength(0);
|
|
149
|
-
expect(warnings).toHaveLength(1);
|
|
150
|
-
});
|
|
151
|
-
test('var() function with multiple values', async () => {
|
|
152
|
-
const {
|
|
153
|
-
// @ts-ignore
|
|
154
|
-
results: [{ warnings, parseErrors }], } = await lint({
|
|
155
|
-
code: '* { margin: var(--spacing) 2rem }',
|
|
156
|
-
config: config(),
|
|
157
|
-
});
|
|
158
|
-
expect(parseErrors).toHaveLength(0);
|
|
159
|
-
expect(warnings).toHaveLength(1);
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
});
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { parse } from 'postcss';
|
|
2
|
-
import { describe, test, expect } from 'vitest';
|
|
3
|
-
import { getValueType } from './get-value-type.js';
|
|
4
|
-
/**
|
|
5
|
-
*
|
|
6
|
-
* @param css
|
|
7
|
-
*/
|
|
8
|
-
function p(css) {
|
|
9
|
-
const root = parse(css);
|
|
10
|
-
const rule = root.first;
|
|
11
|
-
const decl = rule.first;
|
|
12
|
-
const nodeWithType = getValueType(decl);
|
|
13
|
-
return nodeWithType?.map((node) => node.valueType) ?? null;
|
|
14
|
-
}
|
|
15
|
-
describe('getValueType', () => {
|
|
16
|
-
test('flex', () => {
|
|
17
|
-
expect(p('a { flex: 1 1 calc(var(--foo) * 10vw) }')).toEqual([
|
|
18
|
-
'number',
|
|
19
|
-
'number',
|
|
20
|
-
'length',
|
|
21
|
-
]);
|
|
22
|
-
});
|
|
23
|
-
test('max-width', () => {
|
|
24
|
-
expect(p('a { max-width: 10% }')).toEqual(['length-percentage']);
|
|
25
|
-
});
|
|
26
|
-
test('height vw', () => {
|
|
27
|
-
expect(p('a { height: 100vw }')).toEqual(['length']);
|
|
28
|
-
});
|
|
29
|
-
test('background', () => {
|
|
30
|
-
expect(p('a { background: url(../../img/edit.png) no-repeat scroll 0 0 }')).toEqual([
|
|
31
|
-
'bg-image',
|
|
32
|
-
'repeat-style',
|
|
33
|
-
'attachment',
|
|
34
|
-
'length-percentage',
|
|
35
|
-
'length-percentage',
|
|
36
|
-
]);
|
|
37
|
-
});
|
|
38
|
-
test('SASS Variable', () => {
|
|
39
|
-
expect(p('a { flex: 1 2 $basis }')).toEqual(['number', 'number', '$SASS_VARIABLE']);
|
|
40
|
-
});
|
|
41
|
-
test('SASS Variable Definition', () => {
|
|
42
|
-
expect(p('a { $var: value }')).toEqual(null);
|
|
43
|
-
});
|
|
44
|
-
});
|