@master/eslint-plugin-css 2.0.0-beta.185 → 2.0.0-beta.187

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.
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ var f=Object.create;var t=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var n=Object.getPrototypeOf,s=Object.prototype.hasOwnProperty;var u=(o,p,r,m)=>{if(p&&typeof p=="object"||typeof p=="function")for(let i of l(p))!s.call(o,i)&&i!==r&&t(o,i,{get:()=>p[i],enumerable:!(m=g(p,i))||m.enumerable});return o};var x=(o,p,r)=>(r=o!=null?f(n(o)):{},u(p||!o||!o.__esModule?t(r,"default",{value:o,enumerable:!0}):r,o));var e=x(require("./plugin"));module.exports=e.default;
@@ -0,0 +1,8 @@
1
+ declare const plugin: {
2
+ rules: {
3
+ 'class-collision': import("eslint").Rule.RuleModule;
4
+ 'class-order': import("eslint").Rule.RuleModule;
5
+ 'class-validation': import("eslint").Rule.RuleModule;
6
+ };
7
+ };
8
+ export default plugin;
package/dist/plugin.js ADDED
@@ -0,0 +1 @@
1
+ var e=Object.create;var r=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var u=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var v=(s,l)=>{for(var o in l)r(s,o,{get:l[o],enumerable:!0})},t=(s,l,o,c)=>{if(l&&typeof l=="object"||typeof l=="function")for(let i of f(l))!g.call(s,i)&&i!==o&&r(s,i,{get:()=>l[i],enumerable:!(c=p(l,i))||c.enumerable});return s};var a=(s,l,o)=>(o=s!=null?e(u(s)):{},t(l||!s||!s.__esModule?r(o,"default",{value:s,enumerable:!0}):o,s)),x=s=>t(r({},"__esModule",{value:!0}),s);var V={};v(V,{default:()=>O});module.exports=x(V);var m=a(require("./rules/class-collision")),n=a(require("./rules/class-order")),d=a(require("./rules/class-validation"));const C={rules:{"class-collision":m.default,"class-order":n.default,"class-validation":d.default}};var O=C;
@@ -0,0 +1,3 @@
1
+ import { Rule } from 'eslint';
2
+ declare const _default: Rule.RuleModule;
3
+ export default _default;
@@ -0,0 +1 @@
1
+ var M=Object.create;var f=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var V=Object.getOwnPropertyNames;var q=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var D=(e,o)=>{for(var s in o)f(e,s,{get:o[s],enumerable:!0})},R=(e,o,s,c)=>{if(o&&typeof o=="object"||typeof o=="function")for(let l of V(o))!A.call(e,l)&&l!==s&&f(e,l,{get:()=>o[l],enumerable:!(c=N(o,l))||c.enumerable});return e};var m=(e,o,s)=>(s=e!=null?M(q(e)):{},R(o||!e||!e.__esModule?f(s,"default",{value:e,enumerable:!0}):s,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:o,settings:s,config:c}=(0,x.default)(e);return(0,v.default)({context:e,options:o,settings:s,config:c},(E,L=null)=>{S.parseNodeRecursive(E,L,(n,C,T,b,j)=>{const k=e.sourceCode.lines,w=C.loc.start.line,I=C.loc.end.line,p={};console.log(n),n.forEach(i=>{p[i]=(0,y.createValidRules)(i,{config:c})[0]});for(let i=0;i<n.length;i++){const u=n[i],g=p[u],d=[];if(g)for(let a=0;a<n.length;a++){const r=n[a],t=p[r];i!==a&&t&&(0,$.default)(g.declarations,t.declarations)&&g.stateToken===t.stateToken&&d.push(r)}if(d.length>0){const a=d.map(t=>`"${t}"`).join(" and ");let r=T;for(const t of d){const h=t.replace(/(\\|\.|\(|\)|\[|\]|\{|\}|\+|\*|\?|\^|\$|\||\/)/g,"\\$1");r=r.replace(new RegExp(`\\s+${h}|${h}\\s+`),"")}e.report({loc:S.findLoc(u,k,w,I),messageId:"collisionClass",data:{message:`"${u}" applies the same CSS declarations as ${a}.`},fix:function(t){return t.replaceTextRange([b,j],r)}})}}},!1,!1,s.ignoredKeys,e)})}};
@@ -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,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,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
+ 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,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,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,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||"")}}
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.185","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.185"}
1
+ {"name":"@master/eslint-plugin-css","scripts":{"build":"techor pack 'src/**/*.ts' --format cjs","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","files":["dist"],"publishConfig":{"access":"public"},"dependencies":{"@master/css":"^2.0.0-beta.187","@master/css-validator":"^2.0.0-beta.187","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.187"}
package/lib/index.js DELETED
@@ -1,19 +0,0 @@
1
- /**
2
- * @fileoverview Rules enforcing best practices while using Master CSS
3
- * @author Miles
4
- */
5
- 'use strict'
6
-
7
- //------------------------------------------------------------------------------
8
- // Requirements
9
- //------------------------------------------------------------------------------
10
-
11
- const requireIndex = require('requireindex')
12
-
13
- //------------------------------------------------------------------------------
14
- // Plugin Definition
15
- //------------------------------------------------------------------------------
16
-
17
-
18
- // import all rules in lib/rules
19
- module.exports.rules = requireIndex(__dirname + '/rules')
@@ -1,282 +0,0 @@
1
- /* eslint-disable no-case-declarations */
2
- /**
3
- * @fileoverview Use a consistent orders for the Master CSS classnames, based on property then on variants
4
- * @author Miles
5
- */
6
- 'use strict'
7
-
8
- // Modified from https://github.com/francoismassart/eslint-plugin-tailwindcss
9
-
10
- const astUtil = require('../util/ast')
11
- const removeDuplicatesFromClassnamesAndWhitespaces = require('../util/removeDuplicatesFromClassnamesAndWhitespaces')
12
- const getOption = require('../util/settings')
13
- const parserUtil = require('../util/parser')
14
-
15
- const { reorderForReadableClasses } = require('@master/css')
16
-
17
- //------------------------------------------------------------------------------
18
- // Rule Definition
19
- //------------------------------------------------------------------------------
20
-
21
- // Predefine message for use in context.report conditional.
22
- // messageId will still be usable in tests.
23
- const INVALID_CLASSNAMES_ORDER_MSG = 'No consistent class order followed.'
24
-
25
- module.exports = {
26
- meta: {
27
- docs: {
28
- description: 'Enforce a consistent and logical order of classes',
29
- category: 'Stylistic Issues',
30
- recommended: false,
31
- url: 'https://beta.css.master.co/docs/code-linting#enforce-a-consistent-and-logical-order-of-classes',
32
- },
33
- messages: {
34
- invalidOrder: INVALID_CLASSNAMES_ORDER_MSG,
35
- },
36
- fixable: 'code',
37
- schema: [
38
- {
39
- type: 'object',
40
- properties: {
41
- callees: {
42
- type: 'array',
43
- items: { type: 'string', minLength: 0 },
44
- uniqueItems: true,
45
- },
46
- ignoredKeys: {
47
- type: 'array',
48
- items: { type: 'string', minLength: 0 },
49
- uniqueItems: true,
50
- },
51
- config: {
52
- // returned from `loadConfig()` utility
53
- type: ['string', 'object'],
54
- },
55
- removeDuplicates: {
56
- // default: true,
57
- type: 'boolean',
58
- },
59
- tags: {
60
- type: 'array',
61
- items: { type: 'string', minLength: 0 },
62
- uniqueItems: true,
63
- },
64
- },
65
- },
66
- ],
67
- },
68
-
69
- create: function (context) {
70
- const callees = getOption(context, 'callees')
71
- const skipClassAttribute = getOption(context, 'skipClassAttribute')
72
- const tags = getOption(context, 'tags')
73
- const masterCssConfig = getOption(context, 'config')
74
- const classRegex = getOption(context, 'classRegex')
75
-
76
- //----------------------------------------------------------------------
77
- // Helpers
78
- //----------------------------------------------------------------------
79
- /**
80
- * Recursive function crawling into child nodes
81
- * @param {ASTNode} node The root node of the current parsing
82
- * @param {ASTNode} arg The child node of node
83
- * @returns {void}
84
- */
85
- const sortNodeArgumentValue = (node, arg = null) => {
86
- let originalClassNamesValue = null
87
- let start = null
88
- let end = null
89
- let prefix = ''
90
- let suffix = ''
91
- if (arg === null) {
92
- originalClassNamesValue = astUtil.extractValueFromNode(node)
93
- const range = astUtil.extractRangeFromNode(node)
94
- if (node.type === 'TextAttribute') {
95
- start = range[0]
96
- end = range[1]
97
- } else {
98
- start = range[0] + 1
99
- end = range[1] - 1
100
- }
101
- } else {
102
- switch (arg.type) {
103
- case 'Identifier':
104
- return
105
- case 'TemplateLiteral':
106
- arg.expressions.forEach((exp) => {
107
- sortNodeArgumentValue(node, exp)
108
- })
109
- arg.quasis.forEach((quasis) => {
110
- sortNodeArgumentValue(node, quasis)
111
- })
112
- return
113
- case 'ConditionalExpression':
114
- sortNodeArgumentValue(node, arg.consequent)
115
- sortNodeArgumentValue(node, arg.alternate)
116
- return
117
- case 'LogicalExpression':
118
- sortNodeArgumentValue(node, arg.right)
119
- return
120
- case 'ArrayExpression':
121
- arg.elements.forEach((el) => {
122
- sortNodeArgumentValue(node, el)
123
- })
124
- return
125
- case 'ObjectExpression':
126
- const isUsedByClassNamesPlugin = node.callee && node.callee.name === 'classnames'
127
- const isVue = node.key && node.key.type === 'VDirectiveKey'
128
- arg.properties.forEach((prop) => {
129
- const propVal = isUsedByClassNamesPlugin || isVue ? prop.key : prop.value
130
- sortNodeArgumentValue(node, propVal)
131
- })
132
- return
133
- case 'Property':
134
- sortNodeArgumentValue(node, arg.key)
135
- break
136
- case 'Literal':
137
- originalClassNamesValue = arg.value
138
- start = arg.range[0] + 1
139
- end = arg.range[1] - 1
140
- break
141
- case 'SvelteLiteral':
142
- originalClassNamesValue = arg.value
143
- if (originalClassNamesValue === '') {
144
- return
145
- }
146
- start = arg.range[0]
147
- end = arg.range[1]
148
- break;
149
- case 'TemplateElement':
150
- originalClassNamesValue = arg.value.raw
151
- if (originalClassNamesValue === '') {
152
- return
153
- }
154
- start = arg.range[0]
155
- end = arg.range[1]
156
- // https://github.com/eslint/eslint/issues/13360
157
- // The problem is that range computation includes the backticks (`test`)
158
- // but value.raw does not include them, so there is a mismatch.
159
- // start/end does not include the backticks, therefore it matches value.raw.
160
- const txt = context.getSourceCode().getText(arg)
161
- prefix = astUtil.getTemplateElementPrefix(txt, originalClassNamesValue)
162
- suffix = astUtil.getTemplateElementSuffix(txt, originalClassNamesValue)
163
- originalClassNamesValue = astUtil.getTemplateElementBody(txt, prefix, suffix)
164
- break
165
- }
166
- }
167
-
168
- let { classNames, whitespaces, headSpace, tailSpace } =
169
- astUtil.extractClassnamesFromValue(originalClassNamesValue)
170
-
171
- if (classNames.length <= 1) {
172
- // Don't run sorting for a single or empty className
173
- return
174
- }
175
-
176
- let orderedClassNames = reorderForReadableClasses(classNames, masterCssConfig)
177
- .filter(eachOrderedClassName => classNames.includes(eachOrderedClassName))
178
-
179
- orderedClassNames = orderedClassNames.concat(classNames.filter(x => !orderedClassNames.includes(x)))
180
-
181
- removeDuplicatesFromClassnamesAndWhitespaces(orderedClassNames, whitespaces, headSpace, tailSpace)
182
-
183
- // Generates the validated/sorted attribute value
184
- let validatedClassNamesValue = ''
185
- for (let i = 0; i < orderedClassNames.length; i++) {
186
- const w = whitespaces[i] ?? ''
187
- const cls = orderedClassNames[i]
188
- validatedClassNamesValue += headSpace ? `${w}${cls}` : `${cls}${w}`
189
- if (headSpace && tailSpace && i === orderedClassNames.length - 1) {
190
- validatedClassNamesValue += whitespaces[whitespaces.length - 1] ?? ''
191
- }
192
- }
193
-
194
- if (originalClassNamesValue !== validatedClassNamesValue) {
195
- validatedClassNamesValue = prefix + validatedClassNamesValue + suffix
196
- context.report({
197
- node: node,
198
- messageId: 'invalidOrder',
199
- fix: function (fixer) {
200
- return fixer.replaceTextRange([start, end], validatedClassNamesValue)
201
- },
202
- })
203
- }
204
- }
205
-
206
- //----------------------------------------------------------------------
207
- // Public
208
- //----------------------------------------------------------------------
209
-
210
- const attributeVisitor = function (node) {
211
- if (!astUtil.isClassAttribute(node, classRegex) || skipClassAttribute) {
212
- return
213
- }
214
- if (astUtil.isLiteralAttributeValue(node)) {
215
- sortNodeArgumentValue(node)
216
- } else if (node.value && node.value.type === 'JSXExpressionContainer') {
217
- sortNodeArgumentValue(node, node.value.expression)
218
- }
219
- }
220
-
221
- const callExpressionVisitor = function (node) {
222
- const calleeStr = astUtil.calleeToString(node.callee)
223
- if (callees.findIndex((name) => calleeStr === name) === -1) {
224
- return
225
- }
226
-
227
- node.arguments.forEach((arg) => {
228
- sortNodeArgumentValue(node, arg)
229
- })
230
- }
231
-
232
- const scriptVisitor = {
233
- JSXAttribute: attributeVisitor,
234
- SvelteAttribute: function (node) {
235
- if (!node.key?.name) return
236
- if (!new RegExp(classRegex).test(node.key.name) || skipClassAttribute) {
237
- return
238
- }
239
- for (const eachValue of node.value) {
240
- sortNodeArgumentValue(node, eachValue)
241
- }
242
- },
243
- TextAttribute: attributeVisitor,
244
- CallExpression: callExpressionVisitor,
245
- TaggedTemplateExpression: function (node) {
246
- if (!tags.includes(node.tag.name)) {
247
- return
248
- }
249
-
250
- sortNodeArgumentValue(node, node.quasi)
251
- },
252
- }
253
- const templateVisitor = {
254
- CallExpression: callExpressionVisitor,
255
- /*
256
- Tagged templates inside data bindings
257
- https://github.com/vuejs/vue/issues/9721
258
- */
259
- VAttribute: function (node) {
260
- switch (true) {
261
- case !astUtil.isValidVueAttribute(node, classRegex):
262
- return
263
- case astUtil.isVLiteralValue(node):
264
- sortNodeArgumentValue(node, null)
265
- break
266
- case astUtil.isArrayExpression(node):
267
- node.value.expression.elements.forEach((arg) => {
268
- sortNodeArgumentValue(node, arg)
269
- })
270
- break
271
- case astUtil.isObjectExpression(node):
272
- node.value.expression.properties.forEach((prop) => {
273
- sortNodeArgumentValue(node, prop)
274
- })
275
- break
276
- }
277
- },
278
- }
279
-
280
- return parserUtil.defineTemplateBodyVisitor(context, templateVisitor, scriptVisitor)
281
- },
282
- }
package/lib/util/ast.js DELETED
@@ -1,370 +0,0 @@
1
- /**
2
- * @fileoverview Utility functions for AST
3
- */
4
-
5
- 'use strict'
6
-
7
- const { separatorRegEx } = require('./regex')
8
- // context.parserPath
9
- // /.../eslint-plugin-tailwindcss/node_modules/espree/espree.js
10
- // /.../eslint-plugin-tailwindcss/node_modules/@angular-eslint/template-parser/dist/index.js
11
-
12
- const removeDuplicatesFromArray = require('./removeDuplicatesFromArray')
13
-
14
- function calleeToString(calleeNode) {
15
- if (calleeNode.type === 'Identifier') {
16
- return calleeNode.name
17
- }
18
- if (calleeNode.type === 'MemberExpression') {
19
- return `${calleeNode.object.name}.${calleeNode.property.name}`
20
- }
21
- }
22
-
23
- /**
24
- * Find out if node is `class` or `className`
25
- *
26
- * @param {ASTNode} node The AST node being checked
27
- * @param {String} classRegex Regex to test the attribute that is being checked against
28
- * @returns {Boolean}
29
- */
30
- function isClassAttribute(node, classRegex) {
31
- if (!node.name) {
32
- return false
33
- }
34
- let name = ''
35
- switch (node.type) {
36
- case 'TextAttribute':
37
- name = node.name
38
- break
39
- default:
40
- name = node.name.name
41
- }
42
- return new RegExp(classRegex).test(name)
43
- }
44
-
45
- /**
46
- * Find out if node is `class`
47
- *
48
- * @param {ASTNode} node The AST node being checked
49
- * @param {String} classRegex Regex to test the attribute that is being checked against
50
- * @returns {Boolean}
51
- */
52
- function isVueClassAttribute(node, classRegex) {
53
- const re = new RegExp(classRegex)
54
- let name = ''
55
- switch (true) {
56
- case node.key && node.key.name && re.test(node.key.name):
57
- // class="vue-classes-as-litteral"
58
- return true
59
- case node.key &&
60
- node.key.name &&
61
- node.key.name.name &&
62
- node.key.argument &&
63
- node.key.argument.name &&
64
- /^bind$/.test(node.key.name.name) &&
65
- re.test(node.key.argument.name):
66
- // v-bind:class="vue-classes-as-bind"
67
- // :class="vue-classes-as-bind"
68
- return true
69
- default:
70
- return false
71
- }
72
- }
73
-
74
- /**
75
- * Find out if node's value attribute is just simple text
76
- *
77
- * @param {ASTNode} node The AST node being checked
78
- * @returns {Boolean}
79
- */
80
- function isVLiteralValue(node) {
81
- return node.value && node.value.type === 'VLiteral'
82
- }
83
-
84
- /**
85
- * Find out if node's value attribute is an ArrayExpression
86
- *
87
- * @param {ASTNode} node The AST node being checked
88
- * @returns {Boolean}
89
- */
90
- function isArrayExpression(node) {
91
- return node.value && node.value.type === 'VExpressionContainer' && node.value.expression.type === 'ArrayExpression'
92
- }
93
-
94
- /**
95
- * Find out if node's value attribute is an ObjectExpression
96
- *
97
- * @param {ASTNode} node The AST node being checked
98
- * @returns {Boolean}
99
- */
100
- function isObjectExpression(node) {
101
- return node.value && node.value.type === 'VExpressionContainer' && node.value.expression.type === 'ObjectExpression'
102
- }
103
-
104
- /**
105
- * Find out if node's value attribute is just simple text
106
- *
107
- * @param {ASTNode} node The AST node being checked
108
- * @returns {Boolean}
109
- */
110
- function isVueValidAttributeValue(node) {
111
- switch (true) {
112
- case isVLiteralValue(node): // Simple string
113
- case isArrayExpression(node): // ['tw-unknown-class']
114
- case isObjectExpression(node): // {'tw-unknown-class': true}
115
- return true
116
- default:
117
- return false
118
- }
119
- }
120
-
121
- /**
122
- * Find out if node's value attribute is just simple text
123
- *
124
- * @param {ASTNode} node The AST node being checked
125
- * @returns {Boolean}
126
- */
127
- function isLiteralAttributeValue(node) {
128
- if (node.type === 'TextAttribute' && node.name === 'class' && typeof node.value === 'string') {
129
- return true
130
- }
131
- if (node.value) {
132
- switch (node.value.type) {
133
- case 'Literal':
134
- return true
135
- case 'JSXExpressionContainer':
136
- // className={"..."}
137
- return node.value.expression.type === 'Literal'
138
- }
139
- }
140
- return false
141
- }
142
-
143
- /**
144
- * Find out if the node is a valid candidate for our rules
145
- *
146
- * @param {ASTNode} node The AST node being checked
147
- * @param {String} classRegex Regex to test the attribute that is being checked against
148
- * @returns {Boolean}
149
- */
150
- function isValidJSXAttribute(node, classRegex) {
151
- if (!isClassAttribute(node, classRegex)) {
152
- // Only run for class[Name] attributes
153
- return false
154
- }
155
- if (!isLiteralAttributeValue(node)) {
156
- // No support for dynamic or conditional classnames
157
- return false
158
- }
159
- return true
160
- }
161
-
162
- /**
163
- * Find out if the node is a valid candidate for our rules
164
- *
165
- * @param {ASTNode} node The AST node being checked
166
- * @param {String} classRegex Regex to test the attribute that is being checked against
167
- * @returns {Boolean}
168
- */
169
- function isValidVueAttribute(node, classRegex) {
170
- if (!isVueClassAttribute(node, classRegex)) {
171
- // Only run for class attributes
172
- return false
173
- }
174
- if (!isVueValidAttributeValue(node)) {
175
- // No support for dynamic or conditional classnames
176
- return false
177
- }
178
- return true
179
- }
180
-
181
- function extractRangeFromNode(node) {
182
- if (node.type === 'TextAttribute' && node.name === 'class') {
183
- return [node.valueSpan.fullStart.offset, node.valueSpan.end.offset]
184
- }
185
- switch (node.value.type) {
186
- case 'JSXExpressionContainer':
187
- return node.value.expression.range
188
- default:
189
- return node.value.range
190
- }
191
- }
192
-
193
- function extractValueFromNode(node) {
194
- if (node.type === 'TextAttribute' && node.name === 'class') {
195
- return node.value
196
- }
197
- switch (node.value.type) {
198
- case 'JSXExpressionContainer':
199
- return node.value.expression.value
200
- case 'VExpressionContainer':
201
- switch (node.value.expression.type) {
202
- case 'ArrayExpression':
203
- return node.value.expression.elements
204
- case 'ObjectExpression':
205
- return node.value.expression.properties
206
- }
207
- return node.value.expression.value
208
- default:
209
- return node.value.value
210
- }
211
- }
212
-
213
- function extractClassnamesFromValue(classStr) {
214
- if (typeof classStr !== 'string') {
215
- return { classNames: [], whitespaces: [], headSpace: false, tailSpace: false }
216
- }
217
- let parts = classStr.split(separatorRegEx)
218
- if (parts[0] === '') {
219
- parts.shift()
220
- }
221
- if (parts[parts.length - 1] === '') {
222
- parts.pop()
223
- }
224
- let headSpace = separatorRegEx.test(parts[0])
225
- let tailSpace = separatorRegEx.test(parts[parts.length - 1])
226
- const isClass = (_, i) => (headSpace ? i % 2 !== 0 : i % 2 === 0)
227
- const isNotClass = (_, i) => (headSpace ? i % 2 === 0 : i % 2 !== 0)
228
- let classNames = parts.filter(isClass)
229
- let whitespaces = parts.filter(isNotClass)
230
- return { classNames: classNames, whitespaces: whitespaces, headSpace: headSpace, tailSpace: tailSpace }
231
- }
232
-
233
- /**
234
- * Inspect and parse an abstract syntax node and run a callback function
235
- *
236
- * @param {ASTNode} rootNode The current root node being parsed by eslint
237
- * @param {ASTNode} childNode The AST node child argument being checked
238
- * @param {Function} cb The callback function
239
- * @param {Boolean} skipConditional Optional, indicate distinct parsing for conditional nodes
240
- * @param {Boolean} isolate Optional, set internally to isolate parsing and validation on conditional children
241
- * @param {Array} ignoredKeys Optional, set object keys which should not be parsed e.g. for `cva`
242
- * @returns {void}
243
- */
244
- function parseNodeRecursive(rootNode, childNode, cb, skipConditional = false, isolate = false, ignoredKeys = []) {
245
- // TODO allow vue non litteral
246
- let originalClassNamesValue
247
- let classNames
248
- if (childNode === null) {
249
- originalClassNamesValue = extractValueFromNode(rootNode);
250
- ({ classNames } = extractClassnamesFromValue(originalClassNamesValue))
251
- classNames = removeDuplicatesFromArray(classNames)
252
- if (classNames.length === 0) {
253
- // Don't run for empty className
254
- return
255
- }
256
- cb(classNames, rootNode)
257
- } else if (childNode === undefined) {
258
- // Ignore invalid child candidates (probably inside complex TemplateLiteral)
259
- return
260
- } else {
261
- const forceIsolation = skipConditional ? true : isolate
262
- let trim = false
263
- switch (childNode.type) {
264
- case 'TemplateLiteral':
265
- childNode.expressions.forEach((exp) => {
266
- parseNodeRecursive(rootNode, exp, cb, skipConditional, forceIsolation, ignoredKeys)
267
- })
268
- childNode.quasis.forEach((quasis) => {
269
- parseNodeRecursive(rootNode, quasis, cb, skipConditional, isolate, ignoredKeys)
270
- })
271
- return
272
- case 'ConditionalExpression':
273
- parseNodeRecursive(rootNode, childNode.consequent, cb, skipConditional, forceIsolation, ignoredKeys)
274
- parseNodeRecursive(rootNode, childNode.alternate, cb, skipConditional, forceIsolation, ignoredKeys)
275
- return
276
- case 'LogicalExpression':
277
- parseNodeRecursive(rootNode, childNode.right, cb, skipConditional, forceIsolation, ignoredKeys)
278
- return
279
- case 'ArrayExpression':
280
- childNode.elements.forEach((el) => {
281
- parseNodeRecursive(rootNode, el, cb, skipConditional, forceIsolation, ignoredKeys)
282
- })
283
- return
284
- case 'ObjectExpression':
285
- childNode.properties.forEach((prop) => {
286
- const isUsedByClassNamesPlugin = rootNode.callee && rootNode.callee.name === 'classnames'
287
-
288
- if (prop.type === 'SpreadElement') {
289
- // Ignore spread elements
290
- return
291
- }
292
-
293
- if (prop.key.type === 'Identifier' && ignoredKeys.includes(prop.key.name)) {
294
- // Ignore specific keys defined in settings
295
- return
296
- }
297
-
298
- parseNodeRecursive(
299
- rootNode,
300
- isUsedByClassNamesPlugin ? prop.key : prop.value,
301
- cb,
302
- skipConditional,
303
- forceIsolation,
304
- ignoredKeys
305
- )
306
- })
307
- return
308
- case 'Property':
309
- parseNodeRecursive(rootNode, childNode.key, cb, skipConditional, forceIsolation, ignoredKeys)
310
- return
311
- case 'Literal':
312
- trim = true
313
- originalClassNamesValue = childNode.value
314
- break
315
- case 'TemplateElement':
316
- originalClassNamesValue = childNode.value.raw
317
- break
318
- }
319
- ({ classNames } = extractClassnamesFromValue(originalClassNamesValue))
320
- classNames = removeDuplicatesFromArray(classNames)
321
- if (classNames.length === 0) {
322
- // Don't run for empty className
323
- return
324
- }
325
- const targetNode = isolate ? null : rootNode
326
- cb(classNames, targetNode)
327
- }
328
- }
329
-
330
- function getTemplateElementPrefix(text, raw) {
331
- const idx = text.indexOf(raw)
332
- if (idx === 0) {
333
- return ''
334
- }
335
- return text.split(raw).shift()
336
- }
337
-
338
- function getTemplateElementSuffix(text, raw) {
339
- if (text.indexOf(raw) === -1) {
340
- return ''
341
- }
342
- return text.split(raw).pop()
343
- }
344
-
345
- function getTemplateElementBody(text, prefix, suffix) {
346
- let arr = text.split(prefix)
347
- arr.shift()
348
- let body = arr.join(prefix)
349
- arr = body.split(suffix)
350
- arr.pop()
351
- return arr.join(suffix)
352
- }
353
-
354
- module.exports = {
355
- calleeToString,
356
- extractRangeFromNode,
357
- extractValueFromNode,
358
- extractClassnamesFromValue,
359
- isClassAttribute,
360
- isLiteralAttributeValue,
361
- isArrayExpression,
362
- isObjectExpression,
363
- isValidJSXAttribute,
364
- isValidVueAttribute,
365
- isVLiteralValue,
366
- parseNodeRecursive,
367
- getTemplateElementPrefix,
368
- getTemplateElementSuffix,
369
- getTemplateElementBody,
370
- }
@@ -1,21 +0,0 @@
1
- /**
2
- * @see parserServices https://eslint.org/docs/developer-guide/working-with-rules#the-context-object
3
- * @param {Object} context
4
- * @param {Function} templateBodyVisitor
5
- * @param {Function} scriptVisitor
6
- * @returns
7
- */
8
- function defineTemplateBodyVisitor(context, templateBodyVisitor, scriptVisitor) {
9
- if (context.parserServices == null || context.parserServices.defineTemplateBodyVisitor == null) {
10
- // Default parser
11
- return scriptVisitor
12
- }
13
-
14
- // Using "vue-eslint-parser" requires this setup
15
- // @see https://eslint.org/docs/developer-guide/working-with-rules#the-context-object
16
- return context.parserServices.defineTemplateBodyVisitor(templateBodyVisitor, scriptVisitor)
17
- }
18
-
19
- module.exports = {
20
- defineTemplateBodyVisitor,
21
- }
package/lib/util/regex.js DELETED
@@ -1,16 +0,0 @@
1
- /**
2
- * Escapes a string to be used in a regular expression
3
- * Copied from https://stackoverflow.com/a/3561711.
4
- * @param {string} input
5
- * @returns {string}
6
- */
7
- function escapeRegex(input) {
8
- return input.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&')
9
- }
10
-
11
- const separatorRegEx = /([\t\n\f\r ]+)/
12
-
13
- module.exports = {
14
- escapeRegex,
15
- separatorRegEx,
16
- }
@@ -1,7 +0,0 @@
1
- 'use strict'
2
-
3
- function removeDuplicatesFromArray(arr) {
4
- return [...new Set(arr)]
5
- }
6
-
7
- module.exports = removeDuplicatesFromArray
@@ -1,18 +0,0 @@
1
- 'use strict'
2
-
3
- function removeDuplicatesFromClassnamesAndWhitespaces(orderedClassNames, whitespaces, headSpace, tailSpace) {
4
- let previous = orderedClassNames[0]
5
- const offset = (!headSpace && !tailSpace) || tailSpace ? -1 : 0
6
- for (let i = 1; i < orderedClassNames.length; i++) {
7
- const cls = orderedClassNames[i]
8
- // This function assumes that the list of classNames is ordered, so just comparing to the previous className is enough
9
- if (cls === previous) {
10
- orderedClassNames.splice(i, 1)
11
- whitespaces.splice(i + offset, 1)
12
- i--
13
- }
14
- previous = cls
15
- }
16
- }
17
-
18
- module.exports = removeDuplicatesFromClassnamesAndWhitespaces
@@ -1,39 +0,0 @@
1
- 'use strict'
2
- const exploreConfig = require('explore-config').default
3
-
4
- function getOption(context, name) {
5
- // Options (defined at rule level)
6
- const options = context.options[0] || {}
7
- if (options[name] != undefined) {
8
- return options[name]
9
- }
10
- // Settings (defined at plugin level, shared accross rules)
11
- if (context.settings && context.settings.mastercss && context.settings.mastercss[name] != undefined) {
12
- return context.settings.mastercss[name]
13
- }
14
- // Fallback to defaults
15
- switch (name) {
16
- case 'callees':
17
- return ['classnames', 'clsx', 'ctl', 'cva']
18
- case 'ignoredKeys':
19
- return ['compoundVariants', 'defaultVariants']
20
- case 'classRegex':
21
- return '^class(Name)?$'
22
- case 'config':
23
- return exploreConfig('master.css.*', {})
24
- case 'cssFiles':
25
- return ['**/*.css', '!**/node_modules', '!**/.*', '!**/dist', '!**/build']
26
- case 'cssFilesRefreshRate':
27
- return 5_000
28
- case 'removeDuplicates':
29
- return true
30
- case 'skipClassAttribute':
31
- return false
32
- case 'tags':
33
- return []
34
- case 'whitelist':
35
- return []
36
- }
37
- }
38
-
39
- module.exports = getOption
@@ -1,112 +0,0 @@
1
- /**
2
- * @fileoverview Use a consistent orders for the Master CSS classnames, based on property then on variants
3
- * @author Miles
4
- */
5
- 'use strict'
6
-
7
- // Modified from https://github.com/francoismassart/eslint-plugin-tailwindcss
8
-
9
- //------------------------------------------------------------------------------
10
- // Requirements
11
- //------------------------------------------------------------------------------
12
-
13
- var rule = require('../../lib/rules/class-order')
14
- var RuleTester = require('eslint').RuleTester
15
- var parserOptions = {
16
- ecmaVersion: 2019,
17
- sourceType: 'module',
18
- ecmaFeatures: {
19
- jsx: true,
20
- },
21
- }
22
-
23
- var ruleTester = new RuleTester({ parserOptions })
24
- ruleTester.run('class order', rule, {
25
- valid: [
26
- {
27
- code: `<div class="bg:black fg:white f:24 m:8 p:8">Simple, basic</div>`,
28
- },
29
- {
30
- code: `<div test="bg:black fg:white f:24 m:8 p:8">Simple, using 'test' prop</div>`,
31
- options: [
32
- {
33
- classRegex: '^test$',
34
- },
35
- ],
36
- },
37
- ],
38
- invalid: [
39
- // jsx
40
- {
41
- code: `
42
- export interface FakePropsInterface {
43
- readonly name?: string;
44
- }
45
- function Fake({
46
- name = 'yolo'
47
- }: FakeProps) {
48
- return (
49
- <>
50
- <h1 className={"m:8 bg:black p:8 fg:white f:24"}>Welcome {name}</h1>
51
- <p>Bye {name}</p>
52
- </>
53
- );
54
- }
55
- export default Fake;
56
- `,
57
- output: `
58
- export interface FakePropsInterface {
59
- readonly name?: string;
60
- }
61
- function Fake({
62
- name = 'yolo'
63
- }: FakeProps) {
64
- return (
65
- <>
66
- <h1 className={"bg:black fg:white f:24 m:8 p:8"}>Welcome {name}</h1>
67
- <p>Bye {name}</p>
68
- </>
69
- );
70
- }
71
- export default Fake;
72
- `,
73
- parser: require.resolve('@typescript-eslint/parser'),
74
- errors: [{ messageId: 'invalidOrder' }],
75
- },
76
- {
77
- code: `<div class="fg:white f:24 m:8 p:8 bg:black">Classnames will be ordered</div>`,
78
- output: `<div class="bg:black fg:white f:24 m:8 p:8">Classnames will be ordered</div>`,
79
- errors: [{ messageId: 'invalidOrder' }],
80
- },
81
- // html, angular
82
- {
83
- code: `
84
- <div class="
85
- m:8
86
- bg:black
87
- p:8
88
- fg:white
89
- f:24
90
- ">
91
- :)
92
- </div>`,
93
- output: `
94
- <div class="
95
- bg:black
96
- fg:white
97
- f:24
98
- m:8
99
- p:8
100
- ">
101
- :)
102
- </div>`,
103
- errors: [{ messageId: 'invalidOrder' }],
104
- parser: require.resolve('@angular-eslint/template-parser'),
105
- },
106
- {
107
- 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>`,
108
- 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>`,
109
- errors: [{ messageId: 'invalidOrder' }],
110
- }
111
- ],
112
- })
@@ -1,25 +0,0 @@
1
- 'use strict'
2
-
3
- var rule = require('../../lib/rules/class-order')
4
- var RuleTester = require('eslint').RuleTester
5
- var parserOptions = {
6
- ecmaVersion: 2019,
7
- sourceType: 'module',
8
- ecmaFeatures: {
9
- jsx: true,
10
- },
11
- }
12
-
13
- var ruleTester = new RuleTester({ parserOptions })
14
- ruleTester.run('svelte class order', rule, {
15
- valid: [{ code: `<div class="bg:black fg:white f:24 m:8 p:8">Simple, basic</div>` }],
16
- invalid: [
17
- {
18
- code: `<div class="m:8 bg:black p:8 fg:white f:24 {flipped ? 'flipped' : ''}">Enhancing readability</div>`,
19
- output: `<div class="bg:black fg:white f:24 m:8 p:8 {flipped ? 'flipped' : ''}">Enhancing readability</div>`,
20
- errors: [{ messageId: 'invalidOrder' }],
21
- filename: 'test.svelte',
22
- parser: require.resolve('svelte-eslint-parser'),
23
- },
24
- ],
25
- })
@@ -1,25 +0,0 @@
1
- 'use strict'
2
-
3
- var rule = require('../../lib/rules/class-order')
4
- var RuleTester = require('eslint').RuleTester
5
- var parserOptions = {
6
- ecmaVersion: 2019,
7
- sourceType: 'module',
8
- ecmaFeatures: {
9
- jsx: true,
10
- },
11
- }
12
-
13
- var ruleTester = new RuleTester({ parserOptions })
14
- ruleTester.run('vue class order', rule, {
15
- valid: [{ code: `<div class="bg:black fg:white f:24 m:8 p:8">Simple, basic</div>` }],
16
- invalid: [
17
- {
18
- code: `<template><div class="m:8 bg:black p:8 fg:white f:24">Enhancing readability</div></template>`,
19
- output: `<template><div class="bg:black fg:white f:24 m:8 p:8">Enhancing readability</div></template>`,
20
- errors: [{ messageId: 'invalidOrder' }],
21
- filename: 'test.vue',
22
- parser: require.resolve('vue-eslint-parser'),
23
- },
24
- ],
25
- })