@projectwallace/stylelint-plugin 0.1.0 → 0.1.1
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/configs/recommended.d.mts +21 -0
- package/dist/configs/recommended.mjs +21 -0
- package/dist/index.mjs +575 -149
- package/package.json +2 -2
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/configs/recommended.d.ts
|
|
2
|
+
declare const _default: {
|
|
3
|
+
plugins: string[];
|
|
4
|
+
rules: {
|
|
5
|
+
'projectwallace/max-lines-of-code': number;
|
|
6
|
+
'projectwallace/max-selector-complexity': number;
|
|
7
|
+
'projectwallace/no-anonymous-layers': boolean;
|
|
8
|
+
'projectwallace/no-property-browserhacks': boolean;
|
|
9
|
+
'projectwallace/no-static-container-query': boolean;
|
|
10
|
+
'projectwallace/no-static-media-query': boolean;
|
|
11
|
+
'projectwallace/no-undeclared-container-names': boolean;
|
|
12
|
+
'projectwallace/no-unknown-custom-property': boolean;
|
|
13
|
+
'projectwallace/no-unreachable-media-conditions': boolean;
|
|
14
|
+
'projectwallace/no-unused-container-names': boolean;
|
|
15
|
+
'projectwallace/no-unused-custom-properties': boolean;
|
|
16
|
+
'projectwallace/no-unused-layers': boolean;
|
|
17
|
+
'projectwallace/no-useless-custom-property-assignment': boolean;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
export { _default as default };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/configs/recommended.ts
|
|
2
|
+
var recommended_default = {
|
|
3
|
+
plugins: ["@projectwallace/stylelint-plugin"],
|
|
4
|
+
rules: {
|
|
5
|
+
"projectwallace/max-lines-of-code": 1e4,
|
|
6
|
+
"projectwallace/max-selector-complexity": 15,
|
|
7
|
+
"projectwallace/no-anonymous-layers": true,
|
|
8
|
+
"projectwallace/no-property-browserhacks": true,
|
|
9
|
+
"projectwallace/no-static-container-query": true,
|
|
10
|
+
"projectwallace/no-static-media-query": true,
|
|
11
|
+
"projectwallace/no-undeclared-container-names": true,
|
|
12
|
+
"projectwallace/no-unknown-custom-property": true,
|
|
13
|
+
"projectwallace/no-unreachable-media-conditions": true,
|
|
14
|
+
"projectwallace/no-unused-container-names": true,
|
|
15
|
+
"projectwallace/no-unused-custom-properties": true,
|
|
16
|
+
"projectwallace/no-unused-layers": true,
|
|
17
|
+
"projectwallace/no-useless-custom-property-assignment": true
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
export { recommended_default as default };
|
package/dist/index.mjs
CHANGED
|
@@ -1,37 +1,43 @@
|
|
|
1
1
|
import stylelint from "stylelint";
|
|
2
|
-
import {
|
|
3
|
-
import { analyze, selectorComplexity } from "@projectwallace/css-analyzer";
|
|
2
|
+
import { parse_selector } from "@projectwallace/css-parser/parse-selector";
|
|
3
|
+
import { analyze, cssKeywords, selectorComplexity } from "@projectwallace/css-analyzer";
|
|
4
|
+
import { FUNCTION, IDENTIFIER, walk } from "@projectwallace/css-parser";
|
|
5
|
+
import { parse_declaration } from "@projectwallace/css-parser/parse-declaration";
|
|
6
|
+
import { CONTAINER_QUERY, DIMENSION, FEATURE_RANGE, FUNCTION as FUNCTION$1, IDENTIFIER as IDENTIFIER$1, LAYER_NAME, MEDIA_FEATURE, MEDIA_QUERY, NUMBER, OPERATOR, PRELUDE_OPERATOR } from "@projectwallace/css-parser/nodes";
|
|
7
|
+
import { parse_value } from "@projectwallace/css-parser/parse-value";
|
|
8
|
+
import { parse_atrule_prelude } from "@projectwallace/css-parser/parse-atrule-prelude";
|
|
9
|
+
import { BREAK, walk as walk$1 } from "@projectwallace/css-parser/walker";
|
|
4
10
|
//#region src/rules/max-selector-complexity/index.ts
|
|
5
|
-
const { createPlugin: createPlugin$
|
|
6
|
-
const rule_name$
|
|
7
|
-
const messages$
|
|
8
|
-
const meta$
|
|
9
|
-
const ruleFunction$
|
|
11
|
+
const { createPlugin: createPlugin$12, utils: utils$12 } = stylelint;
|
|
12
|
+
const rule_name$12 = "projectwallace/max-selector-complexity";
|
|
13
|
+
const messages$12 = utils$12.ruleMessages(rule_name$12, { rejected: (selector, actual, expected) => `Selector complexity of "${selector}" is ${actual} which is greater than the allowed ${expected}` });
|
|
14
|
+
const meta$12 = { url: "https://github.com/projectwallace/stylelint-plugin/blob/main/src/rules/max-selector-complexity/README.md" };
|
|
15
|
+
const ruleFunction$12 = (primaryOption) => {
|
|
10
16
|
return (root, result) => {
|
|
11
|
-
if (!utils$
|
|
17
|
+
if (!utils$12.validateOptions(result, rule_name$12, {
|
|
12
18
|
actual: primaryOption,
|
|
13
19
|
possible: [Number]
|
|
14
20
|
}) || !Number.isInteger(primaryOption) || primaryOption <= 1) return;
|
|
15
21
|
root.walkRules((rule) => {
|
|
16
|
-
const
|
|
17
|
-
const parsed = parse_selector(
|
|
18
|
-
for (const
|
|
19
|
-
const complexity = selectorComplexity(
|
|
20
|
-
const stringified =
|
|
21
|
-
if (complexity > primaryOption) utils$
|
|
22
|
-
message: messages$
|
|
22
|
+
const selector_list = rule.selector;
|
|
23
|
+
const parsed = parse_selector(selector_list);
|
|
24
|
+
for (const selector of parsed.children) {
|
|
25
|
+
const complexity = selectorComplexity(selector);
|
|
26
|
+
const stringified = selector.text.replace(/\n/g, "");
|
|
27
|
+
if (complexity > primaryOption) utils$12.report({
|
|
28
|
+
message: messages$12.rejected(stringified, complexity, primaryOption),
|
|
23
29
|
node: rule,
|
|
24
30
|
result,
|
|
25
|
-
ruleName: rule_name$
|
|
31
|
+
ruleName: rule_name$12
|
|
26
32
|
});
|
|
27
33
|
}
|
|
28
34
|
});
|
|
29
35
|
};
|
|
30
36
|
};
|
|
31
|
-
ruleFunction$
|
|
32
|
-
ruleFunction$
|
|
33
|
-
ruleFunction$
|
|
34
|
-
var max_selector_complexity_default = createPlugin$
|
|
37
|
+
ruleFunction$12.ruleName = rule_name$12;
|
|
38
|
+
ruleFunction$12.messages = messages$12;
|
|
39
|
+
ruleFunction$12.meta = meta$12;
|
|
40
|
+
var max_selector_complexity_default = createPlugin$12(rule_name$12, ruleFunction$12);
|
|
35
41
|
//#endregion
|
|
36
42
|
//#region src/utils/custom-properties.ts
|
|
37
43
|
function collect_declared_properties(root) {
|
|
@@ -69,13 +75,13 @@ function collect_var_usages(root) {
|
|
|
69
75
|
}
|
|
70
76
|
//#endregion
|
|
71
77
|
//#region src/rules/no-unused-custom-properties/index.ts
|
|
72
|
-
const { createPlugin: createPlugin$
|
|
73
|
-
const rule_name$
|
|
74
|
-
const messages$
|
|
75
|
-
const meta$
|
|
76
|
-
const ruleFunction$
|
|
78
|
+
const { createPlugin: createPlugin$11, utils: utils$11 } = stylelint;
|
|
79
|
+
const rule_name$11 = "projectwallace/no-unused-custom-properties";
|
|
80
|
+
const messages$11 = utils$11.ruleMessages(rule_name$11, { rejected: (property) => `"${property}" was declared but never used in a var()` });
|
|
81
|
+
const meta$11 = { url: "https://github.com/projectwallace/stylelint-plugin/blob/main/src/rules/no-unused-custom-properties/README.md" };
|
|
82
|
+
const ruleFunction$11 = (primaryOptions, secondaryOptions) => {
|
|
77
83
|
return (root, result) => {
|
|
78
|
-
if (!utils$
|
|
84
|
+
if (!utils$11.validateOptions(result, rule_name$11, {
|
|
79
85
|
actual: primaryOptions,
|
|
80
86
|
possible: [true]
|
|
81
87
|
})) return;
|
|
@@ -86,29 +92,29 @@ const ruleFunction$8 = (primaryOptions, secondaryOptions) => {
|
|
|
86
92
|
if (secondaryOptions?.ignoreProperties) {
|
|
87
93
|
if (secondaryOptions.ignoreProperties.some((pattern) => typeof pattern === "string" && pattern === prop || pattern instanceof RegExp && pattern.test(prop))) continue;
|
|
88
94
|
}
|
|
89
|
-
utils$
|
|
95
|
+
utils$11.report({
|
|
90
96
|
result,
|
|
91
|
-
ruleName: rule_name$
|
|
92
|
-
message: messages$
|
|
97
|
+
ruleName: rule_name$11,
|
|
98
|
+
message: messages$11.rejected(prop),
|
|
93
99
|
node,
|
|
94
100
|
word: prop
|
|
95
101
|
});
|
|
96
102
|
}
|
|
97
103
|
};
|
|
98
104
|
};
|
|
99
|
-
ruleFunction$
|
|
100
|
-
ruleFunction$
|
|
101
|
-
ruleFunction$
|
|
102
|
-
var no_unused_custom_properties_default = createPlugin$
|
|
105
|
+
ruleFunction$11.ruleName = rule_name$11;
|
|
106
|
+
ruleFunction$11.messages = messages$11;
|
|
107
|
+
ruleFunction$11.meta = meta$11;
|
|
108
|
+
var no_unused_custom_properties_default = createPlugin$11(rule_name$11, ruleFunction$11);
|
|
103
109
|
//#endregion
|
|
104
110
|
//#region src/rules/no-unknown-custom-property/index.ts
|
|
105
|
-
const { createPlugin: createPlugin$
|
|
106
|
-
const rule_name$
|
|
107
|
-
const messages$
|
|
108
|
-
const meta$
|
|
109
|
-
const ruleFunction$
|
|
111
|
+
const { createPlugin: createPlugin$10, utils: utils$10 } = stylelint;
|
|
112
|
+
const rule_name$10 = "projectwallace/no-unknown-custom-property";
|
|
113
|
+
const messages$10 = utils$10.ruleMessages(rule_name$10, { rejected: (property) => `"${property}" is used in a var() but was never declared` });
|
|
114
|
+
const meta$10 = { url: "https://github.com/projectwallace/stylelint-plugin/blob/main/src/rules/no-unknown-custom-property/README.md" };
|
|
115
|
+
const ruleFunction$10 = (primaryOptions, secondaryOptions) => {
|
|
110
116
|
return (root, result) => {
|
|
111
|
-
if (!utils$
|
|
117
|
+
if (!utils$10.validateOptions(result, rule_name$10, {
|
|
112
118
|
actual: primaryOptions,
|
|
113
119
|
possible: [true]
|
|
114
120
|
})) return;
|
|
@@ -120,81 +126,81 @@ const ruleFunction$7 = (primaryOptions, secondaryOptions) => {
|
|
|
120
126
|
if (secondaryOptions?.allowList) {
|
|
121
127
|
if (secondaryOptions.allowList.some((pattern) => typeof pattern === "string" && pattern === usage.name || pattern instanceof RegExp && pattern.test(usage.name))) continue;
|
|
122
128
|
}
|
|
123
|
-
utils$
|
|
129
|
+
utils$10.report({
|
|
124
130
|
result,
|
|
125
|
-
ruleName: rule_name$
|
|
126
|
-
message: messages$
|
|
131
|
+
ruleName: rule_name$10,
|
|
132
|
+
message: messages$10.rejected(usage.name),
|
|
127
133
|
node: usage.node,
|
|
128
134
|
word: usage.name
|
|
129
135
|
});
|
|
130
136
|
}
|
|
131
137
|
};
|
|
132
138
|
};
|
|
133
|
-
ruleFunction$
|
|
134
|
-
ruleFunction$
|
|
135
|
-
ruleFunction$
|
|
136
|
-
var no_unknown_custom_property_default = createPlugin$
|
|
139
|
+
ruleFunction$10.ruleName = rule_name$10;
|
|
140
|
+
ruleFunction$10.messages = messages$10;
|
|
141
|
+
ruleFunction$10.meta = meta$10;
|
|
142
|
+
var no_unknown_custom_property_default = createPlugin$10(rule_name$10, ruleFunction$10);
|
|
137
143
|
//#endregion
|
|
138
144
|
//#region src/rules/no-property-browserhacks/index.ts
|
|
139
|
-
const { createPlugin: createPlugin$
|
|
140
|
-
const rule_name$
|
|
141
|
-
const messages$
|
|
142
|
-
const meta$
|
|
143
|
-
const ruleFunction$
|
|
145
|
+
const { createPlugin: createPlugin$9, utils: utils$9 } = stylelint;
|
|
146
|
+
const rule_name$9 = "projectwallace/no-property-browserhacks";
|
|
147
|
+
const messages$9 = utils$9.ruleMessages(rule_name$9, { rejected: (property) => `Property "${property}" is a browserhack and is not allowed` });
|
|
148
|
+
const meta$9 = { url: "https://github.com/projectwallace/stylelint-plugin/blob/main/src/rules/no-property-browserhacks/README.md" };
|
|
149
|
+
const ruleFunction$9 = (primaryOption) => {
|
|
144
150
|
return (root, result) => {
|
|
145
|
-
if (!utils$
|
|
151
|
+
if (!utils$9.validateOptions(result, rule_name$9, {
|
|
146
152
|
actual: primaryOption,
|
|
147
153
|
possible: [true]
|
|
148
154
|
})) return;
|
|
149
155
|
root.walkDecls((declaration) => {
|
|
150
156
|
const parsed = parse_declaration(root.source.input.css.substring(declaration.source.start.offset, declaration.source.end.offset));
|
|
151
|
-
if (parsed.is_browserhack) utils$
|
|
152
|
-
message: messages$
|
|
157
|
+
if (parsed.is_browserhack) utils$9.report({
|
|
158
|
+
message: messages$9.rejected(parsed.property),
|
|
153
159
|
node: declaration,
|
|
154
160
|
result,
|
|
155
|
-
ruleName: rule_name$
|
|
161
|
+
ruleName: rule_name$9
|
|
156
162
|
});
|
|
157
163
|
});
|
|
158
164
|
};
|
|
159
165
|
};
|
|
160
|
-
ruleFunction$
|
|
161
|
-
ruleFunction$
|
|
162
|
-
ruleFunction$
|
|
163
|
-
var no_property_browserhacks_default = createPlugin$
|
|
166
|
+
ruleFunction$9.ruleName = rule_name$9;
|
|
167
|
+
ruleFunction$9.messages = messages$9;
|
|
168
|
+
ruleFunction$9.meta = meta$9;
|
|
169
|
+
var no_property_browserhacks_default = createPlugin$9(rule_name$9, ruleFunction$9);
|
|
164
170
|
//#endregion
|
|
165
171
|
//#region src/rules/max-lines-of-code/index.ts
|
|
166
|
-
const { createPlugin: createPlugin$
|
|
167
|
-
const rule_name$
|
|
168
|
-
const messages$
|
|
169
|
-
const meta$
|
|
170
|
-
const ruleFunction$
|
|
172
|
+
const { createPlugin: createPlugin$8, utils: utils$8 } = stylelint;
|
|
173
|
+
const rule_name$8 = "projectwallace/max-lines-of-code";
|
|
174
|
+
const messages$8 = utils$8.ruleMessages(rule_name$8, { rejected: (actual, expected) => `Counted ${actual} Lines of Code which is greater than the allowed ${expected}` });
|
|
175
|
+
const meta$8 = { url: "https://github.com/projectwallace/stylelint-plugin/blob/main/src/rules/max-lines-of-code/README.md" };
|
|
176
|
+
const ruleFunction$8 = (primaryOption) => {
|
|
171
177
|
return (root, result) => {
|
|
172
|
-
if (!utils$
|
|
178
|
+
if (!utils$8.validateOptions(result, rule_name$8, {
|
|
173
179
|
actual: primaryOption,
|
|
174
180
|
possible: [Number]
|
|
175
181
|
}) || !Number.isInteger(primaryOption) || primaryOption <= 0) return;
|
|
176
182
|
const actual = analyze(root.source.input.css).stylesheet.sourceLinesOfCode;
|
|
177
|
-
if (actual > primaryOption) utils$
|
|
178
|
-
message: messages$
|
|
183
|
+
if (actual > primaryOption) utils$8.report({
|
|
184
|
+
message: messages$8.rejected(actual, primaryOption),
|
|
179
185
|
node: root,
|
|
180
186
|
result,
|
|
181
|
-
ruleName: rule_name$
|
|
187
|
+
ruleName: rule_name$8
|
|
182
188
|
});
|
|
183
189
|
};
|
|
184
190
|
};
|
|
185
|
-
ruleFunction$
|
|
186
|
-
ruleFunction$
|
|
187
|
-
ruleFunction$
|
|
188
|
-
var max_lines_of_code_default = createPlugin$
|
|
191
|
+
ruleFunction$8.ruleName = rule_name$8;
|
|
192
|
+
ruleFunction$8.messages = messages$8;
|
|
193
|
+
ruleFunction$8.meta = meta$8;
|
|
194
|
+
var max_lines_of_code_default = createPlugin$8(rule_name$8, ruleFunction$8);
|
|
189
195
|
//#endregion
|
|
190
196
|
//#region src/rules/no-unused-layers/index.ts
|
|
191
|
-
const { createPlugin: createPlugin$
|
|
192
|
-
const rule_name$
|
|
193
|
-
const messages$
|
|
194
|
-
const meta$
|
|
195
|
-
const ruleFunction$
|
|
197
|
+
const { createPlugin: createPlugin$7, utils: utils$7 } = stylelint;
|
|
198
|
+
const rule_name$7 = "projectwallace/no-unused-layers";
|
|
199
|
+
const messages$7 = utils$7.ruleMessages(rule_name$7, { rejected: (layer) => `Layer "${layer}" was declared but never defined` });
|
|
200
|
+
const meta$7 = { url: "https://github.com/projectwallace/stylelint-plugin/blob/main/src/rules/no-unused-layers/README.md" };
|
|
201
|
+
const ruleFunction$7 = (primaryOptions, secondaryOptions) => {
|
|
196
202
|
return (root, result) => {
|
|
197
|
-
if (!utils$
|
|
203
|
+
if (!utils$7.validateOptions(result, rule_name$7, {
|
|
198
204
|
actual: primaryOptions,
|
|
199
205
|
possible: [true]
|
|
200
206
|
})) return;
|
|
@@ -214,33 +220,35 @@ const ruleFunction$4 = (primaryOptions, secondaryOptions) => {
|
|
|
214
220
|
if (secondaryOptions?.allowlist) {
|
|
215
221
|
if (secondaryOptions.allowlist.some((pattern) => typeof pattern === "string" && pattern === layer || pattern instanceof RegExp && pattern.test(layer))) continue;
|
|
216
222
|
}
|
|
217
|
-
utils$
|
|
223
|
+
utils$7.report({
|
|
218
224
|
result,
|
|
219
|
-
ruleName: rule_name$
|
|
220
|
-
message: messages$
|
|
225
|
+
ruleName: rule_name$7,
|
|
226
|
+
message: messages$7.rejected(layer),
|
|
221
227
|
node,
|
|
222
228
|
word: layer
|
|
223
229
|
});
|
|
224
230
|
}
|
|
225
231
|
};
|
|
226
232
|
};
|
|
227
|
-
ruleFunction$
|
|
228
|
-
ruleFunction$
|
|
229
|
-
ruleFunction$
|
|
230
|
-
var no_unused_layers_default = createPlugin$
|
|
233
|
+
ruleFunction$7.ruleName = rule_name$7;
|
|
234
|
+
ruleFunction$7.messages = messages$7;
|
|
235
|
+
ruleFunction$7.meta = meta$7;
|
|
236
|
+
var no_unused_layers_default = createPlugin$7(rule_name$7, ruleFunction$7);
|
|
231
237
|
//#endregion
|
|
232
238
|
//#region src/utils/container-names.ts
|
|
233
239
|
function collect_declared_container_names(root) {
|
|
234
240
|
const names = /* @__PURE__ */ new Map();
|
|
235
241
|
root.walkDecls(/^container(-name)?$/i, (decl) => {
|
|
236
242
|
let value = decl.value.trim();
|
|
237
|
-
if (
|
|
238
|
-
|
|
239
|
-
|
|
243
|
+
if (cssKeywords.has(value)) return;
|
|
244
|
+
const ast = parse_value(value);
|
|
245
|
+
for (const node of ast) {
|
|
246
|
+
if (node.type === OPERATOR) break;
|
|
247
|
+
if (node.type === IDENTIFIER$1) {
|
|
248
|
+
const name = node.text;
|
|
249
|
+
if (!names.has(name)) names.set(name, decl);
|
|
250
|
+
}
|
|
240
251
|
}
|
|
241
|
-
if (value.toLowerCase() === "none") return;
|
|
242
|
-
const name_list = value.split(/\s+/).filter(Boolean);
|
|
243
|
-
for (const name of name_list) if (!names.has(name)) names.set(name, decl);
|
|
244
252
|
});
|
|
245
253
|
return names;
|
|
246
254
|
}
|
|
@@ -259,13 +267,13 @@ function collect_container_name_usages(root) {
|
|
|
259
267
|
}
|
|
260
268
|
//#endregion
|
|
261
269
|
//#region src/rules/no-unused-container-names/index.ts
|
|
262
|
-
const { createPlugin: createPlugin$
|
|
263
|
-
const rule_name$
|
|
264
|
-
const messages$
|
|
265
|
-
const meta$
|
|
266
|
-
const ruleFunction$
|
|
270
|
+
const { createPlugin: createPlugin$6, utils: utils$6 } = stylelint;
|
|
271
|
+
const rule_name$6 = "projectwallace/no-unused-container-names";
|
|
272
|
+
const messages$6 = utils$6.ruleMessages(rule_name$6, { rejected: (name) => `Container name "${name}" was declared but never used in a @container query` });
|
|
273
|
+
const meta$6 = { url: "https://github.com/projectwallace/stylelint-plugin/blob/main/src/rules/no-unused-container-names/README.md" };
|
|
274
|
+
const ruleFunction$6 = (primaryOptions, secondaryOptions) => {
|
|
267
275
|
return (root, result) => {
|
|
268
|
-
if (!utils$
|
|
276
|
+
if (!utils$6.validateOptions(result, rule_name$6, {
|
|
269
277
|
actual: primaryOptions,
|
|
270
278
|
possible: [true]
|
|
271
279
|
})) return;
|
|
@@ -276,29 +284,29 @@ const ruleFunction$3 = (primaryOptions, secondaryOptions) => {
|
|
|
276
284
|
if (secondaryOptions?.allowList) {
|
|
277
285
|
if (secondaryOptions.allowList.some((pattern) => typeof pattern === "string" && pattern === name || pattern instanceof RegExp && pattern.test(name))) continue;
|
|
278
286
|
}
|
|
279
|
-
utils$
|
|
287
|
+
utils$6.report({
|
|
280
288
|
result,
|
|
281
|
-
ruleName: rule_name$
|
|
282
|
-
message: messages$
|
|
289
|
+
ruleName: rule_name$6,
|
|
290
|
+
message: messages$6.rejected(name),
|
|
283
291
|
node,
|
|
284
292
|
word: name
|
|
285
293
|
});
|
|
286
294
|
}
|
|
287
295
|
};
|
|
288
296
|
};
|
|
289
|
-
ruleFunction$
|
|
290
|
-
ruleFunction$
|
|
291
|
-
ruleFunction$
|
|
292
|
-
var no_unused_container_names_default = createPlugin$
|
|
297
|
+
ruleFunction$6.ruleName = rule_name$6;
|
|
298
|
+
ruleFunction$6.messages = messages$6;
|
|
299
|
+
ruleFunction$6.meta = meta$6;
|
|
300
|
+
var no_unused_container_names_default = createPlugin$6(rule_name$6, ruleFunction$6);
|
|
293
301
|
//#endregion
|
|
294
302
|
//#region src/rules/no-undeclared-container-names/index.ts
|
|
295
|
-
const { createPlugin: createPlugin$
|
|
296
|
-
const rule_name$
|
|
297
|
-
const messages$
|
|
298
|
-
const meta$
|
|
299
|
-
const ruleFunction$
|
|
303
|
+
const { createPlugin: createPlugin$5, utils: utils$5 } = stylelint;
|
|
304
|
+
const rule_name$5 = "projectwallace/no-undeclared-container-names";
|
|
305
|
+
const messages$5 = utils$5.ruleMessages(rule_name$5, { rejected: (name) => `Container name "${name}" is used in a @container query but was never declared` });
|
|
306
|
+
const meta$5 = { url: "https://github.com/projectwallace/stylelint-plugin/blob/main/src/rules/no-undeclared-container-names/README.md" };
|
|
307
|
+
const ruleFunction$5 = (primaryOptions, secondaryOptions) => {
|
|
300
308
|
return (root, result) => {
|
|
301
|
-
if (!utils$
|
|
309
|
+
if (!utils$5.validateOptions(result, rule_name$5, {
|
|
302
310
|
actual: primaryOptions,
|
|
303
311
|
possible: [true]
|
|
304
312
|
})) return;
|
|
@@ -309,96 +317,511 @@ const ruleFunction$2 = (primaryOptions, secondaryOptions) => {
|
|
|
309
317
|
if (secondaryOptions?.allowList) {
|
|
310
318
|
if (secondaryOptions.allowList.some((pattern) => typeof pattern === "string" && pattern === usage.name || pattern instanceof RegExp && pattern.test(usage.name))) continue;
|
|
311
319
|
}
|
|
312
|
-
utils$
|
|
320
|
+
utils$5.report({
|
|
313
321
|
result,
|
|
314
|
-
ruleName: rule_name$
|
|
315
|
-
message: messages$
|
|
322
|
+
ruleName: rule_name$5,
|
|
323
|
+
message: messages$5.rejected(usage.name),
|
|
316
324
|
node: usage.node,
|
|
317
325
|
word: usage.name
|
|
318
326
|
});
|
|
319
327
|
}
|
|
320
328
|
};
|
|
321
329
|
};
|
|
322
|
-
ruleFunction$
|
|
323
|
-
ruleFunction$
|
|
324
|
-
ruleFunction$
|
|
325
|
-
var no_undeclared_container_names_default = createPlugin$
|
|
330
|
+
ruleFunction$5.ruleName = rule_name$5;
|
|
331
|
+
ruleFunction$5.messages = messages$5;
|
|
332
|
+
ruleFunction$5.meta = meta$5;
|
|
333
|
+
var no_undeclared_container_names_default = createPlugin$5(rule_name$5, ruleFunction$5);
|
|
326
334
|
//#endregion
|
|
327
335
|
//#region src/rules/no-anonymous-layers/index.ts
|
|
328
|
-
const { createPlugin: createPlugin$
|
|
329
|
-
const rule_name$
|
|
330
|
-
const messages$
|
|
331
|
-
const meta$
|
|
332
|
-
const ruleFunction$
|
|
336
|
+
const { createPlugin: createPlugin$4, utils: utils$4 } = stylelint;
|
|
337
|
+
const rule_name$4 = "projectwallace/no-anonymous-layers";
|
|
338
|
+
const messages$4 = utils$4.ruleMessages(rule_name$4, { rejected: () => `Anonymous @layer is not allowed` });
|
|
339
|
+
const meta$4 = { url: "https://github.com/projectwallace/stylelint-plugin/blob/main/src/rules/no-anonymous-layers/README.md" };
|
|
340
|
+
const ruleFunction$4 = (primaryOptions) => {
|
|
333
341
|
return (root, result) => {
|
|
334
|
-
if (!utils$
|
|
342
|
+
if (!utils$4.validateOptions(result, rule_name$4, {
|
|
335
343
|
actual: primaryOptions,
|
|
336
344
|
possible: [true]
|
|
337
345
|
})) return;
|
|
338
346
|
root.walkAtRules("layer", (atRule) => {
|
|
339
|
-
if (atRule.nodes !== void 0 && atRule.params.trim() === "") utils$
|
|
347
|
+
if (atRule.nodes !== void 0 && atRule.params.trim() === "") utils$4.report({
|
|
340
348
|
result,
|
|
341
|
-
ruleName: rule_name$
|
|
342
|
-
message: messages$
|
|
349
|
+
ruleName: rule_name$4,
|
|
350
|
+
message: messages$4.rejected(),
|
|
343
351
|
node: atRule,
|
|
344
352
|
word: "@layer"
|
|
345
353
|
});
|
|
346
354
|
});
|
|
347
355
|
root.walkAtRules("import", (atRule) => {
|
|
348
356
|
const params = atRule.params;
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
utils$1.report({
|
|
357
|
+
const ast = parse_atrule_prelude("import", params);
|
|
358
|
+
for (const node of ast) if (node.type === LAYER_NAME && !node.name) utils$4.report({
|
|
352
359
|
result,
|
|
353
|
-
ruleName: rule_name$
|
|
354
|
-
message: messages$
|
|
360
|
+
ruleName: rule_name$4,
|
|
361
|
+
message: messages$4.rejected(),
|
|
355
362
|
node: atRule,
|
|
356
363
|
word: "layer"
|
|
357
364
|
});
|
|
358
365
|
});
|
|
359
366
|
};
|
|
360
367
|
};
|
|
361
|
-
ruleFunction$
|
|
362
|
-
ruleFunction$
|
|
363
|
-
ruleFunction$
|
|
364
|
-
var no_anonymous_layers_default = createPlugin$
|
|
368
|
+
ruleFunction$4.ruleName = rule_name$4;
|
|
369
|
+
ruleFunction$4.messages = messages$4;
|
|
370
|
+
ruleFunction$4.meta = meta$4;
|
|
371
|
+
var no_anonymous_layers_default = createPlugin$4(rule_name$4, ruleFunction$4);
|
|
365
372
|
//#endregion
|
|
366
373
|
//#region src/rules/no-useless-custom-property-assignment/index.ts
|
|
367
|
-
const { createPlugin, utils } = stylelint;
|
|
368
|
-
const rule_name = "
|
|
369
|
-
const messages = utils.ruleMessages(rule_name, { rejected: (property) => `"${property}" is assigned to itself via var(), which has no effect` });
|
|
370
|
-
const meta = { url: "https://github.com/projectwallace/stylelint-
|
|
371
|
-
const ruleFunction = (primaryOptions, secondaryOptions) => {
|
|
374
|
+
const { createPlugin: createPlugin$3, utils: utils$3 } = stylelint;
|
|
375
|
+
const rule_name$3 = "projectwallace/no-useless-custom-property-assignment";
|
|
376
|
+
const messages$3 = utils$3.ruleMessages(rule_name$3, { rejected: (property) => `"${property}" is assigned to itself via var(), which has no effect` });
|
|
377
|
+
const meta$3 = { url: "https://github.com/projectwallace/stylelint-plugin/blob/main/src/rules/no-useless-custom-property-assignment/README.md" };
|
|
378
|
+
const ruleFunction$3 = (primaryOptions, secondaryOptions) => {
|
|
372
379
|
return (root, result) => {
|
|
373
|
-
if (!utils.validateOptions(result, rule_name, {
|
|
380
|
+
if (!utils$3.validateOptions(result, rule_name$3, {
|
|
374
381
|
actual: primaryOptions,
|
|
375
382
|
possible: [true]
|
|
376
383
|
})) return;
|
|
377
384
|
root.walkDecls(function(declaration) {
|
|
385
|
+
if (!declaration.variable) return;
|
|
378
386
|
const prop = declaration.prop;
|
|
379
|
-
if (!prop.startsWith("--")) return;
|
|
380
387
|
if (secondaryOptions?.allowList) {
|
|
381
388
|
if (secondaryOptions.allowList.some((pattern) => typeof pattern === "string" && pattern === prop || pattern instanceof RegExp && pattern.test(prop))) return;
|
|
382
389
|
}
|
|
383
390
|
const parsed = parse_declaration(root.source.input.css.substring(declaration.source.start.offset, declaration.source.end.offset));
|
|
384
391
|
let reported = false;
|
|
385
|
-
walk(parsed, (node) => {
|
|
392
|
+
walk$1(parsed, (node) => {
|
|
386
393
|
if (reported) return;
|
|
387
|
-
if (node.type !== FUNCTION || node.name !== "var") return;
|
|
394
|
+
if (node.type !== FUNCTION$1 || node.name !== "var") return;
|
|
388
395
|
for (const child of node.children) {
|
|
389
|
-
if (child.type === IDENTIFIER && child.text === prop) {
|
|
390
|
-
utils.report({
|
|
396
|
+
if (child.type === IDENTIFIER$1 && child.text === prop) {
|
|
397
|
+
utils$3.report({
|
|
391
398
|
result,
|
|
392
|
-
ruleName: rule_name,
|
|
393
|
-
message: messages.rejected(prop),
|
|
399
|
+
ruleName: rule_name$3,
|
|
400
|
+
message: messages$3.rejected(prop),
|
|
394
401
|
node: declaration,
|
|
395
402
|
word: prop
|
|
396
403
|
});
|
|
397
404
|
reported = true;
|
|
398
405
|
return;
|
|
399
406
|
}
|
|
400
|
-
if (child.type === IDENTIFIER && child.text.startsWith("--")) break;
|
|
407
|
+
if (child.type === IDENTIFIER$1 && child.text.startsWith("--")) break;
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
};
|
|
412
|
+
};
|
|
413
|
+
ruleFunction$3.ruleName = rule_name$3;
|
|
414
|
+
ruleFunction$3.messages = messages$3;
|
|
415
|
+
ruleFunction$3.meta = meta$3;
|
|
416
|
+
var no_useless_custom_property_assignment_default = createPlugin$3(rule_name$3, ruleFunction$3);
|
|
417
|
+
//#endregion
|
|
418
|
+
//#region src/utils/media-conditions.ts
|
|
419
|
+
/**
|
|
420
|
+
* Extract bounds from an old-style MEDIA_FEATURE node like (min-width: 1000px) or (width: 300px).
|
|
421
|
+
* For min-/max- prefixed features, returns a single bound.
|
|
422
|
+
* For unprefixed features with a numeric value (equality syntax like `width: 300px`),
|
|
423
|
+
* returns two bounds — one lower and one upper at the same value, both inclusive —
|
|
424
|
+
* making them compatible with find_contradictory_feature.
|
|
425
|
+
* Returns an empty array if the feature is not a numeric range-style feature.
|
|
426
|
+
*/
|
|
427
|
+
function collect_bound_from_media_feature(node) {
|
|
428
|
+
if (node.type !== MEDIA_FEATURE) return [];
|
|
429
|
+
const property = node.property;
|
|
430
|
+
if (!property) return [];
|
|
431
|
+
let direction;
|
|
432
|
+
let feature;
|
|
433
|
+
if (property.startsWith("min-")) {
|
|
434
|
+
direction = "lower";
|
|
435
|
+
feature = property.slice(4);
|
|
436
|
+
} else if (property.startsWith("max-")) {
|
|
437
|
+
direction = "upper";
|
|
438
|
+
feature = property.slice(4);
|
|
439
|
+
} else {
|
|
440
|
+
direction = "both";
|
|
441
|
+
feature = property;
|
|
442
|
+
}
|
|
443
|
+
for (const child of node.children) if (child.type === DIMENSION || child.type === NUMBER) {
|
|
444
|
+
const value = child.value_as_number;
|
|
445
|
+
const unit = child.unit ?? "";
|
|
446
|
+
if (value == null || Number.isNaN(value)) return [];
|
|
447
|
+
if (direction === "both") return [{
|
|
448
|
+
feature,
|
|
449
|
+
value,
|
|
450
|
+
unit,
|
|
451
|
+
inclusive: true,
|
|
452
|
+
direction: "lower"
|
|
453
|
+
}, {
|
|
454
|
+
feature,
|
|
455
|
+
value,
|
|
456
|
+
unit,
|
|
457
|
+
inclusive: true,
|
|
458
|
+
direction: "upper"
|
|
459
|
+
}];
|
|
460
|
+
return [{
|
|
461
|
+
feature,
|
|
462
|
+
value,
|
|
463
|
+
unit,
|
|
464
|
+
inclusive: true,
|
|
465
|
+
direction
|
|
466
|
+
}];
|
|
467
|
+
}
|
|
468
|
+
return [];
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Extract bounds from a FEATURE_RANGE node like (width > 1000px) or (50px <= width <= 100px).
|
|
472
|
+
* Returns an array of bounds (0, 1, or 2 items), each tagged with the feature name.
|
|
473
|
+
*/
|
|
474
|
+
function collect_bounds_from_feature_range(node) {
|
|
475
|
+
if (node.type !== FEATURE_RANGE) return [];
|
|
476
|
+
const feature = node.name;
|
|
477
|
+
if (!feature) return [];
|
|
478
|
+
const children = node.children;
|
|
479
|
+
if (children.length === 0) return [];
|
|
480
|
+
const bounds = [];
|
|
481
|
+
const is_value_node = (n) => n.type === DIMENSION || n.type === NUMBER;
|
|
482
|
+
if (children.length >= 2 && children[0].type === PRELUDE_OPERATOR && is_value_node(children[1])) {
|
|
483
|
+
const operator = children[0].text.trim();
|
|
484
|
+
const dimension = children[1];
|
|
485
|
+
const value = dimension.value_as_number;
|
|
486
|
+
const unit = dimension.unit ?? "";
|
|
487
|
+
if (value != null && !Number.isNaN(value)) {
|
|
488
|
+
const bound = operator_to_bound(operator, value, unit, "feature_left");
|
|
489
|
+
if (bound) bounds.push({
|
|
490
|
+
...bound,
|
|
491
|
+
feature
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
} else if (children.length >= 4 && is_value_node(children[0]) && children[1].type === PRELUDE_OPERATOR && children[2].type === PRELUDE_OPERATOR && is_value_node(children[3])) {
|
|
495
|
+
const dimension1 = children[0];
|
|
496
|
+
const operator1 = children[1].text.trim();
|
|
497
|
+
const operator2 = children[2].text.trim();
|
|
498
|
+
const dimension2 = children[3];
|
|
499
|
+
const value1 = dimension1.value_as_number;
|
|
500
|
+
const unit1 = dimension1.unit ?? "";
|
|
501
|
+
const value2 = dimension2.value_as_number;
|
|
502
|
+
const unit2 = dimension2.unit ?? "";
|
|
503
|
+
if (value1 != null && !Number.isNaN(value1)) {
|
|
504
|
+
const bound = operator_to_bound(operator1, value1, unit1, "feature_right");
|
|
505
|
+
if (bound) bounds.push({
|
|
506
|
+
...bound,
|
|
507
|
+
feature
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
if (value2 != null && !Number.isNaN(value2)) {
|
|
511
|
+
const bound = operator_to_bound(operator2, value2, unit2, "feature_left");
|
|
512
|
+
if (bound) bounds.push({
|
|
513
|
+
...bound,
|
|
514
|
+
feature
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return bounds;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Convert an operator and dimension to a Bound, given whether the feature
|
|
522
|
+
* is on the left or right side of the operator.
|
|
523
|
+
*
|
|
524
|
+
* feature_left: feature OP value e.g. width >= 400px
|
|
525
|
+
* feature_right: value OP feature e.g. 400px <= width
|
|
526
|
+
*
|
|
527
|
+
* Returns null for operators that don't express a range bound (e.g. =).
|
|
528
|
+
*/
|
|
529
|
+
function operator_to_bound(operator, value, unit, side) {
|
|
530
|
+
if (side === "feature_left") {
|
|
531
|
+
if (operator === ">") return {
|
|
532
|
+
value,
|
|
533
|
+
unit,
|
|
534
|
+
inclusive: false,
|
|
535
|
+
direction: "lower"
|
|
536
|
+
};
|
|
537
|
+
if (operator === ">=") return {
|
|
538
|
+
value,
|
|
539
|
+
unit,
|
|
540
|
+
inclusive: true,
|
|
541
|
+
direction: "lower"
|
|
542
|
+
};
|
|
543
|
+
if (operator === "<") return {
|
|
544
|
+
value,
|
|
545
|
+
unit,
|
|
546
|
+
inclusive: false,
|
|
547
|
+
direction: "upper"
|
|
548
|
+
};
|
|
549
|
+
if (operator === "<=") return {
|
|
550
|
+
value,
|
|
551
|
+
unit,
|
|
552
|
+
inclusive: true,
|
|
553
|
+
direction: "upper"
|
|
554
|
+
};
|
|
555
|
+
} else {
|
|
556
|
+
if (operator === "<") return {
|
|
557
|
+
value,
|
|
558
|
+
unit,
|
|
559
|
+
inclusive: false,
|
|
560
|
+
direction: "lower"
|
|
561
|
+
};
|
|
562
|
+
if (operator === "<=") return {
|
|
563
|
+
value,
|
|
564
|
+
unit,
|
|
565
|
+
inclusive: true,
|
|
566
|
+
direction: "lower"
|
|
567
|
+
};
|
|
568
|
+
if (operator === ">") return {
|
|
569
|
+
value,
|
|
570
|
+
unit,
|
|
571
|
+
inclusive: false,
|
|
572
|
+
direction: "upper"
|
|
573
|
+
};
|
|
574
|
+
if (operator === ">=") return {
|
|
575
|
+
value,
|
|
576
|
+
unit,
|
|
577
|
+
inclusive: true,
|
|
578
|
+
direction: "upper"
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
return null;
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Given a list of bounds for potentially multiple features, check whether any
|
|
585
|
+
* feature's combined constraints are contradictory (impossible to satisfy).
|
|
586
|
+
*
|
|
587
|
+
* Bounds with different units are only compared within the same unit.
|
|
588
|
+
* Returns the name of the first contradictory feature, or null if no contradiction found.
|
|
589
|
+
*/
|
|
590
|
+
function find_contradictory_feature(bounds) {
|
|
591
|
+
const by_feature = /* @__PURE__ */ new Map();
|
|
592
|
+
for (const bound of bounds) {
|
|
593
|
+
const existing = by_feature.get(bound.feature) ?? [];
|
|
594
|
+
existing.push(bound);
|
|
595
|
+
by_feature.set(bound.feature, existing);
|
|
596
|
+
}
|
|
597
|
+
for (const [feature, feature_bounds] of by_feature) {
|
|
598
|
+
const lower_bounds = feature_bounds.filter((b) => b.direction === "lower");
|
|
599
|
+
const upper_bounds = feature_bounds.filter((b) => b.direction === "upper");
|
|
600
|
+
if (lower_bounds.length === 0 || upper_bounds.length === 0) continue;
|
|
601
|
+
const lower_units = new Set(lower_bounds.map((b) => b.unit));
|
|
602
|
+
for (const unit of lower_units) {
|
|
603
|
+
const uppers_same_unit = upper_bounds.filter((b) => b.unit === unit);
|
|
604
|
+
if (uppers_same_unit.length === 0) continue;
|
|
605
|
+
const max_lower = lower_bounds.filter((b) => b.unit === unit).reduce((a, b) => {
|
|
606
|
+
if (b.value > a.value) return b;
|
|
607
|
+
if (b.value === a.value && !b.inclusive && a.inclusive) return b;
|
|
608
|
+
return a;
|
|
609
|
+
});
|
|
610
|
+
const min_upper = uppers_same_unit.reduce((a, b) => {
|
|
611
|
+
if (b.value < a.value) return b;
|
|
612
|
+
if (b.value === a.value && !b.inclusive && a.inclusive) return b;
|
|
613
|
+
return a;
|
|
614
|
+
});
|
|
615
|
+
if (max_lower.value > min_upper.value) return feature;
|
|
616
|
+
if (max_lower.value === min_upper.value && (!max_lower.inclusive || !min_upper.inclusive)) return feature;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
return null;
|
|
620
|
+
}
|
|
621
|
+
//#endregion
|
|
622
|
+
//#region src/rules/no-unreachable-media-conditions/index.ts
|
|
623
|
+
const { createPlugin: createPlugin$2, utils: utils$2 } = stylelint;
|
|
624
|
+
const rule_name$2 = "projectwallace/no-unreachable-media-conditions";
|
|
625
|
+
const messages$2 = utils$2.ruleMessages(rule_name$2, { rejected: (feature) => `Media feature "${feature}" creates an unreachable condition` });
|
|
626
|
+
const meta$2 = { url: "https://github.com/projectwallace/stylelint-plugin/blob/main/src/rules/no-unreachable-media-conditions/README.md" };
|
|
627
|
+
/**
|
|
628
|
+
* Parse an at-rule prelude and return the first contradictory feature name,
|
|
629
|
+
* or null if all media conditions are satisfiable.
|
|
630
|
+
*/
|
|
631
|
+
function find_contradiction_in_prelude(at_rule_name, prelude) {
|
|
632
|
+
const parsed = parse_atrule_prelude(at_rule_name, prelude);
|
|
633
|
+
for (const query_node of parsed) {
|
|
634
|
+
if (query_node.type !== MEDIA_QUERY) continue;
|
|
635
|
+
let skip = false;
|
|
636
|
+
walk$1(query_node, (node) => {
|
|
637
|
+
if (node.type === PRELUDE_OPERATOR) {
|
|
638
|
+
const operator = node.text.trim().toLowerCase();
|
|
639
|
+
if (operator === "not" || operator === "or") {
|
|
640
|
+
skip = true;
|
|
641
|
+
return BREAK;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
if (skip) continue;
|
|
646
|
+
const bounds = [];
|
|
647
|
+
walk$1(query_node, (node) => {
|
|
648
|
+
if (node.type === MEDIA_FEATURE) bounds.push(...collect_bound_from_media_feature(node));
|
|
649
|
+
else if (node.type === FEATURE_RANGE) bounds.push(...collect_bounds_from_feature_range(node));
|
|
650
|
+
});
|
|
651
|
+
const contradictory_feature = find_contradictory_feature(bounds);
|
|
652
|
+
if (contradictory_feature !== null) return contradictory_feature;
|
|
653
|
+
}
|
|
654
|
+
return null;
|
|
655
|
+
}
|
|
656
|
+
function check_at_rule$1(at_rule_name, atRule, result) {
|
|
657
|
+
const prelude = atRule.params;
|
|
658
|
+
if (!prelude) return;
|
|
659
|
+
const contradictory_feature = find_contradiction_in_prelude(at_rule_name, prelude);
|
|
660
|
+
if (contradictory_feature !== null) utils$2.report({
|
|
661
|
+
message: messages$2.rejected(contradictory_feature),
|
|
662
|
+
node: atRule,
|
|
663
|
+
result,
|
|
664
|
+
ruleName: rule_name$2
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
const ruleFunction$2 = (primaryOption) => {
|
|
668
|
+
return (root, result) => {
|
|
669
|
+
if (!utils$2.validateOptions(result, rule_name$2, {
|
|
670
|
+
actual: primaryOption,
|
|
671
|
+
possible: [true]
|
|
672
|
+
})) return;
|
|
673
|
+
root.walkAtRules("media", (atRule) => {
|
|
674
|
+
check_at_rule$1("media", atRule, result);
|
|
675
|
+
});
|
|
676
|
+
root.walkAtRules("import", (atRule) => {
|
|
677
|
+
check_at_rule$1("import", atRule, result);
|
|
678
|
+
});
|
|
679
|
+
};
|
|
680
|
+
};
|
|
681
|
+
ruleFunction$2.ruleName = rule_name$2;
|
|
682
|
+
ruleFunction$2.messages = messages$2;
|
|
683
|
+
ruleFunction$2.meta = meta$2;
|
|
684
|
+
var no_unreachable_media_conditions_default = createPlugin$2(rule_name$2, ruleFunction$2);
|
|
685
|
+
//#endregion
|
|
686
|
+
//#region src/rules/no-static-media-query/index.ts
|
|
687
|
+
const { createPlugin: createPlugin$1, utils: utils$1 } = stylelint;
|
|
688
|
+
const rule_name$1 = "projectwallace/no-static-media-query";
|
|
689
|
+
const messages$1 = utils$1.ruleMessages(rule_name$1, { rejected: (feature) => `Media feature "${feature}" creates an unreachable condition` });
|
|
690
|
+
const meta$1 = { url: "https://github.com/projectwallace/stylelint-plugin/blob/main/src/rules/no-static-media-query/README.md" };
|
|
691
|
+
/**
|
|
692
|
+
* Parse an at-rule prelude and return the first static (equality-bound) feature name,
|
|
693
|
+
* or null if no static media features are found.
|
|
694
|
+
*
|
|
695
|
+
* A static media feature uses the equality syntax like `(width: 300px)` — without
|
|
696
|
+
* a `min-` or `max-` prefix. This fixes the feature to a single exact value, which
|
|
697
|
+
* almost never matches in practice.
|
|
698
|
+
*/
|
|
699
|
+
function find_static_feature_in_prelude$1(at_rule_name, prelude) {
|
|
700
|
+
const parsed = parse_atrule_prelude(at_rule_name, prelude);
|
|
701
|
+
for (const query_node of parsed) {
|
|
702
|
+
if (query_node.type !== MEDIA_QUERY) continue;
|
|
703
|
+
let skip = false;
|
|
704
|
+
walk$1(query_node, (node) => {
|
|
705
|
+
if (node.type === PRELUDE_OPERATOR) {
|
|
706
|
+
const operator = node.text.trim().toLowerCase();
|
|
707
|
+
if (operator === "not" || operator === "or") {
|
|
708
|
+
skip = true;
|
|
709
|
+
return BREAK;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
});
|
|
713
|
+
if (skip) continue;
|
|
714
|
+
let static_feature = null;
|
|
715
|
+
walk$1(query_node, (node) => {
|
|
716
|
+
if (static_feature !== null) return;
|
|
717
|
+
if (node.type !== MEDIA_FEATURE) return;
|
|
718
|
+
const property = node.property;
|
|
719
|
+
if (!property) return;
|
|
720
|
+
if (property.startsWith("min-") || property.startsWith("max-")) return;
|
|
721
|
+
for (const child of node.children) if (child.type === DIMENSION || child.type === NUMBER) {
|
|
722
|
+
const value = child.value_as_number;
|
|
723
|
+
if (value != null && !Number.isNaN(value)) {
|
|
724
|
+
static_feature = property;
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
});
|
|
729
|
+
if (static_feature !== null) return static_feature;
|
|
730
|
+
}
|
|
731
|
+
return null;
|
|
732
|
+
}
|
|
733
|
+
function check_at_rule(at_rule_name, atRule, result) {
|
|
734
|
+
const prelude = atRule.params;
|
|
735
|
+
if (!prelude) return;
|
|
736
|
+
const static_feature = find_static_feature_in_prelude$1(at_rule_name, prelude);
|
|
737
|
+
if (static_feature !== null) utils$1.report({
|
|
738
|
+
message: messages$1.rejected(static_feature),
|
|
739
|
+
node: atRule,
|
|
740
|
+
result,
|
|
741
|
+
ruleName: rule_name$1
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
const ruleFunction$1 = (primaryOption) => {
|
|
745
|
+
return (root, result) => {
|
|
746
|
+
if (!utils$1.validateOptions(result, rule_name$1, {
|
|
747
|
+
actual: primaryOption,
|
|
748
|
+
possible: [true]
|
|
749
|
+
})) return;
|
|
750
|
+
root.walkAtRules("media", (atRule) => {
|
|
751
|
+
check_at_rule("media", atRule, result);
|
|
752
|
+
});
|
|
753
|
+
root.walkAtRules("import", (atRule) => {
|
|
754
|
+
check_at_rule("import", atRule, result);
|
|
755
|
+
});
|
|
756
|
+
};
|
|
757
|
+
};
|
|
758
|
+
ruleFunction$1.ruleName = rule_name$1;
|
|
759
|
+
ruleFunction$1.messages = messages$1;
|
|
760
|
+
ruleFunction$1.meta = meta$1;
|
|
761
|
+
var no_static_media_query_default = createPlugin$1(rule_name$1, ruleFunction$1);
|
|
762
|
+
//#endregion
|
|
763
|
+
//#region src/rules/no-static-container-query/index.ts
|
|
764
|
+
const { createPlugin, utils } = stylelint;
|
|
765
|
+
const rule_name = "projectwallace/no-static-container-query";
|
|
766
|
+
const messages = utils.ruleMessages(rule_name, { rejected: (feature) => `Container feature "${feature}" creates an unreachable condition` });
|
|
767
|
+
const meta = { url: "https://github.com/projectwallace/stylelint-plugin/blob/main/src/rules/no-static-container-query/README.md" };
|
|
768
|
+
/**
|
|
769
|
+
* Parse an at-rule prelude and return the first static (equality-bound) feature name,
|
|
770
|
+
* or null if no static container features are found.
|
|
771
|
+
*
|
|
772
|
+
* A static container feature uses the equality syntax like `(width: 300px)` — without
|
|
773
|
+
* a `min-` or `max-` prefix. This fixes the feature to a single exact value, which
|
|
774
|
+
* almost never matches in practice.
|
|
775
|
+
*/
|
|
776
|
+
function find_static_feature_in_prelude(prelude) {
|
|
777
|
+
const parsed = parse_atrule_prelude("container", prelude);
|
|
778
|
+
for (const query_node of parsed) {
|
|
779
|
+
if (query_node.type !== CONTAINER_QUERY) continue;
|
|
780
|
+
let skip = false;
|
|
781
|
+
walk$1(query_node, (node) => {
|
|
782
|
+
if (node.type === PRELUDE_OPERATOR) {
|
|
783
|
+
const operator = node.text.trim().toLowerCase();
|
|
784
|
+
if (operator === "not" || operator === "or") {
|
|
785
|
+
skip = true;
|
|
786
|
+
return BREAK;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
});
|
|
790
|
+
if (skip) continue;
|
|
791
|
+
let static_feature = null;
|
|
792
|
+
walk$1(query_node, (node) => {
|
|
793
|
+
if (static_feature !== null) return;
|
|
794
|
+
if (node.type !== MEDIA_FEATURE) return;
|
|
795
|
+
const property = node.property;
|
|
796
|
+
if (!property) return;
|
|
797
|
+
if (property.startsWith("min-") || property.startsWith("max-")) return;
|
|
798
|
+
for (const child of node.children) if (child.type === DIMENSION || child.type === NUMBER) {
|
|
799
|
+
const value = child.value_as_number;
|
|
800
|
+
if (value != null && !Number.isNaN(value)) {
|
|
801
|
+
static_feature = property;
|
|
802
|
+
return;
|
|
401
803
|
}
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
if (static_feature !== null) return static_feature;
|
|
807
|
+
}
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
810
|
+
const ruleFunction = (primaryOption) => {
|
|
811
|
+
return (root, result) => {
|
|
812
|
+
if (!utils.validateOptions(result, rule_name, {
|
|
813
|
+
actual: primaryOption,
|
|
814
|
+
possible: [true]
|
|
815
|
+
})) return;
|
|
816
|
+
root.walkAtRules("container", (atRule) => {
|
|
817
|
+
const prelude = atRule.params;
|
|
818
|
+
if (!prelude) return;
|
|
819
|
+
const static_feature = find_static_feature_in_prelude(prelude);
|
|
820
|
+
if (static_feature !== null) utils.report({
|
|
821
|
+
message: messages.rejected(static_feature),
|
|
822
|
+
node: atRule,
|
|
823
|
+
result,
|
|
824
|
+
ruleName: rule_name
|
|
402
825
|
});
|
|
403
826
|
});
|
|
404
827
|
};
|
|
@@ -418,6 +841,9 @@ const plugins = [
|
|
|
418
841
|
no_unused_container_names_default,
|
|
419
842
|
no_undeclared_container_names_default,
|
|
420
843
|
no_anonymous_layers_default,
|
|
844
|
+
no_useless_custom_property_assignment_default,
|
|
845
|
+
no_unreachable_media_conditions_default,
|
|
846
|
+
no_static_media_query_default,
|
|
421
847
|
createPlugin(rule_name, ruleFunction)
|
|
422
848
|
];
|
|
423
849
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@projectwallace/stylelint-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "A stylelint plugin that checks the complexity of your CSS.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"complexity",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@projectwallace/css-analyzer": "^9.4.0",
|
|
37
|
-
"@projectwallace/css-parser": "^0.13.
|
|
37
|
+
"@projectwallace/css-parser": "^0.13.10"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@codecov/rollup-plugin": "^1.9.1",
|