@master/eslint-plugin-css 2.0.0-rc.15 → 2.0.0-rc.16
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/config.cjs +16 -0
- package/dist/configs/config.mjs +14 -1
- package/dist/configs/flat.cjs +13 -0
- package/dist/configs/flat.mjs +11 -1
- package/dist/configs/recommended.cjs +12 -0
- package/dist/configs/recommended.mjs +10 -1
- package/dist/index.cjs +15 -0
- package/dist/index.mjs +13 -1
- package/dist/plugin.cjs +18 -0
- package/dist/plugin.mjs +16 -1
- package/dist/rules/class-collision.cjs +103 -0
- package/dist/rules/class-collision.mjs +101 -1
- package/dist/rules/class-order.cjs +196 -0
- package/dist/rules/class-order.mjs +194 -1
- package/dist/rules/class-validation.cjs +91 -0
- package/dist/rules/class-validation.mjs +89 -1
- package/dist/settings.cjs +13 -0
- package/dist/settings.mjs +11 -1
- package/dist/utils/are-declarations-equal.cjs +21 -0
- package/dist/utils/are-declarations-equal.mjs +19 -1
- package/dist/utils/define-visitors.cjs +74 -0
- package/dist/utils/define-visitors.mjs +72 -1
- package/dist/utils/extract-classnames-from-value.cjs +34 -0
- package/dist/utils/extract-classnames-from-value.mjs +32 -1
- package/dist/utils/extract-range-from-node.cjs +18 -0
- package/dist/utils/extract-range-from-node.mjs +16 -1
- package/dist/utils/extract-value-from-node.cjs +23 -0
- package/dist/utils/extract-value-from-node.mjs +21 -1
- package/dist/utils/find-loc.cjs +40 -0
- package/dist/utils/find-loc.mjs +38 -1
- package/dist/utils/get-mastercss.cjs +16 -0
- package/dist/utils/get-mastercss.d.ts +1 -1
- package/dist/utils/get-mastercss.mjs +14 -1
- package/dist/utils/get-template-element-body.cjs +12 -0
- package/dist/utils/get-template-element-body.mjs +10 -1
- package/dist/utils/get-template-element-prefix.cjs +11 -0
- package/dist/utils/get-template-element-prefix.mjs +9 -1
- package/dist/utils/get-template-element-suffix.cjs +10 -0
- package/dist/utils/get-template-element-suffix.mjs +8 -1
- package/dist/utils/parse-node-recursive.cjs +122 -0
- package/dist/utils/parse-node-recursive.mjs +120 -1
- package/dist/utils/reorder-valid-classes-action.cjs +9 -0
- package/dist/utils/reorder-valid-classes-action.mjs +7 -1
- package/dist/utils/resolve-context.cjs +13 -0
- package/dist/utils/resolve-context.mjs +11 -1
- package/dist/utils/valid-rules-action.cjs +9 -0
- package/dist/utils/valid-rules-action.mjs +7 -1
- package/dist/utils/validate-action.cjs +9 -0
- package/dist/utils/validate-action.mjs +7 -1
- package/dist/utils/workers/reorder-valid-classes.cjs +15 -0
- package/dist/utils/workers/reorder-valid-classes.mjs +13 -1
- package/dist/utils/workers/valid-rules.cjs +23 -0
- package/dist/utils/workers/valid-rules.mjs +21 -1
- package/dist/utils/workers/validate.cjs +15 -0
- package/dist/utils/workers/validate.mjs +13 -1
- package/package.json +1 -1
- package/dist/configs/config.js +0 -1
- package/dist/configs/flat.js +0 -1
- package/dist/configs/recommended.js +0 -1
- package/dist/index.js +0 -1
- package/dist/plugin.js +0 -1
- package/dist/rules/class-collision.js +0 -1
- package/dist/rules/class-order.js +0 -1
- package/dist/rules/class-validation.js +0 -1
- package/dist/settings.js +0 -1
- package/dist/utils/are-declarations-equal.js +0 -1
- package/dist/utils/define-visitors.js +0 -1
- package/dist/utils/extract-classnames-from-value.js +0 -1
- package/dist/utils/extract-range-from-node.js +0 -1
- package/dist/utils/extract-value-from-node.js +0 -1
- package/dist/utils/find-loc.js +0 -1
- package/dist/utils/get-mastercss.js +0 -1
- package/dist/utils/get-template-element-body.js +0 -1
- package/dist/utils/get-template-element-prefix.js +0 -1
- package/dist/utils/get-template-element-suffix.js +0 -1
- package/dist/utils/parse-node-recursive.js +0 -1
- package/dist/utils/reorder-valid-classes-action.js +0 -1
- package/dist/utils/resolve-context.js +0 -1
- package/dist/utils/valid-rules-action.js +0 -1
- package/dist/utils/validate-action.js +0 -1
- package/dist/utils/workers/reorder-valid-classes.js +0 -1
- package/dist/utils/workers/valid-rules.js +0 -1
- package/dist/utils/workers/validate.js +0 -1
|
@@ -1 +1,194 @@
|
|
|
1
|
-
import
|
|
1
|
+
import defineVisitors from '../utils/define-visitors.mjs';
|
|
2
|
+
import resolveContext from '../utils/resolve-context.mjs';
|
|
3
|
+
import getTemplateElementBody from '../utils/get-template-element-body.mjs';
|
|
4
|
+
import getTemplateElementSuffix from '../utils/get-template-element-suffix.mjs';
|
|
5
|
+
import getTemplateElementPrefix from '../utils/get-template-element-prefix.mjs';
|
|
6
|
+
import extractValueFromNode from '../utils/extract-value-from-node.mjs';
|
|
7
|
+
import extractRangeFromNode from '../utils/extract-range-from-node.mjs';
|
|
8
|
+
import extractClassnamesFromValue from '../utils/extract-classnames-from-value.mjs';
|
|
9
|
+
import findLoc from '../utils/find-loc.mjs';
|
|
10
|
+
import reorderValidClassesAction from '../utils/reorder-valid-classes-action.mjs';
|
|
11
|
+
|
|
12
|
+
var classOrder = {
|
|
13
|
+
meta: {
|
|
14
|
+
docs: {
|
|
15
|
+
description: 'Enforce a consistent and logical order of classes',
|
|
16
|
+
category: 'Stylistic Issues',
|
|
17
|
+
recommended: false,
|
|
18
|
+
url: 'https://rc.css.master.co/docs/code-linting#consistent-class-order'
|
|
19
|
+
},
|
|
20
|
+
messages: {
|
|
21
|
+
invalidClassOrder: 'No consistent class order followed.'
|
|
22
|
+
},
|
|
23
|
+
fixable: 'code',
|
|
24
|
+
schema: [
|
|
25
|
+
{
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
calleeMatching: {
|
|
29
|
+
type: 'string'
|
|
30
|
+
},
|
|
31
|
+
classMatching: {
|
|
32
|
+
type: 'string'
|
|
33
|
+
},
|
|
34
|
+
ignoredKeys: {
|
|
35
|
+
type: 'array',
|
|
36
|
+
items: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
minLength: 0
|
|
39
|
+
},
|
|
40
|
+
uniqueItems: true
|
|
41
|
+
},
|
|
42
|
+
config: {
|
|
43
|
+
type: [
|
|
44
|
+
'string',
|
|
45
|
+
'object'
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
create: function(context) {
|
|
53
|
+
const { options, settings } = resolveContext(context);
|
|
54
|
+
const sourceCode = context.sourceCode;
|
|
55
|
+
const visitNode = (node, arg = null)=>{
|
|
56
|
+
let originalClassNamesValue = null;
|
|
57
|
+
let start = null;
|
|
58
|
+
let end = null;
|
|
59
|
+
let prefix = '';
|
|
60
|
+
let suffix = '';
|
|
61
|
+
let expStrings = [];
|
|
62
|
+
if (arg === null) {
|
|
63
|
+
originalClassNamesValue = extractValueFromNode(node);
|
|
64
|
+
const range = extractRangeFromNode(node);
|
|
65
|
+
if (node.type === 'TextAttribute') {
|
|
66
|
+
start = range[0];
|
|
67
|
+
end = range[1];
|
|
68
|
+
} else {
|
|
69
|
+
start = range[0] + 1;
|
|
70
|
+
end = range[1] - 1;
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
switch(arg.type){
|
|
74
|
+
case 'Identifier':
|
|
75
|
+
return;
|
|
76
|
+
case 'TemplateLiteral':
|
|
77
|
+
arg.expressions.forEach((exp)=>{
|
|
78
|
+
visitNode(node, exp);
|
|
79
|
+
});
|
|
80
|
+
originalClassNamesValue = sourceCode.getText(arg);
|
|
81
|
+
originalClassNamesValue = originalClassNamesValue.substring(1, originalClassNamesValue.length - 1);
|
|
82
|
+
expStrings = originalClassNamesValue.match(/\$\{(?:(?<!\\\\)(['"`]).*?(?<!\\\\)\1|[^}])*?\}/g) ?? [];
|
|
83
|
+
for(let i = 0; i < expStrings.length; i++){
|
|
84
|
+
originalClassNamesValue = originalClassNamesValue.replace(expStrings[i], `EXPRESSION_STRING_NUM_${i}`);
|
|
85
|
+
}
|
|
86
|
+
start = arg.range[0] + 1;
|
|
87
|
+
end = arg.range[1] - 1;
|
|
88
|
+
break;
|
|
89
|
+
case 'ConditionalExpression':
|
|
90
|
+
visitNode(node, arg.consequent);
|
|
91
|
+
visitNode(node, arg.alternate);
|
|
92
|
+
return;
|
|
93
|
+
case 'LogicalExpression':
|
|
94
|
+
visitNode(node, arg.right);
|
|
95
|
+
return;
|
|
96
|
+
case 'ArrayExpression':
|
|
97
|
+
arg.elements.forEach((el)=>{
|
|
98
|
+
visitNode(node, el);
|
|
99
|
+
});
|
|
100
|
+
return;
|
|
101
|
+
case 'ObjectExpression':
|
|
102
|
+
const isUsedByClassNamesPlugin = node.callee && node.callee.name === 'classnames';
|
|
103
|
+
const isVue = node.key && node.key.type === 'VDirectiveKey';
|
|
104
|
+
arg.properties.forEach((prop)=>{
|
|
105
|
+
const propVal = isUsedByClassNamesPlugin || isVue ? prop.key : prop.value;
|
|
106
|
+
visitNode(node, propVal);
|
|
107
|
+
});
|
|
108
|
+
return;
|
|
109
|
+
case 'Property':
|
|
110
|
+
visitNode(node, arg.key);
|
|
111
|
+
break;
|
|
112
|
+
case 'Literal':
|
|
113
|
+
originalClassNamesValue = arg.value;
|
|
114
|
+
start = arg.range[0] + 1;
|
|
115
|
+
end = arg.range[1] - 1;
|
|
116
|
+
break;
|
|
117
|
+
case 'SvelteLiteral':
|
|
118
|
+
originalClassNamesValue = arg.value;
|
|
119
|
+
if (originalClassNamesValue === '') {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
start = arg.range[0];
|
|
123
|
+
end = arg.range[1];
|
|
124
|
+
break;
|
|
125
|
+
case 'TemplateElement':
|
|
126
|
+
originalClassNamesValue = arg.value.raw;
|
|
127
|
+
if (originalClassNamesValue === '') {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
start = arg.range[0];
|
|
131
|
+
end = arg.range[1];
|
|
132
|
+
// https://github.com/eslint/eslint/issues/13360
|
|
133
|
+
// The problem is that range computation includes the backticks (`test`)
|
|
134
|
+
// but value.raw does not include them, so there is a mismatch.
|
|
135
|
+
// start/end does not include the backticks, therefore it matches value.raw.
|
|
136
|
+
const txt = context.sourceCode.getText(arg);
|
|
137
|
+
prefix = getTemplateElementPrefix(txt, originalClassNamesValue);
|
|
138
|
+
suffix = getTemplateElementSuffix(txt, originalClassNamesValue);
|
|
139
|
+
originalClassNamesValue = getTemplateElementBody(txt, prefix, suffix);
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const { classNames, whitespaces, headSpace, tailSpace } = extractClassnamesFromValue(originalClassNamesValue);
|
|
144
|
+
if (classNames.length <= 1) {
|
|
145
|
+
// Don't run sorting for a single or empty className
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
let orderedClassNames = reorderValidClassesAction(classNames, settings.config);
|
|
149
|
+
orderedClassNames = classNames.filter((x)=>!orderedClassNames.includes(x)).concat(orderedClassNames).filter((x)=>x.trim() !== '');
|
|
150
|
+
// Generates the validated/sorted attribute value
|
|
151
|
+
let validatedClassNamesValue = '';
|
|
152
|
+
for(let i = 0; i < orderedClassNames.length; i++){
|
|
153
|
+
const w = whitespaces[i] ?? '';
|
|
154
|
+
const cls = orderedClassNames[i];
|
|
155
|
+
validatedClassNamesValue += headSpace ? `${w}${cls}` : `${cls}${w}`;
|
|
156
|
+
if (cls) {
|
|
157
|
+
if (!tailSpace && i === orderedClassNames.length - 1) {
|
|
158
|
+
validatedClassNamesValue = validatedClassNamesValue.replace(/\s+$/, '');
|
|
159
|
+
}
|
|
160
|
+
if (headSpace && tailSpace && i === orderedClassNames.length - 1) {
|
|
161
|
+
validatedClassNamesValue += whitespaces[whitespaces.length - 1] ?? '';
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
for(let i = 0; i < expStrings.length; i++){
|
|
166
|
+
originalClassNamesValue = originalClassNamesValue.replace(`EXPRESSION_STRING_NUM_${i}`, expStrings[i]);
|
|
167
|
+
validatedClassNamesValue = validatedClassNamesValue.replace(`EXPRESSION_STRING_NUM_${i}`, expStrings[i]);
|
|
168
|
+
}
|
|
169
|
+
if (originalClassNamesValue !== validatedClassNamesValue) {
|
|
170
|
+
validatedClassNamesValue = prefix + validatedClassNamesValue + suffix;
|
|
171
|
+
const sourceCodeLines = sourceCode.lines;
|
|
172
|
+
const nodeStartLine = node.loc.start.line;
|
|
173
|
+
const nodeEndLine = node.loc.end.line;
|
|
174
|
+
const descriptor = {
|
|
175
|
+
loc: findLoc(originalClassNamesValue, sourceCodeLines, nodeStartLine, nodeEndLine),
|
|
176
|
+
messageId: 'invalidClassOrder',
|
|
177
|
+
fix: function(fixer) {
|
|
178
|
+
return fixer.replaceTextRange([
|
|
179
|
+
start,
|
|
180
|
+
end
|
|
181
|
+
], validatedClassNamesValue);
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
context.report(descriptor);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
return defineVisitors({
|
|
188
|
+
context,
|
|
189
|
+
settings
|
|
190
|
+
}, visitNode);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export { classOrder as default };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var defineVisitors = require('../utils/define-visitors.cjs');
|
|
4
|
+
var resolveContext = require('../utils/resolve-context.cjs');
|
|
5
|
+
var findLoc = require('../utils/find-loc.cjs');
|
|
6
|
+
var parseNodeRecursive = require('../utils/parse-node-recursive.cjs');
|
|
7
|
+
var validateAction = require('../utils/validate-action.cjs');
|
|
8
|
+
|
|
9
|
+
var classValidation = {
|
|
10
|
+
meta: {
|
|
11
|
+
docs: {
|
|
12
|
+
description: 'Detect syntax errors early when writing classes',
|
|
13
|
+
category: 'Stylistic Issues',
|
|
14
|
+
recommended: false,
|
|
15
|
+
url: 'https://rc.css.master.co/docs/code-linting#syntax-error-checks'
|
|
16
|
+
},
|
|
17
|
+
messages: {
|
|
18
|
+
invalidClass: '{{message}}',
|
|
19
|
+
disallowUnknownClass: '{{message}}'
|
|
20
|
+
},
|
|
21
|
+
fixable: null,
|
|
22
|
+
schema: [
|
|
23
|
+
{
|
|
24
|
+
type: 'object',
|
|
25
|
+
properties: {
|
|
26
|
+
calleeMatching: {
|
|
27
|
+
type: 'string'
|
|
28
|
+
},
|
|
29
|
+
classMatching: {
|
|
30
|
+
type: 'string'
|
|
31
|
+
},
|
|
32
|
+
ignoredKeys: {
|
|
33
|
+
type: 'array',
|
|
34
|
+
items: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
minLength: 0
|
|
37
|
+
},
|
|
38
|
+
uniqueItems: true
|
|
39
|
+
},
|
|
40
|
+
config: {
|
|
41
|
+
type: [
|
|
42
|
+
'string',
|
|
43
|
+
'object'
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
create: function(context) {
|
|
51
|
+
const { options, settings } = resolveContext(context);
|
|
52
|
+
const visitNode = (node, arg = null)=>{
|
|
53
|
+
parseNodeRecursive.parseNodeRecursive(node, arg, (classNames, node)=>{
|
|
54
|
+
const sourceCode = context.sourceCode;
|
|
55
|
+
const sourceCodeLines = sourceCode.lines;
|
|
56
|
+
const nodeStartLine = node.loc.start.line;
|
|
57
|
+
const nodeEndLine = node.loc.end.line;
|
|
58
|
+
for (const className of classNames){
|
|
59
|
+
const { isMasterCSS, errors } = validateAction(className, settings.config);
|
|
60
|
+
if (errors.length > 0) {
|
|
61
|
+
for (const error of errors){
|
|
62
|
+
if (isMasterCSS) {
|
|
63
|
+
context.report({
|
|
64
|
+
loc: findLoc(className, sourceCodeLines, nodeStartLine, nodeEndLine),
|
|
65
|
+
messageId: 'invalidClass',
|
|
66
|
+
data: {
|
|
67
|
+
message: error.message + '.'
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
} else if (options.disallowUnknownClass) {
|
|
71
|
+
context.report({
|
|
72
|
+
loc: findLoc(className, sourceCodeLines, nodeStartLine, nodeEndLine),
|
|
73
|
+
messageId: 'disallowUnknownClass',
|
|
74
|
+
data: {
|
|
75
|
+
message: `"${className}" is not a valid or known class.`
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}, false, false, settings.ignoredKeys, context);
|
|
83
|
+
};
|
|
84
|
+
return defineVisitors({
|
|
85
|
+
context,
|
|
86
|
+
settings
|
|
87
|
+
}, visitNode);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
module.exports = classValidation;
|
|
@@ -1 +1,89 @@
|
|
|
1
|
-
import
|
|
1
|
+
import defineVisitors from '../utils/define-visitors.mjs';
|
|
2
|
+
import resolveContext from '../utils/resolve-context.mjs';
|
|
3
|
+
import findLoc from '../utils/find-loc.mjs';
|
|
4
|
+
import { parseNodeRecursive } from '../utils/parse-node-recursive.mjs';
|
|
5
|
+
import validateAction from '../utils/validate-action.mjs';
|
|
6
|
+
|
|
7
|
+
var classValidation = {
|
|
8
|
+
meta: {
|
|
9
|
+
docs: {
|
|
10
|
+
description: 'Detect syntax errors early when writing classes',
|
|
11
|
+
category: 'Stylistic Issues',
|
|
12
|
+
recommended: false,
|
|
13
|
+
url: 'https://rc.css.master.co/docs/code-linting#syntax-error-checks'
|
|
14
|
+
},
|
|
15
|
+
messages: {
|
|
16
|
+
invalidClass: '{{message}}',
|
|
17
|
+
disallowUnknownClass: '{{message}}'
|
|
18
|
+
},
|
|
19
|
+
fixable: null,
|
|
20
|
+
schema: [
|
|
21
|
+
{
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: {
|
|
24
|
+
calleeMatching: {
|
|
25
|
+
type: 'string'
|
|
26
|
+
},
|
|
27
|
+
classMatching: {
|
|
28
|
+
type: 'string'
|
|
29
|
+
},
|
|
30
|
+
ignoredKeys: {
|
|
31
|
+
type: 'array',
|
|
32
|
+
items: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
minLength: 0
|
|
35
|
+
},
|
|
36
|
+
uniqueItems: true
|
|
37
|
+
},
|
|
38
|
+
config: {
|
|
39
|
+
type: [
|
|
40
|
+
'string',
|
|
41
|
+
'object'
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
create: function(context) {
|
|
49
|
+
const { options, settings } = resolveContext(context);
|
|
50
|
+
const visitNode = (node, arg = null)=>{
|
|
51
|
+
parseNodeRecursive(node, arg, (classNames, node)=>{
|
|
52
|
+
const sourceCode = context.sourceCode;
|
|
53
|
+
const sourceCodeLines = sourceCode.lines;
|
|
54
|
+
const nodeStartLine = node.loc.start.line;
|
|
55
|
+
const nodeEndLine = node.loc.end.line;
|
|
56
|
+
for (const className of classNames){
|
|
57
|
+
const { isMasterCSS, errors } = validateAction(className, settings.config);
|
|
58
|
+
if (errors.length > 0) {
|
|
59
|
+
for (const error of errors){
|
|
60
|
+
if (isMasterCSS) {
|
|
61
|
+
context.report({
|
|
62
|
+
loc: findLoc(className, sourceCodeLines, nodeStartLine, nodeEndLine),
|
|
63
|
+
messageId: 'invalidClass',
|
|
64
|
+
data: {
|
|
65
|
+
message: error.message + '.'
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
} else if (options.disallowUnknownClass) {
|
|
69
|
+
context.report({
|
|
70
|
+
loc: findLoc(className, sourceCodeLines, nodeStartLine, nodeEndLine),
|
|
71
|
+
messageId: 'disallowUnknownClass',
|
|
72
|
+
data: {
|
|
73
|
+
message: `"${className}" is not a valid or known class.`
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}, false, false, settings.ignoredKeys, context);
|
|
81
|
+
};
|
|
82
|
+
return defineVisitors({
|
|
83
|
+
context,
|
|
84
|
+
settings
|
|
85
|
+
}, visitNode);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export { classValidation as default };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const settings = {
|
|
4
|
+
calleeMatching: '^(classnames|clsx|ctl|cva|cv|classVariant|styled(?:\\.\\w+)?)',
|
|
5
|
+
classMatching: '^class(Name)?$',
|
|
6
|
+
ignoredKeys: [
|
|
7
|
+
'compoundVariants',
|
|
8
|
+
'defaultVariants'
|
|
9
|
+
],
|
|
10
|
+
config: 'master.css'
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
module.exports = settings;
|
package/dist/settings.mjs
CHANGED
|
@@ -1 +1,11 @@
|
|
|
1
|
-
const
|
|
1
|
+
const settings = {
|
|
2
|
+
calleeMatching: '^(classnames|clsx|ctl|cva|cv|classVariant|styled(?:\\.\\w+)?)',
|
|
3
|
+
classMatching: '^class(Name)?$',
|
|
4
|
+
ignoredKeys: [
|
|
5
|
+
'compoundVariants',
|
|
6
|
+
'defaultVariants'
|
|
7
|
+
],
|
|
8
|
+
config: 'master.css'
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export { settings as default };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function areDeclarationsEqual(aDeclarations, bDeclarations) {
|
|
4
|
+
// 获取对象A和B的所有属性名
|
|
5
|
+
const aKeys = Object.keys(aDeclarations);
|
|
6
|
+
const bKeys = Object.keys(bDeclarations);
|
|
7
|
+
// 如果属性数量不相等,返回false
|
|
8
|
+
if (aKeys.length !== bKeys.length) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
// 检查对象A的属性是否都存在于对象B中
|
|
12
|
+
for (const key of aKeys){
|
|
13
|
+
if (!Object.prototype.hasOwnProperty.call(bDeclarations, key)) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
// 如果所有属性都匹配,返回true
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = areDeclarationsEqual;
|
|
@@ -1 +1,19 @@
|
|
|
1
|
-
function
|
|
1
|
+
function areDeclarationsEqual(aDeclarations, bDeclarations) {
|
|
2
|
+
// 获取对象A和B的所有属性名
|
|
3
|
+
const aKeys = Object.keys(aDeclarations);
|
|
4
|
+
const bKeys = Object.keys(bDeclarations);
|
|
5
|
+
// 如果属性数量不相等,返回false
|
|
6
|
+
if (aKeys.length !== bKeys.length) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
// 检查对象A的属性是否都存在于对象B中
|
|
10
|
+
for (const key of aKeys){
|
|
11
|
+
if (!Object.prototype.hasOwnProperty.call(bDeclarations, key)) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
// 如果所有属性都匹配,返回true
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export { areDeclarationsEqual as default };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function defineVisitors({ context, settings }, visitNode) {
|
|
4
|
+
const isFnNode = (node)=>{
|
|
5
|
+
let calleeName = '';
|
|
6
|
+
const calleeNode = node.callee || node.tag;
|
|
7
|
+
if (calleeNode.type === 'Identifier') {
|
|
8
|
+
calleeName = calleeNode.name;
|
|
9
|
+
}
|
|
10
|
+
if (calleeNode.type === 'MemberExpression') {
|
|
11
|
+
calleeName = `${calleeNode.object.name}.${calleeNode.property.name}`;
|
|
12
|
+
}
|
|
13
|
+
return new RegExp(settings.calleeMatching).test(calleeName);
|
|
14
|
+
};
|
|
15
|
+
const CallExpression = function(node) {
|
|
16
|
+
if (!isFnNode(node)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
node.arguments.forEach((arg)=>{
|
|
20
|
+
visitNode(node, arg);
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
const classMatchingRegex = new RegExp(settings.classMatching);
|
|
24
|
+
const scriptVisitor = {
|
|
25
|
+
CallExpression,
|
|
26
|
+
JSXAttribute: function(node) {
|
|
27
|
+
if (!node.name || !classMatchingRegex.test(node.name.name)) return;
|
|
28
|
+
if (node.value && node.value.type === 'Literal') {
|
|
29
|
+
visitNode(node);
|
|
30
|
+
} else if (node.value && node.value.type === 'JSXExpressionContainer') {
|
|
31
|
+
visitNode(node, node.value.expression);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
SvelteAttribute: function(node) {
|
|
35
|
+
if (!node.key?.name || !classMatchingRegex.test(node.key.name)) return;
|
|
36
|
+
for (const eachValue of node.value){
|
|
37
|
+
visitNode(node, eachValue);
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
TextAttribute: function(node) {
|
|
41
|
+
if (!node.name || !classMatchingRegex.test(node.name)) return;
|
|
42
|
+
visitNode(node);
|
|
43
|
+
},
|
|
44
|
+
TaggedTemplateExpression: function(node) {
|
|
45
|
+
if (isFnNode(node)) {
|
|
46
|
+
visitNode(node, node.quasi);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const templateBodyVisitor = {
|
|
52
|
+
CallExpression,
|
|
53
|
+
VAttribute: function(node) {
|
|
54
|
+
if (node.value && node.value.type === 'VLiteral') {
|
|
55
|
+
visitNode(node);
|
|
56
|
+
} else if (node.value && node.value.type === 'VExpressionContainer' && node.value.expression.type === 'ArrayExpression') {
|
|
57
|
+
node.value.expression.elements.forEach((arg)=>{
|
|
58
|
+
visitNode(node, arg);
|
|
59
|
+
});
|
|
60
|
+
} else if (node.value && node.value.type === 'VExpressionContainer' && node.value.expression.type === 'ObjectExpression') {
|
|
61
|
+
node.value.expression.properties.forEach((prop)=>{
|
|
62
|
+
visitNode(node, prop);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
if (context.sourceCode.parserServices == null || context.sourceCode.parserServices.defineTemplateBodyVisitor == null) {
|
|
68
|
+
return scriptVisitor;
|
|
69
|
+
} else {
|
|
70
|
+
return context.sourceCode.parserServices.defineTemplateBodyVisitor(templateBodyVisitor, scriptVisitor);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = defineVisitors;
|
|
@@ -1 +1,72 @@
|
|
|
1
|
-
function
|
|
1
|
+
function defineVisitors({ context, settings }, visitNode) {
|
|
2
|
+
const isFnNode = (node)=>{
|
|
3
|
+
let calleeName = '';
|
|
4
|
+
const calleeNode = node.callee || node.tag;
|
|
5
|
+
if (calleeNode.type === 'Identifier') {
|
|
6
|
+
calleeName = calleeNode.name;
|
|
7
|
+
}
|
|
8
|
+
if (calleeNode.type === 'MemberExpression') {
|
|
9
|
+
calleeName = `${calleeNode.object.name}.${calleeNode.property.name}`;
|
|
10
|
+
}
|
|
11
|
+
return new RegExp(settings.calleeMatching).test(calleeName);
|
|
12
|
+
};
|
|
13
|
+
const CallExpression = function(node) {
|
|
14
|
+
if (!isFnNode(node)) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
node.arguments.forEach((arg)=>{
|
|
18
|
+
visitNode(node, arg);
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
const classMatchingRegex = new RegExp(settings.classMatching);
|
|
22
|
+
const scriptVisitor = {
|
|
23
|
+
CallExpression,
|
|
24
|
+
JSXAttribute: function(node) {
|
|
25
|
+
if (!node.name || !classMatchingRegex.test(node.name.name)) return;
|
|
26
|
+
if (node.value && node.value.type === 'Literal') {
|
|
27
|
+
visitNode(node);
|
|
28
|
+
} else if (node.value && node.value.type === 'JSXExpressionContainer') {
|
|
29
|
+
visitNode(node, node.value.expression);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
SvelteAttribute: function(node) {
|
|
33
|
+
if (!node.key?.name || !classMatchingRegex.test(node.key.name)) return;
|
|
34
|
+
for (const eachValue of node.value){
|
|
35
|
+
visitNode(node, eachValue);
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
TextAttribute: function(node) {
|
|
39
|
+
if (!node.name || !classMatchingRegex.test(node.name)) return;
|
|
40
|
+
visitNode(node);
|
|
41
|
+
},
|
|
42
|
+
TaggedTemplateExpression: function(node) {
|
|
43
|
+
if (isFnNode(node)) {
|
|
44
|
+
visitNode(node, node.quasi);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const templateBodyVisitor = {
|
|
50
|
+
CallExpression,
|
|
51
|
+
VAttribute: function(node) {
|
|
52
|
+
if (node.value && node.value.type === 'VLiteral') {
|
|
53
|
+
visitNode(node);
|
|
54
|
+
} else if (node.value && node.value.type === 'VExpressionContainer' && node.value.expression.type === 'ArrayExpression') {
|
|
55
|
+
node.value.expression.elements.forEach((arg)=>{
|
|
56
|
+
visitNode(node, arg);
|
|
57
|
+
});
|
|
58
|
+
} else if (node.value && node.value.type === 'VExpressionContainer' && node.value.expression.type === 'ObjectExpression') {
|
|
59
|
+
node.value.expression.properties.forEach((prop)=>{
|
|
60
|
+
visitNode(node, prop);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
if (context.sourceCode.parserServices == null || context.sourceCode.parserServices.defineTemplateBodyVisitor == null) {
|
|
66
|
+
return scriptVisitor;
|
|
67
|
+
} else {
|
|
68
|
+
return context.sourceCode.parserServices.defineTemplateBodyVisitor(templateBodyVisitor, scriptVisitor);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { defineVisitors as default };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const separatorRegEx = /([\t\n\f\r ]+)/;
|
|
4
|
+
function extractClassnamesFromValue(classStr) {
|
|
5
|
+
if (typeof classStr !== 'string') {
|
|
6
|
+
return {
|
|
7
|
+
classNames: [],
|
|
8
|
+
whitespaces: [],
|
|
9
|
+
headSpace: false,
|
|
10
|
+
tailSpace: false
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
const parts = classStr.split(separatorRegEx);
|
|
14
|
+
if (parts[0] === '') {
|
|
15
|
+
parts.shift();
|
|
16
|
+
}
|
|
17
|
+
if (parts[parts.length - 1] === '') {
|
|
18
|
+
parts.pop();
|
|
19
|
+
}
|
|
20
|
+
const headSpace = separatorRegEx.test(parts[0]);
|
|
21
|
+
const tailSpace = separatorRegEx.test(parts[parts.length - 1]);
|
|
22
|
+
const isClass = (_, i)=>headSpace ? i % 2 !== 0 : i % 2 === 0;
|
|
23
|
+
const isNotClass = (_, i)=>headSpace ? i % 2 === 0 : i % 2 !== 0;
|
|
24
|
+
const classNames = parts.filter(isClass);
|
|
25
|
+
const whitespaces = parts.filter(isNotClass);
|
|
26
|
+
return {
|
|
27
|
+
classNames: classNames,
|
|
28
|
+
whitespaces: whitespaces,
|
|
29
|
+
headSpace: headSpace,
|
|
30
|
+
tailSpace: tailSpace
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = extractClassnamesFromValue;
|