@master/eslint-plugin-css 2.0.0-beta.186 → 2.0.0-beta.188

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 (44) hide show
  1. package/dist/config.d.ts +8 -0
  2. package/dist/config.js +1 -0
  3. package/dist/config.mjs +1 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +1 -0
  6. package/dist/index.mjs +1 -0
  7. package/dist/plugin.d.ts +3 -0
  8. package/dist/plugin.js +1 -0
  9. package/dist/plugin.mjs +1 -0
  10. package/dist/rules/class-collision.d.ts +3 -0
  11. package/dist/rules/class-collision.js +1 -0
  12. package/dist/rules/class-collision.mjs +1 -0
  13. package/dist/rules/class-order.d.ts +3 -0
  14. package/dist/rules/class-order.js +1 -0
  15. package/dist/rules/class-order.mjs +1 -0
  16. package/dist/rules/class-validation.d.ts +3 -0
  17. package/dist/rules/class-validation.js +1 -0
  18. package/dist/rules/class-validation.mjs +1 -0
  19. package/dist/settings.d.ts +7 -0
  20. package/dist/settings.js +1 -0
  21. package/dist/settings.mjs +1 -0
  22. package/dist/utils/are-declarations-equal.d.ts +1 -0
  23. package/dist/utils/are-declarations-equal.js +1 -0
  24. package/dist/utils/are-declarations-equal.mjs +1 -0
  25. package/dist/utils/ast.d.ts +31 -0
  26. package/dist/utils/ast.js +1 -0
  27. package/dist/utils/ast.mjs +1 -0
  28. package/dist/utils/define-visitors.d.ts +5 -0
  29. package/dist/utils/define-visitors.js +1 -0
  30. package/dist/utils/define-visitors.mjs +1 -0
  31. package/dist/utils/resolve-context.d.ts +5 -0
  32. package/dist/utils/resolve-context.js +1 -0
  33. package/dist/utils/resolve-context.mjs +1 -0
  34. package/package.json +1 -1
  35. package/lib/index.js +0 -5
  36. package/lib/rules/class-order.js +0 -202
  37. package/lib/rules/class-validation.js +0 -123
  38. package/lib/utils/ast.js +0 -218
  39. package/lib/utils/resolve-context.js +0 -21
  40. package/tests/frameworks/react.js +0 -55
  41. package/tests/frameworks/svelte.js +0 -24
  42. package/tests/frameworks/vue.js +0 -24
  43. package/tests/order.js +0 -66
  44. package/tests/validation.js +0 -69
