@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
|
@@ -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 createRule = require('../create-rule.cjs');
|
|
8
6
|
var settingsSchema = require('../settings-schema.cjs');
|
|
9
7
|
var cssValidator = require('@master/css-validator');
|
|
@@ -27,44 +25,35 @@ var classValidation = createRule({
|
|
|
27
25
|
defaultOptions: [],
|
|
28
26
|
create: function(context) {
|
|
29
27
|
const { options, settings, css } = resolveContext(context);
|
|
30
|
-
const visitNode = (node, arg = null)=>{
|
|
31
|
-
parseNodeRecursive.parseNodeRecursive(node, arg, (classNames, node)=>{
|
|
32
|
-
const sourceCode = context.sourceCode;
|
|
33
|
-
const sourceCodeLines = sourceCode.lines;
|
|
34
|
-
const nodeStartLine = node.loc.start.line;
|
|
35
|
-
const nodeStartColumn = node.loc.start.column;
|
|
36
|
-
const nodeEndLine = node.loc.end.line;
|
|
37
|
-
const nodeEndColumn = node.loc.end.column;
|
|
38
|
-
for (const className of classNames){
|
|
39
|
-
const { matched, errors } = cssValidator.validate(className, css);
|
|
40
|
-
if (errors.length > 0) {
|
|
41
|
-
for (const error of errors){
|
|
42
|
-
if (matched) {
|
|
43
|
-
context.report({
|
|
44
|
-
loc: findLoc(className, sourceCodeLines, nodeStartLine, nodeStartColumn, nodeEndLine, nodeEndColumn),
|
|
45
|
-
messageId: 'invalidClass',
|
|
46
|
-
data: {
|
|
47
|
-
message: error.message + '.'
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
} else if (options.disallowUnknownClass) {
|
|
51
|
-
context.report({
|
|
52
|
-
loc: findLoc(className, sourceCodeLines, nodeStartLine, nodeStartColumn, nodeEndLine, nodeEndColumn),
|
|
53
|
-
messageId: 'disallowUnknownClass',
|
|
54
|
-
data: {
|
|
55
|
-
message: `"${className}" is not a valid or known class.`
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}, false, false, settings.ignoredKeys, context);
|
|
63
|
-
};
|
|
64
28
|
return defineVisitors({
|
|
65
29
|
context,
|
|
66
30
|
settings
|
|
67
|
-
},
|
|
31
|
+
}, (node, { classNodes })=>{
|
|
32
|
+
for (const node of classNodes){
|
|
33
|
+
const { matched, errors } = cssValidator.validate(node.value, css);
|
|
34
|
+
if (errors.length > 0) {
|
|
35
|
+
for (const error of errors){
|
|
36
|
+
if (matched) {
|
|
37
|
+
context.report({
|
|
38
|
+
loc: node.loc,
|
|
39
|
+
messageId: 'invalidClass',
|
|
40
|
+
data: {
|
|
41
|
+
message: error.message + '.'
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
} else if (options.disallowUnknownClass) {
|
|
45
|
+
context.report({
|
|
46
|
+
loc: node.loc,
|
|
47
|
+
messageId: 'disallowUnknownClass',
|
|
48
|
+
data: {
|
|
49
|
+
message: `"${node.raw}" is not a valid or known class.`
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
68
57
|
}
|
|
69
58
|
});
|
|
70
59
|
|
|
@@ -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 createRule from '../create-rule.mjs';
|
|
6
4
|
import settingsSchema from '../settings-schema.mjs';
|
|
7
5
|
import { validate } from '@master/css-validator';
|
|
@@ -25,44 +23,35 @@ var classValidation = createRule({
|
|
|
25
23
|
defaultOptions: [],
|
|
26
24
|
create: function(context) {
|
|
27
25
|
const { options, settings, css } = resolveContext(context);
|
|
28
|
-
const visitNode = (node, arg = null)=>{
|
|
29
|
-
parseNodeRecursive(node, arg, (classNames, node)=>{
|
|
30
|
-
const sourceCode = context.sourceCode;
|
|
31
|
-
const sourceCodeLines = sourceCode.lines;
|
|
32
|
-
const nodeStartLine = node.loc.start.line;
|
|
33
|
-
const nodeStartColumn = node.loc.start.column;
|
|
34
|
-
const nodeEndLine = node.loc.end.line;
|
|
35
|
-
const nodeEndColumn = node.loc.end.column;
|
|
36
|
-
for (const className of classNames){
|
|
37
|
-
const { matched, errors } = validate(className, css);
|
|
38
|
-
if (errors.length > 0) {
|
|
39
|
-
for (const error of errors){
|
|
40
|
-
if (matched) {
|
|
41
|
-
context.report({
|
|
42
|
-
loc: findLoc(className, sourceCodeLines, nodeStartLine, nodeStartColumn, nodeEndLine, nodeEndColumn),
|
|
43
|
-
messageId: 'invalidClass',
|
|
44
|
-
data: {
|
|
45
|
-
message: error.message + '.'
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
} else if (options.disallowUnknownClass) {
|
|
49
|
-
context.report({
|
|
50
|
-
loc: findLoc(className, sourceCodeLines, nodeStartLine, nodeStartColumn, nodeEndLine, nodeEndColumn),
|
|
51
|
-
messageId: 'disallowUnknownClass',
|
|
52
|
-
data: {
|
|
53
|
-
message: `"${className}" is not a valid or known class.`
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}, false, false, settings.ignoredKeys, context);
|
|
61
|
-
};
|
|
62
26
|
return defineVisitors({
|
|
63
27
|
context,
|
|
64
28
|
settings
|
|
65
|
-
},
|
|
29
|
+
}, (node, { classNodes })=>{
|
|
30
|
+
for (const node of classNodes){
|
|
31
|
+
const { matched, errors } = validate(node.value, css);
|
|
32
|
+
if (errors.length > 0) {
|
|
33
|
+
for (const error of errors){
|
|
34
|
+
if (matched) {
|
|
35
|
+
context.report({
|
|
36
|
+
loc: node.loc,
|
|
37
|
+
messageId: 'invalidClass',
|
|
38
|
+
data: {
|
|
39
|
+
message: error.message + '.'
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
} else if (options.disallowUnknownClass) {
|
|
43
|
+
context.report({
|
|
44
|
+
loc: node.loc,
|
|
45
|
+
messageId: 'disallowUnknownClass',
|
|
46
|
+
data: {
|
|
47
|
+
message: `"${node.raw}" is not a valid or known class.`
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
66
55
|
}
|
|
67
56
|
});
|
|
68
57
|
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var withVisitClassNode = require('./with-visit-class-node.cjs');
|
|
4
|
+
|
|
3
5
|
function defineVisitors({ context, settings }, visitNode) {
|
|
4
6
|
const classAttributeRegex = new RegExp(`^(?:${settings.classAttributes.join('|')})$`);
|
|
5
7
|
const classFunctionsRegex = new RegExp(`^(?:${settings.classFunctions.join('|')})`);
|
|
6
8
|
const classDeclarationsRegex = new RegExp(`^(?:${settings.classDeclarations.join('|')})$`);
|
|
7
|
-
const
|
|
9
|
+
const allowCalleeNode = (node)=>{
|
|
8
10
|
let calleeName = '';
|
|
9
11
|
const calleeNode = node.callee || node.tag;
|
|
10
12
|
if (calleeNode.type === 'Identifier') {
|
|
@@ -15,51 +17,48 @@ function defineVisitors({ context, settings }, visitNode) {
|
|
|
15
17
|
}
|
|
16
18
|
return classFunctionsRegex.test(calleeName);
|
|
17
19
|
};
|
|
20
|
+
const visitClassNode = withVisitClassNode(visitNode, context);
|
|
18
21
|
const CallExpression = function(node) {
|
|
19
|
-
if (!
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
node.arguments.forEach((arg)=>{
|
|
23
|
-
visitNode(node, arg);
|
|
22
|
+
if (!allowCalleeNode(node)) return;
|
|
23
|
+
node.arguments.forEach((node)=>{
|
|
24
|
+
visitClassNode(node);
|
|
24
25
|
});
|
|
25
26
|
};
|
|
26
27
|
const scriptVisitor = {
|
|
27
28
|
CallExpression,
|
|
28
29
|
JSXAttribute: function(node) {
|
|
29
30
|
if (!node.name || !classAttributeRegex.test(node.name.name)) return;
|
|
30
|
-
if (node.value
|
|
31
|
-
|
|
32
|
-
} else if (node.value && node.value.type === 'JSXExpressionContainer') {
|
|
33
|
-
visitNode(node, node.value.expression);
|
|
31
|
+
if (node.value) {
|
|
32
|
+
visitClassNode(node.value);
|
|
34
33
|
}
|
|
35
34
|
},
|
|
36
35
|
SvelteAttribute: function(node) {
|
|
37
36
|
if (!node.key?.name || !classAttributeRegex.test(node.key.name)) return;
|
|
38
37
|
for (const eachValue of node.value){
|
|
39
|
-
|
|
38
|
+
visitClassNode(eachValue);
|
|
40
39
|
}
|
|
41
40
|
},
|
|
42
41
|
TextAttribute: function(node) {
|
|
43
42
|
if (!node.name || !classAttributeRegex.test(node.name)) return;
|
|
44
|
-
|
|
43
|
+
visitClassNode(node);
|
|
45
44
|
},
|
|
46
45
|
TaggedTemplateExpression: function(node) {
|
|
47
|
-
if (
|
|
48
|
-
|
|
46
|
+
if (allowCalleeNode(node)) {
|
|
47
|
+
visitClassNode(node.quasi);
|
|
49
48
|
return;
|
|
50
49
|
}
|
|
51
50
|
},
|
|
52
51
|
VariableDeclaration: function(node) {
|
|
53
52
|
node.declarations.forEach((decl)=>{
|
|
54
53
|
if (decl.id.type === 'Identifier' && classDeclarationsRegex.test(decl.id.name)) {
|
|
55
|
-
|
|
54
|
+
visitClassNode(decl.init);
|
|
56
55
|
}
|
|
57
56
|
});
|
|
58
57
|
},
|
|
59
58
|
ObjectExpression: function(node) {
|
|
60
59
|
node.properties.forEach((prop)=>{
|
|
61
60
|
if (prop.type === 'Property' && prop.key.type === 'Identifier' && classDeclarationsRegex.test(prop.key.name)) {
|
|
62
|
-
|
|
61
|
+
visitClassNode(prop.value);
|
|
63
62
|
}
|
|
64
63
|
});
|
|
65
64
|
}
|
|
@@ -67,16 +66,16 @@ function defineVisitors({ context, settings }, visitNode) {
|
|
|
67
66
|
const templateBodyVisitor = {
|
|
68
67
|
CallExpression,
|
|
69
68
|
VAttribute: function(node) {
|
|
69
|
+
const name = node.key.argument?.name || node.key.name;
|
|
70
|
+
if (!name || !classAttributeRegex.test(name)) return;
|
|
70
71
|
if (node.value && node.value.type === 'VLiteral') {
|
|
71
|
-
|
|
72
|
-
} else if (node.value
|
|
73
|
-
node.value.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
visitNode(node, prop);
|
|
79
|
-
});
|
|
72
|
+
visitClassNode(node.value);
|
|
73
|
+
} else if (node.value) {
|
|
74
|
+
if (node.value.type === 'VExpressionContainer') {
|
|
75
|
+
if (node.value.expression?.type === 'ArrayExpression' || node.value.expression?.type === 'ObjectExpression') {
|
|
76
|
+
visitClassNode(node.value.expression);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
80
79
|
}
|
|
81
80
|
}
|
|
82
81
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { TSESTree } from '@typescript-eslint/utils';
|
|
2
2
|
import type { RuleContext, RuleListener } from '@typescript-eslint/utils/ts-eslint';
|
|
3
3
|
import { Settings } from '../settings';
|
|
4
|
+
import resolveClassNode from './resolve-class-node';
|
|
4
5
|
export default function defineVisitors({ context, settings }: {
|
|
5
6
|
context: RuleContext<any, any[]>;
|
|
6
7
|
settings: Settings;
|
|
7
|
-
}, visitNode: (node: TSESTree.Node,
|
|
8
|
+
}, visitNode: (node: TSESTree.Node, resolved: ReturnType<typeof resolveClassNode>) => void): RuleListener;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import withVisitClassNode from './with-visit-class-node.mjs';
|
|
2
|
+
|
|
1
3
|
function defineVisitors({ context, settings }, visitNode) {
|
|
2
4
|
const classAttributeRegex = new RegExp(`^(?:${settings.classAttributes.join('|')})$`);
|
|
3
5
|
const classFunctionsRegex = new RegExp(`^(?:${settings.classFunctions.join('|')})`);
|
|
4
6
|
const classDeclarationsRegex = new RegExp(`^(?:${settings.classDeclarations.join('|')})$`);
|
|
5
|
-
const
|
|
7
|
+
const allowCalleeNode = (node)=>{
|
|
6
8
|
let calleeName = '';
|
|
7
9
|
const calleeNode = node.callee || node.tag;
|
|
8
10
|
if (calleeNode.type === 'Identifier') {
|
|
@@ -13,51 +15,48 @@ function defineVisitors({ context, settings }, visitNode) {
|
|
|
13
15
|
}
|
|
14
16
|
return classFunctionsRegex.test(calleeName);
|
|
15
17
|
};
|
|
18
|
+
const visitClassNode = withVisitClassNode(visitNode, context);
|
|
16
19
|
const CallExpression = function(node) {
|
|
17
|
-
if (!
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
node.arguments.forEach((arg)=>{
|
|
21
|
-
visitNode(node, arg);
|
|
20
|
+
if (!allowCalleeNode(node)) return;
|
|
21
|
+
node.arguments.forEach((node)=>{
|
|
22
|
+
visitClassNode(node);
|
|
22
23
|
});
|
|
23
24
|
};
|
|
24
25
|
const scriptVisitor = {
|
|
25
26
|
CallExpression,
|
|
26
27
|
JSXAttribute: function(node) {
|
|
27
28
|
if (!node.name || !classAttributeRegex.test(node.name.name)) return;
|
|
28
|
-
if (node.value
|
|
29
|
-
|
|
30
|
-
} else if (node.value && node.value.type === 'JSXExpressionContainer') {
|
|
31
|
-
visitNode(node, node.value.expression);
|
|
29
|
+
if (node.value) {
|
|
30
|
+
visitClassNode(node.value);
|
|
32
31
|
}
|
|
33
32
|
},
|
|
34
33
|
SvelteAttribute: function(node) {
|
|
35
34
|
if (!node.key?.name || !classAttributeRegex.test(node.key.name)) return;
|
|
36
35
|
for (const eachValue of node.value){
|
|
37
|
-
|
|
36
|
+
visitClassNode(eachValue);
|
|
38
37
|
}
|
|
39
38
|
},
|
|
40
39
|
TextAttribute: function(node) {
|
|
41
40
|
if (!node.name || !classAttributeRegex.test(node.name)) return;
|
|
42
|
-
|
|
41
|
+
visitClassNode(node);
|
|
43
42
|
},
|
|
44
43
|
TaggedTemplateExpression: function(node) {
|
|
45
|
-
if (
|
|
46
|
-
|
|
44
|
+
if (allowCalleeNode(node)) {
|
|
45
|
+
visitClassNode(node.quasi);
|
|
47
46
|
return;
|
|
48
47
|
}
|
|
49
48
|
},
|
|
50
49
|
VariableDeclaration: function(node) {
|
|
51
50
|
node.declarations.forEach((decl)=>{
|
|
52
51
|
if (decl.id.type === 'Identifier' && classDeclarationsRegex.test(decl.id.name)) {
|
|
53
|
-
|
|
52
|
+
visitClassNode(decl.init);
|
|
54
53
|
}
|
|
55
54
|
});
|
|
56
55
|
},
|
|
57
56
|
ObjectExpression: function(node) {
|
|
58
57
|
node.properties.forEach((prop)=>{
|
|
59
58
|
if (prop.type === 'Property' && prop.key.type === 'Identifier' && classDeclarationsRegex.test(prop.key.name)) {
|
|
60
|
-
|
|
59
|
+
visitClassNode(prop.value);
|
|
61
60
|
}
|
|
62
61
|
});
|
|
63
62
|
}
|
|
@@ -65,16 +64,16 @@ function defineVisitors({ context, settings }, visitNode) {
|
|
|
65
64
|
const templateBodyVisitor = {
|
|
66
65
|
CallExpression,
|
|
67
66
|
VAttribute: function(node) {
|
|
67
|
+
const name = node.key.argument?.name || node.key.name;
|
|
68
|
+
if (!name || !classAttributeRegex.test(name)) return;
|
|
68
69
|
if (node.value && node.value.type === 'VLiteral') {
|
|
69
|
-
|
|
70
|
-
} else if (node.value
|
|
71
|
-
node.value.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
visitNode(node, prop);
|
|
77
|
-
});
|
|
70
|
+
visitClassNode(node.value);
|
|
71
|
+
} else if (node.value) {
|
|
72
|
+
if (node.value.type === 'VExpressionContainer') {
|
|
73
|
+
if (node.value.expression?.type === 'ArrayExpression' || node.value.expression?.type === 'ObjectExpression') {
|
|
74
|
+
visitClassNode(node.value.expression);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
78
77
|
}
|
|
79
78
|
}
|
|
80
79
|
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var common = require('../common.cjs');
|
|
4
|
+
|
|
5
|
+
function resolveClassNode(node, context) {
|
|
6
|
+
const { sourceCode } = context;
|
|
7
|
+
let value = null;
|
|
8
|
+
let raw = null;
|
|
9
|
+
let start = null;
|
|
10
|
+
let end = null;
|
|
11
|
+
switch(node.type){
|
|
12
|
+
case 'Literal':
|
|
13
|
+
value = node.value;
|
|
14
|
+
raw = node.raw;
|
|
15
|
+
start = node.range[0];
|
|
16
|
+
end = node.range[1];
|
|
17
|
+
break;
|
|
18
|
+
case 'VLiteral':
|
|
19
|
+
value = node.value;
|
|
20
|
+
raw = sourceCode.getText(node);
|
|
21
|
+
start = node.range[0];
|
|
22
|
+
end = node.range[1];
|
|
23
|
+
break;
|
|
24
|
+
case 'TextAttribute':
|
|
25
|
+
value = node.value;
|
|
26
|
+
start = node.valueSpan.fullStart.offset;
|
|
27
|
+
end = node.valueSpan.end.offset;
|
|
28
|
+
raw = sourceCode.getText({
|
|
29
|
+
...node,
|
|
30
|
+
range: [
|
|
31
|
+
start,
|
|
32
|
+
end
|
|
33
|
+
]
|
|
34
|
+
});
|
|
35
|
+
break;
|
|
36
|
+
case 'SvelteLiteral':
|
|
37
|
+
value = node.value;
|
|
38
|
+
raw = sourceCode.getText(node);
|
|
39
|
+
start = node.range[0];
|
|
40
|
+
end = node.range[1];
|
|
41
|
+
break;
|
|
42
|
+
case 'TemplateElement':
|
|
43
|
+
if (node.parent.expressions.length) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
value = node.value.cooked;
|
|
47
|
+
raw = node.value.raw;
|
|
48
|
+
start = node.range[0];
|
|
49
|
+
end = node.range[1];
|
|
50
|
+
break;
|
|
51
|
+
default:
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (/^(['"`])(.*)\1$/.test(raw)) {
|
|
55
|
+
raw = raw.slice(1, -1);
|
|
56
|
+
start = start + 1;
|
|
57
|
+
end = end - 1;
|
|
58
|
+
}
|
|
59
|
+
const nodes = [];
|
|
60
|
+
const classValues = value.split(common.HALF_WIDTH_WHITESPACE_REGEX);
|
|
61
|
+
const classRaws = raw.split(common.HALF_WIDTH_WHITESPACE_REGEX);
|
|
62
|
+
const classValueRawMap = new Map();
|
|
63
|
+
const classRawValueMap = new Map();
|
|
64
|
+
for(let i = 0; i < classRaws.length; i++){
|
|
65
|
+
classValueRawMap.set(classValues[i], classRaws[i]);
|
|
66
|
+
classRawValueMap.set(classRaws[i], classValues[i]);
|
|
67
|
+
}
|
|
68
|
+
let lastIndex = 0;
|
|
69
|
+
let match;
|
|
70
|
+
while((match = common.HALF_WIDTH_WHITESPACE_GLOBAL_REGEX.exec(raw)) !== null){
|
|
71
|
+
const spaceRaw = match[0];
|
|
72
|
+
const spaceStart = match.index;
|
|
73
|
+
const spaceEnd = spaceStart + spaceRaw.length;
|
|
74
|
+
// 處理前一段非空白 (class name)
|
|
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
|
+
// 處理空白
|
|
96
|
+
const spaceStartOffset = start + spaceStart;
|
|
97
|
+
const spaceEndOffset = start + spaceEnd;
|
|
98
|
+
nodes.push({
|
|
99
|
+
type: 'space',
|
|
100
|
+
raw: spaceRaw,
|
|
101
|
+
range: [
|
|
102
|
+
spaceStartOffset,
|
|
103
|
+
spaceEndOffset
|
|
104
|
+
],
|
|
105
|
+
loc: {
|
|
106
|
+
start: sourceCode.getLocFromIndex(spaceStartOffset),
|
|
107
|
+
end: sourceCode.getLocFromIndex(spaceEndOffset)
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
lastIndex = spaceEnd;
|
|
111
|
+
}
|
|
112
|
+
// 最後一段 class name(若結尾不是空白)
|
|
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,
|
|
123
|
+
range: [
|
|
124
|
+
startOffset,
|
|
125
|
+
endOffset
|
|
126
|
+
],
|
|
127
|
+
loc: {
|
|
128
|
+
start: sourceCode.getLocFromIndex(startOffset),
|
|
129
|
+
end: sourceCode.getLocFromIndex(endOffset)
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
const classNodes = nodes.filter((node)=>node.type === 'class');
|
|
134
|
+
return {
|
|
135
|
+
nodes,
|
|
136
|
+
start,
|
|
137
|
+
end,
|
|
138
|
+
raw,
|
|
139
|
+
value,
|
|
140
|
+
classRawValueMap,
|
|
141
|
+
classValueRawMap,
|
|
142
|
+
classNodes,
|
|
143
|
+
classValues: classNodes.map((node)=>node.value)
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = resolveClassNode;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { RuleContext } from '@typescript-eslint/utils/ts-eslint';
|
|
2
|
+
export default function resolveClassNode(node: any, context: RuleContext<any, any[]>): {
|
|
3
|
+
nodes: any[];
|
|
4
|
+
start: number;
|
|
5
|
+
end: number;
|
|
6
|
+
raw: string;
|
|
7
|
+
value: string;
|
|
8
|
+
classRawValueMap: Map<any, any>;
|
|
9
|
+
classValueRawMap: Map<any, any>;
|
|
10
|
+
classNodes: any[];
|
|
11
|
+
classValues: any[];
|
|
12
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { HALF_WIDTH_WHITESPACE_REGEX, HALF_WIDTH_WHITESPACE_GLOBAL_REGEX } from '../common.mjs';
|
|
2
|
+
|
|
3
|
+
function resolveClassNode(node, context) {
|
|
4
|
+
const { sourceCode } = context;
|
|
5
|
+
let value = null;
|
|
6
|
+
let raw = null;
|
|
7
|
+
let start = null;
|
|
8
|
+
let end = null;
|
|
9
|
+
switch(node.type){
|
|
10
|
+
case 'Literal':
|
|
11
|
+
value = node.value;
|
|
12
|
+
raw = node.raw;
|
|
13
|
+
start = node.range[0];
|
|
14
|
+
end = node.range[1];
|
|
15
|
+
break;
|
|
16
|
+
case 'VLiteral':
|
|
17
|
+
value = node.value;
|
|
18
|
+
raw = sourceCode.getText(node);
|
|
19
|
+
start = node.range[0];
|
|
20
|
+
end = node.range[1];
|
|
21
|
+
break;
|
|
22
|
+
case 'TextAttribute':
|
|
23
|
+
value = node.value;
|
|
24
|
+
start = node.valueSpan.fullStart.offset;
|
|
25
|
+
end = node.valueSpan.end.offset;
|
|
26
|
+
raw = sourceCode.getText({
|
|
27
|
+
...node,
|
|
28
|
+
range: [
|
|
29
|
+
start,
|
|
30
|
+
end
|
|
31
|
+
]
|
|
32
|
+
});
|
|
33
|
+
break;
|
|
34
|
+
case 'SvelteLiteral':
|
|
35
|
+
value = node.value;
|
|
36
|
+
raw = sourceCode.getText(node);
|
|
37
|
+
start = node.range[0];
|
|
38
|
+
end = node.range[1];
|
|
39
|
+
break;
|
|
40
|
+
case 'TemplateElement':
|
|
41
|
+
if (node.parent.expressions.length) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
value = node.value.cooked;
|
|
45
|
+
raw = node.value.raw;
|
|
46
|
+
start = node.range[0];
|
|
47
|
+
end = node.range[1];
|
|
48
|
+
break;
|
|
49
|
+
default:
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (/^(['"`])(.*)\1$/.test(raw)) {
|
|
53
|
+
raw = raw.slice(1, -1);
|
|
54
|
+
start = start + 1;
|
|
55
|
+
end = end - 1;
|
|
56
|
+
}
|
|
57
|
+
const nodes = [];
|
|
58
|
+
const classValues = value.split(HALF_WIDTH_WHITESPACE_REGEX);
|
|
59
|
+
const classRaws = raw.split(HALF_WIDTH_WHITESPACE_REGEX);
|
|
60
|
+
const classValueRawMap = new Map();
|
|
61
|
+
const classRawValueMap = new Map();
|
|
62
|
+
for(let i = 0; i < classRaws.length; i++){
|
|
63
|
+
classValueRawMap.set(classValues[i], classRaws[i]);
|
|
64
|
+
classRawValueMap.set(classRaws[i], classValues[i]);
|
|
65
|
+
}
|
|
66
|
+
let lastIndex = 0;
|
|
67
|
+
let match;
|
|
68
|
+
while((match = HALF_WIDTH_WHITESPACE_GLOBAL_REGEX.exec(raw)) !== null){
|
|
69
|
+
const spaceRaw = match[0];
|
|
70
|
+
const spaceStart = match.index;
|
|
71
|
+
const spaceEnd = spaceStart + spaceRaw.length;
|
|
72
|
+
// 處理前一段非空白 (class name)
|
|
73
|
+
if (spaceStart > lastIndex) {
|
|
74
|
+
const classRaw = raw.slice(lastIndex, spaceStart);
|
|
75
|
+
const classValue = classRawValueMap.get(classRaw);
|
|
76
|
+
if (!classValue) return;
|
|
77
|
+
const startOffset = start + lastIndex;
|
|
78
|
+
const endOffset = start + spaceStart;
|
|
79
|
+
nodes.push({
|
|
80
|
+
type: 'class',
|
|
81
|
+
value: classValue,
|
|
82
|
+
raw: classRaw,
|
|
83
|
+
range: [
|
|
84
|
+
startOffset,
|
|
85
|
+
endOffset
|
|
86
|
+
],
|
|
87
|
+
loc: {
|
|
88
|
+
start: sourceCode.getLocFromIndex(startOffset),
|
|
89
|
+
end: sourceCode.getLocFromIndex(endOffset)
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// 處理空白
|
|
94
|
+
const spaceStartOffset = start + spaceStart;
|
|
95
|
+
const spaceEndOffset = start + spaceEnd;
|
|
96
|
+
nodes.push({
|
|
97
|
+
type: 'space',
|
|
98
|
+
raw: spaceRaw,
|
|
99
|
+
range: [
|
|
100
|
+
spaceStartOffset,
|
|
101
|
+
spaceEndOffset
|
|
102
|
+
],
|
|
103
|
+
loc: {
|
|
104
|
+
start: sourceCode.getLocFromIndex(spaceStartOffset),
|
|
105
|
+
end: sourceCode.getLocFromIndex(spaceEndOffset)
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
lastIndex = spaceEnd;
|
|
109
|
+
}
|
|
110
|
+
// 最後一段 class name(若結尾不是空白)
|
|
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,
|
|
121
|
+
range: [
|
|
122
|
+
startOffset,
|
|
123
|
+
endOffset
|
|
124
|
+
],
|
|
125
|
+
loc: {
|
|
126
|
+
start: sourceCode.getLocFromIndex(startOffset),
|
|
127
|
+
end: sourceCode.getLocFromIndex(endOffset)
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const classNodes = nodes.filter((node)=>node.type === 'class');
|
|
132
|
+
return {
|
|
133
|
+
nodes,
|
|
134
|
+
start,
|
|
135
|
+
end,
|
|
136
|
+
raw,
|
|
137
|
+
value,
|
|
138
|
+
classRawValueMap,
|
|
139
|
+
classValueRawMap,
|
|
140
|
+
classNodes,
|
|
141
|
+
classValues: classNodes.map((node)=>node.value)
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export { resolveClassNode as default };
|