@nfq/eslint-config 4.0.0-beta.21 → 4.0.0-beta.22

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.
@@ -17,6 +17,11 @@ const componentSingleHook = createRule$a({
17
17
  },
18
18
  name: 'component-single-hook',
19
19
  create(context) {
20
+ const filename = context.getFilename();
21
+ const filenameLower = filename.toLowerCase();
22
+ if (!filenameLower.endsWith('.tsx') && !filenameLower.endsWith('.jsx')) {
23
+ return {};
24
+ }
20
25
  const {
21
26
  sourceCode
22
27
  } = context;
@@ -1 +1 @@
1
- {"version":3,"file":"component-single-hook.js","sources":["../../../../src/rules/custom/component-single-hook.ts"],"sourcesContent":["import {ESLintUtils} from '@typescript-eslint/utils';\n\nimport {\n getComponentInfos,\n getHookCallFromStatement,\n hasReturnStatement,\n isGuardClause\n} from './utils/component-single-hook-utils';\n\nimport type {TSESLint} from '@typescript-eslint/utils';\n\nconst createRule = ESLintUtils.RuleCreator(\n name => `https://github.com/nfqde/eslint-config-nfq/blob/master/docs/rules/${name}.md`\n);\n\ntype MessageIds = 'invalidStatement' | 'tooManyHooks';\n\nexport const componentSingleHook = createRule<[], MessageIds>({\n defaultOptions: [],\n meta: {\n docs: {description: 'Enforce a single hook call and minimal component bodies.'},\n messages: {\n invalidStatement: 'Only a single hook call, guard clauses, and return statements are allowed.',\n tooManyHooks: 'Only a single hook call is allowed in the component body.'\n },\n schema: [],\n type: 'suggestion'\n },\n name: 'component-single-hook',\n /**\n * Creates the rule listener for validating component bodies that should contain only one hook call.\n * It inspects component bodies, counts hook calls, and reports invalid statements or excessive hooks.\n * It also skips components without return statements and non-block bodies to avoid false positives.\n *\n * @param context The ESLint rule context providing source code and reporting utilities.\n * @returns A rule listener that validates component statement structure.\n *\n * @example\n * ```tsx\n * create(context);\n * ```\n */\n create(context) {\n const {sourceCode} = context;\n const componentInfos = getComponentInfos(sourceCode.ast.body);\n\n if (componentInfos.length === 0) {\n return {};\n }\n\n return {\n /**\n * Iterates over discovered component infos and validates each component body. It skips components without\n * block bodies or without return statements to reduce false positives. It enforces a single hook call\n * while allowing guard clauses and return statements.\n *\n * @example\n * ```tsx\n * Program();\n * ```\n */\n Program() {\n for (const component of componentInfos) {\n const {functionNode} = component;\n\n if (functionNode.body.type !== 'BlockStatement') {\n continue;\n }\n\n const statements = functionNode.body.body;\n const hasReturn = statements.some(hasReturnStatement);\n\n if (!hasReturn) {\n continue;\n }\n\n let hookCount = 0;\n\n for (const statement of statements) {\n if (statement.type === 'ReturnStatement') {\n continue;\n }\n\n if (isGuardClause(statement)) {\n continue;\n }\n\n const hookCall = getHookCallFromStatement(statement);\n\n if (hookCall) {\n hookCount += 1;\n\n if (hookCount > 1) {\n context.report({\n messageId: 'tooManyHooks',\n node: statement\n });\n }\n\n continue;\n }\n\n context.report({\n messageId: 'invalidStatement',\n node: statement\n });\n }\n }\n }\n } as TSESLint.RuleListener;\n }\n});"],"names":["createRule","ESLintUtils","RuleCreator","name","componentSingleHook","defaultOptions","meta","docs","description","messages","invalidStatement","tooManyHooks","schema","type","create","context","sourceCode","componentInfos","getComponentInfos","ast","body","length","Program","component","functionNode","statements","hasReturn","some","hasReturnStatement","hookCount","statement","isGuardClause","hookCall","getHookCallFromStatement","report","messageId","node"],"mappings":";;;AAWA,MAAMA,YAAU,GAAGC,WAAW,CAACC,WAAW,CACtCC,IAAI,IAAI,CAAA,kEAAA,EAAqEA,IAAI,CAAA,GAAA,CACrF,CAAC;AAIM,MAAMC,mBAAmB,GAAGJ,YAAU,CAAiB;AAC1DK,EAAAA,cAAc,EAAE,EAAE;AAClBC,EAAAA,IAAI,EAAE;AACFC,IAAAA,IAAI,EAAE;AAACC,MAAAA,WAAW,EAAE;KAA2D;AAC/EC,IAAAA,QAAQ,EAAE;AACNC,MAAAA,gBAAgB,EAAE,4EAA4E;AAC9FC,MAAAA,YAAY,EAAE;KACjB;AACDC,IAAAA,MAAM,EAAE,EAAE;AACVC,IAAAA,IAAI,EAAE;GACT;AACDV,EAAAA,IAAI,EAAE,uBAAuB;EAc7BW,MAAMA,CAACC,OAAO,EAAE;IACZ,MAAM;AAACC,MAAAA;AAAU,KAAC,GAAGD,OAAO;IAC5B,MAAME,cAAc,GAAGC,iBAAiB,CAACF,UAAU,CAACG,GAAG,CAACC,IAAI,CAAC;AAE7D,IAAA,IAAIH,cAAc,CAACI,MAAM,KAAK,CAAC,EAAE;AAC7B,MAAA,OAAO,EAAE;AACb,IAAA;IAEA,OAAO;AAWHC,MAAAA,OAAOA,GAAG;AACN,QAAA,KAAK,MAAMC,SAAS,IAAIN,cAAc,EAAE;UACpC,MAAM;AAACO,YAAAA;AAAY,WAAC,GAAGD,SAAS;AAEhC,UAAA,IAAIC,YAAY,CAACJ,IAAI,CAACP,IAAI,KAAK,gBAAgB,EAAE;AAC7C,YAAA;AACJ,UAAA;AAEA,UAAA,MAAMY,UAAU,GAAGD,YAAY,CAACJ,IAAI,CAACA,IAAI;AACzC,UAAA,MAAMM,SAAS,GAAGD,UAAU,CAACE,IAAI,CAACC,kBAAkB,CAAC;UAErD,IAAI,CAACF,SAAS,EAAE;AACZ,YAAA;AACJ,UAAA;UAEA,IAAIG,SAAS,GAAG,CAAC;AAEjB,UAAA,KAAK,MAAMC,SAAS,IAAIL,UAAU,EAAE;AAChC,YAAA,IAAIK,SAAS,CAACjB,IAAI,KAAK,iBAAiB,EAAE;AACtC,cAAA;AACJ,YAAA;AAEA,YAAA,IAAIkB,aAAa,CAACD,SAAS,CAAC,EAAE;AAC1B,cAAA;AACJ,YAAA;AAEA,YAAA,MAAME,QAAQ,GAAGC,wBAAwB,CAACH,SAAS,CAAC;AAEpD,YAAA,IAAIE,QAAQ,EAAE;AACVH,cAAAA,SAAS,IAAI,CAAC;cAEd,IAAIA,SAAS,GAAG,CAAC,EAAE;gBACfd,OAAO,CAACmB,MAAM,CAAC;AACXC,kBAAAA,SAAS,EAAE,cAAc;AACzBC,kBAAAA,IAAI,EAAEN;AACV,iBAAC,CAAC;AACN,cAAA;AAEA,cAAA;AACJ,YAAA;YAEAf,OAAO,CAACmB,MAAM,CAAC;AACXC,cAAAA,SAAS,EAAE,kBAAkB;AAC7BC,cAAAA,IAAI,EAAEN;AACV,aAAC,CAAC;AACN,UAAA;AACJ,QAAA;AACJ,MAAA;KACH;AACL,EAAA;AACJ,CAAC;;;;"}
1
+ {"version":3,"file":"component-single-hook.js","sources":["../../../../src/rules/custom/component-single-hook.ts"],"sourcesContent":["import {ESLintUtils} from '@typescript-eslint/utils';\n\nimport {\n getComponentInfos,\n getHookCallFromStatement,\n hasReturnStatement,\n isGuardClause\n} from './utils/component-single-hook-utils';\n\nimport type {TSESLint} from '@typescript-eslint/utils';\n\nconst createRule = ESLintUtils.RuleCreator(\n name => `https://github.com/nfqde/eslint-config-nfq/blob/master/docs/rules/${name}.md`\n);\n\ntype MessageIds = 'invalidStatement' | 'tooManyHooks';\n\nexport const componentSingleHook = createRule<[], MessageIds>({\n defaultOptions: [],\n meta: {\n docs: {description: 'Enforce a single hook call and minimal component bodies.'},\n messages: {\n invalidStatement: 'Only a single hook call, guard clauses, and return statements are allowed.',\n tooManyHooks: 'Only a single hook call is allowed in the component body.'\n },\n schema: [],\n type: 'suggestion'\n },\n name: 'component-single-hook',\n /**\n * Creates the rule listener for validating component bodies that should contain only one hook call.\n * It inspects component bodies, counts hook calls, and reports invalid statements or excessive hooks.\n * It also skips components without return statements and non-block bodies to avoid false positives.\n *\n * @param context The ESLint rule context providing source code and reporting utilities.\n * @returns A rule listener that validates component statement structure.\n *\n * @example\n * ```tsx\n * create(context);\n * ```\n */\n create(context) {\n const filename = context.getFilename();\n const filenameLower = filename.toLowerCase();\n\n if (!filenameLower.endsWith('.tsx') && !filenameLower.endsWith('.jsx')) {\n return {};\n }\n\n const {sourceCode} = context;\n const componentInfos = getComponentInfos(sourceCode.ast.body);\n\n if (componentInfos.length === 0) {\n return {};\n }\n\n return {\n /**\n * Iterates over discovered component infos and validates each component body. It skips components without\n * block bodies or without return statements to reduce false positives. It enforces a single hook call\n * while allowing guard clauses and return statements.\n *\n * @example\n * ```tsx\n * Program();\n * ```\n */\n Program() {\n for (const component of componentInfos) {\n const {functionNode} = component;\n\n if (functionNode.body.type !== 'BlockStatement') {\n continue;\n }\n\n const statements = functionNode.body.body;\n const hasReturn = statements.some(hasReturnStatement);\n\n if (!hasReturn) {\n continue;\n }\n\n let hookCount = 0;\n\n for (const statement of statements) {\n if (statement.type === 'ReturnStatement') {\n continue;\n }\n\n if (isGuardClause(statement)) {\n continue;\n }\n\n const hookCall = getHookCallFromStatement(statement);\n\n if (hookCall) {\n hookCount += 1;\n\n if (hookCount > 1) {\n context.report({\n messageId: 'tooManyHooks',\n node: statement\n });\n }\n\n continue;\n }\n\n context.report({\n messageId: 'invalidStatement',\n node: statement\n });\n }\n }\n }\n } as TSESLint.RuleListener;\n }\n});"],"names":["createRule","ESLintUtils","RuleCreator","name","componentSingleHook","defaultOptions","meta","docs","description","messages","invalidStatement","tooManyHooks","schema","type","create","context","filename","getFilename","filenameLower","toLowerCase","endsWith","sourceCode","componentInfos","getComponentInfos","ast","body","length","Program","component","functionNode","statements","hasReturn","some","hasReturnStatement","hookCount","statement","isGuardClause","hookCall","getHookCallFromStatement","report","messageId","node"],"mappings":";;;AAWA,MAAMA,YAAU,GAAGC,WAAW,CAACC,WAAW,CACtCC,IAAI,IAAI,CAAA,kEAAA,EAAqEA,IAAI,CAAA,GAAA,CACrF,CAAC;AAIM,MAAMC,mBAAmB,GAAGJ,YAAU,CAAiB;AAC1DK,EAAAA,cAAc,EAAE,EAAE;AAClBC,EAAAA,IAAI,EAAE;AACFC,IAAAA,IAAI,EAAE;AAACC,MAAAA,WAAW,EAAE;KAA2D;AAC/EC,IAAAA,QAAQ,EAAE;AACNC,MAAAA,gBAAgB,EAAE,4EAA4E;AAC9FC,MAAAA,YAAY,EAAE;KACjB;AACDC,IAAAA,MAAM,EAAE,EAAE;AACVC,IAAAA,IAAI,EAAE;GACT;AACDV,EAAAA,IAAI,EAAE,uBAAuB;EAc7BW,MAAMA,CAACC,OAAO,EAAE;AACZ,IAAA,MAAMC,QAAQ,GAAGD,OAAO,CAACE,WAAW,EAAE;AACtC,IAAA,MAAMC,aAAa,GAAGF,QAAQ,CAACG,WAAW,EAAE;AAE5C,IAAA,IAAI,CAACD,aAAa,CAACE,QAAQ,CAAC,MAAM,CAAC,IAAI,CAACF,aAAa,CAACE,QAAQ,CAAC,MAAM,CAAC,EAAE;AACpE,MAAA,OAAO,EAAE;AACb,IAAA;IAEA,MAAM;AAACC,MAAAA;AAAU,KAAC,GAAGN,OAAO;IAC5B,MAAMO,cAAc,GAAGC,iBAAiB,CAACF,UAAU,CAACG,GAAG,CAACC,IAAI,CAAC;AAE7D,IAAA,IAAIH,cAAc,CAACI,MAAM,KAAK,CAAC,EAAE;AAC7B,MAAA,OAAO,EAAE;AACb,IAAA;IAEA,OAAO;AAWHC,MAAAA,OAAOA,GAAG;AACN,QAAA,KAAK,MAAMC,SAAS,IAAIN,cAAc,EAAE;UACpC,MAAM;AAACO,YAAAA;AAAY,WAAC,GAAGD,SAAS;AAEhC,UAAA,IAAIC,YAAY,CAACJ,IAAI,CAACZ,IAAI,KAAK,gBAAgB,EAAE;AAC7C,YAAA;AACJ,UAAA;AAEA,UAAA,MAAMiB,UAAU,GAAGD,YAAY,CAACJ,IAAI,CAACA,IAAI;AACzC,UAAA,MAAMM,SAAS,GAAGD,UAAU,CAACE,IAAI,CAACC,kBAAkB,CAAC;UAErD,IAAI,CAACF,SAAS,EAAE;AACZ,YAAA;AACJ,UAAA;UAEA,IAAIG,SAAS,GAAG,CAAC;AAEjB,UAAA,KAAK,MAAMC,SAAS,IAAIL,UAAU,EAAE;AAChC,YAAA,IAAIK,SAAS,CAACtB,IAAI,KAAK,iBAAiB,EAAE;AACtC,cAAA;AACJ,YAAA;AAEA,YAAA,IAAIuB,aAAa,CAACD,SAAS,CAAC,EAAE;AAC1B,cAAA;AACJ,YAAA;AAEA,YAAA,MAAME,QAAQ,GAAGC,wBAAwB,CAACH,SAAS,CAAC;AAEpD,YAAA,IAAIE,QAAQ,EAAE;AACVH,cAAAA,SAAS,IAAI,CAAC;cAEd,IAAIA,SAAS,GAAG,CAAC,EAAE;gBACfnB,OAAO,CAACwB,MAAM,CAAC;AACXC,kBAAAA,SAAS,EAAE,cAAc;AACzBC,kBAAAA,IAAI,EAAEN;AACV,iBAAC,CAAC;AACN,cAAA;AAEA,cAAA;AACJ,YAAA;YAEApB,OAAO,CAACwB,MAAM,CAAC;AACXC,cAAAA,SAAS,EAAE,kBAAkB;AAC7BC,cAAAA,IAAI,EAAEN;AACV,aAAC,CAAC;AACN,UAAA;AACJ,QAAA;AACJ,MAAA;KACH;AACL,EAAA;AACJ,CAAC;;;;"}
package/dist/index.js CHANGED
@@ -2388,6 +2388,11 @@ const componentSingleHook = createRule$a({
2388
2388
  },
2389
2389
  name: 'component-single-hook',
2390
2390
  create(context) {
2391
+ const filename = context.getFilename();
2392
+ const filenameLower = filename.toLowerCase();
2393
+ if (!filenameLower.endsWith('.tsx') && !filenameLower.endsWith('.jsx')) {
2394
+ return {};
2395
+ }
2391
2396
  const {
2392
2397
  sourceCode
2393
2398
  } = context;