@master/eslint-plugin-css 2.0.0-rc.4 → 2.0.0-rc.40

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.
Files changed (104) hide show
  1. package/README.md +2 -2
  2. package/dist/create-rule.cjs +8 -0
  3. package/dist/create-rule.d.ts +3 -0
  4. package/dist/create-rule.mjs +6 -0
  5. package/dist/functions/filter-collision-classes.cjs +29 -0
  6. package/dist/functions/filter-collision-classes.d.ts +2 -0
  7. package/dist/functions/filter-collision-classes.mjs +27 -0
  8. package/dist/index.cjs +39 -0
  9. package/dist/index.d.ts +61 -1
  10. package/dist/index.mjs +37 -1
  11. package/dist/plugin.cjs +18 -0
  12. package/dist/plugin.d.ts +10 -2
  13. package/dist/plugin.mjs +16 -1
  14. package/dist/rules/class-collision.cjs +69 -0
  15. package/dist/rules/class-collision.d.ts +1 -2
  16. package/dist/rules/class-collision.mjs +67 -1
  17. package/dist/rules/class-order.cjs +174 -0
  18. package/dist/rules/class-order.d.ts +1 -2
  19. package/dist/rules/class-order.mjs +172 -1
  20. package/dist/rules/class-validation.cjs +70 -0
  21. package/dist/rules/class-validation.d.ts +1 -2
  22. package/dist/rules/class-validation.mjs +68 -1
  23. package/dist/settings-schema.cjs +35 -0
  24. package/dist/settings-schema.d.ts +3 -0
  25. package/dist/settings-schema.mjs +33 -0
  26. package/dist/settings.cjs +16 -0
  27. package/dist/settings.d.ts +10 -2
  28. package/dist/settings.mjs +14 -1
  29. package/dist/utils/define-visitors.cjs +92 -0
  30. package/dist/utils/define-visitors.d.ts +6 -4
  31. package/dist/utils/define-visitors.mjs +90 -1
  32. package/dist/utils/extract-classnames-from-value.cjs +34 -0
  33. package/dist/utils/extract-classnames-from-value.mjs +32 -1
  34. package/dist/utils/extract-range-from-node.cjs +18 -0
  35. package/dist/utils/extract-range-from-node.mjs +16 -1
  36. package/dist/utils/extract-value-from-node.cjs +23 -0
  37. package/dist/utils/extract-value-from-node.mjs +21 -1
  38. package/dist/utils/find-loc.cjs +48 -0
  39. package/dist/utils/find-loc.mjs +46 -1
  40. package/dist/utils/get-template-element-body.cjs +12 -0
  41. package/dist/utils/get-template-element-body.mjs +10 -1
  42. package/dist/utils/get-template-element-prefix.cjs +11 -0
  43. package/dist/utils/get-template-element-prefix.mjs +9 -1
  44. package/dist/utils/get-template-element-suffix.cjs +10 -0
  45. package/dist/utils/get-template-element-suffix.mjs +8 -1
  46. package/dist/utils/index-of-all.cjs +12 -0
  47. package/dist/utils/index-of-all.d.ts +1 -0
  48. package/dist/utils/index-of-all.mjs +10 -0
  49. package/dist/utils/parse-node-recursive.cjs +130 -0
  50. package/dist/utils/parse-node-recursive.d.ts +2 -2
  51. package/dist/utils/parse-node-recursive.mjs +128 -1
  52. package/dist/utils/resolve-context.cjs +35 -0
  53. package/dist/utils/resolve-context.d.ts +11 -2
  54. package/dist/utils/resolve-context.mjs +33 -1
  55. package/package.json +1 -1
  56. package/dist/configs/config.d.ts +0 -13
  57. package/dist/configs/config.js +0 -1
  58. package/dist/configs/config.mjs +0 -1
  59. package/dist/configs/flat.d.ts +0 -16
  60. package/dist/configs/flat.js +0 -1
  61. package/dist/configs/flat.mjs +0 -1
  62. package/dist/configs/recommended.d.ts +0 -14
  63. package/dist/configs/recommended.js +0 -1
  64. package/dist/configs/recommended.mjs +0 -1
  65. package/dist/index.js +0 -1
  66. package/dist/plugin.js +0 -1
  67. package/dist/rules/class-collision.js +0 -1
  68. package/dist/rules/class-order.js +0 -1
  69. package/dist/rules/class-validation.js +0 -1
  70. package/dist/settings.js +0 -1
  71. package/dist/utils/are-declarations-equal.d.ts +0 -1
  72. package/dist/utils/are-declarations-equal.js +0 -1
  73. package/dist/utils/are-declarations-equal.mjs +0 -1
  74. package/dist/utils/define-visitors.js +0 -1
  75. package/dist/utils/extract-classnames-from-value.js +0 -1
  76. package/dist/utils/extract-range-from-node.js +0 -1
  77. package/dist/utils/extract-value-from-node.js +0 -1
  78. package/dist/utils/find-loc.js +0 -1
  79. package/dist/utils/get-mastercss.d.ts +0 -2
  80. package/dist/utils/get-mastercss.js +0 -1
  81. package/dist/utils/get-mastercss.mjs +0 -1
  82. package/dist/utils/get-template-element-body.js +0 -1
  83. package/dist/utils/get-template-element-prefix.js +0 -1
  84. package/dist/utils/get-template-element-suffix.js +0 -1
  85. package/dist/utils/parse-node-recursive.js +0 -1
  86. package/dist/utils/reorder-valid-classes-action.d.ts +0 -3
  87. package/dist/utils/reorder-valid-classes-action.js +0 -1
  88. package/dist/utils/reorder-valid-classes-action.mjs +0 -1
  89. package/dist/utils/resolve-context.js +0 -1
  90. package/dist/utils/valid-rules-action.d.ts +0 -3
  91. package/dist/utils/valid-rules-action.js +0 -1
  92. package/dist/utils/valid-rules-action.mjs +0 -1
  93. package/dist/utils/validate-action.d.ts +0 -3
  94. package/dist/utils/validate-action.js +0 -1
  95. package/dist/utils/validate-action.mjs +0 -1
  96. package/dist/utils/workers/reorder-valid-classes.d.ts +0 -2
  97. package/dist/utils/workers/reorder-valid-classes.js +0 -1
  98. package/dist/utils/workers/reorder-valid-classes.mjs +0 -1
  99. package/dist/utils/workers/valid-rules.d.ts +0 -2
  100. package/dist/utils/workers/valid-rules.js +0 -1
  101. package/dist/utils/workers/valid-rules.mjs +0 -1
  102. package/dist/utils/workers/validate.d.ts +0 -5
  103. package/dist/utils/workers/validate.js +0 -1
  104. package/dist/utils/workers/validate.mjs +0 -1
