History

Ban Effect escape hatches

Rhys Sullivan committed 6 months ago

Commit 427d4e21 parent 10d34f84 files · +57 −0Browse files

Showing the changes to scripts (2 of 4 files). Show all

Unified · Split

2 files
  1. scripts/oxlint-plugin-executor.js +2 −0
  2. scripts/oxlint-plugin-executor/rules/no-effect-escape-hatch.js +33 −0
scripts/oxlint-plugin-executor.js+2−0
@@ -1,6 +1,7 @@
11 import noConditionalTests from "./oxlint-plugin-executor/rules/no-conditional-tests.js";
22 import noCrossPackageRelativeImports from "./oxlint-plugin-executor/rules/no-cross-package-relative-imports.js";
33 import noDoubleCast from "./oxlint-plugin-executor/rules/no-double-cast.js";
4+import noEffectEscapeHatch from "./oxlint-plugin-executor/rules/no-effect-escape-hatch.js";
45 import noEffectInternalTags from "./oxlint-plugin-executor/rules/no-effect-internal-tags.js";
56 import noErrorConstructor from "./oxlint-plugin-executor/rules/no-error-constructor.js";
67 import noInlineObjectTypeAssertion from "./oxlint-plugin-executor/rules/no-inline-object-type-assertion.js";
@@ -34,6 +35,7 @@ export default { · 27 unmodified lines
3435 "no-double-cast": noDoubleCast,
3536 "no-cross-package-relative-imports": noCrossPackageRelativeImports,
3637 "require-reactivity-keys": requireReactivityKeys,
38+ "no-effect-escape-hatch": noEffectEscapeHatch,
3739 "no-effect-internal-tags": noEffectInternalTags,
3840 "no-error-constructor": noErrorConstructor,
3941 "no-ts-nocheck": noTsNocheck,
scripts/oxlint-plugin-executor/rules/no-effect-escape-hatch.js+33−0
@@ -0,0 +1,33 @@
1+import { getPropertyName, isTestLike, unwrapExpression } from "../utils.js";
2+
3+const escapeHatches = new Set(["die", "dieMessage", "orDie", "orDieWith"]);
4+
5+const message =
6+ "Do not collapse Effect failures with die/orDie escape hatches. Keep typed errors in the Effect error channel; at true runtime edges use a narrow boundary suppression. Skill: wrdn-effect-typed-errors.";
7+
8+const isEffectEscapeHatch = (node) => {
9+ const expression = unwrapExpression(node);
10+ if (expression?.type !== "MemberExpression") return false;
11+ const property = getPropertyName(expression.property);
12+ return escapeHatches.has(property);
13+};
14+
15+export default {
16+ meta: {
17+ type: "problem",
18+ docs: {
19+ description: "Disallow Effect die/orDie escape hatches outside test code.",
20+ },
21+ },
22+ create(context) {
23+ if (isTestLike(context.filename)) return {};
24+
25+ return {
26+ MemberExpression(node) {
27+ if (isEffectEscapeHatch(node)) {
28+ context.report({ node, message });
29+ }
30+ },
31+ };
32+ },
33+};