@@ -0,0 +1,8 @@
1
+ declare const config: {
2
+ readonly rules: {
3
+ readonly '@master/css/class-order': "warn";
4
+ readonly '@master/css/class-validation': "error";
5
+ readonly '@master/css/class-collision': "warn";
6
+ };
7
+ };
8
+ export default config;
package/dist/config.js ADDED
@@ -0,0 +1 @@
1
+ var o=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var t=Object.getOwnPropertyNames;var n=Object.prototype.hasOwnProperty;var i=(a,s)=>{for(var c in s)o(a,c,{get:s[c],enumerable:!0})},d=(a,s,c,e)=>{if(s&&typeof s=="object"||typeof s=="function")for(let r of t(s))!n.call(a,r)&&r!==c&&o(a,r,{get:()=>s[r],enumerable:!(e=l(s,r))||e.enumerable});return a};var m=a=>d(o({},"__esModule",{value:!0}),a);var w={};i(w,{default:()=>u});module.exports=m(w);const f={rules:{"@master/css/class-order":"warn","@master/css/class-validation":"error","@master/css/class-collision":"warn"}};var u=f;
@@ -0,0 +1 @@
1
+ const s={rules:{"@master/css/class-order":"warn","@master/css/class-validation":"error","@master/css/class-collision":"warn"}};var a=s;export{a as default};
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ var g=Object.create;var p=Object.defineProperty;var c=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var a=Object.getPrototypeOf,u=Object.prototype.hasOwnProperty;var d=(s,m,o,n)=>{if(m&&typeof m=="object"||typeof m=="function")for(let r of l(m))!u.call(s,r)&&r!==o&&p(s,r,{get:()=>m[r],enumerable:!(n=c(m,r))||n.enumerable});return s};var i=(s,m,o)=>(o=s!=null?g(a(s)):{},d(m||!s||!s.__esModule?p(o,"default",{value:s,enumerable:!0}):o,s));var t=i(require("./plugin")),e=i(require("./config")),f=i(require("./settings"));module.exports={...t.default,configs:{recommended:{plugins:["@master/css"],...e.default},flat:{plugins:{"@master/css":t.default},...e.default}},settings:f.default};
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ var t=(i,s)=>()=>(s||i((s={exports:{}}).exports,s),s.exports);import m from"./plugin";import o from"./config";import e from"./settings";var n=t((l,r)=>{r.exports={...m,configs:{recommended:{plugins:["@master/css"],...o},flat:{plugins:{"@master/css":m},...o}},settings:e}});export default n();
@@ -0,0 +1,3 @@
1
+ import type { ESLint } from 'eslint';
2
+ declare const plugin: ESLint.Plugin;
3
+ export default plugin;
package/dist/plugin.js ADDED
@@ -0,0 +1 @@
1
+ var p=Object.create;var t=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var u=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var E=(s,i)=>{for(var l in i)t(s,l,{get:i[l],enumerable:!0})},n=(s,i,l,a)=>{if(i&&typeof i=="object"||typeof i=="function")for(let o of f(i))!g.call(s,o)&&o!==l&&t(s,o,{get:()=>i[o],enumerable:!(a=d(i,o))||a.enumerable});return s};var r=(s,i,l)=>(l=s!=null?p(u(s)):{},n(i||!s||!s.__esModule?t(l,"default",{value:s,enumerable:!0}):l,s)),L=s=>n(t({},"__esModule",{value:!0}),s);var x={};E(x,{default:()=>v});module.exports=L(x);var e=r(require("./rules/class-collision")),m=r(require("./rules/class-order")),c=r(require("./rules/class-validation"));const S={meta:{name:"@master/eslint-plugin-css"},rules:{"class-collision":e.default,"class-order":m.default,"class-validation":c.default}};var v=S;
@@ -0,0 +1 @@
1
+ import s from"./rules/class-collision";import i from"./rules/class-order";import l from"./rules/class-validation";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};
@@ -0,0 +1,3 @@
1
+ import { Rule } from 'eslint';
2
+ declare const _default: Rule.RuleModule;
3
+ export default _default;
@@ -0,0 +1 @@
1
+ var I=Object.create;var f=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var V=Object.getOwnPropertyNames;var q=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var D=(e,s)=>{for(var o in s)f(e,o,{get:s[o],enumerable:!0})},R=(e,s,o,r)=>{if(s&&typeof s=="object"||typeof s=="function")for(let l of V(s))!A.call(e,l)&&l!==o&&f(e,l,{get:()=>s[l],enumerable:!(r=M(s,l))||r.enumerable});return e};var m=(e,s,o)=>(o=e!=null?I(q(e)):{},R(s||!e||!e.__esModule?f(o,"default",{value:e,enumerable:!0}):o,e)),K=e=>R(f({},"__esModule",{value:!0}),e);var U={};D(U,{default:()=>O});module.exports=K(U);var S=m(require("../utils/ast")),$=m(require("../utils/are-declarations-equal")),v=m(require("../utils/define-visitors")),x=m(require("../utils/resolve-context")),y=require("@master/css-validator"),O={meta:{docs:{description:"Avoid applying classes with the same CSS declaration",category:"Stylistic Issues",recommended:!1,url:"https://beta.css.master.co/docs/code-linting#class-collision-detection"},messages:{collisionClass:"{{message}}"},fixable:"code"},create(e){const{options:s,settings:o,config:r}=(0,x.default)(e);return(0,v.default)({context:e,options:s,settings:o,config:r},(E,L=null)=>{S.parseNodeRecursive(E,L,(c,C,N,T,b)=>{const j=e.sourceCode.lines,k=C.loc.start.line,w=C.loc.end.line,p={};c.forEach(i=>{p[i]=(0,y.createValidRules)(i,{config:r})[0]});for(let i=0;i<c.length;i++){const u=c[i],g=p[u],d=[];if(g)for(let n=0;n<c.length;n++){const a=c[n],t=p[a];i!==n&&t&&(0,$.default)(g.declarations,t.declarations)&&g.stateToken===t.stateToken&&d.push(a)}if(d.length>0){const n=d.map(t=>`"${t}"`).join(" and ");let a=N;for(const t of d){const h=t.replace(/(\\|\.|\(|\)|\[|\]|\{|\}|\+|\*|\?|\^|\$|\||\/)/g,"\\$1");a=a.replace(new RegExp(`\\s+${h}|${h}\\s+`),"")}e.report({loc:S.findLoc(u,j,k,w),messageId:"collisionClass",data:{message:`"${u}" applies the same CSS declarations as ${n}.`},fix:function(t){return t.replaceTextRange([T,b],a)}})}}},!1,!1,o.ignoredKeys,e)})}};
@@ -0,0 +1 @@
1
+ import*as u from"../utils/ast";import E from"../utils/are-declarations-equal";import L from"../utils/define-visitors";import N from"../utils/resolve-context";import{createValidRules as T}from"@master/css-validator";var A={meta:{docs:{description:"Avoid applying classes with the same CSS declaration",category:"Stylistic Issues",recommended:!1,url:"https://beta.css.master.co/docs/code-linting#class-collision-detection"},messages:{collisionClass:"{{message}}"},fixable:"code"},create(i){const{options:g,settings:d,config:f}=N(i);return L({context:i,options:g,settings:d,config:f},(C,h=null)=>{u.parseNodeRecursive(C,h,(l,m,R,S,$)=>{const v=i.sourceCode.lines,x=m.loc.start.line,y=m.loc.end.line,a={};l.forEach(s=>{a[s]=T(s,{config:f})[0]});for(let s=0;s<l.length;s++){const r=l[s],c=a[r],n=[];if(c)for(let o=0;o<l.length;o++){const t=l[o],e=a[t];s!==o&&e&&E(c.declarations,e.declarations)&&c.stateToken===e.stateToken&&n.push(t)}if(n.length>0){const o=n.map(e=>`"${e}"`).join(" and ");let t=R;for(const e of n){const p=e.replace(/(\\|\.|\(|\)|\[|\]|\{|\}|\+|\*|\?|\^|\$|\||\/)/g,"\\$1");t=t.replace(new RegExp(`\\s+${p}|${p}\\s+`),"")}i.report({loc:u.findLoc(r,v,x,y),messageId:"collisionClass",data:{message:`"${r}" applies the same CSS declarations as ${o}.`},fix:function(e){return e.replaceTextRange([S,$],t)}})}}},!1,!1,d.ignoredKeys,i)})}};export{A as default};
@@ -0,0 +1,3 @@
1
+ import { Rule } from 'eslint';
2
+ declare const _default: Rule.RuleModule;
3
+ export default _default;
@@ -0,0 +1 @@
1
+ var $=Object.create;var y=Object.defineProperty;var F=Object.getOwnPropertyDescriptor;var I=Object.getOwnPropertyNames;var O=Object.getPrototypeOf,P=Object.prototype.hasOwnProperty;var q=(e,a)=>{for(var n in a)y(e,n,{get:a[n],enumerable:!0})},T=(e,a,n,C)=>{if(a&&typeof a=="object"||typeof a=="function")for(let r of I(a))!P.call(e,r)&&r!==n&&y(e,r,{get:()=>a[r],enumerable:!(C=F(a,r))||C.enumerable});return e};var N=(e,a,n)=>(n=e!=null?$(O(e)):{},T(a||!e||!e.__esModule?y(n,"default",{value:e,enumerable:!0}):n,e)),A=e=>T(y({},"__esModule",{value:!0}),e);var U={};q(U,{default:()=>B});module.exports=A(U);var m=N(require("../utils/ast")),V=N(require("../utils/define-visitors")),R=N(require("../utils/resolve-context")),S=require("@master/css"),B={meta:{docs:{description:"Enforce a consistent and logical order of classes",category:"Stylistic Issues",recommended:!1,url:"https://beta.css.master.co/docs/code-linting#consistent-class-order"},messages:{invalidClassOrder:"No consistent class order followed."},fixable:"code"},create:function(e){const{options:a,settings:n,config:C}=(0,R.default)(e),r=(l,s=null)=>{let i=null,p=null,d=null,E="",v="";if(s===null){i=m.extractValueFromNode(l);const t=m.extractRangeFromNode(l);l.type==="TextAttribute"?(p=t[0],d=t[1]):(p=t[0]+1,d=t[1]-1)}else switch(s.type){case"Identifier":return;case"TemplateLiteral":s.expressions.forEach(o=>{r(l,o)}),s.quasis.forEach(o=>{r(l,o)});return;case"ConditionalExpression":r(l,s.consequent),r(l,s.alternate);return;case"LogicalExpression":r(l,s.right);return;case"ArrayExpression":s.elements.forEach(o=>{r(l,o)});return;case"ObjectExpression":const t=l.callee&&l.callee.name==="classnames",x=l.key&&l.key.type==="VDirectiveKey";s.properties.forEach(o=>{const b=t||x?o.key:o.value;r(l,b)});return;case"Property":r(l,s.key);break;case"Literal":i=s.value,p=s.range[0]+1,d=s.range[1]-1;break;case"SvelteLiteral":if(i=s.value,i==="")return;p=s.range[0],d=s.range[1];break;case"TemplateElement":if(i=s.value.raw,i==="")return;p=s.range[0],d=s.range[1];const c=e.sourceCode.getText(s);E=m.getTemplateElementPrefix(c,i),v=m.getTemplateElementSuffix(c,i),i=m.getTemplateElementBody(c,E,v);break}const{classNames:h,whitespaces:g,headSpace:k,tailSpace:L}=m.extractClassnamesFromValue(i);if(h.length<=1)return;let f=(0,S.reorderForReadableClasses)(h,C).filter(t=>h.includes(t));f=h.filter(t=>!f.includes(t)).concat(f).filter(t=>t.trim()!=="");let u="";for(let t=0;t<f.length;t++){const x=g[t]??"",c=f[t];u+=k?`${x}${c}`:`${c}${x}`,c&&(!L&&t===f.length-1&&(u=u.replace(/\s+$/,"")),k&&L&&t===f.length-1&&(u+=g[g.length-1]??""))}if(i!==u){u=E+u+v;const x=e.sourceCode.lines,c=l.loc.start.line,o=l.loc.end.line,b={loc:m.findLoc(i,x,c,o),messageId:"invalidClassOrder",fix:function(w){return w.replaceTextRange([p,d],u)}};e.report(b)}};return(0,V.default)({context:e,options:a,settings:n,config:C},r)}};
@@ -0,0 +1 @@
1
+ import*as c from"../utils/ast";import L from"../utils/define-visitors";import T from"../utils/resolve-context";import{reorderForReadableClasses as V}from"@master/css";var I={meta:{docs:{description:"Enforce a consistent and logical order of classes",category:"Stylistic Issues",recommended:!1,url:"https://beta.css.master.co/docs/code-linting#consistent-class-order"},messages:{invalidClassOrder:"No consistent class order followed."},fixable:"code"},create:function(p){const{options:b,settings:N,config:E}=T(p),a=(t,e=null)=>{let l=null,u=null,f=null,x="",C="";if(e===null){l=c.extractValueFromNode(t);const s=c.extractRangeFromNode(t);t.type==="TextAttribute"?(u=s[0],f=s[1]):(u=s[0]+1,f=s[1]-1)}else switch(e.type){case"Identifier":return;case"TemplateLiteral":e.expressions.forEach(r=>{a(t,r)}),e.quasis.forEach(r=>{a(t,r)});return;case"ConditionalExpression":a(t,e.consequent),a(t,e.alternate);return;case"LogicalExpression":a(t,e.right);return;case"ArrayExpression":e.elements.forEach(r=>{a(t,r)});return;case"ObjectExpression":const s=t.callee&&t.callee.name==="classnames",m=t.key&&t.key.type==="VDirectiveKey";e.properties.forEach(r=>{const y=s||m?r.key:r.value;a(t,y)});return;case"Property":a(t,e.key);break;case"Literal":l=e.value,u=e.range[0]+1,f=e.range[1]-1;break;case"SvelteLiteral":if(l=e.value,l==="")return;u=e.range[0],f=e.range[1];break;case"TemplateElement":if(l=e.value.raw,l==="")return;u=e.range[0],f=e.range[1];const i=p.sourceCode.getText(e);x=c.getTemplateElementPrefix(i,l),C=c.getTemplateElementSuffix(i,l),l=c.getTemplateElementBody(i,x,C);break}const{classNames:d,whitespaces:h,headSpace:v,tailSpace:g}=c.extractClassnamesFromValue(l);if(d.length<=1)return;let o=V(d,E).filter(s=>d.includes(s));o=d.filter(s=>!o.includes(s)).concat(o).filter(s=>s.trim()!=="");let n="";for(let s=0;s<o.length;s++){const m=h[s]??"",i=o[s];n+=v?`${m}${i}`:`${i}${m}`,i&&(!g&&s===o.length-1&&(n=n.replace(/\s+$/,"")),v&&g&&s===o.length-1&&(n+=h[h.length-1]??""))}if(l!==n){n=x+n+C;const m=p.sourceCode.lines,i=t.loc.start.line,r=t.loc.end.line,y={loc:c.findLoc(l,m,i,r),messageId:"invalidClassOrder",fix:function(k){return k.replaceTextRange([u,f],n)}};p.report(y)}};return L({context:p,options:b,settings:N,config:E},a)}};export{I as default};
@@ -0,0 +1,3 @@
1
+ import { Rule } from 'eslint';
2
+ declare const _default: Rule.RuleModule;
3
+ export default _default;
@@ -0,0 +1 @@
1
+ var N=Object.create;var n=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var U=Object.getPrototypeOf,I=Object.prototype.hasOwnProperty;var b=(s,e)=>{for(var o in e)n(s,o,{get:e[o],enumerable:!0})},g=(s,e,o,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of S(e))!I.call(s,r)&&r!==o&&n(s,r,{get:()=>e[r],enumerable:!(a=R(e,r))||a.enumerable});return s};var l=(s,e,o)=>(o=s!=null?N(U(s)):{},g(e||!s||!s.__esModule?n(o,"default",{value:s,enumerable:!0}):o,s)),M=s=>g(n({},"__esModule",{value:!0}),s);var E={};b(E,{default:()=>D});module.exports=M(E);var t=l(require("../utils/ast")),p=l(require("../utils/define-visitors")),C=l(require("../utils/resolve-context")),w=require("@master/css-validator"),D={meta:{docs:{description:"Detect syntax errors early when writing classes",category:"Stylistic Issues",recommended:!1,url:"https://beta.css.master.co/docs/code-linting#syntax-error-checks"},messages:{invalidClass:"{{message}}",disallowUnknownClass:"{{message}}"},fixable:null},create:function(s){const{options:e,settings:o,config:a}=(0,C.default)(s);return(0,p.default)({context:s,options:e,settings:o,config:a},(v,y=null)=>{t.parseNodeRecursive(v,y,(k,c)=>{const d=s.sourceCode.lines,m=c.loc.start.line,f=c.loc.end.line;for(const i of k){const{isMasterCSS:L,errors:u}=(0,w.validate)(i,{config:a});if(u.length>0)for(const h of u)L?s.report({loc:t.findLoc(i,d,m,f),messageId:"invalidClass",data:{message:h.message+"."}}):e.disallowUnknownClass&&s.report({loc:t.findLoc(i,d,m,f),messageId:"disallowUnknownClass",data:{message:`"${i}" is not a valid or known class.`}})}},!1,!1,o.ignoredKeys,s)})}};
@@ -0,0 +1 @@
1
+ import*as o from"../utils/ast";import C from"../utils/define-visitors";import w from"../utils/resolve-context";import{validate as v}from"@master/css-validator";var U={meta:{docs:{description:"Detect syntax errors early when writing classes",category:"Stylistic Issues",recommended:!1,url:"https://beta.css.master.co/docs/code-linting#syntax-error-checks"},messages:{invalidClass:"{{message}}",disallowUnknownClass:"{{message}}"},fixable:null},create:function(s){const{options:r,settings:a,config:i}=w(s);return C({context:s,options:r,settings:a,config:i},(m,f=null)=>{o.parseNodeRecursive(m,f,(u,n)=>{const l=s.sourceCode.lines,t=n.loc.start.line,c=n.loc.end.line;for(const e of u){const{isMasterCSS:g,errors:d}=v(e,{config:i});if(d.length>0)for(const p of d)g?s.report({loc:o.findLoc(e,l,t,c),messageId:"invalidClass",data:{message:p.message+"."}}):r.disallowUnknownClass&&s.report({loc:o.findLoc(e,l,t,c),messageId:"disallowUnknownClass",data:{message:`"${e}" is not a valid or known class.`}})}},!1,!1,a.ignoredKeys,s)})}};export{U as default};
@@ -0,0 +1,7 @@
1
+ declare const settings: {
2
+ calleeMatching: string;
3
+ classMatching: string;
4
+ ignoredKeys: string[];
5
+ config: string;
6
+ };
7
+ export default settings;
@@ -0,0 +1 @@
1
+ var e=Object.defineProperty;var n=Object.getOwnPropertyDescriptor;var i=Object.getOwnPropertyNames;var o=Object.prototype.hasOwnProperty;var r=(a,s)=>{for(var t in s)e(a,t,{get:s[t],enumerable:!0})},d=(a,s,t,l)=>{if(s&&typeof s=="object"||typeof s=="function")for(let c of i(s))!o.call(a,c)&&c!==t&&e(a,c,{get:()=>s[c],enumerable:!(l=n(s,c))||l.enumerable});return a};var g=a=>d(e({},"__esModule",{value:!0}),a);var u={};r(u,{default:()=>f});module.exports=g(u);const m={calleeMatching:"^(classnames|clsx|ctl|cva|cv|classVariant|styled(?:\\.\\w+)?)",classMatching:"^class(Name)?$",ignoredKeys:["compoundVariants","defaultVariants"],config:"master.css.*"};var f=m;
@@ -0,0 +1 @@
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};
@@ -0,0 +1 @@
1
+ export default function areDeclarationsEqual(aDeclarations: any, bDeclarations: any): boolean;
@@ -0,0 +1 @@
1
+ var s=Object.defineProperty;var c=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var u=(t,e)=>{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},y=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of f(e))!l.call(t,n)&&n!==r&&s(t,n,{get:()=>e[n],enumerable:!(o=c(e,n))||o.enumerable});return t};var p=t=>y(s({},"__esModule",{value:!0}),t);var O={};u(O,{default:()=>a});module.exports=p(O);function a(t,e){const r=Object.keys(t),o=Object.keys(e);if(r.length!==o.length)return!1;for(const n of r)if(!Object.prototype.hasOwnProperty.call(e,n))return!1;return!0}
@@ -0,0 +1 @@
1
+ function s(r,e){const t=Object.keys(r),n=Object.keys(e);if(t.length!==n.length)return!1;for(const o of t)if(!Object.prototype.hasOwnProperty.call(e,o))return!1;return!0}export{s as default};
@@ -0,0 +1,31 @@
1
+ import { Rule } from 'eslint';
2
+ export declare function extractRangeFromNode(node: any): any;
3
+ export declare function extractValueFromNode(node: any): any;
4
+ export declare function extractClassnamesFromValue(classStr: any): {
5
+ classNames: string[];
6
+ whitespaces: string[];
7
+ headSpace: boolean;
8
+ tailSpace: boolean;
9
+ };
10
+ /**
11
+ * Inspect and parse an abstract syntax node and run a callback function
12
+ *
13
+ * @param {ASTNode} rootNode The current root node being parsed by eslint
14
+ * @param {ASTNode} childNode The AST node child argument being checked
15
+ * @param {Function} cb The callback function
16
+ * @param {Boolean} skipConditional Optional, indicate distinct parsing for conditional nodes
17
+ * @param {Boolean} isolate Optional, set internally to isolate parsing and validation on conditional children
18
+ * @param {Array} ignoredKeys Optional, set object keys which should not be parsed e.g. for `cva`
19
+ * @returns {void}
20
+ */
21
+ export declare function parseNodeRecursive(rootNode: any, childNode: any, cb: any, skipConditional?: boolean, isolate?: boolean, ignoredKeys?: any[], context?: Rule.RuleContext): void;
22
+ export declare function getTemplateElementPrefix(text: any, raw: any): any;
23
+ export declare function getTemplateElementSuffix(text: any, raw: any): any;
24
+ export declare function getTemplateElementBody(text: any, prefix: any, suffix: any): any;
25
+ export declare function findLoc(text: any, lines: any, startLine: any, endLine: any): {
26
+ start: any;
27
+ end: {
28
+ line: any;
29
+ column: any;
30
+ };
31
+ };
@@ -0,0 +1 @@
1
+ var E=Object.defineProperty;var O=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var V=Object.prototype.hasOwnProperty;var F=(e,t)=>{for(var r in t)E(e,r,{get:t[r],enumerable:!0})},P=(e,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let u of j(t))!V.call(e,u)&&u!==r&&E(e,u,{get:()=>t[u],enumerable:!(s=O(t,u))||s.enumerable});return e};var q=e=>P(E({},"__esModule",{value:!0}),e);var J={};F(J,{extractClassnamesFromValue:()=>y,extractRangeFromNode:()=>L,extractValueFromNode:()=>w,findLoc:()=>I,getTemplateElementBody:()=>B,getTemplateElementPrefix:()=>h,getTemplateElementSuffix:()=>R,parseNodeRecursive:()=>x});module.exports=q(J);const S=/([\t\n\f\r ]+)/;function L(e){if(e.type==="TextAttribute"&&e.name==="class")return[e.valueSpan.fullStart.offset,e.valueSpan.end.offset];switch(e.value.type){case"JSXExpressionContainer":return e.value.expression.range;default:return e.value.range}}function w(e){if(e.type==="TextAttribute"&&e.name==="class")return e.value;switch(e.value.type){case"JSXExpressionContainer":return e.value.expression.value;case"VExpressionContainer":switch(e.value.expression.type){case"ArrayExpression":return e.value.expression.elements;case"ObjectExpression":return e.value.expression.properties}return e.value.expression.value;default:return e.value.value}}function y(e){if(typeof e!="string")return{classNames:[],whitespaces:[],headSpace:!1,tailSpace:!1};const t=e.split(S);t[0]===""&&t.shift(),t[t.length-1]===""&&t.pop();const r=S.test(t[0]),s=S.test(t[t.length-1]),u=(a,f)=>r?f%2!==0:f%2===0,n=(a,f)=>r?f%2===0:f%2!==0,m=t.filter(u),l=t.filter(n);return{classNames:m,whitespaces:l,headSpace:r,tailSpace:s}}function x(e,t,r,s=!1,u=!1,n=[],m=null){let l,a,f=null,i=null,g="",v="";if(t===null){if(l=w(e),{classNames:a}=y(l),a=[...new Set(a)],a.length===0)return;const c=L(e);e.type==="TextAttribute"?(f=c[0],i=c[1]):(f=c[0]+1,i=c[1]-1),r(a,e,l,f,i,g,v)}else{if(t===void 0)return;{const c=s?!0:u;let A=!1;switch(t.type){case"TemplateLiteral":t.expressions.forEach(p=>{x(e,p,r,s,c,n)}),t.quasis.forEach(p=>{x(e,p,r,s,u,n)});return;case"ConditionalExpression":x(e,t.consequent,r,s,c,n),x(e,t.alternate,r,s,c,n);return;case"LogicalExpression":x(e,t.right,r,s,c,n);return;case"ArrayExpression":t.elements.forEach(p=>{x(e,p,r,s,c,n)});return;case"ObjectExpression":t.properties.forEach(p=>{const C=e.callee&&e.callee.name==="classnames";p.type!=="SpreadElement"&&(p.key.type==="Identifier"&&n.includes(p.key.name)||x(e,C?p.key:p.value,r,s,c,n))});return;case"Property":x(e,t.key,r,s,c,n);return;case"Literal":A=!0,l=t.value,f=t.range[0]+1,i=t.range[1]-1;break;case"SvelteLiteral":l=t.value,f=t.range[0],i=t.range[1];break;case"TemplateElement":l=t.value.raw,f=t.range[0],i=t.range[1];const T=m?.sourceCode.getText(t)??"";g=h(T,l),v=R(T,l);break}if({classNames:a}=y(l),a=[...new Set(a)],a.length===0)return;r(a,u?null:e,l,f,i,g,v)}}}function h(e,t){return e.indexOf(t)===0?"":e.split(t).shift()}function R(e,t){return e.indexOf(t)===-1?"":e.split(t).pop()}function B(e,t,r){let s=e.split(t);return s.shift(),s=s.join(t).split(r),s.pop(),s.join(r)}function I(e,t,r,s){const u=e.match(/.+(?:\r\n|\n)?/g);let n=0,m=null,l=!1;for(let a=r;a<=s;a++){const i=t[a-1].indexOf(u[n].replace(/\r\n|\n/,""));if(i!==-1){if(n===0&&(m={line:a,column:i}),n===u.length-1)return{start:m,end:{line:a,column:i+e.length}};l=!0,n++}else l&&(l=!1,n=0,m=null)}return null}
@@ -0,0 +1 @@
1
+ const E=/([\t\n\f\r ]+)/;function w(e){if(e.type==="TextAttribute"&&e.name==="class")return[e.valueSpan.fullStart.offset,e.valueSpan.end.offset];switch(e.value.type){case"JSXExpressionContainer":return e.value.expression.range;default:return e.value.range}}function h(e){if(e.type==="TextAttribute"&&e.name==="class")return e.value;switch(e.value.type){case"JSXExpressionContainer":return e.value.expression.value;case"VExpressionContainer":switch(e.value.expression.type){case"ArrayExpression":return e.value.expression.elements;case"ObjectExpression":return e.value.expression.properties}return e.value.expression.value;default:return e.value.value}}function y(e){if(typeof e!="string")return{classNames:[],whitespaces:[],headSpace:!1,tailSpace:!1};const t=e.split(E);t[0]===""&&t.shift(),t[t.length-1]===""&&t.pop();const r=E.test(t[0]),s=E.test(t[t.length-1]),p=(a,u)=>r?u%2!==0:u%2===0,n=(a,u)=>r?u%2===0:u%2!==0,m=t.filter(p),l=t.filter(n);return{classNames:m,whitespaces:l,headSpace:r,tailSpace:s}}function x(e,t,r,s=!1,p=!1,n=[],m=null){let l,a,u=null,c=null,g="",v="";if(t===null){if(l=h(e),{classNames:a}=y(l),a=[...new Set(a)],a.length===0)return;const f=w(e);e.type==="TextAttribute"?(u=f[0],c=f[1]):(u=f[0]+1,c=f[1]-1),r(a,e,l,u,c,g,v)}else{if(t===void 0)return;{const f=s?!0:p;let T=!1;switch(t.type){case"TemplateLiteral":t.expressions.forEach(i=>{x(e,i,r,s,f,n)}),t.quasis.forEach(i=>{x(e,i,r,s,p,n)});return;case"ConditionalExpression":x(e,t.consequent,r,s,f,n),x(e,t.alternate,r,s,f,n);return;case"LogicalExpression":x(e,t.right,r,s,f,n);return;case"ArrayExpression":t.elements.forEach(i=>{x(e,i,r,s,f,n)});return;case"ObjectExpression":t.properties.forEach(i=>{const L=e.callee&&e.callee.name==="classnames";i.type!=="SpreadElement"&&(i.key.type==="Identifier"&&n.includes(i.key.name)||x(e,L?i.key:i.value,r,s,f,n))});return;case"Property":x(e,t.key,r,s,f,n);return;case"Literal":T=!0,l=t.value,u=t.range[0]+1,c=t.range[1]-1;break;case"SvelteLiteral":l=t.value,u=t.range[0],c=t.range[1];break;case"TemplateElement":l=t.value.raw,u=t.range[0],c=t.range[1];const S=m?.sourceCode.getText(t)??"";g=R(S,l),v=A(S,l);break}if({classNames:a}=y(l),a=[...new Set(a)],a.length===0)return;r(a,p?null:e,l,u,c,g,v)}}}function R(e,t){return e.indexOf(t)===0?"":e.split(t).shift()}function A(e,t){return e.indexOf(t)===-1?"":e.split(t).pop()}function V(e,t,r){let s=e.split(t);return s.shift(),s=s.join(t).split(r),s.pop(),s.join(r)}function F(e,t,r,s){const p=e.match(/.+(?:\r\n|\n)?/g);let n=0,m=null,l=!1;for(let a=r;a<=s;a++){const c=t[a-1].indexOf(p[n].replace(/\r\n|\n/,""));if(c!==-1){if(n===0&&(m={line:a,column:c}),n===p.length-1)return{start:m,end:{line:a,column:c+e.length}};l=!0,n++}else l&&(l=!1,n=0,m=null)}return null}export{y as extractClassnamesFromValue,w as extractRangeFromNode,h as extractValueFromNode,F as findLoc,V as getTemplateElementBody,R as getTemplateElementPrefix,A as getTemplateElementSuffix,x as parseNodeRecursive};
@@ -0,0 +1,5 @@
1
+ import { Rule } from 'eslint';
2
+ export default function defineVisitors({ context, settings }: {
3
+ context: Rule.RuleContext;
4
+ settings: any;
5
+ }, visitNode: any): any;
@@ -0,0 +1 @@
1
+ var p=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var o=Object.getOwnPropertyNames;var x=Object.prototype.hasOwnProperty;var E=(s,r)=>{for(var t in r)p(s,t,{get:r[t],enumerable:!0})},v=(s,r,t,l)=>{if(r&&typeof r=="object"||typeof r=="function")for(let i of o(r))!x.call(s,i)&&i!==t&&p(s,i,{get:()=>r[i],enumerable:!(l=m(r,i))||l.enumerable});return s};var g=s=>v(p({},"__esModule",{value:!0}),s);var V={};E(V,{default:()=>f});module.exports=g(V);function f({context:s,settings:r},t){const l=e=>{let a="";const n=e.callee||e.tag;return n.type==="Identifier"&&(a=n.name),n.type==="MemberExpression"&&(a=`${n.object.name}.${n.property.name}`),new RegExp(r.calleeMatching).test(a)},i=function(e){l(e)&&e.arguments.forEach(a=>{t(e,a)})},u=new RegExp(r.classMatching),c={CallExpression:i,JSXAttribute:function(e){!e.name||!u.test(e.name.name)||(e.value&&e.value.type==="Literal"?t(e):e.value&&e.value.type==="JSXExpressionContainer"&&t(e,e.value.expression))},SvelteAttribute:function(e){if(!(!e.key?.name||!u.test(e.key.name)))for(const a of e.value)t(e,a)},TextAttribute:function(e){!e.name||!u.test(e.name)||t(e)},TaggedTemplateExpression:function(e){if(l(e)){t(e,e.quasi);return}}},y={CallExpression:i,VAttribute:function(e){e.value&&e.value.type==="VLiteral"?t(e):e.value&&e.value.type==="VExpressionContainer"&&e.value.expression.type==="ArrayExpression"?e.value.expression.elements.forEach(a=>{t(e,a)}):e.value&&e.value.type==="VExpressionContainer"&&e.value.expression.type==="ObjectExpression"&&e.value.expression.properties.forEach(a=>{t(e,a)})}};return s.sourceCode.parserServices==null||s.sourceCode.parserServices.defineTemplateBodyVisitor==null?c:s.sourceCode.parserServices.defineTemplateBodyVisitor(y,c)}
@@ -0,0 +1 @@
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};
@@ -0,0 +1,5 @@
1
+ export default function resolveContext(context: any): {
2
+ settings: any;
3
+ options: any;
4
+ config: any;
5
+ };
@@ -0,0 +1 @@
1
+ var m=Object.create;var n=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var a=Object.getOwnPropertyNames;var u=Object.getPrototypeOf,b=Object.prototype.hasOwnProperty;var d=(o,t)=>{for(var s in t)n(o,s,{get:t[s],enumerable:!0})},r=(o,t,s,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let e of a(t))!b.call(o,e)&&e!==s&&n(o,e,{get:()=>t[e],enumerable:!(i=l(t,e))||i.enumerable});return o};var f=(o,t,s)=>(s=o!=null?m(u(o)):{},r(t||!o||!o.__esModule?n(s,"default",{value:o,enumerable:!0}):s,o)),j=o=>r(n({},"__esModule",{value:!0}),o);var v={};d(v,{default:()=>p});module.exports=j(v);var g=f(require("../settings")),c=f(require("explore-config"));function p(o){const t=Object.assign(g.default,o.settings?.["@master/css"]),s=t?.config;return{settings:t,options:o.options[0]||{},config:typeof s=="object"?s:(0,c.default)(t?.config||"")}}
@@ -0,0 +1 @@
1
+ import e from"../settings";import n from"explore-config";function i(t){const o=Object.assign(e,t.settings?.["@master/css"]),s=o?.config;return{settings:o,options:t.options[0]||{},config:typeof s=="object"?s:n(o?.config||"")}}export{i as default};
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@master/eslint-plugin-css","scripts":{"test":"mocha tests --recursive --timeout 10000","test:file":"mocha tests"},"keywords":["mastercss","eslint","eslintplugin"],"license":"MIT","description":"Master CSS ESLint Plugin","author":"Aoyue Design LLC.","funding":"https://css.master.co/docs/donate","homepage":"https://css.master.co","bugs":{"url":"https://github.com/master-co/css/issues"},"repository":{"type":"git","url":"https://github.com/master-co/css.git","directory":"packages/eslint-plugin"},"sideEffects":false,"main":"./lib/index.js","exports":"./lib/index.js","publishConfig":{"access":"public"},"dependencies":{"@master/css":"^2.0.0-beta.186","@master/css-validator":"^2.0.0-beta.186","explore-config":"^2.2.10","requireindex":"^1.2.0"},"devDependencies":{"@angular-eslint/template-parser":"^16.2.0","@types/node":"^20.6.0","@typescript-eslint/parser":"^5.50.0","eslint":"^7.1.0","mocha":"^10.2.0","svelte-eslint-parser":"^0.33.1","vue-eslint-parser":"^9.3.1"},"version":"2.0.0-beta.186"}
1
+ {"name":"@master/eslint-plugin-css","scripts":{"build":"techor pack 'src/**/*.ts'","dev":"pnpm run build --watch --no-declare","test":"jest","type-check":"tsc --noEmit","lint":"eslint src"},"keywords":["mastercss","eslint","eslintplugin"],"license":"MIT","description":"Master CSS ESLint Plugin","author":"Aoyue Design LLC.","funding":"https://css.master.co/docs/donate","homepage":"https://css.master.co","bugs":{"url":"https://github.com/master-co/css/issues"},"repository":{"type":"git","url":"https://github.com/master-co/css.git","directory":"packages/eslint-plugin"},"sideEffects":false,"main":"./dist/index.js","types":"./dist/index.d.ts","exports":"./dist/index.js","module":"./dist/index.mjs","jsnext:main":"./dist/index.mjs","esnext":"./dist/index.mjs","files":["dist"],"publishConfig":{"access":"public"},"dependencies":{"@master/css":"^2.0.0-beta.188","@master/css-validator":"^2.0.0-beta.188","explore-config":"^2.2.10"},"devDependencies":{"@angular-eslint/template-parser":"^16.2.0","@types/node":"^20.6.0","@typescript-eslint/parser":"^5.50.0","@typescript-eslint/utils":"^6.9.0","eslint":"^8.0.0","svelte-eslint-parser":"^0.33.1","vue-eslint-parser":"^9.3.1"},"version":"2.0.0-beta.188"}
package/lib/index.js DELETED
@@ -1,5 +0,0 @@
1
- 'use strict'
2
-
3
- const requireIndex = require('requireindex')
4
-
5
- module.exports.rules = requireIndex(__dirname + '/rules')
@@ -1,202 +0,0 @@
1
- 'use strict'
2
-
3
- const astUtil = require('../utils/ast')
4
- const resolveContext = require('../utils/resolve-context')
5
- const { reorderForReadableClasses } = require('@master/css')
6
-
7
- module.exports = {
8
- meta: {
9
- docs: {
10
- description: 'Enforce a consistent and logical order of classes',
11
- category: 'Stylistic Issues',
12
- recommended: false,
13
- url: 'https://beta.css.master.co/docs/code-linting#enforce-a-consistent-and-logical-order-of-classes',
14
- },
15
- messages: {
16
- invalidClassOrder: 'No consistent class order followed.',
17
- },
18
- fixable: 'code'
19
- },
20
- create: function (context) {
21
- const { options, settings, config } = resolveContext(context)
22
- const sortNodeArgumentValue = (node, arg = null) => {
23
- let originalClassNamesValue = null
24
- let start = null
25
- let end = null
26
- let prefix = ''
27
- let suffix = ''
28
- if (arg === null) {
29
- originalClassNamesValue = astUtil.extractValueFromNode(node)
30
- const range = astUtil.extractRangeFromNode(node)
31
- if (node.type === 'TextAttribute') {
32
- start = range[0]
33
- end = range[1]
34
- } else {
35
- start = range[0] + 1
36
- end = range[1] - 1
37
- }
38
- } else {
39
- switch (arg.type) {
40
- case 'Identifier':
41
- return
42
- case 'TemplateLiteral':
43
- arg.expressions.forEach((exp) => {
44
- sortNodeArgumentValue(node, exp)
45
- })
46
- arg.quasis.forEach((quasis) => {
47
- sortNodeArgumentValue(node, quasis)
48
- })
49
- return
50
- case 'ConditionalExpression':
51
- sortNodeArgumentValue(node, arg.consequent)
52
- sortNodeArgumentValue(node, arg.alternate)
53
- return
54
- case 'LogicalExpression':
55
- sortNodeArgumentValue(node, arg.right)
56
- return
57
- case 'ArrayExpression':
58
- arg.elements.forEach((el) => {
59
- sortNodeArgumentValue(node, el)
60
- })
61
- return
62
- case 'ObjectExpression':
63
- const isUsedByClassNamesPlugin = node.callee && node.callee.name === 'classnames'
64
- const isVue = node.key && node.key.type === 'VDirectiveKey'
65
- arg.properties.forEach((prop) => {
66
- const propVal = isUsedByClassNamesPlugin || isVue ? prop.key : prop.value
67
- sortNodeArgumentValue(node, propVal)
68
- })
69
- return
70
- case 'Property':
71
- sortNodeArgumentValue(node, arg.key)
72
- break
73
- case 'Literal':
74
- originalClassNamesValue = arg.value
75
- start = arg.range[0] + 1
76
- end = arg.range[1] - 1
77
- break
78
- case 'SvelteLiteral':
79
- originalClassNamesValue = arg.value
80
- if (originalClassNamesValue === '') {
81
- return
82
- }
83
- start = arg.range[0]
84
- end = arg.range[1]
85
- break
86
- case 'TemplateElement':
87
- originalClassNamesValue = arg.value.raw
88
- if (originalClassNamesValue === '') {
89
- return
90
- }
91
- start = arg.range[0]
92
- end = arg.range[1]
93
- // https://github.com/eslint/eslint/issues/13360
94
- // The problem is that range computation includes the backticks (`test`)
95
- // but value.raw does not include them, so there is a mismatch.
96
- // start/end does not include the backticks, therefore it matches value.raw.
97
- const txt = context.getSourceCode().getText(arg)
98
- prefix = astUtil.getTemplateElementPrefix(txt, originalClassNamesValue)
99
- suffix = astUtil.getTemplateElementSuffix(txt, originalClassNamesValue)
100
- originalClassNamesValue = astUtil.getTemplateElementBody(txt, prefix, suffix)
101
- break
102
- }
103
- }
104
-
105
- let { classNames, whitespaces, headSpace, tailSpace } =
106
- astUtil.extractClassnamesFromValue(originalClassNamesValue)
107
-
108
- if (classNames.length <= 1) {
109
- // Don't run sorting for a single or empty className
110
- return
111
- }
112
-
113
- let orderedClassNames = reorderForReadableClasses(classNames, config)
114
- .filter(eachOrderedClassName => classNames.includes(eachOrderedClassName))
115
-
116
- orderedClassNames = classNames.filter(x => !orderedClassNames.includes(x))
117
- .concat(orderedClassNames)
118
- .filter(x => x.trim() !== '')
119
-
120
- // Generates the validated/sorted attribute value
121
- let validatedClassNamesValue = ''
122
- for (let i = 0; i < orderedClassNames.length; i++) {
123
- const w = whitespaces[i] ?? ''
124
- const cls = orderedClassNames[i]
125
- validatedClassNamesValue += headSpace ? `${w}${cls}` : `${cls}${w}`
126
- if (headSpace && tailSpace && i === orderedClassNames.length - 1) {
127
- validatedClassNamesValue += whitespaces[whitespaces.length - 1] ?? ''
128
- }
129
- }
130
-
131
- if (originalClassNamesValue !== validatedClassNamesValue) {
132
- validatedClassNamesValue = prefix + validatedClassNamesValue + suffix
133
- context.report({
134
- node: node,
135
- messageId: 'invalidClassOrder',
136
- fix: function (fixer) {
137
- return fixer.replaceTextRange([start, end], validatedClassNamesValue)
138
- },
139
- })
140
- }
141
- }
142
-
143
- const callExpressionVisitor = function (node) {
144
- const calleeStr = astUtil.calleeToString(node.callee)
145
- if (settings.callees.findIndex((name) => calleeStr === name) === -1) {
146
- return
147
- }
148
-
149
- node.arguments.forEach((arg) => {
150
- sortNodeArgumentValue(node, arg)
151
- })
152
- }
153
-
154
- const scriptVisitor = {
155
- CallExpression: callExpressionVisitor,
156
- JSXAttribute: function (node) {
157
- if (!node.name || !new RegExp(settings.classMatching).test(node.name.name)) return
158
- if (node.value && node.value.type === 'Literal') {
159
- sortNodeArgumentValue(node)
160
- } else if (node.value && node.value.type === 'JSXExpressionContainer') {
161
- sortNodeArgumentValue(node, node.value.expression)
162
- }
163
- },
164
- SvelteAttribute: function (node) {
165
- if (!node.key?.name || !new RegExp(settings.classMatching).test(node.key.name)) return
166
- for (const eachValue of node.value) {
167
- sortNodeArgumentValue(node, eachValue)
168
- }
169
- },
170
- TextAttribute: function (node) {
171
- if (!node.name || !new RegExp(settings.classMatching).test(node.name)) return
172
- sortNodeArgumentValue(node)
173
- },
174
- TaggedTemplateExpression: function (node) {
175
- if (!settings.tags.includes(node.tag.name)) {
176
- return
177
- }
178
- sortNodeArgumentValue(node, node.quasi)
179
- },
180
- }
181
- const templateBodyVisitor = {
182
- CallExpression: callExpressionVisitor,
183
- VAttribute: function (node) {
184
- if (node.value && node.value.type === 'VLiteral') {
185
- sortNodeArgumentValue(node)
186
- } else if (node.value && node.value.type === 'VExpressionContainer' && node.value.expression.type === 'ArrayExpression') {
187
- node.value.expression.elements.forEach((arg) => {
188
- sortNodeArgumentValue(node, arg)
189
- })
190
- } else if (node.value && node.value.type === 'VExpressionContainer' && node.value.expression.type === 'ObjectExpression') {
191
- sortNodeArgumentValue(node, prop)
192
- }
193
- },
194
- }
195
-
196
- if (context.parserServices == null || context.parserServices.defineTemplateBodyVisitor == null) {
197
- return scriptVisitor
198
- } else {
199
- return context.parserServices.defineTemplateBodyVisitor(templateBodyVisitor, scriptVisitor)
200
- }
201
- },
202
- }
@@ -1,123 +0,0 @@
1
- 'use strict'
2
-
3
- const astUtil = require('../utils/ast')
4
- const resolveContext = require('../utils/resolve-context')
5
- const { validate } = require('@master/css-validator')
6
-
7
- module.exports = {
8
- meta: {
9
- docs: {
10
- description: 'Check the validity of classes with your configuration',
11
- category: 'Stylistic Issues',
12
- recommended: false,
13
- url: 'https://beta.css.master.co/docs/code-linting#check-the-validity-of-classes-with-your-configuration',
14
- },
15
- messages: {
16
- invalidClass: '{{message}}',
17
- disallowTraditionalClass: '{{message}}',
18
- },
19
- fixable: null
20
- },
21
- create: function (context) {
22
- const { options, settings, config } = resolveContext(context)
23
- const checkNodeArgumentValue = (node, arg = null) => {
24
- astUtil.parseNodeRecursive(
25
- node,
26
- arg,
27
- (classNames, node) => {
28
- const sourceCode = context.getSourceCode()
29
- const sourceCodeLines = sourceCode.lines
30
- const nodeStartLine = node.loc.start.line
31
- const nodeEndLine = node.loc.end.line
32
- for (const className of classNames) {
33
- const { isMasterCSS, errors } = validate(className, { config })
34
- if (errors.length > 0) {
35
- for (const error of errors) {
36
- if (isMasterCSS) {
37
- context.report({
38
- loc: astUtil.findLoc(className, sourceCodeLines, nodeStartLine, nodeEndLine),
39
- messageId: 'invalidClass',
40
- data: {
41
- message: error.message + '.',
42
- }
43
- })
44
- } else if (!isMasterCSS && options.disallowTraditionalClass) {
45
- context.report({
46
- loc: astUtil.findLoc(className, sourceCodeLines, nodeStartLine, nodeEndLine),
47
- messageId: 'disallowTraditionalClass',
48
- data: {
49
- message: `Disallow a traditional class \`${className}\`.`,
50
- }
51
- })
52
- }
53
- }
54
- }
55
- }
56
- },
57
- false,
58
- false,
59
- settings.ignoredKeys
60
- )
61
- }
62
-
63
- const callExpressionVisitor = function (node) {
64
- const calleeStr = astUtil.calleeToString(node.callee)
65
- if (settings.callees.findIndex((name) => calleeStr === name) === -1) {
66
- return
67
- }
68
-
69
- node.arguments.forEach((arg) => {
70
- checkNodeArgumentValue(node, arg)
71
- })
72
- }
73
-
74
- const scriptVisitor = {
75
- CallExpression: callExpressionVisitor,
76
- JSXAttribute: function (node) {
77
- if (!node.name || !new RegExp(settings.classMatching).test(node.name.name)) return
78
- if (node.value && node.value.type === 'Literal') {
79
- checkNodeArgumentValue(node)
80
- } else if (node.value && node.value.type === 'JSXExpressionContainer') {
81
- checkNodeArgumentValue(node, node.value.expression)
82
- }
83
- },
84
- SvelteAttribute: function (node) {
85
- if (!node.key?.name || !new RegExp(settings.classMatching).test(node.key.name)) return
86
- for (const eachValue of node.value) {
87
- checkNodeArgumentValue(node, eachValue)
88
- }
89
- },
90
- TextAttribute: function (node) {
91
- if (!node.name || !new RegExp(settings.classMatching).test(node.name)) return
92
- checkNodeArgumentValue(node)
93
- },
94
- TaggedTemplateExpression: function (node) {
95
- if (!settings.tags.includes(node.tag.name)) {
96
- return
97
- }
98
- checkNodeArgumentValue(node, node.quasi)
99
- },
100
- }
101
-
102
- const templateBodyVisitor = {
103
- CallExpression: callExpressionVisitor,
104
- VAttribute: function (node) {
105
- if (node.value && node.value.type === 'VLiteral') {
106
- checkNodeArgumentValue(node)
107
- } else if (node.value && node.value.type === 'VExpressionContainer' && node.value.expression.type === 'ArrayExpression') {
108
- node.value.expression.elements.forEach((arg) => {
109
- checkNodeArgumentValue(node, arg)
110
- })
111
- } else if (node.value && node.value.type === 'VExpressionContainer' && node.value.expression.type === 'ObjectExpression') {
112
- checkNodeArgumentValue(node, prop)
113
- }
114
- },
115
- }
116
-
117
- if (context.parserServices == null || context.parserServices.defineTemplateBodyVisitor == null) {
118
- return scriptVisitor
119
- } else {
120
- return context.parserServices.defineTemplateBodyVisitor(templateBodyVisitor, scriptVisitor)
121
- }
122
- },
123
- }
package/lib/utils/ast.js DELETED
@@ -1,218 +0,0 @@
1
- 'use strict'
2
-
3
- const separatorRegEx = /([\t\n\f\r ]+)/
4
-
5
- function calleeToString(calleeNode) {
6
- if (calleeNode.type === 'Identifier') {
7
- return calleeNode.name
8
- }
9
- if (calleeNode.type === 'MemberExpression') {
10
- return `${calleeNode.object.name}.${calleeNode.property.name}`
11
- }
12
- }
13
-
14
- function extractRangeFromNode(node) {
15
- if (node.type === 'TextAttribute' && node.name === 'class') {
16
- return [node.valueSpan.fullStart.offset, node.valueSpan.end.offset]
17
- }
18
- switch (node.value.type) {
19
- case 'JSXExpressionContainer':
20
- return node.value.expression.range
21
- default:
22
- return node.value.range
23
- }
24
- }
25
-
26
- function extractValueFromNode(node) {
27
- if (node.type === 'TextAttribute' && node.name === 'class') {
28
- return node.value
29
- }
30
- switch (node.value.type) {
31
- case 'JSXExpressionContainer':
32
- return node.value.expression.value
33
- case 'VExpressionContainer':
34
- switch (node.value.expression.type) {
35
- case 'ArrayExpression':
36
- return node.value.expression.elements
37
- case 'ObjectExpression':
38
- return node.value.expression.properties
39
- }
40
- return node.value.expression.value
41
- default:
42
- return node.value.value
43
- }
44
- }
45
-
46
- function extractClassnamesFromValue(classStr) {
47
- if (typeof classStr !== 'string') {
48
- return { classNames: [], whitespaces: [], headSpace: false, tailSpace: false }
49
- }
50
- let parts = classStr.split(separatorRegEx)
51
- if (parts[0] === '') {
52
- parts.shift()
53
- }
54
- if (parts[parts.length - 1] === '') {
55
- parts.pop()
56
- }
57
- let headSpace = separatorRegEx.test(parts[0])
58
- let tailSpace = separatorRegEx.test(parts[parts.length - 1])
59
- const isClass = (_, i) => (headSpace ? i % 2 !== 0 : i % 2 === 0)
60
- const isNotClass = (_, i) => (headSpace ? i % 2 === 0 : i % 2 !== 0)
61
- let classNames = parts.filter(isClass)
62
- let whitespaces = parts.filter(isNotClass)
63
- return { classNames: classNames, whitespaces: whitespaces, headSpace: headSpace, tailSpace: tailSpace }
64
- }
65
-
66
-
67
- /**
68
- * Inspect and parse an abstract syntax node and run a callback function
69
- *
70
- * @param {ASTNode} rootNode The current root node being parsed by eslint
71
- * @param {ASTNode} childNode The AST node child argument being checked
72
- * @param {Function} cb The callback function
73
- * @param {Boolean} skipConditional Optional, indicate distinct parsing for conditional nodes
74
- * @param {Boolean} isolate Optional, set internally to isolate parsing and validation on conditional children
75
- * @param {Array} ignoredKeys Optional, set object keys which should not be parsed e.g. for `cva`
76
- * @returns {void}
77
- */
78
- function parseNodeRecursive(rootNode, childNode, cb, skipConditional = false, isolate = false, ignoredKeys = []) {
79
- // TODO allow vue non litteral
80
- let originalClassNamesValue
81
- let classNames
82
- if (childNode === null) {
83
- originalClassNamesValue = extractValueFromNode(rootNode);
84
- ({ classNames } = extractClassnamesFromValue(originalClassNamesValue))
85
- classNames = [... new Set(classNames)]
86
- if (classNames.length === 0) {
87
- // Don't run for empty className
88
- return
89
- }
90
- cb(classNames, rootNode)
91
- } else if (childNode === undefined) {
92
- // Ignore invalid child candidates (probably inside complex TemplateLiteral)
93
- return
94
- } else {
95
- const forceIsolation = skipConditional ? true : isolate
96
- let trim = false
97
- switch (childNode.type) {
98
- case 'TemplateLiteral':
99
- childNode.expressions.forEach((exp) => {
100
- parseNodeRecursive(rootNode, exp, cb, skipConditional, forceIsolation, ignoredKeys)
101
- })
102
- childNode.quasis.forEach((quasis) => {
103
- parseNodeRecursive(rootNode, quasis, cb, skipConditional, isolate, ignoredKeys)
104
- })
105
- return
106
- case 'ConditionalExpression':
107
- parseNodeRecursive(rootNode, childNode.consequent, cb, skipConditional, forceIsolation, ignoredKeys)
108
- parseNodeRecursive(rootNode, childNode.alternate, cb, skipConditional, forceIsolation, ignoredKeys)
109
- return
110
- case 'LogicalExpression':
111
- parseNodeRecursive(rootNode, childNode.right, cb, skipConditional, forceIsolation, ignoredKeys)
112
- return
113
- case 'ArrayExpression':
114
- childNode.elements.forEach((el) => {
115
- parseNodeRecursive(rootNode, el, cb, skipConditional, forceIsolation, ignoredKeys)
116
- })
117
- return
118
- case 'ObjectExpression':
119
- childNode.properties.forEach((prop) => {
120
- const isUsedByClassNamesPlugin = rootNode.callee && rootNode.callee.name === 'classnames'
121
-
122
- if (prop.type === 'SpreadElement') {
123
- // Ignore spread elements
124
- return
125
- }
126
-
127
- if (prop.key.type === 'Identifier' && ignoredKeys.includes(prop.key.name)) {
128
- // Ignore specific keys defined in settings
129
- return
130
- }
131
-
132
- parseNodeRecursive(
133
- rootNode,
134
- isUsedByClassNamesPlugin ? prop.key : prop.value,
135
- cb,
136
- skipConditional,
137
- forceIsolation,
138
- ignoredKeys
139
- )
140
- })
141
- return
142
- case 'Property':
143
- parseNodeRecursive(rootNode, childNode.key, cb, skipConditional, forceIsolation, ignoredKeys)
144
- return
145
- case 'Literal':
146
- trim = true
147
- originalClassNamesValue = childNode.value
148
- break
149
- case 'TemplateElement':
150
- originalClassNamesValue = childNode.value.raw
151
- break
152
- }
153
- ({ classNames } = extractClassnamesFromValue(originalClassNamesValue))
154
- classNames = removeDuplicatesFromArray(classNames)
155
- if (classNames.length === 0) {
156
- // Don't run for empty className
157
- return
158
- }
159
- const targetNode = isolate ? null : rootNode
160
- cb(classNames, targetNode)
161
- }
162
- }
163
-
164
- function getTemplateElementPrefix(text, raw) {
165
- const idx = text.indexOf(raw)
166
- if (idx === 0) {
167
- return ''
168
- }
169
- return text.split(raw).shift()
170
- }
171
-
172
- function getTemplateElementSuffix(text, raw) {
173
- if (text.indexOf(raw) === -1) {
174
- return ''
175
- }
176
- return text.split(raw).pop()
177
- }
178
-
179
- function getTemplateElementBody(text, prefix, suffix) {
180
- let arr = text.split(prefix)
181
- arr.shift()
182
- let body = arr.join(prefix)
183
- arr = body.split(suffix)
184
- arr.pop()
185
- return arr.join(suffix)
186
- }
187
-
188
- function findLoc(text, lines, startLine, endLine) {
189
- for (let i = startLine; i <= endLine; i++) {
190
- const sourceCodeLine = lines[i - 1]
191
- const index = sourceCodeLine.indexOf(text)
192
- if (index !== -1) {
193
- return {
194
- start: {
195
- line: i,
196
- column: index
197
- },
198
- end: {
199
- line: i,
200
- column: index + text.length
201
- }
202
- }
203
- }
204
- }
205
- return null
206
- }
207
-
208
- module.exports = {
209
- calleeToString,
210
- extractRangeFromNode,
211
- extractValueFromNode,
212
- extractClassnamesFromValue,
213
- getTemplateElementPrefix,
214
- getTemplateElementSuffix,
215
- getTemplateElementBody,
216
- parseNodeRecursive,
217
- findLoc
218
- }
@@ -1,21 +0,0 @@
1
- 'use strict'
2
-
3
- const exploreConfig = require('explore-config').default
4
-
5
- const resolveContext = function (context) {
6
- const settings = Object.assign({
7
- callees: ['classnames', 'clsx', 'ctl', 'cva', 'cv', 'classVariant', 'styled'],
8
- ignoredKeys: ['compoundVariants', 'defaultVariants'],
9
- classMatching: '^class(Name)?$',
10
- config: 'master.css.*',
11
- tags: []
12
- }, context.settings?.['@master/css'])
13
- const config = settings?.config
14
- return {
15
- settings,
16
- options: context.options[0] || {},
17
- config: typeof config === 'object' ? config : exploreConfig(settings?.config || '')
18
- }
19
- }
20
-
21
- module.exports = resolveContext
@@ -1,55 +0,0 @@
1
- 'use strict'
2
-
3
- const rule = require('../../lib/rules/class-order')
4
- const RuleTester = require('eslint').RuleTester
5
- const ruleTester = new RuleTester({
6
- parserOptions: {
7
- ecmaFeatures: {
8
- jsx: true,
9
- },
10
- }
11
- })
12
-
13
- ruleTester.run('class order', rule, {
14
- valid: [
15
- { code: '<h1 className={"bg:black fg:white f:24 m:8 p:8"}>Welcome {name}</h1>' }
16
- ],
17
- invalid: [
18
- {
19
- code: `
20
- export interface FakePropsInterface {
21
- readonly name?: string;
22
- }
23
- function Fake({
24
- name = 'yolo'
25
- }: FakeProps) {
26
- return (
27
- <>
28
- <h1 className={"m:8 bg:black p:8 fg:white f:24"}>Welcome {name}</h1>
29
- <p>Bye {name}</p>
30
- </>
31
- );
32
- }
33
- export default Fake;
34
- `,
35
- output: `
36
- export interface FakePropsInterface {
37
- readonly name?: string;
38
- }
39
- function Fake({
40
- name = 'yolo'
41
- }: FakeProps) {
42
- return (
43
- <>
44
- <h1 className={"bg:black fg:white f:24 m:8 p:8"}>Welcome {name}</h1>
45
- <p>Bye {name}</p>
46
- </>
47
- );
48
- }
49
- export default Fake;
50
- `,
51
- parser: require.resolve('@typescript-eslint/parser'),
52
- errors: [{ messageId: 'invalidClassOrder' }],
53
- },
54
- ]
55
- })
@@ -1,24 +0,0 @@
1
- 'use strict'
2
-
3
- const rule = require('../../lib/rules/class-order')
4
- const RuleTester = require('eslint').RuleTester
5
- const ruleTester = new RuleTester({
6
- parserOptions: {
7
- ecmaFeatures: {
8
- jsx: true,
9
- },
10
- }
11
- })
12
-
13
- ruleTester.run('svelte class order', rule, {
14
- valid: [{ code: `<div class="bg:black fg:white f:24 m:8 p:8">Simple, basic</div>` }],
15
- invalid: [
16
- {
17
- code: `<div class="m:8 bg:black p:8 fg:white f:24 {flipped ? 'flipped' : ''}">Enhancing readability</div>`,
18
- output: `<div class="bg:black fg:white f:24 m:8 p:8 {flipped ? 'flipped' : ''}">Enhancing readability</div>`,
19
- errors: [{ messageId: 'invalidClassOrder' }],
20
- filename: 'test.svelte',
21
- parser: require.resolve('svelte-eslint-parser'),
22
- },
23
- ],
24
- })
@@ -1,24 +0,0 @@
1
- 'use strict'
2
-
3
- const rule = require('../../lib/rules/class-order')
4
- const RuleTester = require('eslint').RuleTester
5
- const ruleTester = new RuleTester({
6
- parserOptions: {
7
- ecmaFeatures: {
8
- jsx: true,
9
- }
10
- }
11
- })
12
-
13
- ruleTester.run('vue class order', rule, {
14
- valid: [{ code: `<div class="bg:black fg:white f:24 m:8 p:8">Simple, basic</div>` }],
15
- invalid: [
16
- {
17
- code: `<template><div class="m:8 bg:black p:8 fg:white f:24">Enhancing readability</div></template>`,
18
- output: `<template><div class="bg:black fg:white f:24 m:8 p:8">Enhancing readability</div></template>`,
19
- errors: [{ messageId: 'invalidClassOrder' }],
20
- filename: 'test.vue',
21
- parser: require.resolve('vue-eslint-parser'),
22
- },
23
- ],
24
- })
package/tests/order.js DELETED
@@ -1,66 +0,0 @@
1
- 'use strict'
2
-
3
- const rule = require('../lib/rules/class-order')
4
- const RuleTester = require('eslint').RuleTester
5
- const ruleTester = new RuleTester({
6
- parserOptions: {
7
- ecmaFeatures: {
8
- jsx: true,
9
- },
10
- }
11
- })
12
-
13
- ruleTester.run('class order', rule, {
14
- valid: [
15
- {
16
- code: `<div class="bg:black fg:white f:24 m:8 p:8">Simple, basic</div>`,
17
- },
18
- {
19
- code: `<div class="card mt:20">Traditional class + syntax</div>`,
20
- },
21
- {
22
- code: `<div test="bg:black fg:white f:24 m:8 p:8">Simple, using 'test' prop</div>`,
23
- options: [
24
- {
25
- classMatching: '^test$',
26
- },
27
- ],
28
- },
29
- ],
30
- invalid: [
31
- {
32
- code: `<div class="fg:white f:24 m:8 p:8 bg:black">Classnames will be ordered</div>`,
33
- output: `<div class="bg:black fg:white f:24 m:8 p:8">Classnames will be ordered</div>`,
34
- errors: [{ messageId: 'invalidClassOrder' }],
35
- },
36
- {
37
- code: `
38
- <div class="
39
- m:8
40
- bg:black
41
- p:8
42
- fg:white
43
- f:24
44
- ">
45
- :)
46
- </div>`,
47
- output: `
48
- <div class="
49
- bg:black
50
- fg:white
51
- f:24
52
- m:8
53
- p:8
54
- ">
55
- :)
56
- </div>`,
57
- errors: [{ messageId: 'invalidClassOrder' }],
58
- parser: require.resolve('@angular-eslint/template-parser'),
59
- },
60
- {
61
- code: `<div class="flex uppercase m:0 m:0>li text-decoration:none>li>a px:4>li align-items:baseline fg:gray-30>li>a gap-x:28 font:12 font:semibold pb:6>li pt:20 pt:10>li {bb:3|solid|black}>li:has(>.router-link-active) {fg:black}>li:has(>.router-link-active)>a fg:gray-10>li>a:hover box-shadow:none>li>a:focus">Group</div>`,
62
- output: `<div class="flex uppercase align-items:baseline box-shadow:none>li>a:focus fg:gray-30>li>a fg:gray-10>li>a:hover gap-x:28 font:12 font:semibold {bb:3|solid|black}>li:has(>.router-link-active) {fg:black}>li:has(>.router-link-active)>a m:0 m:0>li pb:6>li pt:20 pt:10>li px:4>li text-decoration:none>li>a">Group</div>`,
63
- errors: [{ messageId: 'invalidClassOrder' }],
64
- }
65
- ],
66
- })
@@ -1,69 +0,0 @@
1
- 'use strict'
2
-
3
- const rule = require('../lib/rules/class-validation')
4
- const RuleTester = require('eslint').RuleTester
5
-
6
- new RuleTester({
7
- parserOptions: {
8
- ecmaFeatures: {
9
- jsx: true,
10
- },
11
- }
12
- }).run('invalid', rule, {
13
- valid: [
14
- {
15
- code: `<div class="bg:black fg:white f:24 m:8 p:8">Simple, basic</div>`,
16
- }
17
- ],
18
- invalid: [
19
- {
20
- code: `<div class="bg:black m:mistake rrr">Simple, basic</div>`,
21
- errors: [
22
- { messageId: 'invalidClass' },
23
- { messageId: 'disallowTraditionalClass' }
24
- ],
25
- options: [
26
- {
27
- disallowTraditionalClass: true
28
- }
29
- ]
30
- },
31
- {
32
- code: `<div class="bg:black m:mistake rrr">Simple, basic</div>`,
33
- errors: [
34
- { messageId: 'invalidClass' },
35
- ]
36
- }
37
- ]
38
- })
39
-
40
- new RuleTester({
41
- parserOptions: {
42
- ecmaFeatures: {
43
- jsx: true,
44
- },
45
- },
46
- settings: {
47
- '@master/css': {
48
- config: {
49
- styles: { btn: 'block' }
50
- }
51
- }
52
- }
53
- }).run('invalid', rule, {
54
- valid: [],
55
- invalid: [
56
- {
57
- code: `<div class="bg:black m:mistake rrr btn">Simple, basic</div>`,
58
- errors: [
59
- { messageId: 'invalidClass' },
60
- { messageId: 'disallowTraditionalClass' }
61
- ],
62
- options: [
63
- {
64
- disallowTraditionalClass: true
65
- }
66
- ]
67
- },
68
- ],
69
- })