@@ -1 +1,172 @@
1
- import T from"../utils/define-visitors.mjs";import b from"../utils/resolve-context.mjs";import v from"../utils/get-template-element-body.mjs";import R from"../utils/get-template-element-suffix.mjs";import I from"../utils/get-template-element-prefix.mjs";import k from"../utils/extract-value-from-node.mjs";import L from"../utils/extract-range-from-node.mjs";import V from"../utils/extract-classnames-from-value.mjs";import _ from"../utils/find-loc.mjs";import $ from"../utils/reorder-valid-classes-action.mjs";var D={meta:{docs:{description:"Enforce a consistent and logical order of classes",category:"Stylistic Issues",recommended:!1,url:"https://rc.css.master.co/docs/code-linting#consistent-class-order"},messages:{invalidClassOrder:"No consistent class order followed."},fixable:"code",schema:[{type:"object",properties:{calleeMatching:{type:"string"},classMatching:{type:"string"},ignoredKeys:{type:"array",items:{type:"string",minLength:0},uniqueItems:!0},config:{type:["string","object"]}}}]},create:function(u){const{options:M,settings:x}=b(u),N=u.sourceCode,a=(r,t=null)=>{let s=null,o=null,c=null,d="",g="",p=[];if(t===null){s=k(r);const e=L(r);r.type==="TextAttribute"?(o=e[0],c=e[1]):(o=e[0]+1,c=e[1]-1)}else switch(t.type){case"Identifier":return;case"TemplateLiteral":t.expressions.forEach(l=>{a(r,l)}),s=N.getText(t),s=s.substring(1,s.length-1),p=s.match(/\$\{(?:(?<!\\\\)(['"`]).*?(?<!\\\\)\1|[^}])*?\}/g)??[];for(let l=0;l<p.length;l++)s=s.replace(p[l],`EXPRESSION_STRING_NUM_${l}`);o=t.range[0]+1,c=t.range[1]-1;break;case"ConditionalExpression":a(r,t.consequent),a(r,t.alternate);return;case"LogicalExpression":a(r,t.right);return;case"ArrayExpression":t.elements.forEach(l=>{a(r,l)});return;case"ObjectExpression":const e=r.callee&&r.callee.name==="classnames",f=r.key&&r.key.type==="VDirectiveKey";t.properties.forEach(l=>{const E=e||f?l.key:l.value;a(r,E)});return;case"Property":a(r,t.key);break;case"Literal":s=t.value,o=t.range[0]+1,c=t.range[1]-1;break;case"SvelteLiteral":if(s=t.value,s==="")return;o=t.range[0],c=t.range[1];break;case"TemplateElement":if(s=t.value.raw,s==="")return;o=t.range[0],c=t.range[1];const n=u.sourceCode.getText(t);d=I(n,s),g=R(n,s),s=v(n,d,g);break}const{classNames:y,whitespaces:h,headSpace:S,tailSpace:C}=V(s);if(y.length<=1)return;let m=$(y,x.config);m=y.filter(e=>!m.includes(e)).concat(m).filter(e=>e.trim()!=="");let i="";for(let e=0;e<m.length;e++){const f=h[e]??"",n=m[e];i+=S?`${f}${n}`:`${n}${f}`,n&&(!C&&e===m.length-1&&(i=i.replace(/\s+$/,"")),S&&C&&e===m.length-1&&(i+=h[h.length-1]??""))}for(let e=0;e<p.length;e++)s=s.replace(`EXPRESSION_STRING_NUM_${e}`,p[e]),i=i.replace(`EXPRESSION_STRING_NUM_${e}`,p[e]);if(s!==i){i=d+i+g;const e=N.lines,f=r.loc.start.line,n=r.loc.end.line,l={loc:_(s,e,f,n),messageId:"invalidClassOrder",fix:function(E){return E.replaceTextRange([o,c],i)}};u.report(l)}};return T({context:u,settings:x},a)}};export{D as default};
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 createRule from '../create-rule.mjs';
11
+ import settingsSchema from '../settings-schema.mjs';
12
+ import { reorderForReadableClasses } from '@master/css';
13
+
14
+ var classOrder = createRule({
15
+ name: 'consistent-class-order',
16
+ meta: {
17
+ type: 'layout',
18
+ fixable: 'code',
19
+ docs: {
20
+ description: 'Enforce a consistent and logical order of classes',
21
+ recommended: 'recommended'
22
+ },
23
+ messages: {
24
+ invalidClassOrder: 'No consistent class order followed.'
25
+ },
26
+ schema: [
27
+ settingsSchema
28
+ ]
29
+ },
30
+ defaultOptions: [],
31
+ create: function(context) {
32
+ const { settings, css } = resolveContext(context);
33
+ const sourceCode = context.sourceCode;
34
+ const visitNode = (node, arg = null)=>{
35
+ let originalClassNamesValue = null;
36
+ let start = null;
37
+ let end = null;
38
+ let prefix = '';
39
+ let suffix = '';
40
+ let expStrings = [];
41
+ if (arg === null) {
42
+ originalClassNamesValue = extractValueFromNode(node);
43
+ const range = extractRangeFromNode(node);
44
+ if (node.type === 'TextAttribute') {
45
+ start = range[0];
46
+ end = range[1];
47
+ } else {
48
+ start = range[0] + 1;
49
+ end = range[1] - 1;
50
+ }
51
+ } else {
52
+ switch(arg.type){
53
+ case 'Identifier':
54
+ return;
55
+ case 'TemplateLiteral':
56
+ arg.expressions.forEach((exp)=>{
57
+ visitNode(node, exp);
58
+ });
59
+ originalClassNamesValue = sourceCode.getText(arg);
60
+ originalClassNamesValue = originalClassNamesValue.substring(1, originalClassNamesValue.length - 1);
61
+ expStrings = originalClassNamesValue.match(/\$\{(?:(?<!\\\\)(['"`]).*?(?<!\\\\)\1|[^}])*?\}/g) ?? [];
62
+ for(let i = 0; i < expStrings.length; i++){
63
+ originalClassNamesValue = originalClassNamesValue.replace(expStrings[i], `EXPRESSION_STRING_NUM_${i}`);
64
+ }
65
+ start = arg.range[0] + 1;
66
+ end = arg.range[1] - 1;
67
+ break;
68
+ case 'ConditionalExpression':
69
+ visitNode(node, arg.consequent);
70
+ visitNode(node, arg.alternate);
71
+ return;
72
+ case 'LogicalExpression':
73
+ visitNode(node, arg.right);
74
+ return;
75
+ case 'ArrayExpression':
76
+ arg.elements.forEach((el)=>{
77
+ visitNode(node, el);
78
+ });
79
+ return;
80
+ case 'ObjectExpression':
81
+ const isUsedByClassNamesPlugin = node.callee && node.callee.name === 'classnames';
82
+ const isVue = node.key && node.key.type === 'VDirectiveKey';
83
+ arg.properties.forEach((prop)=>{
84
+ const propVal = isUsedByClassNamesPlugin || isVue ? prop.key : prop.value;
85
+ visitNode(node, propVal);
86
+ });
87
+ return;
88
+ case 'Property':
89
+ visitNode(node, arg.key);
90
+ break;
91
+ case 'Literal':
92
+ originalClassNamesValue = arg.raw.slice(1, arg.raw.length - 1);
93
+ start = arg.range[0] + 1;
94
+ end = arg.range[1] - 1;
95
+ break;
96
+ case 'SvelteLiteral':
97
+ originalClassNamesValue = arg.value;
98
+ if (originalClassNamesValue === '') {
99
+ return;
100
+ }
101
+ start = arg.range[0];
102
+ end = arg.range[1];
103
+ break;
104
+ case 'TemplateElement':
105
+ originalClassNamesValue = arg.value.raw;
106
+ if (originalClassNamesValue === '') {
107
+ return;
108
+ }
109
+ start = arg.range[0];
110
+ end = arg.range[1];
111
+ // https://github.com/eslint/eslint/issues/13360
112
+ // The problem is that range computation includes the backticks (`test`)
113
+ // but value.raw does not include them, so there is a mismatch.
114
+ // start/end does not include the backticks, therefore it matches value.raw.
115
+ const txt = context.sourceCode.getText(arg);
116
+ prefix = getTemplateElementPrefix(txt, originalClassNamesValue);
117
+ suffix = getTemplateElementSuffix(txt, originalClassNamesValue);
118
+ originalClassNamesValue = getTemplateElementBody(txt, prefix, suffix);
119
+ break;
120
+ }
121
+ }
122
+ const { classNames, whitespaces, headSpace, tailSpace } = extractClassnamesFromValue(originalClassNamesValue);
123
+ if (classNames.length <= 1) {
124
+ // Don't run sorting for a single or empty className
125
+ return;
126
+ }
127
+ let orderedClassNames = reorderForReadableClasses(classNames, css).filter((eachOrderedClassName)=>classNames.includes(eachOrderedClassName));
128
+ orderedClassNames = classNames.filter((x)=>!orderedClassNames.includes(x)).concat(orderedClassNames).filter((x)=>x.trim() !== '');
129
+ // Generates the validated/sorted attribute value
130
+ let validatedClassNamesValue = '';
131
+ for(let i = 0; i < orderedClassNames.length; i++){
132
+ const w = whitespaces[i] ?? '';
133
+ const cls = orderedClassNames[i];
134
+ validatedClassNamesValue += headSpace ? `${w}${cls}` : `${cls}${w}`;
135
+ if (cls) {
136
+ if (!tailSpace && i === orderedClassNames.length - 1) {
137
+ validatedClassNamesValue = validatedClassNamesValue.replace(/\s+$/, '');
138
+ }
139
+ if (headSpace && tailSpace && i === orderedClassNames.length - 1) {
140
+ validatedClassNamesValue += whitespaces[whitespaces.length - 1] ?? '';
141
+ }
142
+ }
143
+ }
144
+ for(let i = 0; i < expStrings.length; i++){
145
+ originalClassNamesValue = originalClassNamesValue.replace(`EXPRESSION_STRING_NUM_${i}`, expStrings[i]);
146
+ validatedClassNamesValue = validatedClassNamesValue.replace(`EXPRESSION_STRING_NUM_${i}`, expStrings[i]);
147
+ }
148
+ if (originalClassNamesValue !== validatedClassNamesValue) {
149
+ validatedClassNamesValue = prefix + validatedClassNamesValue + suffix;
150
+ const sourceCodeLines = sourceCode.lines;
151
+ const nodeStartLine = node.loc.start.line;
152
+ const nodeEndLine = node.loc.end.line;
153
+ context.report({
154
+ loc: findLoc(originalClassNamesValue, sourceCodeLines, nodeStartLine, nodeEndLine),
155
+ messageId: 'invalidClassOrder',
156
+ fix: function(fixer) {
157
+ return fixer.replaceTextRange([
158
+ start,
159
+ end
160
+ ], validatedClassNamesValue);
161
+ }
162
+ });
163
+ }
164
+ };
165
+ return defineVisitors({
166
+ context,
167
+ settings
168
+ }, visitNode);
169
+ }
170
+ });
171
+
172
+ export { classOrder as default };
@@ -0,0 +1,70 @@
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 createRule = require('../create-rule.cjs');
8
+ var settingsSchema = require('../settings-schema.cjs');
9
+ var cssValidator = require('@master/css-validator');
10
+
11
+ var classValidation = createRule({
12
+ name: 'syntax-error-checks',
13
+ meta: {
14
+ type: 'problem',
15
+ docs: {
16
+ description: 'Detect syntax errors early when writing classes',
17
+ recommended: 'recommended'
18
+ },
19
+ messages: {
20
+ invalidClass: '{{message}}',
21
+ disallowUnknownClass: '{{message}}'
22
+ },
23
+ fixable: null,
24
+ schema: [
25
+ settingsSchema
26
+ ]
27
+ },
28
+ defaultOptions: [],
29
+ create: function(context) {
30
+ const { options, settings, css } = resolveContext(context);
31
+ const visitNode = (node, arg = null)=>{
32
+ parseNodeRecursive.parseNodeRecursive(node, arg, (classNames, node)=>{
33
+ const sourceCode = context.sourceCode;
34
+ const sourceCodeLines = sourceCode.lines;
35
+ const nodeStartLine = node.loc.start.line;
36
+ const nodeEndLine = node.loc.end.line;
37
+ for (const className of classNames){
38
+ const { matched, errors } = cssValidator.validate(className, css);
39
+ if (errors.length > 0) {
40
+ for (const error of errors){
41
+ if (matched) {
42
+ context.report({
43
+ loc: findLoc(className, sourceCodeLines, nodeStartLine, nodeEndLine),
44
+ messageId: 'invalidClass',
45
+ data: {
46
+ message: error.message + '.'
47
+ }
48
+ });
49
+ } else if (options.disallowUnknownClass) {
50
+ context.report({
51
+ loc: findLoc(className, sourceCodeLines, nodeStartLine, nodeEndLine),
52
+ messageId: 'disallowUnknownClass',
53
+ data: {
54
+ message: `"${className}" is not a valid or known class.`
55
+ }
56
+ });
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }, false, false, settings.ignoredKeys, context);
62
+ };
63
+ return defineVisitors({
64
+ context,
65
+ settings
66
+ }, visitNode);
67
+ }
68
+ });
69
+
70
+ module.exports = classValidation;
@@ -1,3 +1,2 @@
1
- import { Rule } from 'eslint';
2
- declare const _default: Rule.RuleModule;
1
+ declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidClass" | "disallowUnknownClass", [], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
3
2
  export default _default;
@@ -1 +1,68 @@
1
- import u from"../utils/define-visitors.mjs";import y from"../utils/resolve-context.mjs";import l from"../utils/find-loc.mjs";import{parseNodeRecursive as C}from"../utils/parse-node-recursive.mjs";import w from"../utils/validate-action.mjs";var b={meta:{docs:{description:"Detect syntax errors early when writing classes",category:"Stylistic Issues",recommended:!1,url:"https://rc.css.master.co/docs/code-linting#syntax-error-checks"},messages:{invalidClass:"{{message}}",disallowUnknownClass:"{{message}}"},fixable:null,schema:[{type:"object",properties:{calleeMatching:{type:"string"},classMatching:{type:"string"},ignoredKeys:{type:"array",items:{type:"string",minLength:0},uniqueItems:!0},config:{type:["string","object"]}}}]},create:function(e){const{options:c,settings:o}=y(e);return u({context:e,settings:o},(d,m=null)=>{C(d,m,(g,r)=>{const t=e.sourceCode.lines,i=r.loc.start.line,n=r.loc.end.line;for(const s of g){const{isMasterCSS:f,errors:a}=w(s,o.config);if(a.length>0)for(const p of a)f?e.report({loc:l(s,t,i,n),messageId:"invalidClass",data:{message:p.message+"."}}):c.disallowUnknownClass&&e.report({loc:l(s,t,i,n),messageId:"disallowUnknownClass",data:{message:`"${s}" is not a valid or known class.`}})}},!1,!1,o.ignoredKeys,e)})}};export{b as default};
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 createRule from '../create-rule.mjs';
6
+ import settingsSchema from '../settings-schema.mjs';
7
+ import { validate } from '@master/css-validator';
8
+
9
+ var classValidation = createRule({
10
+ name: 'syntax-error-checks',
11
+ meta: {
12
+ type: 'problem',
13
+ docs: {
14
+ description: 'Detect syntax errors early when writing classes',
15
+ recommended: 'recommended'
16
+ },
17
+ messages: {
18
+ invalidClass: '{{message}}',
19
+ disallowUnknownClass: '{{message}}'
20
+ },
21
+ fixable: null,
22
+ schema: [
23
+ settingsSchema
24
+ ]
25
+ },
26
+ defaultOptions: [],
27
+ create: function(context) {
28
+ const { options, settings, css } = resolveContext(context);
29
+ const visitNode = (node, arg = null)=>{
30
+ parseNodeRecursive(node, arg, (classNames, node)=>{
31
+ const sourceCode = context.sourceCode;
32
+ const sourceCodeLines = sourceCode.lines;
33
+ const nodeStartLine = node.loc.start.line;
34
+ const nodeEndLine = node.loc.end.line;
35
+ for (const className of classNames){
36
+ const { matched, errors } = validate(className, css);
37
+ if (errors.length > 0) {
38
+ for (const error of errors){
39
+ if (matched) {
40
+ context.report({
41
+ loc: findLoc(className, sourceCodeLines, nodeStartLine, nodeEndLine),
42
+ messageId: 'invalidClass',
43
+ data: {
44
+ message: error.message + '.'
45
+ }
46
+ });
47
+ } else if (options.disallowUnknownClass) {
48
+ context.report({
49
+ loc: findLoc(className, sourceCodeLines, nodeStartLine, nodeEndLine),
50
+ messageId: 'disallowUnknownClass',
51
+ data: {
52
+ message: `"${className}" is not a valid or known class.`
53
+ }
54
+ });
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }, false, false, settings.ignoredKeys, context);
60
+ };
61
+ return defineVisitors({
62
+ context,
63
+ settings
64
+ }, visitNode);
65
+ }
66
+ });
67
+
68
+ export { classValidation as default };
@@ -0,0 +1,35 @@
1
+ 'use strict';
2
+
3
+ const settingsSchema = {
4
+ type: 'object',
5
+ properties: {
6
+ classAttributes: {
7
+ type: 'array',
8
+ items: {
9
+ type: 'string'
10
+ }
11
+ },
12
+ classFunctions: {
13
+ type: 'array',
14
+ items: {
15
+ type: 'string'
16
+ }
17
+ },
18
+ ignoredKeys: {
19
+ type: 'array',
20
+ items: {
21
+ type: 'string',
22
+ minLength: 0
23
+ },
24
+ uniqueItems: true
25
+ },
26
+ config: {
27
+ type: [
28
+ 'string',
29
+ 'object'
30
+ ]
31
+ }
32
+ }
33
+ };
34
+
35
+ module.exports = settingsSchema;
@@ -0,0 +1,3 @@
1
+ import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema';
2
+ declare const settingsSchema: JSONSchema4;
3
+ export default settingsSchema;
@@ -0,0 +1,33 @@
1
+ const settingsSchema = {
2
+ type: 'object',
3
+ properties: {
4
+ classAttributes: {
5
+ type: 'array',
6
+ items: {
7
+ type: 'string'
8
+ }
9
+ },
10
+ classFunctions: {
11
+ type: 'array',
12
+ items: {
13
+ type: 'string'
14
+ }
15
+ },
16
+ ignoredKeys: {
17
+ type: 'array',
18
+ items: {
19
+ type: 'string',
20
+ minLength: 0
21
+ },
22
+ uniqueItems: true
23
+ },
24
+ config: {
25
+ type: [
26
+ 'string',
27
+ 'object'
28
+ ]
29
+ }
30
+ }
31
+ };
32
+
33
+ export { settingsSchema as default };
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ var css = require('@master/css');
4
+
5
+ const settings = {
6
+ classAttributes: css.CLASS_ATTRIBUTES,
7
+ classFunctions: css.CLASS_FUNCTIONS,
8
+ classDeclarations: css.CLASS_DECLARATIONS,
9
+ ignoredKeys: [
10
+ 'compoundVariants',
11
+ 'defaultVariants'
12
+ ],
13
+ config: 'master.css'
14
+ };
15
+
16
+ module.exports = settings;
@@ -1,7 +1,15 @@
1
1
  declare const settings: {
2
- calleeMatching: string;
3
- classMatching: string;
2
+ classAttributes: string[];
3
+ classFunctions: string[];
4
+ classDeclarations: string[];
4
5
  ignoredKeys: string[];
5
6
  config: string;
6
7
  };
7
8
  export default settings;
9
+ export interface Settings {
10
+ classAttributes?: string[];
11
+ classFunctions?: string[];
12
+ classDeclarations?: string[];
13
+ ignoredKeys: string[];
14
+ config: string | object;
15
+ }
package/dist/settings.mjs CHANGED
@@ -1 +1,14 @@
1
- const s={calleeMatching:"^(classnames|clsx|ctl|cva|cv|classVariant|styled(?:\\.\\w+)?)",classMatching:"^class(Name)?$",ignoredKeys:["compoundVariants","defaultVariants"],config:"master.css.*"};var a=s;export{a as default};
1
+ import { CLASS_ATTRIBUTES, CLASS_FUNCTIONS, CLASS_DECLARATIONS } from '@master/css';
2
+
3
+ const settings = {
4
+ classAttributes: CLASS_ATTRIBUTES,
5
+ classFunctions: CLASS_FUNCTIONS,
6
+ classDeclarations: CLASS_DECLARATIONS,
7
+ ignoredKeys: [
8
+ 'compoundVariants',
9
+ 'defaultVariants'
10
+ ],
11
+ config: 'master.css'
12
+ };
13
+
14
+ export { settings as default };
@@ -0,0 +1,92 @@
1
+ 'use strict';
2
+
3
+ function defineVisitors({ context, settings }, visitNode) {
4
+ const classAttributeRegex = new RegExp(`^(?:${settings.classAttributes.join('|')})$`);
5
+ const classFunctionsRegex = new RegExp(`^(?:${settings.classFunctions.join('|')})`);
6
+ const classDeclarationsRegex = new RegExp(`^(?:${settings.classDeclarations.join('|')})$`);
7
+ const isFnNode = (node)=>{
8
+ let calleeName = '';
9
+ const calleeNode = node.callee || node.tag;
10
+ if (calleeNode.type === 'Identifier') {
11
+ calleeName = calleeNode.name;
12
+ }
13
+ if (calleeNode.type === 'MemberExpression') {
14
+ calleeName = `${calleeNode.object.name}.${calleeNode.property.name}`;
15
+ }
16
+ return classFunctionsRegex.test(calleeName);
17
+ };
18
+ const CallExpression = function(node) {
19
+ if (!isFnNode(node)) {
20
+ return;
21
+ }
22
+ node.arguments.forEach((arg)=>{
23
+ visitNode(node, arg);
24
+ });
25
+ };
26
+ const scriptVisitor = {
27
+ CallExpression,
28
+ JSXAttribute: function(node) {
29
+ if (!node.name || !classAttributeRegex.test(node.name.name)) return;
30
+ if (node.value && node.value.type === 'Literal') {
31
+ visitNode(node);
32
+ } else if (node.value && node.value.type === 'JSXExpressionContainer') {
33
+ visitNode(node, node.value.expression);
34
+ }
35
+ },
36
+ SvelteAttribute: function(node) {
37
+ if (!node.key?.name || !classAttributeRegex.test(node.key.name)) return;
38
+ for (const eachValue of node.value){
39
+ visitNode(node, eachValue);
40
+ }
41
+ },
42
+ TextAttribute: function(node) {
43
+ if (!node.name || !classAttributeRegex.test(node.name)) return;
44
+ visitNode(node);
45
+ },
46
+ TaggedTemplateExpression: function(node) {
47
+ if (isFnNode(node)) {
48
+ visitNode(node, node.quasi);
49
+ return;
50
+ }
51
+ },
52
+ VariableDeclaration: function(node) {
53
+ node.declarations.forEach((decl)=>{
54
+ if (decl.id.type === 'Identifier' && classDeclarationsRegex.test(decl.id.name)) {
55
+ visitNode(node, decl.init);
56
+ }
57
+ });
58
+ },
59
+ ObjectExpression: function(node) {
60
+ node.properties.forEach((prop)=>{
61
+ if (prop.type === 'Property' && prop.key.type === 'Identifier' && classDeclarationsRegex.test(prop.key.name)) {
62
+ visitNode(node, prop.value);
63
+ }
64
+ });
65
+ }
66
+ };
67
+ const templateBodyVisitor = {
68
+ CallExpression,
69
+ VAttribute: function(node) {
70
+ if (node.value && node.value.type === 'VLiteral') {
71
+ visitNode(node);
72
+ } else if (node.value && node.value.type === 'VExpressionContainer' && node.value.expression?.type === 'ArrayExpression') {
73
+ node.value.expression.elements.forEach((arg)=>{
74
+ visitNode(node, arg);
75
+ });
76
+ } else if (node.value && node.value.type === 'VExpressionContainer' && node.value.expression?.type === 'ObjectExpression') {
77
+ node.value.expression.properties.forEach((prop)=>{
78
+ visitNode(node, prop);
79
+ });
80
+ }
81
+ }
82
+ };
83
+ // @ts-expect-error defineTemplateBodyVisitor
84
+ if (context.sourceCode.parserServices == null || context.sourceCode.parserServices.defineTemplateBodyVisitor == null) {
85
+ return scriptVisitor;
86
+ } else {
87
+ // @ts-expect-error defineTemplateBodyVisitor
88
+ return context.sourceCode.parserServices.defineTemplateBodyVisitor(templateBodyVisitor, scriptVisitor);
89
+ }
90
+ }
91
+
92
+ module.exports = defineVisitors;
@@ -1,5 +1,7 @@
1
- import { Rule } from 'eslint';
1
+ import { TSESTree } from '@typescript-eslint/utils';
2
+ import type { RuleContext, RuleListener } from '@typescript-eslint/utils/ts-eslint';
3
+ import { Settings } from '../settings';
2
4
  export default function defineVisitors({ context, settings }: {
3
- context: Rule.RuleContext;
4
- settings: any;
5
- }, visitNode: any): any;
5
+ context: RuleContext<any, any[]>;
6
+ settings: Settings;
7
+ }, visitNode: (node: TSESTree.Node, args?: any) => void): RuleListener;
@@ -1 +1,90 @@
1
- function f({context:a,settings:l},r){const n=e=>{let t="";const s=e.callee||e.tag;return s.type==="Identifier"&&(t=s.name),s.type==="MemberExpression"&&(t=`${s.object.name}.${s.property.name}`),new RegExp(l.calleeMatching).test(t)},u=function(e){n(e)&&e.arguments.forEach(t=>{r(e,t)})},i=new RegExp(l.classMatching),p={CallExpression:u,JSXAttribute:function(e){!e.name||!i.test(e.name.name)||(e.value&&e.value.type==="Literal"?r(e):e.value&&e.value.type==="JSXExpressionContainer"&&r(e,e.value.expression))},SvelteAttribute:function(e){if(!(!e.key?.name||!i.test(e.key.name)))for(const t of e.value)r(e,t)},TextAttribute:function(e){!e.name||!i.test(e.name)||r(e)},TaggedTemplateExpression:function(e){if(n(e)){r(e,e.quasi);return}}},c={CallExpression:u,VAttribute:function(e){e.value&&e.value.type==="VLiteral"?r(e):e.value&&e.value.type==="VExpressionContainer"&&e.value.expression.type==="ArrayExpression"?e.value.expression.elements.forEach(t=>{r(e,t)}):e.value&&e.value.type==="VExpressionContainer"&&e.value.expression.type==="ObjectExpression"&&e.value.expression.properties.forEach(t=>{r(e,t)})}};return a.sourceCode.parserServices==null||a.sourceCode.parserServices.defineTemplateBodyVisitor==null?p:a.sourceCode.parserServices.defineTemplateBodyVisitor(c,p)}export{f as default};
1
+ function defineVisitors({ context, settings }, visitNode) {
2
+ const classAttributeRegex = new RegExp(`^(?:${settings.classAttributes.join('|')})$`);
3
+ const classFunctionsRegex = new RegExp(`^(?:${settings.classFunctions.join('|')})`);
4
+ const classDeclarationsRegex = new RegExp(`^(?:${settings.classDeclarations.join('|')})$`);
5
+ const isFnNode = (node)=>{
6
+ let calleeName = '';
7
+ const calleeNode = node.callee || node.tag;
8
+ if (calleeNode.type === 'Identifier') {
9
+ calleeName = calleeNode.name;
10
+ }
11
+ if (calleeNode.type === 'MemberExpression') {
12
+ calleeName = `${calleeNode.object.name}.${calleeNode.property.name}`;
13
+ }
14
+ return classFunctionsRegex.test(calleeName);
15
+ };
16
+ const CallExpression = function(node) {
17
+ if (!isFnNode(node)) {
18
+ return;
19
+ }
20
+ node.arguments.forEach((arg)=>{
21
+ visitNode(node, arg);
22
+ });
23
+ };
24
+ const scriptVisitor = {
25
+ CallExpression,
26
+ JSXAttribute: function(node) {
27
+ if (!node.name || !classAttributeRegex.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 || !classAttributeRegex.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 || !classAttributeRegex.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
+ VariableDeclaration: function(node) {
51
+ node.declarations.forEach((decl)=>{
52
+ if (decl.id.type === 'Identifier' && classDeclarationsRegex.test(decl.id.name)) {
53
+ visitNode(node, decl.init);
54
+ }
55
+ });
56
+ },
57
+ ObjectExpression: function(node) {
58
+ node.properties.forEach((prop)=>{
59
+ if (prop.type === 'Property' && prop.key.type === 'Identifier' && classDeclarationsRegex.test(prop.key.name)) {
60
+ visitNode(node, prop.value);
61
+ }
62
+ });
63
+ }
64
+ };
65
+ const templateBodyVisitor = {
66
+ CallExpression,
67
+ VAttribute: function(node) {
68
+ if (node.value && node.value.type === 'VLiteral') {
69
+ visitNode(node);
70
+ } else if (node.value && node.value.type === 'VExpressionContainer' && node.value.expression?.type === 'ArrayExpression') {
71
+ node.value.expression.elements.forEach((arg)=>{
72
+ visitNode(node, arg);
73
+ });
74
+ } else if (node.value && node.value.type === 'VExpressionContainer' && node.value.expression?.type === 'ObjectExpression') {
75
+ node.value.expression.properties.forEach((prop)=>{
76
+ visitNode(node, prop);
77
+ });
78
+ }
79
+ }
80
+ };
81
+ // @ts-expect-error defineTemplateBodyVisitor
82
+ if (context.sourceCode.parserServices == null || context.sourceCode.parserServices.defineTemplateBodyVisitor == null) {
83
+ return scriptVisitor;
84
+ } else {
85
+ // @ts-expect-error defineTemplateBodyVisitor
86
+ return context.sourceCode.parserServices.defineTemplateBodyVisitor(templateBodyVisitor, scriptVisitor);
87
+ }
88
+ }
89
+
90
+ export { defineVisitors as default };