@deslop/coding-standards 0.1.1083 → 0.1.1086

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/oxlint.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as dedupeWith, At as flatMap, B as flatMap$1, Bt as match, C as TaggedError, D as contains$1, Dt as exists, E as appendAll, Er as isNotNullish, Et as contains, F as filter$1, Fr as isString, Ft as getOrUndefined, G as getSomes, Gt as zipWith, H as forEach, Hr as constVoid, Ht as orElse, I as filterMap, It as isNone, J as isArrayNonEmpty, Jr as pipe, K as head, L as findFirst, Lt as isSome, M as empty, Mt as fromNullishOr, N as ensure, Nr as isReadonlyObject, Nt as fromUndefinedOr, O as containsWith, Or as isNullish$1, Ot as filter, P as every, Pr as isRegExp, Pt as getOrElse, Q as last, R as findFirstIndex, T as append, Tr as isNotNull, Tt as all, Ut as some, V as flatten, Vt as none, W as get$1, Wr as dual, Wt as toArray$1, X as isReadonlyArrayNonEmpty, Xn as NodeInspectSymbol, Z as join, Zr as pipeArguments, _ as startsWith, _t as fromOption, b as parse, c as make$3, cr as equals, ct as take, d as Order, dr as combine, et as map$1, f as includes, fr as hash, g as split, h as replaceAll, hr as string, in as strictEqual, it as prepend, j as dropRight, jt as flatten$1, k as dedupe, kr as isNumber, kt as firstSomeOf, l as update, lr as symbol, lt as fromEntries, m as replace, mr as optimize, mt as values, nt as matchRight, o as toArray, ot as some$1, p as match$1, pr as number, pt as remove, q as isArrayEmpty, r as make$2, rt as of, s as get$3, sr as byReferenceUnsafe, st as sort, t as append$1, u as match$2, ut as get$2, v as trim, vr as symbol$1, xr as isBoolean, yr as hasProperty, zr as constFalse, zt as map } from "./MutableList-Cpkiw3Cl.mjs";
1
+ import { A as dedupeWith, Ar as isNumber, At as firstSomeOf, B as flatMap$1, Br as constFalse, Bt as map, C as TaggedError, D as contains, Dr as isNotNullish, Dt as contains$1, E as appendAll, Er as isNotNull, Et as all, F as filter$1, Fr as isRegExp, Ft as getOrElse, G as getSomes, Gr as dual, Gt as toArray$1, H as forEach, Ht as none, I as filterMap, Ir as isString, It as getOrUndefined, J as isArrayNonEmpty, K as head, Kt as zipWith, L as findFirst, Lt as isNone, M as empty, Mt as flatten$1, N as ensure, Nt as fromNullishOr, O as containsWith, Ot as exists, P as every, Pr as isReadonlyObject, Pt as fromUndefinedOr, Q as last, Qr as pipeArguments, R as findFirstIndex, Rt as isSome, Sr as isBoolean, T as append, Ur as constVoid, Ut as orElse, V as flatten, Vt as match, W as get$1, Wt as some, X as isReadonlyArrayNonEmpty, Yr as pipe, Z as join, Zn as NodeInspectSymbol, _ as toUpperCase, an as strictEqual, b as parse, br as hasProperty, c as make$3, cr as byReferenceUnsafe, ct as take, d as Order, dt as get$2, et as map$1, f as includes, fr as combine, g as startsWith, gr as string, h as split, hr as optimize, ht as values, it as prepend, j as dropRight, jt as flatMap, k as dedupe, kr as isNullish, kt as filter, l as update, lr as equals, lt as takeWhile, m as replaceAll, mr as number, mt as remove, nt as matchRight, o as toArray, ot as some$1, p as match$1, pr as hash, q as isArrayEmpty, r as make$2, rt as of, s as get$3, st as sort, t as append$1, u as match$2, ur as symbol, ut as fromEntries, v as trim, vt as fromOption, yr as symbol$1 } from "./MutableList-CnvD7fcZ.mjs";
2
2
  //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/internal/graph.js
3
3
  /** @internal */
4
4
  const TypeId = "~effect/Graph";
@@ -621,7 +621,7 @@ Object.freeze({
621
621
  }
622
622
  });
623
623
  //#endregion
