@2digits/eslint-plugin 3.5.0 → 3.5.2

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.
package/dist/index.d.mts CHANGED
@@ -9,10 +9,18 @@ declare const plugin: {
9
9
  version: string;
10
10
  };
11
11
  rules: {
12
- 'if-curly': _typescript_eslint_utils_ts_eslint0.RuleModule<"missingCurly", [], unknown, _typescript_eslint_utils_ts_eslint0.RuleListener>;
13
- 'prefer-inline-array-callbacks': _typescript_eslint_utils_ts_eslint0.RuleModule<"noCallbackReference", [], unknown, _typescript_eslint_utils_ts_eslint0.RuleListener>;
14
- 'prefer-inline-handlers': _typescript_eslint_utils_ts_eslint0.RuleModule<"preferInlineHandler", [], unknown, _typescript_eslint_utils_ts_eslint0.RuleListener>;
15
- 'type-param-names': _typescript_eslint_utils_ts_eslint0.RuleModule<"prefix" | "initial" | "remainder" | "suggestRename", [], unknown, _typescript_eslint_utils_ts_eslint0.RuleListener>;
12
+ 'if-curly': _typescript_eslint_utils_ts_eslint0.RuleModule<"missingCurly", [], unknown, _typescript_eslint_utils_ts_eslint0.RuleListener> & {
13
+ name: string;
14
+ };
15
+ 'prefer-inline-array-callbacks': _typescript_eslint_utils_ts_eslint0.RuleModule<"noCallbackReference", [], unknown, _typescript_eslint_utils_ts_eslint0.RuleListener> & {
16
+ name: string;
17
+ };
18
+ 'prefer-inline-handlers': _typescript_eslint_utils_ts_eslint0.RuleModule<"preferInlineHandler", [], unknown, _typescript_eslint_utils_ts_eslint0.RuleListener> & {
19
+ name: string;
20
+ };
21
+ 'type-param-names': _typescript_eslint_utils_ts_eslint0.RuleModule<"prefix" | "initial" | "remainder" | "suggestRename", [], unknown, _typescript_eslint_utils_ts_eslint0.RuleListener> & {
22
+ name: string;
23
+ };
16
24
  };
