UNPKG

@getify/eslint-plugin-proper-arrows

Version:

ESLint rules to ensure proper arrow function definitions

6 lines (5 loc) 9.99 kB
/*! @getify/eslint-plugin-proper-arrows v11.0.3 (c) 2021 Kyle Simpson MIT License: http://getify.mit-license.org */ "use strict";function isObjectOrClassMethod(e){const r=e.parent;return r&&("MethodDefinition"===r.type||"Property"===r.type&&(r.method||"get"===r.kind||"set"===r.kind))}function arrowHasInferredName(e){var r=e.parent;return"VariableDeclarator"===r.type&&"Identifier"===r.id.type&&r.init===e||["Property","ClassProperty"].includes(r.type)&&r.value===e||["AssignmentExpression","AssignmentPattern"].includes(r.type)&&"Identifier"===r.left.type&&r.right===e||"ExportDefaultDeclaration"===r.type&&r.declaration===e}function getParentArrowFunction(e,r=!1){var t;for(let o of[...e].reverse()){if(isObjectOrClassMethod(o)||"FunctionExpression"==o.type||"FunctionDeclaration"==o.type)return;if(!("ArrowFunctionExpression"!=o.type||r&&t&&o.body!=t))return o;t=o}}function getAllIdentifiers(e){var r=[];for(let t of e)t&&("Identifier"==t.type?r=[...r,t]:"AssignmentPattern"==t.type?r=[...r,...getAllIdentifiers([t.left])]:"ArrayPattern"==t.type?r=[...r,...getAllIdentifiers(t.elements)]:"ObjectPattern"==t.type?r=[...r,...getAllIdentifiers(t.properties)]:"Property"==t.type&&(r=[...r,...getAllIdentifiers([t.value])]));return r}function inArrowParams(e,r){for(var t,o=e;o&&o!=r;)t=o,o=o.parent;return o==r&&t&&r.params.includes(t)}function isTrivialArrow(e){return"ArrowFunctionExpression"==e.type&&e.params.length<=1&&(0==e.params.length||"Identifier"==e.params[0].type)&&("BlockStatement"==e.body.type&&0==e.body.body.length||"Literal"==e.body.type&&["number","string","boolean"].includes(typeof e.body.value)||"Literal"==e.body.type&&null===e.body.value||"Identifier"==e.body.type||"UnaryExpression"==e.body.type&&"void"==e.body.operator&&"Literal"==e.body.argument.type)}function currentlyInGlobalScope(e,r){var t=e.ecmaFeatures&&e.ecmaFeatures.globalReturn;return t&&r.upper&&r.upper.upper&&["global","module"].includes(r.upper.upper.type)||!t&&r.upper&&["global","module"].includes(r.upper.type)}module.exports={configs:{"getify-says":{plugins:["@getify/proper-arrows"],rules:{"@getify/proper-arrows/params":["error",{unused:"trailing",count:2,length:3,allowed:["e","v","cb","fn","pr"]}],"@getify/proper-arrows/name":"error","@getify/proper-arrows/return":["error",{ternary:1}],"@getify/proper-arrows/where":"error","@getify/proper-arrows/this":["error","nested",{"no-global":!0}]}}},rules:{params:{meta:{type:"problem",docs:{description:"Control various aspects of arrow function parameters to keep them readable",category:"Best Practices",url:"https://github.com/getify/eslint-plugin-proper-arrows/#rule-params"},schema:[{type:"object",properties:{unused:{enum:["all","trailing","none"]},count:{type:"integer",min:0},length:{type:"integer",min:1},allowed:{type:"array",uniqueItems:!0,items:{type:"string"}},trivial:{type:"boolean"}},additionalProperties:!1}],messages:{unused:"Parameter `{{param}}` is unused",tooMany:"Parameter `{{param}}` is beyond the parameter limit allowed",tooShort:"Parameter `{{param}}` is too short"}},create(e){var r=0==e.options.length,t=r?null:e.options[0],o=(r||!("unused"in t)||t.unused,t&&"trailing"===t.unused),n=t&&"none"===t.unused,i=r||!("count"in t)?3:t.count,a=r||!("length"in t)?2:t.length,s=r||!("allowed"in t)?[]:t.allowed,l=!(t&&!0===t.trivial);return{"ArrowFunctionExpression:exit":function exit(r){if(!l||!isTrivialArrow(r)){var t=getAllIdentifiers(r.params);if(t.length>i)for(let r of t.slice(i))if(!s.includes(r.name)){e.report({node:r,messageId:"tooMany",data:{param:r.name}});break}var p=t.filter((function skipAllowed(e){return!s.includes(e.name)}));for(let r of p){let t=r.name;!s.includes(t)&&t.length<a&&e.report({node:r,messageId:"tooShort",data:{param:t}})}if(!n){let n=e.getScope(),i=p.map((function getName(e){return e.name})),a=[],s=null;for(let e of n.variables){let o=e.defs.find((function isParameter(e){return"Parameter"==e.type}));if(o){let n=!!e.defs.find((function isVariable(e){return"Variable"==e.type})),i=e.name,l=!1;if(e.references.length>0)for(let t of e.references){let e=inArrowParams(t.identifier,r);if(!n&&!e||e&&t.identifier!=o.name){l=!0;break}}l?s=i:a.push(t.find((function getParam(e){return e.name==i})))}}let l=!1;for(let r of t)o&&null!=s&&(r.name==s&&(l=!0),!l)||a.includes(r)&&i.includes(r.name)&&e.report({node:r,messageId:"unused",data:{param:r.name}})}}}}}},name:{meta:{type:"problem",docs:{description:"Require arrow functions to receive inferenced names",category:"Best Practices",url:"https://github.com/getify/eslint-plugin-proper-arrows/#rule-name"},schema:[{type:"object",properties:{trivial:{type:"boolean"}},additionalProperties:!1}],messages:{noName:"Required name inference not possible for this arrow function"}},create(e){var r=!(e.options.length>0&&!0===e.options[0].trivial);return{ArrowFunctionExpression:function exit(t){r&&isTrivialArrow(t)||arrowHasInferredName(t)||e.report({node:t,messageId:"noName"})}}}},where:{meta:{type:"problem",docs:{description:"Forbid arrow functions from various locations",category:"Best Practices",url:"https://github.com/getify/eslint-plugin-proper-arrows/#rule-where"},schema:[{type:"object",properties:{global:{type:"boolean"},"global-declaration":{type:"boolean"},property:{type:"boolean"},export:{type:"boolean"},trivial:{type:"boolean"}},additionalProperties:!1}],messages:{noGlobal:"Arrow function not allowed in global/top-level-module scope",noGlobalDeclaration:"Arrow function not allowed as declaration in global/top-level-module scope",noProperty:"Arrow function not allowed in object property",noExport:"Arrow function not allowed in 'export' statement"}},create(e){var r=0==e.options.length,t=r?null:e.options[0],o=r||!("global"in t)||!0===t.global,n=!r&&"global-declaration"in t?t["global-declaration"]:o,i=r||!("property"in t)||!0===t.property,a=r||!("export"in t)||!0===t.export,s=!(t&&!0===t.trivial);return{ArrowFunctionExpression:function exit(r){if(!s||!isTrivialArrow(r)){var t=currentlyInGlobalScope(e.parserOptions,e.getScope()),l=t&&"VariableDeclarator"==r.parent.type;n&&l?e.report({node:r.parent,messageId:"noGlobalDeclaration"}):o&&t&&e.report({node:r,messageId:"noGlobal"}),i&&"Property"==r.parent.type&&"ObjectExpression"==r.parent.parent.type&&r.parent.value==r&&e.report({node:r,messageId:"noProperty"}),a&&("ExportDefaultDeclaration"==r.parent.type&&r.parent.declaration==r||"VariableDeclarator"==r.parent.type&&"VariableDeclaration"==r.parent.parent.type&&"ExportNamedDeclaration"==r.parent.parent.parent.type&&r.parent.init==r)&&e.report({node:r,messageId:"noExport"})}}}}},return:{meta:{type:"problem",docs:{description:"Control various aspects of arrow function returns to keep them readable",category:"Best Practices",url:"https://github.com/getify/eslint-plugin-proper-arrows/#rule-return"},schema:[{type:"object",properties:{object:{type:"boolean"},ternary:{type:"integer",min:0},chained:{type:"boolean"},sequence:{type:"boolean"},trivial:{type:"boolean"}},additionalProperties:!1}],messages:{noConciseObject:"Concise return of object literal not allowed here",noTernary:"Ternary/conditional ('? :') expression not allowed here",noChainedArrow:"Chained arrow function return needs visual delimiters '(' and ')'",noSequence:"Return of comma sequence expression not allowed here"}},create(e){var r=0==e.options.length,t=r?null:e.options[0],o=r||!("object"in t)||!0===t.object,n=r||!("ternary"in t)?0:t.ternary,i=r||!("chained"in t)||!0===t.chained,a=r||!("sequence"in t)||!0===t.sequence,s=!(t&&!0===t.trivial),l=e.getSourceCode(),p=new Map;return{"ConditionalExpression:exit":function exit(r){var t=getParentArrowFunction(e.getAncestors(),!0);if(t){p.has(t)||p.set(t,[]),p.get(t).unshift(r)}},ArrowFunctionExpression:function enter(r){if((!s||!isTrivialArrow(r))&&(o&&"ObjectExpression"==r.body.type&&e.report({node:r,loc:r.body.loc.start,messageId:"noConciseObject"}),a&&"SequenceExpression"==r.body.type&&e.report({node:r,loc:r.body.loc.start,messageId:"noSequence"}),i&&"ArrowFunctionExpression"==r.body.type)){if(s&&isTrivialArrow(r.body))return;r.body.async;let t=l.getTokenBefore(r.body),o=l.getTokenAfter(r.body);t&&"Punctuator"==t.type&&"("==t.value&&o&&"Punctuator"==o.type&&")"==o.value||e.report({node:r,loc:r.body.loc.start,messageId:"noChainedArrow"})}},"ArrowFunctionExpression:exit":function exit(r){if(!(s&&isTrivialArrow(r)||"BlockStatement"==r.body.type)){let t=p.get(r);t&&(t.length>n&&e.report({node:t[n],messageId:"noTernary"}),t.length=0)}}}}},this:{meta:{type:"problem",docs:{description:"Require arrow functions to reference the 'this' keyword",category:"Best Practices",url:"https://github.com/getify/eslint-plugin-proper-arrows/#rule-this"},schema:[{enum:["always","nested","never","never-global"]},{type:"object",properties:{"no-global":{type:"boolean"},trivial:{type:"boolean"}},additionalProperties:!1}],messages:{noThis:"Required 'this' not found in arrow function",noThisNested:"Required 'this' not found in arrow function (or nested arrow functions)",neverThis:"Forbidden 'this' found in arrow function",noGlobal:"Arrow function not allowed in global scope",neverGlobal:"Arrow function with 'this' not allowed in global scope"}},create(e){e.parserOptions;var r="nested"===e.options[0]||!("0"in e.options),t="never-global"===e.options[0],o="always"===e.options[0],n="never"===e.options[0],i=["always","nested"].includes(e.options[0])&&e.options[1]&&!0===e.options[1]["no-global"],a=!(e.options[1]&&!0===e.options[1].trivial),s=new Set;return{ThisExpression:function enter(r){var t=getParentArrowFunction(e.getAncestors());s.add(t)},"ArrowFunctionExpression:exit":function exit(l){if(!a||!isTrivialArrow(l)){var p=currentlyInGlobalScope(e.parserOptions,e.getScope());if(s.has(l)){if(n&&e.report({node:l,messageId:"neverThis"}),p&&(t&&e.report({node:l,messageId:"neverGlobal"}),i&&e.report({node:l,messageId:"noGlobal"})),r||t){let r=getParentArrowFunction(e.getAncestors());r&&s.add(r)}}else if(!n&&!t){let r=o?"noThis":"noThisNested";e.report({node:l,messageId:r})}}}}}}}};