624
- //#region ../../node_modules/.pnpm/oxlint@1.88.0_oxlint-tsgolint@7.0.2004_vite-plus@1.2.0_@opentelemetry+api@1.9.1_@types+_d0d0d8af4627f12721655e70fc027515/node_modules/oxlint/dist/index.js
624
+ //#region ../../node_modules/.pnpm/oxlint@1.88.0_oxlint-tsgolint@7.0.2004_vite-plus@1.3.0_@opentelemetry+api@1.9.1_@types+_73e40377152d496dbecb939f0b8a3193/node_modules/oxlint/dist/index.js
625
625
  /**
626
626
  * Define an Oxlint configuration with type inference.
627
627
  *
@@ -633,6 +633,28 @@ function defineConfig(config) {
633
633
  }
634
634
  //#endregion
635
635
  //#region src/rules/shared.ts
636
+ function inert(token) {
637
+ if (contains([
638
+ "Boolean",
639
+ "Identifier",
640
+ "Null",
641
+ "Numeric",
642
+ "String"
643
+ ], token.type)) return true;
644
+ if (token.type === "Keyword") return contains([
645
+ "const",
646
+ "new",
647
+ "return"
648
+ ], token.value);
649
+ return token.type === "Punctuator" && contains([
650
+ "(",
651
+ ",",
652
+ ":",
653
+ "=",
654
+ "[",
655
+ "{"
656
+ ], token.value);
657
+ }
636
658
  function variableFromScope(input) {
637
659
  if (input.scope === null) return none();
638
660
  const scope = input.scope;
@@ -690,7 +712,7 @@ function importedMember(input) {
690
712
  importedName: input.importedName,
691
713
  node: input.node.object,
692
714
  source: "effect"
693
- }) && (input.propertyName === void 0 || contains(memberName(input.node), input.propertyName));
715
+ }) && (input.propertyName === void 0 || contains$1(memberName(input.node), input.propertyName));
694
716
  }
695
717
  function matches(regExp) {
696
718
  return (text) => isSome(pipe(text, match$1(regExp)));
@@ -711,7 +733,7 @@ function isReactUseState(input) {
711
733
  node: input.node.callee,
712
734
  source: "react"
713
735
  });
714
- return input.node.callee.type === "MemberExpression" && contains(memberName(input.node.callee), "useState") && input.node.callee.object.type === "Identifier" && isNamespaceImport({
736
+ return input.node.callee.type === "MemberExpression" && contains$1(memberName(input.node.callee), "useState") && input.node.callee.object.type === "Identifier" && isNamespaceImport({
715
737
  context: input.context,
716
738
  node: input.node.callee.object,
717
739
  source: "react"
@@ -868,7 +890,7 @@ function schemaCycleNames(input) {
868
890
  const indices = fromEntries(map$1(names, (name) => [name, addNode(mutable, name)]));
869
891
  for (const edge of edges) for (const target of edge.targets) zipWith(get$2(indices, edge.name), get$2(indices, target), (source, sink) => addEdge(mutable, source, sink, "reads"));
870
892
  });
871
- return pipe(stronglyConnectedComponents(graph), map$1((component) => getSomes(map$1(component, (index) => getNode(graph, index)))), filter$1((component) => (component.length > 1 || some$1(edges, (edge) => contains$1(component, edge.name) && contains$1(edge.targets, edge.name))) && some$1(component, (name) => contains$1(seeds, name))), flatten);
893
+ return pipe(stronglyConnectedComponents(graph), map$1((component) => getSomes(map$1(component, (index) => getNode(graph, index)))), filter$1((component) => (component.length > 1 || some$1(edges, (edge) => contains(component, edge.name) && contains(edge.targets, edge.name))) && some$1(component, (name) => contains(seeds, name))), flatten);
872
894
  }
873
895
  function hasSingleStatementExpression(node) {
874
896
  if (node.body === null) return false;
@@ -908,7 +930,7 @@ const explicitEffectConcurrency = defineRule({
908
930
  })) return;
909
931
  const name = memberName(node.callee);
910
932
  if (!exists(name, (method) => method === "all" || method === "forEach")) return;
911
- const index = match$2(contains(name, "all") || isFunction(node.arguments[0]) || node.arguments[1]?.type === "ObjectExpression", {
933
+ const index = match$2(contains$1(name, "all") || isFunction(node.arguments[0]) || node.arguments[1]?.type === "ObjectExpression", {
912
934
  onFalse: () => 2,
913
935
  onTrue: () => 1
914
936
  });
@@ -921,17 +943,105 @@ const explicitEffectConcurrency = defineRule({
921
943
  meta: { type: "problem" }
922
944
  });
923
945
  //#endregion
946
+ //#region src/rules/module-constant.ts
947
+ const isConstantName = matches(/^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$/u);
948
+ function literal(node) {
949
+ if (node.type === "Literal") return node.value !== null;
950
+ if (node.type === "TemplateLiteral") return isArrayEmpty(node.expressions);
951
+ if (node.type === "UnaryExpression") return node.operator === "-" && literal(node.argument);
952
+ if (node.type === "BinaryExpression") return literal(node.left) && literal(node.right);
953
+ if (node.type === "ArrayExpression") return every(node.elements, (element) => element !== null && element.type !== "SpreadElement" && literal(element));
954
+ if (node.type === "ObjectExpression") return every(node.properties, (property) => property.type === "Property" && !property.computed && property.kind === "init" && literal(property.value));
955
+ return pipe(typeWrapped(node), exists(literal));
956
+ }
957
+ function literalConstant(statement) {
958
+ if (statement.type !== "VariableDeclaration" || statement.kind !== "const" || statement.declarations.length !== 1) return none();
959
+ const [node] = statement.declarations;
960
+ if (node?.id.type !== "Identifier" || node.init === null || !literal(node.init)) return none();
961
+ return some({
962
+ id: node.id,
963
+ node
964
+ });
965
+ }
966
+ function renamed(input) {
967
+ if (input.reference.identifier.parent.type === "Property" && input.reference.identifier.parent.shorthand) return input.fixer.replaceText(input.reference.identifier, `${input.reference.identifier.name}: ${input.name}`);
968
+ return input.fixer.replaceText(input.reference.identifier, input.name);
969
+ }
970
+ function primitive(node) {
971
+ if (node.type === "Literal") return !hasProperty(node, "regex");
972
+ return contains([
973
+ "BinaryExpression",
974
+ "TemplateLiteral",
975
+ "UnaryExpression"
976
+ ], node.type) || pipe(typeWrapped(node), exists(primitive));
977
+ }
978
+ function check$2(input) {
979
+ if (input.found.id.typeAnnotation === null && input.found.node.init !== null && primitive(input.found.node.init) && filter$1(input.variable.references, (reference) => reference.isRead()).length === 1 && !pipe(input.context.sourceCode.getText(input.found.node), includes("\n"))) {
980
+ input.context.report({
981
+ message: "Inline this value at its only use.",
982
+ node: input.found.node
983
+ });
984
+ return;
985
+ }
986
+ if (!isConstantName(input.found.id.name)) {
987
+ const name = pipe(input.found.id.name, replaceAll(/(?<=[a-z0-9])(?=[A-Z])/gu, "_"), toUpperCase);
988
+ const taken = some$1([input.found.id, ...map$1(input.variable.references, (reference) => reference.identifier)], (node) => isSome(variableFromScope({
989
+ name,
990
+ scope: input.context.sourceCode.getScope(node)
991
+ })));
992
+ input.context.report({
993
+ fix: (fixer) => {
994
+ if (taken) return [];
995
+ return [fixer.replaceTextRange([input.found.id.range[0], input.found.id.range[0] + input.found.id.name.length], name), ...pipe(input.variable.references, filter$1((reference) => reference.identifier !== input.found.id), map$1((reference) => renamed({
996
+ fixer,
997
+ name,
998
+ reference
999
+ })))];
1000
+ },
1001
+ message: `Name this module constant ${name}.`,
1002
+ node: input.found.node
1003
+ });
1004
+ }
1005
+ if (!input.leading) input.context.report({
1006
+ message: "Declare this module constant directly under the imports.",
1007
+ node: input.found.node
1008
+ });
1009
+ }
1010
+ const moduleConstant = defineRule({
1011
+ create: (context) => ({ Program: (program) => {
1012
+ const leading = takeWhile(program.body, (statement) => statement.type === "ImportDeclaration" || isSome(literalConstant(statement)));
1013
+ for (const statement of program.body) pipe(literalConstant(statement), flatMap((found) => pipe(variableFromScope({
1014
+ name: found.id.name,
1015
+ scope: context.sourceCode.getScope(found.node)
1016
+ }), filter((variable) => !some$1(variable.references, (reference) => reference.identifier.parent.type === "ExportSpecifier")), map((variable) => ({
1017
+ found,
1018
+ variable
1019
+ })))), match({
1020
+ onNone: constVoid,
1021
+ onSome: (match) => check$2({
1022
+ ...match,
1023
+ context,
1024
+ leading: contains(leading, statement)
1025
+ })
1026
+ }));
1027
+ } }),
1028
+ meta: {
1029
+ fixable: "code",
1030
+ type: "suggestion"
1031
+ }
1032
+ });
1033
+ //#endregion
924
1034
  //#region src/rules/motion-limits.ts
925
1035
  function utility(token) {
926
- return pipe(token, split(":"), last, getOrElse(() => token), replace(/^!|!$/gu, ""));
1036
+ return pipe(token, split(":"), last, getOrElse(() => token), replaceAll(/^!|!$/gu, ""));
927
1037
  }
928
1038
  function amount(token, pattern) {
929
1039
  return pipe(utility(token), match$1(pattern), flatMap((match) => fromNullishOr(match[1])), map((value) => pipe(parse(value), getOrElse(() => 0))));
930
1040
  }
931
1041
  function violation(token) {
932
- if (exists(amount(token, /^duration-(\d+)$/u), (value) => value > 300)) return some("Keep a transition under 300 ms: duration-300 or less.");
1042
+ if (exists(amount(token, /^duration-(\d+)$/u), (value) => value >= 300)) return some("Keep a tween under 300 ms, such as duration-200.");
933
1043
  if (matches(/^zoom-(?:in|out)$/u)(utility(token)) || exists(amount(token, /^zoom-(?:in|out)-(\d+)$/u), (value) => value < 90)) return some("Enter from 0.9 scale or more: zoom-in-90 or zoom-in-95.");
934
- if (pipe(token, split(":"), dropRight(1), contains$1("starting")) && exists(amount(token, /^scale-(\d+)$/u), (value) => value < 90)) return some("Enter from 0.9 scale or more: starting:scale-90 or starting:scale-95.");
1044
+ if (pipe(token, split(":"), dropRight(1), contains("starting")) && exists(amount(token, /^scale-(\d+)$/u), (value) => value < 90)) return some("Enter from 0.9 scale or more: starting:scale-90 or starting:scale-95.");
935
1045
  return none();
936
1046
  }
937
1047
  function check$1(context, node, text) {
@@ -952,53 +1062,6 @@ const motionLimits = defineRule({
952
1062
  meta: { type: "problem" }
953
1063
  });
954
1064
  //#endregion
955
- //#region src/rules/no-array-wrap-ternary.ts
956
- function testedValue(node) {
957
- if (node.type !== "CallExpression" || node.callee.type !== "MemberExpression" || node.callee.object.type !== "Identifier" || node.callee.object.name !== "Array" || !contains(memberName(node.callee), "isArray") || node.arguments.length !== 1) return none();
958
- const argument = node.arguments[0];
959
- if (argument?.type !== "Identifier" && argument?.type !== "MemberExpression") return none();
960
- return some(argument);
961
- }
962
- function isSingletonArray(input) {
963
- if (input.node.type !== "ArrayExpression" || input.node.elements.length !== 1) return false;
964
- const element = input.node.elements[0];
965
- if (isNullish$1(element) || element.type === "SpreadElement") return false;
966
- return input.context.sourceCode.getText(element) === input.context.sourceCode.getText(input.value);
967
- }
968
- function wrapsTestedValue(input) {
969
- return exists(testedValue(input.test), (value) => input.context.sourceCode.getText(input.kept) === input.context.sourceCode.getText(value) && isSingletonArray({
970
- context: input.context,
971
- node: input.wrapped,
972
- value
973
- }));
974
- }
975
- function restatesArrayEnsure(input) {
976
- if (input.node.test.type === "UnaryExpression" && input.node.test.operator === "!") return wrapsTestedValue({
977
- context: input.context,
978
- kept: input.node.alternate,
979
- test: input.node.test.argument,
980
- wrapped: input.node.consequent
981
- });
982
- return wrapsTestedValue({
983
- context: input.context,
984
- kept: input.node.consequent,
985
- test: input.node.test,
986
- wrapped: input.node.alternate
987
- });
988
- }
989
- const noArrayWrapTernary = defineRule({
990
- create: (context) => ({ ConditionalExpression: (node) => {
991
- if (restatesArrayEnsure({
992
- context,
993
- node
994
- })) context.report({
995
- message: "Use Array.ensure; the ternary restates it.",
996
- node
997
- });
998
- } }),
999
- meta: { type: "problem" }
1000
- });
1001
- //#endregion
1002
1065
  //#region src/rules/no-barrel-module.ts
1003
1066
  const noBarrelModule = defineRule({
1004
1067
  create: (context) => ({
@@ -1025,7 +1088,7 @@ const noCompilerOptOut = defineRule({
1025
1088
  create: (context) => ({ ExpressionStatement: (node) => {
1026
1089
  if (node.directive !== "use no memo" && node.directive !== "use no forget") return;
1027
1090
  context.report({
1028
- message: "Fix the code React Compiler rejects instead of opting the function out of compilation.",
1091
+ message: "Remove this directive, rerun lint and fix the React Compiler diagnostic it hid.",
1029
1092
  node
1030
1093
  });
1031
1094
  } }),
@@ -1105,7 +1168,7 @@ function isPipeCall(context, node) {
1105
1168
  });
1106
1169
  }
1107
1170
  function enclosingPipes(context, node) {
1108
- if (node.type === "Program" || contains$1([
1171
+ if (node.type === "Program" || contains([
1109
1172
  "ArrowFunctionExpression",
1110
1173
  "FunctionDeclaration",
1111
1174
  "FunctionExpression"
@@ -1117,7 +1180,7 @@ function enclosingPipes(context, node) {
1117
1180
  const noDeepPipe = defineRule({
1118
1181
  create: (context) => ({ CallExpression: (node) => {
1119
1182
  if (isPipeCall(context, node) && enclosingPipes(context, node) >= 3) context.report({
1120
- message: "Flatten this pipeline; pipe calls nest at most three deep.",
1183
+ message: "Merge this pipe into its parent, or move it into a named function declaration; pipe calls nest at most three deep.",
1121
1184
  node
1122
1185
  });
1123
1186
  } }),
@@ -1126,7 +1189,7 @@ const noDeepPipe = defineRule({
1126
1189
  //#endregion
1127
1190
  //#region src/rules/no-destructured-parameter.ts
1128
1191
  function namedTuple(input) {
1129
- if (contains$1(input.seen, input.node)) return false;
1192
+ if (contains(input.seen, input.node)) return false;
1130
1193
  if (input.node.type === "TSTupleType") return isArrayNonEmpty(input.node.elementTypes) && every(input.node.elementTypes, (element) => element.type === "TSNamedTupleMember");
1131
1194
  if (input.node.type === "TSParenthesizedType" || input.node.type === "TSTypeOperator" && input.node.operator === "readonly") return namedTuple({
1132
1195
  ...input,
@@ -1200,6 +1263,9 @@ const noDestructuredParameter = defineRule({
1200
1263
  });
1201
1264
  //#endregion
1202
1265
  //#region src/rules/no-discarded-failure.ts
1266
+ function logged(node) {
1267
+ return node.parent.type === "CallExpression" && node.parent.callee === node && some$1(node.parent.arguments, (argument) => argument.type === "ObjectExpression" && every(argument.properties, (property) => property.type === "Property") && some$1(argument.properties, (property) => !property.computed && (property.key.type === "Identifier" && property.key.name === "log" || property.key.type === "Literal" && property.key.value === "log") && property.value.type === "Literal" && (property.value.value === true || isString(property.value.value))));
1268
+ }
1203
1269
  const noDiscardedFailure = defineRule({
1204
1270
  create: (context) => ({ MemberExpression: (node) => {
1205
1271
  if (!importedMember({
@@ -1207,13 +1273,15 @@ const noDiscardedFailure = defineRule({
1207
1273
  importedName: "Effect",
1208
1274
  node
1209
1275
  })) return;
1210
- if (!exists(memberName(node), (name) => contains$1([
1276
+ if (!exists(memberName(node), (name) => contains([
1211
1277
  "ignore",
1278
+ "ignoreCause",
1212
1279
  "orDie",
1213
1280
  "orDieWith"
1214
1281
  ], name))) return;
1282
+ if (exists(memberName(node), (name) => name !== "orDie" && name !== "orDieWith") && logged(node)) return;
1215
1283
  context.report({
1216
- message: "Map the failure to the service's error; an expected failure is never ignored or turned into a defect.",
1284
+ message: "Map the failure to the service's error, or log best-effort work with Effect.ignore({log: 'Warn', message}); an expected failure is never dropped silently or turned into a defect.",
1217
1285
  node
1218
1286
  });
1219
1287
  } }),
@@ -1221,12 +1289,7 @@ const noDiscardedFailure = defineRule({
1221
1289
  });
1222
1290
  //#endregion
1223
1291
  //#region src/rules/no-double-nullish-check.ts
1224
- function nullishOperand(node) {
1225
- if (node.type === "Literal" && node.value === null) return some("null");
1226
- if (node.type === "Identifier" && node.name === "undefined") return some("undefined");
1227
- return none();
1228
- }
1229
- const variants = {
1292
+ const VARIANTS = {
1230
1293
  "&&": {
1231
1294
  comparison: "!==",
1232
1295
  message: "Use Predicate.isNotNullish."
@@ -1236,6 +1299,11 @@ const variants = {
1236
1299
  message: "Use Predicate.isNullish."
1237
1300
  }
1238
1301
  };
1302
+ function nullishOperand(node) {
1303
+ if (node.type === "Literal" && node.value === null) return some("null");
1304
+ if (node.type === "Identifier" && node.name === "undefined") return some("undefined");
1305
+ return none();
1306
+ }
1239
1307
  function operands(input) {
1240
1308
  if (input.node.type !== "LogicalExpression" || input.node.operator !== input.operator) return [input.node];
1241
1309
  return appendAll(operands({
@@ -1258,7 +1326,7 @@ const noDoubleNullishCheck = defineRule({
1258
1326
  create: (context) => ({ LogicalExpression: (node) => {
1259
1327
  if (node.operator === "??") return;
1260
1328
  if (node.parent.type === "LogicalExpression" && node.parent.operator === node.operator) return;
1261
- const variant = variants[node.operator];
1329
+ const variant = VARIANTS[node.operator];
1262
1330
  const checks = pipe(operands({
1263
1331
  node,
1264
1332
  operator: node.operator
@@ -1312,14 +1380,14 @@ function calleeOf(node) {
1312
1380
  }
1313
1381
  function isEffectEmpty(input) {
1314
1382
  const member = calleeOf(input.node);
1315
- return member.type === "MemberExpression" && member.object.type === "Identifier" && contains(memberName(member), "empty") && isImportBinding({
1383
+ return member.type === "MemberExpression" && member.object.type === "Identifier" && contains$1(memberName(member), "empty") && isImportBinding({
1316
1384
  context: input.context,
1317
1385
  node: member.object,
1318
1386
  source: "effect"
1319
1387
  });
1320
1388
  }
1321
1389
  function isEmptyValue(input) {
1322
- if (isNullish$1(input.node)) return false;
1390
+ if (isNullish(input.node)) return false;
1323
1391
  if (input.node.type === "Identifier") return input.node.name === "undefined";
1324
1392
  if (input.node.type === "Literal") return input.node.value === null || input.node.value === "";
1325
1393
  if (input.node.type === "ArrayExpression") return isArrayEmpty(input.node.elements);
@@ -1331,7 +1399,7 @@ function isEmptyValue(input) {
1331
1399
  });
1332
1400
  }
1333
1401
  function isEmptySuccess(input) {
1334
- if (isNullish$1(input.node)) return false;
1402
+ if (isNullish(input.node)) return false;
1335
1403
  if (importedMember({
1336
1404
  context: input.context,
1337
1405
  importedName: "Effect",
@@ -1372,7 +1440,7 @@ const noEmptyRecovery = defineRule({
1372
1440
  name,
1373
1441
  node: returnedExpression(argument)
1374
1442
  })) context.report({
1375
- message: "Let the failure flow, or map it to the service’s error; an empty value hides that the work failed.",
1443
+ message: "Let the failure flow, map it with Effect.mapError(cause => ServiceError.make({cause, message})), or use Effect.option when absence is a valid result; an empty value hides the failure.",
1376
1444
  node: argument
1377
1445
  });
1378
1446
  } }),
@@ -1380,19 +1448,20 @@ const noEmptyRecovery = defineRule({
1380
1448
  });
1381
1449
  //#endregion
1382
1450
  //#region src/rules/no-error-message-assertion.ts
1451
+ const ASSERT_IDENTITY = "Assert the failure's identity, such as assert.containsSubset(error, {_tag: 'NotFound'}) on Effect.flip's result, never its message.";
1383
1452
  function receiverName(node) {
1384
1453
  if (node.type === "Identifier") return some(node.name);
1385
1454
  if (node.type !== "MemberExpression") return none();
1386
1455
  return memberName(node);
1387
1456
  }
1388
1457
  function isErrorMessage(node) {
1389
- return node?.type === "MemberExpression" && contains(memberName(node), "message") && exists(receiverName(node.object), matches(/^(?:e|err|error|failure|cause|exception)$|Error$/iu));
1458
+ return node?.type === "MemberExpression" && contains$1(memberName(node), "message") && exists(receiverName(node.object), matches(/^(?:e|err|error|failure|cause|exception)$|Error$/iu));
1390
1459
  }
1391
1460
  function expectsErrorMessage(node) {
1392
1461
  return node.type === "CallExpression" && node.callee.type === "Identifier" && node.callee.name === "expect" && isErrorMessage(node.arguments[0]);
1393
1462
  }
1394
1463
  function expectsMessage(node) {
1395
- if (node.object.type === "MemberExpression" && contains(memberName(node.object), "not")) return expectsErrorMessage(node.object.object);
1464
+ if (node.object.type === "MemberExpression" && contains$1(memberName(node.object), "not")) return expectsErrorMessage(node.object.object);
1396
1465
  return expectsErrorMessage(node.object);
1397
1466
  }
1398
1467
  function assertsMessage(node) {
@@ -1403,13 +1472,13 @@ const noErrorMessageAssertion = defineRule({
1403
1472
  create: (context) => ({ CallExpression: (node) => {
1404
1473
  if (assertsMessage(node)) {
1405
1474
  context.report({
1406
- message: "Assert the failure, never its message wording.",
1475
+ message: ASSERT_IDENTITY,
1407
1476
  node
1408
1477
  });
1409
1478
  return;
1410
1479
  }
1411
- if (node.callee.type === "MemberExpression" && (node.arguments[0]?.type === "Literal" || node.arguments[0]?.type === "TemplateLiteral") && (exists(memberName(node.callee), (name) => contains$1(["toThrow", "toThrowError"], name)) || expectsMessage(node.callee))) context.report({
1412
- message: "Assert the failure, never its message wording.",
1480
+ if (node.callee.type === "MemberExpression" && (node.arguments[0]?.type === "Literal" || node.arguments[0]?.type === "TemplateLiteral") && (exists(memberName(node.callee), (name) => contains(["toThrow", "toThrowError"], name)) || expectsMessage(node.callee))) context.report({
1481
+ message: ASSERT_IDENTITY,
1413
1482
  node
1414
1483
  });
1415
1484
  } }),
@@ -1425,7 +1494,7 @@ function propertyName(node) {
1425
1494
  function hasUnusedSetter(input) {
1426
1495
  if (input.node.parent.type !== "VariableDeclarator" || input.node.parent.id.type !== "ArrayPattern") return false;
1427
1496
  const setter = input.node.parent.id.elements[1];
1428
- if (isNullish$1(setter)) return true;
1497
+ if (isNullish(setter)) return true;
1429
1498
  if (setter.type !== "Identifier") return false;
1430
1499
  return pipe(variableFromScope({
1431
1500
  name: setter.name,
@@ -1434,7 +1503,7 @@ function hasUnusedSetter(input) {
1434
1503
  }
1435
1504
  function isFakeRefState(input) {
1436
1505
  if (!isReactUseState(input) || input.node.arguments[0]?.type !== "ArrowFunctionExpression" || input.node.arguments[0].body.type !== "ObjectExpression" || input.node.arguments[0].body.properties.length !== 1 || !hasUnusedSetter(input)) return false;
1437
- return some$1(input.node.arguments[0].body.properties, (property) => property.type === "Property" && contains(propertyName(property), "current") && property.value.type === "Literal" && property.value.value === null);
1506
+ return some$1(input.node.arguments[0].body.properties, (property) => property.type === "Property" && contains$1(propertyName(property), "current") && property.value.type === "Literal" && property.value.value === null);
1438
1507
  }
1439
1508
  const noFakeRefState = defineRule({
1440
1509
  create: (context) => ({ CallExpression: (node) => {
@@ -1449,21 +1518,44 @@ const noFakeRefState = defineRule({
1449
1518
  meta: { type: "problem" }
1450
1519
  });
1451
1520
  //#endregion
1521
+ //#region src/rules/no-floating-derived-type.ts
1522
+ function derived(node) {
1523
+ if (node.type === "TSIndexedAccessType") return derived(node.objectType);
1524
+ return node.type === "TSTypeReference" && node.typeName.type === "Identifier" && contains([
1525
+ "Awaited",
1526
+ "ConstructorParameters",
1527
+ "InstanceType",
1528
+ "Parameters",
1529
+ "ReturnType"
1530
+ ], node.typeName.name);
1531
+ }
1532
+ const noFloatingDerivedType = defineRule({
1533
+ create: (context) => ({ TSTypeAliasDeclaration: (node) => {
1534
+ const listed = some$1(context.sourceCode.ast.body, (statement) => statement.type === "ExportNamedDeclaration" && some$1(statement.specifiers, (specifier) => specifier.local.type === "Identifier" && specifier.local.name === node.id.name));
1535
+ if (node.parent.type === "ExportNamedDeclaration" || listed || !derived(node.typeAnnotation)) return;
1536
+ context.report({
1537
+ message: "Import the library's exported type, else write ReturnType<typeof f> in the signature that needs it, or pass the value straight to the call that types it.",
1538
+ node
1539
+ });
1540
+ } }),
1541
+ meta: { type: "problem" }
1542
+ });
1543
+ //#endregion
1452
1544
  //#region src/rules/no-gradient.ts
1453
- const gradient = /(?:^|[\s:])bg-(?:linear|radial|conic|gradient)(?:-|$|\s)|gradient\(/u;
1545
+ const GRADIENT = /(?:^|[\s:])bg-(?:linear|radial|conic|gradient)(?:-|$|\s)|gradient\(/u;
1454
1546
  function report$4(context, node) {
1455
1547
  context.report({
1456
- message: "Use a flat theme color; gradients are never part of the design.",
1548
+ message: "Use a flat theme token such as bg-card or bg-muted; gradients are never part of the design.",
1457
1549
  node
1458
1550
  });
1459
1551
  }
1460
1552
  const noGradient = defineRule({
1461
1553
  create: (context) => ({
1462
1554
  Literal: (node) => {
1463
- if (isString(node.value) && gradient.test(node.value)) report$4(context, node);
1555
+ if (isString(node.value) && GRADIENT.test(node.value)) report$4(context, node);
1464
1556
  },
1465
1557
  TemplateElement: (node) => {
1466
- if (gradient.test(node.value.raw)) report$4(context, node);
1558
+ if (GRADIENT.test(node.value.raw)) report$4(context, node);
1467
1559
  }
1468
1560
  }),
1469
1561
  meta: { type: "problem" }
@@ -1497,7 +1589,7 @@ function check(input) {
1497
1589
  if (input.node.type === "UnaryExpression" && input.node.operator === "!" && input.node.argument.type === "CallExpression" && input.node.argument.callee.type === "MemberExpression" && isSubject({
1498
1590
  name: "Array",
1499
1591
  node: input.node.argument.callee.object
1500
- }) && contains(memberName(input.node.argument.callee), "isArray") && input.node.argument.arguments.length === 1 && every(input.node.argument.arguments, (argument) => isSubject({
1592
+ }) && contains$1(memberName(input.node.argument.callee), "isArray") && input.node.argument.arguments.length === 1 && every(input.node.argument.arguments, (argument) => isSubject({
1501
1593
  name: input.name,
1502
1594
  node: argument
1503
1595
  }))) return some(["!Array.isArray"]);
@@ -1521,11 +1613,11 @@ function check(input) {
1521
1613
  subject: input.node.right
1522
1614
  })]), map(of));
1523
1615
  }
1524
- function report$3(input) {
1525
- const predicate = input.node.returnType?.typeAnnotation;
1526
- const returned = returnedExpression(input.node);
1527
- if (predicate?.type !== "TSTypePredicate" || predicate.asserts || predicate.parameterName.type !== "Identifier" || isNullish$1(returned)) return;
1528
- const name = pipe(check({
1616
+ function replaceableGuard(node) {
1617
+ const predicate = node.returnType?.typeAnnotation;
1618
+ const returned = returnedExpression(node);
1619
+ if (predicate?.type !== "TSTypePredicate" || predicate.asserts || predicate.parameterName.type !== "Identifier" || isNullish(returned)) return none();
1620
+ return pipe(check({
1529
1621
  name: predicate.parameterName.name,
1530
1622
  node: returned
1531
1623
  }), map((checks) => pipe(checks, sort(Order), join(" && "))), flatMap((key) => get$2({
@@ -1551,12 +1643,12 @@ function report$3(input) {
1551
1643
  "typeof === symbol": "isSymbol",
1552
1644
  "typeof === undefined": "isUndefined"
1553
1645
  }, key)));
1554
- map(name, (guard) => {
1555
- input.context.report({
1556
- message: `Use Predicate.${guard} instead of this hand-written type guard.`,
1557
- node: input.node
1558
- });
1559
- });
1646
+ }
1647
+ function report$3(input) {
1648
+ map(replaceableGuard(input.node), (guard) => input.context.report({
1649
+ message: `Use Predicate.${guard} instead of this hand-written type guard.`,
1650
+ node: input.node
1651
+ }));
1560
1652
  }
1561
1653
  const noHandWrittenGuard = defineRule({
1562
1654
  create: (context) => ({
@@ -1606,13 +1698,12 @@ const noLet = defineRule({
1606
1698
  });
1607
1699
  //#endregion
1608
1700
  //#region src/rules/no-multiline-comment.ts
1609
- const directive = /^\s*(?:eslint|oxlint|@effect-diagnostics|@ts-|\/\s*<reference|#region|#endregion)/u;
1610
1701
  function adjacentLines(pair) {
1611
1702
  return pair.first?.type === "Line" && pair.second?.type === "Line" && pair.second.loc.start.line === pair.first.loc.end.line + 1;
1612
1703
  }
1613
1704
  const noMultilineComment = defineRule({
1614
1705
  create: (context) => ({ Program: () => {
1615
- const comments = pipe(context.sourceCode.getAllComments(), filter$1((comment) => !directive.test(comment.value)));
1706
+ const comments = pipe(context.sourceCode.getAllComments(), filter$1((comment) => !matches(/^\s*(?:eslint|oxlint|@effect-diagnostics|@ts-|\/\s*<reference|#region|#endregion)/u)(comment.value)));
1616
1707
  pipe(comments, filter$1((comment, index) => adjacentLines({
1617
1708
  first: comment,
1618
1709
  second: comments[index + 1]
@@ -1628,13 +1719,13 @@ const noMultilineComment = defineRule({
1628
1719
  });
1629
1720
  //#endregion
1630
1721
  //#region src/rules/no-native-control.ts
1631
- const primitives = {
1722
+ const PRIMITIVES = {
1632
1723
  button: "Button",
1633
1724
  input: "Input",
1634
1725
  select: "Select",
1635
1726
  textarea: "Textarea"
1636
1727
  };
1637
- const controlStyle = /(?:^|:)(?:hover|focus|focus-visible|active):|(?:^|:)(?:rounded|shadow|ring)(?:-|$)|(?:^|:)p[blrtxy]?-(?!0$)|(?:^|:)bg-(?!transparent$)|(?:^|:)border(?:-[blrtxy])?$|(?:^|:)border-(?!0$|[blrtxy]-0$)/u;
1728
+ const CONTROL_STYLE = /(?:^|:)(?:hover|focus|focus-visible|active):|(?:^|:)(?:rounded|shadow|ring)(?:-|$)|(?:^|:)p[blrtxy]?-(?!0$)|(?:^|:)bg-(?!transparent$)|(?:^|:)border(?:-[blrtxy])?$|(?:^|:)border-(?!0$|[blrtxy]-0$)/u;
1638
1729
  function classStrings(node) {
1639
1730
  if (node.type === "Literal") return filter$1([node.value], isString);
1640
1731
  if (node.type === "TemplateLiteral") return map$1(node.quasis, (quasi) => quasi.value.raw);
@@ -1649,11 +1740,11 @@ const noNativeControl = defineRule({
1649
1740
  create: (context) => ({ JSXOpeningElement: (node) => {
1650
1741
  if (node.name.type !== "JSXIdentifier") return;
1651
1742
  const name = node.name.name;
1652
- map(get$2(primitives, name), (primitive) => {
1743
+ map(get$2(PRIMITIVES, name), (primitive) => {
1653
1744
  const styled = pipe(node.attributes, findFirst((attribute) => attribute.type === "JSXAttribute" && attribute.name.type === "JSXIdentifier" && attribute.name.name === "className"), map((attribute) => {
1654
1745
  if (attribute.type !== "JSXAttribute" || attribute.value === null) return empty();
1655
1746
  return classStrings(attribute.value);
1656
- }), exists((values) => some$1(values, (value) => some$1(split(value, /\s+/u), matches(controlStyle)))));
1747
+ }), exists((values) => some$1(values, (value) => some$1(split(value, /\s+/u), matches(CONTROL_STYLE)))));
1657
1748
  if (name !== "select" && !styled) return;
1658
1749
  context.report({
1659
1750
  message: `Use the ${primitive} UI primitive instead of a styled native control.`,
@@ -1666,7 +1757,7 @@ const noNativeControl = defineRule({
1666
1757
  //#endregion
1667
1758
  //#region src/rules/no-native-emptiness-check.ts
1668
1759
  function emptinessPredicate(node) {
1669
- const comparesLength = node.left.type === "MemberExpression" && contains(memberName(node.left), "length") && node.right.type === "Literal" && node.right.value === 0;
1760
+ const comparesLength = node.left.type === "MemberExpression" && contains$1(memberName(node.left), "length") && node.right.type === "Literal" && node.right.value === 0;
1670
1761
  if (comparesLength && node.operator === "===") return some("Array.isArrayEmpty, Array.isReadonlyArrayEmpty, or String.isEmpty");
1671
1762
  if (comparesLength && node.operator === ">") return some("Array.isArrayNonEmpty, Array.isReadonlyArrayNonEmpty, or String.isNonEmpty");
1672
1763
  return none();
@@ -1684,69 +1775,54 @@ const noNativeEmptinessCheck = defineRule({
1684
1775
  });
1685
1776
  //#endregion
1686
1777
  //#region src/rules/no-native-method-call.ts
1687
- const nativeMethods = [
1688
- "at",
1689
- "catch",
1690
- "charAt",
1691
- "charCodeAt",
1692
- "codePointAt",
1693
- "concat",
1694
- "endsWith",
1695
- "entries",
1696
- "every",
1697
- "fill",
1698
- "filter",
1699
- "finally",
1700
- "find",
1701
- "findIndex",
1702
- "findLast",
1703
- "findLastIndex",
1704
- "flat",
1705
- "flatMap",
1706
- "forEach",
1707
- "includes",
1708
- "indexOf",
1709
- "join",
1710
- "keys",
1711
- "lastIndexOf",
1712
- "localeCompare",
1713
- "map",
1714
- "match",
1715
- "matchAll",
1716
- "normalize",
1717
- "padEnd",
1718
- "padStart",
1719
- "pop",
1720
- "push",
1721
- "reduce",
1722
- "reduceRight",
1723
- "repeat",
1724
- "replace",
1725
- "replaceAll",
1726
- "reverse",
1727
- "shift",
1728
- "slice",
1729
- "some",
1730
- "sort",
1731
- "splice",
1732
- "split",
1733
- "startsWith",
1734
- "substring",
1735
- "then",
1736
- "toLocaleLowerCase",
1737
- "toLocaleUpperCase",
1738
- "toLowerCase",
1739
- "toReversed",
1740
- "toSorted",
1741
- "toSpliced",
1742
- "toUpperCase",
1743
- "trim",
1744
- "trimEnd",
1745
- "trimStart",
1746
- "unshift",
1747
- "values",
1748
- "with"
1749
- ];
1778
+ const REPLACEMENTS = {
1779
+ at: "Array.get or String.at",
1780
+ catch: "Effect.tryPromise and Effect.catchTag",
1781
+ charAt: "String.charAt",
1782
+ charCodeAt: "String.charCodeAt",
1783
+ codePointAt: "String.codePointAt",
1784
+ concat: "Array.appendAll or String.concat",
1785
+ endsWith: "String.endsWith",
1786
+ entries: "Array.map(items, (item, index) => [index, item]), Record.toEntries or HashMap.entries",
1787
+ fill: "Array.replicate or Array.makeBy",
1788
+ finally: "Effect.ensuring",
1789
+ flat: "Array.flatten",
1790
+ includes: "Array.contains or String.includes",
1791
+ indexOf: "Array.findFirstIndex or String.indexOf",
1792
+ keys: "Record.keys or HashMap.keys",
1793
+ lastIndexOf: "Array.findLastIndex or String.lastIndexOf",
1794
+ localeCompare: "String.localeCompare",
1795
+ match: "String.match",
1796
+ matchAll: "String.matchAll",
1797
+ normalize: "String.normalize",
1798
+ padEnd: "String.padEnd",
1799
+ padStart: "String.padStart",
1800
+ pop: "Array.last and Array.dropRight",
1801
+ push: "Array.append",
1802
+ repeat: "String.repeat",
1803
+ replace: "String.replace",
1804
+ replaceAll: "String.replaceAll",
1805
+ reverse: "Array.reverse",
1806
+ shift: "Array.head and Array.drop",
1807
+ slice: "Array.take, Array.drop or String.slice",
1808
+ sort: "Array.sort(items, Order.mapInput(...))",
1809
+ splice: "Array.remove or Array.insertAt",
1810
+ split: "String.split",
1811
+ startsWith: "String.startsWith",
1812
+ substring: "String.substring",
1813
+ then: "Effect.tryPromise and Effect.map",
1814
+ toLocaleLowerCase: "String.toLowerCase",
1815
+ toLocaleUpperCase: "String.toUpperCase",
1816
+ toLowerCase: "String.toLowerCase",
1817
+ toSpliced: "Array.remove",
1818
+ toUpperCase: "String.toUpperCase",
1819
+ trim: "String.trim",
1820
+ trimEnd: "String.trimEnd",
1821
+ trimStart: "String.trimStart",
1822
+ unshift: "Array.prepend",
1823
+ values: "Record.values or HashMap.values",
1824
+ with: "Array.replace"
1825
+ };
1750
1826
  function freshRegExpFlags(input) {
1751
1827
  if (input.node.type === "Literal" && hasProperty(input.node, "regex")) return some(pipe(input.context.sourceCode.getText(input.node), split("/"), last));
1752
1828
  if (input.node.type !== "NewExpression" && input.node.type !== "CallExpression" || input.node.callee.type !== "Identifier" || input.node.callee.name !== "RegExp") return none();
@@ -1755,11 +1831,6 @@ function freshRegExpFlags(input) {
1755
1831
  if (flags.type !== "Literal" || !isString(flags.value)) return some(none());
1756
1832
  return some(some(flags.value));
1757
1833
  }
1758
- const nativeGlobals = [
1759
- "Object",
1760
- "Promise",
1761
- "RegExp"
1762
- ];
1763
1834
  function memberRoot(node) {
1764
1835
  if (node.type === "MemberExpression") return memberRoot(node.object);
1765
1836
  return node;
@@ -1771,7 +1842,7 @@ function chainRoot(node) {
1771
1842
  return node;
1772
1843
  }
1773
1844
  function isYieldedService(node) {
1774
- if (node?.type !== "YieldExpression" || !node.delegate || isNullish$1(node.argument)) return false;
1845
+ if (node?.type !== "YieldExpression" || !node.delegate || isNullish(node.argument)) return false;
1775
1846
  if (node.argument.type === "Identifier") return matches(/^[A-Z]/u)(node.argument.name);
1776
1847
  return node.argument.type === "MemberExpression" && exists(memberName(node.argument), (name) => matches(/^[A-Z]/u)(name));
1777
1848
  }
@@ -1784,7 +1855,11 @@ function ownsMethod(input) {
1784
1855
  if (root.type !== "Identifier") return false;
1785
1856
  if (root.name === "path") return !throughCall;
1786
1857
  return pipe(variableFor(input.context, root), filter((variable) => isReadonlyArrayNonEmpty(variable.defs)), match({
1787
- onNone: () => !throughCall && matches(/^[A-Z]/u)(root.name) && !contains$1(nativeGlobals, root.name),
1858
+ onNone: () => !throughCall && matches(/^[A-Z]/u)(root.name) && !contains([
1859
+ "Object",
1860
+ "Promise",
1861
+ "RegExp"
1862
+ ], root.name),
1788
1863
  onSome: (variable) => some$1(variable.defs, (definition) => {
1789
1864
  if (definition.node.type === "VariableDeclarator") return !throughCall && isYieldedService(definition.node.init);
1790
1865
  if (definition.type !== "ImportBinding" || definition.parent?.type !== "ImportDeclaration") return false;
@@ -1798,10 +1873,9 @@ const noNativeMethodCall = defineRule({
1798
1873
  context,
1799
1874
  receiver: node.callee.object
1800
1875
  })) return;
1801
- const receiver = node.callee.object;
1802
1876
  const regExpFlags = freshRegExpFlags({
1803
1877
  context,
1804
- node: receiver
1878
+ node: node.callee.object
1805
1879
  });
1806
1880
  if (isSome(regExpFlags) && exists(memberName(node.callee), (name) => name === "test" || name === "exec" && exists(flatten$1(regExpFlags), (flags) => !pipe(flags, includes("g"))))) {
1807
1881
  context.report({
@@ -1810,62 +1884,21 @@ const noNativeMethodCall = defineRule({
1810
1884
  });
1811
1885
  return;
1812
1886
  }
1813
- pipe(memberName(node.callee), filter((name) => contains$1(nativeMethods, name)), filter((name) => !contains$1([
1887
+ pipe(memberName(node.callee), filter((name) => !contains([
1814
1888
  "entries",
1815
1889
  "keys",
1816
1890
  "values"
1817
- ], name) || isArrayEmpty(node.arguments) || receiver.type === "Identifier" && receiver.name === "Object"), map((name) => context.report({
1818
- message: `Replace .${name}() on a native array, string, record, or Promise with its Effect Array, String, Record, or Effect function; a third-party API's own method stays, with an inline disable and its reason.`,
1891
+ ], name) || isArrayEmpty(node.arguments)), flatMap((name) => pipe(get$2(REPLACEMENTS, name), map((replacement) => ({
1892
+ name,
1893
+ replacement
1894
+ })))), map((method) => context.report({
1895
+ message: `Use ${method.replacement} instead of the native .${method.name}(); a third-party object's own method stays, with an inline disable naming it.`,
1819
1896
  node: node.callee
1820
1897
  })));
1821
1898
  } }),
1822
1899
  meta: { type: "problem" }
1823
1900
  });
1824
1901
  //#endregion
1825
- //#region src/rules/no-nullish-ternary.ts
1826
- const nullishPredicates = [
1827
- "isNotNull",
1828
- "isNotNullish",
1829
- "isNotUndefined",
1830
- "isNull",
1831
- "isNullish",
1832
- "isUndefined"
1833
- ];
1834
- function isNullish(input) {
1835
- if (input.node.type === "Literal") return input.node.value === null;
1836
- return input.node.type === "Identifier" && input.node.name === "undefined";
1837
- }
1838
- function testsNullish(input) {
1839
- if (input.node.type === "UnaryExpression" && input.node.operator === "!") return testsNullish({
1840
- context: input.context,
1841
- node: input.node.argument
1842
- });
1843
- if (input.node.type === "BinaryExpression" && (input.node.operator === "===" || input.node.operator === "!==")) return isNullish({
1844
- context: input.context,
1845
- node: input.node.left
1846
- }) || isNullish({
1847
- context: input.context,
1848
- node: input.node.right
1849
- });
1850
- return input.node.type === "CallExpression" && input.node.callee.type === "MemberExpression" && importedMember({
1851
- context: input.context,
1852
- importedName: "Predicate",
1853
- node: input.node.callee
1854
- }) && exists(memberName(input.node.callee), (name) => contains$1(nullishPredicates, name));
1855
- }
1856
- const noNullishTernary = defineRule({
1857
- create: (context) => ({ ConditionalExpression: (node) => {
1858
- if (testsNullish({
1859
- context,
1860
- node: node.test
1861
- })) context.report({
1862
- message: "Use ?? for a default, or Option for a value that may be absent, instead of a nullish ternary.",
1863
- node
1864
- });
1865
- } }),
1866
- meta: { type: "problem" }
1867
- });
1868
- //#endregion
1869
1902
  //#region src/rules/no-option-value-access.ts
1870
1903
  function checks(input) {
1871
1904
  if (input.test.type === "LogicalExpression" && input.test.operator === input.operator) return checks({
@@ -1883,7 +1916,7 @@ function checks(input) {
1883
1916
  }) && input.test.arguments[0] !== void 0 && input.context.sourceCode.getText(input.test.arguments[0]) === input.subject;
1884
1917
  }
1885
1918
  function exits(node) {
1886
- return contains$1([
1919
+ return contains([
1887
1920
  "ContinueStatement",
1888
1921
  "ReturnStatement",
1889
1922
  "ThrowStatement"
@@ -1920,7 +1953,7 @@ function guarded(input) {
1920
1953
  }
1921
1954
  const noOptionValueAccess = defineRule({
1922
1955
  create: (context) => ({ MemberExpression: (node) => {
1923
- if (!contains(memberName(node), "value")) return;
1956
+ if (!contains$1(memberName(node), "value")) return;
1924
1957
  if (guarded({
1925
1958
  context,
1926
1959
  node,
@@ -1934,26 +1967,14 @@ const noOptionValueAccess = defineRule({
1934
1967
  });
1935
1968
  //#endregion
1936
1969
  //#region src/rules/no-property-alias.ts
1937
- const functions = [
1970
+ const FUNCTIONS = [
1938
1971
  "ArrowFunctionExpression",
1939
1972
  "FunctionDeclaration",
1940
1973
  "FunctionExpression"
1941
1974
  ];
1942
- const deferred = [
1943
- "ChainExpression",
1944
- "ConditionalExpression",
1945
- "DoWhileStatement",
1946
- "ForInStatement",
1947
- "ForOfStatement",
1948
- "ForStatement",
1949
- "IfStatement",
1950
- "LogicalExpression",
1951
- "SwitchStatement",
1952
- "WhileStatement"
1953
- ];
1954
1975
  function insideFunction(node) {
1955
- if (isNullish$1(node.parent) || node.parent.type === "Program") return false;
1956
- if (contains$1(functions, node.parent.type)) return true;
1976
+ if (isNullish(node.parent) || node.parent.type === "Program") return false;
1977
+ if (contains(FUNCTIONS, node.parent.type)) return true;
1957
1978
  return insideFunction(node.parent);
1958
1979
  }
1959
1980
  function sameRoot(input) {
@@ -1965,9 +1986,58 @@ function sameRoot(input) {
1965
1986
  scope: input.context.sourceCode.getScope(input.read)
1966
1987
  }));
1967
1988
  }
1989
+ function pathTop(node) {
1990
+ if (node.parent?.type === "MemberExpression" && node.parent.object === node && !node.parent.computed) return pathTop(node.parent);
1991
+ return node;
1992
+ }
1993
+ function tested(node) {
1994
+ if (isNullish(node.parent)) return false;
1995
+ if (node.parent.type === "LogicalExpression") return node.parent.left === node || tested(node.parent);
1996
+ if (contains([
1997
+ "ChainExpression",
1998
+ "TSAsExpression",
1999
+ "TSNonNullExpression"
2000
+ ], node.parent.type)) return tested(node.parent);
2001
+ return node.parent.type === "BinaryExpression" && contains([
2002
+ "!=",
2003
+ "!==",
2004
+ "==",
2005
+ "===",
2006
+ "in",
2007
+ "instanceof"
2008
+ ], node.parent.operator) || node.parent.type === "UnaryExpression" && contains(["!", "typeof"], node.parent.operator) || node.parent.type === "ConditionalExpression" && node.parent.test === node || node.parent.type === "IfStatement" && node.parent.test === node || node.parent.type === "SwitchStatement" && node.parent.discriminant === node || node.parent.type === "CallExpression" && node.parent.callee !== node && !(node.parent.parent.type === "CallExpression" && node.parent.parent.callee === node.parent) && (predicate(node.parent.callee) || tested(node.parent));
2009
+ }
2010
+ function predicate(callee) {
2011
+ if (callee.type === "CallExpression") return predicate(callee.callee);
2012
+ if (callee.type === "Identifier") return matches(/^(?:has|is)(?:[A-Z]|$)/u)(callee.name);
2013
+ return callee.type === "MemberExpression" && callee.property.type === "Identifier" && matches(/^(?:has|is)(?:[A-Z]|$)/u)(callee.property.name);
2014
+ }
2015
+ function deferred(input) {
2016
+ if (isNullish(input.node.parent) || input.node.parent === input.block) return false;
2017
+ const parent = input.node.parent;
2018
+ if (contains(FUNCTIONS, parent.type) && !(parent.parent?.type === "CallExpression" && some$1(parent.parent.arguments, (argument) => argument === parent))) return true;
2019
+ return deferred({
2020
+ ...input,
2021
+ node: parent
2022
+ });
2023
+ }
2024
+ function needsAlias(input) {
2025
+ if (input.declaration.parent.type !== "BlockStatement" || !contains(FUNCTIONS, input.declaration.parent.parent.type) || !pipe(input.declaration.parent.body, takeWhile((statement) => statement !== input.declaration), every((statement) => statement.type === "VariableDeclaration"))) return true;
2026
+ const block = input.declaration.parent;
2027
+ const paths = map$1(input.reads, (read) => ({
2028
+ callback: enclosed({
2029
+ block,
2030
+ node: read,
2031
+ types: FUNCTIONS
2032
+ }),
2033
+ node: pathTop(read),
2034
+ text: input.context.sourceCode.getText(pathTop(read))
2035
+ }));
2036
+ return some$1(paths, (checked) => tested(checked.node) && some$1(paths, (read) => read.callback && (read.text === checked.text || startsWith(`${checked.text}.`)(read.text))));
2037
+ }
1968
2038
  function enclosed(input) {
1969
- if (isNullish$1(input.node.parent) || input.node.parent === input.block) return false;
1970
- if (contains$1(input.types, input.node.parent.type)) return true;
2039
+ if (isNullish(input.node.parent) || input.node.parent === input.block) return false;
2040
+ if (contains(input.types, input.node.parent.type)) return true;
1971
2041
  return enclosed({
1972
2042
  ...input,
1973
2043
  node: input.node.parent
@@ -1986,24 +2056,6 @@ function written(node) {
1986
2056
  if (node.type === "UpdateExpression" || node.type === "UnaryExpression" && node.operator === "delete") return objectRoot(node.argument);
1987
2057
  return none();
1988
2058
  }
1989
- function inert(token) {
1990
- if (contains$1([
1991
- "Boolean",
1992
- "Identifier",
1993
- "Null",
1994
- "Numeric",
1995
- "String"
1996
- ], token.type)) return true;
1997
- if (token.type === "Keyword") return contains$1(["const", "return"], token.value);
1998
- return token.type === "Punctuator" && contains$1([
1999
- "(",
2000
- ",",
2001
- ":",
2002
- "=",
2003
- "[",
2004
- "{"
2005
- ], token.value);
2006
- }
2007
2059
  function replacement(input) {
2008
2060
  if (input.read.parent?.type === "Property" && input.read.parent.shorthand) return `${input.name}: ${input.text}`;
2009
2061
  return input.text;
@@ -2013,15 +2065,22 @@ function report$2(input) {
2013
2065
  const text = input.context.sourceCode.getText(input.init);
2014
2066
  pipe(rootName(input.init), filter((root) => isArrayNonEmpty(reads) && every(reads, (read) => {
2015
2067
  const used = outermost(read);
2016
- return read.parent.type !== "ExportSpecifier" && !enclosed({
2068
+ return read.parent.type !== "ExportSpecifier" && (!needsAlias({
2069
+ context: input.context,
2070
+ declaration: input.declaration,
2071
+ reads
2072
+ }) || !enclosed({
2017
2073
  block: input.declaration.parent,
2018
2074
  node: read,
2019
- types: functions
2075
+ types: FUNCTIONS
2076
+ })) && !deferred({
2077
+ block: input.declaration.parent,
2078
+ node: read
2020
2079
  }) && !(used.parent?.type === "CallExpression" && used.parent.callee === used) && !(used.parent?.type === "TaggedTemplateExpression" && used.parent.tag === used) && !some$1(input.writes, (write) => between({
2021
2080
  declaration: input.declaration,
2022
2081
  node: write,
2023
2082
  read
2024
- }) && contains(written(write), root)) && sameRoot({
2083
+ }) && contains$1(written(write), root)) && sameRoot({
2025
2084
  context: input.context,
2026
2085
  declarator: input.node,
2027
2086
  name: root,
@@ -2034,7 +2093,19 @@ function report$2(input) {
2034
2093
  if (reads.length !== 1 || some$1(reads, (read) => startsWith("JSX")(read.parent.type) || enclosed({
2035
2094
  block: input.declaration.parent,
2036
2095
  node: read,
2037
- types: deferred
2096
+ types: [
2097
+ ...FUNCTIONS,
2098
+ "ChainExpression",
2099
+ "ConditionalExpression",
2100
+ "DoWhileStatement",
2101
+ "ForInStatement",
2102
+ "ForOfStatement",
2103
+ "ForStatement",
2104
+ "IfStatement",
2105
+ "LogicalExpression",
2106
+ "SwitchStatement",
2107
+ "WhileStatement"
2108
+ ]
2038
2109
  }) || some$1(input.statements, (node) => between({
2039
2110
  declaration: input.declaration,
2040
2111
  node,
@@ -2080,6 +2151,19 @@ const noPropertyAlias = defineRule({
2080
2151
  },
2081
2152
  UpdateExpression: write,
2082
2153
  VariableDeclarator: (node) => {
2154
+ if (node.parent.type === "VariableDeclaration" && node.parent.parent.type === "ExportNamedDeclaration" && node.id.type === "Identifier" && node.init?.type === "MemberExpression") {
2155
+ const init = node.init;
2156
+ pipe(rootName(init), flatMap((root) => variableFromScope({
2157
+ name: root,
2158
+ scope: context.sourceCode.getScope(node)
2159
+ })), filter((variable) => every(variable.defs, (definition) => definition.type === "Variable")), match({
2160
+ onNone: constVoid,
2161
+ onSome: (variable) => context.report({
2162
+ message: `Export ${variable.name} and read ${context.sourceCode.getText(init)} where it is used.`,
2163
+ node
2164
+ })
2165
+ }));
2166
+ }
2083
2167
  if (node.parent.type === "VariableDeclaration" && node.parent.kind === "const" && node.parent.declarations.length === 1 && (node.parent.parent.type === "BlockStatement" || node.parent.parent.type === "StaticBlock") && node.id.type === "Identifier" && node.id.typeAnnotation === null && node.init?.type === "MemberExpression" && insideFunction(node.parent)) append$1(candidates, {
2084
2168
  declaration: node.parent,
2085
2169
  init: node.init,
@@ -2103,7 +2187,7 @@ function isTopLevelStatement(node) {
2103
2187
  }
2104
2188
  function insideCycleType(input) {
2105
2189
  if (input.node.type === "Program") return false;
2106
- if (input.node.type === "TSTypeAliasDeclaration" && isTopLevelStatement(input.node)) return contains$1(input.cycleNames, input.node.id.name);
2190
+ if (input.node.type === "TSTypeAliasDeclaration" && isTopLevelStatement(input.node)) return contains(input.cycleNames, input.node.id.name);
2107
2191
  return insideCycleType({
2108
2192
  cycleNames: input.cycleNames,
2109
2193
  node: input.node.parent
@@ -2144,7 +2228,7 @@ function shapeLiterals(input) {
2144
2228
  return pipe(typeDeclarations({
2145
2229
  context: input.context,
2146
2230
  name: input.type.typeName
2147
- }), filter$1((declaration) => declaration.type === "TSTypeAliasDeclaration"), filter$1((alias) => !contains$1(input.seen, alias)), flatMap$1((alias) => shapeLiterals({
2231
+ }), filter$1((declaration) => declaration.type === "TSTypeAliasDeclaration"), filter$1((alias) => !contains(input.seen, alias)), flatMap$1((alias) => shapeLiterals({
2148
2232
  ...input,
2149
2233
  seen: append(input.seen, alias),
2150
2234
  type: alias.typeAnnotation
@@ -2292,7 +2376,7 @@ function isReactUseRef(input) {
2292
2376
  node: input.node.callee,
2293
2377
  source: "react"
2294
2378
  });
2295
- return input.node.callee.type === "MemberExpression" && contains(memberName(input.node.callee), "useRef") && input.node.callee.object.type === "Identifier" && isNamespaceImport({
2379
+ return input.node.callee.type === "MemberExpression" && contains$1(memberName(input.node.callee), "useRef") && input.node.callee.object.type === "Identifier" && isNamespaceImport({
2296
2380
  context: input.context,
2297
2381
  node: input.node.callee.object,
2298
2382
  source: "react"
@@ -2318,16 +2402,10 @@ const noRedundantUseRefNullType = defineRule({
2318
2402
  //#region src/rules/no-redundant-variable-annotation.ts
2319
2403
  const noRedundantVariableAnnotation = defineRule({
2320
2404
  create: (context) => ({ VariableDeclarator: (node) => {
2321
- if (node.init === null || isNullish$1(node.id.typeAnnotation)) return;
2322
- if (node.init.type === "ArrayExpression" && isArrayEmpty(node.init.elements)) {
2323
- context.report({
2324
- message: "Write Array.empty<T>() instead of annotating an empty array.",
2325
- node: node.id.typeAnnotation
2326
- });
2327
- return;
2328
- }
2329
- if (node.init.type === "TSAsExpression" && context.sourceCode.getText(node.init.typeAnnotation) === context.sourceCode.getText(node.id.typeAnnotation.typeAnnotation)) context.report({
2330
- message: "Drop this annotation; inference gives the same type.",
2405
+ if (node.init?.type !== "ArrayExpression" || isNullish(node.id.typeAnnotation)) return;
2406
+ if (!isArrayEmpty(node.init.elements)) return;
2407
+ context.report({
2408
+ message: "Write Array.empty<T>() instead of annotating an empty array.",
2331
2409
  node: node.id.typeAnnotation
2332
2410
  });
2333
2411
  } }),
@@ -2367,7 +2445,7 @@ const shipped = [
2367
2445
  schema: "Natural"
2368
2446
  }
2369
2447
  ];
2370
- function schemaMember(input) {
2448
+ function schemaMember$1(input) {
2371
2449
  if (input.node.type !== "MemberExpression" || !importedMember({
2372
2450
  context: input.context,
2373
2451
  importedName: "Schema",
@@ -2377,16 +2455,16 @@ function schemaMember(input) {
2377
2455
  }
2378
2456
  function shippedSchema(input) {
2379
2457
  if (input.filter.type !== "CallExpression") return none();
2380
- const base = schemaMember({
2458
+ const base = schemaMember$1({
2381
2459
  context: input.context,
2382
2460
  node: input.base
2383
2461
  });
2384
- const check = schemaMember({
2462
+ const check = schemaMember$1({
2385
2463
  context: input.context,
2386
2464
  node: input.filter.callee
2387
2465
  });
2388
2466
  const [value, ...rest] = input.filter.arguments;
2389
- return pipe(shipped, findFirst((entry) => contains(base, entry.base) && contains(check, entry.check) && isArrayEmpty(rest) && match(fromUndefinedOr(entry.only), {
2467
+ return pipe(shipped, findFirst((entry) => contains$1(base, entry.base) && contains$1(check, entry.check) && isArrayEmpty(rest) && match(fromUndefinedOr(entry.only), {
2390
2468
  onNone: () => value === void 0,
2391
2469
  onSome: (only) => value?.type === "Literal" && value.value === only
2392
2470
  })), map((entry) => entry.schema));
@@ -2397,14 +2475,14 @@ function pipedBase(node) {
2397
2475
  if (node.parent.arguments[1] !== node) return none();
2398
2476
  return fromNullishOr(node.parent.arguments[0]);
2399
2477
  }
2400
- if (node.parent.callee.type !== "MemberExpression" || !contains(memberName(node.parent.callee), "pipe") || node.parent.arguments.length !== 1) return none();
2478
+ if (node.parent.callee.type !== "MemberExpression" || !contains$1(memberName(node.parent.callee), "pipe") || node.parent.arguments.length !== 1) return none();
2401
2479
  return some(node.parent.callee.object);
2402
2480
  }
2403
2481
  function reinventedSchema(input) {
2404
- if (input.node.callee.type !== "MemberExpression" || !contains(memberName(input.node.callee), "check")) return none();
2482
+ if (input.node.callee.type !== "MemberExpression" || !contains$1(memberName(input.node.callee), "check")) return none();
2405
2483
  const callee = input.node.callee;
2406
2484
  const [filter] = input.node.arguments;
2407
- if (isSome(schemaMember({
2485
+ if (isSome(schemaMember$1({
2408
2486
  context: input.context,
2409
2487
  node: callee
2410
2488
  }))) {
@@ -2500,7 +2578,7 @@ function recursive(input) {
2500
2578
  const noReturnType = defineRule({
2501
2579
  create: (context) => {
2502
2580
  function check(node) {
2503
- if (isNullish$1(node.returnType) || node.body === null || node.returnType.typeAnnotation.type === "TSTypePredicate" || node.parent.type === "CallExpression" && importedMember({
2581
+ if (isNullish(node.returnType) || node.body === null || node.returnType.typeAnnotation.type === "TSTypePredicate" || node.parent.type === "CallExpression" && importedMember({
2504
2582
  context,
2505
2583
  importedName: "Schema",
2506
2584
  node: node.parent.callee,
@@ -2524,7 +2602,7 @@ const noReturnType = defineRule({
2524
2602
  });
2525
2603
  //#endregion
2526
2604
  //#region src/rules/no-single-use-value.ts
2527
- const repeating = [
2605
+ const REPEATING = [
2528
2606
  "ArrowFunctionExpression",
2529
2607
  "DoWhileStatement",
2530
2608
  "ForInStatement",
@@ -2539,7 +2617,7 @@ function runsOnce(input) {
2539
2617
  ...input,
2540
2618
  node: input.node
2541
2619
  });
2542
- if (contains$1(repeating, input.node.type) || input.node.type === "IfStatement" || input.node.type === "ConditionalExpression" || input.node.type === "LogicalExpression" || input.node.type === "ChainExpression" || input.node.type === "SwitchStatement" || input.node.type === "TryStatement") return false;
2620
+ if (contains(REPEATING, input.node.type) || input.node.type === "IfStatement" || input.node.type === "ConditionalExpression" || input.node.type === "LogicalExpression" || input.node.type === "ChainExpression" || input.node.type === "SwitchStatement" || input.node.type === "TryStatement") return false;
2543
2621
  return climb({
2544
2622
  ...input,
2545
2623
  node: input.node
@@ -2547,7 +2625,7 @@ function runsOnce(input) {
2547
2625
  }
2548
2626
  function climb(input) {
2549
2627
  if (input.node === input.statement) return true;
2550
- if (isNullish$1(input.node.parent)) return false;
2628
+ if (isNullish(input.node.parent)) return false;
2551
2629
  return runsOnce({
2552
2630
  child: input.node,
2553
2631
  node: input.node.parent,
@@ -2562,8 +2640,16 @@ function insideConditional(input) {
2562
2640
  node: input.node.parent
2563
2641
  });
2564
2642
  }
2565
- function candidate(node) {
2566
- return node.parent.type === "VariableDeclaration" && node.parent.kind === "const" && node.parent.declarations.length === 1 && node.parent.parent.type === "BlockStatement" && node.id.type === "Identifier" && node.id.typeAnnotation === null && node.init !== null && !contains$1(["ArrowFunctionExpression", "FunctionExpression"], node.init.type) && !(node.init.type === "MemberExpression" && isSome(rootName(node.init))) && !(node.init.type === "Literal" && !hasProperty(node.init, "regex")) && !(node.init.type === "TemplateLiteral" && isArrayEmpty(node.init.expressions));
2643
+ function candidate(context, node) {
2644
+ return node.parent.type === "VariableDeclaration" && node.parent.kind === "const" && node.parent.declarations.length === 1 && node.parent.parent.type === "BlockStatement" && node.id.type === "Identifier" && node.id.typeAnnotation === null && node.init !== null && !contains([
2645
+ "ArrowFunctionExpression",
2646
+ "FunctionExpression",
2647
+ "JSXElement",
2648
+ "JSXFragment"
2649
+ ], unwrapped(node.init).type) && !(node.init.type === "CallExpression" && isSchemaOperationCall({
2650
+ context,
2651
+ node: node.init
2652
+ })) && !(node.init.type === "MemberExpression" && isSome(rootName(node.init))) && !(node.init.type === "Literal" && !hasProperty(node.init, "regex")) && !(node.init.type === "TemplateLiteral" && isArrayEmpty(node.init.expressions));
2567
2653
  }
2568
2654
  function unwrapped(node) {
2569
2655
  return pipe(typeWrapped(node), match({
@@ -2581,10 +2667,61 @@ function inlined(input) {
2581
2667
  if (input.read.range[0] === input.next.range[0]) return `;${value}`;
2582
2668
  return value;
2583
2669
  }
2670
+ function executes(node) {
2671
+ if (contains([
2672
+ "AwaitExpression",
2673
+ "CallExpression",
2674
+ "MemberExpression",
2675
+ "NewExpression",
2676
+ "SpreadElement",
2677
+ "TaggedTemplateExpression",
2678
+ "YieldExpression"
2679
+ ], node.type)) return true;
2680
+ if (contains([
2681
+ "ArrowFunctionExpression",
2682
+ "FunctionDeclaration",
2683
+ "FunctionExpression"
2684
+ ], node.type)) return false;
2685
+ return some$1(childNodes(node), executes);
2686
+ }
2687
+ function suspends(node) {
2688
+ if (node.type === "YieldExpression" || node.type === "AwaitExpression") return true;
2689
+ if (contains([
2690
+ "ArrowFunctionExpression",
2691
+ "FunctionDeclaration",
2692
+ "FunctionExpression"
2693
+ ], node.type)) return false;
2694
+ return some$1(childNodes(node), suspends);
2695
+ }
2696
+ function surface(node) {
2697
+ if (contains([
2698
+ "ExpressionStatement",
2699
+ "ReturnStatement",
2700
+ "VariableDeclaration"
2701
+ ], node.type) || node.type === "ArrowFunctionExpression" && node.expression) return true;
2702
+ if (isNullish(node.parent) || !contains([
2703
+ "AwaitExpression",
2704
+ "JSXAttribute",
2705
+ "JSXElement",
2706
+ "JSXExpressionContainer",
2707
+ "JSXFragment",
2708
+ "JSXOpeningElement",
2709
+ "VariableDeclarator",
2710
+ "YieldExpression"
2711
+ ], node.type)) return false;
2712
+ return surface(node.parent);
2713
+ }
2714
+ function readable(input) {
2715
+ if (!pipe(input.context.sourceCode.getText(input.init), includes("\n"))) return true;
2716
+ const slot = outermost(input.read);
2717
+ if (isNullish(slot.parent) || suspends(input.init)) return false;
2718
+ if (slot.parent.type === "JSXExpressionContainer" || slot.parent.type === "ReturnStatement") return true;
2719
+ return isNotNullish(slot.parent.parent) && (slot.parent.type === "CallExpression" && slot.parent.callee !== slot || slot.parent.type === "ArrayExpression") && surface(slot.parent.parent);
2720
+ }
2584
2721
  function report$1(input) {
2585
2722
  const declaration = input.node.parent;
2586
2723
  const init = input.node.init;
2587
- if (declaration.type !== "VariableDeclaration" || declaration.parent.type !== "BlockStatement" || input.node.id.type !== "Identifier" || init === null || pipe(input.context.sourceCode.getText(init), includes("\n"))) return;
2724
+ if (declaration.type !== "VariableDeclaration" || declaration.parent.type !== "BlockStatement" || input.node.id.type !== "Identifier" || init === null) return;
2588
2725
  const statements = declaration.parent.body;
2589
2726
  const name = input.node.id.name;
2590
2727
  pipe(findFirstIndex(statements, (statement) => statement === declaration), flatMap((index) => get$1(statements, index + 1)), flatMap((next) => pipe(variableFromScope({
@@ -2593,6 +2730,10 @@ function report$1(input) {
2593
2730
  }), map((variable) => filter$1(variable.references, (reference) => reference.isRead())), filter((reads) => reads.length === 1), flatMap(head), map((reference) => reference.identifier), filter((read) => read.range[0] >= next.range[0] && read.range[1] <= next.range[1] && climb({
2594
2731
  node: read,
2595
2732
  statement: next
2733
+ }) && readable({
2734
+ context: input.context,
2735
+ init,
2736
+ read
2596
2737
  }) && !(init.type === "ConditionalExpression" && insideConditional({
2597
2738
  node: read,
2598
2739
  statement: next
@@ -2606,7 +2747,7 @@ function report$1(input) {
2606
2747
  if (!fixable({
2607
2748
  init,
2608
2749
  read: found.read
2609
- })) return [];
2750
+ }) || executes(init) && !every(input.context.sourceCode.getTokensBetween(declaration, found.read), inert)) return [];
2610
2751
  return [fixer.remove(declaration), fixer.replaceText(found.read, inlined({
2611
2752
  context: input.context,
2612
2753
  init,
@@ -2641,7 +2782,7 @@ const noSingleUseValue = defineRule({
2641
2782
  TaggedTemplateExpression: effect,
2642
2783
  UpdateExpression: effect,
2643
2784
  VariableDeclarator: (node) => {
2644
- if (candidate(node)) update(candidates, append(node));
2785
+ if (candidate(context, node)) update(candidates, append(node));
2645
2786
  },
2646
2787
  YieldExpression: effect
2647
2788
  };
@@ -2652,6 +2793,22 @@ const noSingleUseValue = defineRule({
2652
2793
  }
2653
2794
  });
2654
2795
  //#endregion
2796
+ //#region src/rules/no-stored-jsx.ts
2797
+ function element(node) {
2798
+ if (node.type === "JSXElement" || node.type === "JSXFragment") return true;
2799
+ return pipe(typeWrapped(node), exists(element));
2800
+ }
2801
+ const noStoredJsx = defineRule({
2802
+ create: (context) => ({ VariableDeclarator: (node) => {
2803
+ if (node.init === null || !element(node.init)) return;
2804
+ context.report({
2805
+ message: "Write the element where it renders, or make it a component when several places render it.",
2806
+ node
2807
+ });
2808
+ } }),
2809
+ meta: { type: "problem" }
2810
+ });
2811
+ //#endregion
2655
2812
  //#region src/rules/no-stored-schema-operation.ts
2656
2813
  function storedSchemaOperation(node) {
2657
2814
  return node.parent.type === "VariableDeclarator" && node.parent.init === node || node.parent.type === "Property" && node.parent.value === node || node.parent.type === "PropertyDefinition" && node.parent.value === node || node.parent.type === "ArrayExpression" || node.parent.type === "AssignmentExpression" && node.parent.right === node;
@@ -2673,7 +2830,7 @@ const noStoredSchemaOperation = defineRule({
2673
2830
  const noSwitchStatement = defineRule({
2674
2831
  create: (context) => ({ SwitchStatement: (node) => {
2675
2832
  context.report({
2676
- message: "Use Match instead of switch.",
2833
+ message: "Use pipe(Match.value(x), Match.tag(...) or Match.when(...), Match.exhaustive) instead of switch.",
2677
2834
  node
2678
2835
  });
2679
2836
  } }),
@@ -2715,7 +2872,7 @@ function detachable(input) {
2715
2872
  function forwardedChain(input) {
2716
2873
  const chain = callGroups(input.returned);
2717
2874
  function fixed(node) {
2718
- return node.type === "Literal" || exists(rootName(node), (root) => !contains$1(input.names, root));
2875
+ return node.type === "Literal" || exists(rootName(node), (root) => !contains(input.names, root));
2719
2876
  }
2720
2877
  return matchRight(chain.groups, {
2721
2878
  onEmpty: constFalse,
@@ -2731,7 +2888,7 @@ function forwardedChain(input) {
2731
2888
  function exactForwardingFunction(input) {
2732
2889
  const names = pipe(input.node.params, map$1(parameterName), getSomes);
2733
2890
  const returned = returnedExpression(input.node);
2734
- if (input.node.async || input.node.generator || isArrayEmpty(names) || names.length !== input.node.params.length || isNullish$1(returned)) return false;
2891
+ if (input.node.async || input.node.generator || isArrayEmpty(names) || names.length !== input.node.params.length || isNullish(returned)) return false;
2735
2892
  if (returned.type === "Identifier") return names.length === 1 && returned.name === names[0];
2736
2893
  return returned.type === "NewExpression" && returned.callee.type === "Identifier" && forwarded({
2737
2894
  args: returned.arguments,
@@ -2789,7 +2946,7 @@ function exportedAlias(input) {
2789
2946
  return input.node.parent.type === "VariableDeclaration" && input.node.parent.kind === "const" && input.node.parent.parent.type === "ExportNamedDeclaration" && input.node.id.type === "Identifier" && input.node.init?.type === "Identifier" && pipe(variableFor(input.context, input.node.init), exists((variable) => some$1(variable.defs, (definition) => definition.type === "ImportBinding" || definition.type === "FunctionName" || definition.type === "ClassName" || definition.node.type === "VariableDeclarator" && definition.node.parent.type === "VariableDeclaration" && definition.node.parent.kind === "const")));
2790
2947
  }
2791
2948
  function singleUseLiteral(input) {
2792
- if (input.node.parent.type !== "VariableDeclaration" || input.node.parent.kind !== "const" || isExport(input.node.parent.parent) || input.node.id.type !== "Identifier" || input.node.id.typeAnnotation !== null || !(input.node.init?.type === "Literal" && !hasProperty(input.node.init, "regex") || input.node.init?.type === "TemplateLiteral" && isArrayEmpty(input.node.init.expressions))) return false;
2949
+ if (input.node.parent.type !== "VariableDeclaration" || input.node.parent.kind !== "const" || isExport(input.node.parent.parent) || input.node.parent.parent.type === "Program" || input.node.id.type !== "Identifier" || input.node.id.typeAnnotation !== null || !(input.node.init?.type === "Literal" && !hasProperty(input.node.init, "regex") || input.node.init?.type === "TemplateLiteral" && isArrayEmpty(input.node.init.expressions))) return false;
2793
2950
  return pipe(variableFromScope({
2794
2951
  name: input.node.id.name,
2795
2952
  scope: input.context.sourceCode.getScope(input.node)
@@ -2804,7 +2961,7 @@ function singleUseLayerPart(input) {
2804
2961
  }), map((variable) => filter$1(variable.references, (reference) => reference.isRead())), exists((reads) => {
2805
2962
  const consumer = reads[0]?.identifier.parent;
2806
2963
  if (reads.length !== 1 || consumer?.type !== "CallExpression") return false;
2807
- if (init.type === "MemberExpression") return contains(memberName(init), "layer") && (importedMember({
2964
+ if (init.type === "MemberExpression") return contains$1(memberName(init), "layer") && (importedMember({
2808
2965
  context: input.context,
2809
2966
  importedName: "Layer",
2810
2967
  node: consumer.callee
@@ -2827,10 +2984,17 @@ function singleUseLayerPart(input) {
2827
2984
  });
2828
2985
  }));
2829
2986
  }
2987
+ function isComponent(node) {
2988
+ if (node.type === "FunctionDeclaration") return exists(fromNullishOr(node.id), (id) => matches(/^[A-Z]/u)(id.name));
2989
+ return node.parent.type === "VariableDeclarator" && node.parent.id.type === "Identifier" && matches(/^[A-Z]/u)(node.parent.id.name);
2990
+ }
2991
+ function isCatchHandler(node) {
2992
+ return node.parent.type === "Property" && !node.parent.computed && node.parent.key.type === "Identifier" && node.parent.key.name === "catch";
2993
+ }
2830
2994
  const noTrivialIndirection = defineRule({
2831
2995
  create: (context) => ({
2832
2996
  ArrowFunctionExpression: (node) => {
2833
- if ((node.parent.type === "VariableDeclarator" || node.parent.type === "Property") && (exactForwardingFunction({
2997
+ if ((node.parent.type === "VariableDeclarator" || node.parent.type === "Property") && !isComponent(node) && !isCatchHandler(node) && (exactForwardingFunction({
2834
2998
  context,
2835
2999
  node
2836
3000
  }) || singleUseThunk({
@@ -2848,7 +3012,7 @@ const noTrivialIndirection = defineRule({
2848
3012
  });
2849
3013
  },
2850
3014
  FunctionDeclaration: (node) => {
2851
- if (exactForwardingFunction({
3015
+ if (!isComponent(node) && (exactForwardingFunction({
2852
3016
  context,
2853
3017
  node
2854
3018
  }) || singleUseThunk({
@@ -2857,7 +3021,7 @@ const noTrivialIndirection = defineRule({
2857
3021
  }) || singleCallerWrapper({
2858
3022
  context,
2859
3023
  node
2860
- })) context.report({
3024
+ }))) context.report({
2861
3025
  message: indirectionMessage({
2862
3026
  context,
2863
3027
  node
@@ -2866,7 +3030,7 @@ const noTrivialIndirection = defineRule({
2866
3030
  });
2867
3031
  },
2868
3032
  FunctionExpression: (node) => {
2869
- if ((node.parent.type === "VariableDeclarator" || node.parent.type === "Property" || node.parent.type === "MethodDefinition" && node.parent.override !== true) && (exactForwardingFunction({
3033
+ if ((node.parent.type === "VariableDeclarator" || node.parent.type === "Property" || node.parent.type === "MethodDefinition" && node.parent.override !== true) && !isComponent(node) && !isCatchHandler(node) && (exactForwardingFunction({
2870
3034
  context,
2871
3035
  node
2872
3036
  }) || singleUseThunk({
@@ -2895,7 +3059,7 @@ const noTrivialIndirection = defineRule({
2895
3059
  context,
2896
3060
  node
2897
3061
  })) context.report({
2898
- message: "Use the immutable source binding directly.",
3062
+ message: `Use ${context.sourceCode.getText(node.init)} directly; this name is an alias.`,
2899
3063
  node
2900
3064
  });
2901
3065
  if (singleUseLiteral({
@@ -2917,13 +3081,57 @@ const noTrivialIndirection = defineRule({
2917
3081
  meta: { type: "problem" }
2918
3082
  });
2919
3083
  //#endregion
3084
+ //#region src/rules/no-type-from-value.ts
3085
+ function schemaMember(name) {
3086
+ return name.type === "TSQualifiedName" && contains([
3087
+ "Encoded",
3088
+ "Type",
3089
+ "cases",
3090
+ "fields",
3091
+ "literals",
3092
+ "members"
3093
+ ], name.right.name);
3094
+ }
3095
+ function valueQuery(node) {
3096
+ if (node.type === "TSParenthesizedType") return valueQuery(node.typeAnnotation);
3097
+ if (node.type === "TSIndexedAccessType") return valueQuery(node.objectType);
3098
+ return node.type === "TSTypeQuery" && (node.exprName.type === "Identifier" || node.exprName.type === "TSQualifiedName" && !schemaMember(node.exprName));
3099
+ }
3100
+ function nestedObject(node) {
3101
+ return node.parent?.type === "TSIndexedAccessType" && node.parent.objectType === node;
3102
+ }
3103
+ const noTypeFromValue = defineRule({
3104
+ create: (context) => {
3105
+ function report(node) {
3106
+ context.report({
3107
+ message: "Declare the closed set as a schema, such as Schema.Literals, and read its type with typeof X.Type.",
3108
+ node
3109
+ });
3110
+ }
3111
+ return {
3112
+ TSIndexedAccessType: (node) => {
3113
+ if (!nestedObject(node) && valueQuery(node.objectType)) report(node);
3114
+ },
3115
+ TSTypeOperator: (node) => {
3116
+ if (node.operator === "keyof" && !nestedObject(node) && valueQuery(node.typeAnnotation)) report(node);
3117
+ }
3118
+ };
3119
+ },
3120
+ meta: { type: "problem" }
3121
+ });
3122
+ //#endregion
2920
3123
  //#region src/rules/no-typeof.ts
3124
+ function enclosingFunction(node) {
3125
+ if (node.type === "ArrowFunctionExpression" || node.type === "FunctionDeclaration" || node.type === "FunctionExpression") return some(node);
3126
+ return flatMap(fromNullishOr(node.parent), enclosingFunction);
3127
+ }
2921
3128
  const noTypeof = defineRule({
2922
3129
  create: (context) => ({ UnaryExpression: (node) => {
2923
3130
  if (node.operator !== "typeof") return;
2924
3131
  if (node.argument.type === "Identifier" && !exists(variableFor(context, node.argument), (variable) => isArrayNonEmpty(variable.defs))) return;
3132
+ if (exists(enclosingFunction(node), (fn) => isSome(replaceableGuard(fn)))) return;
2925
3133
  context.report({
2926
- message: "Replace typeof with a Predicate guard such as Predicate.isString.",
3134
+ message: "Replace typeof with its Predicate guard: Predicate.isString, isNumber, isBoolean, isFunction, isObject or isUndefined.",
2927
3135
  node
2928
3136
  });
2929
3137
  } }),
@@ -3001,7 +3209,7 @@ const noUnvalidatedJsonDecode = defineRule({
3001
3209
  //#region src/rules/preserve-error-cause.ts
3002
3210
  function constructedFields(node) {
3003
3211
  if (node?.type !== "CallExpression" && node?.type !== "NewExpression") return none();
3004
- const constructs = node.type === "NewExpression" || node.callee.type === "MemberExpression" && contains(memberName(node.callee), "make");
3212
+ const constructs = node.type === "NewExpression" || node.callee.type === "MemberExpression" && contains$1(memberName(node.callee), "make");
3005
3213
  const fields = node.arguments[0];
3006
3214
  if (!constructs || fields?.type !== "ObjectExpression") return none();
3007
3215
  return some(fields);
@@ -3024,7 +3232,7 @@ const preserveErrorCause = defineRule({
3024
3232
  node: node.callee
3025
3233
  })) return;
3026
3234
  const name = memberName(node.callee);
3027
- if (contains(name, "mapError")) {
3235
+ if (contains$1(name, "mapError")) {
3028
3236
  forEach(filter$1(node.arguments, dropsCause), (callback) => report(context, callback));
3029
3237
  return;
3030
3238
  }
@@ -3085,7 +3293,7 @@ function isSchemaDefinition(input) {
3085
3293
  context: input.context,
3086
3294
  importedName: "Schema",
3087
3295
  node: input.node.callee
3088
- }) && contains(memberName(input.node.callee), "make")) return false;
3296
+ }) && contains$1(memberName(input.node.callee), "make")) return false;
3089
3297
  if (!expressionUsesImport({
3090
3298
  context: input.context,
3091
3299
  importedName: "Schema",
@@ -3126,7 +3334,7 @@ function exportLists(program) {
3126
3334
  };
3127
3335
  }
3128
3336
  function isExported(input) {
3129
- return input.statement.type === "ExportNamedDeclaration" || contains$1(input.exports.values, input.name) || input.typeOnly && contains$1(input.exports.types, input.name);
3337
+ return input.statement.type === "ExportNamedDeclaration" || contains(input.exports.values, input.name) || input.typeOnly && contains(input.exports.types, input.name);
3130
3338
  }
3131
3339
  function reportSchemaVariable(input) {
3132
3340
  if (input.variable.id.type !== "Identifier" || !matches(/^[A-Z]/u)(input.variable.id.name)) return;
@@ -3136,7 +3344,7 @@ function reportSchemaVariable(input) {
3136
3344
  })) return;
3137
3345
  const name = input.variable.id.name;
3138
3346
  const typeStatement = pipe(input.program.body, findFirstIndex((statement) => statement === input.statement), filter((index) => index > 0), flatMap((index) => get$1(input.program.body, index - 1)));
3139
- if (contains$1(input.cycleNames, name)) {
3347
+ if (contains(input.cycleNames, name)) {
3140
3348
  if (!pipe(namedTypeAlias({
3141
3349
  name,
3142
3350
  typeStatement
@@ -3215,7 +3423,7 @@ const schemaTypePair = defineRule({
3215
3423
  });
3216
3424
  //#endregion
3217
3425
  //#region src/oxlint.ts
3218
- const reactLegacyApis = [
3426
+ const REACT_LEGACY_APIS = [
3219
3427
  "Component",
3220
3428
  "PureComponent",
3221
3429
  "createRef",
@@ -3224,9 +3432,9 @@ const reactLegacyApis = [
3224
3432
  "useCallback",
3225
3433
  "useMemo"
3226
3434
  ];
3227
- const reactLegacyMessage = "Use React 19 function components with refs as props; React Compiler owns memoization.";
3228
- const mapMessage = "Use HashMap, or MutableHashMap for local mutation; for identity keys, wrap objects the code owns in Equal.byReferenceUnsafe, which marks them reference-compared globally.";
3229
- const reactHooks = [
3435
+ const REACT_LEGACY_MESSAGE = "Use React 19 function components with refs as props; React Compiler owns memoization.";
3436
+ const MAP_MESSAGE = "Use HashMap, or MutableHashMap for local mutation; for identity keys, wrap objects the code owns in Equal.byReferenceUnsafe, which marks them reference-compared globally.";
3437
+ const REACT_HOOKS = [
3230
3438
  "use",
3231
3439
  "useActionState",
3232
3440
  "useContext",
@@ -3245,8 +3453,8 @@ const reactHooks = [
3245
3453
  "useSyncExternalStore",
3246
3454
  "useTransition"
3247
3455
  ];
3248
- const runMessage = "Run the entry point with NodeRuntime.runMain, and Effects in React through atoms. A Promise that an external contract demands takes Effect.runPromise once, with an inline disable that names the contract.";
3249
- const runners = [
3456
+ const RUN_MESSAGE = "Run the entry point with NodeRuntime.runMain, and Effects in React through atoms. A Promise that an external contract demands takes Effect.runPromise once, with an inline disable that names the contract.";
3457
+ const RUNNERS = [
3250
3458
  "runCallback",
3251
3459
  "runCallbackWith",
3252
3460
  "runFork",
@@ -3260,7 +3468,7 @@ const runners = [
3260
3468
  "runSyncExitWith",
3261
3469
  "runSyncWith"
3262
3470
  ];
3263
- const setMessage = "Use HashSet, or MutableHashSet for local mutation; for identity keys, wrap objects the code owns in Equal.byReferenceUnsafe, which marks them reference-compared globally.";
3471
+ const SET_MESSAGE = "Use HashSet, or MutableHashSet for local mutation; for identity keys, wrap objects the code owns in Equal.byReferenceUnsafe, which marks them reference-compared globally.";
3264
3472
  const oxlint = defineConfig({
3265
3473
  categories: {
3266
3474
  correctness: "off",
@@ -3298,11 +3506,7 @@ const oxlint = defineConfig({
3298
3506
  },
3299
3507
  overrides: [
3300
3508
  {
3301
- files: [
3302
- "**/*.config.ts",
3303
- "**/app.plugin.js",
3304
- "**/main.*"
3305
- ],
3509
+ files: ["**/*.config.ts", "**/app.plugin.js"],
3306
3510
  rules: { "import/no-default-export": "off" }