17
25
  configs: {
18
26
  recommended: {
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{AST_NODE_TYPES as e,AST_TOKEN_TYPES as t,ESLintUtils as n}from"@typescript-eslint/utils";import{ScopeType as r}from"@typescript-eslint/scope-manager";import*as i from"ts-api-utils";var a=`3.5.0`;const o={rules:{"@2digits/if-curly":`error`,"@2digits/prefer-inline-array-callbacks":`error`,"@2digits/prefer-inline-handlers":`error`,"@2digits/type-param-names":`error`}},s=n.RuleCreator(e=>`https://github.com/2digits-agency/configs/tree/main/packages/eslint-plugin/src/rules/${e}.ts`),c=s({name:`if-curly`,meta:{type:`suggestion`,docs:{description:`Require curly braces around if statement bodies`},fixable:`code`,schema:[],messages:{missingCurly:`Expected curly braces around if statement body`}},defaultOptions:[],create(n){let r=n.sourceCode;function i(e){return(r.lines[e.loc.start.line-1]??``).match(/^(\s*)/)?.[1]??``}function a(a,o,s=!1){if(a.type===e.BlockStatement)return;let c=s?r.getTokenBefore(a,e=>e.type===t.Keyword&&e.value===`else`):r.getFirstToken(o);n.report({node:a,loc:c?.loc??a.loc,messageId:`missingCurly`,fix(e){let t=r.getText(a),n=i(a);return e.replaceText(a,`{\n${n} ${t}\n${n}}`)}})}return{IfStatement(t){a(t.consequent,t,!1),t.alternate&&t.alternate.type!==e.IfStatement&&a(t.alternate,t,!0)}}}}),l=new Map([[`every`,new Set([`Boolean`])],[`filter`,new Set([`Boolean`])],[`find`,new Set([`Boolean`])],[`findLast`,new Set([`Boolean`])],[`findIndex`,new Set([`Boolean`])],[`findLastIndex`,new Set([`Boolean`])],[`flatMap`,void 0],[`forEach`,void 0],[`map`,new Set([`String`,`Number`,`BigInt`,`Boolean`,`Symbol`])],[`some`,new Set([`Boolean`])]]),u=new Set([`sort`,`toSorted`]),d=new Set([`reduce`,`reduceRight`]),f=new Set([...l.keys(),...d,...u]),p=new WeakMap;function m(t,n){return t.type===e.Identifier&&t.name===n}function h(t,n,i){if(n.type!==e.Identifier||!l.get(t)?.has(n.name))return!1;let a=i.getScope(n).references.find(e=>e.identifier===n);return a?.resolved?a.resolved.scope.type===r.global:!0}function g(t){return t.type===e.ArrowFunctionExpression||t.type===e.FunctionExpression}function _(t){return t.type===e.CallExpression&&t.callee.type===e.MemberExpression&&m(t.callee.property,`bind`)}function v(t){if(t.type===e.Identifier)return t.name;if(t.type===e.MemberExpression){if(t.property.type===e.Identifier)return t.property.name;if(t.property.type===e.Literal)return String(t.property.value)}return`callback`}const y=[e.SequenceExpression,e.YieldExpression,e.ArrowFunctionExpression,e.ConditionalExpression,e.AssignmentExpression,e.LogicalExpression,e.BinaryExpression,e.UnaryExpression,e.UpdateExpression];function b(e){return y.includes(e.type)}function x(e,t){return i.unionConstituents(t).some(t=>i.intersectionConstituents(t).every(t=>e.isArrayType(t)||e.isTupleType(t)))}const S=s({name:`prefer-inline-array-callbacks`,meta:{type:`problem`,docs:{description:`Disallow passing function references to array methods`},fixable:`code`,schema:[],messages:{noCallbackReference:"Do not pass `{{name}}` by reference to `Array#{{method}}`. Array methods pass extra arguments (index, array) which may cause unexpected behavior."}},defaultOptions:[],create(t){let r=n.getParserServices(t,!0);if(!r.program||!(`getTypeAtLocation`in r))return{};let i=r.program.getTypeChecker();function a(n){let{object:a,property:o}=n.callee,s=o.name;if(!f.has(s)||n.arguments.length===0||n.arguments.length>2)return;let[c]=n.arguments;if(!c||c.type===e.SpreadElement||g(c)||_(c)||h(s,c,t.sourceCode))return;let l=p.get(a);if(l===void 0){let e=r.esTreeNodeToTSNodeMap.get(a);l=x(i,i.getTypeAtLocation(e)),p.set(a,l)}if(!l)return;let m=v(c),y=t.sourceCode.getText(c),S=b(c)?`(${y})`:y,C=d.has(s),w=u.has(s),T=C?`(acc, element)`:w?`(a, b)`:`(element)`,E=C?`acc, element`:w?`a, b`:`element`,D=`${T} => ${s===`forEach`?`{ ${S}(${E}); }`:`${S}(${E})`}`;t.report({node:c,messageId:`noCallbackReference`,data:{name:m,method:s},fix(e){return e.replaceText(c,D)}})}return{'CallExpression[callee.type="MemberExpression"][callee.computed=false][callee.property.type="Identifier"]':a}}}),C=new Set([`useCallback`,`useMemo`]),w=new WeakMap;function T(t){let n=w.get(t);if(n!==void 0)return n;let r=t.parent,i;for(;r;){if(r.type===e.FunctionDeclaration||r.type===e.FunctionExpression||r.type===e.ArrowFunctionExpression){i=r;break}r=r.parent}return w.set(t,i),i}function E(t){if(t.type!==e.CallExpression)return!1;let{callee:n}=t;return n.type===e.Identifier?C.has(n.name):!1}function D(e,t){let n=e;for(;n;){let e=n.set.get(t);if(e)return e;n=n.upper}}function O(t,n){if(n.type===e.FunctionDeclaration){let e=n.params.map(e=>t.getText(e)).join(`, `),r=t.getText(n.body);return`${n.async?`async `:``}(${e}) => ${r}`}return t.getText(n)}function k(t){if(t.type===e.FunctionDeclaration)return t;if(t.type===e.VariableDeclarator&&t.parent.declarations.length===1)return t.parent}const A=s({name:`prefer-inline-handlers`,meta:{type:`suggestion`,docs:{description:`Discourage hoisting event handlers only used once in JSX; prefer inlining`},fixable:`code`,schema:[],messages:{preferInlineHandler:`Handler '{{name}}' is only used once as a JSX prop. Inline it where it's used.`}},defaultOptions:[],create(t){let n=t.sourceCode;function r(r,i,a){let o=D(n.getScope(i),r.name);if(!o)return;let s=o.references.filter(e=>e.isRead()&&e.identifier!==r);if(s.length!==1)return;let c=s[0];if(!c)return;let l=c.identifier,{parent:u}=l;u.type===e.JSXExpressionContainer&&u.parent.type===e.JSXAttribute&&t.report({node:r,messageId:`preferInlineHandler`,data:{name:r.name},fix(e){let t=O(n,a),r=k(i),o=[e.replaceText(l,t)];return r&&o.push(e.remove(r)),o}})}return{"VariableDeclarator[init.type=ArrowFunctionExpression], VariableDeclarator[init.type=FunctionExpression]":function(t){if(t.id.type!==e.Identifier||!t.init||!T(t)||E(t.init))return;let n=t.init;r(t.id,t,n)},"VariableDeclarator[init.type=CallExpression]":function(t){t.id.type===e.Identifier&&(!t.init||t.init.type!==e.CallExpression||T(t)&&E(t.init))},FunctionDeclaration(e){e.id&&T(e)&&r(e.id,e,e)}}}}),j=/^[T$][A-Z][a-z]+\d*$/,M=/^[T$]/,N=/^[T$][A-Z]/,P=/^[T$][A-Z][a-z]/,F={prefix:`prefix`,initial:`initial`,remainder:`remainder`,suggestRename:`suggestRename`},I=s({name:`type-param-names`,meta:{type:`suggestion`,docs:{description:`Enforce giving proper names to type parameters when there are two or more`},hasSuggestions:!0,schema:[],messages:{prefix:`Type parameter {{name}} should have a prefix of "T" or "$"`,initial:`Type parameter {{name}}'s name should start with an uppercase letter`,remainder:`Type parameter {{name}}'s name should contain at least one lowercase letter`,suggestRename:`Rename to {{suggestion}}`}},defaultOptions:[],create(e){return{TSTypeParameterDeclaration(t){let{params:n}=t;if(!(n.length===1&&n.at(0)?.name.name===`T`))for(let t of n){let{name:n}=t.name,r=L(n);if(r){let i=R(n);e.report({node:t,messageId:r,data:{name:n},suggest:[{messageId:`suggestRename`,data:{suggestion:i},fix(e){return e.replaceText(t.name,i)}}]})}}}}}});function L(e){if(!j.test(e)){if(!M.test(e))return F.prefix;if(!N.test(e))return F.initial;if(!P.test(e))return F.remainder}}function R(e){if(!M.test(e))return`T${e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()}`;let t=e.charAt(0),n=e.slice(1);return n.length===0?`${t}Value`:`${t}${n.charAt(0).toUpperCase()+(n.length>1?n.slice(1).toLowerCase():`a`)}`}const z={meta:{name:`@2digits`,version:a},rules:{"if-curly":c,"prefer-inline-array-callbacks":S,"prefer-inline-handlers":A,"type-param-names":I},configs:{recommended:{plugins:{"@2digits":{}},rules:o.rules}}};z.configs.recommended.plugins[`@2digits`]=z;var B=z;export{B as default};
1
+ import{AST_NODE_TYPES as e,AST_TOKEN_TYPES as t,ESLintUtils as n}from"@typescript-eslint/utils";import{ScopeType as r}from"@typescript-eslint/scope-manager";import*as i from"ts-api-utils";var a=`3.5.2`;const o={rules:{"@2digits/if-curly":`error`,"@2digits/prefer-inline-array-callbacks":`error`,"@2digits/prefer-inline-handlers":`error`,"@2digits/type-param-names":`error`}},s=n.RuleCreator(e=>`https://github.com/2digits-agency/configs/tree/main/packages/eslint-plugin/src/rules/${e}.ts`),c=s({name:`if-curly`,meta:{type:`suggestion`,docs:{description:`Require curly braces around if statement bodies`},fixable:`code`,schema:[],messages:{missingCurly:`Expected curly braces around if statement body`}},defaultOptions:[],create(n){let r=n.sourceCode;function i(e){return(r.lines[e.loc.start.line-1]??``).match(/^(\s*)/)?.[1]??``}function a(a,o,s=!1){if(a.type===e.BlockStatement)return;let c=s?r.getTokenBefore(a,e=>e.type===t.Keyword&&e.value===`else`):r.getFirstToken(o);n.report({node:a,loc:c?.loc??a.loc,messageId:`missingCurly`,fix(e){let t=r.getText(a),n=i(a);return e.replaceText(a,`{\n${n} ${t}\n${n}}`)}})}return{IfStatement(t){a(t.consequent,t,!1),t.alternate&&t.alternate.type!==e.IfStatement&&a(t.alternate,t,!0)}}}}),l=new Map([[`every`,new Set([`Boolean`])],[`filter`,new Set([`Boolean`])],[`find`,new Set([`Boolean`])],[`findLast`,new Set([`Boolean`])],[`findIndex`,new Set([`Boolean`])],[`findLastIndex`,new Set([`Boolean`])],[`flatMap`,void 0],[`forEach`,void 0],[`map`,new Set([`String`,`Number`,`BigInt`,`Boolean`,`Symbol`])],[`some`,new Set([`Boolean`])]]),u=new Set([`sort`,`toSorted`]),d=new Set([`reduce`,`reduceRight`]),f=new Set([...l.keys(),...d,...u]),p=new WeakMap;function m(t,n){return t.type===e.Identifier&&t.name===n}function h(t,n,i){if(n.type!==e.Identifier||!l.get(t)?.has(n.name))return!1;let a=i.getScope(n).references.find(e=>e.identifier===n);return a?.resolved?a.resolved.scope.type===r.global:!0}function g(t){return t.type===e.ArrowFunctionExpression||t.type===e.FunctionExpression}function _(t){return t.type===e.CallExpression&&t.callee.type===e.MemberExpression&&m(t.callee.property,`bind`)}function v(t){if(t.type===e.Identifier)return t.name;if(t.type===e.MemberExpression){if(t.property.type===e.Identifier)return t.property.name;if(t.property.type===e.Literal)return String(t.property.value)}return`callback`}const y=[e.SequenceExpression,e.YieldExpression,e.ArrowFunctionExpression,e.ConditionalExpression,e.AssignmentExpression,e.LogicalExpression,e.BinaryExpression,e.UnaryExpression,e.UpdateExpression];function b(e){return y.includes(e.type)}function x(e,t){return i.unionConstituents(t).some(t=>i.intersectionConstituents(t).every(t=>e.isArrayType(t)||e.isTupleType(t)))}const S=s({name:`prefer-inline-array-callbacks`,meta:{type:`problem`,docs:{description:`Disallow passing function references to array methods`},fixable:`code`,schema:[],messages:{noCallbackReference:"Do not pass `{{name}}` by reference to `Array#{{method}}`. Array methods pass extra arguments (index, array) which may cause unexpected behavior."}},defaultOptions:[],create(t){let r=n.getParserServices(t,!0);if(!r.program||!(`getTypeAtLocation`in r))return{};let i=r.program.getTypeChecker();function a(n){let{object:a,property:o}=n.callee,s=o.name;if(!f.has(s)||n.arguments.length===0||n.arguments.length>2)return;let[c]=n.arguments;if(!c||c.type===e.SpreadElement||g(c)||_(c)||h(s,c,t.sourceCode))return;let l=p.get(a);if(l===void 0){let e=r.esTreeNodeToTSNodeMap.get(a);l=x(i,i.getTypeAtLocation(e)),p.set(a,l)}if(!l)return;let m=v(c),y=t.sourceCode.getText(c),S=b(c)?`(${y})`:y,C=d.has(s),w=u.has(s),T=C?`(acc, element)`:w?`(a, b)`:`(element)`,E=C?`acc, element`:w?`a, b`:`element`,D=`${T} => ${s===`forEach`?`{ ${S}(${E}); }`:`${S}(${E})`}`;t.report({node:c,messageId:`noCallbackReference`,data:{name:m,method:s},fix(e){return e.replaceText(c,D)}})}return{'CallExpression[callee.type="MemberExpression"][callee.computed=false][callee.property.type="Identifier"]':a}}}),C=new Set([`useCallback`,`useMemo`]),w=new WeakMap;function T(t){let n=w.get(t);if(n!==void 0)return n;let r=t.parent,i;for(;r;){if(r.type===e.FunctionDeclaration||r.type===e.FunctionExpression||r.type===e.ArrowFunctionExpression){i=r;break}r=r.parent}return w.set(t,i),i}function E(t){if(t.type!==e.CallExpression)return!1;let{callee:n}=t;return n.type===e.Identifier?C.has(n.name):!1}function D(e,t){let n=e;for(;n;){let e=n.set.get(t);if(e)return e;n=n.upper}}function O(t,n){if(n.type===e.FunctionDeclaration){let e=n.params.map(e=>t.getText(e)).join(`, `),r=t.getText(n.body);return`${n.async?`async `:``}(${e}) => ${r}`}return t.getText(n)}function k(t){if(t.type===e.FunctionDeclaration)return t;if(t.type===e.VariableDeclarator&&t.parent.declarations.length===1)return t.parent}const A=s({name:`prefer-inline-handlers`,meta:{type:`suggestion`,docs:{description:`Discourage hoisting event handlers only used once in JSX; prefer inlining`},fixable:`code`,schema:[],messages:{preferInlineHandler:`Handler '{{name}}' is only used once as a JSX prop. Inline it where it's used.`}},defaultOptions:[],create(t){let n=t.sourceCode;function r(r,i,a){let o=D(n.getScope(i),r.name);if(!o)return;let s=o.references.filter(e=>e.isRead()&&e.identifier!==r);if(s.length!==1)return;let c=s[0];if(!c)return;let l=c.identifier,{parent:u}=l;u.type===e.JSXExpressionContainer&&u.parent.type===e.JSXAttribute&&t.report({node:r,messageId:`preferInlineHandler`,data:{name:r.name},fix(e){let t=O(n,a),r=k(i),o=[e.replaceText(l,t)];return r&&o.push(e.remove(r)),o}})}return{"VariableDeclarator[init.type=ArrowFunctionExpression], VariableDeclarator[init.type=FunctionExpression]":function(t){if(t.id.type!==e.Identifier||!t.init||!T(t)||E(t.init))return;let n=t.init;r(t.id,t,n)},"VariableDeclarator[init.type=CallExpression]":function(t){t.id.type===e.Identifier&&(!t.init||t.init.type!==e.CallExpression||T(t)&&E(t.init))},FunctionDeclaration(e){e.id&&T(e)&&r(e.id,e,e)}}}}),j=/^[T$][A-Z][a-z]+\d*$/,M=/^[T$]/,N=/^[T$][A-Z]/,P=/^[T$][A-Z][a-z]/,F={prefix:`prefix`,initial:`initial`,remainder:`remainder`,suggestRename:`suggestRename`},I=s({name:`type-param-names`,meta:{type:`suggestion`,docs:{description:`Enforce giving proper names to type parameters when there are two or more`},hasSuggestions:!0,schema:[],messages:{prefix:`Type parameter {{name}} should have a prefix of "T" or "$"`,initial:`Type parameter {{name}}'s name should start with an uppercase letter`,remainder:`Type parameter {{name}}'s name should contain at least one lowercase letter`,suggestRename:`Rename to {{suggestion}}`}},defaultOptions:[],create(e){return{TSTypeParameterDeclaration(t){let{params:n}=t;if(!(n.length===1&&n.at(0)?.name.name===`T`))for(let t of n){let{name:n}=t.name,r=L(n);if(r){let i=R(n);e.report({node:t,messageId:r,data:{name:n},suggest:[{messageId:`suggestRename`,data:{suggestion:i},fix(e){return e.replaceText(t.name,i)}}]})}}}}}});function L(e){if(!j.test(e)){if(!M.test(e))return F.prefix;if(!N.test(e))return F.initial;if(!P.test(e))return F.remainder}}function R(e){if(!M.test(e))return`T${e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()}`;let t=e.charAt(0),n=e.slice(1);return n.length===0?`${t}Value`:`${t}${n.charAt(0).toUpperCase()+(n.length>1?n.slice(1).toLowerCase():`a`)}`}const z={meta:{name:`@2digits`,version:a},rules:{"if-curly":c,"prefer-inline-array-callbacks":S,"prefer-inline-handlers":A,"type-param-names":I},configs:{recommended:{plugins:{"@2digits":{}},rules:o.rules}}};z.configs.recommended.plugins[`@2digits`]=z;var B=z;export{B as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2digits/eslint-plugin",
3
- "version": "3.5.0",
3
+ "version": "3.5.2",
4
4
  "description": "An eslint plugin that provides a set of rules to enforce best practices for 2digits projects",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,17 +27,17 @@
27
27
  "license": "MIT",
28
28
  "public": true,
29
29
  "dependencies": {
30
- "@typescript-eslint/scope-manager": "8.50.1",
31
- "@typescript-eslint/utils": "8.50.1",
30
+ "@typescript-eslint/scope-manager": "8.51.0",
31
+ "@typescript-eslint/utils": "8.51.0",
32
32
  "eslint": "9.39.2",
33
- "ts-api-utils": "2.2.0"
33
+ "ts-api-utils": "2.3.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@arethetypeswrong/core": "0.18.2",
37
- "@typescript-eslint/parser": "8.50.1",
37
+ "@typescript-eslint/parser": "8.51.0",
38
38
  "eslint-vitest-rule-tester": "3.0.1",
39
39
  "publint": "0.3.16",
40
- "tsdown": "0.18.3",
40
+ "tsdown": "0.18.4",
41
41
  "typescript": "5.9.3",
42
42
  "vitest": "4.0.16",
43
43
  "@2digits/tsconfig": "0.8.6"