@shell-shock/eslint-plugin 0.0.45 → 0.0.46

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/package.cjs CHANGED
@@ -1 +1 @@
1
- var e=`0.0.45`;Object.defineProperty(exports,`version`,{enumerable:!0,get:function(){return e}});
1
+ var e=`0.0.46`;Object.defineProperty(exports,`version`,{enumerable:!0,get:function(){return e}});
package/dist/package.mjs CHANGED
@@ -1,2 +1,2 @@
1
- var e=`0.0.45`;export{e as version};
1
+ var e=`0.0.46`;export{e as version};
2
2
  //# sourceMappingURL=package.mjs.map
@@ -1 +1 @@
1
- Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}}),require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../helpers/create-rule.cjs`);let t=require(`@stryke/path/file-path-fns`),n=require(`@typescript-eslint/utils`);const r=`invalid-handler-params`;function i(e){switch(e.type){case n.AST_NODE_TYPES.Identifier:return e.typeAnnotation?e.typeAnnotation.typeAnnotation:null;case n.AST_NODE_TYPES.AssignmentPattern:{let t=e.left;return t.type===n.AST_NODE_TYPES.Identifier&&t.typeAnnotation?t.typeAnnotation.typeAnnotation:null}case n.AST_NODE_TYPES.RestElement:{let t=e.argument;return t.type===n.AST_NODE_TYPES.Identifier&&t.typeAnnotation?t.typeAnnotation.typeAnnotation:null}case n.AST_NODE_TYPES.ArrayPattern:case n.AST_NODE_TYPES.ObjectPattern:case n.AST_NODE_TYPES.TSParameterProperty:default:return null}}function a(e,t,r){if(t.params.length>0&&t.params[0]){let a=i(t.params[0]);if(a||r.report({node:t.params[0],messageId:`invalidOptionsParam`}),a.type===n.AST_NODE_TYPES.TSTypeLiteral&&a.members.some(e=>e.type===n.AST_NODE_TYPES.TSPropertySignature)||a.type===n.AST_NODE_TYPES.TSIntersectionType&&a.types.some(e=>e.type===n.AST_NODE_TYPES.TSTypeLiteral&&e.members.some(e=>e.type===n.AST_NODE_TYPES.TSPropertySignature)))return;if(a.type===n.AST_NODE_TYPES.TSTypeReference&&a.typeName.type===n.AST_NODE_TYPES.Identifier){let t=a.typeName.name;if(!e.some(e=>e.type===n.AST_NODE_TYPES.TSInterfaceDeclaration&&e.id.name===t||e.type===n.AST_NODE_TYPES.TSTypeAliasDeclaration&&e.id.name===t&&(e.typeAnnotation.type===n.AST_NODE_TYPES.TSTypeLiteral&&e.typeAnnotation.members.some(e=>e.type===n.AST_NODE_TYPES.TSPropertySignature)||e.typeAnnotation.type===n.AST_NODE_TYPES.TSIntersectionType&&e.typeAnnotation.types.some(e=>e.type===n.AST_NODE_TYPES.TSTypeLiteral&&e.members.some(e=>e.type===n.AST_NODE_TYPES.TSPropertySignature)))))return}r.report({node:a,messageId:`invalidOptionsParam`})}}function o(e,t,r){t.params.length>1&&t.params.slice(1).forEach(e=>{let t=i(e);t?.type!==n.AST_NODE_TYPES.TSStringKeyword&&t?.type!==n.AST_NODE_TYPES.TSNumberKeyword&&t?.type!==n.AST_NODE_TYPES.TSBooleanKeyword&&!(t?.type===n.AST_NODE_TYPES.TSArrayType&&(t.elementType.type===n.AST_NODE_TYPES.TSStringKeyword||t.elementType.type===n.AST_NODE_TYPES.TSNumberKeyword))&&r.report({node:t,messageId:`invalidArgsParam`})})}var s=e.createRule({name:r,meta:{type:`problem`,docs:{description:`The command handler function must have a valid parameter types.`},schema:[],messages:{invalidOptionsParam:`The command handler function's first parameter should represent the command's potential options. As a result, it must be an object type with properties.`,invalidArgsParam:`All command handler function parameters except the first should represent the command's positional arguments. As a result, their types must be included in the following list: \\n- string \\n- number \\n- boolean \\n- string[] \\n- number[]`}},defaultOptions:[],create:e=>({Program(n){if((0,t.findFileName)(e.filename??e.getFilename(),{withExtension:!1})===`command`){for(let t of n.body)if(t.type===`ExportDefaultDeclaration`){if(t.declaration?.type===`FunctionDeclaration`)t.declaration.params.length>0&&(a(n.body,t.declaration,e),o(n.body,t.declaration,e));else if(t.declaration?.type===`Identifier`){let r=t.declaration.name,i=n.body.find(e=>e.type===`FunctionDeclaration`&&e.id.name===r||e.type===`VariableDeclaration`&&e.declarations.find(e=>e.id?.type===`Identifier`&&e.id.name===r));if(i?.type===`FunctionDeclaration`)a(n.body,i,e),o(n.body,i,e);else if(i?.type===`VariableDeclaration`){let t=i.declarations.find(e=>e.id?.type===`Identifier`&&e.id.name===r);t?.init?.type===`ArrowFunctionExpression`&&(a(n.body,t.init,e),o(n.body,t.init,e))}}}}}})});exports.RULE_NAME=r,exports.default=s;
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}}),require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../helpers/create-rule.cjs`);let t=require(`@stryke/path/file-path-fns`),n=require(`@typescript-eslint/utils`);const r=`invalid-handler-params`;function i(e){switch(e.type){case n.AST_NODE_TYPES.Identifier:return e.typeAnnotation?e.typeAnnotation.typeAnnotation:null;case n.AST_NODE_TYPES.AssignmentPattern:{let t=e.left;return t.type===n.AST_NODE_TYPES.Identifier&&t.typeAnnotation?t.typeAnnotation.typeAnnotation:null}case n.AST_NODE_TYPES.RestElement:{let t=e.argument;return t.type===n.AST_NODE_TYPES.Identifier&&t.typeAnnotation?t.typeAnnotation.typeAnnotation:null}case n.AST_NODE_TYPES.ArrayPattern:case n.AST_NODE_TYPES.ObjectPattern:case n.AST_NODE_TYPES.TSParameterProperty:default:return null}}function a(e,t,r){if(t.params.length>0&&t.params[0]){let a=i(t.params[0]);if(a||r.report({node:t.params[0],messageId:`invalidOptionsParam`}),a.type===n.AST_NODE_TYPES.TSTypeLiteral&&a.members.some(e=>e.type===n.AST_NODE_TYPES.TSPropertySignature)||a.type===n.AST_NODE_TYPES.TSIntersectionType&&a.types.some(e=>e.type===n.AST_NODE_TYPES.TSTypeLiteral&&e.members.some(e=>e.type===n.AST_NODE_TYPES.TSPropertySignature)))return;if(a.type===n.AST_NODE_TYPES.TSTypeReference&&a.typeName.type===n.AST_NODE_TYPES.Identifier){let t=a.typeName.name;if(!e.some(e=>e.type===n.AST_NODE_TYPES.TSInterfaceDeclaration&&e.id.name===t||e.type===n.AST_NODE_TYPES.TSTypeAliasDeclaration&&e.id.name===t&&(e.typeAnnotation.type===n.AST_NODE_TYPES.TSTypeLiteral&&e.typeAnnotation.members.some(e=>e.type===n.AST_NODE_TYPES.TSPropertySignature)||e.typeAnnotation.type===n.AST_NODE_TYPES.TSIntersectionType&&e.typeAnnotation.types.some(e=>e.type===n.AST_NODE_TYPES.TSTypeLiteral&&e.members.some(e=>e.type===n.AST_NODE_TYPES.TSPropertySignature)))))return}r.report({node:a,messageId:`invalidOptionsParam`})}}function o(e,t,r){t.params.length>1&&t.params.slice(1).forEach(e=>{let t=i(e);t?.type!==n.AST_NODE_TYPES.TSStringKeyword&&t?.type!==n.AST_NODE_TYPES.TSNumberKeyword&&t?.type!==n.AST_NODE_TYPES.TSBooleanKeyword&&t?.type!==n.AST_NODE_TYPES.TSTypeLiteral&&!(t?.type===n.AST_NODE_TYPES.TSArrayType&&(t.elementType.type===n.AST_NODE_TYPES.TSStringKeyword||t.elementType.type===n.AST_NODE_TYPES.TSNumberKeyword||t.elementType.type===n.AST_NODE_TYPES.TSTypeLiteral))&&r.report({node:t,messageId:`invalidArgsParam`})})}var s=e.createRule({name:r,meta:{type:`problem`,docs:{description:`The command handler function must have a valid parameter types.`},schema:[],messages:{invalidOptionsParam:`The command handler function's first parameter should represent the command's potential options. As a result, it must be an object type with properties.`,invalidArgsParam:`All command handler function parameters except the first should represent the command's positional arguments. As a result, their types must be included in the following list: \\n- string \\n- number \\n- boolean \\n- string[] \\n- number[]`}},defaultOptions:[],create:e=>({Program(n){if((0,t.findFileName)(e.filename??e.getFilename(),{withExtension:!1})===`command`){for(let t of n.body)if(t.type===`ExportDefaultDeclaration`){if(t.declaration?.type===`FunctionDeclaration`)t.declaration.params.length>0&&(a(n.body,t.declaration,e),o(n.body,t.declaration,e));else if(t.declaration?.type===`Identifier`){let r=t.declaration.name,i=n.body.find(e=>e.type===`FunctionDeclaration`&&e.id.name===r||e.type===`VariableDeclaration`&&e.declarations.find(e=>e.id?.type===`Identifier`&&e.id.name===r));if(i?.type===`FunctionDeclaration`)a(n.body,i,e),o(n.body,i,e);else if(i?.type===`VariableDeclaration`){let t=i.declarations.find(e=>e.id?.type===`Identifier`&&e.id.name===r);t?.init?.type===`ArrowFunctionExpression`&&(a(n.body,t.init,e),o(n.body,t.init,e))}}}}}})});exports.RULE_NAME=r,exports.default=s;
@@ -1,2 +1,2 @@
1
- import{createRule as e}from"../helpers/create-rule.mjs";import{findFileName as t}from"@stryke/path/file-path-fns";import{AST_NODE_TYPES as n}from"@typescript-eslint/utils";const r=`invalid-handler-params`;function i(e){switch(e.type){case n.Identifier:return e.typeAnnotation?e.typeAnnotation.typeAnnotation:null;case n.AssignmentPattern:{let t=e.left;return t.type===n.Identifier&&t.typeAnnotation?t.typeAnnotation.typeAnnotation:null}case n.RestElement:{let t=e.argument;return t.type===n.Identifier&&t.typeAnnotation?t.typeAnnotation.typeAnnotation:null}case n.ArrayPattern:case n.ObjectPattern:case n.TSParameterProperty:default:return null}}function a(e,t,r){if(t.params.length>0&&t.params[0]){let a=i(t.params[0]);if(a||r.report({node:t.params[0],messageId:`invalidOptionsParam`}),a.type===n.TSTypeLiteral&&a.members.some(e=>e.type===n.TSPropertySignature)||a.type===n.TSIntersectionType&&a.types.some(e=>e.type===n.TSTypeLiteral&&e.members.some(e=>e.type===n.TSPropertySignature)))return;if(a.type===n.TSTypeReference&&a.typeName.type===n.Identifier){let t=a.typeName.name;if(!e.some(e=>e.type===n.TSInterfaceDeclaration&&e.id.name===t||e.type===n.TSTypeAliasDeclaration&&e.id.name===t&&(e.typeAnnotation.type===n.TSTypeLiteral&&e.typeAnnotation.members.some(e=>e.type===n.TSPropertySignature)||e.typeAnnotation.type===n.TSIntersectionType&&e.typeAnnotation.types.some(e=>e.type===n.TSTypeLiteral&&e.members.some(e=>e.type===n.TSPropertySignature)))))return}r.report({node:a,messageId:`invalidOptionsParam`})}}function o(e,t,r){t.params.length>1&&t.params.slice(1).forEach(e=>{let t=i(e);t?.type!==n.TSStringKeyword&&t?.type!==n.TSNumberKeyword&&t?.type!==n.TSBooleanKeyword&&!(t?.type===n.TSArrayType&&(t.elementType.type===n.TSStringKeyword||t.elementType.type===n.TSNumberKeyword))&&r.report({node:t,messageId:`invalidArgsParam`})})}var s=e({name:r,meta:{type:`problem`,docs:{description:`The command handler function must have a valid parameter types.`},schema:[],messages:{invalidOptionsParam:`The command handler function's first parameter should represent the command's potential options. As a result, it must be an object type with properties.`,invalidArgsParam:`All command handler function parameters except the first should represent the command's positional arguments. As a result, their types must be included in the following list: \\n- string \\n- number \\n- boolean \\n- string[] \\n- number[]`}},defaultOptions:[],create:e=>({Program(n){if(t(e.filename??e.getFilename(),{withExtension:!1})===`command`){for(let t of n.body)if(t.type===`ExportDefaultDeclaration`){if(t.declaration?.type===`FunctionDeclaration`)t.declaration.params.length>0&&(a(n.body,t.declaration,e),o(n.body,t.declaration,e));else if(t.declaration?.type===`Identifier`){let r=t.declaration.name,i=n.body.find(e=>e.type===`FunctionDeclaration`&&e.id.name===r||e.type===`VariableDeclaration`&&e.declarations.find(e=>e.id?.type===`Identifier`&&e.id.name===r));if(i?.type===`FunctionDeclaration`)a(n.body,i,e),o(n.body,i,e);else if(i?.type===`VariableDeclaration`){let t=i.declarations.find(e=>e.id?.type===`Identifier`&&e.id.name===r);t?.init?.type===`ArrowFunctionExpression`&&(a(n.body,t.init,e),o(n.body,t.init,e))}}}}}})});export{r as RULE_NAME,s as default};
1
+ import{createRule as e}from"../helpers/create-rule.mjs";import{findFileName as t}from"@stryke/path/file-path-fns";import{AST_NODE_TYPES as n}from"@typescript-eslint/utils";const r=`invalid-handler-params`;function i(e){switch(e.type){case n.Identifier:return e.typeAnnotation?e.typeAnnotation.typeAnnotation:null;case n.AssignmentPattern:{let t=e.left;return t.type===n.Identifier&&t.typeAnnotation?t.typeAnnotation.typeAnnotation:null}case n.RestElement:{let t=e.argument;return t.type===n.Identifier&&t.typeAnnotation?t.typeAnnotation.typeAnnotation:null}case n.ArrayPattern:case n.ObjectPattern:case n.TSParameterProperty:default:return null}}function a(e,t,r){if(t.params.length>0&&t.params[0]){let a=i(t.params[0]);if(a||r.report({node:t.params[0],messageId:`invalidOptionsParam`}),a.type===n.TSTypeLiteral&&a.members.some(e=>e.type===n.TSPropertySignature)||a.type===n.TSIntersectionType&&a.types.some(e=>e.type===n.TSTypeLiteral&&e.members.some(e=>e.type===n.TSPropertySignature)))return;if(a.type===n.TSTypeReference&&a.typeName.type===n.Identifier){let t=a.typeName.name;if(!e.some(e=>e.type===n.TSInterfaceDeclaration&&e.id.name===t||e.type===n.TSTypeAliasDeclaration&&e.id.name===t&&(e.typeAnnotation.type===n.TSTypeLiteral&&e.typeAnnotation.members.some(e=>e.type===n.TSPropertySignature)||e.typeAnnotation.type===n.TSIntersectionType&&e.typeAnnotation.types.some(e=>e.type===n.TSTypeLiteral&&e.members.some(e=>e.type===n.TSPropertySignature)))))return}r.report({node:a,messageId:`invalidOptionsParam`})}}function o(e,t,r){t.params.length>1&&t.params.slice(1).forEach(e=>{let t=i(e);t?.type!==n.TSStringKeyword&&t?.type!==n.TSNumberKeyword&&t?.type!==n.TSBooleanKeyword&&t?.type!==n.TSTypeLiteral&&!(t?.type===n.TSArrayType&&(t.elementType.type===n.TSStringKeyword||t.elementType.type===n.TSNumberKeyword||t.elementType.type===n.TSTypeLiteral))&&r.report({node:t,messageId:`invalidArgsParam`})})}var s=e({name:r,meta:{type:`problem`,docs:{description:`The command handler function must have a valid parameter types.`},schema:[],messages:{invalidOptionsParam:`The command handler function's first parameter should represent the command's potential options. As a result, it must be an object type with properties.`,invalidArgsParam:`All command handler function parameters except the first should represent the command's positional arguments. As a result, their types must be included in the following list: \\n- string \\n- number \\n- boolean \\n- string[] \\n- number[]`}},defaultOptions:[],create:e=>({Program(n){if(t(e.filename??e.getFilename(),{withExtension:!1})===`command`){for(let t of n.body)if(t.type===`ExportDefaultDeclaration`){if(t.declaration?.type===`FunctionDeclaration`)t.declaration.params.length>0&&(a(n.body,t.declaration,e),o(n.body,t.declaration,e));else if(t.declaration?.type===`Identifier`){let r=t.declaration.name,i=n.body.find(e=>e.type===`FunctionDeclaration`&&e.id.name===r||e.type===`VariableDeclaration`&&e.declarations.find(e=>e.id?.type===`Identifier`&&e.id.name===r));if(i?.type===`FunctionDeclaration`)a(n.body,i,e),o(n.body,i,e);else if(i?.type===`VariableDeclaration`){let t=i.declarations.find(e=>e.id?.type===`Identifier`&&e.id.name===r);t?.init?.type===`ArrowFunctionExpression`&&(a(n.body,t.init,e),o(n.body,t.init,e))}}}}}})});export{r as RULE_NAME,s as default};
2
2
  //# sourceMappingURL=invalid-handler-params.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"invalid-handler-params.mjs","names":[],"sources":["../../src/rules/invalid-handler-params.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Shell Shock\n\n This code was released as part of the Shell Shock project. Shell Shock\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/shell-shock.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/shell-shock\n Documentation: https://docs.stormsoftware.com/projects/shell-shock\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { findFileName } from \"@stryke/path/file-path-fns\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport { AST_NODE_TYPES } from \"@typescript-eslint/utils\";\nimport type { RuleContext } from \"@typescript-eslint/utils/ts-eslint\";\nimport { createRule } from \"../helpers/create-rule\";\n\nexport const RULE_NAME = \"invalid-handler-params\";\nexport type MessageIds = \"invalidOptionsParam\" | \"invalidArgsParam\";\nexport type Options = [];\n\nfunction getTypeNode(param: TSESTree.Parameter): TSESTree.TypeNode | null {\n switch (param.type) {\n case AST_NODE_TYPES.Identifier:\n return param.typeAnnotation ? param.typeAnnotation.typeAnnotation : null;\n\n case AST_NODE_TYPES.AssignmentPattern: {\n const left = param.left;\n if (left.type === AST_NODE_TYPES.Identifier && left.typeAnnotation) {\n return left.typeAnnotation.typeAnnotation;\n }\n return null;\n }\n\n case AST_NODE_TYPES.RestElement: {\n const arg = param.argument;\n if (arg.type === AST_NODE_TYPES.Identifier && arg.typeAnnotation) {\n return arg.typeAnnotation.typeAnnotation;\n }\n return null;\n }\n\n case AST_NODE_TYPES.ArrayPattern:\n case AST_NODE_TYPES.ObjectPattern:\n case AST_NODE_TYPES.TSParameterProperty:\n default:\n return null;\n }\n}\n\n/**\n * Checks the validity of the command handler function's options parameters.\n *\n * @remarks\n * The first parameter should represent the command's potential options, and as a result, it must be an object type with properties.\n *\n * @param body - The body of the program, used to check for type/interface declarations when validating the options parameter.\n * @param node - The function node representing the command handler, used to access its parameters and validate their types.\n * @param context - The ESLint rule context, used to report any validation errors found in the parameters.\n */\nfunction checkOptionsParam(\n body: TSESTree.ProgramStatement[],\n node: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression,\n context: Readonly<RuleContext<\"invalidOptionsParam\", []>>\n) {\n if (node.params.length > 0 && node.params[0]) {\n const type = getTypeNode(node.params[0]);\n if (!type) {\n context.report({\n node: node.params[0],\n messageId: \"invalidOptionsParam\"\n });\n }\n\n if (\n type!.type === AST_NODE_TYPES.TSTypeLiteral &&\n type.members.some(\n member => member.type === AST_NODE_TYPES.TSPropertySignature\n )\n ) {\n return;\n } else if (\n type!.type === AST_NODE_TYPES.TSIntersectionType &&\n type.types.some(\n type =>\n type.type === AST_NODE_TYPES.TSTypeLiteral &&\n type.members.some(\n member => member.type === AST_NODE_TYPES.TSPropertySignature\n )\n )\n ) {\n return;\n } else if (\n type!.type === AST_NODE_TYPES.TSTypeReference &&\n type.typeName.type === AST_NODE_TYPES.Identifier\n ) {\n const typeName = type.typeName.name;\n if (\n !body.some(\n localBlock =>\n (localBlock.type === AST_NODE_TYPES.TSInterfaceDeclaration &&\n localBlock.id.name === typeName) ||\n (localBlock.type === AST_NODE_TYPES.TSTypeAliasDeclaration &&\n localBlock.id.name === typeName &&\n ((localBlock.typeAnnotation.type ===\n AST_NODE_TYPES.TSTypeLiteral &&\n localBlock.typeAnnotation.members.some(\n member => member.type === AST_NODE_TYPES.TSPropertySignature\n )) ||\n (localBlock.typeAnnotation.type ===\n AST_NODE_TYPES.TSIntersectionType &&\n localBlock.typeAnnotation.types.some(\n type =>\n type.type === AST_NODE_TYPES.TSTypeLiteral &&\n type.members.some(\n member =>\n member.type === AST_NODE_TYPES.TSPropertySignature\n )\n ))))\n )\n ) {\n return;\n }\n }\n\n context.report({\n node: type!,\n messageId: \"invalidOptionsParam\"\n });\n }\n}\n\n/**\n * Checks the validity of the command handler function's positional argument parameters.\n *\n * @remarks\n * All parameters except the first should represent the command's positional arguments, and as a result, their types must be included in the following list:\n * - string\n * - number\n * - boolean\n * - string[]\n * - number[]\n *\n * @param body - The body of the program, used to check for type/interface declarations when validating the args parameters.\n * @param node - The function node representing the command handler, used to access its parameters and validate their types.\n * @param context - The ESLint rule context, used to report any validation errors found in the parameters.\n */\nfunction checkArgsParam(\n body: TSESTree.ProgramStatement[],\n node: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression,\n context: Readonly<RuleContext<\"invalidArgsParam\", []>>\n) {\n if (node.params.length > 1) {\n node.params.slice(1).forEach(param => {\n const type = getTypeNode(param);\n if (\n type?.type !== AST_NODE_TYPES.TSStringKeyword &&\n type?.type !== AST_NODE_TYPES.TSNumberKeyword &&\n type?.type !== AST_NODE_TYPES.TSBooleanKeyword &&\n !(\n type?.type === AST_NODE_TYPES.TSArrayType &&\n (type.elementType.type === AST_NODE_TYPES.TSStringKeyword ||\n type.elementType.type === AST_NODE_TYPES.TSNumberKeyword)\n )\n ) {\n context.report({\n node: type!,\n messageId: \"invalidArgsParam\"\n });\n }\n });\n }\n}\n\nexport default createRule<Options, MessageIds>({\n name: RULE_NAME,\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"The command handler function must have a valid parameter types.\"\n },\n schema: [],\n messages: {\n invalidOptionsParam:\n \"The command handler function's first parameter should represent the command's potential options. As a result, it must be an object type with properties.\",\n invalidArgsParam:\n \"All command handler function parameters except the first should represent the command's positional arguments. As a result, their types must be included in the following list: \\\\n- string \\\\n- number \\\\n- boolean \\\\n- string[] \\\\n- number[]\"\n }\n },\n defaultOptions: [],\n create: context => {\n return {\n Program(node) {\n const fileName = context.filename ?? context.getFilename();\n if (\n findFileName(fileName, {\n withExtension: false\n }) !== \"command\"\n ) {\n return;\n }\n\n for (const block of node.body) {\n if (block.type === \"ExportDefaultDeclaration\") {\n // export default async function handler() {...}\n if (block.declaration?.type === \"FunctionDeclaration\") {\n if (block.declaration.params.length > 0) {\n checkOptionsParam(node.body, block.declaration, context);\n checkArgsParam(node.body, block.declaration, context);\n }\n } else if (block.declaration?.type === \"Identifier\") {\n // async function handler() {...}; export default handler;\n const targetName = block.declaration.name;\n const functionDeclaration = node.body.find(\n localBlock =>\n (localBlock.type === \"FunctionDeclaration\" &&\n localBlock.id.name === targetName) ||\n (localBlock.type === \"VariableDeclaration\" &&\n localBlock.declarations.find(\n declaration =>\n declaration.id?.type === \"Identifier\" &&\n declaration.id.name === targetName\n ))\n );\n if (functionDeclaration?.type === \"FunctionDeclaration\") {\n checkOptionsParam(node.body, functionDeclaration, context);\n checkArgsParam(node.body, functionDeclaration, context);\n } else if (functionDeclaration?.type === \"VariableDeclaration\") {\n const varDeclarator = functionDeclaration.declarations.find(\n declaration =>\n declaration.id?.type === \"Identifier\" &&\n declaration.id.name === targetName\n );\n if (varDeclarator?.init?.type === \"ArrowFunctionExpression\") {\n checkOptionsParam(node.body, varDeclarator.init, context);\n checkArgsParam(node.body, varDeclarator.init, context);\n }\n }\n }\n }\n }\n }\n };\n }\n});\n"],"mappings":"4KAwBA,MAAa,EAAY,yBAIzB,SAAS,EAAY,EAAqD,CACxE,OAAQ,EAAM,KAAd,CACE,KAAK,EAAe,WAClB,OAAO,EAAM,eAAiB,EAAM,eAAe,eAAiB,KAEtE,KAAK,EAAe,kBAAmB,CACrC,IAAM,EAAO,EAAM,KAInB,OAHI,EAAK,OAAS,EAAe,YAAc,EAAK,eAC3C,EAAK,eAAe,eAEtB,KAGT,KAAK,EAAe,YAAa,CAC/B,IAAM,EAAM,EAAM,SAIlB,OAHI,EAAI,OAAS,EAAe,YAAc,EAAI,eACzC,EAAI,eAAe,eAErB,KAGT,KAAK,EAAe,aACpB,KAAK,EAAe,cACpB,KAAK,EAAe,oBACpB,QACE,OAAO,MAcb,SAAS,EACP,EACA,EACA,EACA,CACA,GAAI,EAAK,OAAO,OAAS,GAAK,EAAK,OAAO,GAAI,CAC5C,IAAM,EAAO,EAAY,EAAK,OAAO,GAAG,IACnC,GACH,EAAQ,OAAO,CACb,KAAM,EAAK,OAAO,GAClB,UAAW,sBACZ,CAAC,CAIF,EAAM,OAAS,EAAe,eAC9B,EAAK,QAAQ,KACX,GAAU,EAAO,OAAS,EAAe,oBAC1C,EAID,EAAM,OAAS,EAAe,oBAC9B,EAAK,MAAM,KACT,GACE,EAAK,OAAS,EAAe,eAC7B,EAAK,QAAQ,KACX,GAAU,EAAO,OAAS,EAAe,oBAC1C,CACJ,CAED,UAEA,EAAM,OAAS,EAAe,iBAC9B,EAAK,SAAS,OAAS,EAAe,WACtC,CACA,IAAM,EAAW,EAAK,SAAS,KAC/B,GACE,CAAC,EAAK,KACJ,GACG,EAAW,OAAS,EAAe,wBAClC,EAAW,GAAG,OAAS,GACxB,EAAW,OAAS,EAAe,wBAClC,EAAW,GAAG,OAAS,IACrB,EAAW,eAAe,OAC1B,EAAe,eACf,EAAW,eAAe,QAAQ,KAChC,GAAU,EAAO,OAAS,EAAe,oBAC1C,EACA,EAAW,eAAe,OACzB,EAAe,oBACf,EAAW,eAAe,MAAM,KAC9B,GACE,EAAK,OAAS,EAAe,eAC7B,EAAK,QAAQ,KACX,GACE,EAAO,OAAS,EAAe,oBAClC,CACJ,EACV,CAED,OAIJ,EAAQ,OAAO,CACb,KAAM,EACN,UAAW,sBACZ,CAAC,EAmBN,SAAS,EACP,EACA,EACA,EACA,CACI,EAAK,OAAO,OAAS,GACvB,EAAK,OAAO,MAAM,EAAE,CAAC,QAAQ,GAAS,CACpC,IAAM,EAAO,EAAY,EAAM,CAE7B,GAAM,OAAS,EAAe,iBAC9B,GAAM,OAAS,EAAe,iBAC9B,GAAM,OAAS,EAAe,kBAC9B,EACE,GAAM,OAAS,EAAe,cAC7B,EAAK,YAAY,OAAS,EAAe,iBACxC,EAAK,YAAY,OAAS,EAAe,mBAG7C,EAAQ,OAAO,CACb,KAAM,EACN,UAAW,mBACZ,CAAC,EAEJ,CAIN,IAAA,EAAe,EAAgC,CAC7C,KAAM,EACN,KAAM,CACJ,KAAM,UACN,KAAM,CACJ,YACE,kEACH,CACD,OAAQ,EAAE,CACV,SAAU,CACR,oBACE,2JACF,iBACE,kPACH,CACF,CACD,eAAgB,EAAE,CAClB,OAAQ,IACC,CACL,QAAQ,EAAM,CAGV,KAFe,EAAQ,UAAY,EAAQ,aAAa,CAEjC,CACrB,cAAe,GAChB,CAAC,GAAK,UAKT,KAAK,IAAM,KAAS,EAAK,KACvB,GAAI,EAAM,OAAS,+BAEb,EAAM,aAAa,OAAS,sBAC1B,EAAM,YAAY,OAAO,OAAS,IACpC,EAAkB,EAAK,KAAM,EAAM,YAAa,EAAQ,CACxD,EAAe,EAAK,KAAM,EAAM,YAAa,EAAQ,UAE9C,EAAM,aAAa,OAAS,aAAc,CAEnD,IAAM,EAAa,EAAM,YAAY,KAC/B,EAAsB,EAAK,KAAK,KACpC,GACG,EAAW,OAAS,uBACnB,EAAW,GAAG,OAAS,GACxB,EAAW,OAAS,uBACnB,EAAW,aAAa,KACtB,GACE,EAAY,IAAI,OAAS,cACzB,EAAY,GAAG,OAAS,EAC3B,CACN,CACD,GAAI,GAAqB,OAAS,sBAChC,EAAkB,EAAK,KAAM,EAAqB,EAAQ,CAC1D,EAAe,EAAK,KAAM,EAAqB,EAAQ,SAC9C,GAAqB,OAAS,sBAAuB,CAC9D,IAAM,EAAgB,EAAoB,aAAa,KACrD,GACE,EAAY,IAAI,OAAS,cACzB,EAAY,GAAG,OAAS,EAC3B,CACG,GAAe,MAAM,OAAS,4BAChC,EAAkB,EAAK,KAAM,EAAc,KAAM,EAAQ,CACzD,EAAe,EAAK,KAAM,EAAc,KAAM,EAAQ,OAOnE,EAEJ,CAAC"}
