@venizia/dev-configs 0.4.7 → 0.4.8-1

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.
Files changed (199) hide show
  1. package/README.md +3 -3
  2. package/dist/checks/catalog.d.ts +15 -2
  3. package/dist/checks/catalog.js +1 -0
  4. package/dist/checks/catalog.js.map +1 -1
  5. package/dist/checks/module-cycles.d.ts +2 -0
  6. package/dist/checks/module-cycles.js +2 -0
  7. package/dist/checks/module-cycles.js.map +1 -1
  8. package/dist/checks/purity/manifest.d.ts +6 -1
  9. package/dist/checks/purity/manifest.js.map +1 -1
  10. package/dist/checks/purity/probe.d.ts +4 -1
  11. package/dist/checks/purity/probe.js +1 -0
  12. package/dist/checks/purity/probe.js.map +1 -1
  13. package/dist/checks/purity/run.d.ts +3 -0
  14. package/dist/checks/purity/run.js +1 -0
  15. package/dist/checks/purity/run.js.map +1 -1
  16. package/dist/checks/split-report.d.ts +1 -0
  17. package/dist/checks/split-report.js +1 -0
  18. package/dist/checks/split-report.js.map +1 -1
  19. package/dist/checks/test-controls.d.ts +11 -2
  20. package/dist/checks/test-controls.js +1 -0
  21. package/dist/checks/test-controls.js.map +1 -1
  22. package/dist/checks/test-dead-code.d.ts +1 -0
  23. package/dist/checks/test-dead-code.js +1 -0
  24. package/dist/checks/test-dead-code.js.map +1 -1
  25. package/dist/checks/test-mutate.d.ts +14 -2
  26. package/dist/checks/test-mutate.js +1 -0
  27. package/dist/checks/test-mutate.js.map +1 -1
  28. package/dist/checks/test-weight.d.ts +3 -0
  29. package/dist/checks/test-weight.js +1 -0
  30. package/dist/checks/test-weight.js.map +1 -1
  31. package/dist/cli/check.js.map +1 -1
  32. package/dist/cli/clean.js.map +1 -1
  33. package/dist/cli/codemod/async-style.d.ts +1 -1
  34. package/dist/cli/codemod/async-style.js +3 -3
  35. package/dist/cli/codemod/async-style.js.map +1 -1
  36. package/dist/cli/codemod/connector-imports.js.map +1 -1
  37. package/dist/cli/codemod/const-classes.js.map +1 -1
  38. package/dist/cli/codemod/drop-redundant-casts.js.map +1 -1
  39. package/dist/cli/codemod/files.js.map +1 -1
  40. package/dist/cli/codemod/index.js.map +1 -1
  41. package/dist/cli/codemod/namespace-functions/index.js.map +1 -1
  42. package/dist/cli/codemod/namespace-functions/logger-scope.js.map +1 -1
  43. package/dist/cli/codemod/namespace-functions/mapping.js.map +1 -1
  44. package/dist/cli/codemod/namespace-functions/rewriter.js.map +1 -1
  45. package/dist/cli/index.js.map +1 -1
  46. package/dist/cli/lint.js.map +1 -1
  47. package/dist/linters/eslint.js +7 -5
  48. package/dist/linters/eslint.js.map +1 -1
  49. package/dist/linters/house/async-rules.d.ts +10 -0
  50. package/dist/linters/house/async-rules.js +29 -0
  51. package/dist/linters/house/async-rules.js.map +1 -0
  52. package/dist/linters/house/await-support.d.ts +2 -0
  53. package/dist/linters/house/await-support.js +15 -10
  54. package/dist/linters/house/await-support.js.map +1 -1
  55. package/dist/linters/house/common.d.ts +2 -0
  56. package/dist/linters/house/common.js +2 -0
  57. package/dist/linters/house/common.js.map +1 -1
  58. package/dist/linters/house/configs.d.ts +3 -29
  59. package/dist/linters/house/configs.js +24 -51
  60. package/dist/linters/house/configs.js.map +1 -1
  61. package/dist/linters/house/const-class-values.rule.js.map +1 -1
  62. package/dist/linters/house/effect-cleanup-consistency.rule.js +2 -1
  63. package/dist/linters/house/effect-cleanup-consistency.rule.js.map +1 -1
  64. package/dist/linters/house/hook-support.js.map +1 -1
  65. package/dist/linters/house/index.d.ts +2 -1
  66. package/dist/linters/house/index.js +4 -1
  67. package/dist/linters/house/index.js.map +1 -1
  68. package/dist/linters/house/max-params-own.rule.d.ts +3 -1
  69. package/dist/linters/house/max-params-own.rule.js +1 -1
  70. package/dist/linters/house/max-params-own.rule.js.map +1 -1
  71. package/dist/linters/house/no-async-hook-callback.rule.js.map +1 -1
  72. package/dist/linters/house/no-await-promise-chain.rule.js +2 -3
  73. package/dist/linters/house/no-await-promise-chain.rule.js.map +1 -1
  74. package/dist/linters/house/no-leaked-render.rule.js.map +1 -1
  75. package/dist/linters/house/no-return-await.rule.js +2 -8
  76. package/dist/linters/house/no-return-await.rule.js.map +1 -1
  77. package/dist/linters/house/no-silent-catch.rule.js +1 -1
  78. package/dist/linters/house/no-silent-catch.rule.js.map +1 -1
  79. package/dist/linters/house/no-unbraced-case.rule.d.ts +15 -0
  80. package/dist/linters/house/no-unbraced-case.rule.js +45 -0
  81. package/dist/linters/house/no-unbraced-case.rule.js.map +1 -0
  82. package/dist/linters/house/plugin.js +2 -0
  83. package/dist/linters/house/plugin.js.map +1 -1
  84. package/dist/linters/house/promise-chain-support.js.map +1 -1
  85. package/dist/linters/ignore.js.map +1 -1
  86. package/dist/linters/index.d.ts +1 -0
  87. package/dist/linters/index.js +1 -0
  88. package/dist/linters/index.js.map +1 -1
  89. package/dist/linters/oxlint.d.ts +6 -1
  90. package/dist/linters/oxlint.js.map +1 -1
  91. package/dist/linters/padding.d.ts +8 -0
  92. package/dist/linters/padding.js +25 -0
  93. package/dist/linters/padding.js.map +1 -0
  94. package/dist/linters/rules/eqeqeq.rule.js.map +1 -1
  95. package/dist/linters/rules/index.d.ts +2 -0
  96. package/dist/linters/rules/index.js +2 -0
  97. package/dist/linters/rules/index.js.map +1 -1
  98. package/dist/linters/rules/lines-between-class-members.rule.d.ts +14 -0
  99. package/dist/linters/rules/lines-between-class-members.rule.js +17 -0
  100. package/dist/linters/rules/lines-between-class-members.rule.js.map +1 -0
  101. package/dist/linters/rules/naming-convention.rule.js.map +1 -1
  102. package/dist/linters/rules/no-restricted-imports.rule.js.map +1 -1
  103. package/dist/linters/rules/no-restricted-properties.rule.js.map +1 -1
  104. package/dist/linters/rules/no-unused-vars.rule.d.ts +6 -1
  105. package/dist/linters/rules/no-unused-vars.rule.js +1 -1
  106. package/dist/linters/rules/no-unused-vars.rule.js.map +1 -1
  107. package/dist/linters/rules/padding-line-between-statements.rule.d.ts +16 -0
  108. package/dist/linters/rules/padding-line-between-statements.rule.js +25 -0
  109. package/dist/linters/rules/padding-line-between-statements.rule.js.map +1 -0
  110. package/dist/linters/rules/prefer-nullish-coalescing.rule.js.map +1 -1
  111. package/dist/linters/rules/switch-case-braces.rule.js.map +1 -1
  112. package/dist/testing/rejection.helper.d.ts +1 -0
  113. package/dist/testing/rejection.helper.js +1 -0
  114. package/dist/testing/rejection.helper.js.map +1 -1
  115. package/dist/testing/repo-tmp.d.ts +1 -0
  116. package/dist/testing/repo-tmp.js +1 -0
  117. package/dist/testing/repo-tmp.js.map +1 -1
  118. package/dist/testing/spawn.helper.d.ts +1 -0
  119. package/dist/testing/spawn.helper.js +1 -0
  120. package/dist/testing/spawn.helper.js.map +1 -1
  121. package/package.json +3 -5
  122. package/dist/checks/catalog.d.ts.map +0 -1
  123. package/dist/checks/index.d.ts.map +0 -1
  124. package/dist/checks/module-cycles.d.ts.map +0 -1
  125. package/dist/checks/purity/manifest.d.ts.map +0 -1
  126. package/dist/checks/purity/probe.d.ts.map +0 -1
  127. package/dist/checks/purity/run.d.ts.map +0 -1
  128. package/dist/checks/split-report.d.ts.map +0 -1
  129. package/dist/checks/test-controls.d.ts.map +0 -1
  130. package/dist/checks/test-dead-code.d.ts.map +0 -1
  131. package/dist/checks/test-mutate.d.ts.map +0 -1
  132. package/dist/checks/test-weight.d.ts.map +0 -1
  133. package/dist/cli/check.d.ts.map +0 -1
  134. package/dist/cli/clean.d.ts.map +0 -1
  135. package/dist/cli/codemod/async-style.d.ts.map +0 -1
  136. package/dist/cli/codemod/connector-imports.d.ts.map +0 -1
  137. package/dist/cli/codemod/const-classes.d.ts.map +0 -1
  138. package/dist/cli/codemod/drop-redundant-casts.d.ts.map +0 -1
  139. package/dist/cli/codemod/files.d.ts.map +0 -1
  140. package/dist/cli/codemod/index.d.ts.map +0 -1
  141. package/dist/cli/codemod/namespace-functions/index.d.ts.map +0 -1
  142. package/dist/cli/codemod/namespace-functions/logger-scope.d.ts.map +0 -1
  143. package/dist/cli/codemod/namespace-functions/mapping.d.ts.map +0 -1
  144. package/dist/cli/codemod/namespace-functions/mappings/boot.d.ts.map +0 -1
  145. package/dist/cli/codemod/namespace-functions/mappings/connectors.d.ts.map +0 -1
  146. package/dist/cli/codemod/namespace-functions/mappings/core-server.d.ts.map +0 -1
  147. package/dist/cli/codemod/namespace-functions/mappings/core-worker.d.ts.map +0 -1
  148. package/dist/cli/codemod/namespace-functions/mappings/dev-configs.d.ts.map +0 -1
  149. package/dist/cli/codemod/namespace-functions/mappings/filter.d.ts.map +0 -1
  150. package/dist/cli/codemod/namespace-functions/mappings/helpers.d.ts.map +0 -1
  151. package/dist/cli/codemod/namespace-functions/mappings/index.d.ts.map +0 -1
  152. package/dist/cli/codemod/namespace-functions/mappings/inversion.d.ts.map +0 -1
  153. package/dist/cli/codemod/namespace-functions/mappings/kernel.d.ts.map +0 -1
  154. package/dist/cli/codemod/namespace-functions/rewriter.d.ts.map +0 -1
  155. package/dist/cli/index.d.ts.map +0 -1
  156. package/dist/cli/lint.d.ts.map +0 -1
  157. package/dist/compilers/bun.d.ts.map +0 -1
  158. package/dist/compilers/index.d.ts.map +0 -1
  159. package/dist/index.d.ts.map +0 -1
  160. package/dist/linters/browser.d.ts.map +0 -1
  161. package/dist/linters/eslint.d.ts.map +0 -1
  162. package/dist/linters/house/await-support.d.ts.map +0 -1
  163. package/dist/linters/house/common.d.ts.map +0 -1
  164. package/dist/linters/house/configs.d.ts.map +0 -1
  165. package/dist/linters/house/const-class-values.rule.d.ts.map +0 -1
  166. package/dist/linters/house/effect-cleanup-consistency.rule.d.ts.map +0 -1
  167. package/dist/linters/house/hook-support.d.ts.map +0 -1
  168. package/dist/linters/house/index.d.ts.map +0 -1
  169. package/dist/linters/house/max-params-own.rule.d.ts.map +0 -1
  170. package/dist/linters/house/no-async-hook-callback.rule.d.ts.map +0 -1
  171. package/dist/linters/house/no-await-promise-chain.rule.d.ts.map +0 -1
  172. package/dist/linters/house/no-inline-await.rule.d.ts.map +0 -1
  173. package/dist/linters/house/no-leaked-render.rule.d.ts.map +0 -1
  174. package/dist/linters/house/no-new-error.rule.d.ts.map +0 -1
  175. package/dist/linters/house/no-return-await.rule.d.ts.map +0 -1
  176. package/dist/linters/house/no-silent-catch.rule.d.ts.map +0 -1
  177. package/dist/linters/house/plugin.d.ts.map +0 -1
  178. package/dist/linters/house/promise-chain-support.d.ts.map +0 -1
  179. package/dist/linters/ignore.d.ts.map +0 -1
  180. package/dist/linters/index.d.ts.map +0 -1
  181. package/dist/linters/jsx-files.d.ts.map +0 -1
  182. package/dist/linters/oxlint-presets.d.ts.map +0 -1
  183. package/dist/linters/oxlint.d.ts.map +0 -1
  184. package/dist/linters/react-eslint.d.ts.map +0 -1
  185. package/dist/linters/react-oxlint.d.ts.map +0 -1
  186. package/dist/linters/rules/common.d.ts.map +0 -1
  187. package/dist/linters/rules/eqeqeq.rule.d.ts.map +0 -1
  188. package/dist/linters/rules/index.d.ts.map +0 -1
  189. package/dist/linters/rules/naming-convention.rule.d.ts.map +0 -1
  190. package/dist/linters/rules/no-restricted-imports.rule.d.ts.map +0 -1
  191. package/dist/linters/rules/no-restricted-properties.rule.d.ts.map +0 -1
  192. package/dist/linters/rules/no-unused-vars.rule.d.ts.map +0 -1
  193. package/dist/linters/rules/prefer-nullish-coalescing.rule.d.ts.map +0 -1
  194. package/dist/linters/rules/switch-case-braces.rule.d.ts.map +0 -1
  195. package/dist/testing/index.d.ts.map +0 -1
  196. package/dist/testing/rejection.helper.d.ts.map +0 -1
  197. package/dist/testing/repo-tmp.d.ts.map +0 -1
  198. package/dist/testing/spawn.helper.d.ts.map +0 -1
  199. package/dist/testing/tmpdir-preload.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"effect-cleanup-consistency.rule.js","sourceRoot":"","sources":["../../../src/linters/house/effect-cleanup-consistency.rule.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Rule } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { AstNode, AstNodeTypes, HOUSE_PLUGIN_NAMESPACE } from './common';\nimport { HookSupport } from './hook-support';\n\n/** What the rule knows about the function whose code path is open; one per function, so a nested function is its own. */\ninterface IFunctionFrame {\n upper: IFunctionFrame | undefined;\n hook: string | undefined;\n returnsValue: boolean;\n returnsNothing: boolean;\n segments: Set<{ reachable: boolean }>;\n}\n\n/**\n * `venizia/effect-cleanup-consistency`. The callback of `useEffect`, `useLayoutEffect` and `useInsertionEffect`\n * returns a cleanup on every path or on none. An early `return;` beside a later `return () => {}` leaves React\n * with a cleanup on some runs only; the early exit returns a no-op instead. A bare `return;` and falling off the\n * end both mean \"no value\". It uses ESLint's code path analysis the way `consistent-return` does, so an\n * unreachable end of the function is not a path. A nested function's own `return` is not counted.\n */\nexport class EffectCleanupConsistencyRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/effect-cleanup-consistency`;\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'problem',\n schema: [],\n messages: {\n inconsistent:\n 'The callback of `{{hook}}` returns a cleanup on some paths only; return one on every path (a no-op `() => {}` for an early exit) or on none.',\n },\n },\n create: (context) => {\n const targets = new Map<unknown, string>();\n let frame: IFunctionFrame | undefined;\n\n const checkExit = (node: Rule.Node) => {\n const current = frame;\n if (\n !current?.hook ||\n AstNode.getType({ node: AstNode.readField({ node, key: 'body' }) }) !== 'BlockStatement'\n ) {\n return;\n }\n\n const endIsReachable = [...current.segments].some((segment) => segment.reachable);\n if (current.returnsValue && (current.returnsNothing || endIsReachable)) {\n context.report({ node, messageId: 'inconsistent', data: { hook: current.hook } });\n }\n };\n\n return {\n [AstNodeTypes.CALL_EXPRESSION]: (node: Rule.Node) => {\n const hook = HookSupport.calleeName({ call: node });\n const args = AstNode.readField({ node, key: 'arguments' });\n if (\n !HookSupport.isEffectHook({ name: hook }) ||\n hook === undefined ||\n !Array.isArray(args)\n ) {\n return;\n }\n\n if (HookSupport.isCallback({ node: args[0] })) {\n targets.set(args[0], hook);\n }\n },\n onCodePathStart: (_codePath, node) => {\n frame = {\n upper: frame,\n hook: targets.get(node),\n returnsValue: false,\n returnsNothing: false,\n segments: new Set(),\n };\n },\n onCodePathEnd: () => {\n frame = frame?.upper;\n },\n onCodePathSegmentStart: (segment) => frame?.segments.add(segment),\n onCodePathSegmentEnd: (segment) => frame?.segments.delete(segment),\n onUnreachableCodePathSegmentStart: (segment) => frame?.segments.add(segment),\n onUnreachableCodePathSegmentEnd: (segment) => frame?.segments.delete(segment),\n [AstNodeTypes.RETURN_STATEMENT]: (node: Rule.Node) => {\n if (!frame) {\n return;\n }\n\n if (AstNode.readField({ node, key: 'argument' })) {\n frame.returnsValue = true;\n } else {\n frame.returnsNothing = true;\n }\n },\n 'FunctionExpression:exit': checkExit,\n 'ArrowFunctionExpression:exit': checkExit,\n };\n },\n };\n\n static build(opts: { severity?: TRuleSeverity } = {}): TRuleSeverity {\n return opts.severity ?? 'error';\n }\n}\n"]}
