@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.
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
package/README.md CHANGED
@@ -41,7 +41,7 @@
41
41
  <img alt="Follow @mastercorg" src="https://img.shields.io/static/v1?label=%20&message=twitter&color=f6f7f8&logo=twitter&style=for-the-badge">
42
42
  </picture>
43
43
  </a>
44
- <a aria-label="Github Actions" href="https://github.com/1aron/repo/actions/workflows/release.yml">
44
+ <a aria-label="Github Actions" href="https://github.com/master-co/css/actions/workflows/release.yml">
45
45
  <picture>
46
46
  <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/actions/workflow/status/master-co/css/release.yml?branch=rc&label=%20&message=twitter&color=212022&logo=githubactions&style=for-the-badge">
47
47
  <source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/github/actions/workflow/status/master-co/css/release.yml?branch=rc&label=%20&message=twitter&color=f6f7f8&logo=githubactions&style=for-the-badge&logoColor=%23000">
@@ -53,7 +53,7 @@
53
53
  </div>
54
54
 
55
55
  ## Documentation
56
- Check out the official [documentation](https://rc.css.master.co/docs/code-linting).
56
+ Check out the official [documentation](https://rc.css.master.co/guide/code-linting).
57
57
 
58
58
  ## Credits
59
59
  This plugin is heavily inspired by the awesome [eslint-plugin-tailwindcss](https://github.com/francoismassart/eslint-plugin-tailwindcss). We want to thank for their initial work, which served as the foundation for this project. While significant modifications have been made, the core ideas and concepts from A Plugin have been instrumental in developing this plugin.
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+
3
+ var css = require('@master/css');
4
+ var utils = require('@typescript-eslint/utils');
5
+
6
+ var createRule = utils.ESLintUtils.RuleCreator((name)=>new URL(`/docs/code-linting#${name}`, css.OFFICIAL_URL).href);
7
+
8
+ module.exports = createRule;
@@ -0,0 +1,3 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ declare const _default: <Options extends readonly unknown[], MessageIds extends string>({ name, meta, ...rule }: Readonly<ESLintUtils.RuleWithMetaAndName<Options, MessageIds>>) => ESLintUtils.RuleModule<MessageIds, Options, ESLintUtils.RuleListener>;
3
+ export default _default;
@@ -0,0 +1,6 @@
1
+ import { OFFICIAL_URL } from '@master/css';
2
+ import { ESLintUtils } from '@typescript-eslint/utils';
3
+
4
+ var createRule = ESLintUtils.RuleCreator((name)=>new URL(`/docs/code-linting#${name}`, OFFICIAL_URL).href);
5
+
6
+ export { createRule as default };
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ var cssValidator = require('@master/css-validator');
4
+ var css = require('@master/css');
5
+
6
+ function filterCollisionClasses(classNames, css$1) {
7
+ const validRules = classNames.map((eachClassName)=>cssValidator.generateValidRules(eachClassName, css$1)[0]).filter(Boolean);
8
+ const collisionClassesRecord = {};
9
+ for(let i = 0; i < classNames.length; i++){
10
+ const className = classNames[i];
11
+ const rule = validRules.find((eachValidRule)=>eachValidRule.className === className);
12
+ const collisionClasses = [];
13
+ if (rule) {
14
+ for(let j = 0; j < classNames.length; j++){
15
+ const compareClassName = classNames[j];
16
+ const compareRule = validRules.find((eachValidRule)=>eachValidRule.className === compareClassName);
17
+ if (i !== j && compareRule && css.areRulesDuplicated(rule, compareRule) && css.areRuleStatesEqual(rule, compareRule)) {
18
+ collisionClasses.push(compareClassName);
19
+ }
20
+ }
21
+ if (collisionClasses.length > 0) {
22
+ collisionClassesRecord[className] = collisionClasses;
23
+ }
24
+ }
25
+ }
26
+ return collisionClassesRecord;
27
+ }
28
+
29
+ module.exports = filterCollisionClasses;
@@ -0,0 +1,2 @@
1
+ import { MasterCSS } from '@master/css';
2
+ export default function filterCollisionClasses(classNames: string[], css: MasterCSS): Record<string, string[]>;
@@ -0,0 +1,27 @@
1
+ import { generateValidRules } from '@master/css-validator';
2
+ import { areRulesDuplicated, areRuleStatesEqual } from '@master/css';
3
+
4
+ function filterCollisionClasses(classNames, css) {
5
+ const validRules = classNames.map((eachClassName)=>generateValidRules(eachClassName, css)[0]).filter(Boolean);
6
+ const collisionClassesRecord = {};
7
+ for(let i = 0; i < classNames.length; i++){
8
+ const className = classNames[i];
9
+ const rule = validRules.find((eachValidRule)=>eachValidRule.className === className);
10
+ const collisionClasses = [];
11
+ if (rule) {
12
+ for(let j = 0; j < classNames.length; j++){
13
+ const compareClassName = classNames[j];
14
+ const compareRule = validRules.find((eachValidRule)=>eachValidRule.className === compareClassName);
15
+ if (i !== j && compareRule && areRulesDuplicated(rule, compareRule) && areRuleStatesEqual(rule, compareRule)) {
16
+ collisionClasses.push(compareClassName);
17
+ }
18
+ }
19
+ if (collisionClasses.length > 0) {
20
+ collisionClassesRecord[className] = collisionClasses;
21
+ }
22
+ }
23
+ }
24
+ return collisionClassesRecord;
25
+ }
26
+
27
+ export { filterCollisionClasses as default };
package/dist/index.cjs ADDED
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ var plugin = require('./plugin.cjs');
4
+ var settings = require('./settings.cjs');
5
+
6
+ const parserOptions = {
7
+ ecmaFeatures: {
8
+ jsx: true
9
+ }
10
+ };
11
+ const rules = {
12
+ '@master/css/class-order': 'warn',
13
+ '@master/css/class-validation': 'error',
14
+ '@master/css/class-collision': 'warn'
15
+ };
16
+ /** @type {import('typescript-eslint').Config} */ var index = {
17
+ ...plugin,
18
+ configs: {
19
+ recommended: {
20
+ plugins: [
21
+ '@master/css'
22
+ ],
23
+ rules,
24
+ parserOptions
25
+ },
26
+ flat: {
27
+ plugins: {
28
+ '@master/css': plugin
29
+ },
30
+ rules,
31
+ languageOptions: {
32
+ parserOptions
33
+ }
34
+ }
35
+ },
36
+ settings
37
+ };
38
+
39
+ module.exports = index;
package/dist/index.d.ts CHANGED
@@ -1 +1,61 @@
1
- export {};
1
+ /** @type {import('typescript-eslint').Config} */
2
+ declare const _default: {
3
+ configs: {
4
+ recommended: {
5
+ plugins: string[];
6
+ rules: {
7
+ '@master/css/class-order': string;
8
+ '@master/css/class-validation': string;
9
+ '@master/css/class-collision': string;
10
+ };
11
+ parserOptions: {
12
+ ecmaFeatures: {
13
+ jsx: boolean;
14
+ };
15
+ };
16
+ };
17
+ flat: {
18
+ plugins: {
19
+ '@master/css': {
20
+ meta: {
21
+ name: string;
22
+ };
23
+ rules: {
24
+ 'class-collision': import("@typescript-eslint/utils/ts-eslint").RuleModule<"collisionClass", [], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
25
+ 'class-order': import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidClassOrder", [], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
26
+ 'class-validation': import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidClass" | "disallowUnknownClass", [], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
27
+ };
28
+ };
29
+ };
30
+ rules: {
31
+ '@master/css/class-order': string;
32
+ '@master/css/class-validation': string;
33
+ '@master/css/class-collision': string;
34
+ };
35
+ languageOptions: {
36
+ parserOptions: {
37
+ ecmaFeatures: {
38
+ jsx: boolean;
39
+ };
40
+ };
41
+ };
42
+ };
43
+ };
44
+ settings: {
45
+ classAttributes: string[];
46
+ classFunctions: string[];
47
+ classDeclarations: string[];
48
+ ignoredKeys: string[];
49
+ /** @type {import('typescript-eslint').Config} */
50
+ config: string;
51
+ };
52
+ meta: {
53
+ name: string;
54
+ };
55
+ rules: {
56
+ 'class-collision': import("@typescript-eslint/utils/ts-eslint").RuleModule<"collisionClass", [], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
57
+ 'class-order': import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidClassOrder", [], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
58
+ 'class-validation': import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidClass" | "disallowUnknownClass", [], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
59
+ };
60
+ };
61
+ export default _default;
package/dist/index.mjs CHANGED
@@ -1 +1,37 @@
1
- var i=(r,o)=>()=>(o||r((o={exports:{}}).exports,o),o.exports);import t from"./plugin.mjs";import f from"./settings.mjs";import p from"./configs/recommended.mjs";import e from"./configs/flat.mjs";var n=i((x,m)=>{m.exports={...t,configs:{recommended:p,flat:e},settings:f}});export default n();
1
+ import plugin from './plugin.mjs';
2
+ import settings from './settings.mjs';
3
+
4
+ const parserOptions = {
5
+ ecmaFeatures: {
6
+ jsx: true
7
+ }
8
+ };
9
+ const rules = {
10
+ '@master/css/class-order': 'warn',
11
+ '@master/css/class-validation': 'error',
12
+ '@master/css/class-collision': 'warn'
13
+ };
14
+ /** @type {import('typescript-eslint').Config} */ var index = {
15
+ ...plugin,
16
+ configs: {
17
+ recommended: {
18
+ plugins: [
19
+ '@master/css'
20
+ ],
21
+ rules,
22
+ parserOptions
23
+ },
24
+ flat: {
25
+ plugins: {
26
+ '@master/css': plugin
27
+ },
28
+ rules,
29
+ languageOptions: {
30
+ parserOptions
31
+ }
32
+ }
33
+ },
34
+ settings
35
+ };
36
+
37
+ export { index as default };
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ var classCollision = require('./rules/class-collision.cjs');
4
+ var classOrder = require('./rules/class-order.cjs');
5
+ var classValidation = require('./rules/class-validation.cjs');
6
+
7
+ const plugin = {
8
+ meta: {
9
+ name: '@master/eslint-plugin-css'
10
+ },
11
+ rules: {
12
+ 'class-collision': classCollision,
13
+ 'class-order': classOrder,
14
+ 'class-validation': classValidation
15
+ }
16
+ };
17
+
18
+ module.exports = plugin;
package/dist/plugin.d.ts CHANGED
@@ -1,3 +1,11 @@
1
- import type { ESLint } from 'eslint';
2
- declare const plugin: ESLint.Plugin;
1
+ declare const plugin: {
2
+ meta: {
3
+ name: string;
4
+ };
5
+ rules: {
6
+ 'class-collision': import("@typescript-eslint/utils/ts-eslint").RuleModule<"collisionClass", [], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
7
+ 'class-order': import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidClassOrder", [], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
8
+ 'class-validation': import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidClass" | "disallowUnknownClass", [], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
9
+ };
10
+ };
3
11
  export default plugin;
package/dist/plugin.mjs CHANGED
@@ -1 +1,16 @@
1
- import s from"./rules/class-collision.mjs";import i from"./rules/class-order.mjs";import l from"./rules/class-validation.mjs";const o={meta:{name:"@master/eslint-plugin-css"},rules:{"class-collision":s,"class-order":i,"class-validation":l}};var n=o;export{n as default};
1
+ import classCollision from './rules/class-collision.mjs';
2
+ import classOrder from './rules/class-order.mjs';
3
+ import classValidation from './rules/class-validation.mjs';
4
+
5
+ const plugin = {
6
+ meta: {
7
+ name: '@master/eslint-plugin-css'
8
+ },
9
+ rules: {
10
+ 'class-collision': classCollision,
11
+ 'class-order': classOrder,
12
+ 'class-validation': classValidation
13
+ }
14
+ };
15
+
16
+ export { plugin as default };
@@ -0,0 +1,69 @@
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 filterCollisionClasses = require('../functions/filter-collision-classes.cjs');
8
+ var createRule = require('../create-rule.cjs');
9
+ var settingsSchema = require('../settings-schema.cjs');
10
+
11
+ var classCollision = createRule({
12
+ name: 'class-collision-detection',
13
+ meta: {
14
+ type: 'layout',
15
+ docs: {
16
+ description: 'Avoid applying classes with the same CSS declaration',
17
+ recommended: 'recommended'
18
+ },
19
+ messages: {
20
+ collisionClass: '{{message}}'
21
+ },
22
+ fixable: 'code',
23
+ schema: [
24
+ settingsSchema
25
+ ]
26
+ },
27
+ defaultOptions: [],
28
+ create (context) {
29
+ const { settings, css } = resolveContext(context);
30
+ const visitNode = (node, arg = null)=>{
31
+ parseNodeRecursive.parseNodeRecursive(node, arg, (classNames, node, originalClassNamesValue, start, end)=>{
32
+ const sourceCode = context.sourceCode;
33
+ const sourceCodeLines = sourceCode.lines;
34
+ const nodeStartLine = node.loc.start.line;
35
+ const nodeEndLine = node.loc.end.line;
36
+ // todo css
37
+ const collisionClassesRecord = filterCollisionClasses(classNames, css);
38
+ for(const className in collisionClassesRecord){
39
+ const collisionClasses = collisionClassesRecord[className];
40
+ const collisionClassNamesMsg = collisionClasses.map((x)=>`"${x}"`).join(' and ');
41
+ let fixClassNames = originalClassNamesValue;
42
+ for (const collisionClassName of collisionClasses){
43
+ const regexSafe = collisionClassName.replace(/(\\|\.|\(|\)|\[|\]|\{|\}|\+|\*|\?|\^|\$|\||\/)/g, '\\$1');
44
+ fixClassNames = fixClassNames.replace(new RegExp(`\\s+${regexSafe}|${regexSafe}\\s+`), '');
45
+ }
46
+ context.report({
47
+ loc: findLoc(className, sourceCodeLines, nodeStartLine, nodeEndLine),
48
+ messageId: 'collisionClass',
49
+ data: {
50
+ message: `"${className}" applies the same CSS declarations as ${collisionClassNamesMsg}.`
51
+ },
52
+ fix: function(fixer) {
53
+ return fixer.replaceTextRange([
54
+ start,
55
+ end
56
+ ], fixClassNames);
57
+ }
58
+ });
59
+ }
60
+ }, false, false, settings.ignoredKeys, context);
61
+ };
62
+ return defineVisitors({
63
+ context,
64
+ settings
65
+ }, visitNode);
66
+ }
67
+ });
68
+
69
+ module.exports = classCollision;
@@ -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<"collisionClass", [], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
3
2
  export default _default;
@@ -1 +1,67 @@
1
- import $ from"../utils/are-declarations-equal.mjs";import v from"../utils/define-visitors.mjs";import L from"../utils/resolve-context.mjs";import j from"../utils/find-loc.mjs";import{parseNodeRecursive as x}from"../utils/parse-node-recursive.mjs";import M from"../utils/valid-rules-action.mjs";var O={meta:{docs:{description:"Avoid applying classes with the same CSS declaration",category:"Stylistic Issues",recommended:!1,url:"https://rc.css.master.co/docs/code-linting#class-collision-detection"},messages:{collisionClass:"{{message}}"},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(t){const{options:N,settings:a}=L(t);return v({context:t,settings:a},(f,g=null)=>{x(f,g,(i,d,u,C,h)=>{const y=t.sourceCode.lines,R=d.loc.start.line,S=d.loc.end.line,p=M(i,a.config);for(let n=0;n<i.length;n++){const c=i[n],l=p[c],r=[];if(l)for(let s=0;s<i.length;s++){const o=i[s],e=p[o];n!==s&&e&&$(l.declarations,e.declarations)&&l.stateToken===e.stateToken&&r.push(o)}if(r.length>0){const s=r.map(e=>`"${e}"`).join(" and ");let o=u;for(const e of r){const m=e.replace(/(\\|\.|\(|\)|\[|\]|\{|\}|\+|\*|\?|\^|\$|\||\/)/g,"\\$1");o=o.replace(new RegExp(`\\s+${m}|${m}\\s+`),"")}t.report({loc:j(c,y,R,S),messageId:"collisionClass",data:{message:`"${c}" applies the same CSS declarations as ${s}.`},fix:function(e){return e.replaceTextRange([C,h],o)}})}}},!1,!1,a.ignoredKeys,t)})}};export{O 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 filterCollisionClasses from '../functions/filter-collision-classes.mjs';
6
+ import createRule from '../create-rule.mjs';
7
+ import settingsSchema from '../settings-schema.mjs';
8
+
9
+ var classCollision = createRule({
10
+ name: 'class-collision-detection',
11
+ meta: {
12
+ type: 'layout',
13
+ docs: {
14
+ description: 'Avoid applying classes with the same CSS declaration',
15
+ recommended: 'recommended'
16
+ },
17
+ messages: {
18
+ collisionClass: '{{message}}'
19
+ },
20
+ fixable: 'code',
21
+ schema: [
22
+ settingsSchema
23
+ ]
24
+ },
25
+ defaultOptions: [],
26
+ create (context) {
27
+ const { settings, css } = resolveContext(context);
28
+ const visitNode = (node, arg = null)=>{
29
+ parseNodeRecursive(node, arg, (classNames, node, originalClassNamesValue, start, end)=>{
30
+ const sourceCode = context.sourceCode;
31
+ const sourceCodeLines = sourceCode.lines;
32
+ const nodeStartLine = node.loc.start.line;
33
+ const nodeEndLine = node.loc.end.line;
34
+ // todo css
35
+ const collisionClassesRecord = filterCollisionClasses(classNames, css);
36
+ for(const className in collisionClassesRecord){
37
+ const collisionClasses = collisionClassesRecord[className];
38
+ const collisionClassNamesMsg = collisionClasses.map((x)=>`"${x}"`).join(' and ');
39
+ let fixClassNames = originalClassNamesValue;
40
+ for (const collisionClassName of collisionClasses){
41
+ const regexSafe = collisionClassName.replace(/(\\|\.|\(|\)|\[|\]|\{|\}|\+|\*|\?|\^|\$|\||\/)/g, '\\$1');
42
+ fixClassNames = fixClassNames.replace(new RegExp(`\\s+${regexSafe}|${regexSafe}\\s+`), '');
43
+ }
44
+ context.report({
45
+ loc: findLoc(className, sourceCodeLines, nodeStartLine, nodeEndLine),
46
+ messageId: 'collisionClass',
47
+ data: {
48
+ message: `"${className}" applies the same CSS declarations as ${collisionClassNamesMsg}.`
49
+ },
50
+ fix: function(fixer) {
51
+ return fixer.replaceTextRange([
52
+ start,
53
+ end
54
+ ], fixClassNames);
55
+ }
56
+ });
57
+ }
58
+ }, false, false, settings.ignoredKeys, context);
59
+ };
60
+ return defineVisitors({
61
+ context,
62
+ settings
63
+ }, visitNode);
64
+ }
65
+ });
66
+
67
+ export { classCollision as default };
@@ -0,0 +1,174 @@
1
+ 'use strict';
2
+
3
+ var defineVisitors = require('../utils/define-visitors.cjs');
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
+ var createRule = require('../create-rule.cjs');
13
+ var settingsSchema = require('../settings-schema.cjs');
14
+ var css = require('@master/css');
15
+
16
+ var classOrder = createRule({
17
+ name: 'consistent-class-order',
18
+ meta: {
19
+ type: 'layout',
20
+ fixable: 'code',
21
+ docs: {
22
+ description: 'Enforce a consistent and logical order of classes',
23
+ recommended: 'recommended'
24
+ },
25
+ messages: {
26
+ invalidClassOrder: 'No consistent class order followed.'
27
+ },
28
+ schema: [
29
+ settingsSchema
30
+ ]
31
+ },
32
+ defaultOptions: [],
33
+ create: function(context) {
34
+ const { settings, css: css$1 } = resolveContext(context);
35
+ const sourceCode = context.sourceCode;
36
+ const visitNode = (node, arg = null)=>{
37
+ let originalClassNamesValue = null;
38
+ let start = null;
39
+ let end = null;
40
+ let prefix = '';
41
+ let suffix = '';
42
+ let expStrings = [];
43
+ if (arg === null) {
44
+ originalClassNamesValue = extractValueFromNode(node);
45
+ const range = extractRangeFromNode(node);
46
+ if (node.type === 'TextAttribute') {
47
+ start = range[0];
48
+ end = range[1];
49
+ } else {
50
+ start = range[0] + 1;
51
+ end = range[1] - 1;
52
+ }
53
+ } else {
54
+ switch(arg.type){
55
+ case 'Identifier':
56
+ return;
57
+ case 'TemplateLiteral':
58
+ arg.expressions.forEach((exp)=>{
59
+ visitNode(node, exp);
60
+ });
61
+ originalClassNamesValue = sourceCode.getText(arg);
62
+ originalClassNamesValue = originalClassNamesValue.substring(1, originalClassNamesValue.length - 1);
63
+ expStrings = originalClassNamesValue.match(/\$\{(?:(?<!\\\\)(['"`]).*?(?<!\\\\)\1|[^}])*?\}/g) ?? [];
64
+ for(let i = 0; i < expStrings.length; i++){
65
+ originalClassNamesValue = originalClassNamesValue.replace(expStrings[i], `EXPRESSION_STRING_NUM_${i}`);
66
+ }
67
+ start = arg.range[0] + 1;
68
+ end = arg.range[1] - 1;
69
+ break;
70
+ case 'ConditionalExpression':
71
+ visitNode(node, arg.consequent);
72
+ visitNode(node, arg.alternate);
73
+ return;
74
+ case 'LogicalExpression':
75
+ visitNode(node, arg.right);
76
+ return;
77
+ case 'ArrayExpression':
78
+ arg.elements.forEach((el)=>{
79
+ visitNode(node, el);
80
+ });
81
+ return;
82
+ case 'ObjectExpression':
83
+ const isUsedByClassNamesPlugin = node.callee && node.callee.name === 'classnames';
84
+ const isVue = node.key && node.key.type === 'VDirectiveKey';
85
+ arg.properties.forEach((prop)=>{
86
+ const propVal = isUsedByClassNamesPlugin || isVue ? prop.key : prop.value;
87
+ visitNode(node, propVal);
88
+ });
89
+ return;
90
+ case 'Property':
91
+ visitNode(node, arg.key);
92
+ break;
93
+ case 'Literal':
94
+ originalClassNamesValue = arg.raw.slice(1, arg.raw.length - 1);
95
+ start = arg.range[0] + 1;
96
+ end = arg.range[1] - 1;
97
+ break;
98
+ case 'SvelteLiteral':
99
+ originalClassNamesValue = arg.value;
100
+ if (originalClassNamesValue === '') {
101
+ return;
102
+ }
103
+ start = arg.range[0];
104
+ end = arg.range[1];
105
+ break;
106
+ case 'TemplateElement':
107
+ originalClassNamesValue = arg.value.raw;
108
+ if (originalClassNamesValue === '') {
109
+ return;
110
+ }
111
+ start = arg.range[0];
112
+ end = arg.range[1];
113
+ // https://github.com/eslint/eslint/issues/13360
114
+ // The problem is that range computation includes the backticks (`test`)
115
+ // but value.raw does not include them, so there is a mismatch.
116
+ // start/end does not include the backticks, therefore it matches value.raw.
117
+ const txt = context.sourceCode.getText(arg);
118
+ prefix = getTemplateElementPrefix(txt, originalClassNamesValue);
119
+ suffix = getTemplateElementSuffix(txt, originalClassNamesValue);
120
+ originalClassNamesValue = getTemplateElementBody(txt, prefix, suffix);
121
+ break;
122
+ }
123
+ }
124
+ const { classNames, whitespaces, headSpace, tailSpace } = extractClassnamesFromValue(originalClassNamesValue);
125
+ if (classNames.length <= 1) {
126
+ // Don't run sorting for a single or empty className
127
+ return;
128
+ }
129
+ let orderedClassNames = css.reorderForReadableClasses(classNames, css$1).filter((eachOrderedClassName)=>classNames.includes(eachOrderedClassName));
130
+ orderedClassNames = classNames.filter((x)=>!orderedClassNames.includes(x)).concat(orderedClassNames).filter((x)=>x.trim() !== '');
131
+ // Generates the validated/sorted attribute value
132
+ let validatedClassNamesValue = '';
133
+ for(let i = 0; i < orderedClassNames.length; i++){
134
+ const w = whitespaces[i] ?? '';
135
+ const cls = orderedClassNames[i];
136
+ validatedClassNamesValue += headSpace ? `${w}${cls}` : `${cls}${w}`;
137
+ if (cls) {
138
+ if (!tailSpace && i === orderedClassNames.length - 1) {
139
+ validatedClassNamesValue = validatedClassNamesValue.replace(/\s+$/, '');
140
+ }
141
+ if (headSpace && tailSpace && i === orderedClassNames.length - 1) {
142
+ validatedClassNamesValue += whitespaces[whitespaces.length - 1] ?? '';
143
+ }
144
+ }
145
+ }
146
+ for(let i = 0; i < expStrings.length; i++){
147
+ originalClassNamesValue = originalClassNamesValue.replace(`EXPRESSION_STRING_NUM_${i}`, expStrings[i]);
148
+ validatedClassNamesValue = validatedClassNamesValue.replace(`EXPRESSION_STRING_NUM_${i}`, expStrings[i]);
149
+ }
150
+ if (originalClassNamesValue !== validatedClassNamesValue) {
151
+ validatedClassNamesValue = prefix + validatedClassNamesValue + suffix;
152
+ const sourceCodeLines = sourceCode.lines;
153
+ const nodeStartLine = node.loc.start.line;
154
+ const nodeEndLine = node.loc.end.line;
155
+ context.report({
156
+ loc: findLoc(originalClassNamesValue, sourceCodeLines, nodeStartLine, nodeEndLine),
157
+ messageId: 'invalidClassOrder',
158
+ fix: function(fixer) {
159
+ return fixer.replaceTextRange([
160
+ start,
161
+ end
162
+ ], validatedClassNamesValue);
163
+ }
164
+ });
165
+ }
166
+ };
167
+ return defineVisitors({
168
+ context,
169
+ settings
170
+ }, visitNode);
171
+ }
172
+ });
173
+
174
+ module.exports = classOrder;
@@ -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<"invalidClassOrder", [], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
3
2
  export default _default;