1
+ {"version":3,"file":"invalid-handler-params.mjs","names":[],"sources":["../../src/rules/invalid-handler-params.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Shell Shock\n\n This code was released as part of the Shell Shock project. Shell Shock\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/shell-shock.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/shell-shock\n Documentation: https://docs.stormsoftware.com/projects/shell-shock\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { findFileName } from \"@stryke/path/file-path-fns\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport { AST_NODE_TYPES } from \"@typescript-eslint/utils\";\nimport type { RuleContext } from \"@typescript-eslint/utils/ts-eslint\";\nimport { createRule } from \"../helpers/create-rule\";\n\nexport const RULE_NAME = \"invalid-handler-params\";\nexport type MessageIds = \"invalidOptionsParam\" | \"invalidArgsParam\";\nexport type Options = [];\n\nfunction getTypeNode(param: TSESTree.Parameter): TSESTree.TypeNode | null {\n switch (param.type) {\n case AST_NODE_TYPES.Identifier:\n return param.typeAnnotation ? param.typeAnnotation.typeAnnotation : null;\n\n case AST_NODE_TYPES.AssignmentPattern: {\n const left = param.left;\n if (left.type === AST_NODE_TYPES.Identifier && left.typeAnnotation) {\n return left.typeAnnotation.typeAnnotation;\n }\n return null;\n }\n\n case AST_NODE_TYPES.RestElement: {\n const arg = param.argument;\n if (arg.type === AST_NODE_TYPES.Identifier && arg.typeAnnotation) {\n return arg.typeAnnotation.typeAnnotation;\n }\n return null;\n }\n\n case AST_NODE_TYPES.ArrayPattern:\n case AST_NODE_TYPES.ObjectPattern:\n case AST_NODE_TYPES.TSParameterProperty:\n default:\n return null;\n }\n}\n\n/**\n * Checks the validity of the command handler function's options parameters.\n *\n * @remarks\n * The first parameter should represent the command's potential options, and as a result, it must be an object type with properties.\n *\n * @param body - The body of the program, used to check for type/interface declarations when validating the options parameter.\n * @param node - The function node representing the command handler, used to access its parameters and validate their types.\n * @param context - The ESLint rule context, used to report any validation errors found in the parameters.\n */\nfunction checkOptionsParam(\n body: TSESTree.ProgramStatement[],\n node: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression,\n context: Readonly<RuleContext<\"invalidOptionsParam\", []>>\n) {\n if (node.params.length > 0 && node.params[0]) {\n const type = getTypeNode(node.params[0]);\n if (!type) {\n context.report({\n node: node.params[0],\n messageId: \"invalidOptionsParam\"\n });\n }\n\n if (\n type!.type === AST_NODE_TYPES.TSTypeLiteral &&\n type.members.some(\n member => member.type === AST_NODE_TYPES.TSPropertySignature\n )\n ) {\n return;\n } else if (\n type!.type === AST_NODE_TYPES.TSIntersectionType &&\n type.types.some(\n type =>\n type.type === AST_NODE_TYPES.TSTypeLiteral &&\n type.members.some(\n member => member.type === AST_NODE_TYPES.TSPropertySignature\n )\n )\n ) {\n return;\n } else if (\n type!.type === AST_NODE_TYPES.TSTypeReference &&\n type.typeName.type === AST_NODE_TYPES.Identifier\n ) {\n const typeName = type.typeName.name;\n if (\n !body.some(\n localBlock =>\n (localBlock.type === AST_NODE_TYPES.TSInterfaceDeclaration &&\n localBlock.id.name === typeName) ||\n (localBlock.type === AST_NODE_TYPES.TSTypeAliasDeclaration &&\n localBlock.id.name === typeName &&\n ((localBlock.typeAnnotation.type ===\n AST_NODE_TYPES.TSTypeLiteral &&\n localBlock.typeAnnotation.members.some(\n member => member.type === AST_NODE_TYPES.TSPropertySignature\n )) ||\n (localBlock.typeAnnotation.type ===\n AST_NODE_TYPES.TSIntersectionType &&\n localBlock.typeAnnotation.types.some(\n type =>\n type.type === AST_NODE_TYPES.TSTypeLiteral &&\n type.members.some(\n member =>\n member.type === AST_NODE_TYPES.TSPropertySignature\n )\n ))))\n )\n ) {\n return;\n }\n }\n\n context.report({\n node: type!,\n messageId: \"invalidOptionsParam\"\n });\n }\n}\n\n/**\n * Checks the validity of the command handler function's positional argument parameters.\n *\n * @remarks\n * All parameters except the first should represent the command's positional arguments, and as a result, their types must be included in the following list:\n * - string\n * - number\n * - boolean\n * - string[]\n * - number[]\n *\n * @param body - The body of the program, used to check for type/interface declarations when validating the args parameters.\n * @param node - The function node representing the command handler, used to access its parameters and validate their types.\n * @param context - The ESLint rule context, used to report any validation errors found in the parameters.\n */\nfunction checkArgsParam(\n body: TSESTree.ProgramStatement[],\n node: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression,\n context: Readonly<RuleContext<\"invalidArgsParam\", []>>\n) {\n if (node.params.length > 1) {\n node.params.slice(1).forEach(param => {\n const type = getTypeNode(param);\n if (\n type?.type !== AST_NODE_TYPES.TSStringKeyword &&\n type?.type !== AST_NODE_TYPES.TSNumberKeyword &&\n type?.type !== AST_NODE_TYPES.TSBooleanKeyword &&\n type?.type !== AST_NODE_TYPES.TSTypeLiteral &&\n !(\n type?.type === AST_NODE_TYPES.TSArrayType &&\n (type.elementType.type === AST_NODE_TYPES.TSStringKeyword ||\n type.elementType.type === AST_NODE_TYPES.TSNumberKeyword ||\n type.elementType.type === AST_NODE_TYPES.TSTypeLiteral)\n )\n ) {\n context.report({\n node: type!,\n messageId: \"invalidArgsParam\"\n });\n }\n });\n }\n}\n\nexport default createRule<Options, MessageIds>({\n name: RULE_NAME,\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"The command handler function must have a valid parameter types.\"\n },\n schema: [],\n messages: {\n invalidOptionsParam:\n \"The command handler function's first parameter should represent the command's potential options. As a result, it must be an object type with properties.\",\n invalidArgsParam:\n \"All command handler function parameters except the first should represent the command's positional arguments. As a result, their types must be included in the following list: \\\\n- string \\\\n- number \\\\n- boolean \\\\n- string[] \\\\n- number[]\"\n }\n },\n defaultOptions: [],\n create: context => {\n return {\n Program(node) {\n const fileName = context.filename ?? context.getFilename();\n if (\n findFileName(fileName, {\n withExtension: false\n }) !== \"command\"\n ) {\n return;\n }\n\n for (const block of node.body) {\n if (block.type === \"ExportDefaultDeclaration\") {\n // export default async function handler() {...}\n if (block.declaration?.type === \"FunctionDeclaration\") {\n if (block.declaration.params.length > 0) {\n checkOptionsParam(node.body, block.declaration, context);\n checkArgsParam(node.body, block.declaration, context);\n }\n } else if (block.declaration?.type === \"Identifier\") {\n // async function handler() {...}; export default handler;\n const targetName = block.declaration.name;\n const functionDeclaration = node.body.find(\n localBlock =>\n (localBlock.type === \"FunctionDeclaration\" &&\n localBlock.id.name === targetName) ||\n (localBlock.type === \"VariableDeclaration\" &&\n localBlock.declarations.find(\n declaration =>\n declaration.id?.type === \"Identifier\" &&\n declaration.id.name === targetName\n ))\n );\n if (functionDeclaration?.type === \"FunctionDeclaration\") {\n checkOptionsParam(node.body, functionDeclaration, context);\n checkArgsParam(node.body, functionDeclaration, context);\n } else if (functionDeclaration?.type === \"VariableDeclaration\") {\n const varDeclarator = functionDeclaration.declarations.find(\n declaration =>\n declaration.id?.type === \"Identifier\" &&\n declaration.id.name === targetName\n );\n if (varDeclarator?.init?.type === \"ArrowFunctionExpression\") {\n checkOptionsParam(node.body, varDeclarator.init, context);\n checkArgsParam(node.body, varDeclarator.init, context);\n }\n }\n }\n }\n }\n }\n };\n }\n});\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shell-shock/eslint-plugin",
3
- "version": "0.0.45",
3
+ "version": "0.0.46",
4
4
  "private": false,
5
5
  "description": "An ESLint Plugin with linting rules that ensure a Shell Shock project is following the best practices.",
6
6
  "keywords": ["eslint", "eslint-plugin", "shell-shock", "storm-software"],
@@ -165,12 +165,12 @@
165
165
  "@typescript-eslint/utils": "^8.57.1",
166
166
  "defu": "^6.1.4",
167
167
  "@storm-software/testing-tools": "^1.119.121",
168
- "powerlines": "^0.42.10"
168
+ "powerlines": "^0.42.11"
169
169
  },
170
170
  "devDependencies": {
171
171
  "@eslint/compat": "^2.0.3",
172
172
  "@eslint/config-inspector": "^1.5.0",
173
- "@powerlines/plugin-tsdown": "^0.1.317",
173
+ "@powerlines/plugin-tsdown": "^0.1.318",
174
174
  "@storm-software/testing-tools": "^1.119.121",
175
175
  "@types/eslint": "^9.6.1",
176
176
  "@types/eslint__js": "^9.14.0",
@@ -182,7 +182,7 @@
182
182
  "eslint-plugin-i18n-text": "^1.0.1",
183
183
  "eslint-rule-documentation": "^1.0.23",
184
184
  "eslint-typegen": "^2.3.1",
185
- "powerlines": "^0.42.10"
185
+ "powerlines": "^0.42.11"
186
186
  },
187
187
  "peerDependencies": { "eslint": ">=9.39.3" },
188
188
  "peerDependenciesMeta": { "eslint": { "optional": false } },
@@ -217,5 +217,5 @@
217
217
  "./package.json": "./package.json"
218
218
  }
219
219
  },
220
- "gitHead": "c955b6fabcce1fef3179f9f169867eaa8eafc38d"
220
+ "gitHead": "ce5a0050c63b47111d5b663c65141fe3eb56dba2"
221
221
  }