@master/eslint-plugin-css 2.0.0-rc.4 → 2.0.0-rc.41
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 +2 -2
- package/dist/create-rule.cjs +8 -0
- package/dist/create-rule.d.ts +3 -0
- package/dist/create-rule.mjs +6 -0
- package/dist/functions/filter-collision-classes.cjs +29 -0
- package/dist/functions/filter-collision-classes.d.ts +2 -0
- package/dist/functions/filter-collision-classes.mjs +27 -0
- package/dist/index.cjs +39 -0
- package/dist/index.d.ts +61 -1
- package/dist/index.mjs +37 -1
- package/dist/plugin.cjs +18 -0
- package/dist/plugin.d.ts +10 -2
- package/dist/plugin.mjs +16 -1
- package/dist/rules/class-collision.cjs +69 -0
- package/dist/rules/class-collision.d.ts +1 -2
- package/dist/rules/class-collision.mjs +67 -1
- package/dist/rules/class-order.cjs +174 -0
- package/dist/rules/class-order.d.ts +1 -2
- package/dist/rules/class-order.mjs +172 -1
- package/dist/rules/class-validation.cjs +70 -0
- package/dist/rules/class-validation.d.ts +1 -2
- package/dist/rules/class-validation.mjs +68 -1
- package/dist/settings-schema.cjs +35 -0
- package/dist/settings-schema.d.ts +3 -0
- package/dist/settings-schema.mjs +33 -0
- package/dist/settings.cjs +16 -0
- package/dist/settings.d.ts +10 -2
- package/dist/settings.mjs +14 -1
- package/dist/utils/define-visitors.cjs +92 -0
- package/dist/utils/define-visitors.d.ts +6 -4
- package/dist/utils/define-visitors.mjs +90 -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 +48 -0
- package/dist/utils/find-loc.mjs +46 -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/index-of-all.cjs +12 -0
- package/dist/utils/index-of-all.d.ts +1 -0
- package/dist/utils/index-of-all.mjs +10 -0
- package/dist/utils/parse-node-recursive.cjs +130 -0
- package/dist/utils/parse-node-recursive.d.ts +2 -2
- package/dist/utils/parse-node-recursive.mjs +128 -1
- package/dist/utils/resolve-context.cjs +35 -0
- package/dist/utils/resolve-context.d.ts +11 -2
- package/dist/utils/resolve-context.mjs +33 -1
- package/package.json +1 -1
- package/dist/configs/config.d.ts +0 -13
- package/dist/configs/config.js +0 -1
- package/dist/configs/config.mjs +0 -1
- package/dist/configs/flat.d.ts +0 -16
- package/dist/configs/flat.js +0 -1
- package/dist/configs/flat.mjs +0 -1
- package/dist/configs/recommended.d.ts +0 -14
- package/dist/configs/recommended.js +0 -1
- package/dist/configs/recommended.mjs +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.d.ts +0 -1
- package/dist/utils/are-declarations-equal.js +0 -1
- package/dist/utils/are-declarations-equal.mjs +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.d.ts +0 -2
- package/dist/utils/get-mastercss.js +0 -1
- package/dist/utils/get-mastercss.mjs +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.d.ts +0 -3
- package/dist/utils/reorder-valid-classes-action.js +0 -1
- package/dist/utils/reorder-valid-classes-action.mjs +0 -1
- package/dist/utils/resolve-context.js +0 -1
- package/dist/utils/valid-rules-action.d.ts +0 -3
- package/dist/utils/valid-rules-action.js +0 -1
- package/dist/utils/valid-rules-action.mjs +0 -1
- package/dist/utils/validate-action.d.ts +0 -3
- package/dist/utils/validate-action.js +0 -1
- package/dist/utils/validate-action.mjs +0 -1
- package/dist/utils/workers/reorder-valid-classes.d.ts +0 -2
- package/dist/utils/workers/reorder-valid-classes.js +0 -1
- package/dist/utils/workers/reorder-valid-classes.mjs +0 -1
- package/dist/utils/workers/valid-rules.d.ts +0 -2
- package/dist/utils/workers/valid-rules.js +0 -1
- package/dist/utils/workers/valid-rules.mjs +0 -1
- package/dist/utils/workers/validate.d.ts +0 -5
- package/dist/utils/workers/validate.js +0 -1
- package/dist/utils/workers/validate.mjs +0 -1
|
@@ -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;
|
|
@@ -1 +1,32 @@
|
|
|
1
|
-
const
|
|
1
|
+
const separatorRegEx = /([\t\n\f\r ]+)/;
|
|
2
|
+
function extractClassnamesFromValue(classStr) {
|
|
3
|
+
if (typeof classStr !== 'string') {
|
|
4
|
+
return {
|
|
5
|
+
classNames: [],
|
|
6
|
+
whitespaces: [],
|
|
7
|
+
headSpace: false,
|
|
8
|
+
tailSpace: false
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
const parts = classStr.split(separatorRegEx);
|
|
12
|
+
if (parts[0] === '') {
|
|
13
|
+
parts.shift();
|
|
14
|
+
}
|
|
15
|
+
if (parts[parts.length - 1] === '') {
|
|
16
|
+
parts.pop();
|
|
17
|
+
}
|
|
18
|
+
const headSpace = separatorRegEx.test(parts[0]);
|
|
19
|
+
const tailSpace = separatorRegEx.test(parts[parts.length - 1]);
|
|
20
|
+
const isClass = (_, i)=>headSpace ? i % 2 !== 0 : i % 2 === 0;
|
|
21
|
+
const isNotClass = (_, i)=>headSpace ? i % 2 === 0 : i % 2 !== 0;
|
|
22
|
+
const classNames = parts.filter(isClass);
|
|
23
|
+
const whitespaces = parts.filter(isNotClass);
|
|
24
|
+
return {
|
|
25
|
+
classNames: classNames,
|
|
26
|
+
whitespaces: whitespaces,
|
|
27
|
+
headSpace: headSpace,
|
|
28
|
+
tailSpace: tailSpace
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { extractClassnamesFromValue as default };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function extractRangeFromNode(node) {
|
|
4
|
+
if (node.type === 'TextAttribute' && node.name === 'class') {
|
|
5
|
+
return [
|
|
6
|
+
node.valueSpan.fullStart.offset,
|
|
7
|
+
node.valueSpan.end.offset
|
|
8
|
+
];
|
|
9
|
+
}
|
|
10
|
+
switch(node.value.type){
|
|
11
|
+
case 'JSXExpressionContainer':
|
|
12
|
+
return node.value.expression.range;
|
|
13
|
+
default:
|
|
14
|
+
return node.value.range;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = extractRangeFromNode;
|
|
@@ -1 +1,16 @@
|
|
|
1
|
-
function
|
|
1
|
+
function extractRangeFromNode(node) {
|
|
2
|
+
if (node.type === 'TextAttribute' && node.name === 'class') {
|
|
3
|
+
return [
|
|
4
|
+
node.valueSpan.fullStart.offset,
|
|
5
|
+
node.valueSpan.end.offset
|
|
6
|
+
];
|
|
7
|
+
}
|
|
8
|
+
switch(node.value.type){
|
|
9
|
+
case 'JSXExpressionContainer':
|
|
10
|
+
return node.value.expression.range;
|
|
11
|
+
default:
|
|
12
|
+
return node.value.range;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { extractRangeFromNode as default };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function extractValueFromNode(node) {
|
|
4
|
+
if (node.type === 'TextAttribute' && node.name === 'class') {
|
|
5
|
+
return node.value;
|
|
6
|
+
}
|
|
7
|
+
switch(node.value.type){
|
|
8
|
+
case 'JSXExpressionContainer':
|
|
9
|
+
return node.value.expression.value;
|
|
10
|
+
case 'VExpressionContainer':
|
|
11
|
+
switch(node.value.expression.type){
|
|
12
|
+
case 'ArrayExpression':
|
|
13
|
+
return node.value.expression.elements;
|
|
14
|
+
case 'ObjectExpression':
|
|
15
|
+
return node.value.expression.properties;
|
|
16
|
+
}
|
|
17
|
+
return node.value.expression.value;
|
|
18
|
+
default:
|
|
19
|
+
return node.value.value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = extractValueFromNode;
|
|
@@ -1 +1,21 @@
|
|
|
1
|
-
function
|
|
1
|
+
function extractValueFromNode(node) {
|
|
2
|
+
if (node.type === 'TextAttribute' && node.name === 'class') {
|
|
3
|
+
return node.value;
|
|
4
|
+
}
|
|
5
|
+
switch(node.value.type){
|
|
6
|
+
case 'JSXExpressionContainer':
|
|
7
|
+
return node.value.expression.value;
|
|
8
|
+
case 'VExpressionContainer':
|
|
9
|
+
switch(node.value.expression.type){
|
|
10
|
+
case 'ArrayExpression':
|
|
11
|
+
return node.value.expression.elements;
|
|
12
|
+
case 'ObjectExpression':
|
|
13
|
+
return node.value.expression.properties;
|
|
14
|
+
}
|
|
15
|
+
return node.value.expression.value;
|
|
16
|
+
default:
|
|
17
|
+
return node.value.value;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { extractValueFromNode as default };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var indexOfAll = require('./index-of-all.cjs');
|
|
4
|
+
|
|
5
|
+
function findLoc(text, lines, startLine, endLine) {
|
|
6
|
+
const targetLines = text.match(/.+(?:\r\n|\n)?/g);
|
|
7
|
+
let checkingTargetLine = 0;
|
|
8
|
+
let resultStart = null;
|
|
9
|
+
let checking = false;
|
|
10
|
+
for(let i = startLine; i <= endLine; i++){
|
|
11
|
+
const sourceCodeLine = lines[i - 1];
|
|
12
|
+
const content = targetLines[checkingTargetLine].replace(/\r\n|\n/, '');
|
|
13
|
+
const indexes = indexOfAll.indexOfAll(sourceCodeLine, content);
|
|
14
|
+
if (indexes.length > 0) {
|
|
15
|
+
for (const index of indexes){
|
|
16
|
+
if (index !== 0 && sourceCodeLine[index - 1].match(/\w/) || index + content.length < sourceCodeLine.length && sourceCodeLine[index + content.length].match(/\w/)) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (checkingTargetLine === 0) {
|
|
20
|
+
resultStart = {
|
|
21
|
+
line: i,
|
|
22
|
+
column: index
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
if (checkingTargetLine === targetLines.length - 1) {
|
|
26
|
+
return {
|
|
27
|
+
start: resultStart,
|
|
28
|
+
end: {
|
|
29
|
+
line: i,
|
|
30
|
+
column: index + text.length
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
checking = true;
|
|
35
|
+
checkingTargetLine++;
|
|
36
|
+
}
|
|
37
|
+
} else {
|
|
38
|
+
if (checking) {
|
|
39
|
+
checking = false;
|
|
40
|
+
checkingTargetLine = 0;
|
|
41
|
+
resultStart = null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = findLoc;
|
package/dist/utils/find-loc.mjs
CHANGED
|
@@ -1 +1,46 @@
|
|
|
1
|
-
|
|
1
|
+
import { indexOfAll } from './index-of-all.mjs';
|
|
2
|
+
|
|
3
|
+
function findLoc(text, lines, startLine, endLine) {
|
|
4
|
+
const targetLines = text.match(/.+(?:\r\n|\n)?/g);
|
|
5
|
+
let checkingTargetLine = 0;
|
|
6
|
+
let resultStart = null;
|
|
7
|
+
let checking = false;
|
|
8
|
+
for(let i = startLine; i <= endLine; i++){
|
|
9
|
+
const sourceCodeLine = lines[i - 1];
|
|
10
|
+
const content = targetLines[checkingTargetLine].replace(/\r\n|\n/, '');
|
|
11
|
+
const indexes = indexOfAll(sourceCodeLine, content);
|
|
12
|
+
if (indexes.length > 0) {
|
|
13
|
+
for (const index of indexes){
|
|
14
|
+
if (index !== 0 && sourceCodeLine[index - 1].match(/\w/) || index + content.length < sourceCodeLine.length && sourceCodeLine[index + content.length].match(/\w/)) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (checkingTargetLine === 0) {
|
|
18
|
+
resultStart = {
|
|
19
|
+
line: i,
|
|
20
|
+
column: index
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (checkingTargetLine === targetLines.length - 1) {
|
|
24
|
+
return {
|
|
25
|
+
start: resultStart,
|
|
26
|
+
end: {
|
|
27
|
+
line: i,
|
|
28
|
+
column: index + text.length
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
checking = true;
|
|
33
|
+
checkingTargetLine++;
|
|
34
|
+
}
|
|
35
|
+
} else {
|
|
36
|
+
if (checking) {
|
|
37
|
+
checking = false;
|
|
38
|
+
checkingTargetLine = 0;
|
|
39
|
+
resultStart = null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { findLoc as default };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function getTemplateElementBody(text, prefix, suffix) {
|
|
4
|
+
let arr = text.split(prefix);
|
|
5
|
+
arr.shift();
|
|
6
|
+
const body = arr.join(prefix);
|
|
7
|
+
arr = body.split(suffix);
|
|
8
|
+
arr.pop();
|
|
9
|
+
return arr.join(suffix);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
module.exports = getTemplateElementBody;
|
|
@@ -1 +1,10 @@
|
|
|
1
|
-
function
|
|
1
|
+
function getTemplateElementBody(text, prefix, suffix) {
|
|
2
|
+
let arr = text.split(prefix);
|
|
3
|
+
arr.shift();
|
|
4
|
+
const body = arr.join(prefix);
|
|
5
|
+
arr = body.split(suffix);
|
|
6
|
+
arr.pop();
|
|
7
|
+
return arr.join(suffix);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export { getTemplateElementBody as default };
|
|
@@ -1 +1,9 @@
|
|
|
1
|
-
function
|
|
1
|
+
function getTemplateElementPrefix(text, raw) {
|
|
2
|
+
const idx = text.indexOf(raw);
|
|
3
|
+
if (idx === 0) {
|
|
4
|
+
return '';
|
|
5
|
+
}
|
|
6
|
+
return text.split(raw).shift();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { getTemplateElementPrefix as default };
|
|
@@ -1 +1,8 @@
|
|
|
1
|
-
function
|
|
1
|
+
function getTemplateElementSuffix(text, raw) {
|
|
2
|
+
if (text.indexOf(raw) === -1) {
|
|
3
|
+
return '';
|
|
4
|
+
}
|
|
5
|
+
return text.split(raw).pop();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export { getTemplateElementSuffix as default };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function indexOfAll(arr: any[] | string, value: any): number[];
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var getTemplateElementPrefix = require('./get-template-element-prefix.cjs');
|
|
4
|
+
var getTemplateElementSuffix = require('./get-template-element-suffix.cjs');
|
|
5
|
+
var extractValueFromNode = require('./extract-value-from-node.cjs');
|
|
6
|
+
var extractClassnamesFromValue = require('./extract-classnames-from-value.cjs');
|
|
7
|
+
var extractRangeFromNode = require('./extract-range-from-node.cjs');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Inspect and parse an abstract syntax node and run a callback function
|
|
11
|
+
*
|
|
12
|
+
* @param {ASTNode} rootNode The current root node being parsed by eslint
|
|
13
|
+
* @param {ASTNode} childNode The AST node child argument being checked
|
|
14
|
+
* @param {Function} cb The callback function
|
|
15
|
+
* @param {Boolean} skipConditional Optional, indicate distinct parsing for conditional nodes
|
|
16
|
+
* @param {Boolean} isolate Optional, set internally to isolate parsing and validation on conditional children
|
|
17
|
+
* @param {Array} ignoredKeys Optional, set object keys which should not be parsed e.g. for `cva`
|
|
18
|
+
* @returns {void}
|
|
19
|
+
*/ function parseNodeRecursive(rootNode, childNode, cb, skipConditional = false, isolate = false, ignoredKeys = [], context) {
|
|
20
|
+
// TODO allow vue non litteral
|
|
21
|
+
let originalClassNamesValue;
|
|
22
|
+
let classNames;
|
|
23
|
+
let start = null;
|
|
24
|
+
let end = null;
|
|
25
|
+
let prefix = '';
|
|
26
|
+
let suffix = '';
|
|
27
|
+
if (childNode === null) {
|
|
28
|
+
originalClassNamesValue = extractValueFromNode(rootNode);
|
|
29
|
+
({ classNames } = extractClassnamesFromValue(originalClassNamesValue));
|
|
30
|
+
classNames = [
|
|
31
|
+
...new Set(classNames)
|
|
32
|
+
];
|
|
33
|
+
if (classNames.length === 0) {
|
|
34
|
+
// Don't run for empty className
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const range = extractRangeFromNode(rootNode);
|
|
38
|
+
if (rootNode.type === 'TextAttribute') {
|
|
39
|
+
start = range[0];
|
|
40
|
+
end = range[1];
|
|
41
|
+
} else {
|
|
42
|
+
start = range[0] + 1;
|
|
43
|
+
end = range[1] - 1;
|
|
44
|
+
}
|
|
45
|
+
cb(classNames, rootNode, originalClassNamesValue, start, end, prefix, suffix);
|
|
46
|
+
} else if (childNode === undefined) {
|
|
47
|
+
// Ignore invalid child candidates (probably inside complex TemplateLiteral)
|
|
48
|
+
return;
|
|
49
|
+
} else {
|
|
50
|
+
const forceIsolation = skipConditional ? true : isolate;
|
|
51
|
+
let expStrings = [];
|
|
52
|
+
switch(childNode.type){
|
|
53
|
+
case 'TemplateLiteral':
|
|
54
|
+
childNode.expressions.forEach((exp)=>{
|
|
55
|
+
parseNodeRecursive(rootNode, exp, cb, skipConditional, forceIsolation, ignoredKeys, context);
|
|
56
|
+
});
|
|
57
|
+
const sourceCode = context.sourceCode;
|
|
58
|
+
originalClassNamesValue = sourceCode.getText(childNode);
|
|
59
|
+
originalClassNamesValue = originalClassNamesValue.substring(1, originalClassNamesValue.length - 1);
|
|
60
|
+
expStrings = originalClassNamesValue.match(/\$\{(?:(?<!\\\\)(['"`]).*?(?<!\\\\)\1|[^}])*?\}/g) ?? [];
|
|
61
|
+
for(let i = 0; i < expStrings.length; i++){
|
|
62
|
+
originalClassNamesValue = originalClassNamesValue.replace(expStrings[i], `EXPRESSION_STRING_NUM_${i}`);
|
|
63
|
+
}
|
|
64
|
+
break;
|
|
65
|
+
case 'ConditionalExpression':
|
|
66
|
+
parseNodeRecursive(rootNode, childNode.consequent, cb, skipConditional, forceIsolation, ignoredKeys, context);
|
|
67
|
+
parseNodeRecursive(rootNode, childNode.alternate, cb, skipConditional, forceIsolation, ignoredKeys, context);
|
|
68
|
+
return;
|
|
69
|
+
case 'LogicalExpression':
|
|
70
|
+
parseNodeRecursive(rootNode, childNode.right, cb, skipConditional, forceIsolation, ignoredKeys, context);
|
|
71
|
+
return;
|
|
72
|
+
case 'ArrayExpression':
|
|
73
|
+
childNode.elements.forEach((el)=>{
|
|
74
|
+
parseNodeRecursive(rootNode, el, cb, skipConditional, forceIsolation, ignoredKeys, context);
|
|
75
|
+
});
|
|
76
|
+
return;
|
|
77
|
+
case 'ObjectExpression':
|
|
78
|
+
childNode.properties.forEach((prop)=>{
|
|
79
|
+
const isUsedByClassNamesPlugin = rootNode.callee && rootNode.callee.name === 'classnames';
|
|
80
|
+
if (prop.type === 'SpreadElement') {
|
|
81
|
+
// Ignore spread elements
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (prop.key.type === 'Identifier' && ignoredKeys.includes(prop.key.name)) {
|
|
85
|
+
// Ignore specific keys defined in settings
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
parseNodeRecursive(rootNode, isUsedByClassNamesPlugin ? prop.key : prop.value, cb, skipConditional, forceIsolation, ignoredKeys, context);
|
|
89
|
+
});
|
|
90
|
+
return;
|
|
91
|
+
case 'Property':
|
|
92
|
+
parseNodeRecursive(rootNode, childNode.key, cb, skipConditional, forceIsolation, ignoredKeys, context);
|
|
93
|
+
return;
|
|
94
|
+
case 'Literal':
|
|
95
|
+
originalClassNamesValue = childNode.value;
|
|
96
|
+
start = childNode.range[0] + 1;
|
|
97
|
+
end = childNode.range[1] - 1;
|
|
98
|
+
break;
|
|
99
|
+
case 'SvelteLiteral':
|
|
100
|
+
originalClassNamesValue = childNode.value;
|
|
101
|
+
start = childNode.range[0];
|
|
102
|
+
end = childNode.range[1];
|
|
103
|
+
break;
|
|
104
|
+
case 'TemplateElement':
|
|
105
|
+
originalClassNamesValue = childNode.value.raw;
|
|
106
|
+
start = childNode.range[0];
|
|
107
|
+
end = childNode.range[1];
|
|
108
|
+
// eslint-disable-next-line no-case-declarations
|
|
109
|
+
const txt = context?.sourceCode.getText(childNode) ?? '';
|
|
110
|
+
prefix = getTemplateElementPrefix(txt, originalClassNamesValue);
|
|
111
|
+
suffix = getTemplateElementSuffix(txt, originalClassNamesValue);
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
for(let i = 0; i < expStrings.length; i++){
|
|
115
|
+
originalClassNamesValue = originalClassNamesValue.replace(`EXPRESSION_STRING_NUM_${i}`, expStrings[i]);
|
|
116
|
+
}
|
|
117
|
+
({ classNames } = extractClassnamesFromValue(originalClassNamesValue));
|
|
118
|
+
classNames = [
|
|
119
|
+
...new Set(classNames)
|
|
120
|
+
];
|
|
121
|
+
if (classNames.length === 0) {
|
|
122
|
+
// Don't run for empty className
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const targetNode = isolate ? null : rootNode;
|
|
126
|
+
cb(classNames, targetNode, originalClassNamesValue, start, end, prefix, suffix);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
exports.parseNodeRecursive = parseNodeRecursive;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { RuleContext } from '@typescript-eslint/utils/ts-eslint';
|
|
2
2
|
/**
|
|
3
3
|
* Inspect and parse an abstract syntax node and run a callback function
|
|
4
4
|
*
|
|
@@ -10,4 +10,4 @@ import { Rule } from 'eslint';
|
|
|
10
10
|
* @param {Array} ignoredKeys Optional, set object keys which should not be parsed e.g. for `cva`
|
|
11
11
|
* @returns {void}
|
|
12
12
|
*/
|
|
13
|
-
export declare function parseNodeRecursive(rootNode: any, childNode: any, cb: any, skipConditional
|
|
13
|
+
export declare function parseNodeRecursive(rootNode: any, childNode: any, cb: any, skipConditional: boolean, isolate: boolean, ignoredKeys: any[], context: RuleContext<any, any>): void;
|
|
@@ -1 +1,128 @@
|
|
|
1
|
-
import
|
|
1
|
+
import getTemplateElementPrefix from './get-template-element-prefix.mjs';
|
|
2
|
+
import getTemplateElementSuffix from './get-template-element-suffix.mjs';
|
|
3
|
+
import extractValueFromNode from './extract-value-from-node.mjs';
|
|
4
|
+
import extractClassnamesFromValue from './extract-classnames-from-value.mjs';
|
|
5
|
+
import extractRangeFromNode from './extract-range-from-node.mjs';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Inspect and parse an abstract syntax node and run a callback function
|
|
9
|
+
*
|
|
10
|
+
* @param {ASTNode} rootNode The current root node being parsed by eslint
|
|
11
|
+
* @param {ASTNode} childNode The AST node child argument being checked
|
|
12
|
+
* @param {Function} cb The callback function
|
|
13
|
+
* @param {Boolean} skipConditional Optional, indicate distinct parsing for conditional nodes
|
|
14
|
+
* @param {Boolean} isolate Optional, set internally to isolate parsing and validation on conditional children
|
|
15
|
+
* @param {Array} ignoredKeys Optional, set object keys which should not be parsed e.g. for `cva`
|
|
16
|
+
* @returns {void}
|
|
17
|
+
*/ function parseNodeRecursive(rootNode, childNode, cb, skipConditional = false, isolate = false, ignoredKeys = [], context) {
|
|
18
|
+
// TODO allow vue non litteral
|
|
19
|
+
let originalClassNamesValue;
|
|
20
|
+
let classNames;
|
|
21
|
+
let start = null;
|
|
22
|
+
let end = null;
|
|
23
|
+
let prefix = '';
|
|
24
|
+
let suffix = '';
|
|
25
|
+
if (childNode === null) {
|
|
26
|
+
originalClassNamesValue = extractValueFromNode(rootNode);
|
|
27
|
+
({ classNames } = extractClassnamesFromValue(originalClassNamesValue));
|
|
28
|
+
classNames = [
|
|
29
|
+
...new Set(classNames)
|
|
30
|
+
];
|
|
31
|
+
if (classNames.length === 0) {
|
|
32
|
+
// Don't run for empty className
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const range = extractRangeFromNode(rootNode);
|
|
36
|
+
if (rootNode.type === 'TextAttribute') {
|
|
37
|
+
start = range[0];
|
|
38
|
+
end = range[1];
|
|
39
|
+
} else {
|
|
40
|
+
start = range[0] + 1;
|
|
41
|
+
end = range[1] - 1;
|
|
42
|
+
}
|
|
43
|
+
cb(classNames, rootNode, originalClassNamesValue, start, end, prefix, suffix);
|
|
44
|
+
} else if (childNode === undefined) {
|
|
45
|
+
// Ignore invalid child candidates (probably inside complex TemplateLiteral)
|
|
46
|
+
return;
|
|
47
|
+
} else {
|
|
48
|
+
const forceIsolation = skipConditional ? true : isolate;
|
|
49
|
+
let expStrings = [];
|
|
50
|
+
switch(childNode.type){
|
|
51
|
+
case 'TemplateLiteral':
|
|
52
|
+
childNode.expressions.forEach((exp)=>{
|
|
53
|
+
parseNodeRecursive(rootNode, exp, cb, skipConditional, forceIsolation, ignoredKeys, context);
|
|
54
|
+
});
|
|
55
|
+
const sourceCode = context.sourceCode;
|
|
56
|
+
originalClassNamesValue = sourceCode.getText(childNode);
|
|
57
|
+
originalClassNamesValue = originalClassNamesValue.substring(1, originalClassNamesValue.length - 1);
|
|
58
|
+
expStrings = originalClassNamesValue.match(/\$\{(?:(?<!\\\\)(['"`]).*?(?<!\\\\)\1|[^}])*?\}/g) ?? [];
|
|
59
|
+
for(let i = 0; i < expStrings.length; i++){
|
|
60
|
+
originalClassNamesValue = originalClassNamesValue.replace(expStrings[i], `EXPRESSION_STRING_NUM_${i}`);
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
case 'ConditionalExpression':
|
|
64
|
+
parseNodeRecursive(rootNode, childNode.consequent, cb, skipConditional, forceIsolation, ignoredKeys, context);
|
|
65
|
+
parseNodeRecursive(rootNode, childNode.alternate, cb, skipConditional, forceIsolation, ignoredKeys, context);
|
|
66
|
+
return;
|
|
67
|
+
case 'LogicalExpression':
|
|
68
|
+
parseNodeRecursive(rootNode, childNode.right, cb, skipConditional, forceIsolation, ignoredKeys, context);
|
|
69
|
+
return;
|
|
70
|
+
case 'ArrayExpression':
|
|
71
|
+
childNode.elements.forEach((el)=>{
|
|
72
|
+
parseNodeRecursive(rootNode, el, cb, skipConditional, forceIsolation, ignoredKeys, context);
|
|
73
|
+
});
|
|
74
|
+
return;
|
|
75
|
+
case 'ObjectExpression':
|
|
76
|
+
childNode.properties.forEach((prop)=>{
|
|
77
|
+
const isUsedByClassNamesPlugin = rootNode.callee && rootNode.callee.name === 'classnames';
|
|
78
|
+
if (prop.type === 'SpreadElement') {
|
|
79
|
+
// Ignore spread elements
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (prop.key.type === 'Identifier' && ignoredKeys.includes(prop.key.name)) {
|
|
83
|
+
// Ignore specific keys defined in settings
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
parseNodeRecursive(rootNode, isUsedByClassNamesPlugin ? prop.key : prop.value, cb, skipConditional, forceIsolation, ignoredKeys, context);
|
|
87
|
+
});
|
|
88
|
+
return;
|
|
89
|
+
case 'Property':
|
|
90
|
+
parseNodeRecursive(rootNode, childNode.key, cb, skipConditional, forceIsolation, ignoredKeys, context);
|
|
91
|
+
return;
|
|
92
|
+
case 'Literal':
|
|
93
|
+
originalClassNamesValue = childNode.value;
|
|
94
|
+
start = childNode.range[0] + 1;
|
|
95
|
+
end = childNode.range[1] - 1;
|
|
96
|
+
break;
|
|
97
|
+
case 'SvelteLiteral':
|
|
98
|
+
originalClassNamesValue = childNode.value;
|
|
99
|
+
start = childNode.range[0];
|
|
100
|
+
end = childNode.range[1];
|
|
101
|
+
break;
|
|
102
|
+
case 'TemplateElement':
|
|
103
|
+
originalClassNamesValue = childNode.value.raw;
|
|
104
|
+
start = childNode.range[0];
|
|
105
|
+
end = childNode.range[1];
|
|
106
|
+
// eslint-disable-next-line no-case-declarations
|
|
107
|
+
const txt = context?.sourceCode.getText(childNode) ?? '';
|
|
108
|
+
prefix = getTemplateElementPrefix(txt, originalClassNamesValue);
|
|
109
|
+
suffix = getTemplateElementSuffix(txt, originalClassNamesValue);
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
for(let i = 0; i < expStrings.length; i++){
|
|
113
|
+
originalClassNamesValue = originalClassNamesValue.replace(`EXPRESSION_STRING_NUM_${i}`, expStrings[i]);
|
|
114
|
+
}
|
|
115
|
+
({ classNames } = extractClassnamesFromValue(originalClassNamesValue));
|
|
116
|
+
classNames = [
|
|
117
|
+
...new Set(classNames)
|
|
118
|
+
];
|
|
119
|
+
if (classNames.length === 0) {
|
|
120
|
+
// Don't run for empty className
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const targetNode = isolate ? null : rootNode;
|
|
124
|
+
cb(classNames, targetNode, originalClassNamesValue, start, end, prefix, suffix);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export { parseNodeRecursive };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var settings = require('../settings.cjs');
|
|
4
|
+
var exploreConfig = require('@master/css-explore-config');
|
|
5
|
+
var css = require('@master/css');
|
|
6
|
+
|
|
7
|
+
const cssCaches = [];
|
|
8
|
+
function resolveContext(context) {
|
|
9
|
+
const resolvedSettings = Object.assign({}, settings, context.settings?.['@master/css']);
|
|
10
|
+
let css$1 = cssCaches.find((cache)=>cache.settings.config === resolvedSettings.config && cache.cwd === context.cwd)?.css;
|
|
11
|
+
if (!css$1) {
|
|
12
|
+
let config;
|
|
13
|
+
if (typeof resolvedSettings.config === 'object') {
|
|
14
|
+
config = resolvedSettings.config;
|
|
15
|
+
} else {
|
|
16
|
+
config = exploreConfig({
|
|
17
|
+
name: resolvedSettings.config,
|
|
18
|
+
found: undefined
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
css$1 = new css.MasterCSS(config);
|
|
22
|
+
cssCaches.push({
|
|
23
|
+
cwd: context.cwd,
|
|
24
|
+
settings: resolvedSettings,
|
|
25
|
+
css: css$1
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
settings: resolvedSettings,
|
|
30
|
+
options: context.options[0] || {},
|
|
31
|
+
css: css$1
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = resolveContext;
|