1
+ {"version":3,"file":"effect-cleanup-consistency.rule.js","sourceRoot":"","sources":["../../../src/linters/house/effect-cleanup-consistency.rule.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Rule } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { AstNode, AstNodeTypes, HOUSE_PLUGIN_NAMESPACE } from './common';\nimport { HookSupport } from './hook-support';\n\n/** What the rule knows about the function whose code path is open; one per function, so a nested function is its own. */\ninterface IFunctionFrame {\n upper: IFunctionFrame | undefined;\n hook: string | undefined;\n returnsValue: boolean;\n returnsNothing: boolean;\n segments: Set<{ reachable: boolean }>;\n}\n\n/**\n * `venizia/effect-cleanup-consistency`. The callback of `useEffect`, `useLayoutEffect` and `useInsertionEffect`\n * returns a cleanup on every path or on none. An early `return;` beside a later `return () => {}` leaves React\n * with a cleanup on some runs only; the early exit returns a no-op instead. A bare `return;` and falling off the\n * end both mean \"no value\". It uses ESLint's code path analysis the way `consistent-return` does, so an\n * unreachable end of the function is not a path. A nested function's own `return` is not counted.\n */\nexport class EffectCleanupConsistencyRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/effect-cleanup-consistency`;\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'problem',\n schema: [],\n messages: {\n inconsistent:\n 'The callback of `{{hook}}` returns a cleanup on some paths only; return one on every path (a no-op `() => {}` for an early exit) or on none.',\n },\n },\n create: (context) => {\n const targets = new Map<unknown, string>();\n let frame: IFunctionFrame | undefined;\n\n const checkExit = (node: Rule.Node) => {\n const current = frame;\n\n if (\n !current?.hook ||\n AstNode.getType({ node: AstNode.readField({ node, key: 'body' }) }) !==\n AstNodeTypes.BLOCK_STATEMENT\n ) {\n return;\n }\n\n const endIsReachable = [...current.segments].some((segment) => segment.reachable);\n\n if (current.returnsValue && (current.returnsNothing || endIsReachable)) {\n context.report({ node, messageId: 'inconsistent', data: { hook: current.hook } });\n }\n };\n\n return {\n [AstNodeTypes.CALL_EXPRESSION]: (node: Rule.Node) => {\n const hook = HookSupport.calleeName({ call: node });\n const args = AstNode.readField({ node, key: 'arguments' });\n\n if (\n !HookSupport.isEffectHook({ name: hook }) ||\n hook === undefined ||\n !Array.isArray(args)\n ) {\n return;\n }\n\n if (HookSupport.isCallback({ node: args[0] })) {\n targets.set(args[0], hook);\n }\n },\n onCodePathStart: (_codePath, node) => {\n frame = {\n upper: frame,\n hook: targets.get(node),\n returnsValue: false,\n returnsNothing: false,\n segments: new Set(),\n };\n },\n onCodePathEnd: () => {\n frame = frame?.upper;\n },\n onCodePathSegmentStart: (segment) => frame?.segments.add(segment),\n onCodePathSegmentEnd: (segment) => frame?.segments.delete(segment),\n onUnreachableCodePathSegmentStart: (segment) => frame?.segments.add(segment),\n onUnreachableCodePathSegmentEnd: (segment) => frame?.segments.delete(segment),\n [AstNodeTypes.RETURN_STATEMENT]: (node: Rule.Node) => {\n if (!frame) {\n return;\n }\n\n if (AstNode.readField({ node, key: 'argument' })) {\n frame.returnsValue = true;\n } else {\n frame.returnsNothing = true;\n }\n },\n 'FunctionExpression:exit': checkExit,\n 'ArrowFunctionExpression:exit': checkExit,\n };\n },\n };\n\n static build(opts: { severity?: TRuleSeverity } = {}): TRuleSeverity {\n return opts.severity ?? 'error';\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"hook-support.js","sourceRoot":"","sources":["../../../src/linters/house/hook-support.ts"],"names":[],"mappings":"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","sourcesContent":["import { AstNode } from './common';\n\nconst HOOK_NAME = /^use[A-Z]/;\nconst EFFECT_HOOKS = new Set(['useEffect', 'useLayoutEffect', 'useInsertionEffect']);\nconst CALLBACK_TYPES = new Set(['ArrowFunctionExpression', 'FunctionExpression']);\n\n/** The shared parts of the two hook rules: which call is a hook, and which argument is a function. */\nexport class HookSupport {\n /** `useX(...)` and `React.useX(...)`: the name the call is made through, or `undefined` when it is not a plain name. */\n static calleeName(opts: { call: unknown }): string | undefined {\n const callee = AstNode.readField({ node: opts.call, key: 'callee' });\n const type = AstNode.getType({ node: callee });\n\n if (type === 'Identifier') {\n const name = AstNode.readField({ node: callee, key: 'name' });\n return typeof name === 'string' ? name : undefined;\n }\n\n if (\n type === 'MemberExpression' &&\n AstNode.readField({ node: callee, key: 'computed' }) === false\n ) {\n const property = AstNode.readField({ node: callee, key: 'property' });\n const name = AstNode.readField({ node: property, key: 'name' });\n return AstNode.getType({ node: property }) === 'Identifier' && typeof name === 'string'\n ? name\n : undefined;\n }\n\n return undefined;\n }\n\n static isHook(opts: { name: string | undefined }): boolean {\n return opts.name !== undefined && HOOK_NAME.test(opts.name);\n }\n\n static isEffectHook(opts: { name: string | undefined }): boolean {\n return opts.name !== undefined && EFFECT_HOOKS.has(opts.name);\n }\n\n /** An arrow or a function expression: the two forms a hook callback is written in. */\n static isCallback(opts: { node: unknown }): boolean {\n return CALLBACK_TYPES.has(AstNode.getType({ node: opts.node }) ?? '');\n }\n\n static isAsync(opts: { node: unknown }): boolean {\n return (\n HookSupport.isCallback(opts) && AstNode.readField({ node: opts.node, key: 'async' }) === true\n );\n }\n\n /**\n * The async functions an argument hands over: the argument itself, a property value of an object literal\n * (`useMutation({ mutationFn: async () => {} })`, an async method too) and an element of an array literal, at any\n * depth of literals. It does not look inside a function: what a sync callback builds is not an argument.\n */\n static asyncFunctionsIn(opts: { node: unknown }): unknown[] {\n const { node } = opts;\n const type = AstNode.getType({ node });\n\n if (HookSupport.isAsync({ node })) {\n return [node];\n }\n\n if (type === 'ObjectExpression') {\n const properties = AstNode.readField({ node, key: 'properties' });\n\n return Array.isArray(properties)\n ? properties.flatMap((property) =>\n AstNode.getType({ node: property }) === 'Property'\n ? HookSupport.asyncFunctionsIn({\n node: AstNode.readField({ node: property, key: 'value' }),\n })\n : [],\n )\n : [];\n }\n\n if (type === 'ArrayExpression') {\n const elements = AstNode.readField({ node, key: 'elements' });\n\n return Array.isArray(elements)\n ? elements.flatMap((element) => HookSupport.asyncFunctionsIn({ node: element }))\n : [];\n }\n\n return [];\n }\n}\n"]}
1
+ {"version":3,"file":"hook-support.js","sourceRoot":"","sources":["../../../src/linters/house/hook-support.ts"],"names":[],"mappings":";;;AAAA,qCAAmC;AAEnC,MAAM,SAAS,GAAG,WAAW,CAAC;AAC9B,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,iBAAiB,EAAE,oBAAoB,CAAC,CAAC,CAAC;AACrF,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,yBAAyB,EAAE,oBAAoB,CAAC,CAAC,CAAC;AAElF,sGAAsG;AACtG,MAAa,WAAW;IACtB,wHAAwH;IACxH,MAAM,CAAC,UAAU,CAAC,IAAuB;QACvC,MAAM,MAAM,GAAG,gBAAO,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;QACrE,MAAM,IAAI,GAAG,gBAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAE/C,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,gBAAO,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;YAE9D,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QACrD,CAAC;QAED,IACE,IAAI,KAAK,kBAAkB;YAC3B,gBAAO,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,KAAK,KAAK,EAC9D,CAAC;YACD,MAAM,QAAQ,GAAG,gBAAO,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;YACtE,MAAM,IAAI,GAAG,gBAAO,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;YAEhE,OAAO,gBAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,KAAK,YAAY,IAAI,OAAO,IAAI,KAAK,QAAQ;gBACrF,CAAC,CAAC,IAAI;gBACN,CAAC,CAAC,SAAS,CAAC;QAChB,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,IAAkC;QAC9C,OAAO,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,IAAkC;QACpD,OAAO,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChE,CAAC;IAED,sFAAsF;IACtF,MAAM,CAAC,UAAU,CAAC,IAAuB;QACvC,OAAO,cAAc,CAAC,GAAG,CAAC,gBAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,IAAuB;QACpC,OAAO,CACL,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,gBAAO,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,KAAK,IAAI,CAC9F,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,gBAAgB,CAAC,IAAuB;QAC7C,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;QACtB,MAAM,IAAI,GAAG,gBAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvC,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC;QAED,IAAI,IAAI,KAAK,kBAAkB,EAAE,CAAC;YAChC,MAAM,UAAU,GAAG,gBAAO,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;YAElE,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;gBAC9B,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAC9B,gBAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,KAAK,UAAU;oBAChD,CAAC,CAAC,WAAW,CAAC,gBAAgB,CAAC;wBAC3B,IAAI,EAAE,gBAAO,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;qBAC1D,CAAC;oBACJ,CAAC,CAAC,EAAE,CACP;gBACH,CAAC,CAAC,EAAE,CAAC;QACT,CAAC;QAED,IAAI,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAC/B,MAAM,QAAQ,GAAG,gBAAO,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;YAE9D,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;gBAC5B,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;gBAChF,CAAC,CAAC,EAAE,CAAC;QACT,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;CACF;AAnFD,kCAmFC","sourcesContent":["import { AstNode } from './common';\n\nconst HOOK_NAME = /^use[A-Z]/;\nconst EFFECT_HOOKS = new Set(['useEffect', 'useLayoutEffect', 'useInsertionEffect']);\nconst CALLBACK_TYPES = new Set(['ArrowFunctionExpression', 'FunctionExpression']);\n\n/** The shared parts of the two hook rules: which call is a hook, and which argument is a function. */\nexport class HookSupport {\n /** `useX(...)` and `React.useX(...)`: the name the call is made through, or `undefined` when it is not a plain name. */\n static calleeName(opts: { call: unknown }): string | undefined {\n const callee = AstNode.readField({ node: opts.call, key: 'callee' });\n const type = AstNode.getType({ node: callee });\n\n if (type === 'Identifier') {\n const name = AstNode.readField({ node: callee, key: 'name' });\n\n return typeof name === 'string' ? name : undefined;\n }\n\n if (\n type === 'MemberExpression' &&\n AstNode.readField({ node: callee, key: 'computed' }) === false\n ) {\n const property = AstNode.readField({ node: callee, key: 'property' });\n const name = AstNode.readField({ node: property, key: 'name' });\n\n return AstNode.getType({ node: property }) === 'Identifier' && typeof name === 'string'\n ? name\n : undefined;\n }\n\n return undefined;\n }\n\n static isHook(opts: { name: string | undefined }): boolean {\n return opts.name !== undefined && HOOK_NAME.test(opts.name);\n }\n\n static isEffectHook(opts: { name: string | undefined }): boolean {\n return opts.name !== undefined && EFFECT_HOOKS.has(opts.name);\n }\n\n /** An arrow or a function expression: the two forms a hook callback is written in. */\n static isCallback(opts: { node: unknown }): boolean {\n return CALLBACK_TYPES.has(AstNode.getType({ node: opts.node }) ?? '');\n }\n\n static isAsync(opts: { node: unknown }): boolean {\n return (\n HookSupport.isCallback(opts) && AstNode.readField({ node: opts.node, key: 'async' }) === true\n );\n }\n\n /**\n * The async functions an argument hands over: the argument itself, a property value of an object literal\n * (`useMutation({ mutationFn: async () => {} })`, an async method too) and an element of an array literal, at any\n * depth of literals. It does not look inside a function: what a sync callback builds is not an argument.\n */\n static asyncFunctionsIn(opts: { node: unknown }): unknown[] {\n const { node } = opts;\n const type = AstNode.getType({ node });\n\n if (HookSupport.isAsync({ node })) {\n return [node];\n }\n\n if (type === 'ObjectExpression') {\n const properties = AstNode.readField({ node, key: 'properties' });\n\n return Array.isArray(properties)\n ? properties.flatMap((property) =>\n AstNode.getType({ node: property }) === 'Property'\n ? HookSupport.asyncFunctionsIn({\n node: AstNode.readField({ node: property, key: 'value' }),\n })\n : [],\n )\n : [];\n }\n\n if (type === 'ArrayExpression') {\n const elements = AstNode.readField({ node, key: 'elements' });\n\n return Array.isArray(elements)\n ? elements.flatMap((element) => HookSupport.asyncFunctionsIn({ node: element }))\n : [];\n }\n\n return [];\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- export * from './await-support';
1
+ export { AwaitSupport } from './await-support';
2
2
  export * from './common';
3
3
  export * from './const-class-values.rule';
4
4
  export * from './effect-cleanup-consistency.rule';
@@ -11,6 +11,7 @@ export * from './no-leaked-render.rule';
11
11
  export * from './no-new-error.rule';
12
12
  export * from './no-return-await.rule';
13
13
  export * from './no-silent-catch.rule';
14
+ export * from './no-unbraced-case.rule';
14
15
  export * from './plugin';
15
16
  export * from './promise-chain-support';
16
17
  export * from './configs';
@@ -14,7 +14,9 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./await-support"), exports);
17
+ exports.AwaitSupport = void 0;
18
+ var await_support_1 = require("./await-support");
19
+ Object.defineProperty(exports, "AwaitSupport", { enumerable: true, get: function () { return await_support_1.AwaitSupport; } });
18
20
  __exportStar(require("./common"), exports);
19
21
  __exportStar(require("./const-class-values.rule"), exports);
20
22
  __exportStar(require("./effect-cleanup-consistency.rule"), exports);
@@ -27,6 +29,7 @@ __exportStar(require("./no-leaked-render.rule"), exports);
27
29
  __exportStar(require("./no-new-error.rule"), exports);
28
30
  __exportStar(require("./no-return-await.rule"), exports);
29
31
  __exportStar(require("./no-silent-catch.rule"), exports);
32
+ __exportStar(require("./no-unbraced-case.rule"), exports);
30
33
  __exportStar(require("./plugin"), exports);
31
34
  __exportStar(require("./promise-chain-support"), exports);
32
35
  __exportStar(require("./configs"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/linters/house/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kDAAgC;AAChC,2CAAyB;AACzB,4DAA0C;AAC1C,oEAAkD;AAClD,iDAA+B;AAC/B,wDAAsC;AACtC,gEAA8C;AAC9C,gEAA8C;AAC9C,yDAAuC;AACvC,0DAAwC;AACxC,sDAAoC;AACpC,yDAAuC;AACvC,yDAAuC;AACvC,2CAAyB;AACzB,0DAAwC;AACxC,4CAA0B","sourcesContent":["export * from './await-support';\nexport * from './common';\nexport * from './const-class-values.rule';\nexport * from './effect-cleanup-consistency.rule';\nexport * from './hook-support';\nexport * from './max-params-own.rule';\nexport * from './no-async-hook-callback.rule';\nexport * from './no-await-promise-chain.rule';\nexport * from './no-inline-await.rule';\nexport * from './no-leaked-render.rule';\nexport * from './no-new-error.rule';\nexport * from './no-return-await.rule';\nexport * from './no-silent-catch.rule';\nexport * from './plugin';\nexport * from './promise-chain-support';\nexport * from './configs';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/linters/house/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,iDAA+C;AAAtC,6GAAA,YAAY,OAAA;AACrB,2CAAyB;AACzB,4DAA0C;AAC1C,oEAAkD;AAClD,iDAA+B;AAC/B,wDAAsC;AACtC,gEAA8C;AAC9C,gEAA8C;AAC9C,yDAAuC;AACvC,0DAAwC;AACxC,sDAAoC;AACpC,yDAAuC;AACvC,yDAAuC;AACvC,0DAAwC;AACxC,2CAAyB;AACzB,0DAAwC;AACxC,4CAA0B","sourcesContent":["export { AwaitSupport } from './await-support';\nexport * from './common';\nexport * from './const-class-values.rule';\nexport * from './effect-cleanup-consistency.rule';\nexport * from './hook-support';\nexport * from './max-params-own.rule';\nexport * from './no-async-hook-callback.rule';\nexport * from './no-await-promise-chain.rule';\nexport * from './no-inline-await.rule';\nexport * from './no-leaked-render.rule';\nexport * from './no-new-error.rule';\nexport * from './no-return-await.rule';\nexport * from './no-silent-catch.rule';\nexport * from './no-unbraced-case.rule';\nexport * from './plugin';\nexport * from './promise-chain-support';\nexport * from './configs';\n"]}
@@ -1,7 +1,7 @@
1
1
  import type { Linter, Rule } from 'eslint';
2
2
  import type { TRuleSeverity } from '../rules/common';
3
3
  /**
4
- * `venizia/max-params-own`. A function we write takes at most `max` (default 5) positional parameters;
4
+ * `venizia/max-params-own`. A function we write takes at most `max` positional parameters;
5
5
  * beyond that it takes one options object. A signature that belongs to someone else is not counted: an
6
6
  * inline callback handed to a call (map, reduce, sort, a library handler) or to a JSX prop, a function a
7
7
  * declared type fixes (`const x: TFn = (...)`, a member of a typed or `satisfies` object), and a
@@ -12,7 +12,9 @@ export declare class MaxParamsOwnRule {
12
12
  static readonly DEFAULT_MAX = 5;
13
13
  static readonly RULE: Rule.RuleModule;
14
14
  static build(opts?: {
15
+ /** @default 'error' */
15
16
  severity?: TRuleSeverity;
17
+ /** @default 5 */
16
18
  max?: number;
17
19
  }): Linter.RuleEntry;
18
20
  }
@@ -45,7 +45,7 @@ const hasDeclaredShape = (object) => {
45
45
  return false;
46
46
  };
47
47
  /**
48
- * `venizia/max-params-own`. A function we write takes at most `max` (default 5) positional parameters;
48
+ * `venizia/max-params-own`. A function we write takes at most `max` positional parameters;
49
49
  * beyond that it takes one options object. A signature that belongs to someone else is not counted: an
50
50
  * inline callback handed to a call (map, reduce, sort, a library handler) or to a JSX prop, a function a
51
51
  * declared type fixes (`const x: TFn = (...)`, a member of a typed or `satisfies` object), and a
@@ -1 +1 @@
1
- {"version":3,"file":"max-params-own.rule.js","sourceRoot":"","sources":["../../../src/linters/house/max-params-own.rule.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Linter, Rule } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { AstNode, AstNodeTypes, HOUSE_PLUGIN_NAMESPACE } from './common';\n\nconst HOOK_NAME = /^use[A-Z]/;\nconst CALL_TYPES = new Set(['CallExpression', 'NewExpression']);\n\nconst isArrayContaining = (opts: { list: unknown; item: unknown }) =>\n Array.isArray(opts.list) && opts.list.includes(opts.item);\n\n/** `useX(...)`: a hook's callback is ours, so it counts. */\nconst isHookCall = (call: unknown) => {\n const callee = AstNode.readField({ node: call, key: 'callee' });\n const name = AstNode.readField({ node: callee, key: 'name' });\n return (\n AstNode.getType({ node: callee }) === 'Identifier' &&\n typeof name === 'string' &&\n HOOK_NAME.test(name)\n );\n};\n\n/** `node` is an argument of a call or `new` that is not a hook. */\nconst isLibraryArgument = (opts: { node: unknown; parent: unknown }) =>\n CALL_TYPES.has(AstNode.getType({ node: opts.parent }) ?? '') &&\n isArrayContaining({\n list: AstNode.readField({ node: opts.parent, key: 'arguments' }),\n item: opts.node,\n }) &&\n !isHookCall(opts.parent);\n\n/**\n * An object literal whose shape something else declares: a typed variable, `satisfies`, or an argument\n * of a non-hook call (a library option bag). A nested literal inherits it.\n */\nconst hasDeclaredShape = (object: unknown): boolean => {\n let current = object;\n\n while (current) {\n const parent = AstNode.readField({ node: current, key: 'parent' });\n const parentType = AstNode.getType({ node: parent });\n const isTypedVariable =\n parentType === 'VariableDeclarator' &&\n Boolean(\n AstNode.readField({\n node: AstNode.readField({ node: parent, key: 'id' }),\n key: 'typeAnnotation',\n }),\n );\n\n if (\n isTypedVariable ||\n parentType === 'TSSatisfiesExpression' ||\n isLibraryArgument({ node: current, parent })\n ) {\n return true;\n }\n\n const isNestedValue =\n parentType === 'Property' && AstNode.readField({ node: parent, key: 'value' }) === current;\n current = isNestedValue ? AstNode.readField({ node: parent, key: 'parent' }) : undefined;\n }\n\n return false;\n};\n\n/**\n * `venizia/max-params-own`. A function we write takes at most `max` (default 5) positional parameters;\n * beyond that it takes one options object. A signature that belongs to someone else is not counted: an\n * inline callback handed to a call (map, reduce, sort, a library handler) or to a JSX prop, a function a\n * declared type fixes (`const x: TFn = (...)`, a member of a typed or `satisfies` object), and a\n * constructor whose every parameter is injected (`@inject`). A hook's callback (`useCallback(...)`) is ours.\n */\nexport class MaxParamsOwnRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/max-params-own`;\n\n static readonly DEFAULT_MAX = 5;\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n schema: [{ type: 'integer', minimum: 0 }],\n messages: {\n tooMany:\n 'A function we write takes up to {{max}} positional parameters, not {{count}}: take one options object.',\n },\n },\n create: (context) => {\n const max =\n typeof context.options[0] === 'number' ? context.options[0] : MaxParamsOwnRule.DEFAULT_MAX;\n\n const isCallback = (node: Rule.Node) => {\n const parent = node.parent;\n const isJsxProp =\n AstNode.getType({ node: parent }) === 'JSXExpressionContainer' &&\n AstNode.getType({ node: AstNode.readField({ node: parent, key: 'parent' }) }) ===\n 'JSXAttribute';\n return isJsxProp || isLibraryArgument({ node, parent });\n };\n\n const isInjectedConstructor = (opts: { node: Rule.Node; params: unknown[] }) => {\n const parent = opts.node.parent;\n const isDecorated = (param: unknown) => {\n const own = AstNode.readField({ node: param, key: 'decorators' });\n const property = AstNode.readField({\n node: AstNode.readField({ node: param, key: 'parameter' }),\n key: 'decorators',\n });\n return (\n (Array.isArray(own) && own.length > 0) ||\n (Array.isArray(property) && property.length > 0)\n );\n };\n\n return (\n AstNode.getType({ node: parent }) === 'MethodDefinition' &&\n AstNode.readField({ node: parent, key: 'kind' }) === 'constructor' &&\n opts.params.every(isDecorated)\n );\n };\n\n const isTypedByContext = (node: Rule.Node) => {\n const parent = node.parent;\n const parentType = AstNode.getType({ node: parent });\n const isTypedInit =\n parentType === 'VariableDeclarator' &&\n AstNode.readField({ node: parent, key: 'init' }) === node &&\n Boolean(\n AstNode.readField({\n node: AstNode.readField({ node: parent, key: 'id' }),\n key: 'typeAnnotation',\n }),\n );\n const grandParent = AstNode.readField({ node: parent, key: 'parent' });\n const isMember =\n parentType === 'Property' &&\n AstNode.readField({ node: parent, key: 'value' }) === node &&\n AstNode.getType({ node: grandParent }) === 'ObjectExpression';\n\n return isTypedInit || (isMember && hasDeclaredShape(grandParent));\n };\n\n const check = (node: Rule.Node) => {\n const params = AstNode.readField({ node, key: 'params' });\n if (!Array.isArray(params) || params.length <= max) {\n return;\n }\n\n if (isCallback(node) || isInjectedConstructor({ node, params }) || isTypedByContext(node)) {\n return;\n }\n\n context.report({\n node,\n messageId: 'tooMany',\n data: { count: String(params.length), max: String(max) },\n });\n };\n\n return {\n [AstNodeTypes.FUNCTION_DECLARATION]: check,\n [AstNodeTypes.FUNCTION_EXPRESSION]: check,\n [AstNodeTypes.ARROW_FUNCTION_EXPRESSION]: check,\n };\n },\n };\n\n static build(opts: { severity?: TRuleSeverity; max?: number } = {}): Linter.RuleEntry {\n const { severity = 'error', max = MaxParamsOwnRule.DEFAULT_MAX } = opts;\n return [severity, max];\n }\n}\n"]}
1
+ {"version":3,"file":"max-params-own.rule.js","sourceRoot":"","sources":["../../../src/linters/house/max-params-own.rule.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Linter, Rule } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { AstNode, AstNodeTypes, HOUSE_PLUGIN_NAMESPACE } from './common';\n\nconst HOOK_NAME = /^use[A-Z]/;\nconst CALL_TYPES = new Set(['CallExpression', 'NewExpression']);\n\nconst isArrayContaining = (opts: { list: unknown; item: unknown }) =>\n Array.isArray(opts.list) && opts.list.includes(opts.item);\n\n/** `useX(...)`: a hook's callback is ours, so it counts. */\nconst isHookCall = (call: unknown) => {\n const callee = AstNode.readField({ node: call, key: 'callee' });\n const name = AstNode.readField({ node: callee, key: 'name' });\n\n return (\n AstNode.getType({ node: callee }) === 'Identifier' &&\n typeof name === 'string' &&\n HOOK_NAME.test(name)\n );\n};\n\n/** `node` is an argument of a call or `new` that is not a hook. */\nconst isLibraryArgument = (opts: { node: unknown; parent: unknown }) =>\n CALL_TYPES.has(AstNode.getType({ node: opts.parent }) ?? '') &&\n isArrayContaining({\n list: AstNode.readField({ node: opts.parent, key: 'arguments' }),\n item: opts.node,\n }) &&\n !isHookCall(opts.parent);\n\n/**\n * An object literal whose shape something else declares: a typed variable, `satisfies`, or an argument\n * of a non-hook call (a library option bag). A nested literal inherits it.\n */\nconst hasDeclaredShape = (object: unknown): boolean => {\n let current = object;\n\n while (current) {\n const parent = AstNode.readField({ node: current, key: 'parent' });\n const parentType = AstNode.getType({ node: parent });\n const isTypedVariable =\n parentType === 'VariableDeclarator' &&\n Boolean(\n AstNode.readField({\n node: AstNode.readField({ node: parent, key: 'id' }),\n key: 'typeAnnotation',\n }),\n );\n\n if (\n isTypedVariable ||\n parentType === 'TSSatisfiesExpression' ||\n isLibraryArgument({ node: current, parent })\n ) {\n return true;\n }\n\n const isNestedValue =\n parentType === 'Property' && AstNode.readField({ node: parent, key: 'value' }) === current;\n current = isNestedValue ? AstNode.readField({ node: parent, key: 'parent' }) : undefined;\n }\n\n return false;\n};\n\n/**\n * `venizia/max-params-own`. A function we write takes at most `max` positional parameters;\n * beyond that it takes one options object. A signature that belongs to someone else is not counted: an\n * inline callback handed to a call (map, reduce, sort, a library handler) or to a JSX prop, a function a\n * declared type fixes (`const x: TFn = (...)`, a member of a typed or `satisfies` object), and a\n * constructor whose every parameter is injected (`@inject`). A hook's callback (`useCallback(...)`) is ours.\n */\nexport class MaxParamsOwnRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/max-params-own`;\n\n static readonly DEFAULT_MAX = 5;\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n schema: [{ type: 'integer', minimum: 0 }],\n messages: {\n tooMany:\n 'A function we write takes up to {{max}} positional parameters, not {{count}}: take one options object.',\n },\n },\n create: (context) => {\n const max =\n typeof context.options[0] === 'number' ? context.options[0] : MaxParamsOwnRule.DEFAULT_MAX;\n\n const isCallback = (node: Rule.Node) => {\n const parent = node.parent;\n const isJsxProp =\n AstNode.getType({ node: parent }) === 'JSXExpressionContainer' &&\n AstNode.getType({ node: AstNode.readField({ node: parent, key: 'parent' }) }) ===\n 'JSXAttribute';\n\n return isJsxProp || isLibraryArgument({ node, parent });\n };\n\n const isInjectedConstructor = (opts: { node: Rule.Node; params: unknown[] }) => {\n const parent = opts.node.parent;\n\n const isDecorated = (param: unknown) => {\n const own = AstNode.readField({ node: param, key: 'decorators' });\n const property = AstNode.readField({\n node: AstNode.readField({ node: param, key: 'parameter' }),\n key: 'decorators',\n });\n\n return (\n (Array.isArray(own) && own.length > 0) ||\n (Array.isArray(property) && property.length > 0)\n );\n };\n\n return (\n AstNode.getType({ node: parent }) === 'MethodDefinition' &&\n AstNode.readField({ node: parent, key: 'kind' }) === 'constructor' &&\n opts.params.every(isDecorated)\n );\n };\n\n const isTypedByContext = (node: Rule.Node) => {\n const parent = node.parent;\n const parentType = AstNode.getType({ node: parent });\n const isTypedInit =\n parentType === 'VariableDeclarator' &&\n AstNode.readField({ node: parent, key: 'init' }) === node &&\n Boolean(\n AstNode.readField({\n node: AstNode.readField({ node: parent, key: 'id' }),\n key: 'typeAnnotation',\n }),\n );\n const grandParent = AstNode.readField({ node: parent, key: 'parent' });\n const isMember =\n parentType === 'Property' &&\n AstNode.readField({ node: parent, key: 'value' }) === node &&\n AstNode.getType({ node: grandParent }) === 'ObjectExpression';\n\n return isTypedInit || (isMember && hasDeclaredShape(grandParent));\n };\n\n const check = (node: Rule.Node) => {\n const params = AstNode.readField({ node, key: 'params' });\n\n if (!Array.isArray(params) || params.length <= max) {\n return;\n }\n\n if (isCallback(node) || isInjectedConstructor({ node, params }) || isTypedByContext(node)) {\n return;\n }\n\n context.report({\n node,\n messageId: 'tooMany',\n data: { count: String(params.length), max: String(max) },\n });\n };\n\n return {\n [AstNodeTypes.FUNCTION_DECLARATION]: check,\n [AstNodeTypes.FUNCTION_EXPRESSION]: check,\n [AstNodeTypes.ARROW_FUNCTION_EXPRESSION]: check,\n };\n },\n };\n\n static build(\n opts: {\n /** @default 'error' */\n severity?: TRuleSeverity;\n /** @default 5 */\n max?: number;\n } = {},\n ): Linter.RuleEntry {\n const { severity = 'error', max = MaxParamsOwnRule.DEFAULT_MAX } = opts;\n\n return [severity, max];\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"no-async-hook-callback.rule.js","sourceRoot":"","sources":["../../../src/linters/house/no-async-hook-callback.rule.ts"],"names":[],"mappings":";;;AAEA,mDAA+C;AAC/C,qCAAyE;AACzE,iDAA6C;AAE7C;;;;;;;GAOG;AACH,MAAa,uBAAuB;aAClB,SAAI,GAAG,GAAG,+BAAsB,yBAAyB,CAAC;aAE1D,SAAI,GAAoB;QACtC,IAAI,EAAE;YACJ,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,EAAE;YACV,QAAQ,EAAE;gBACR,aAAa,EACX,gIAAgI;aACnI;SACF;QACD,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACpB,CAAC,qBAAY,CAAC,eAAe,CAAC,EAAE,CAAC,IAAe,EAAE,EAAE;gBAClD,MAAM,IAAI,GAAG,0BAAW,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBACpD,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,0BAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;oBAC9D,OAAO;gBACT,CAAC;gBAED,MAAM,IAAI,GAAG,gBAAO,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;gBAC3D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;oBACzB,OAAO;gBACT,CAAC;gBAED,KAAK,MAAM,QAAQ,IAAI,IAAI,EAAE,CAAC;oBAC5B,KAAK,MAAM,KAAK,IAAI,0BAAW,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;wBACrE,IAAI,4BAAY,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;4BAC/B,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;wBAC9E,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;KACH,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,OAAqC,EAAE;QAClD,OAAO,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC;IAClC,CAAC;;AArCH,0DAsCC","sourcesContent":["import type { Rule } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { AwaitSupport } from './await-support';\nimport { AstNode, AstNodeTypes, HOUSE_PLUGIN_NAMESPACE } from './common';\nimport { HookSupport } from './hook-support';\n\n/**\n * `venizia/no-async-hook-callback`. A hook never gets an async function: `useEffect(async () => {})` makes the\n * callback return a promise where React expects a cleanup function or nothing. Pass a sync callback and handle\n * the promise inside it with `.then`, `.catch` and `.finally`. Every argument of a `use[A-Z]...` call is checked,\n * `React.useX` too: an async function as the argument, as the value of a property of an object literal\n * (`useMutation({ mutationFn: async () => {} })`) and as an element of an array literal. A sync callback that\n * builds an async function inside is not an argument and is left alone.\n */\nexport class NoAsyncHookCallbackRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/no-async-hook-callback`;\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'problem',\n schema: [],\n messages: {\n asyncCallback:\n 'Do not pass an async function to `{{hook}}`; pass a sync callback and handle the promise inside it with .then/.catch/.finally.',\n },\n },\n create: (context) => ({\n [AstNodeTypes.CALL_EXPRESSION]: (node: Rule.Node) => {\n const hook = HookSupport.calleeName({ call: node });\n if (hook === undefined || !HookSupport.isHook({ name: hook })) {\n return;\n }\n\n const args = AstNode.readField({ node, key: 'arguments' });\n if (!Array.isArray(args)) {\n return;\n }\n\n for (const argument of args) {\n for (const found of HookSupport.asyncFunctionsIn({ node: argument })) {\n if (AwaitSupport.isNode(found)) {\n context.report({ node: found, messageId: 'asyncCallback', data: { hook } });\n }\n }\n }\n },\n }),\n };\n\n static build(opts: { severity?: TRuleSeverity } = {}): TRuleSeverity {\n return opts.severity ?? 'error';\n }\n}\n"]}
1
+ {"version":3,"file":"no-async-hook-callback.rule.js","sourceRoot":"","sources":["../../../src/linters/house/no-async-hook-callback.rule.ts"],"names":[],"mappings":";;;AAEA,mDAA+C;AAC/C,qCAAyE;AACzE,iDAA6C;AAE7C;;;;;;;GAOG;AACH,MAAa,uBAAuB;aAClB,SAAI,GAAG,GAAG,+BAAsB,yBAAyB,CAAC;aAE1D,SAAI,GAAoB;QACtC,IAAI,EAAE;YACJ,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,EAAE;YACV,QAAQ,EAAE;gBACR,aAAa,EACX,gIAAgI;aACnI;SACF;QACD,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACpB,CAAC,qBAAY,CAAC,eAAe,CAAC,EAAE,CAAC,IAAe,EAAE,EAAE;gBAClD,MAAM,IAAI,GAAG,0BAAW,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBAEpD,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,0BAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;oBAC9D,OAAO;gBACT,CAAC;gBAED,MAAM,IAAI,GAAG,gBAAO,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;gBAE3D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;oBACzB,OAAO;gBACT,CAAC;gBAED,KAAK,MAAM,QAAQ,IAAI,IAAI,EAAE,CAAC;oBAC5B,KAAK,MAAM,KAAK,IAAI,0BAAW,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;wBACrE,IAAI,4BAAY,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;4BAC/B,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;wBAC9E,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;KACH,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,OAAqC,EAAE;QAClD,OAAO,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC;IAClC,CAAC;;AAvCH,0DAwCC","sourcesContent":["import type { Rule } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { AwaitSupport } from './await-support';\nimport { AstNode, AstNodeTypes, HOUSE_PLUGIN_NAMESPACE } from './common';\nimport { HookSupport } from './hook-support';\n\n/**\n * `venizia/no-async-hook-callback`. A hook never gets an async function: `useEffect(async () => {})` makes the\n * callback return a promise where React expects a cleanup function or nothing. Pass a sync callback and handle\n * the promise inside it with `.then`, `.catch` and `.finally`. Every argument of a `use[A-Z]...` call is checked,\n * `React.useX` too: an async function as the argument, as the value of a property of an object literal\n * (`useMutation({ mutationFn: async () => {} })`) and as an element of an array literal. A sync callback that\n * builds an async function inside is not an argument and is left alone.\n */\nexport class NoAsyncHookCallbackRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/no-async-hook-callback`;\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'problem',\n schema: [],\n messages: {\n asyncCallback:\n 'Do not pass an async function to `{{hook}}`; pass a sync callback and handle the promise inside it with .then/.catch/.finally.',\n },\n },\n create: (context) => ({\n [AstNodeTypes.CALL_EXPRESSION]: (node: Rule.Node) => {\n const hook = HookSupport.calleeName({ call: node });\n\n if (hook === undefined || !HookSupport.isHook({ name: hook })) {\n return;\n }\n\n const args = AstNode.readField({ node, key: 'arguments' });\n\n if (!Array.isArray(args)) {\n return;\n }\n\n for (const argument of args) {\n for (const found of HookSupport.asyncFunctionsIn({ node: argument })) {\n if (AwaitSupport.isNode(found)) {\n context.report({ node: found, messageId: 'asyncCallback', data: { hook } });\n }\n }\n }\n },\n }),\n };\n\n static build(opts: { severity?: TRuleSeverity } = {}): TRuleSeverity {\n return opts.severity ?? 'error';\n }\n}\n"]}
@@ -4,7 +4,6 @@ exports.NoAwaitPromiseChainRule = void 0;
4
4
  const await_support_1 = require("./await-support");
5
5
  const common_1 = require("./common");
6
6
  const promise_chain_support_1 = require("./promise-chain-support");
7
- const STATEMENT_LISTS = new Set(['BlockStatement', 'Program', 'StaticBlock', 'SwitchCase']);
8
7
  /** The catch variable the fix writes when the handler has no parameter. */
9
8
  const CATCH_NAME = 'error';
10
9
  /** The identifiers a fallback value reads, and whether every node of it is a value the fix may move. */
@@ -95,7 +94,7 @@ const planFix = (opts) => {
95
94
  const parameter = Array.isArray(params) ? params[0] : undefined;
96
95
  if (common_1.AstNode.getType({ node: handler }) !== 'ArrowFunctionExpression' ||
97
96
  common_1.AstNode.readField({ node: handler, key: 'async' }) === true ||
98
- common_1.AstNode.getType({ node: body }) === 'BlockStatement' ||
97
+ common_1.AstNode.getType({ node: body }) === common_1.AstNodeTypes.BLOCK_STATEMENT ||
99
98
  common_1.AstNode.readField({ node: handler, key: 'returnType' }) ||
100
99
  common_1.AstNode.readField({ node: handler, key: 'typeParameters' }) ||
101
100
  !Array.isArray(params) ||
@@ -128,7 +127,7 @@ const planFix = (opts) => {
128
127
  !Array.isArray(declarations) ||
129
128
  declarations.length !== 1 ||
130
129
  !['const', 'let'].includes(kind) ||
131
- !STATEMENT_LISTS.has(common_1.AstNode.getType({ node: await_support_1.AwaitSupport.parentOf({ node: declaration }) }) ?? '')) {
130
+ !await_support_1.STATEMENT_LISTS.has(common_1.AstNode.getType({ node: await_support_1.AwaitSupport.parentOf({ node: declaration }) }) ?? '')) {
132
131
  return undefined;
133
132
  }
134
133
  const name = String(common_1.AstNode.readField({ node: id, key: 'name' }));
@@ -1 +1 @@
1
- {"version":3,"file":"no-await-promise-chain.rule.js","sourceRoot":"","sources":["../../../src/linters/house/no-await-promise-chain.rule.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Rule, Scope, SourceCode } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { AwaitSupport } from './await-support';\nimport { AstNode, AstNodeTypes, HOUSE_PLUGIN_NAMESPACE } from './common';\nimport { PromiseChainSupport } from './promise-chain-support';\n\nconst STATEMENT_LISTS = new Set(['BlockStatement', 'Program', 'StaticBlock', 'SwitchCase']);\n/** The catch variable the fix writes when the handler has no parameter. */\nconst CATCH_NAME = 'error';\n\n/** What the fix needs, read once from a `const x = await f().catch(h)` that passed every check. */\ninterface IFixPlan {\n declaration: Rule.Node;\n kind: string;\n name: string;\n annotation: string;\n receiverText: string;\n catchName: string;\n isErrorRead: boolean;\n valueText: string;\n}\n\n/** The identifiers a fallback value reads, and whether every node of it is a value the fix may move. */\nconst collectValue = (opts: {\n node: unknown;\n parameter: string | undefined;\n identifiers: unknown[];\n}): boolean => {\n const { node, parameter, identifiers } = opts;\n const type = AstNode.getType({ node }) ?? '';\n const value = (child: unknown) => collectValue({ node: child, parameter, identifiers });\n\n switch (type) {\n case 'Literal': {\n return true;\n }\n case 'Identifier': {\n identifiers.push(node);\n return true;\n }\n case 'TemplateLiteral': {\n return PromiseChainSupport.isConstant({ node });\n }\n case 'UnaryExpression': {\n return PromiseChainSupport.isConstant({ node });\n }\n case 'ChainExpression': {\n return value(AstNode.readField({ node, key: 'expression' }));\n }\n case 'MemberExpression': {\n // Only a read of the error itself: `error.message`, `error?.response.status`.\n const object = AstNode.readField({ node, key: 'object' });\n const isRead =\n AstNode.readField({ node, key: 'computed' }) !== true ||\n AstNode.getType({ node: AstNode.readField({ node, key: 'property' }) }) === 'Literal';\n const isRooted =\n AstNode.getType({ node: object }) === 'MemberExpression' ||\n (AstNode.getType({ node: object }) === 'Identifier' &&\n AstNode.readField({ node: object, key: 'name' }) === parameter);\n\n return isRead && isRooted && parameter !== undefined && value(object);\n }\n case 'ArrayExpression': {\n const elements = AstNode.readField({ node, key: 'elements' });\n return (\n Array.isArray(elements) && elements.every((element) => element === null || value(element))\n );\n }\n case 'ObjectExpression': {\n const properties = AstNode.readField({ node, key: 'properties' });\n return (\n Array.isArray(properties) &&\n properties.every(\n (property) =>\n AstNode.getType({ node: property }) === 'Property' &&\n AstNode.readField({ node: property, key: 'computed' }) !== true &&\n AstNode.readField({ node: property, key: 'method' }) !== true &&\n AstNode.readField({ node: property, key: 'kind' }) === 'init' &&\n value(AstNode.readField({ node: property, key: 'value' })),\n )\n );\n }\n default: {\n return false;\n }\n }\n};\n\n/** Whether `name` is declared in `scope` or any scope around it: a catch variable of that name would shadow it. */\nconst isDeclaredAround = (opts: { scope: Scope.Scope | null; name: string }): boolean => {\n for (let scope = opts.scope; scope; scope = scope.upper) {\n if (scope.set.has(opts.name)) {\n return true;\n }\n }\n\n return false;\n};\n\n/**\n * The plan of the fix for `awaitNode`, or `undefined` when the strict safe shape does not hold:\n * `const|let x[: T] = await f().catch(() => <value>)` or `.catch((error) => <value>)`, alone in its declaration,\n * in a statement list; `x` never written again and, without a type annotation, read only in its own function;\n * the handler an expression-bodied, non-async arrow with at most one plain parameter; `<value>` a literal, an\n * identifier, a read of the error (`error.message`) or an array or object literal of those; `f()` with no\n * `.then`, `.catch` or `.finally` before and no `await` inside; no comment the fix would drop.\n */\nconst planFix = (opts: { awaitNode: Rule.Node; sourceCode: SourceCode }): IFixPlan | undefined => {\n const { awaitNode, sourceCode } = opts;\n const call = AstNode.readField({ node: awaitNode, key: 'argument' });\n const callee = AstNode.readField({ node: call, key: 'callee' });\n const args = AstNode.readField({ node: call, key: 'arguments' });\n\n if (\n AstNode.getType({ node: call }) !== 'CallExpression' ||\n AstNode.readField({ node: call, key: 'optional' }) === true ||\n AstNode.getType({ node: callee }) !== 'MemberExpression' ||\n AstNode.readField({ node: callee, key: 'computed' }) === true ||\n AstNode.readField({ node: callee, key: 'optional' }) === true ||\n PromiseChainSupport.memberName({ member: callee }) !== 'catch' ||\n !Array.isArray(args) ||\n args.length !== 1\n ) {\n return undefined;\n }\n\n const handler: unknown = args[0];\n const params = AstNode.readField({ node: handler, key: 'params' });\n const body = AstNode.readField({ node: handler, key: 'body' });\n const parameter: unknown = Array.isArray(params) ? params[0] : undefined;\n\n if (\n AstNode.getType({ node: handler }) !== 'ArrowFunctionExpression' ||\n AstNode.readField({ node: handler, key: 'async' }) === true ||\n AstNode.getType({ node: body }) === 'BlockStatement' ||\n AstNode.readField({ node: handler, key: 'returnType' }) ||\n AstNode.readField({ node: handler, key: 'typeParameters' }) ||\n !Array.isArray(params) ||\n params.length > 1 ||\n (parameter !== undefined &&\n (AstNode.getType({ node: parameter }) !== 'Identifier' ||\n AstNode.readField({ node: parameter, key: 'typeAnnotation' }) ||\n AstNode.readField({ node: parameter, key: 'optional' }) === true))\n ) {\n return undefined;\n }\n\n const receiver = AstNode.readField({ node: callee, key: 'object' });\n if (\n !AwaitSupport.isNode(receiver) ||\n !AwaitSupport.isNode(body) ||\n !AwaitSupport.isNode(handler) ||\n PromiseChainSupport.hasChainOnSpine({ node: receiver }) ||\n /\\b(await|yield)\\b/.test(sourceCode.getText(receiver))\n ) {\n return undefined;\n }\n\n const declarator = AwaitSupport.parentOf({ node: awaitNode });\n const declaration = AwaitSupport.parentOf({ node: declarator });\n const id = AstNode.readField({ node: declarator, key: 'id' });\n const declarations = AstNode.readField({ node: declaration, key: 'declarations' });\n const kind = String(AstNode.readField({ node: declaration, key: 'kind' }));\n\n if (\n AstNode.getType({ node: declarator }) !== 'VariableDeclarator' ||\n AstNode.readField({ node: declarator, key: 'init' }) !== awaitNode ||\n AstNode.readField({ node: declarator, key: 'definite' }) === true ||\n AstNode.getType({ node: id }) !== 'Identifier' ||\n !AwaitSupport.isNode(declarator) ||\n !AwaitSupport.isNode(declaration) ||\n !Array.isArray(declarations) ||\n declarations.length !== 1 ||\n !['const', 'let'].includes(kind) ||\n !STATEMENT_LISTS.has(\n AstNode.getType({ node: AwaitSupport.parentOf({ node: declaration }) }) ?? '',\n )\n ) {\n return undefined;\n }\n\n const name = String(AstNode.readField({ node: id, key: 'name' }));\n const typeAnnotation = AstNode.readField({ node: id, key: 'typeAnnotation' });\n const annotation = AwaitSupport.isNode(typeAnnotation) ? sourceCode.getText(typeAnnotation) : '';\n\n // `let x;` with no annotation takes its type from the assignments that follow, so TypeScript must see every\n // read in the same function: a read from a nested function, an export or a `typeof` makes it an implicit any.\n const variable = sourceCode.getDeclaredVariables(declarator).find((entry) => entry.name === name);\n if (!variable) {\n return undefined;\n }\n for (const reference of variable.references) {\n if (reference.identifier === id) {\n continue;\n }\n const parentType = AstNode.getType({\n node: AwaitSupport.parentOf({ node: reference.identifier }),\n });\n if (\n reference.isWrite() ||\n (annotation === '' &&\n (reference.from.variableScope !== variable.scope.variableScope ||\n parentType === 'ExportSpecifier' ||\n parentType === 'TSTypeQuery'))\n ) {\n return undefined;\n }\n }\n\n const parameterName =\n parameter === undefined\n ? undefined\n : String(AstNode.readField({ node: parameter, key: 'name' }));\n const identifiers: unknown[] = [];\n if (!collectValue({ node: body, parameter: parameterName, identifiers })) {\n return undefined;\n }\n\n // `x = []` on a `let x;` with no annotation makes an evolving `any[]`, looser than the `never[]` it was.\n const elements = AstNode.readField({ node: body, key: 'elements' });\n if (\n annotation === '' &&\n AstNode.getType({ node: body }) === 'ArrayExpression' &&\n Array.isArray(elements) &&\n elements.length === 0\n ) {\n return undefined;\n }\n\n const parameterVariable = sourceCode\n .getDeclaredVariables(handler)\n .find((entry) => entry.name === parameterName);\n const errorReads = new Set<unknown>(\n parameterVariable?.references.map((reference) => reference.identifier) ?? [],\n );\n const freeNames = new Set(\n identifiers\n .filter((identifier) => !errorReads.has(identifier))\n .map((identifier) => String(AstNode.readField({ node: identifier, key: 'name' }))),\n );\n\n // The fallback is evaluated after the `let`: reading the declared name there would read `undefined`.\n if (freeNames.has(name)) {\n return undefined;\n }\n\n const scope = sourceCode.getScope(declaration);\n const isTaken = (candidate: string) =>\n candidate === name ||\n freeNames.has(candidate) ||\n (candidate !== parameterName && isDeclaredAround({ scope, name: candidate }));\n const base = parameterName ?? CATCH_NAME;\n let catchName = base;\n for (let index = 2; isTaken(catchName); index += 1) {\n catchName = `${base}${index}`;\n }\n\n const comments = sourceCode.getCommentsInside(declaration);\n const isInside = (range: [number, number] | undefined, inner: [number, number] | undefined) =>\n range !== undefined && inner !== undefined && range[0] <= inner[0] && inner[1] <= range[1];\n if (\n comments.some(\n (comment) => !isInside(receiver.range, comment.range) && !isInside(body.range, comment.range),\n )\n ) {\n return undefined;\n }\n\n const bodyStart = body.range?.[0] ?? 0;\n let valueText = sourceCode.getText(body);\n if (catchName !== parameterName && errorReads.size > 0) {\n const edits = [...errorReads]\n .filter(AwaitSupport.isNode)\n .map((identifier) => {\n const parent = AwaitSupport.parentOf({ node: identifier });\n const isShorthand =\n AstNode.getType({ node: parent }) === 'Property' &&\n AstNode.readField({ node: parent, key: 'shorthand' }) === true;\n\n return {\n range: identifier.range ?? [0, 0],\n text: isShorthand ? `${parameterName}: ${catchName}` : catchName,\n };\n })\n .sort((left, right) => right.range[0] - left.range[0]);\n\n for (const edit of edits) {\n valueText =\n valueText.slice(0, edit.range[0] - bodyStart) +\n edit.text +\n valueText.slice(edit.range[1] - bodyStart);\n }\n }\n\n return {\n declaration,\n kind,\n name,\n annotation,\n receiverText: sourceCode.getText(receiver),\n catchName,\n isErrorRead: errorReads.size > 0,\n valueText,\n };\n};\n\n/**\n * `venizia/no-await-promise-chain`. One expression uses one async style: `await` (in a try/catch when it can\n * fail), or a promise chain that is not awaited. An `await` whose operand - after parentheses, `!`, `as`,\n * `satisfies` and an optional chain - is a call of `.then`, `.catch` or `.finally` (`?.then(`, `['then'](`, a\n * thenable such as a query builder) is reported once, however long the chain. A chain that is returned or stands\n * as a statement is not awaited and is not reported, nor is `await Promise.all(xs.map(f))`, `await new Promise(...)`,\n * `await x.then` (no call), or an `await` inside a callback of a chain.\n *\n * The fix is made for one shape only, `const|let x = await f().catch(() => <value>)` (see `planFix` for every\n * condition), and writes `let x; try { x = await f(); } catch (error) { x = <value>; }` (`catch { ... }` when the value does not read the error): the `const` becomes a\n * `let`, a type annotation stays, the catch variable takes the handler's parameter name (`error` without one,\n * renamed when the name is taken), and is typed `any` when the value reads it, as the handler's parameter was.\n * The try also catches a synchronous throw of `f()`, which the chain let through. Everything else is reported.\n */\nexport class NoAwaitPromiseChainRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/no-await-promise-chain`;\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n fixable: 'code',\n schema: [],\n messages: {\n mixed:\n 'Do not `await` a promise chain (`.{{method}}(...)`): wrap `await f()` in try/catch, or drop the `await` and keep the chain.',\n mixedConst:\n 'Do not `await` a promise chain (`.{{method}}(...)`): wrap `await f()` in try/catch, or drop the `await` and keep the chain. The fix writes the try/catch and turns the `const` into a `let`.',\n },\n },\n create: (context) => {\n const { sourceCode } = context;\n\n return {\n [AstNodeTypes.AWAIT_EXPRESSION]: (node: Rule.Node) => {\n const method = PromiseChainSupport.chainMethodOf({\n node: AstNode.readField({ node, key: 'argument' }),\n });\n if (method === undefined) {\n return;\n }\n\n const plan = planFix({ awaitNode: node, sourceCode });\n\n context.report({\n node,\n messageId: plan?.kind === 'const' ? 'mixedConst' : 'mixed',\n data: { method },\n fix: plan\n ? (fixer) => {\n const indent = AwaitSupport.indentOf({ node: plan.declaration, sourceCode });\n const inner = `${indent} `;\n // The optional catch binding when nothing reads the error: a named one would be an unused variable.\n const head = plan.isErrorRead ? `catch (${plan.catchName}: any)` : 'catch';\n\n return fixer.replaceText(\n plan.declaration,\n [\n `let ${plan.name}${plan.annotation};`,\n `${indent}try {`,\n `${inner}${plan.name} = await ${plan.receiverText};`,\n `${indent}} ${head} {`,\n `${inner}${plan.name} = ${plan.valueText};`,\n `${indent}}`,\n ].join('\\n'),\n );\n }\n : null,\n });\n },\n };\n },\n };\n\n static build(opts: { severity?: TRuleSeverity } = {}): TRuleSeverity {\n return opts.severity ?? 'error';\n }\n}\n"]}
1
+ {"version":3,"file":"no-await-promise-chain.rule.js","sourceRoot":"","sources":["../../../src/linters/house/no-await-promise-chain.rule.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Rule, Scope, SourceCode } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { AwaitSupport, STATEMENT_LISTS } from './await-support';\nimport { AstNode, AstNodeTypes, HOUSE_PLUGIN_NAMESPACE } from './common';\nimport { PromiseChainSupport } from './promise-chain-support';\n\n/** The catch variable the fix writes when the handler has no parameter. */\nconst CATCH_NAME = 'error';\n\n/** What the fix needs, read once from a `const x = await f().catch(h)` that passed every check. */\ninterface IFixPlan {\n declaration: Rule.Node;\n kind: string;\n name: string;\n annotation: string;\n receiverText: string;\n catchName: string;\n isErrorRead: boolean;\n valueText: string;\n}\n\n/** The identifiers a fallback value reads, and whether every node of it is a value the fix may move. */\nconst collectValue = (opts: {\n node: unknown;\n parameter: string | undefined;\n identifiers: unknown[];\n}): boolean => {\n const { node, parameter, identifiers } = opts;\n const type = AstNode.getType({ node }) ?? '';\n const value = (child: unknown) => collectValue({ node: child, parameter, identifiers });\n\n switch (type) {\n case 'Literal': {\n return true;\n }\n case 'Identifier': {\n identifiers.push(node);\n\n return true;\n }\n case 'TemplateLiteral': {\n return PromiseChainSupport.isConstant({ node });\n }\n case 'UnaryExpression': {\n return PromiseChainSupport.isConstant({ node });\n }\n case 'ChainExpression': {\n return value(AstNode.readField({ node, key: 'expression' }));\n }\n case 'MemberExpression': {\n // Only a read of the error itself: `error.message`, `error?.response.status`.\n const object = AstNode.readField({ node, key: 'object' });\n const isRead =\n AstNode.readField({ node, key: 'computed' }) !== true ||\n AstNode.getType({ node: AstNode.readField({ node, key: 'property' }) }) === 'Literal';\n const isRooted =\n AstNode.getType({ node: object }) === 'MemberExpression' ||\n (AstNode.getType({ node: object }) === 'Identifier' &&\n AstNode.readField({ node: object, key: 'name' }) === parameter);\n\n return isRead && isRooted && parameter !== undefined && value(object);\n }\n case 'ArrayExpression': {\n const elements = AstNode.readField({ node, key: 'elements' });\n\n return (\n Array.isArray(elements) && elements.every((element) => element === null || value(element))\n );\n }\n case 'ObjectExpression': {\n const properties = AstNode.readField({ node, key: 'properties' });\n\n return (\n Array.isArray(properties) &&\n properties.every(\n (property) =>\n AstNode.getType({ node: property }) === 'Property' &&\n AstNode.readField({ node: property, key: 'computed' }) !== true &&\n AstNode.readField({ node: property, key: 'method' }) !== true &&\n AstNode.readField({ node: property, key: 'kind' }) === 'init' &&\n value(AstNode.readField({ node: property, key: 'value' })),\n )\n );\n }\n default: {\n return false;\n }\n }\n};\n\n/** Whether `name` is declared in `scope` or any scope around it: a catch variable of that name would shadow it. */\nconst isDeclaredAround = (opts: { scope: Scope.Scope | null; name: string }): boolean => {\n for (let scope = opts.scope; scope; scope = scope.upper) {\n if (scope.set.has(opts.name)) {\n return true;\n }\n }\n\n return false;\n};\n\n/**\n * The plan of the fix for `awaitNode`, or `undefined` when the strict safe shape does not hold:\n * `const|let x[: T] = await f().catch(() => <value>)` or `.catch((error) => <value>)`, alone in its declaration,\n * in a statement list; `x` never written again and, without a type annotation, read only in its own function;\n * the handler an expression-bodied, non-async arrow with at most one plain parameter; `<value>` a literal, an\n * identifier, a read of the error (`error.message`) or an array or object literal of those; `f()` with no\n * `.then`, `.catch` or `.finally` before and no `await` inside; no comment the fix would drop.\n */\nconst planFix = (opts: { awaitNode: Rule.Node; sourceCode: SourceCode }): IFixPlan | undefined => {\n const { awaitNode, sourceCode } = opts;\n const call = AstNode.readField({ node: awaitNode, key: 'argument' });\n const callee = AstNode.readField({ node: call, key: 'callee' });\n const args = AstNode.readField({ node: call, key: 'arguments' });\n\n if (\n AstNode.getType({ node: call }) !== 'CallExpression' ||\n AstNode.readField({ node: call, key: 'optional' }) === true ||\n AstNode.getType({ node: callee }) !== 'MemberExpression' ||\n AstNode.readField({ node: callee, key: 'computed' }) === true ||\n AstNode.readField({ node: callee, key: 'optional' }) === true ||\n PromiseChainSupport.memberName({ member: callee }) !== 'catch' ||\n !Array.isArray(args) ||\n args.length !== 1\n ) {\n return undefined;\n }\n\n const handler: unknown = args[0];\n const params = AstNode.readField({ node: handler, key: 'params' });\n const body = AstNode.readField({ node: handler, key: 'body' });\n const parameter: unknown = Array.isArray(params) ? params[0] : undefined;\n\n if (\n AstNode.getType({ node: handler }) !== 'ArrowFunctionExpression' ||\n AstNode.readField({ node: handler, key: 'async' }) === true ||\n AstNode.getType({ node: body }) === AstNodeTypes.BLOCK_STATEMENT ||\n AstNode.readField({ node: handler, key: 'returnType' }) ||\n AstNode.readField({ node: handler, key: 'typeParameters' }) ||\n !Array.isArray(params) ||\n params.length > 1 ||\n (parameter !== undefined &&\n (AstNode.getType({ node: parameter }) !== 'Identifier' ||\n AstNode.readField({ node: parameter, key: 'typeAnnotation' }) ||\n AstNode.readField({ node: parameter, key: 'optional' }) === true))\n ) {\n return undefined;\n }\n\n const receiver = AstNode.readField({ node: callee, key: 'object' });\n\n if (\n !AwaitSupport.isNode(receiver) ||\n !AwaitSupport.isNode(body) ||\n !AwaitSupport.isNode(handler) ||\n PromiseChainSupport.hasChainOnSpine({ node: receiver }) ||\n /\\b(await|yield)\\b/.test(sourceCode.getText(receiver))\n ) {\n return undefined;\n }\n\n const declarator = AwaitSupport.parentOf({ node: awaitNode });\n const declaration = AwaitSupport.parentOf({ node: declarator });\n const id = AstNode.readField({ node: declarator, key: 'id' });\n const declarations = AstNode.readField({ node: declaration, key: 'declarations' });\n const kind = String(AstNode.readField({ node: declaration, key: 'kind' }));\n\n if (\n AstNode.getType({ node: declarator }) !== 'VariableDeclarator' ||\n AstNode.readField({ node: declarator, key: 'init' }) !== awaitNode ||\n AstNode.readField({ node: declarator, key: 'definite' }) === true ||\n AstNode.getType({ node: id }) !== 'Identifier' ||\n !AwaitSupport.isNode(declarator) ||\n !AwaitSupport.isNode(declaration) ||\n !Array.isArray(declarations) ||\n declarations.length !== 1 ||\n !['const', 'let'].includes(kind) ||\n !STATEMENT_LISTS.has(\n AstNode.getType({ node: AwaitSupport.parentOf({ node: declaration }) }) ?? '',\n )\n ) {\n return undefined;\n }\n\n const name = String(AstNode.readField({ node: id, key: 'name' }));\n const typeAnnotation = AstNode.readField({ node: id, key: 'typeAnnotation' });\n const annotation = AwaitSupport.isNode(typeAnnotation) ? sourceCode.getText(typeAnnotation) : '';\n\n // `let x;` with no annotation takes its type from the assignments that follow, so TypeScript must see every\n // read in the same function: a read from a nested function, an export or a `typeof` makes it an implicit any.\n const variable = sourceCode.getDeclaredVariables(declarator).find((entry) => entry.name === name);\n\n if (!variable) {\n return undefined;\n }\n\n for (const reference of variable.references) {\n if (reference.identifier === id) {\n continue;\n }\n\n const parentType = AstNode.getType({\n node: AwaitSupport.parentOf({ node: reference.identifier }),\n });\n\n if (\n reference.isWrite() ||\n (annotation === '' &&\n (reference.from.variableScope !== variable.scope.variableScope ||\n parentType === 'ExportSpecifier' ||\n parentType === 'TSTypeQuery'))\n ) {\n return undefined;\n }\n }\n\n const parameterName =\n parameter === undefined\n ? undefined\n : String(AstNode.readField({ node: parameter, key: 'name' }));\n const identifiers: unknown[] = [];\n\n if (!collectValue({ node: body, parameter: parameterName, identifiers })) {\n return undefined;\n }\n\n // `x = []` on a `let x;` with no annotation makes an evolving `any[]`, looser than the `never[]` it was.\n const elements = AstNode.readField({ node: body, key: 'elements' });\n\n if (\n annotation === '' &&\n AstNode.getType({ node: body }) === 'ArrayExpression' &&\n Array.isArray(elements) &&\n elements.length === 0\n ) {\n return undefined;\n }\n\n const parameterVariable = sourceCode\n .getDeclaredVariables(handler)\n .find((entry) => entry.name === parameterName);\n const errorReads = new Set<unknown>(\n parameterVariable?.references.map((reference) => reference.identifier) ?? [],\n );\n const freeNames = new Set(\n identifiers\n .filter((identifier) => !errorReads.has(identifier))\n .map((identifier) => String(AstNode.readField({ node: identifier, key: 'name' }))),\n );\n\n // The fallback is evaluated after the `let`: reading the declared name there would read `undefined`.\n if (freeNames.has(name)) {\n return undefined;\n }\n\n const scope = sourceCode.getScope(declaration);\n const isTaken = (candidate: string) =>\n candidate === name ||\n freeNames.has(candidate) ||\n (candidate !== parameterName && isDeclaredAround({ scope, name: candidate }));\n const base = parameterName ?? CATCH_NAME;\n let catchName = base;\n\n for (let index = 2; isTaken(catchName); index += 1) {\n catchName = `${base}${index}`;\n }\n\n const comments = sourceCode.getCommentsInside(declaration);\n const isInside = (range: [number, number] | undefined, inner: [number, number] | undefined) =>\n range !== undefined && inner !== undefined && range[0] <= inner[0] && inner[1] <= range[1];\n\n if (\n comments.some(\n (comment) => !isInside(receiver.range, comment.range) && !isInside(body.range, comment.range),\n )\n ) {\n return undefined;\n }\n\n const bodyStart = body.range?.[0] ?? 0;\n let valueText = sourceCode.getText(body);\n\n if (catchName !== parameterName && errorReads.size > 0) {\n const edits = [...errorReads]\n .filter(AwaitSupport.isNode)\n .map((identifier) => {\n const parent = AwaitSupport.parentOf({ node: identifier });\n const isShorthand =\n AstNode.getType({ node: parent }) === 'Property' &&\n AstNode.readField({ node: parent, key: 'shorthand' }) === true;\n\n return {\n range: identifier.range ?? [0, 0],\n text: isShorthand ? `${parameterName}: ${catchName}` : catchName,\n };\n })\n .sort((left, right) => right.range[0] - left.range[0]);\n\n for (const edit of edits) {\n valueText =\n valueText.slice(0, edit.range[0] - bodyStart) +\n edit.text +\n valueText.slice(edit.range[1] - bodyStart);\n }\n }\n\n return {\n declaration,\n kind,\n name,\n annotation,\n receiverText: sourceCode.getText(receiver),\n catchName,\n isErrorRead: errorReads.size > 0,\n valueText,\n };\n};\n\n/**\n * `venizia/no-await-promise-chain`. One expression uses one async style: `await` (in a try/catch when it can\n * fail), or a promise chain that is not awaited. An `await` whose operand - after parentheses, `!`, `as`,\n * `satisfies` and an optional chain - is a call of `.then`, `.catch` or `.finally` (`?.then(`, `['then'](`, a\n * thenable such as a query builder) is reported once, however long the chain. A chain that is returned or stands\n * as a statement is not awaited and is not reported, nor is `await Promise.all(xs.map(f))`, `await new Promise(...)`,\n * `await x.then` (no call), or an `await` inside a callback of a chain.\n *\n * The fix is made for one shape only, `const|let x = await f().catch(() => <value>)` (see `planFix` for every\n * condition), and writes `let x; try { x = await f(); } catch (error) { x = <value>; }` (`catch { ... }` when the value does not read the error): the `const` becomes a\n * `let`, a type annotation stays, the catch variable takes the handler's parameter name (`error` without one,\n * renamed when the name is taken), and is typed `any` when the value reads it, as the handler's parameter was.\n * The try also catches a synchronous throw of `f()`, which the chain let through. Everything else is reported.\n */\nexport class NoAwaitPromiseChainRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/no-await-promise-chain`;\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n fixable: 'code',\n schema: [],\n messages: {\n mixed:\n 'Do not `await` a promise chain (`.{{method}}(...)`): wrap `await f()` in try/catch, or drop the `await` and keep the chain.',\n mixedConst:\n 'Do not `await` a promise chain (`.{{method}}(...)`): wrap `await f()` in try/catch, or drop the `await` and keep the chain. The fix writes the try/catch and turns the `const` into a `let`.',\n },\n },\n create: (context) => {\n const { sourceCode } = context;\n\n return {\n [AstNodeTypes.AWAIT_EXPRESSION]: (node: Rule.Node) => {\n const method = PromiseChainSupport.chainMethodOf({\n node: AstNode.readField({ node, key: 'argument' }),\n });\n\n if (method === undefined) {\n return;\n }\n\n const plan = planFix({ awaitNode: node, sourceCode });\n\n context.report({\n node,\n messageId: plan?.kind === 'const' ? 'mixedConst' : 'mixed',\n data: { method },\n fix: plan\n ? (fixer) => {\n const indent = AwaitSupport.indentOf({ node: plan.declaration, sourceCode });\n const inner = `${indent} `;\n // The optional catch binding when nothing reads the error: a named one would be an unused variable.\n const head = plan.isErrorRead ? `catch (${plan.catchName}: any)` : 'catch';\n\n return fixer.replaceText(\n plan.declaration,\n [\n `let ${plan.name}${plan.annotation};`,\n `${indent}try {`,\n `${inner}${plan.name} = await ${plan.receiverText};`,\n `${indent}} ${head} {`,\n `${inner}${plan.name} = ${plan.valueText};`,\n `${indent}}`,\n ].join('\\n'),\n );\n }\n : null,\n });\n },\n };\n },\n };\n\n static build(opts: { severity?: TRuleSeverity } = {}): TRuleSeverity {\n return opts.severity ?? 'error';\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"no-leaked-render.rule.js","sourceRoot":"","sources":["../../../src/linters/house/no-leaked-render.rule.ts"],"names":[],"mappings":";;;AAEA,qCAAkD;AAElD,4FAA4F;AAC5F,MAAM,sBAAsB,GAAG,CAAC,YAAY,EAAE,aAAa,CAAC;KACzD,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,MAAM,8DAA8D,CAAC;KACxF,IAAI,CAAC,IAAI,CAAC,CAAC;AAEd;;;;GAIG;AACH,MAAa,kBAAkB;aACb,SAAI,GAAG,GAAG,+BAAsB,mBAAmB,CAAC;aAEpD,SAAI,GAAoB;QACtC,IAAI,EAAE;YACJ,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,EAAE;YACV,QAAQ,EAAE;gBACR,MAAM,EAAE,uEAAuE;aAChF;SACF;QACD,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACpB,CAAC,sBAAsB,CAAC,EAAE,CAAC,IAAe,EAAE,EAAE;gBAC5C,IAAI,IAAI,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;oBACtC,OAAO;gBACT,CAAC;gBAED,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;gBAClC,MAAM,QAAQ,GAAG,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;gBAClF,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,OAAO;gBACT,CAAC;gBAED,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC3E,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI;oBACJ,SAAS,EAAE,QAAQ;oBACnB,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC;iBAC1F,CAAC,CAAC;YACL,CAAC;SACF,CAAC;KACH,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,OAAqC,EAAE;QAClD,OAAO,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC;IAClC,CAAC;;AApCH,gDAqCC","sourcesContent":["import type { Rule } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { HOUSE_PLUGIN_NAMESPACE } from './common';\n\n/** `&&` directly under a JSX child: `disabled={a && b}` is a value, not something drawn. */\nconst LEAKED_RENDER_SELECTOR = ['JSXElement', 'JSXFragment']\n .map((parent) => `${parent} > JSXExpressionContainer > LogicalExpression[operator='&&']`)\n .join(', ');\n\n/**\n * `venizia/no-leaked-render`. `{count && <X />}` draws `0` when `count` is `0`; draw nothing with\n * `cond ? <X /> : null`. Only a child of JSX is checked. The fix rewrites it to the ternary and keeps\n * any comment between `&&` and the drawn part.\n */\nexport class NoLeakedRenderRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/no-leaked-render`;\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'problem',\n fixable: 'code',\n schema: [],\n messages: {\n leaked: 'Draw nothing with `cond ? <X /> : null`; `&&` draws 0 when cond is 0.',\n },\n },\n create: (context) => ({\n [LEAKED_RENDER_SELECTOR]: (node: Rule.Node) => {\n if (node.type !== 'LogicalExpression') {\n return;\n }\n\n const source = context.sourceCode;\n const operator = source.getTokenAfter(node.left, (token) => token.value === '&&');\n if (!operator) {\n return;\n }\n\n const drawn = source.text.slice(operator.range[1], node.range?.[1]).trim();\n context.report({\n node,\n messageId: 'leaked',\n fix: (fixer) => fixer.replaceText(node, `${source.getText(node.left)} ? ${drawn} : null`),\n });\n },\n }),\n };\n\n static build(opts: { severity?: TRuleSeverity } = {}): TRuleSeverity {\n return opts.severity ?? 'error';\n }\n}\n"]}
1
+ {"version":3,"file":"no-leaked-render.rule.js","sourceRoot":"","sources":["../../../src/linters/house/no-leaked-render.rule.ts"],"names":[],"mappings":";;;AAEA,qCAAkD;AAElD,4FAA4F;AAC5F,MAAM,sBAAsB,GAAG,CAAC,YAAY,EAAE,aAAa,CAAC;KACzD,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,MAAM,8DAA8D,CAAC;KACxF,IAAI,CAAC,IAAI,CAAC,CAAC;AAEd;;;;GAIG;AACH,MAAa,kBAAkB;aACb,SAAI,GAAG,GAAG,+BAAsB,mBAAmB,CAAC;aAEpD,SAAI,GAAoB;QACtC,IAAI,EAAE;YACJ,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,EAAE;YACV,QAAQ,EAAE;gBACR,MAAM,EAAE,uEAAuE;aAChF;SACF;QACD,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACpB,CAAC,sBAAsB,CAAC,EAAE,CAAC,IAAe,EAAE,EAAE;gBAC5C,IAAI,IAAI,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;oBACtC,OAAO;gBACT,CAAC;gBAED,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;gBAClC,MAAM,QAAQ,GAAG,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;gBAElF,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,OAAO;gBACT,CAAC;gBAED,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC3E,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI;oBACJ,SAAS,EAAE,QAAQ;oBACnB,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC;iBAC1F,CAAC,CAAC;YACL,CAAC;SACF,CAAC;KACH,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,OAAqC,EAAE;QAClD,OAAO,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC;IAClC,CAAC;;AArCH,gDAsCC","sourcesContent":["import type { Rule } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { HOUSE_PLUGIN_NAMESPACE } from './common';\n\n/** `&&` directly under a JSX child: `disabled={a && b}` is a value, not something drawn. */\nconst LEAKED_RENDER_SELECTOR = ['JSXElement', 'JSXFragment']\n .map((parent) => `${parent} > JSXExpressionContainer > LogicalExpression[operator='&&']`)\n .join(', ');\n\n/**\n * `venizia/no-leaked-render`. `{count && <X />}` draws `0` when `count` is `0`; draw nothing with\n * `cond ? <X /> : null`. Only a child of JSX is checked. The fix rewrites it to the ternary and keeps\n * any comment between `&&` and the drawn part.\n */\nexport class NoLeakedRenderRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/no-leaked-render`;\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'problem',\n fixable: 'code',\n schema: [],\n messages: {\n leaked: 'Draw nothing with `cond ? <X /> : null`; `&&` draws 0 when cond is 0.',\n },\n },\n create: (context) => ({\n [LEAKED_RENDER_SELECTOR]: (node: Rule.Node) => {\n if (node.type !== 'LogicalExpression') {\n return;\n }\n\n const source = context.sourceCode;\n const operator = source.getTokenAfter(node.left, (token) => token.value === '&&');\n\n if (!operator) {\n return;\n }\n\n const drawn = source.text.slice(operator.range[1], node.range?.[1]).trim();\n context.report({\n node,\n messageId: 'leaked',\n fix: (fixer) => fixer.replaceText(node, `${source.getText(node.left)} ? ${drawn} : null`),\n });\n },\n }),\n };\n\n static build(opts: { severity?: TRuleSeverity } = {}): TRuleSeverity {\n return opts.severity ?? 'error';\n }\n}\n"]}
@@ -3,16 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NoReturnAwaitRule = void 0;
4
4
  const await_support_1 = require("./await-support");
5
5
  const common_1 = require("./common");
6
- const FUNCTION_TYPES = new Set([
7
- 'FunctionDeclaration',
8
- 'FunctionExpression',
9
- 'ArrowFunctionExpression',
10
- ]);
11
- const STATEMENT_LISTS = new Set(['BlockStatement', 'Program', 'StaticBlock', 'SwitchCase']);
12
6
  /** `node` sits inside a `try`, `catch` or `finally` of its own function. */
13
7
  const isInTry = (node) => {
14
8
  let current = await_support_1.AwaitSupport.parentOf({ node });
15
- while (current && !FUNCTION_TYPES.has(common_1.AstNode.getType({ node: current }) ?? '')) {
9
+ while (current && !await_support_1.FUNCTION_TYPES.has(common_1.AstNode.getType({ node: current }) ?? '')) {
16
10
  if (common_1.AstNode.getType({ node: current }) === 'TryStatement') {
17
11
  return true;
18
12
  }
@@ -54,7 +48,7 @@ class NoReturnAwaitRule {
54
48
  return fixer.replaceText(opts.awaitNode, argumentText);
55
49
  }
56
50
  const outer = await_support_1.AwaitSupport.parentOf({ node: opts.statement });
57
- if (!STATEMENT_LISTS.has(common_1.AstNode.getType({ node: outer }) ?? '')) {
51
+ if (!await_support_1.STATEMENT_LISTS.has(common_1.AstNode.getType({ node: outer }) ?? '')) {
58
52
  return null;
59
53
  }
60
54
  const name = await_support_1.AwaitSupport.freshName({
@@ -1 +1 @@
1
- {"version":3,"file":"no-return-await.rule.js","sourceRoot":"","sources":["../../../src/linters/house/no-return-await.rule.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Rule } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { AwaitSupport } from './await-support';\nimport { AstNode, AstNodeTypes, HOUSE_PLUGIN_NAMESPACE } from './common';\n\nconst FUNCTION_TYPES = new Set([\n 'FunctionDeclaration',\n 'FunctionExpression',\n 'ArrowFunctionExpression',\n]);\nconst STATEMENT_LISTS = new Set(['BlockStatement', 'Program', 'StaticBlock', 'SwitchCase']);\n\n/** `node` sits inside a `try`, `catch` or `finally` of its own function. */\nconst isInTry = (node: unknown): boolean => {\n let current = AwaitSupport.parentOf({ node });\n\n while (current && !FUNCTION_TYPES.has(AstNode.getType({ node: current }) ?? '')) {\n if (AstNode.getType({ node: current }) === 'TryStatement') {\n return true;\n }\n current = AwaitSupport.parentOf({ node: current });\n }\n\n return false;\n};\n\n/**\n * `venizia/no-return-await`. A function returns the promise (`return f()`), never `return await f()`. Where the\n * `await` matters (inside `try`, `catch` or `finally`) it is written on its own line:\n * `const result = await f(); return result;`. An arrow whose body is an `await` is the same: `() => f()`.\n */\nexport class NoReturnAwaitRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/no-return-await`;\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n fixable: 'code',\n schema: [],\n messages: {\n returnAwait:\n 'Return the promise (`return f()`), not `return await f()`; where the await matters (inside try, catch or finally) write `const result = await f(); return result;`.',\n },\n },\n create: (context) => {\n const { sourceCode } = context;\n\n const reportAwait = (opts: {\n reported: Rule.Node;\n awaitNode: Rule.Node;\n statement?: Rule.Node;\n }) => {\n const argument = AstNode.readField({ node: opts.awaitNode, key: 'argument' });\n const argumentText =\n AwaitSupport.isNode(argument) &&\n AstNode.getType({ node: argument }) !== 'SequenceExpression'\n ? sourceCode.getText(argument)\n : undefined;\n\n context.report({\n node: opts.reported,\n messageId: 'returnAwait',\n fix:\n argumentText === undefined\n ? null\n : (fixer) => {\n if (!opts.statement || !isInTry(opts.statement)) {\n return fixer.replaceText(opts.awaitNode, argumentText);\n }\n\n const outer = AwaitSupport.parentOf({ node: opts.statement });\n if (!STATEMENT_LISTS.has(AstNode.getType({ node: outer }) ?? '')) {\n return null;\n }\n\n const name = AwaitSupport.freshName({\n node: opts.statement,\n base: 'result',\n sourceCode,\n });\n const indent = AwaitSupport.indentOf({ node: opts.statement, sourceCode });\n\n return fixer.replaceText(\n opts.statement,\n `const ${name} = await ${argumentText};\\n${indent}return ${name};`,\n );\n },\n });\n };\n\n return {\n [AstNodeTypes.RETURN_STATEMENT]: (node: Rule.Node) => {\n const argument = AstNode.readField({ node, key: 'argument' });\n if (\n AwaitSupport.isNode(argument) &&\n AstNode.getType({ node: argument }) === 'AwaitExpression'\n ) {\n reportAwait({ reported: node, awaitNode: argument, statement: node });\n }\n },\n [AstNodeTypes.ARROW_FUNCTION_EXPRESSION]: (node: Rule.Node) => {\n const body = AstNode.readField({ node, key: 'body' });\n if (AwaitSupport.isNode(body) && AstNode.getType({ node: body }) === 'AwaitExpression') {\n reportAwait({ reported: node, awaitNode: body });\n }\n },\n };\n },\n };\n\n static build(opts: { severity?: TRuleSeverity } = {}): TRuleSeverity {\n return opts.severity ?? 'error';\n }\n}\n"]}
1
+ {"version":3,"file":"no-return-await.rule.js","sourceRoot":"","sources":["../../../src/linters/house/no-return-await.rule.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Rule } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { AwaitSupport, FUNCTION_TYPES, STATEMENT_LISTS } from './await-support';\nimport { AstNode, AstNodeTypes, HOUSE_PLUGIN_NAMESPACE } from './common';\n\n/** `node` sits inside a `try`, `catch` or `finally` of its own function. */\nconst isInTry = (node: unknown): boolean => {\n let current = AwaitSupport.parentOf({ node });\n\n while (current && !FUNCTION_TYPES.has(AstNode.getType({ node: current }) ?? '')) {\n if (AstNode.getType({ node: current }) === 'TryStatement') {\n return true;\n }\n\n current = AwaitSupport.parentOf({ node: current });\n }\n\n return false;\n};\n\n/**\n * `venizia/no-return-await`. A function returns the promise (`return f()`), never `return await f()`. Where the\n * `await` matters (inside `try`, `catch` or `finally`) it is written on its own line:\n * `const result = await f(); return result;`. An arrow whose body is an `await` is the same: `() => f()`.\n */\nexport class NoReturnAwaitRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/no-return-await`;\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n fixable: 'code',\n schema: [],\n messages: {\n returnAwait:\n 'Return the promise (`return f()`), not `return await f()`; where the await matters (inside try, catch or finally) write `const result = await f(); return result;`.',\n },\n },\n create: (context) => {\n const { sourceCode } = context;\n\n const reportAwait = (opts: {\n reported: Rule.Node;\n awaitNode: Rule.Node;\n statement?: Rule.Node;\n }) => {\n const argument = AstNode.readField({ node: opts.awaitNode, key: 'argument' });\n const argumentText =\n AwaitSupport.isNode(argument) &&\n AstNode.getType({ node: argument }) !== 'SequenceExpression'\n ? sourceCode.getText(argument)\n : undefined;\n\n context.report({\n node: opts.reported,\n messageId: 'returnAwait',\n fix:\n argumentText === undefined\n ? null\n : (fixer) => {\n if (!opts.statement || !isInTry(opts.statement)) {\n return fixer.replaceText(opts.awaitNode, argumentText);\n }\n\n const outer = AwaitSupport.parentOf({ node: opts.statement });\n\n if (!STATEMENT_LISTS.has(AstNode.getType({ node: outer }) ?? '')) {\n return null;\n }\n\n const name = AwaitSupport.freshName({\n node: opts.statement,\n base: 'result',\n sourceCode,\n });\n const indent = AwaitSupport.indentOf({ node: opts.statement, sourceCode });\n\n return fixer.replaceText(\n opts.statement,\n `const ${name} = await ${argumentText};\\n${indent}return ${name};`,\n );\n },\n });\n };\n\n return {\n [AstNodeTypes.RETURN_STATEMENT]: (node: Rule.Node) => {\n const argument = AstNode.readField({ node, key: 'argument' });\n\n if (\n AwaitSupport.isNode(argument) &&\n AstNode.getType({ node: argument }) === 'AwaitExpression'\n ) {\n reportAwait({ reported: node, awaitNode: argument, statement: node });\n }\n },\n [AstNodeTypes.ARROW_FUNCTION_EXPRESSION]: (node: Rule.Node) => {\n const body = AstNode.readField({ node, key: 'body' });\n\n if (AwaitSupport.isNode(body) && AstNode.getType({ node: body }) === 'AwaitExpression') {\n reportAwait({ reported: node, awaitNode: body });\n }\n },\n };\n },\n };\n\n static build(opts: { severity?: TRuleSeverity } = {}): TRuleSeverity {\n return opts.severity ?? 'error';\n }\n}\n"]}
@@ -56,7 +56,7 @@ class NoSilentCatchRule {
56
56
  return;
57
57
  }
58
58
  const body = common_1.AstNode.readField({ node: handler, key: 'body' });
59
- const isSilent = common_1.AstNode.getType({ node: body }) === 'BlockStatement'
59
+ const isSilent = common_1.AstNode.getType({ node: body }) === common_1.AstNodeTypes.BLOCK_STATEMENT
60
60
  ? promise_chain_support_1.PromiseChainSupport.isSilentBlock({
61
61
  statements: common_1.AstNode.readField({ node: body, key: 'body' }),
62
62
  })
@@ -1 +1 @@
1
- {"version":3,"file":"no-silent-catch.rule.js","sourceRoot":"","sources":["../../../src/linters/house/no-silent-catch.rule.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Rule, SourceCode } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { AwaitSupport } from './await-support';\nimport { AstNode, AstNodeTypes, HOUSE_PLUGIN_NAMESPACE } from './common';\nimport { PromiseChainSupport } from './promise-chain-support';\n\n/** Whether a parameter of `owner` (a function or a catch clause) is read or written anywhere. */\nconst isParameterUsed = (opts: { owner: Rule.Node; sourceCode: SourceCode }): boolean =>\n opts.sourceCode\n .getDeclaredVariables(opts.owner)\n .some(\n (variable) =>\n variable.defs.some((definition) =>\n ['Parameter', 'CatchClause'].includes(definition.type),\n ) && variable.references.length > 0,\n );\n\n/** A parameter that is not a plain name (`({ message }) =>`, `catch ({ message })`) reads the error by itself. */\nconst isPlainParameter = (opts: { parameter: unknown }): boolean =>\n opts.parameter === null ||\n opts.parameter === undefined ||\n AstNode.getType({ node: opts.parameter }) === 'Identifier';\n\n/**\n * `venizia/no-silent-catch`. A handled error leaves a trace (V-C-06). Reported: a `.catch(h)` (also `?.catch`,\n * `['catch']`) whose handler is an arrow or function expression that ignores its parameter and whose body is empty\n * or only gives back a constant (`() => null`, `() => undefined`, `() => ({})`, `() => []`, `() => {}`,\n * `function () {}`), and a `catch` block that is empty, holds only a comment, or only assigns or returns a constant\n * without reading the error. Handled, and not reported: anything that reads the error (logs, wraps or rethrows\n * it), makes any call (a log, a cleanup, a fallback), throws, or reads another variable.\n *\n * It is not ESLint's `no-empty`: `no-empty` reports an empty block only, lets a block that holds a comment pass,\n * and never sees `.catch(() => null)`. Both report `catch {}`, each with its own message. There is no fix: what to\n * log is a decision. A deliberate silent catch carries an `eslint-disable-next-line` with its reason.\n */\nexport class NoSilentCatchRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/no-silent-catch`;\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n schema: [],\n messages: {\n silentHandler:\n 'This `.catch` handler swallows the error with no trace: log it, rethrow it or wrap it (V-C-06), or keep it with an `eslint-disable-next-line` and the reason.',\n silentBlock:\n 'This `catch` block swallows the error with no trace: log it, rethrow it or wrap it (V-C-06), or keep it with an `eslint-disable-next-line` and the reason.',\n },\n },\n create: (context) => {\n const { sourceCode } = context;\n\n return {\n [AstNodeTypes.CALL_EXPRESSION]: (node: Rule.Node) => {\n if (PromiseChainSupport.chainMethodOf({ node }) !== 'catch') {\n return;\n }\n\n const args = AstNode.readField({ node, key: 'arguments' });\n const handler: unknown = Array.isArray(args) ? args[0] : undefined;\n const handlerType = AstNode.getType({ node: handler });\n if (\n !AwaitSupport.isNode(handler) ||\n (handlerType !== 'ArrowFunctionExpression' && handlerType !== 'FunctionExpression')\n ) {\n return;\n }\n\n const params = AstNode.readField({ node: handler, key: 'params' });\n if (\n !Array.isArray(params) ||\n !params.every((parameter) => isPlainParameter({ parameter })) ||\n isParameterUsed({ owner: handler, sourceCode })\n ) {\n return;\n }\n\n const body = AstNode.readField({ node: handler, key: 'body' });\n const isSilent =\n AstNode.getType({ node: body }) === 'BlockStatement'\n ? PromiseChainSupport.isSilentBlock({\n statements: AstNode.readField({ node: body, key: 'body' }),\n })\n : PromiseChainSupport.isConstant({ node: body });\n\n if (isSilent) {\n context.report({ node: handler, messageId: 'silentHandler' });\n }\n },\n [AstNodeTypes.CATCH_CLAUSE]: (node: Rule.Node) => {\n if (\n !isPlainParameter({ parameter: AstNode.readField({ node, key: 'param' }) }) ||\n isParameterUsed({ owner: node, sourceCode })\n ) {\n return;\n }\n\n const body = AstNode.readField({ node, key: 'body' });\n if (\n PromiseChainSupport.isSilentBlock({\n statements: AstNode.readField({ node: body, key: 'body' }),\n })\n ) {\n context.report({ node, messageId: 'silentBlock' });\n }\n },\n };\n },\n };\n\n static build(opts: { severity?: TRuleSeverity } = {}): TRuleSeverity {\n return opts.severity ?? 'error';\n }\n}\n"]}
1
+ {"version":3,"file":"no-silent-catch.rule.js","sourceRoot":"","sources":["../../../src/linters/house/no-silent-catch.rule.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Rule, SourceCode } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { AwaitSupport } from './await-support';\nimport { AstNode, AstNodeTypes, HOUSE_PLUGIN_NAMESPACE } from './common';\nimport { PromiseChainSupport } from './promise-chain-support';\n\n/** Whether a parameter of `owner` (a function or a catch clause) is read or written anywhere. */\nconst isParameterUsed = (opts: { owner: Rule.Node; sourceCode: SourceCode }): boolean =>\n opts.sourceCode\n .getDeclaredVariables(opts.owner)\n .some(\n (variable) =>\n variable.defs.some((definition) =>\n ['Parameter', 'CatchClause'].includes(definition.type),\n ) && variable.references.length > 0,\n );\n\n/** A parameter that is not a plain name (`({ message }) =>`, `catch ({ message })`) reads the error by itself. */\nconst isPlainParameter = (opts: { parameter: unknown }): boolean =>\n opts.parameter === null ||\n opts.parameter === undefined ||\n AstNode.getType({ node: opts.parameter }) === 'Identifier';\n\n/**\n * `venizia/no-silent-catch`. A handled error leaves a trace (V-C-06). Reported: a `.catch(h)` (also `?.catch`,\n * `['catch']`) whose handler is an arrow or function expression that ignores its parameter and whose body is empty\n * or only gives back a constant (`() => null`, `() => undefined`, `() => ({})`, `() => []`, `() => {}`,\n * `function () {}`), and a `catch` block that is empty, holds only a comment, or only assigns or returns a constant\n * without reading the error. Handled, and not reported: anything that reads the error (logs, wraps or rethrows\n * it), makes any call (a log, a cleanup, a fallback), throws, or reads another variable.\n *\n * It is not ESLint's `no-empty`: `no-empty` reports an empty block only, lets a block that holds a comment pass,\n * and never sees `.catch(() => null)`. Both report `catch {}`, each with its own message. There is no fix: what to\n * log is a decision. A deliberate silent catch carries an `eslint-disable-next-line` with its reason.\n */\nexport class NoSilentCatchRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/no-silent-catch`;\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n schema: [],\n messages: {\n silentHandler:\n 'This `.catch` handler swallows the error with no trace: log it, rethrow it or wrap it (V-C-06), or keep it with an `eslint-disable-next-line` and the reason.',\n silentBlock:\n 'This `catch` block swallows the error with no trace: log it, rethrow it or wrap it (V-C-06), or keep it with an `eslint-disable-next-line` and the reason.',\n },\n },\n create: (context) => {\n const { sourceCode } = context;\n\n return {\n [AstNodeTypes.CALL_EXPRESSION]: (node: Rule.Node) => {\n if (PromiseChainSupport.chainMethodOf({ node }) !== 'catch') {\n return;\n }\n\n const args = AstNode.readField({ node, key: 'arguments' });\n const handler: unknown = Array.isArray(args) ? args[0] : undefined;\n const handlerType = AstNode.getType({ node: handler });\n\n if (\n !AwaitSupport.isNode(handler) ||\n (handlerType !== 'ArrowFunctionExpression' && handlerType !== 'FunctionExpression')\n ) {\n return;\n }\n\n const params = AstNode.readField({ node: handler, key: 'params' });\n\n if (\n !Array.isArray(params) ||\n !params.every((parameter) => isPlainParameter({ parameter })) ||\n isParameterUsed({ owner: handler, sourceCode })\n ) {\n return;\n }\n\n const body = AstNode.readField({ node: handler, key: 'body' });\n const isSilent =\n AstNode.getType({ node: body }) === AstNodeTypes.BLOCK_STATEMENT\n ? PromiseChainSupport.isSilentBlock({\n statements: AstNode.readField({ node: body, key: 'body' }),\n })\n : PromiseChainSupport.isConstant({ node: body });\n\n if (isSilent) {\n context.report({ node: handler, messageId: 'silentHandler' });\n }\n },\n [AstNodeTypes.CATCH_CLAUSE]: (node: Rule.Node) => {\n if (\n !isPlainParameter({ parameter: AstNode.readField({ node, key: 'param' }) }) ||\n isParameterUsed({ owner: node, sourceCode })\n ) {\n return;\n }\n\n const body = AstNode.readField({ node, key: 'body' });\n\n if (\n PromiseChainSupport.isSilentBlock({\n statements: AstNode.readField({ node: body, key: 'body' }),\n })\n ) {\n context.report({ node, messageId: 'silentBlock' });\n }\n },\n };\n },\n };\n\n static build(opts: { severity?: TRuleSeverity } = {}): TRuleSeverity {\n return opts.severity ?? 'error';\n }\n}\n"]}
@@ -0,0 +1,15 @@
1
+ import type { Linter, Rule } from 'eslint';
2
+ import type { TRuleSeverity } from '../rules/common';
3
+ /**
4
+ * `venizia/no-unbraced-case`: the statements of a `case` or `default` sit in one block, `case 'a': { ... }`.
5
+ * It is the ESLint twin of oxlint's `unicorn/switch-case-braces` (`SwitchCaseBracesRule`, mode `always`).
6
+ * Stacked labels with no statements stay as written. The fix wraps the statements in `{ }`.
7
+ */
8
+ export declare class NoUnbracedCaseRule {
9
+ static readonly NAME = "venizia/no-unbraced-case";
10
+ static readonly RULE: Rule.RuleModule;
11
+ static build(opts?: {
12
+ severity?: TRuleSeverity;
13
+ }): Linter.RuleEntry;
14
+ }
15
+ //# sourceMappingURL=no-unbraced-case.rule.d.ts.map