@master/eslint-plugin-css 2.0.0-rc.70 → 2.0.0-rc.72
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/README.md +68 -11
- package/dist/configs/recommended.cjs +4 -3
- package/dist/configs/recommended.mjs +4 -3
- package/dist/plugin.cjs +10 -6
- package/dist/plugin.mjs +10 -6
- package/dist/rules/no-conflicting-classes.cjs +101 -0
- package/dist/rules/no-conflicting-classes.d.ts +4 -0
- package/dist/rules/no-conflicting-classes.mjs +99 -0
- package/dist/rules/no-invalid-classes.cjs +51 -0
- package/dist/rules/{class-validation.d.ts → no-invalid-classes.d.ts} +1 -1
- package/dist/rules/no-invalid-classes.mjs +49 -0
- package/dist/rules/no-unapproved-raw-values.cjs +77 -0
- package/dist/rules/no-unapproved-raw-values.d.ts +8 -0
- package/dist/rules/no-unapproved-raw-values.mjs +75 -0
- package/dist/rules/prefer-canonical-classes.cjs +112 -0
- package/dist/rules/prefer-canonical-classes.d.ts +5 -0
- package/dist/rules/prefer-canonical-classes.mjs +110 -0
- package/dist/rules/{class-order.cjs → sort-classes.cjs} +10 -21
- package/dist/rules/{class-order.mjs → sort-classes.mjs} +10 -21
- package/dist/settings-schema.cjs +29 -23
- package/dist/settings-schema.d.ts +3 -2
- package/dist/settings-schema.mjs +25 -23
- package/dist/settings.cjs +2 -8
- package/dist/settings.d.ts +2 -2
- package/dist/settings.mjs +2 -8
- package/dist/utils/define-visitors.cjs +1 -1
- package/dist/utils/define-visitors.mjs +1 -1
- package/dist/utils/master-css.cjs +2 -82
- package/dist/utils/master-css.d.ts +0 -16
- package/dist/utils/master-css.mjs +1 -75
- package/dist/utils/resolve-class-node.cjs +18 -67
- package/dist/utils/resolve-class-node.d.ts +15 -7
- package/dist/utils/resolve-class-node.mjs +18 -67
- package/dist/utils/resolve-context.d.ts +1 -1
- package/package.json +1 -1
- package/dist/common.cjs +0 -7
- package/dist/common.d.ts +0 -2
- package/dist/common.mjs +0 -4
- package/dist/functions/filter-collision-classes.cjs +0 -29
- package/dist/functions/filter-collision-classes.d.ts +0 -2
- package/dist/functions/filter-collision-classes.mjs +0 -27
- package/dist/rules/class-collision.cjs +0 -76
- package/dist/rules/class-collision.d.ts +0 -4
- package/dist/rules/class-collision.mjs +0 -74
- package/dist/rules/class-validation.cjs +0 -60
- package/dist/rules/class-validation.mjs +0 -58
- /package/dist/rules/{class-order.d.ts → sort-classes.d.ts} +0 -0
|
@@ -1,94 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var css = require('@master/css');
|
|
4
3
|
var cssValidator = require('@master/css-validator');
|
|
5
4
|
var node_module = require('node:module');
|
|
6
|
-
var UtilityType = require('@master/css-schema/utility-type');
|
|
7
5
|
|
|
8
6
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
9
7
|
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('utils/master-css.cjs', document.baseURI).href)));
|
|
10
8
|
const defaultManifest = require$1('@master/css-preset/default-manifest.json');
|
|
11
|
-
const CLASS_ATTRIBUTES = [
|
|
12
|
-
'class',
|
|
13
|
-
'className'
|
|
14
|
-
];
|
|
15
|
-
const CLASS_DECLARATIONS = [];
|
|
16
|
-
const CLASS_FUNCTIONS = [
|
|
17
|
-
'clsx',
|
|
18
|
-
'cva',
|
|
19
|
-
'ctl',
|
|
20
|
-
'cv',
|
|
21
|
-
'class',
|
|
22
|
-
'classnames',
|
|
23
|
-
'classVariant',
|
|
24
|
-
'styled(?:\\s+)?(?:\\.\\w+)?',
|
|
25
|
-
'classList(?:\\s+)?\\.(?:add|remove|toggle|replace)'
|
|
26
|
-
];
|
|
27
|
-
const LAYER_ORDER = [
|
|
28
|
-
'theme',
|
|
29
|
-
'base',
|
|
30
|
-
'defaults',
|
|
31
|
-
'components',
|
|
32
|
-
'utilities'
|
|
33
|
-
];
|
|
34
|
-
function stable(value) {
|
|
35
|
-
if (!value || typeof value !== 'object') return JSON.stringify(value);
|
|
36
|
-
if (Array.isArray(value)) return `[${value.map(stable).join(',')}]`;
|
|
37
|
-
return `{${Object.entries(value).sort(([a], [b])=>a.localeCompare(b)).map(([key, item])=>`${JSON.stringify(key)}:${stable(item)}`).join(',')}}`;
|
|
38
|
-
}
|
|
39
|
-
function equalDeclarations(a, b) {
|
|
40
|
-
if (!a || !b || typeof a !== 'object' || typeof b !== 'object') return stable(a) === stable(b);
|
|
41
|
-
const aKeys = Object.keys(a).sort();
|
|
42
|
-
const bKeys = Object.keys(b).sort();
|
|
43
|
-
return stable(aKeys) === stable(bKeys);
|
|
44
|
-
}
|
|
45
|
-
function equalVariants(a, b) {
|
|
46
|
-
const branchA = a.variantBranchKey;
|
|
47
|
-
const branchB = b.variantBranchKey;
|
|
48
|
-
return (branchA !== undefined || branchB !== undefined ? branchA === branchB : a.selectorText === b.selectorText) && a.layerName === b.layerName && stable(a.atRules) === stable(b.atRules);
|
|
49
|
-
}
|
|
50
|
-
function getLayerOrder(layerName) {
|
|
51
|
-
const index = LAYER_ORDER.indexOf(layerName || 'utilities');
|
|
52
|
-
return index === -1 ? LAYER_ORDER.length : index;
|
|
53
|
-
}
|
|
54
|
-
function getReadableGroupOrder(rule) {
|
|
55
|
-
if (rule.atRules) return 3;
|
|
56
|
-
if (rule.mode) return 2;
|
|
57
|
-
if (rule.selectorNodes?.length) return 1;
|
|
58
|
-
return 0;
|
|
59
|
-
}
|
|
60
|
-
function getReadableTypeOrder(rule) {
|
|
61
|
-
if (rule.fixedClass) return 0;
|
|
62
|
-
if (rule.type === UtilityType.Semantic) return 1;
|
|
63
|
-
return 2;
|
|
64
|
-
}
|
|
65
|
-
function sortReadableClasses(classNames, css$1) {
|
|
66
|
-
return [
|
|
67
|
-
...new Set(classNames)
|
|
68
|
-
].sort((a, b)=>{
|
|
69
|
-
const ruleA = css$1.generate(a)[0];
|
|
70
|
-
const ruleB = css$1.generate(b)[0];
|
|
71
|
-
if (!ruleA && !ruleB) return a.localeCompare(b);
|
|
72
|
-
if (!ruleA) return 1;
|
|
73
|
-
if (!ruleB) return -1;
|
|
74
|
-
const layerCmp = getLayerOrder(ruleA.layerName) - getLayerOrder(ruleB.layerName);
|
|
75
|
-
if (layerCmp !== 0) return layerCmp;
|
|
76
|
-
const groupCmp = getReadableGroupOrder(ruleA) - getReadableGroupOrder(ruleB);
|
|
77
|
-
if (groupCmp !== 0) return groupCmp;
|
|
78
|
-
const typeCmp = getReadableTypeOrder(ruleA) - getReadableTypeOrder(ruleB);
|
|
79
|
-
if (typeCmp !== 0) return typeCmp;
|
|
80
|
-
return css.compareRulePriority(ruleA, ruleB) || a.localeCompare(b);
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
9
|
|
|
84
10
|
Object.defineProperty(exports, "createCSSWithNativeDeclarations", {
|
|
85
|
-
|
|
86
|
-
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () { return cssValidator.createCSSWithNativeDeclarations; }
|
|
87
13
|
});
|
|
88
|
-
exports.CLASS_ATTRIBUTES = CLASS_ATTRIBUTES;
|
|
89
|
-
exports.CLASS_DECLARATIONS = CLASS_DECLARATIONS;
|
|
90
|
-
exports.CLASS_FUNCTIONS = CLASS_FUNCTIONS;
|
|
91
14
|
exports.defaultManifest = defaultManifest;
|
|
92
|
-
exports.equalDeclarations = equalDeclarations;
|
|
93
|
-
exports.equalVariants = equalVariants;
|
|
94
|
-
exports.sortReadableClasses = sortReadableClasses;
|
|
@@ -3,19 +3,3 @@ import { createCSSWithNativeDeclarations } from '@master/css-validator';
|
|
|
3
3
|
export type { MasterCSS, MasterCSSManifest };
|
|
4
4
|
declare const defaultManifest: MasterCSSManifest;
|
|
5
5
|
export { createCSSWithNativeDeclarations, defaultManifest };
|
|
6
|
-
export declare const CLASS_ATTRIBUTES: string[];
|
|
7
|
-
export declare const CLASS_DECLARATIONS: string[];
|
|
8
|
-
export declare const CLASS_FUNCTIONS: string[];
|
|
9
|
-
export declare function equalDeclarations(a: unknown, b: unknown): boolean;
|
|
10
|
-
export declare function equalVariants(a: {
|
|
11
|
-
selectorText?: string;
|
|
12
|
-
atRules?: unknown;
|
|
13
|
-
layerName?: string;
|
|
14
|
-
variantBranchKey?: string;
|
|
15
|
-
}, b: {
|
|
16
|
-
selectorText?: string;
|
|
17
|
-
atRules?: unknown;
|
|
18
|
-
layerName?: string;
|
|
19
|
-
variantBranchKey?: string;
|
|
20
|
-
}): boolean;
|
|
21
|
-
export declare function sortReadableClasses(classNames: string[], css: MasterCSS): string[];
|
|
@@ -1,81 +1,7 @@
|
|
|
1
|
-
import { compareRulePriority } from '@master/css';
|
|
2
1
|
export { createCSSWithNativeDeclarations } from '@master/css-validator';
|
|
3
2
|
import { createRequire } from 'node:module';
|
|
4
|
-
import UtilityType from '@master/css-schema/utility-type';
|
|
5
3
|
|
|
6
4
|
const require$1 = createRequire(import.meta.url);
|
|
7
5
|
const defaultManifest = require$1('@master/css-preset/default-manifest.json');
|
|
8
|
-
const CLASS_ATTRIBUTES = [
|
|
9
|
-
'class',
|
|
10
|
-
'className'
|
|
11
|
-
];
|
|
12
|
-
const CLASS_DECLARATIONS = [];
|
|
13
|
-
const CLASS_FUNCTIONS = [
|
|
14
|
-
'clsx',
|
|
15
|
-
'cva',
|
|
16
|
-
'ctl',
|
|
17
|
-
'cv',
|
|
18
|
-
'class',
|
|
19
|
-
'classnames',
|
|
20
|
-
'classVariant',
|
|
21
|
-
'styled(?:\\s+)?(?:\\.\\w+)?',
|
|
22
|
-
'classList(?:\\s+)?\\.(?:add|remove|toggle|replace)'
|
|
23
|
-
];
|
|
24
|
-
const LAYER_ORDER = [
|
|
25
|
-
'theme',
|
|
26
|
-
'base',
|
|
27
|
-
'defaults',
|
|
28
|
-
'components',
|
|
29
|
-
'utilities'
|
|
30
|
-
];
|
|
31
|
-
function stable(value) {
|
|
32
|
-
if (!value || typeof value !== 'object') return JSON.stringify(value);
|
|
33
|
-
if (Array.isArray(value)) return `[${value.map(stable).join(',')}]`;
|
|
34
|
-
return `{${Object.entries(value).sort(([a], [b])=>a.localeCompare(b)).map(([key, item])=>`${JSON.stringify(key)}:${stable(item)}`).join(',')}}`;
|
|
35
|
-
}
|
|
36
|
-
function equalDeclarations(a, b) {
|
|
37
|
-
if (!a || !b || typeof a !== 'object' || typeof b !== 'object') return stable(a) === stable(b);
|
|
38
|
-
const aKeys = Object.keys(a).sort();
|
|
39
|
-
const bKeys = Object.keys(b).sort();
|
|
40
|
-
return stable(aKeys) === stable(bKeys);
|
|
41
|
-
}
|
|
42
|
-
function equalVariants(a, b) {
|
|
43
|
-
const branchA = a.variantBranchKey;
|
|
44
|
-
const branchB = b.variantBranchKey;
|
|
45
|
-
return (branchA !== undefined || branchB !== undefined ? branchA === branchB : a.selectorText === b.selectorText) && a.layerName === b.layerName && stable(a.atRules) === stable(b.atRules);
|
|
46
|
-
}
|
|
47
|
-
function getLayerOrder(layerName) {
|
|
48
|
-
const index = LAYER_ORDER.indexOf(layerName || 'utilities');
|
|
49
|
-
return index === -1 ? LAYER_ORDER.length : index;
|
|
50
|
-
}
|
|
51
|
-
function getReadableGroupOrder(rule) {
|
|
52
|
-
if (rule.atRules) return 3;
|
|
53
|
-
if (rule.mode) return 2;
|
|
54
|
-
if (rule.selectorNodes?.length) return 1;
|
|
55
|
-
return 0;
|
|
56
|
-
}
|
|
57
|
-
function getReadableTypeOrder(rule) {
|
|
58
|
-
if (rule.fixedClass) return 0;
|
|
59
|
-
if (rule.type === UtilityType.Semantic) return 1;
|
|
60
|
-
return 2;
|
|
61
|
-
}
|
|
62
|
-
function sortReadableClasses(classNames, css) {
|
|
63
|
-
return [
|
|
64
|
-
...new Set(classNames)
|
|
65
|
-
].sort((a, b)=>{
|
|
66
|
-
const ruleA = css.generate(a)[0];
|
|
67
|
-
const ruleB = css.generate(b)[0];
|
|
68
|
-
if (!ruleA && !ruleB) return a.localeCompare(b);
|
|
69
|
-
if (!ruleA) return 1;
|
|
70
|
-
if (!ruleB) return -1;
|
|
71
|
-
const layerCmp = getLayerOrder(ruleA.layerName) - getLayerOrder(ruleB.layerName);
|
|
72
|
-
if (layerCmp !== 0) return layerCmp;
|
|
73
|
-
const groupCmp = getReadableGroupOrder(ruleA) - getReadableGroupOrder(ruleB);
|
|
74
|
-
if (groupCmp !== 0) return groupCmp;
|
|
75
|
-
const typeCmp = getReadableTypeOrder(ruleA) - getReadableTypeOrder(ruleB);
|
|
76
|
-
if (typeCmp !== 0) return typeCmp;
|
|
77
|
-
return compareRulePriority(ruleA, ruleB) || a.localeCompare(b);
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
6
|
|
|
81
|
-
export {
|
|
7
|
+
export { defaultManifest };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var cssLexer = require('@master/css-lexer');
|
|
4
4
|
|
|
5
5
|
function resolveClassNode(node, context) {
|
|
6
6
|
const { sourceCode } = context;
|
|
@@ -8,6 +8,7 @@ function resolveClassNode(node, context) {
|
|
|
8
8
|
let raw = null;
|
|
9
9
|
let start = null;
|
|
10
10
|
let end = null;
|
|
11
|
+
let unescape = false;
|
|
11
12
|
switch(node.type){
|
|
12
13
|
case 'Literal':
|
|
13
14
|
value = node.value;
|
|
@@ -47,6 +48,7 @@ function resolveClassNode(node, context) {
|
|
|
47
48
|
raw = node.value.raw;
|
|
48
49
|
start = node.range[0] + 1;
|
|
49
50
|
end = node.range[1] - 1;
|
|
51
|
+
unescape = '`';
|
|
50
52
|
break;
|
|
51
53
|
default:
|
|
52
54
|
return;
|
|
@@ -54,72 +56,22 @@ function resolveClassNode(node, context) {
|
|
|
54
56
|
if (typeof value !== 'string') {
|
|
55
57
|
return;
|
|
56
58
|
}
|
|
57
|
-
if (/^(['"`])(
|
|
59
|
+
if (/^(['"`])([\s\S]*)\1$/.test(raw)) {
|
|
60
|
+
unescape = raw[0];
|
|
58
61
|
raw = raw.slice(1, -1);
|
|
59
62
|
start = start + 1;
|
|
60
63
|
end = end - 1;
|
|
61
64
|
}
|
|
62
|
-
const nodes =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
let match;
|
|
73
|
-
while((match = common.HALF_WIDTH_WHITESPACE_GLOBAL_REGEX.exec(raw)) !== null){
|
|
74
|
-
const spaceRaw = match[0];
|
|
75
|
-
const spaceStart = match.index;
|
|
76
|
-
const spaceEnd = spaceStart + spaceRaw.length;
|
|
77
|
-
if (spaceStart > lastIndex) {
|
|
78
|
-
const classRaw = raw.slice(lastIndex, spaceStart);
|
|
79
|
-
const classValue = classRawValueMap.get(classRaw);
|
|
80
|
-
if (!classValue) return;
|
|
81
|
-
const startOffset = start + lastIndex;
|
|
82
|
-
const endOffset = start + spaceStart;
|
|
83
|
-
nodes.push({
|
|
84
|
-
type: 'class',
|
|
85
|
-
value: classValue,
|
|
86
|
-
raw: classRaw,
|
|
87
|
-
range: [
|
|
88
|
-
startOffset,
|
|
89
|
-
endOffset
|
|
90
|
-
],
|
|
91
|
-
loc: {
|
|
92
|
-
start: sourceCode.getLocFromIndex(startOffset),
|
|
93
|
-
end: sourceCode.getLocFromIndex(endOffset)
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
const spaceStartOffset = start + spaceStart;
|
|
98
|
-
const spaceEndOffset = start + spaceEnd;
|
|
99
|
-
nodes.push({
|
|
100
|
-
type: 'space',
|
|
101
|
-
raw: spaceRaw,
|
|
102
|
-
range: [
|
|
103
|
-
spaceStartOffset,
|
|
104
|
-
spaceEndOffset
|
|
105
|
-
],
|
|
106
|
-
loc: {
|
|
107
|
-
start: sourceCode.getLocFromIndex(spaceStartOffset),
|
|
108
|
-
end: sourceCode.getLocFromIndex(spaceEndOffset)
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
lastIndex = spaceEnd;
|
|
112
|
-
}
|
|
113
|
-
if (lastIndex < raw.length) {
|
|
114
|
-
const classRaw = raw.slice(lastIndex);
|
|
115
|
-
const classValue = classRawValueMap.get(classRaw);
|
|
116
|
-
if (!classValue) return;
|
|
117
|
-
const startOffset = start + lastIndex;
|
|
118
|
-
const endOffset = start + raw.length;
|
|
119
|
-
nodes.push({
|
|
120
|
-
type: 'class',
|
|
121
|
-
value: classValue,
|
|
122
|
-
raw: classRaw,
|
|
65
|
+
const nodes = cssLexer.parseMasterCSSClassList(raw, {
|
|
66
|
+
preserveSpaces: true,
|
|
67
|
+
unescape
|
|
68
|
+
}).map((item)=>{
|
|
69
|
+
const startOffset = start + item.start;
|
|
70
|
+
const endOffset = start + item.end;
|
|
71
|
+
return {
|
|
72
|
+
type: item.type,
|
|
73
|
+
value: item.token,
|
|
74
|
+
raw: item.raw,
|
|
123
75
|
range: [
|
|
124
76
|
startOffset,
|
|
125
77
|
endOffset
|
|
@@ -128,8 +80,8 @@ function resolveClassNode(node, context) {
|
|
|
128
80
|
start: sourceCode.getLocFromIndex(startOffset),
|
|
129
81
|
end: sourceCode.getLocFromIndex(endOffset)
|
|
130
82
|
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
83
|
+
};
|
|
84
|
+
});
|
|
133
85
|
const classNodes = nodes.filter((node)=>node.type === 'class');
|
|
134
86
|
return {
|
|
135
87
|
nodes,
|
|
@@ -137,8 +89,7 @@ function resolveClassNode(node, context) {
|
|
|
137
89
|
end,
|
|
138
90
|
raw,
|
|
139
91
|
value,
|
|
140
|
-
|
|
141
|
-
classValueRawMap,
|
|
92
|
+
unescape,
|
|
142
93
|
classNodes,
|
|
143
94
|
classValues: classNodes.map((node)=>node.value)
|
|
144
95
|
};
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { RuleContext } from '@typescript-eslint/utils/ts-eslint';
|
|
2
|
-
export
|
|
3
|
-
|
|
2
|
+
export type ResolvedClassListUnescape = string | false;
|
|
3
|
+
export interface ResolvedClassListNode {
|
|
4
|
+
type: 'class' | 'space';
|
|
5
|
+
value: string;
|
|
6
|
+
raw: string;
|
|
7
|
+
range: [number, number];
|
|
8
|
+
loc: any;
|
|
9
|
+
}
|
|
10
|
+
export interface ResolvedClassNode {
|
|
11
|
+
nodes: ResolvedClassListNode[];
|
|
4
12
|
start: number;
|
|
5
13
|
end: number;
|
|
6
14
|
raw: string;
|
|
7
15
|
value: string;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
unescape: ResolvedClassListUnescape;
|
|
17
|
+
classNodes: ResolvedClassListNode[];
|
|
18
|
+
classValues: string[];
|
|
19
|
+
}
|
|
20
|
+
export default function resolveClassNode(node: any, context: RuleContext<any, any[]>): ResolvedClassNode | undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parseMasterCSSClassList } from '@master/css-lexer';
|
|
2
2
|
|
|
3
3
|
function resolveClassNode(node, context) {
|
|
4
4
|
const { sourceCode } = context;
|
|
@@ -6,6 +6,7 @@ function resolveClassNode(node, context) {
|
|
|
6
6
|
let raw = null;
|
|
7
7
|
let start = null;
|
|
8
8
|
let end = null;
|
|
9
|
+
let unescape = false;
|
|
9
10
|
switch(node.type){
|
|
10
11
|
case 'Literal':
|
|
11
12
|
value = node.value;
|
|
@@ -45,6 +46,7 @@ function resolveClassNode(node, context) {
|
|
|
45
46
|
raw = node.value.raw;
|
|
46
47
|
start = node.range[0] + 1;
|
|
47
48
|
end = node.range[1] - 1;
|
|
49
|
+
unescape = '`';
|
|
48
50
|
break;
|
|
49
51
|
default:
|
|
50
52
|
return;
|
|
@@ -52,72 +54,22 @@ function resolveClassNode(node, context) {
|
|
|
52
54
|
if (typeof value !== 'string') {
|
|
53
55
|
return;
|
|
54
56
|
}
|
|
55
|
-
if (/^(['"`])(
|
|
57
|
+
if (/^(['"`])([\s\S]*)\1$/.test(raw)) {
|
|
58
|
+
unescape = raw[0];
|
|
56
59
|
raw = raw.slice(1, -1);
|
|
57
60
|
start = start + 1;
|
|
58
61
|
end = end - 1;
|
|
59
62
|
}
|
|
60
|
-
const nodes =
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
let match;
|
|
71
|
-
while((match = HALF_WIDTH_WHITESPACE_GLOBAL_REGEX.exec(raw)) !== null){
|
|
72
|
-
const spaceRaw = match[0];
|
|
73
|
-
const spaceStart = match.index;
|
|
74
|
-
const spaceEnd = spaceStart + spaceRaw.length;
|
|
75
|
-
if (spaceStart > lastIndex) {
|
|
76
|
-
const classRaw = raw.slice(lastIndex, spaceStart);
|
|
77
|
-
const classValue = classRawValueMap.get(classRaw);
|
|
78
|
-
if (!classValue) return;
|
|
79
|
-
const startOffset = start + lastIndex;
|
|
80
|
-
const endOffset = start + spaceStart;
|
|
81
|
-
nodes.push({
|
|
82
|
-
type: 'class',
|
|
83
|
-
value: classValue,
|
|
84
|
-
raw: classRaw,
|
|
85
|
-
range: [
|
|
86
|
-
startOffset,
|
|
87
|
-
endOffset
|
|
88
|
-
],
|
|
89
|
-
loc: {
|
|
90
|
-
start: sourceCode.getLocFromIndex(startOffset),
|
|
91
|
-
end: sourceCode.getLocFromIndex(endOffset)
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
const spaceStartOffset = start + spaceStart;
|
|
96
|
-
const spaceEndOffset = start + spaceEnd;
|
|
97
|
-
nodes.push({
|
|
98
|
-
type: 'space',
|
|
99
|
-
raw: spaceRaw,
|
|
100
|
-
range: [
|
|
101
|
-
spaceStartOffset,
|
|
102
|
-
spaceEndOffset
|
|
103
|
-
],
|
|
104
|
-
loc: {
|
|
105
|
-
start: sourceCode.getLocFromIndex(spaceStartOffset),
|
|
106
|
-
end: sourceCode.getLocFromIndex(spaceEndOffset)
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
lastIndex = spaceEnd;
|
|
110
|
-
}
|
|
111
|
-
if (lastIndex < raw.length) {
|
|
112
|
-
const classRaw = raw.slice(lastIndex);
|
|
113
|
-
const classValue = classRawValueMap.get(classRaw);
|
|
114
|
-
if (!classValue) return;
|
|
115
|
-
const startOffset = start + lastIndex;
|
|
116
|
-
const endOffset = start + raw.length;
|
|
117
|
-
nodes.push({
|
|
118
|
-
type: 'class',
|
|
119
|
-
value: classValue,
|
|
120
|
-
raw: classRaw,
|
|
63
|
+
const nodes = parseMasterCSSClassList(raw, {
|
|
64
|
+
preserveSpaces: true,
|
|
65
|
+
unescape
|
|
66
|
+
}).map((item)=>{
|
|
67
|
+
const startOffset = start + item.start;
|
|
68
|
+
const endOffset = start + item.end;
|
|
69
|
+
return {
|
|
70
|
+
type: item.type,
|
|
71
|
+
value: item.token,
|
|
72
|
+
raw: item.raw,
|
|
121
73
|
range: [
|
|
122
74
|
startOffset,
|
|
123
75
|
endOffset
|
|
@@ -126,8 +78,8 @@ function resolveClassNode(node, context) {
|
|
|
126
78
|
start: sourceCode.getLocFromIndex(startOffset),
|
|
127
79
|
end: sourceCode.getLocFromIndex(endOffset)
|
|
128
80
|
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
81
|
+
};
|
|
82
|
+
});
|
|
131
83
|
const classNodes = nodes.filter((node)=>node.type === 'class');
|
|
132
84
|
return {
|
|
133
85
|
nodes,
|
|
@@ -135,8 +87,7 @@ function resolveClassNode(node, context) {
|
|
|
135
87
|
end,
|
|
136
88
|
raw,
|
|
137
89
|
value,
|
|
138
|
-
|
|
139
|
-
classValueRawMap,
|
|
90
|
+
unescape,
|
|
140
91
|
classNodes,
|
|
141
92
|
classValues: classNodes.map((node)=>node.value)
|
|
142
93
|
};
|
|
@@ -2,11 +2,11 @@ import type { RuleContext } from '@typescript-eslint/utils/ts-eslint';
|
|
|
2
2
|
import { MasterCSS } from './master-css';
|
|
3
3
|
export default function resolveContext(context: RuleContext<any, any[]>): {
|
|
4
4
|
settings: {
|
|
5
|
+
manifest: any;
|
|
5
6
|
classAttributes: string[];
|
|
6
7
|
classFunctions: string[];
|
|
7
8
|
classDeclarations: string[];
|
|
8
9
|
ignoredKeys: string[];
|
|
9
|
-
manifest: any;
|
|
10
10
|
};
|
|
11
11
|
options: any;
|
|
12
12
|
css: MasterCSS;
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@master/eslint-plugin-css","type":"module","scripts":{"build":"techor build \"src/**/*.{js,ts}\"","dev":"pnpm build --watch","test":"vitest","type-check":"tsc --noEmit","lint":"eslint"},"keywords":["mastercss","eslint","eslintplugin"],"license":"MIT","description":"Master CSS ESLint Plugin","author":"Aoyue Design LLC.","funding":"https://rc.css.master.co/sponsor","homepage":"https://css.master.co","bugs":{"url":"https://github.com/master-co/css/issues"},"repository":{"type":"git","url":"https://github.com/master-co/css.git","directory":"packages/eslint-plugin"},"sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.mjs","jsnext:main":"./dist/index.mjs","esnext":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"},"./configs/*":{"types":"./dist/configs/*.d.ts","import":"./dist/configs/*.mjs","require":"./dist/configs/*.cjs"}},"files":["dist"],"publishConfig":{"access":"public","provenance":true},"dependencies":{"@master/css":"^2.0.0-rc.
|
|
1
|
+
{"name":"@master/eslint-plugin-css","type":"module","scripts":{"build":"techor build \"src/**/*.{js,ts}\"","dev":"pnpm build --watch","test":"vitest","type-check":"tsc --noEmit","lint":"eslint"},"keywords":["mastercss","eslint","eslintplugin"],"license":"MIT","description":"Master CSS ESLint Plugin","author":"Aoyue Design LLC.","funding":"https://rc.css.master.co/sponsor","homepage":"https://css.master.co","bugs":{"url":"https://github.com/master-co/css/issues"},"repository":{"type":"git","url":"https://github.com/master-co/css.git","directory":"packages/eslint-plugin"},"sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.mjs","jsnext:main":"./dist/index.mjs","esnext":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"},"./configs/*":{"types":"./dist/configs/*.d.ts","import":"./dist/configs/*.mjs","require":"./dist/configs/*.cjs"}},"files":["dist"],"publishConfig":{"access":"public","provenance":true},"dependencies":{"@master/css":"^2.0.0-rc.72","@master/css-lexer":"^2.0.0-rc.72","@master/css-lint":"^2.0.0-rc.72","@master/css-project":"^2.0.0-rc.72","@master/css-preset":"^2.0.0-rc.72","@master/css-validator":"^2.0.0-rc.72","@typescript-eslint/utils":"^8.61.1","typescript-eslint":"^8.61.1"},"devDependencies":{"@angular-eslint/template-parser":"^21.4.0","@master/css-schema":"^2.0.0-rc.72","@angular/compiler":"^21.2.17","@typescript-eslint/rule-tester":"^8.61.1","eslint":"^10.5.0","eslint-mdx":"^3.8.1","eslint-plugin-markdown":"^5.1.0","eslint-plugin-mdx":"^3.8.1","svelte-eslint-parser":"^1.8.0","ts-node":"^10.9.2","vue-eslint-parser":"^10.4.1"},"version":"2.0.0-rc.72"}
|
package/dist/common.cjs
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const HALF_WIDTH_WHITESPACE_REGEX = /([\t\n\f\r ]+)/;
|
|
4
|
-
const HALF_WIDTH_WHITESPACE_GLOBAL_REGEX = /([\t\n\f\r ]+)/g;
|
|
5
|
-
|
|
6
|
-
exports.HALF_WIDTH_WHITESPACE_GLOBAL_REGEX = HALF_WIDTH_WHITESPACE_GLOBAL_REGEX;
|
|
7
|
-
exports.HALF_WIDTH_WHITESPACE_REGEX = HALF_WIDTH_WHITESPACE_REGEX;
|
package/dist/common.d.ts
DELETED
package/dist/common.mjs
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var cssValidator = require('@master/css-validator');
|
|
4
|
-
var masterCss = require('../utils/master-css.cjs');
|
|
5
|
-
|
|
6
|
-
function filterCollisionClasses(classNames, css) {
|
|
7
|
-
const validRules = classNames.map((eachClassName)=>cssValidator.generateValidRules(eachClassName, css)[0]).filter(Boolean);
|
|
8
|
-
const collisionClassesRecord = {};
|
|
9
|
-
for(let i = 0; i < classNames.length; i++){
|
|
10
|
-
const className = classNames[i];
|
|
11
|
-
const rule = validRules.find((eachValidRule)=>eachValidRule.name === className);
|
|
12
|
-
const collisionClasses = [];
|
|
13
|
-
if (rule) {
|
|
14
|
-
for(let j = 0; j < classNames.length; j++){
|
|
15
|
-
const compareClassName = classNames[j];
|
|
16
|
-
const compareRule = validRules.find((eachValidRule)=>eachValidRule.name === compareClassName);
|
|
17
|
-
if (i !== j && compareRule && masterCss.equalDeclarations(rule.declarations, compareRule.declarations) && masterCss.equalVariants(rule, compareRule)) {
|
|
18
|
-
collisionClasses.push(compareClassName);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
if (collisionClasses.length > 0) {
|
|
22
|
-
collisionClassesRecord[className] = collisionClasses;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
return collisionClassesRecord;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
module.exports = filterCollisionClasses;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { generateValidRules } from '@master/css-validator';
|
|
2
|
-
import { equalDeclarations, equalVariants } from '../utils/master-css.mjs';
|
|
3
|
-
|
|
4
|
-
function filterCollisionClasses(classNames, css) {
|
|
5
|
-
const validRules = classNames.map((eachClassName)=>generateValidRules(eachClassName, css)[0]).filter(Boolean);
|
|
6
|
-
const collisionClassesRecord = {};
|
|
7
|
-
for(let i = 0; i < classNames.length; i++){
|
|
8
|
-
const className = classNames[i];
|
|
9
|
-
const rule = validRules.find((eachValidRule)=>eachValidRule.name === className);
|
|
10
|
-
const collisionClasses = [];
|
|
11
|
-
if (rule) {
|
|
12
|
-
for(let j = 0; j < classNames.length; j++){
|
|
13
|
-
const compareClassName = classNames[j];
|
|
14
|
-
const compareRule = validRules.find((eachValidRule)=>eachValidRule.name === compareClassName);
|
|
15
|
-
if (i !== j && compareRule && equalDeclarations(rule.declarations, compareRule.declarations) && equalVariants(rule, compareRule)) {
|
|
16
|
-
collisionClasses.push(compareClassName);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
if (collisionClasses.length > 0) {
|
|
20
|
-
collisionClassesRecord[className] = collisionClasses;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return collisionClassesRecord;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export { filterCollisionClasses as default };
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var defineVisitors = require('../utils/define-visitors.cjs');
|
|
4
|
-
var resolveContext = require('../utils/resolve-context.cjs');
|
|
5
|
-
var filterCollisionClasses = require('../functions/filter-collision-classes.cjs');
|
|
6
|
-
var createRule = require('../create-rule.cjs');
|
|
7
|
-
var settingsSchema = require('../settings-schema.cjs');
|
|
8
|
-
|
|
9
|
-
var classCollision = createRule({
|
|
10
|
-
name: 'class-collision-detection',
|
|
11
|
-
meta: {
|
|
12
|
-
type: 'layout',
|
|
13
|
-
docs: {
|
|
14
|
-
description: 'Avoid applying classes with the same declarations'
|
|
15
|
-
},
|
|
16
|
-
messages: {
|
|
17
|
-
collisionClass: '{{message}}'
|
|
18
|
-
},
|
|
19
|
-
fixable: 'code',
|
|
20
|
-
schema: [
|
|
21
|
-
settingsSchema
|
|
22
|
-
]
|
|
23
|
-
},
|
|
24
|
-
defaultOptions: [],
|
|
25
|
-
create (context) {
|
|
26
|
-
const { settings, css } = resolveContext(context);
|
|
27
|
-
return defineVisitors({
|
|
28
|
-
context,
|
|
29
|
-
settings
|
|
30
|
-
}, (node, { raw, start, end, nodes, classNodes, classValues })=>{
|
|
31
|
-
const collisionClassesRecord = filterCollisionClasses(classValues, css);
|
|
32
|
-
for(const className in collisionClassesRecord){
|
|
33
|
-
const collisionClasses = collisionClassesRecord[className];
|
|
34
|
-
const collisionClassNamesMsg = collisionClasses.map((x)=>`"${x}"`).join(' and ');
|
|
35
|
-
const classNode = classNodes.find((node)=>node.value === className);
|
|
36
|
-
const fixedNodes = [
|
|
37
|
-
...nodes
|
|
38
|
-
];
|
|
39
|
-
const removeCollision = (removedClassNode)=>{
|
|
40
|
-
for(let i = 0; i < fixedNodes.length; i++){
|
|
41
|
-
const fixedNode = fixedNodes[i];
|
|
42
|
-
const target = fixedNode === removedClassNode;
|
|
43
|
-
if (target) {
|
|
44
|
-
const prev = fixedNodes[i - 1];
|
|
45
|
-
const isSpaceBefore = prev && prev.type === 'space';
|
|
46
|
-
fixedNodes.splice(i, 1);
|
|
47
|
-
if (isSpaceBefore) {
|
|
48
|
-
fixedNodes.splice(i - 1, 1);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
collisionClasses.forEach((collisionClass)=>{
|
|
54
|
-
const collisionNode = classNodes.find((node)=>node.value === collisionClass);
|
|
55
|
-
removeCollision(collisionNode);
|
|
56
|
-
});
|
|
57
|
-
const fixedRaw = fixedNodes.map((node)=>node.raw).join('');
|
|
58
|
-
context.report({
|
|
59
|
-
loc: classNode.loc,
|
|
60
|
-
messageId: 'collisionClass',
|
|
61
|
-
data: {
|
|
62
|
-
message: `"${className}" applies the same declarations as ${collisionClassNamesMsg}.`
|
|
63
|
-
},
|
|
64
|
-
fix: function(fixer) {
|
|
65
|
-
return fixer.replaceTextRange([
|
|
66
|
-
start,
|
|
67
|
-
end
|
|
68
|
-
], fixedRaw);
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
module.exports = classCollision;
|