@master/eslint-plugin-css 2.0.0-rc.60 → 2.0.0-rc.62
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/common.cjs +7 -0
- package/dist/common.d.ts +2 -0
- package/dist/common.mjs +4 -0
- package/dist/create-rule.cjs +1 -1
- package/dist/create-rule.mjs +1 -1
- package/dist/functions/filter-collision-classes.cjs +1 -1
- package/dist/functions/filter-collision-classes.mjs +2 -2
- package/dist/rules/class-collision.cjs +44 -38
- package/dist/rules/class-collision.mjs +44 -38
- package/dist/rules/class-order.cjs +25 -133
- package/dist/rules/class-order.mjs +26 -134
- package/dist/rules/class-validation.cjs +26 -37
- package/dist/rules/class-validation.mjs +26 -37
- package/dist/utils/define-visitors.cjs +24 -25
- package/dist/utils/define-visitors.d.ts +2 -1
- package/dist/utils/define-visitors.mjs +24 -25
- package/dist/utils/resolve-class-node.cjs +147 -0
- package/dist/utils/resolve-class-node.d.ts +12 -0
- package/dist/utils/resolve-class-node.mjs +145 -0
- package/dist/utils/resolve-context.cjs +6 -2
- package/dist/utils/resolve-context.mjs +6 -2
- package/dist/utils/with-visit-class-node.cjs +62 -0
- package/dist/utils/with-visit-class-node.d.ts +4 -0
- package/dist/utils/with-visit-class-node.mjs +60 -0
- package/package.json +1 -1
- package/dist/utils/extract-classnames-from-value.cjs +0 -34
- package/dist/utils/extract-classnames-from-value.d.ts +0 -6
- package/dist/utils/extract-classnames-from-value.mjs +0 -32
- package/dist/utils/extract-range-from-node.cjs +0 -18
- package/dist/utils/extract-range-from-node.d.ts +0 -1
- package/dist/utils/extract-range-from-node.mjs +0 -16
- package/dist/utils/extract-value-from-node.cjs +0 -23
- package/dist/utils/extract-value-from-node.d.ts +0 -1
- package/dist/utils/extract-value-from-node.mjs +0 -21
- package/dist/utils/find-loc.cjs +0 -51
- package/dist/utils/find-loc.d.ts +0 -7
- package/dist/utils/find-loc.mjs +0 -49
- package/dist/utils/get-template-element-body.cjs +0 -12
- package/dist/utils/get-template-element-body.d.ts +0 -1
- package/dist/utils/get-template-element-body.mjs +0 -10
- package/dist/utils/get-template-element-prefix.cjs +0 -11
- package/dist/utils/get-template-element-prefix.d.ts +0 -1
- package/dist/utils/get-template-element-prefix.mjs +0 -9
- package/dist/utils/get-template-element-suffix.cjs +0 -10
- package/dist/utils/get-template-element-suffix.d.ts +0 -1
- package/dist/utils/get-template-element-suffix.mjs +0 -8
- package/dist/utils/index-of-all.cjs +0 -12
- package/dist/utils/index-of-all.d.ts +0 -1
- package/dist/utils/index-of-all.mjs +0 -10
- package/dist/utils/parse-node-recursive.cjs +0 -129
- package/dist/utils/parse-node-recursive.d.ts +0 -13
- package/dist/utils/parse-node-recursive.mjs +0 -127
package/dist/common.cjs
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
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
ADDED
package/dist/common.mjs
ADDED
package/dist/create-rule.cjs
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
var css = require('@master/css');
|
|
4
4
|
var utils = require('@typescript-eslint/utils');
|
|
5
5
|
|
|
6
|
-
var createRule = utils.ESLintUtils.RuleCreator((name)=>new URL(`/
|
|
6
|
+
var createRule = utils.ESLintUtils.RuleCreator((name)=>new URL(`/guide/code-linting#${name}`, css.OFFICIAL_URL).href);
|
|
7
7
|
|
|
8
8
|
module.exports = createRule;
|
package/dist/create-rule.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { OFFICIAL_URL } from '@master/css';
|
|
2
2
|
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
3
3
|
|
|
4
|
-
var createRule = ESLintUtils.RuleCreator((name)=>new URL(`/
|
|
4
|
+
var createRule = ESLintUtils.RuleCreator((name)=>new URL(`/guide/code-linting#${name}`, OFFICIAL_URL).href);
|
|
5
5
|
|
|
6
6
|
export { createRule as default };
|
|
@@ -14,7 +14,7 @@ function filterCollisionClasses(classNames, css$1) {
|
|
|
14
14
|
for(let j = 0; j < classNames.length; j++){
|
|
15
15
|
const compareClassName = classNames[j];
|
|
16
16
|
const compareRule = validRules.find((eachValidRule)=>eachValidRule.name === compareClassName);
|
|
17
|
-
if (i !== j && compareRule && css.
|
|
17
|
+
if (i !== j && compareRule && css.equalDeclarations(rule.declarations, compareRule.declarations) && css.equalVariants(rule, compareRule)) {
|
|
18
18
|
collisionClasses.push(compareClassName);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { generateValidRules } from '@master/css-validator';
|
|
2
|
-
import {
|
|
2
|
+
import { equalDeclarations, equalVariants } from '@master/css';
|
|
3
3
|
|
|
4
4
|
function filterCollisionClasses(classNames, css) {
|
|
5
5
|
const validRules = classNames.map((eachClassName)=>generateValidRules(eachClassName, css)[0]).filter(Boolean);
|
|
@@ -12,7 +12,7 @@ function filterCollisionClasses(classNames, css) {
|
|
|
12
12
|
for(let j = 0; j < classNames.length; j++){
|
|
13
13
|
const compareClassName = classNames[j];
|
|
14
14
|
const compareRule = validRules.find((eachValidRule)=>eachValidRule.name === compareClassName);
|
|
15
|
-
if (i !== j && compareRule &&
|
|
15
|
+
if (i !== j && compareRule && equalDeclarations(rule.declarations, compareRule.declarations) && equalVariants(rule, compareRule)) {
|
|
16
16
|
collisionClasses.push(compareClassName);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
var defineVisitors = require('../utils/define-visitors.cjs');
|
|
4
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
5
|
var filterCollisionClasses = require('../functions/filter-collision-classes.cjs');
|
|
8
6
|
var createRule = require('../create-rule.cjs');
|
|
9
7
|
var settingsSchema = require('../settings-schema.cjs');
|
|
@@ -13,7 +11,7 @@ var classCollision = createRule({
|
|
|
13
11
|
meta: {
|
|
14
12
|
type: 'layout',
|
|
15
13
|
docs: {
|
|
16
|
-
description: 'Avoid applying classes with the same
|
|
14
|
+
description: 'Avoid applying classes with the same declarations'
|
|
17
15
|
},
|
|
18
16
|
messages: {
|
|
19
17
|
collisionClass: '{{message}}'
|
|
@@ -26,44 +24,52 @@ var classCollision = createRule({
|
|
|
26
24
|
defaultOptions: [],
|
|
27
25
|
create (context) {
|
|
28
26
|
const { settings, css } = resolveContext(context);
|
|
29
|
-
const visitNode = (node, arg = null)=>{
|
|
30
|
-
parseNodeRecursive.parseNodeRecursive(node, arg, (classNames, node, originalClassNamesValue, start, end)=>{
|
|
31
|
-
const sourceCode = context.sourceCode;
|
|
32
|
-
const sourceCodeLines = sourceCode.lines;
|
|
33
|
-
const nodeStartLine = node.loc.start.line;
|
|
34
|
-
const nodeStartColumn = node.loc.start.column;
|
|
35
|
-
const nodeEndLine = node.loc.end.line;
|
|
36
|
-
const nodeEndColumn = node.loc.end.column;
|
|
37
|
-
// todo css
|
|
38
|
-
const collisionClassesRecord = filterCollisionClasses(classNames, css);
|
|
39
|
-
for(const className in collisionClassesRecord){
|
|
40
|
-
const collisionClasses = collisionClassesRecord[className];
|
|
41
|
-
const collisionClassNamesMsg = collisionClasses.map((x)=>`"${x}"`).join(' and ');
|
|
42
|
-
let fixClassNames = originalClassNamesValue;
|
|
43
|
-
for (const collisionClassName of collisionClasses){
|
|
44
|
-
const regexSafe = collisionClassName.replace(/(\\|\.|\(|\)|\[|\]|\{|\}|\+|\*|\?|\^|\$|\||\/)/g, '\\$1');
|
|
45
|
-
fixClassNames = fixClassNames.replace(new RegExp(`\\s+${regexSafe}|${regexSafe}\\s+`), '');
|
|
46
|
-
}
|
|
47
|
-
context.report({
|
|
48
|
-
loc: findLoc(className, sourceCodeLines, nodeStartLine, nodeStartColumn, nodeEndLine, nodeEndColumn),
|
|
49
|
-
messageId: 'collisionClass',
|
|
50
|
-
data: {
|
|
51
|
-
message: `"${className}" applies the same CSS declarations as ${collisionClassNamesMsg}.`
|
|
52
|
-
},
|
|
53
|
-
fix: function(fixer) {
|
|
54
|
-
return fixer.replaceTextRange([
|
|
55
|
-
start,
|
|
56
|
-
end
|
|
57
|
-
], fixClassNames);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
}, false, false, settings.ignoredKeys, context);
|
|
62
|
-
};
|
|
63
27
|
return defineVisitors({
|
|
64
28
|
context,
|
|
65
29
|
settings
|
|
66
|
-
},
|
|
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
|
+
});
|
|
67
73
|
}
|
|
68
74
|
});
|
|
69
75
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import defineVisitors from '../utils/define-visitors.mjs';
|
|
2
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
3
|
import filterCollisionClasses from '../functions/filter-collision-classes.mjs';
|
|
6
4
|
import createRule from '../create-rule.mjs';
|
|
7
5
|
import settingsSchema from '../settings-schema.mjs';
|
|
@@ -11,7 +9,7 @@ var classCollision = createRule({
|
|
|
11
9
|
meta: {
|
|
12
10
|
type: 'layout',
|
|
13
11
|
docs: {
|
|
14
|
-
description: 'Avoid applying classes with the same
|
|
12
|
+
description: 'Avoid applying classes with the same declarations'
|
|
15
13
|
},
|
|
16
14
|
messages: {
|
|
17
15
|
collisionClass: '{{message}}'
|
|
@@ -24,44 +22,52 @@ var classCollision = createRule({
|
|
|
24
22
|
defaultOptions: [],
|
|
25
23
|
create (context) {
|
|
26
24
|
const { settings, css } = resolveContext(context);
|
|
27
|
-
const visitNode = (node, arg = null)=>{
|
|
28
|
-
parseNodeRecursive(node, arg, (classNames, node, originalClassNamesValue, start, end)=>{
|
|
29
|
-
const sourceCode = context.sourceCode;
|
|
30
|
-
const sourceCodeLines = sourceCode.lines;
|
|
31
|
-
const nodeStartLine = node.loc.start.line;
|
|
32
|
-
const nodeStartColumn = node.loc.start.column;
|
|
33
|
-
const nodeEndLine = node.loc.end.line;
|
|
34
|
-
const nodeEndColumn = node.loc.end.column;
|
|
35
|
-
// todo css
|
|
36
|
-
const collisionClassesRecord = filterCollisionClasses(classNames, css);
|
|
37
|
-
for(const className in collisionClassesRecord){
|
|
38
|
-
const collisionClasses = collisionClassesRecord[className];
|
|
39
|
-
const collisionClassNamesMsg = collisionClasses.map((x)=>`"${x}"`).join(' and ');
|
|
40
|
-
let fixClassNames = originalClassNamesValue;
|
|
41
|
-
for (const collisionClassName of collisionClasses){
|
|
42
|
-
const regexSafe = collisionClassName.replace(/(\\|\.|\(|\)|\[|\]|\{|\}|\+|\*|\?|\^|\$|\||\/)/g, '\\$1');
|
|
43
|
-
fixClassNames = fixClassNames.replace(new RegExp(`\\s+${regexSafe}|${regexSafe}\\s+`), '');
|
|
44
|
-
}
|
|
45
|
-
context.report({
|
|
46
|
-
loc: findLoc(className, sourceCodeLines, nodeStartLine, nodeStartColumn, nodeEndLine, nodeEndColumn),
|
|
47
|
-
messageId: 'collisionClass',
|
|
48
|
-
data: {
|
|
49
|
-
message: `"${className}" applies the same CSS declarations as ${collisionClassNamesMsg}.`
|
|
50
|
-
},
|
|
51
|
-
fix: function(fixer) {
|
|
52
|
-
return fixer.replaceTextRange([
|
|
53
|
-
start,
|
|
54
|
-
end
|
|
55
|
-
], fixClassNames);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
}, false, false, settings.ignoredKeys, context);
|
|
60
|
-
};
|
|
61
25
|
return defineVisitors({
|
|
62
26
|
context,
|
|
63
27
|
settings
|
|
64
|
-
},
|
|
28
|
+
}, (node, { raw, start, end, nodes, classNodes, classValues })=>{
|
|
29
|
+
const collisionClassesRecord = filterCollisionClasses(classValues, css);
|
|
30
|
+
for(const className in collisionClassesRecord){
|
|
31
|
+
const collisionClasses = collisionClassesRecord[className];
|
|
32
|
+
const collisionClassNamesMsg = collisionClasses.map((x)=>`"${x}"`).join(' and ');
|
|
33
|
+
const classNode = classNodes.find((node)=>node.value === className);
|
|
34
|
+
const fixedNodes = [
|
|
35
|
+
...nodes
|
|
36
|
+
];
|
|
37
|
+
const removeCollision = (removedClassNode)=>{
|
|
38
|
+
for(let i = 0; i < fixedNodes.length; i++){
|
|
39
|
+
const fixedNode = fixedNodes[i];
|
|
40
|
+
const target = fixedNode === removedClassNode;
|
|
41
|
+
if (target) {
|
|
42
|
+
const prev = fixedNodes[i - 1];
|
|
43
|
+
const isSpaceBefore = prev && prev.type === 'space';
|
|
44
|
+
fixedNodes.splice(i, 1);
|
|
45
|
+
if (isSpaceBefore) {
|
|
46
|
+
fixedNodes.splice(i - 1, 1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
collisionClasses.forEach((collisionClass)=>{
|
|
52
|
+
const collisionNode = classNodes.find((node)=>node.value === collisionClass);
|
|
53
|
+
removeCollision(collisionNode);
|
|
54
|
+
});
|
|
55
|
+
const fixedRaw = fixedNodes.map((node)=>node.raw).join('');
|
|
56
|
+
context.report({
|
|
57
|
+
loc: classNode.loc,
|
|
58
|
+
messageId: 'collisionClass',
|
|
59
|
+
data: {
|
|
60
|
+
message: `"${className}" applies the same declarations as ${collisionClassNamesMsg}.`
|
|
61
|
+
},
|
|
62
|
+
fix: function(fixer) {
|
|
63
|
+
return fixer.replaceTextRange([
|
|
64
|
+
start,
|
|
65
|
+
end
|
|
66
|
+
], fixedRaw);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
65
71
|
}
|
|
66
72
|
});
|
|
67
73
|
|
|
@@ -2,13 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
var defineVisitors = require('../utils/define-visitors.cjs');
|
|
4
4
|
var resolveContext = require('../utils/resolve-context.cjs');
|
|
5
|
-
var getTemplateElementBody = require('../utils/get-template-element-body.cjs');
|
|
6
|
-
var getTemplateElementSuffix = require('../utils/get-template-element-suffix.cjs');
|
|
7
|
-
var getTemplateElementPrefix = require('../utils/get-template-element-prefix.cjs');
|
|
8
|
-
var extractValueFromNode = require('../utils/extract-value-from-node.cjs');
|
|
9
|
-
var extractRangeFromNode = require('../utils/extract-range-from-node.cjs');
|
|
10
|
-
var extractClassnamesFromValue = require('../utils/extract-classnames-from-value.cjs');
|
|
11
|
-
var findLoc = require('../utils/find-loc.cjs');
|
|
12
5
|
var createRule = require('../create-rule.cjs');
|
|
13
6
|
var settingsSchema = require('../settings-schema.cjs');
|
|
14
7
|
var css = require('@master/css');
|
|
@@ -31,144 +24,43 @@ var classOrder = createRule({
|
|
|
31
24
|
defaultOptions: [],
|
|
32
25
|
create: function(context) {
|
|
33
26
|
const { settings, css: css$1 } = resolveContext(context);
|
|
34
|
-
const sourceCode = context
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
let
|
|
41
|
-
let
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (node.type === 'TextAttribute') {
|
|
46
|
-
start = range[0];
|
|
47
|
-
end = range[1];
|
|
48
|
-
} else {
|
|
49
|
-
start = range[0] + 1;
|
|
50
|
-
end = range[1] - 1;
|
|
27
|
+
const { sourceCode } = context;
|
|
28
|
+
return defineVisitors({
|
|
29
|
+
context,
|
|
30
|
+
settings
|
|
31
|
+
}, (node, { raw, start, end, nodes, classValueRawMap, classValues })=>{
|
|
32
|
+
if (nodes.length <= 1) return;
|
|
33
|
+
let orderedClasses = css.sortReadableClasses(classValues, css$1);
|
|
34
|
+
let orderedRaw = nodes.map((node, i)=>{
|
|
35
|
+
if (node.type === 'class') {
|
|
36
|
+
const value = orderedClasses.shift();
|
|
37
|
+
return classValueRawMap.get(value);
|
|
51
38
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
case 'Identifier':
|
|
55
|
-
return;
|
|
56
|
-
case 'TemplateLiteral':
|
|
57
|
-
arg.expressions.forEach((exp)=>{
|
|
58
|
-
visitNode(node, exp);
|
|
59
|
-
});
|
|
60
|
-
originalClassNamesValue = sourceCode.getText(arg);
|
|
61
|
-
originalClassNamesValue = originalClassNamesValue.substring(1, originalClassNamesValue.length - 1);
|
|
62
|
-
expStrings = originalClassNamesValue.match(/\$\{(?:(?<!\\\\)(['"`]).*?(?<!\\\\)\1|[^}])*?\}/g) ?? [];
|
|
63
|
-
for(let i = 0; i < expStrings.length; i++){
|
|
64
|
-
originalClassNamesValue = originalClassNamesValue.replace(expStrings[i], `EXPRESSION_STRING_NUM_${i}`);
|
|
65
|
-
}
|
|
66
|
-
start = arg.range[0] + 1;
|
|
67
|
-
end = arg.range[1] - 1;
|
|
68
|
-
break;
|
|
69
|
-
case 'ConditionalExpression':
|
|
70
|
-
visitNode(node, arg.consequent);
|
|
71
|
-
visitNode(node, arg.alternate);
|
|
72
|
-
return;
|
|
73
|
-
case 'LogicalExpression':
|
|
74
|
-
visitNode(node, arg.right);
|
|
75
|
-
return;
|
|
76
|
-
case 'ArrayExpression':
|
|
77
|
-
arg.elements.forEach((el)=>{
|
|
78
|
-
visitNode(node, el);
|
|
79
|
-
});
|
|
80
|
-
return;
|
|
81
|
-
case 'ObjectExpression':
|
|
82
|
-
const isUsedByClassNamesPlugin = node.callee && node.callee.name === 'classnames';
|
|
83
|
-
const isVue = node.key && node.key.type === 'VDirectiveKey';
|
|
84
|
-
arg.properties.forEach((prop)=>{
|
|
85
|
-
const propVal = isUsedByClassNamesPlugin || isVue ? prop.key : prop.value;
|
|
86
|
-
visitNode(node, propVal);
|
|
87
|
-
});
|
|
88
|
-
return;
|
|
89
|
-
case 'Property':
|
|
90
|
-
visitNode(node, arg.key);
|
|
91
|
-
break;
|
|
92
|
-
case 'Literal':
|
|
93
|
-
originalClassNamesValue = arg.raw.slice(1, arg.raw.length - 1);
|
|
94
|
-
start = arg.range[0] + 1;
|
|
95
|
-
end = arg.range[1] - 1;
|
|
96
|
-
break;
|
|
97
|
-
case 'SvelteLiteral':
|
|
98
|
-
originalClassNamesValue = arg.value;
|
|
99
|
-
if (originalClassNamesValue === '') {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
start = arg.range[0];
|
|
103
|
-
end = arg.range[1];
|
|
104
|
-
break;
|
|
105
|
-
case 'TemplateElement':
|
|
106
|
-
originalClassNamesValue = arg.value.raw;
|
|
107
|
-
if (originalClassNamesValue === '') {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
start = arg.range[0];
|
|
111
|
-
end = arg.range[1];
|
|
112
|
-
// https://github.com/eslint/eslint/issues/13360
|
|
113
|
-
// The problem is that range computation includes the backticks (`test`)
|
|
114
|
-
// but value.raw does not include them, so there is a mismatch.
|
|
115
|
-
// start/end does not include the backticks, therefore it matches value.raw.
|
|
116
|
-
const txt = context.sourceCode.getText(arg);
|
|
117
|
-
prefix = getTemplateElementPrefix(txt, originalClassNamesValue);
|
|
118
|
-
suffix = getTemplateElementSuffix(txt, originalClassNamesValue);
|
|
119
|
-
originalClassNamesValue = getTemplateElementBody(txt, prefix, suffix);
|
|
120
|
-
break;
|
|
39
|
+
if (node.type === 'space' && (orderedClasses.length !== 0 || i === nodes.length - 1)) {
|
|
40
|
+
return node.raw;
|
|
121
41
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
let orderedClassNames = css.reorderForReadableClasses(classNames, css$1).filter((eachOrderedClassName)=>classNames.includes(eachOrderedClassName));
|
|
129
|
-
orderedClassNames = classNames.filter((x)=>!orderedClassNames.includes(x)).concat(orderedClassNames).filter((x)=>x.trim() !== '');
|
|
130
|
-
// Generates the validated/sorted attribute value
|
|
131
|
-
let validatedClassNamesValue = '';
|
|
132
|
-
for(let i = 0; i < orderedClassNames.length; i++){
|
|
133
|
-
const w = whitespaces[i] ?? '';
|
|
134
|
-
const cls = orderedClassNames[i];
|
|
135
|
-
validatedClassNamesValue += headSpace ? `${w}${cls}` : `${cls}${w}`;
|
|
136
|
-
if (cls) {
|
|
137
|
-
if (!tailSpace && i === orderedClassNames.length - 1) {
|
|
138
|
-
validatedClassNamesValue = validatedClassNamesValue.replace(/\s+$/, '');
|
|
139
|
-
}
|
|
140
|
-
if (headSpace && tailSpace && i === orderedClassNames.length - 1) {
|
|
141
|
-
validatedClassNamesValue += whitespaces[whitespaces.length - 1] ?? '';
|
|
142
|
-
}
|
|
42
|
+
return '';
|
|
43
|
+
}).join('');
|
|
44
|
+
if (raw !== orderedRaw) {
|
|
45
|
+
if (node.type === 'TemplateElement') {
|
|
46
|
+
orderedRaw = '`' + orderedRaw + '`';
|
|
143
47
|
}
|
|
144
|
-
}
|
|
145
|
-
for(let i = 0; i < expStrings.length; i++){
|
|
146
|
-
originalClassNamesValue = originalClassNamesValue.replace(`EXPRESSION_STRING_NUM_${i}`, expStrings[i]);
|
|
147
|
-
validatedClassNamesValue = validatedClassNamesValue.replace(`EXPRESSION_STRING_NUM_${i}`, expStrings[i]);
|
|
148
|
-
}
|
|
149
|
-
if (originalClassNamesValue !== validatedClassNamesValue) {
|
|
150
|
-
validatedClassNamesValue = prefix + validatedClassNamesValue + suffix;
|
|
151
|
-
const sourceCodeLines = sourceCode.lines;
|
|
152
|
-
const nodeStartLine = node.loc.start.line;
|
|
153
|
-
const nodeStartColumn = node.loc.start.column;
|
|
154
|
-
const nodeEndLine = node.loc.end.line;
|
|
155
|
-
const nodeEndColumn = node.loc.end.column;
|
|
156
48
|
context.report({
|
|
157
|
-
|
|
49
|
+
node,
|
|
50
|
+
loc: {
|
|
51
|
+
start: sourceCode.getLocFromIndex(start),
|
|
52
|
+
end: sourceCode.getLocFromIndex(end)
|
|
53
|
+
},
|
|
158
54
|
messageId: 'invalidClassOrder',
|
|
159
55
|
fix: function(fixer) {
|
|
160
56
|
return fixer.replaceTextRange([
|
|
161
57
|
start,
|
|
162
58
|
end
|
|
163
|
-
],
|
|
59
|
+
], orderedRaw);
|
|
164
60
|
}
|
|
165
61
|
});
|
|
166
62
|
}
|
|
167
|
-
};
|
|
168
|
-
return defineVisitors({
|
|
169
|
-
context,
|
|
170
|
-
settings
|
|
171
|
-
}, visitNode);
|
|
63
|
+
});
|
|
172
64
|
}
|
|
173
65
|
});
|
|
174
66
|
|
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
import defineVisitors from '../utils/define-visitors.mjs';
|
|
2
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
3
|
import createRule from '../create-rule.mjs';
|
|
11
4
|
import settingsSchema from '../settings-schema.mjs';
|
|
12
|
-
import {
|
|
5
|
+
import { sortReadableClasses } from '@master/css';
|
|
13
6
|
|
|
14
7
|
var classOrder = createRule({
|
|
15
8
|
name: 'consistent-class-order',
|
|
@@ -29,144 +22,43 @@ var classOrder = createRule({
|
|
|
29
22
|
defaultOptions: [],
|
|
30
23
|
create: function(context) {
|
|
31
24
|
const { settings, css } = resolveContext(context);
|
|
32
|
-
const sourceCode = context
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
let
|
|
39
|
-
let
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (node.type === 'TextAttribute') {
|
|
44
|
-
start = range[0];
|
|
45
|
-
end = range[1];
|
|
46
|
-
} else {
|
|
47
|
-
start = range[0] + 1;
|
|
48
|
-
end = range[1] - 1;
|
|
25
|
+
const { sourceCode } = context;
|
|
26
|
+
return defineVisitors({
|
|
27
|
+
context,
|
|
28
|
+
settings
|
|
29
|
+
}, (node, { raw, start, end, nodes, classValueRawMap, classValues })=>{
|
|
30
|
+
if (nodes.length <= 1) return;
|
|
31
|
+
let orderedClasses = sortReadableClasses(classValues, css);
|
|
32
|
+
let orderedRaw = nodes.map((node, i)=>{
|
|
33
|
+
if (node.type === 'class') {
|
|
34
|
+
const value = orderedClasses.shift();
|
|
35
|
+
return classValueRawMap.get(value);
|
|
49
36
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
case 'Identifier':
|
|
53
|
-
return;
|
|
54
|
-
case 'TemplateLiteral':
|
|
55
|
-
arg.expressions.forEach((exp)=>{
|
|
56
|
-
visitNode(node, exp);
|
|
57
|
-
});
|
|
58
|
-
originalClassNamesValue = sourceCode.getText(arg);
|
|
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
|
-
start = arg.range[0] + 1;
|
|
65
|
-
end = arg.range[1] - 1;
|
|
66
|
-
break;
|
|
67
|
-
case 'ConditionalExpression':
|
|
68
|
-
visitNode(node, arg.consequent);
|
|
69
|
-
visitNode(node, arg.alternate);
|
|
70
|
-
return;
|
|
71
|
-
case 'LogicalExpression':
|
|
72
|
-
visitNode(node, arg.right);
|
|
73
|
-
return;
|
|
74
|
-
case 'ArrayExpression':
|
|
75
|
-
arg.elements.forEach((el)=>{
|
|
76
|
-
visitNode(node, el);
|
|
77
|
-
});
|
|
78
|
-
return;
|
|
79
|
-
case 'ObjectExpression':
|
|
80
|
-
const isUsedByClassNamesPlugin = node.callee && node.callee.name === 'classnames';
|
|
81
|
-
const isVue = node.key && node.key.type === 'VDirectiveKey';
|
|
82
|
-
arg.properties.forEach((prop)=>{
|
|
83
|
-
const propVal = isUsedByClassNamesPlugin || isVue ? prop.key : prop.value;
|
|
84
|
-
visitNode(node, propVal);
|
|
85
|
-
});
|
|
86
|
-
return;
|
|
87
|
-
case 'Property':
|
|
88
|
-
visitNode(node, arg.key);
|
|
89
|
-
break;
|
|
90
|
-
case 'Literal':
|
|
91
|
-
originalClassNamesValue = arg.raw.slice(1, arg.raw.length - 1);
|
|
92
|
-
start = arg.range[0] + 1;
|
|
93
|
-
end = arg.range[1] - 1;
|
|
94
|
-
break;
|
|
95
|
-
case 'SvelteLiteral':
|
|
96
|
-
originalClassNamesValue = arg.value;
|
|
97
|
-
if (originalClassNamesValue === '') {
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
start = arg.range[0];
|
|
101
|
-
end = arg.range[1];
|
|
102
|
-
break;
|
|
103
|
-
case 'TemplateElement':
|
|
104
|
-
originalClassNamesValue = arg.value.raw;
|
|
105
|
-
if (originalClassNamesValue === '') {
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
start = arg.range[0];
|
|
109
|
-
end = arg.range[1];
|
|
110
|
-
// https://github.com/eslint/eslint/issues/13360
|
|
111
|
-
// The problem is that range computation includes the backticks (`test`)
|
|
112
|
-
// but value.raw does not include them, so there is a mismatch.
|
|
113
|
-
// start/end does not include the backticks, therefore it matches value.raw.
|
|
114
|
-
const txt = context.sourceCode.getText(arg);
|
|
115
|
-
prefix = getTemplateElementPrefix(txt, originalClassNamesValue);
|
|
116
|
-
suffix = getTemplateElementSuffix(txt, originalClassNamesValue);
|
|
117
|
-
originalClassNamesValue = getTemplateElementBody(txt, prefix, suffix);
|
|
118
|
-
break;
|
|
37
|
+
if (node.type === 'space' && (orderedClasses.length !== 0 || i === nodes.length - 1)) {
|
|
38
|
+
return node.raw;
|
|
119
39
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
let orderedClassNames = reorderForReadableClasses(classNames, css).filter((eachOrderedClassName)=>classNames.includes(eachOrderedClassName));
|
|
127
|
-
orderedClassNames = classNames.filter((x)=>!orderedClassNames.includes(x)).concat(orderedClassNames).filter((x)=>x.trim() !== '');
|
|
128
|
-
// Generates the validated/sorted attribute value
|
|
129
|
-
let validatedClassNamesValue = '';
|
|
130
|
-
for(let i = 0; i < orderedClassNames.length; i++){
|
|
131
|
-
const w = whitespaces[i] ?? '';
|
|
132
|
-
const cls = orderedClassNames[i];
|
|
133
|
-
validatedClassNamesValue += headSpace ? `${w}${cls}` : `${cls}${w}`;
|
|
134
|
-
if (cls) {
|
|
135
|
-
if (!tailSpace && i === orderedClassNames.length - 1) {
|
|
136
|
-
validatedClassNamesValue = validatedClassNamesValue.replace(/\s+$/, '');
|
|
137
|
-
}
|
|
138
|
-
if (headSpace && tailSpace && i === orderedClassNames.length - 1) {
|
|
139
|
-
validatedClassNamesValue += whitespaces[whitespaces.length - 1] ?? '';
|
|
140
|
-
}
|
|
40
|
+
return '';
|
|
41
|
+
}).join('');
|
|
42
|
+
if (raw !== orderedRaw) {
|
|
43
|
+
if (node.type === 'TemplateElement') {
|
|
44
|
+
orderedRaw = '`' + orderedRaw + '`';
|
|
141
45
|
}
|
|
142
|
-
}
|
|
143
|
-
for(let i = 0; i < expStrings.length; i++){
|
|
144
|
-
originalClassNamesValue = originalClassNamesValue.replace(`EXPRESSION_STRING_NUM_${i}`, expStrings[i]);
|
|
145
|
-
validatedClassNamesValue = validatedClassNamesValue.replace(`EXPRESSION_STRING_NUM_${i}`, expStrings[i]);
|
|
146
|
-
}
|
|
147
|
-
if (originalClassNamesValue !== validatedClassNamesValue) {
|
|
148
|
-
validatedClassNamesValue = prefix + validatedClassNamesValue + suffix;
|
|
149
|
-
const sourceCodeLines = sourceCode.lines;
|
|
150
|
-
const nodeStartLine = node.loc.start.line;
|
|
151
|
-
const nodeStartColumn = node.loc.start.column;
|
|
152
|
-
const nodeEndLine = node.loc.end.line;
|
|
153
|
-
const nodeEndColumn = node.loc.end.column;
|
|
154
46
|
context.report({
|
|
155
|
-
|
|
47
|
+
node,
|
|
48
|
+
loc: {
|
|
49
|
+
start: sourceCode.getLocFromIndex(start),
|
|
50
|
+
end: sourceCode.getLocFromIndex(end)
|
|
51
|
+
},
|
|
156
52
|
messageId: 'invalidClassOrder',
|
|
157
53
|
fix: function(fixer) {
|
|
158
54
|
return fixer.replaceTextRange([
|
|
159
55
|
start,
|
|
160
56
|
end
|
|
161
|
-
],
|
|
57
|
+
], orderedRaw);
|
|
162
58
|
}
|
|
163
59
|
});
|
|
164
60
|
}
|
|
165
|
-
};
|
|
166
|
-
return defineVisitors({
|
|
167
|
-
context,
|
|
168
|
-
settings
|
|
169
|
-
}, visitNode);
|
|
61
|
+
});
|
|
170
62
|
}
|
|
171
63
|
});
|
|
172
64
|
|