3307
3511
  },
3308
3512
  {
@@ -3331,7 +3535,7 @@ const oxlint = defineConfig({
3331
3535
  rules: { "react/rules-of-hooks": "off" }
3332
3536
  },
3333
3537
  {
3334
- files: ["**/*.test.ts", "**/*.test.tsx"],
3538
+ files: ["**/*.test.ts"],
3335
3539
  rules: { "@deslop/coding-standards/no-discarded-failure": "off" }
3336
3540
  },
3337
3541
  {
@@ -3356,8 +3560,8 @@ const oxlint = defineConfig({
3356
3560
  ],
3357
3561
  rules: {
3358
3562
  "@deslop/coding-standards/explicit-effect-concurrency": "error",
3563
+ "@deslop/coding-standards/module-constant": "error",
3359
3564
  "@deslop/coding-standards/motion-limits": "error",
3360
- "@deslop/coding-standards/no-array-wrap-ternary": "error",
3361
3565
  "@deslop/coding-standards/no-barrel-module": "error",
3362
3566
  "@deslop/coding-standards/no-compiler-opt-out": "error",
3363
3567
  "@deslop/coding-standards/no-component-atom-allocation": "error",
@@ -3370,6 +3574,7 @@ const oxlint = defineConfig({
3370
3574
  "@deslop/coding-standards/no-empty-recovery": "error",
3371
3575
  "@deslop/coding-standards/no-error-message-assertion": "error",
3372
3576
  "@deslop/coding-standards/no-fake-ref-state": "error",
3577
+ "@deslop/coding-standards/no-floating-derived-type": "error",
3373
3578
  "@deslop/coding-standards/no-gradient": "error",
3374
3579
  "@deslop/coding-standards/no-hand-written-guard": "error",
3375
3580
  "@deslop/coding-standards/no-in-operator": "error",
@@ -3378,7 +3583,6 @@ const oxlint = defineConfig({
3378
3583
  "@deslop/coding-standards/no-native-control": "error",
3379
3584
  "@deslop/coding-standards/no-native-emptiness-check": "error",
3380
3585
  "@deslop/coding-standards/no-native-method-call": "error",
3381
- "@deslop/coding-standards/no-nullish-ternary": "error",
3382
3586
  "@deslop/coding-standards/no-option-value-access": "error",
3383
3587
  "@deslop/coding-standards/no-property-alias": "error",
3384
3588
  "@deslop/coding-standards/no-readonly-type-syntax": "error",
@@ -3389,9 +3593,11 @@ const oxlint = defineConfig({
3389
3593
  "@deslop/coding-standards/no-renamed-import": "error",
3390
3594
  "@deslop/coding-standards/no-return-type": "error",
3391
3595
  "@deslop/coding-standards/no-single-use-value": "error",
3596
+ "@deslop/coding-standards/no-stored-jsx": "error",
3392
3597
  "@deslop/coding-standards/no-stored-schema-operation": "error",
3393
3598
  "@deslop/coding-standards/no-switch-statement": "error",
3394
3599
  "@deslop/coding-standards/no-trivial-indirection": "error",
3600
+ "@deslop/coding-standards/no-type-from-value": "error",
3395
3601
  "@deslop/coding-standards/no-typeof": "error",
3396
3602
  "@deslop/coding-standards/no-undestructured-use-state": "error",
3397
3603
  "@deslop/coding-standards/no-unexplained-disable": "error",
@@ -3412,6 +3618,8 @@ const oxlint = defineConfig({
3412
3618
  "effecttsgo/global-timers": "error",
3413
3619
  "effecttsgo/global-timers-in-effect": "error",
3414
3620
  "effecttsgo/node-builtin-import": "error",
3621
+ "effecttsgo/prefer-effect-array": "error",
3622
+ "effecttsgo/prefer-effect-record": "error",
3415
3623
  "effecttsgo/prefer-schema-over-json": "error",
3416
3624
  "effecttsgo/process-env": "error",
3417
3625
  "effecttsgo/process-env-in-effect": "error",
@@ -3430,9 +3638,11 @@ const oxlint = defineConfig({
3430
3638
  "effecttsgo/effect-in-void-success": "error",
3431
3639
  "effecttsgo/effect-map-flatten": "error",
3432
3640
  "effecttsgo/effect-map-void": "error",
3641
+ "effecttsgo/effect-sleep-zero-to-yield-now": "error",
3433
3642
  "effecttsgo/effect-succeed-with-void": "error",
3434
3643
  "effecttsgo/flat-map-ignored-param-to-and-then": "error",
3435
3644
  "effecttsgo/flat-map-to-map": "error",
3645
+ "effecttsgo/flat-map-to-tap": "error",
3436
3646
  "effecttsgo/floating-effect": "error",
3437
3647
  "effecttsgo/floating-effect-in-vitest": "error",
3438
3648
  "effecttsgo/layer-merge-all-with-dependencies": "error",
@@ -3470,11 +3680,10 @@ const oxlint = defineConfig({
3470
3680
  "effecttsgo/catch-all-to-map-error": "error",
3471
3681
  "effecttsgo/catch-chain-to-first-success-of": "error",
3472
3682
  "effecttsgo/catch-conditional-refail-to-catch-if": "error",
3473
- "effecttsgo/catch-die-to-or-die": "error",
3474
3683
  "effecttsgo/catch-tag-to-catch-reason": "error",
3475
- "effecttsgo/catch-to-ignore": "error",
3476
3684
  "effecttsgo/catch-to-or-else-succeed": "error",
3477
3685
  "effecttsgo/catch-unfailable-effect": "error",
3686
+ "effecttsgo/error-payload-shadows-name": "error",
3478
3687
  "effecttsgo/flat-map-conditional-to-filter-or-fail": "error",
3479
3688
  "effecttsgo/global-error-in-effect-catch": "error",
3480
3689
  "effecttsgo/global-error-in-effect-failure": "error",
@@ -3483,10 +3692,8 @@ const oxlint = defineConfig({
3483
3692
  "effecttsgo/redundant-map-error": "error",
3484
3693
  "effecttsgo/redundant-or-die": "error",
3485
3694
  "effecttsgo/timeout-catch-tag-to-timeout-or-else": "error",
3486
- "effecttsgo/unknown-in-effect-catch": "error",
3487
3695
  "effecttsgo/class-self-mismatch": "error",
3488
3696
  "effecttsgo/deterministic-keys": "error",
3489
- "effecttsgo/generic-effect-services": "error",
3490
3697
  "effecttsgo/instance-of-schema": "error",
3491
3698
  "effecttsgo/new-schema-class": "error",
3492
3699
  "effecttsgo/obsolete-match-import": "error",
@@ -3499,6 +3706,7 @@ const oxlint = defineConfig({
3499
3706
  "effecttsgo/schema-number": "error",
3500
3707
  "effecttsgo/schema-struct-with-tag": "error",
3501
3708
  "effecttsgo/schema-sync-in-effect": "error",
3709
+ "effecttsgo/schema-union-of-literals": "error",
3502
3710
  "effecttsgo/service-not-as-class": "error",
3503
3711
  "effecttsgo/unnecessary-typeof-type": "error",
3504
3712
  "typescript/consistent-generic-constructors": "error",
@@ -3556,7 +3764,7 @@ const oxlint = defineConfig({
3556
3764
  "typescript/unbound-method": "error",
3557
3765
  "typescript/unified-signatures": "error",
3558
3766
  "typescript/prefer-as-const": "error",
3559
- "typescript/prefer-nullish-coalescing": "error",
3767
+ "typescript/prefer-nullish-coalescing": ["error", { ignoreTernaryTests: true }],
3560
3768
  "typescript/prefer-optional-chain": "error",
3561
3769
  "typescript/restrict-plus-operands": "error",
3562
3770
  "typescript/restrict-template-expressions": "error",
@@ -3591,8 +3799,8 @@ const oxlint = defineConfig({
3591
3799
  "no-restricted-imports": ["error", {
3592
3800
  paths: [
3593
3801
  {
3594
- importNames: reactLegacyApis,
3595
- message: reactLegacyMessage,
3802
+ importNames: REACT_LEGACY_APIS,
3803
+ message: REACT_LEGACY_MESSAGE,
3596
3804
  name: "react"
3597
3805
  },
3598
3806
  {
@@ -3621,6 +3829,10 @@ const oxlint = defineConfig({
3621
3829
  }
3622
3830
  ],
3623
3831
  patterns: [
3832
+ {
3833
+ message: "Prove a screen in the browser; no UI tests.",
3834
+ regex: "^(?:@testing-library/|jsdom$|happy-dom$)"
3835
+ },
3624
3836
  {
3625
3837
  message: "Use public package exports.",
3626
3838
  regex: "^@[^/]+/[^/]+/(?:src|lib)(?:/|$)"
@@ -3655,7 +3867,6 @@ const oxlint = defineConfig({
3655
3867
  }
3656
3868
  ]
3657
3869
  }],
3658
- "array-callback-return": "error",
3659
3870
  "max-depth": ["error", 3],
3660
3871
  "max-nested-callbacks": ["error", 6],
3661
3872
  "no-cond-assign": "error",
@@ -3701,17 +3912,13 @@ const oxlint = defineConfig({
3701
3912
  name: "Error"
3702
3913
  },
3703
3914
  {
3704
- message: mapMessage,
3915
+ message: MAP_MESSAGE,
3705
3916
  name: "Map"
3706
3917
  },
3707
3918
  {
3708
3919
  message: "Import Number from 'effect'.",
3709
3920
  name: "Number"
3710
3921
  },
3711
- {
3712
- message: "Use Record or Struct from 'effect'.",
3713
- name: "Object"
3714
- },
3715
3922
  {
3716
3923
  message: "Use Number.parse.",
3717
3924
  name: "parseFloat"
@@ -3729,7 +3936,7 @@ const oxlint = defineConfig({
3729
3936
  name: "Reflect"
3730
3937
  },
3731
3938
  {
3732
- message: setMessage,
3939
+ message: SET_MESSAGE,
3733
3940
  name: "Set"
3734
3941
  },
3735
3942
  {
@@ -3752,17 +3959,23 @@ const oxlint = defineConfig({
3752
3959
  property: "pipe"
3753
3960
  },
3754
3961
  {
3755
- allowObjects: ["Predicate"],
3756
- message: "Use Predicate.hasProperty.",
3757
- property: "hasOwnProperty"
3962
+ allowProperties: [
3963
+ "entries",
3964
+ "fromEntries",
3965
+ "hasOwn",
3966
+ "keys",
3967
+ "values"
3968
+ ],
3969
+ message: "Use Record or Struct from 'effect'.",
3970
+ object: "Object"
3758
3971
  },
3759
- ...map$1(runners, (property) => ({
3760
- message: runMessage,
3972
+ ...map$1(RUNNERS, (property) => ({
3973
+ message: RUN_MESSAGE,
3761
3974
  object: "Effect",
3762
3975
  property
3763
3976
  })),
3764
3977
  {
3765
- message: runMessage,
3978
+ message: RUN_MESSAGE,
3766
3979
  object: "ManagedRuntime",
3767
3980
  property: "make"
3768
3981
  },
@@ -3786,12 +3999,12 @@ const oxlint = defineConfig({
3786
3999
  object: "Math",
3787
4000
  property: "round"
3788
4001
  },
3789
- ...map$1(reactLegacyApis, (property) => ({
3790
- message: reactLegacyMessage,
4002
+ ...map$1(REACT_LEGACY_APIS, (property) => ({
4003
+ message: REACT_LEGACY_MESSAGE,
3791
4004
  object: "React",
3792
4005
  property
3793
4006
  })),
3794
- ...map$1(reactHooks, (property) => ({
4007
+ ...map$1(REACT_HOOKS, (property) => ({
3795
4008
  message: `Import ${property} by name from react.`,
3796
4009
  object: "React",
3797
4010
  property
@@ -3898,16 +4111,22 @@ const oxlint = defineConfig({
3898
4111
  "no-ternary": "error",
3899
4112
  "no-throw-literal": "error",
3900
4113
  "no-unmodified-loop-condition": "error",
3901
- "no-unneeded-ternary": "error",
3902
4114
  "no-unreachable-loop": "error",
3903
4115
  "no-unsafe-finally": "error",
3904
4116
  "no-unsafe-optional-chaining": ["error", { disallowArithmeticOperators: true }],
3905
4117
  "no-unused-expressions": "error",
3906
4118
  "no-unused-vars": ["error", {
4119
+ args: "all",
3907
4120
  argsIgnorePattern: "^_",
3908
4121
  ignoreRestSiblings: true,
3909
4122
  reportUsedIgnorePattern: true
3910
4123
  }],
4124
+ "no-use-before-define": ["error", {
4125
+ classes: false,
4126
+ functions: false,
4127
+ typedefs: false,
4128
+ variables: true
4129
+ }],
3911
4130
  "no-useless-assignment": "error",
3912
4131
  "no-useless-backreference": "error",
3913
4132
  "no-useless-call": "error",
@@ -3922,18 +4141,23 @@ const oxlint = defineConfig({
3922
4141
  "no-void": "error",
3923
4142
  "object-shorthand": "error",
3924
4143
  "oxc/branches-sharing-code": "error",
3925
- "oxc/no-accumulating-spread": "error",
3926
- "oxc/no-map-spread": "error",
3927
4144
  "oxc/only-used-in-recursion": "error",
3928
4145
  "prefer-arrow-callback": "error",
3929
4146
  "prefer-const": ["error", { destructuring: "all" }],
3930
4147
  "prefer-template": "error",
3931
4148
  "require-unicode-regexp": "error",
4149
+ "jsx-a11y/alt-text": "error",
4150
+ "jsx-a11y/aria-props": "error",
4151
+ "jsx-a11y/aria-proptypes": "error",
3932
4152
  "jsx-a11y/autocomplete-valid": "error",
3933
4153
  "jsx-a11y/click-events-have-key-events": "error",
3934
4154
  "jsx-a11y/control-has-associated-label": "error",
4155
+ "jsx-a11y/heading-has-content": "error",
3935
4156
  "jsx-a11y/interactive-supports-focus": "error",
3936
4157
  "jsx-a11y/label-has-associated-control": "error",
4158
+ "jsx-a11y/no-aria-hidden-on-focusable": "error",
4159
+ "jsx-a11y/role-has-required-aria-props": "error",
4160
+ "jsx-a11y/tabindex-no-positive": "error",
3937
4161
  "react-doctor/no-aria-invalid-without-description": "error",
3938
4162
  "react-doctor/no-call-component-as-function": "error",
3939
4163
  "react-doctor/no-controlled-input-value-without-state-update": "error",
@@ -4002,7 +4226,6 @@ const oxlint = defineConfig({
4002
4226
  "react/jsx-no-script-url": "error",
4003
4227
  "react/jsx-no-target-blank": "error",
4004
4228
  "react/jsx-no-useless-fragment": "error",
4005
- "react/memo-dependencies": "error",
4006
4229
  "react/no-array-index-key": "error",
4007
4230
  "react/no-children-prop": "error",
4008
4231
  "react/no-clone-element": "error",
@@ -4010,8 +4233,6 @@ const oxlint = defineConfig({
4010
4233
  "react/no-object-type-as-default-prop": "error",
4011
4234
  "react/no-react-children": "error",
4012
4235
  "react/no-unknown-property": "error",
4013
- "react/no-unstable-nested-components": ["error", { allowAsProps: true }],
4014
- "react/preserve-manual-memoization": "error",
4015
4236
  "react/purity": "error",
4016
4237
  "react/refs": "error",
4017
4238
  "react/rule-suppression": "error",
@@ -4020,9 +4241,7 @@ const oxlint = defineConfig({
4020
4241
  "react/set-state-in-effect": "error",
4021
4242
  "react/set-state-in-render": "error",
4022
4243
  "react/static-components": "error",
4023
- "react/use-memo": "error",
4024
4244
  "react/void-dom-elements-no-children": "error",
4025
- "react/void-use-memo": "error",
4026
4245
  "shadcn/no-arbitrary-values": "error",
4027
4246
  "shadcn/no-inline-styles": "error",
4028
4247
  "shadcn/no-raw-colors": "error",
@@ -4044,12 +4263,12 @@ const oxlint = defineConfig({
4044
4263
  Date: "Use DateTime.",
4045
4264
  Error: "Use Schema.TaggedError.",
4046
4265
  Iterable: "Use T[].",
4047
- Map: mapMessage,
4266
+ Map: MAP_MESSAGE,
4048
4267
  Promise: "Use Effect.",
4049
4268
  ReadonlyArray: "Use T[].",
4050
- ReadonlyMap: mapMessage,
4051
- ReadonlySet: setMessage,
4052
- Set: setMessage,
4269
+ ReadonlyMap: MAP_MESSAGE,
4270
+ ReadonlySet: SET_MESSAGE,
4271
+ Set: SET_MESSAGE,
4053
4272
  undefined: "Use an optional property or parameter, or let inference supply undefined."
4054
4273
  } }],
4055
4274
  "typescript/no-unnecessary-type-assertion": "error",
@@ -4063,10 +4282,9 @@ const oxlint = defineConfig({
4063
4282
  "unicorn/no-process-exit": "error",
4064
4283
  "unicorn/no-static-only-class": "error",
4065
4284
  "unicorn/no-useless-fallback-in-spread": "error",
4066
- "unicorn/no-useless-length-check": "error",
4067
4285
  "unicorn/no-useless-spread": "error",
4068
- "unicorn/prefer-logical-operator-over-ternary": "error",
4069
4286
  "unicorn/prefer-optional-catch-binding": "error",
4287
+ "unicorn/prefer-string-replace-all": "error",
4070
4288
  "use-isnan": "error"
4071
4289
  },
4072
4290
  settings: {
@@ -4084,8 +4302,8 @@ var oxlint_default = definePlugin({
4084
4302
  meta: { name: "@deslop/coding-standards" },
4085
4303
  rules: {
4086
4304
  "explicit-effect-concurrency": explicitEffectConcurrency,
4305
+ "module-constant": moduleConstant,
4087
4306
  "motion-limits": motionLimits,
4088
- "no-array-wrap-ternary": noArrayWrapTernary,
4089
4307
  "no-barrel-module": noBarrelModule,
4090
4308
  "no-compiler-opt-out": noCompilerOptOut,
4091
4309
  "no-component-atom-allocation": noComponentAtomAllocation,
@@ -4098,6 +4316,7 @@ var oxlint_default = definePlugin({
4098
4316
  "no-empty-recovery": noEmptyRecovery,
4099
4317
  "no-error-message-assertion": noErrorMessageAssertion,
4100
4318
  "no-fake-ref-state": noFakeRefState,
4319
+ "no-floating-derived-type": noFloatingDerivedType,
4101
4320
  "no-gradient": noGradient,
4102
4321
  "no-hand-written-guard": noHandWrittenGuard,
4103
4322
  "no-in-operator": noInOperator,
@@ -4106,7 +4325,6 @@ var oxlint_default = definePlugin({
4106
4325
  "no-native-control": noNativeControl,
4107
4326
  "no-native-emptiness-check": noNativeEmptinessCheck,
4108
4327
  "no-native-method-call": noNativeMethodCall,
4109
- "no-nullish-ternary": noNullishTernary,
4110
4328
  "no-option-value-access": noOptionValueAccess,
4111
4329
  "no-property-alias": noPropertyAlias,
4112
4330
  "no-readonly-type-syntax": noReadonlyTypeSyntax,
@@ -4117,9 +4335,11 @@ var oxlint_default = definePlugin({
4117
4335
  "no-renamed-import": noRenamedImport,
4118
4336
  "no-return-type": noReturnType,
4119
4337
  "no-single-use-value": noSingleUseValue,
4338
+ "no-stored-jsx": noStoredJsx,
4120
4339
  "no-stored-schema-operation": noStoredSchemaOperation,
4121
4340
  "no-switch-statement": noSwitchStatement,
4122
4341
  "no-trivial-indirection": noTrivialIndirection,
4342
+ "no-type-from-value": noTypeFromValue,
4123
4343
  "no-typeof": noTypeof,
4124
4344
  "no-undestructured-use-state": noUndestructuredUseState,
4125
4345
  "no-unexplained-disable": noUnexplainedDisable,