@deslop/coding-standards 0.1.1077 → 0.1.1079

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,5 +1,5 @@
1
- import { $ as values, $n as symbol$1, C as filterMap, D as flatMap$1, Dt as orElse, Et as none, F as isArrayNonEmpty, Gn as combine, Hn as equals, J as take, Jn as optimize, K as some$1, Kn as hash, M as getSomes, N as head, Nn as NodeInspectSymbol, O as flatten, Or as pipe, Ot as some, P as isArrayEmpty, Q as remove, R as join, S as filter$1, St as isSome, T as findFirstIndex, Tt as match$1, U as of, Un as symbol, V as map$1, Vn as byReferenceUnsafe, W as prepend, X as get$2, Xn as string, Y as fromEntries, _ as dedupe, _t as fromNullishOr, a as includes, b as ensure, c as startsWith, dt as contains, er as hasProperty, f as TaggedError, ft as exists, g as contains$1, gt as flatten$1, h as appendAll, hr as isString, ht as flatMap, i as Order, j as get$1, jr as pipeArguments, k as forEach, kt as zipWith, l as trim, lr as isNullish$1, m as append, mr as isReadonlyObject, mt as firstSomeOf, n as make$2, nr as isBoolean, nt as fromOption, o as match, or as isNotNull, pt as filter, q as sort, qn as number, r as update, s as split, sr as isNotNullish, t as get$3, ur as isNumber, ut as all, v as dropRight, vt as fromUndefinedOr, w as findFirst, wr as dual, wt as map, x as every, y as empty, yt as getOrElse, z as last } from "./MutableRef-KfyWrSvW.mjs";
2
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/internal/graph.js
1
+ import { $ as prepend, $t as strictEqual, A as filter$1, Ar as isString, At as getOrUndefined, B as getSomes, Bt as zipWith, C as contains$1, Cr as isNullish$1, Ct as filter, D as empty, Dt as fromNullishOr, E as dedupeWith, Et as flatten$1, F as flatMap$1, Ft as match, Gn as NodeInspectSymbol, H as isArrayEmpty, I as flatten, It as none, K as join, Kr as pipeArguments, L as forEach, Lr as constVoid, Lt as orElse, M as findFirst, Mt as isSome, N as findFirstIndex, O as ensure, Or as isReadonlyObject, Ot as fromUndefinedOr, Pr as constFalse, Pt as map, Q as of, Rt as some, S as appendAll, St as exists, T as dedupe, Tt as flatMap, U as isArrayNonEmpty, Ur as pipe, V as head, Y as map$1, Z as matchRight, at as get$2, bt as all, c as make$3, cr as number, ct as remove, d as includes, f as match$1, ft as fromOption, g as trim, gr as isBoolean, h as startsWith, ir as symbol, it as fromEntries, j as filterMap, k as every, kr as isRegExp, kt as getOrElse, l as update, lr as optimize, lt as values, m as split, mr as hasProperty, nr as byReferenceUnsafe, nt as sort, o as toArray, or as combine, p as replaceAll, pr as symbol$1, q as last, r as make$2, rr as equals, rt as take, s as get$3, sr as hash, t as append$1, tt as some$1, u as Order, ur as string, w as containsWith, wr as isNumber, wt as firstSomeOf, x as append, xr as isNotNullish, xt as contains, y as TaggedError, z as get$1, zr as dual, zt as toArray$1 } from "./MutableList-BCF17jPH.mjs";
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";
5
5
  /** @internal */
@@ -94,7 +94,7 @@ const finalize = (source) => {
94
94
  return graph;
95
95
  };
96
96
  //#endregion
97
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/internal/graphCsr.js
97
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/internal/graphCsr.js
98
98
  const cache = /*#__PURE__*/ new WeakMap();
99
99
  const makeAdjacency = (csr, incoming) => {
100
100
  const impl = toImpl(csr.graph);
@@ -168,7 +168,7 @@ const get = (graph) => {
168
168
  return result;
169
169
  };
170
170
  //#endregion
171
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/Graph.js
171
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/Graph.js
172
172
  /**
173
173
  * Models relationships between indexed nodes and edges.
174
174
  *
@@ -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+_05cbd3a08eae06c0731a5b89848c76f6/node_modules/oxlint/dist/index.js
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
625
625
  /**
626
626
  * Define an Oxlint configuration with type inference.
627
627
  *
@@ -650,20 +650,35 @@ function variableFor(context, node) {
650
650
  function isImportBinding(input) {
651
651
  return pipe(variableFor(input.context, input.node), exists((variable) => some$1(variable.defs, (definition) => {
652
652
  if (definition.type !== "ImportBinding" || definition.parent?.type !== "ImportDeclaration") return false;
653
- const source = definition.parent.source.value;
654
- if (isString(input.source) ? source !== input.source : !input.source.test(source)) return false;
653
+ if (isString(input.source) && definition.parent.source.value !== input.source) return false;
654
+ if (isRegExp(input.source) && !input.source.test(definition.parent.source.value)) return false;
655
655
  return input.importedName === void 0 || definition.node.type === "ImportSpecifier" && definition.node.imported.type === "Identifier" && definition.node.imported.name === input.importedName;
656
656
  })));
657
657
  }
658
658
  function isNamespaceImport(input) {
659
659
  return pipe(variableFor(input.context, input.node), exists((variable) => some$1(variable.defs, (definition) => definition.type === "ImportBinding" && definition.node.type === "ImportNamespaceSpecifier" && definition.parent?.type === "ImportDeclaration" && definition.parent.source.value === input.source)));
660
660
  }
661
+ function typeWrapped(node) {
662
+ if (node.type === "TSAsExpression" || node.type === "TSInstantiationExpression" || node.type === "TSNonNullExpression" || node.type === "TSSatisfiesExpression" || node.type === "TSTypeAssertion") return some(node.expression);
663
+ return none();
664
+ }
665
+ function outermost(node) {
666
+ return pipe(fromNullishOr(node.parent), filter((parent) => isSome(typeWrapped(parent))), match({
667
+ onNone: () => node,
668
+ onSome: outermost
669
+ }));
670
+ }
661
671
  function returnedExpression(node) {
662
672
  if (node.body === null) return;
663
673
  if (node.body.type !== "BlockStatement") return node.body;
664
674
  if (node.body.body.length !== 1 || node.body.body[0]?.type !== "ReturnStatement") return;
665
675
  return node.body.body[0].argument;
666
676
  }
677
+ function rootName(node) {
678
+ if (node.type === "Identifier") return some(node.name);
679
+ if (node.type === "MemberExpression" && !node.computed && !node.optional) return rootName(node.object);
680
+ return none();
681
+ }
667
682
  function memberName(node) {
668
683
  if (!node.computed && node.property.type === "Identifier") return some(node.property.name);
669
684
  if (node.computed && node.property.type === "Literal" && isString(node.property.value)) return some(node.property.value);
@@ -678,11 +693,9 @@ function importedMember(input) {
678
693
  }) && (input.propertyName === void 0 || contains(memberName(input.node), input.propertyName));
679
694
  }
680
695
  function matches(regExp) {
681
- return (text) => isSome(pipe(text, match(regExp)));
682
- }
683
- function isSchemaOperationName(name) {
684
- return matches(/^(?:(?:decode|encode)(?:Unknown)?(?:Effect|Exit|Option|Promise|Result|Sync)|asserts|is)$/u)(name);
696
+ return (text) => isSome(pipe(text, match$1(regExp)));
685
697
  }
698
+ const isSchemaOperationName = matches(/^(?:(?:decode|encode)(?:Unknown)?(?:Effect|Exit|Option|Promise|Result|Sync)|asserts|is)$/u);
686
699
  function isSchemaOperationCall(input) {
687
700
  if (input.node.callee.type !== "MemberExpression" || !importedMember({
688
701
  context: input.context,
@@ -705,11 +718,13 @@ function isReactUseState(input) {
705
718
  });
706
719
  }
707
720
  function statementDeclaration(statement) {
708
- return statement.type === "ExportNamedDeclaration" ? statement.declaration : statement;
721
+ if (statement.type === "ExportNamedDeclaration") return statement.declaration;
722
+ return statement;
709
723
  }
710
724
  function typeAlias(statement) {
711
725
  const declaration = statementDeclaration(statement);
712
- return declaration?.type === "TSTypeAliasDeclaration" ? some(declaration) : none();
726
+ if (declaration?.type !== "TSTypeAliasDeclaration") return none();
727
+ return some(declaration);
713
728
  }
714
729
  function isInferredType(input) {
715
730
  return input.node.type === "TSTypeQuery" && input.node.exprName.type === "TSQualifiedName" && input.node.exprName.left.type === "Identifier" && input.node.exprName.left.name === input.name && input.node.exprName.right.name === "Type";
@@ -738,7 +753,10 @@ function isSchemaCodecType(input) {
738
753
  }
739
754
  function typeArgumentName(node) {
740
755
  if (node.type !== "TSTypeReference" || node.typeArguments === null) return none();
741
- return pipe(get$1(node.typeArguments.params, 0), flatMap((parameter) => parameter.type === "TSTypeReference" && parameter.typeName.type === "Identifier" ? some(parameter.typeName.name) : none()));
756
+ return pipe(get$1(node.typeArguments.params, 0), flatMap((parameter) => {
757
+ if (parameter.type !== "TSTypeReference" || parameter.typeName.type !== "Identifier") return none();
758
+ return some(parameter.typeName.name);
759
+ }));
742
760
  }
743
761
  function suspendedTypeName(input) {
744
762
  if (input.node.callee.type === "Super" || !importedMember({
@@ -747,7 +765,10 @@ function suspendedTypeName(input) {
747
765
  node: input.node.callee,
748
766
  propertyName: "suspend"
749
767
  })) return none();
750
- return pipe(get$1(input.node.arguments, 0), flatMap((argument) => argument.type === "ArrowFunctionExpression" || argument.type === "FunctionExpression" ? fromNullishOr(argument.returnType) : none()), filter((returnType) => isSchemaCodecType({
768
+ return pipe(get$1(input.node.arguments, 0), flatMap((argument) => {
769
+ if (argument.type !== "ArrowFunctionExpression" && argument.type !== "FunctionExpression") return none();
770
+ return fromNullishOr(argument.returnType);
771
+ }), filter((returnType) => isSchemaCodecType({
751
772
  context: input.context,
752
773
  node: returnType.typeAnnotation
753
774
  })), flatMap((returnType) => typeArgumentName(returnType.typeAnnotation)));
@@ -755,7 +776,8 @@ function suspendedTypeName(input) {
755
776
  function referencedTypeNames(node) {
756
777
  if (node.type === "TSTypeReference") {
757
778
  const argumentNames = pipe(fromNullishOr(node.typeArguments), map((typeArguments) => pipe(typeArguments.params, flatMap$1(referencedTypeNames))), getOrElse(() => empty()));
758
- return node.typeName.type === "Identifier" ? prepend(argumentNames, node.typeName.name) : argumentNames;
779
+ if (node.typeName.type !== "Identifier") return argumentNames;
780
+ return prepend(argumentNames, node.typeName.name);
759
781
  }
760
782
  if (node.type === "TSArrayType") return referencedTypeNames(node.elementType);
761
783
  if (node.type === "TSUnionType" || node.type === "TSIntersectionType") return pipe(node.types, flatMap$1(referencedTypeNames));
@@ -779,9 +801,13 @@ function referencedTypeNames(node) {
779
801
  if (node.type === "TSTypeLiteral") return pipe(node.members, flatMap$1(memberTypeNames));
780
802
  return empty();
781
803
  }
804
+ function annotationTypeNames(annotation) {
805
+ return pipe(fromNullishOr(annotation), map((present) => referencedTypeNames(present.typeAnnotation)), getOrElse(() => empty()));
806
+ }
782
807
  function memberTypeNames(member) {
783
808
  if (member.type === "TSIndexSignature") return referencedTypeNames(member.typeAnnotation.typeAnnotation);
784
- return pipe(fromNullishOr(member.type === "TSPropertySignature" ? member.typeAnnotation : member.returnType), map((annotation) => referencedTypeNames(annotation.typeAnnotation)), getOrElse(() => empty()));
809
+ if (member.type === "TSPropertySignature") return annotationTypeNames(member.typeAnnotation);
810
+ return annotationTypeNames(member.returnType);
785
811
  }
786
812
  function isNode(value) {
787
813
  return hasProperty(value, "type") && isString(value.type);
@@ -799,24 +825,28 @@ function suspendSeeds(input) {
799
825
  return pipe(suspendedTypeName({
800
826
  context: input.context,
801
827
  node: input.node
802
- }), match$1({
828
+ }), match({
803
829
  onNone: () => seeds,
804
830
  onSome: (name) => prepend(seeds, name)
805
831
  }));
806
832
  }
807
833
  function referenceNames(node) {
808
834
  const nested = pipe(childNodes(node), filter$1((child) => !(node.type === "Property" && !node.computed && child === node.key) && !(node.type === "MemberExpression" && !node.computed && child === node.property)), flatMap$1(referenceNames));
809
- return node.type === "Identifier" ? prepend(nested, node.name) : nested;
835
+ if (node.type !== "Identifier") return nested;
836
+ return prepend(nested, node.name);
810
837
  }
811
838
  function schemaEdges(statement) {
812
839
  const declaration = statementDeclaration(statement);
813
- if (declaration?.type === "TSTypeAliasDeclaration") return isInferredType({
814
- name: declaration.id.name,
815
- node: declaration.typeAnnotation
816
- }) ? empty() : [{
817
- name: declaration.id.name,
818
- targets: referencedTypeNames(declaration.typeAnnotation)
819
- }];
840
+ if (declaration?.type === "TSTypeAliasDeclaration") {
841
+ if (isInferredType({
842
+ name: declaration.id.name,
843
+ node: declaration.typeAnnotation
844
+ })) return empty();
845
+ return [{
846
+ name: declaration.id.name,
847
+ targets: referencedTypeNames(declaration.typeAnnotation)
848
+ }];
849
+ }
820
850
  if (declaration?.type !== "VariableDeclaration" || declaration.kind !== "const") return empty();
821
851
  return flatMap$1(declaration.declarations, (declarator) => {
822
852
  if (declarator.id.type !== "Identifier" || declarator.init === null) return empty();
@@ -873,15 +903,27 @@ function isSingletonArray(input) {
873
903
  if (isNullish$1(element) || element.type === "SpreadElement") return false;
874
904
  return input.context.sourceCode.getText(element) === input.context.sourceCode.getText(input.value);
875
905
  }
876
- function restatesArrayEnsure(input) {
877
- const test = input.node.test.type === "UnaryExpression" && input.node.test.operator === "!" ? input.node.test.argument : input.node.test;
878
- const negated = test !== input.node.test;
879
- return exists(testedValue(test), (value) => input.context.sourceCode.getText(negated ? input.node.alternate : input.node.consequent) === input.context.sourceCode.getText(value) && isSingletonArray({
906
+ function wrapsTestedValue(input) {
907
+ return exists(testedValue(input.test), (value) => input.context.sourceCode.getText(input.kept) === input.context.sourceCode.getText(value) && isSingletonArray({
880
908
  context: input.context,
881
- node: negated ? input.node.consequent : input.node.alternate,
909
+ node: input.wrapped,
882
910
  value
883
911
  }));
884
912
  }
913
+ function restatesArrayEnsure(input) {
914
+ if (input.node.test.type === "UnaryExpression" && input.node.test.operator === "!") return wrapsTestedValue({
915
+ context: input.context,
916
+ kept: input.node.alternate,
917
+ test: input.node.test.argument,
918
+ wrapped: input.node.consequent
919
+ });
920
+ return wrapsTestedValue({
921
+ context: input.context,
922
+ kept: input.node.consequent,
923
+ test: input.node.test,
924
+ wrapped: input.node.alternate
925
+ });
926
+ }
885
927
  const noArrayWrapTernary = defineRule({
886
928
  create: (context) => ({ ConditionalExpression: (node) => {
887
929
  if (restatesArrayEnsure({
@@ -949,7 +991,9 @@ function enclosingPipes(context, node) {
949
991
  "FunctionDeclaration",
950
992
  "FunctionExpression"
951
993
  ], node.type)) return 0;
952
- return enclosingPipes(context, node.parent) + (isPipeCall(context, node.parent) && some$1(node.parent.arguments, (argument) => argument === node) ? 1 : 0);
994
+ const depth = enclosingPipes(context, node.parent);
995
+ if (isPipeCall(context, node.parent) && some$1(node.parent.arguments, (argument) => argument === node)) return depth + 1;
996
+ return depth;
953
997
  }
954
998
  const noDeepPipe = defineRule({
955
999
  create: (context) => ({ CallExpression: (node) => {
@@ -980,22 +1024,28 @@ function namedTuple(input) {
980
1024
  seen: append(input.seen, input.node)
981
1025
  }))));
982
1026
  }
1027
+ function componentName(node) {
1028
+ if (node.type !== "ArrowFunctionExpression" && node.id !== null) return some(node.id.name);
1029
+ return bindingName(node);
1030
+ }
983
1031
  function component(node) {
984
- const name = (node.type === "ArrowFunctionExpression" ? void 0 : node.id) ?? (node.parent.type === "VariableDeclarator" && node.parent.id.type === "Identifier" ? node.parent.id : void 0);
985
- if (name === void 0 || !matches(/^[A-Z]/u)(name.name) || node.params.length !== 1 || node.body === null) return false;
1032
+ if (!exists(componentName(node), matches(/^[A-Z]/u)) || node.params.length !== 1 || node.body === null) return false;
986
1033
  if (node.body.type === "JSXElement" || node.body.type === "JSXFragment") return true;
987
1034
  return node.body.type === "BlockStatement" && some$1(node.body.body, (statement) => statement.type === "ReturnStatement" && (statement.argument?.type === "JSXElement" || statement.argument?.type === "JSXFragment"));
988
1035
  }
989
1036
  function isPattern(input) {
990
- const target = input.node.type === "AssignmentPattern" ? input.node.left : input.node;
991
- if (target.type === "ArrayPattern") return !exists(fromNullishOr(target.typeAnnotation), (annotation) => namedTuple({
1037
+ if (input.node.type === "AssignmentPattern") return isPattern({
1038
+ ...input,
1039
+ node: input.node.left
1040
+ });
1041
+ if (input.node.type === "ArrayPattern") return !exists(fromNullishOr(input.node.typeAnnotation), (annotation) => namedTuple({
992
1042
  context: input.context,
993
1043
  node: annotation.typeAnnotation,
994
1044
  seen: []
995
1045
  }));
996
- if (target.type !== "ObjectPattern") return false;
997
- const named = filter$1(target.properties, (property) => property.type === "Property");
998
- return !(input.component && named.length === 1 && named[0]?.key.type === "Identifier" && named[0].key.name === "ref" && some$1(target.properties, (property) => property.type === "RestElement"));
1046
+ if (input.node.type !== "ObjectPattern") return false;
1047
+ const named = filter$1(input.node.properties, (property) => property.type === "Property");
1048
+ return !(input.component && named.length === 1 && named[0]?.key.type === "Identifier" && named[0].key.name === "ref" && some$1(input.node.properties, (property) => property.type === "RestElement"));
999
1049
  }
1000
1050
  const noDestructuredParameter = defineRule({
1001
1051
  create: (context) => {
@@ -1054,8 +1104,19 @@ const noDiscardedFailure = defineRule({
1054
1104
  //#region src/rules/no-double-nullish-check.ts
1055
1105
  function nullishOperand(node) {
1056
1106
  if (node.type === "Literal" && node.value === null) return some("null");
1057
- return node.type === "Identifier" && node.name === "undefined" ? some("undefined") : none();
1107
+ if (node.type === "Identifier" && node.name === "undefined") return some("undefined");
1108
+ return none();
1058
1109
  }
1110
+ const variants = {
1111
+ "&&": {
1112
+ comparison: "!==",
1113
+ message: "Use Predicate.isNotNullish."
1114
+ },
1115
+ "||": {
1116
+ comparison: "===",
1117
+ message: "Use Predicate.isNullish."
1118
+ }
1119
+ };
1059
1120
  function operands(input) {
1060
1121
  if (input.node.type !== "LogicalExpression" || input.node.operator !== input.operator) return [input.node];
1061
1122
  return appendAll(operands({
@@ -1078,17 +1139,17 @@ const noDoubleNullishCheck = defineRule({
1078
1139
  create: (context) => ({ LogicalExpression: (node) => {
1079
1140
  if (node.operator === "??") return;
1080
1141
  if (node.parent.type === "LogicalExpression" && node.parent.operator === node.operator) return;
1081
- const comparison = node.operator === "&&" ? "!==" : "===";
1142
+ const variant = variants[node.operator];
1082
1143
  const checks = pipe(operands({
1083
1144
  node,
1084
1145
  operator: node.operator
1085
1146
  }), filterMap((operand) => fromOption(comparedNullish({
1086
1147
  context,
1087
1148
  node: operand,
1088
- operator: comparison
1149
+ operator: variant.comparison
1089
1150
  }), () => void 0)));
1090
1151
  if (some$1(checks, (check) => some$1(checks, (other) => other.subject === check.subject && other.nullish !== check.nullish))) context.report({
1091
- message: comparison === "!==" ? "Use Predicate.isNotNullish." : "Use Predicate.isNullish.",
1152
+ message: variant.message,
1092
1153
  node
1093
1154
  });
1094
1155
  } }),
@@ -1099,11 +1160,10 @@ const noDoubleNullishCheck = defineRule({
1099
1160
  const noEffectPropertyArrow = defineRule({
1100
1161
  create: (context) => ({ Property: (node) => {
1101
1162
  if (node.value.type !== "ArrowFunctionExpression" || isArrayEmpty(node.value.params) || node.value.body.type !== "CallExpression") return;
1102
- const callee = node.value.body.callee;
1103
- if (callee.type === "Identifier" && isImportBinding({
1163
+ if (node.value.body.callee.type === "Identifier" && isImportBinding({
1104
1164
  context,
1105
1165
  importedName: "pipe",
1106
- node: callee,
1166
+ node: node.value.body.callee,
1107
1167
  source: "effect"
1108
1168
  }) && some$1(node.value.body.arguments, (argument) => argument.type !== "SpreadElement" && importedMember({
1109
1169
  context,
@@ -1113,10 +1173,10 @@ const noEffectPropertyArrow = defineRule({
1113
1173
  context,
1114
1174
  importedName: "Effect",
1115
1175
  node: argument.callee
1116
- })) || callee.type === "MemberExpression" && importedMember({
1176
+ })) || node.value.body.callee.type === "MemberExpression" && importedMember({
1117
1177
  context,
1118
1178
  importedName: "Effect",
1119
- node: callee,
1179
+ node: node.value.body.callee,
1120
1180
  propertyName: "tryPromise"
1121
1181
  })) context.report({
1122
1182
  message: "Define this property with Effect.fn or Effect.fnUntraced instead of an arrow.",
@@ -1129,14 +1189,18 @@ const noEffectPropertyArrow = defineRule({
1129
1189
  //#region src/rules/no-error-message-assertion.ts
1130
1190
  function receiverName(node) {
1131
1191
  if (node.type === "Identifier") return some(node.name);
1132
- return node.type === "MemberExpression" ? memberName(node) : none();
1192
+ if (node.type !== "MemberExpression") return none();
1193
+ return memberName(node);
1133
1194
  }
1134
1195
  function isErrorMessage(node) {
1135
1196
  return node?.type === "MemberExpression" && contains(memberName(node), "message") && exists(receiverName(node.object), matches(/^(?:e|err|error|failure|cause|exception)$|Error$/iu));
1136
1197
  }
1198
+ function expectsErrorMessage(node) {
1199
+ return node.type === "CallExpression" && node.callee.type === "Identifier" && node.callee.name === "expect" && isErrorMessage(node.arguments[0]);
1200
+ }
1137
1201
  function expectsMessage(node) {
1138
- const subject = node.object.type === "MemberExpression" && contains(memberName(node.object), "not") ? node.object.object : node.object;
1139
- return subject.type === "CallExpression" && subject.callee.type === "Identifier" && subject.callee.name === "expect" && isErrorMessage(subject.arguments[0]);
1202
+ if (node.object.type === "MemberExpression" && contains(memberName(node.object), "not")) return expectsErrorMessage(node.object.object);
1203
+ return expectsErrorMessage(node.object);
1140
1204
  }
1141
1205
  function assertsMessage(node) {
1142
1206
  const [actual, expected] = node.arguments;
@@ -1166,9 +1230,8 @@ function propertyName(node) {
1166
1230
  return none();
1167
1231
  }
1168
1232
  function hasUnusedSetter(input) {
1169
- const declaration = input.node.parent;
1170
- if (declaration.type !== "VariableDeclarator" || declaration.id.type !== "ArrayPattern") return false;
1171
- const setter = declaration.id.elements[1];
1233
+ if (input.node.parent.type !== "VariableDeclarator" || input.node.parent.id.type !== "ArrayPattern") return false;
1234
+ const setter = input.node.parent.id.elements[1];
1172
1235
  if (isNullish$1(setter)) return true;
1173
1236
  if (setter.type !== "Identifier") return false;
1174
1237
  return pipe(variableFromScope({
@@ -1226,10 +1289,13 @@ function check(input) {
1226
1289
  node: argument
1227
1290
  }))) return some(["!Array.isArray"]);
1228
1291
  if (input.node.type !== "BinaryExpression") return none();
1229
- if (input.node.operator === "instanceof") return isSubject({
1230
- name: input.name,
1231
- node: input.node.left
1232
- }) && input.node.right.type === "Identifier" ? some([`instanceof ${input.node.right.name}`]) : none();
1292
+ if (input.node.operator === "instanceof") {
1293
+ if (!isSubject({
1294
+ name: input.name,
1295
+ node: input.node.left
1296
+ }) || input.node.right.type !== "Identifier") return none();
1297
+ return some([`instanceof ${input.node.right.name}`]);
1298
+ }
1233
1299
  return pipe(firstSomeOf([comparison({
1234
1300
  name: input.name,
1235
1301
  operator: input.node.operator,
@@ -1242,7 +1308,7 @@ function check(input) {
1242
1308
  subject: input.node.right
1243
1309
  })]), map(of));
1244
1310
  }
1245
- function report$1(input) {
1311
+ function report$2(input) {
1246
1312
  const predicate = input.node.returnType?.typeAnnotation;
1247
1313
  const returned = returnedExpression(input.node);
1248
1314
  if (predicate?.type !== "TSTypePredicate" || predicate.asserts || predicate.parameterName.type !== "Identifier" || isNullish$1(returned)) return;
@@ -1282,19 +1348,19 @@ function report$1(input) {
1282
1348
  const noHandWrittenGuard = defineRule({
1283
1349
  create: (context) => ({
1284
1350
  ArrowFunctionExpression: (node) => {
1285
- report$1({
1351
+ report$2({
1286
1352
  context,
1287
1353
  node
1288
1354
  });
1289
1355
  },
1290
1356
  FunctionDeclaration: (node) => {
1291
- report$1({
1357
+ report$2({
1292
1358
  context,
1293
1359
  node
1294
1360
  });
1295
1361
  },
1296
1362
  FunctionExpression: (node) => {
1297
- report$1({
1363
+ report$2({
1298
1364
  context,
1299
1365
  node
1300
1366
  });
@@ -1303,6 +1369,18 @@ const noHandWrittenGuard = defineRule({
1303
1369
  meta: { type: "problem" }
1304
1370
  });
1305
1371
  //#endregion
1372
+ //#region src/rules/no-in-operator.ts
1373
+ const noInOperator = defineRule({
1374
+ create: (context) => ({ BinaryExpression: (node) => {
1375
+ if (node.operator !== "in") return;
1376
+ context.report({
1377
+ message: "Decode the value with Schema, or narrow it with Predicate.hasProperty, instead of the in operator.",
1378
+ node
1379
+ });
1380
+ } }),
1381
+ meta: { type: "problem" }
1382
+ });
1383
+ //#endregion
1306
1384
  //#region src/rules/no-let.ts
1307
1385
  const noLet = defineRule({
1308
1386
  create: (context) => ({ VariableDeclaration: (node) => {
@@ -1317,9 +1395,7 @@ const noLet = defineRule({
1317
1395
  //#region src/rules/no-multiline-comment.ts
1318
1396
  const directive = /^\s*(?:eslint|oxlint|@effect-diagnostics|@ts-|\/\s*<reference|#region|#endregion)/u;
1319
1397
  function adjacentLines(pair) {
1320
- const first = pair.first;
1321
- const second = pair.second;
1322
- return first?.type === "Line" && second?.type === "Line" && second.loc.start.line === first.loc.end.line + 1;
1398
+ return pair.first?.type === "Line" && pair.second?.type === "Line" && pair.second.loc.start.line === pair.first.loc.end.line + 1;
1323
1399
  }
1324
1400
  const noMultilineComment = defineRule({
1325
1401
  create: (context) => ({ Program: () => {
@@ -1351,7 +1427,10 @@ const noNativeControl = defineRule({
1351
1427
  if (node.name.type !== "JSXIdentifier") return;
1352
1428
  const name = node.name.name;
1353
1429
  map(get$2(primitives, name), (primitive) => {
1354
- const styled = pipe(node.attributes, findFirst((attribute) => attribute.type === "JSXAttribute" && attribute.name.type === "JSXIdentifier" && attribute.name.name === "className"), flatMap((attribute) => attribute.type === "JSXAttribute" && attribute.value?.type === "Literal" ? fromNullishOr(attribute.value.value) : none()), exists((value) => some$1(split(value, /\s+/u), matches(controlStyle))));
1430
+ const styled = pipe(node.attributes, findFirst((attribute) => attribute.type === "JSXAttribute" && attribute.name.type === "JSXIdentifier" && attribute.name.name === "className"), flatMap((attribute) => {
1431
+ if (attribute.type !== "JSXAttribute" || attribute.value?.type !== "Literal") return none();
1432
+ return fromNullishOr(attribute.value.value);
1433
+ }), exists((value) => some$1(split(value, /\s+/u), matches(controlStyle))));
1355
1434
  if (name !== "select" && !styled) return;
1356
1435
  context.report({
1357
1436
  message: `Use the ${primitive} UI primitive instead of a styled native control.`,
@@ -1450,7 +1529,8 @@ function freshRegExpFlags(input) {
1450
1529
  if (input.node.type !== "NewExpression" && input.node.type !== "CallExpression" || input.node.callee.type !== "Identifier" || input.node.callee.name !== "RegExp") return none();
1451
1530
  const flags = input.node.arguments[1];
1452
1531
  if (flags === void 0) return some(some(""));
1453
- return some(flags.type === "Literal" && isString(flags.value) ? some(flags.value) : none());
1532
+ if (flags.type !== "Literal" || !isString(flags.value)) return some(none());
1533
+ return some(some(flags.value));
1454
1534
  }
1455
1535
  const noNativeMethodCall = defineRule({
1456
1536
  create: (context) => ({ CallExpression: (node) => {
@@ -1553,9 +1633,8 @@ function exits(node) {
1553
1633
  ], node.type) || node.type === "BlockStatement" && some$1(node.body, exits);
1554
1634
  }
1555
1635
  function earlyExit(input) {
1556
- const parent = input.node.parent;
1557
- if (parent?.type !== "BlockStatement" && parent?.type !== "Program") return false;
1558
- return some$1(take(parent.body, getOrElse(findFirstIndex(parent.body, (statement) => statement === input.node), () => 0)), (statement) => statement.type === "IfStatement" && exits(statement.consequent) && checks({
1636
+ if (input.node.parent?.type !== "BlockStatement" && input.node.parent?.type !== "Program") return false;
1637
+ return some$1(take(input.node.parent.body, getOrElse(findFirstIndex(input.node.parent.body, (statement) => statement === input.node), () => 0)), (statement) => statement.type === "IfStatement" && exits(statement.consequent) && checks({
1559
1638
  ...input,
1560
1639
  name: "isNone",
1561
1640
  operator: "||",
@@ -1563,8 +1642,7 @@ function earlyExit(input) {
1563
1642
  }));
1564
1643
  }
1565
1644
  function guarded(input) {
1566
- const parent = input.node.parent;
1567
- if (parent === null || parent.type === "FunctionDeclaration") return false;
1645
+ if (input.node.parent === null || input.node.parent.type === "FunctionDeclaration") return false;
1568
1646
  function some(test) {
1569
1647
  return checks({
1570
1648
  ...input,
@@ -1573,14 +1651,14 @@ function guarded(input) {
1573
1651
  test
1574
1652
  });
1575
1653
  }
1576
- return parent.type === "IfStatement" && parent.consequent === input.node && some(parent.test) || parent.type === "ConditionalExpression" && parent.consequent === input.node && some(parent.test) || parent.type === "LogicalExpression" && parent.right === input.node && parent.operator === "&&" && some(parent.left) || parent.type === "LogicalExpression" && parent.right === input.node && parent.operator === "||" && checks({
1654
+ return input.node.parent.type === "IfStatement" && input.node.parent.consequent === input.node && some(input.node.parent.test) || input.node.parent.type === "ConditionalExpression" && input.node.parent.consequent === input.node && some(input.node.parent.test) || input.node.parent.type === "LogicalExpression" && input.node.parent.right === input.node && input.node.parent.operator === "&&" && some(input.node.parent.left) || input.node.parent.type === "LogicalExpression" && input.node.parent.right === input.node && input.node.parent.operator === "||" && checks({
1577
1655
  ...input,
1578
1656
  name: "isNone",
1579
1657
  operator: "||",
1580
- test: parent.left
1658
+ test: input.node.parent.left
1581
1659
  }) || earlyExit(input) || guarded({
1582
1660
  ...input,
1583
- node: parent
1661
+ node: input.node.parent
1584
1662
  });
1585
1663
  }
1586
1664
  const noOptionValueAccess = defineRule({
@@ -1598,6 +1676,169 @@ const noOptionValueAccess = defineRule({
1598
1676
  meta: { type: "problem" }
1599
1677
  });
1600
1678
  //#endregion
1679
+ //#region src/rules/no-property-alias.ts
1680
+ const functions = [
1681
+ "ArrowFunctionExpression",
1682
+ "FunctionDeclaration",
1683
+ "FunctionExpression"
1684
+ ];
1685
+ const deferred = [
1686
+ "ChainExpression",
1687
+ "ConditionalExpression",
1688
+ "DoWhileStatement",
1689
+ "ForInStatement",
1690
+ "ForOfStatement",
1691
+ "ForStatement",
1692
+ "IfStatement",
1693
+ "LogicalExpression",
1694
+ "SwitchStatement",
1695
+ "WhileStatement"
1696
+ ];
1697
+ function insideFunction(node) {
1698
+ if (isNullish$1(node.parent) || node.parent.type === "Program") return false;
1699
+ if (contains$1(functions, node.parent.type)) return true;
1700
+ return insideFunction(node.parent);
1701
+ }
1702
+ function sameRoot(input) {
1703
+ return getOrUndefined(variableFromScope({
1704
+ name: input.name,
1705
+ scope: input.context.sourceCode.getScope(input.declarator)
1706
+ })) === getOrUndefined(variableFromScope({
1707
+ name: input.name,
1708
+ scope: input.context.sourceCode.getScope(input.read)
1709
+ }));
1710
+ }
1711
+ function enclosed(input) {
1712
+ if (isNullish$1(input.node.parent) || input.node.parent === input.block) return false;
1713
+ if (contains$1(input.types, input.node.parent.type)) return true;
1714
+ return enclosed({
1715
+ ...input,
1716
+ node: input.node.parent
1717
+ });
1718
+ }
1719
+ function between(input) {
1720
+ return input.node.range[0] >= input.declaration.range[1] && input.node.range[1] <= input.read.range[0];
1721
+ }
1722
+ function objectRoot(node) {
1723
+ if (node.type === "Identifier") return some(node.name);
1724
+ if (node.type === "MemberExpression") return objectRoot(node.object);
1725
+ return none();
1726
+ }
1727
+ function written(node) {
1728
+ if (node.type === "AssignmentExpression") return objectRoot(node.left);
1729
+ if (node.type === "UpdateExpression" || node.type === "UnaryExpression" && node.operator === "delete") return objectRoot(node.argument);
1730
+ return none();
1731
+ }
1732
+ function inert(token) {
1733
+ if (contains$1([
1734
+ "Boolean",
1735
+ "Identifier",
1736
+ "Null",
1737
+ "Numeric",
1738
+ "String"
1739
+ ], token.type)) return true;
1740
+ if (token.type === "Keyword") return contains$1(["const", "return"], token.value);
1741
+ return token.type === "Punctuator" && contains$1([
1742
+ "(",
1743
+ ",",
1744
+ ":",
1745
+ "=",
1746
+ "[",
1747
+ "{"
1748
+ ], token.value);
1749
+ }
1750
+ function replacement(input) {
1751
+ if (input.read.parent?.type === "Property" && input.read.parent.shorthand) return `${input.name}: ${input.text}`;
1752
+ return input.text;
1753
+ }
1754
+ function report$1(input) {
1755
+ const reads = pipe(input.variable.references, filter$1((reference) => reference.isRead()), map$1((reference) => reference.identifier));
1756
+ const text = input.context.sourceCode.getText(input.init);
1757
+ pipe(rootName(input.init), filter((root) => isArrayNonEmpty(reads) && every(reads, (read) => {
1758
+ const used = outermost(read);
1759
+ return read.parent.type !== "ExportSpecifier" && !enclosed({
1760
+ block: input.declaration.parent,
1761
+ node: read,
1762
+ types: functions
1763
+ }) && !(used.parent?.type === "CallExpression" && used.parent.callee === used) && !(used.parent?.type === "TaggedTemplateExpression" && used.parent.tag === used) && !some$1(input.writes, (write) => between({
1764
+ declaration: input.declaration,
1765
+ node: write,
1766
+ read
1767
+ }) && contains(written(write), root)) && sameRoot({
1768
+ context: input.context,
1769
+ declarator: input.node,
1770
+ name: root,
1771
+ read
1772
+ });
1773
+ })), match({
1774
+ onNone: constVoid,
1775
+ onSome: () => input.context.report({
1776
+ fix: (fixer) => {
1777
+ if (reads.length !== 1 || some$1(reads, (read) => startsWith("JSX")(read.parent.type) || enclosed({
1778
+ block: input.declaration.parent,
1779
+ node: read,
1780
+ types: deferred
1781
+ }) || some$1(input.statements, (node) => between({
1782
+ declaration: input.declaration,
1783
+ node,
1784
+ read
1785
+ })) || !every(input.context.sourceCode.getTokensBetween(input.declaration, read), inert))) return [];
1786
+ return [fixer.remove(input.declaration), ...map$1(reads, (read) => fixer.replaceText(read, replacement({
1787
+ name: input.name,
1788
+ read,
1789
+ text
1790
+ })))];
1791
+ },
1792
+ message: `Read ${text} where it is used; this name adds no value.`,
1793
+ node: input.node
1794
+ })
1795
+ }));
1796
+ }
1797
+ const noPropertyAlias = defineRule({
1798
+ create: (context) => {
1799
+ const writes = make$2();
1800
+ const candidates = make$2();
1801
+ function write(node) {
1802
+ append$1(writes, node);
1803
+ }
1804
+ return {
1805
+ AssignmentExpression: write,
1806
+ "Program:exit": () => {
1807
+ const nodes = toArray(writes);
1808
+ for (const candidate of toArray(candidates)) pipe(variableFromScope({
1809
+ name: candidate.name,
1810
+ scope: context.sourceCode.getScope(candidate.node)
1811
+ }), match({
1812
+ onNone: constVoid,
1813
+ onSome: (variable) => report$1({
1814
+ ...candidate,
1815
+ context,
1816
+ variable,
1817
+ writes: nodes
1818
+ })
1819
+ }));
1820
+ },
1821
+ UnaryExpression: (node) => {
1822
+ if (node.operator === "delete") write(node);
1823
+ },
1824
+ UpdateExpression: write,
1825
+ VariableDeclarator: (node) => {
1826
+ 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, {
1827
+ declaration: node.parent,
1828
+ init: node.init,
1829
+ name: node.id.name,
1830
+ node,
1831
+ statements: node.parent.parent.body
1832
+ });
1833
+ }
1834
+ };
1835
+ },
1836
+ meta: {
1837
+ fixable: "code",
1838
+ type: "problem"
1839
+ }
1840
+ });
1841
+ //#endregion
1601
1842
  //#region src/rules/no-readonly-type-syntax.ts
1602
1843
  function isTopLevelStatement(node) {
1603
1844
  if (node.parent.type === "Program") return true;
@@ -1615,10 +1856,13 @@ function typeDeclarations(input) {
1615
1856
  if (input.name.type === "Identifier") return pipe(variableFromScope({
1616
1857
  name: input.name.name,
1617
1858
  scope: input.context.sourceCode.getScope(input.name)
1618
- }), flatMap((variable) => variable.scope.block.type === "ClassDeclaration" && some$1(variable.defs, (definition) => definition.node === variable.scope.block) ? variableFromScope({
1619
- name: variable.name,
1620
- scope: variable.scope.upper
1621
- }) : some(variable)), map((variable) => map$1(variable.defs, (definition) => definition.node)), getOrElse(() => empty()));
1859
+ }), flatMap((variable) => {
1860
+ if (variable.scope.block.type !== "ClassDeclaration" || !some$1(variable.defs, (definition) => definition.node === variable.scope.block)) return some(variable);
1861
+ return variableFromScope({
1862
+ name: variable.name,
1863
+ scope: variable.scope.upper
1864
+ });
1865
+ }), map((variable) => map$1(variable.defs, (definition) => definition.node)), getOrElse(() => empty()));
1622
1866
  if (input.name.type !== "TSQualifiedName") return [];
1623
1867
  const name = input.name;
1624
1868
  return pipe(typeDeclarations({
@@ -1649,15 +1893,18 @@ function shapeLiterals(input) {
1649
1893
  type: alias.typeAnnotation
1650
1894
  })));
1651
1895
  }
1896
+ function removeLeading(input) {
1897
+ return (fixer) => pipe(input.context.sourceCode.getText(input.node), match$1(input.pattern), map((match) => fixer.replaceTextRange([input.node.range[0], input.node.range[0] + match[0].length], match[1] ?? "")), getOrUndefined);
1898
+ }
1652
1899
  const noReadonlyTypeSyntax = defineRule({
1653
1900
  create: (context) => {
1654
1901
  const cycleNames = schemaCycleNames({
1655
1902
  context,
1656
1903
  program: context.sourceCode.ast
1657
1904
  });
1658
- const shapes = make$2(empty());
1659
- const properties = make$2(empty());
1660
- const methods = make$2(empty());
1905
+ const shapes = make$3(empty());
1906
+ const properties = make$3(empty());
1907
+ const methods = make$3(empty());
1661
1908
  function exempt(node) {
1662
1909
  return insideCycleType({
1663
1910
  cycleNames,
@@ -1684,10 +1931,16 @@ const noReadonlyTypeSyntax = defineRule({
1684
1931
  }
1685
1932
  for (const node of get$3(properties)) {
1686
1933
  if (inShape(node) && !node.readonly) context.report({
1934
+ fix: (fixer) => fixer.insertTextBefore(node, "readonly "),
1687
1935
  message: "Mark this service property readonly.",
1688
1936
  node
1689
1937
  });
1690
1938
  if (!inShape(node) && node.readonly && !exempt(node)) context.report({
1939
+ fix: removeLeading({
1940
+ context,
1941
+ node,
1942
+ pattern: /^readonly\s+/u
1943
+ }),
1691
1944
  message: "Remove the readonly property modifier.",
1692
1945
  node
1693
1946
  });
@@ -1699,12 +1952,22 @@ const noReadonlyTypeSyntax = defineRule({
1699
1952
  },
1700
1953
  TSIndexSignature: (node) => {
1701
1954
  if (node.readonly) context.report({
1955
+ fix: removeLeading({
1956
+ context,
1957
+ node,
1958
+ pattern: /^readonly\s+/u
1959
+ }),
1702
1960
  message: "Remove the readonly index modifier.",
1703
1961
  node
1704
1962
  });
1705
1963
  },
1706
1964
  TSMappedType: (node) => {
1707
1965
  if (node.readonly === true || node.readonly === "+") context.report({
1966
+ fix: removeLeading({
1967
+ context,
1968
+ node,
1969
+ pattern: /^(\{\s*)\+?readonly\s+/u
1970
+ }),
1708
1971
  message: "Remove the readonly mapped-type modifier.",
1709
1972
  node
1710
1973
  });
@@ -1717,78 +1980,24 @@ const noReadonlyTypeSyntax = defineRule({
1717
1980
  },
1718
1981
  TSTypeOperator: (node) => {
1719
1982
  if (node.operator === "readonly" && !exempt(node)) context.report({
1983
+ fix: (fixer) => fixer.replaceText(node, context.sourceCode.getText(node.typeAnnotation)),
1720
1984
  message: "Use a mutable type shape.",
1721
1985
  node
1722
1986
  });
1723
1987
  },
1724
1988
  TSTypeReference: (node) => {
1725
1989
  if (node.typeName.type === "Identifier" && node.typeName.name === "Readonly" && !exempt(node)) context.report({
1990
+ fix: (fixer) => pipe(fromNullishOr(node.typeArguments?.params[0]), map((shape) => fixer.replaceText(node, `(${context.sourceCode.getText(shape)})`)), getOrUndefined),
1726
1991
  message: "Use a mutable type shape.",
1727
1992
  node
1728
1993
  });
1729
1994
  }
1730
1995
  };
1731
1996
  },
1732
- meta: { type: "problem" }
1733
- });
1734
- //#endregion
1735
- //#region src/rules/no-redundant-return-type.ts
1736
- function isExported(node) {
1737
- if (node.parent.type === "ExportNamedDeclaration" || node.parent.type === "ExportDefaultDeclaration") return true;
1738
- return node.parent.type === "VariableDeclarator" && node.parent.parent.type === "VariableDeclaration" && node.parent.parent.parent.type === "ExportNamedDeclaration";
1739
- }
1740
- function inferredIdentically(input) {
1741
- const text = input.context.sourceCode.getText;
1742
- const body = input.node.body;
1743
- if (body === null) return false;
1744
- const block = body.type === "BlockStatement";
1745
- const values = body.type === "BlockStatement" ? map$1(input.returns, (statement) => statement.argument) : [body];
1746
- const expressions = filter$1(values, isNotNull);
1747
- if (input.type.type === "TSVoidKeyword") return block && isArrayEmpty(expressions);
1748
- if (isArrayEmpty(expressions) || expressions.length !== values.length) return false;
1749
- if (input.type.type === "TSStringKeyword") return every(expressions, (value) => value.type === "TemplateLiteral" && isArrayNonEmpty(value.expressions));
1750
- if (isExported(input.node)) return false;
1751
- return every(expressions, (value) => value.type === "TSAsExpression" && text(value.typeAnnotation) === text(input.type) || !block && value.type === "NewExpression" && input.type.type === "TSTypeReference" && input.type.typeArguments === null && text(value.callee) === text(input.type.typeName));
1752
- }
1753
- const noRedundantReturnType = defineRule({
1754
- create: (context) => {
1755
- const frames = make$2(empty());
1756
- function enter() {
1757
- update(frames, append({ returns: empty() }));
1758
- }
1759
- function exit(node) {
1760
- const frame = last(get$3(frames));
1761
- update(frames, dropRight(1));
1762
- if (node.async || node.generator || isNullish$1(node.returnType)) return;
1763
- if (inferredIdentically({
1764
- context,
1765
- node,
1766
- returns: match$1(frame, {
1767
- onNone: () => empty(),
1768
- onSome: (top) => top.returns
1769
- }),
1770
- type: node.returnType.typeAnnotation
1771
- })) context.report({
1772
- message: "Drop this return type; inference gives the same type.",
1773
- node: node.returnType
1774
- });
1775
- }
1776
- return {
1777
- ArrowFunctionExpression: enter,
1778
- "ArrowFunctionExpression:exit": exit,
1779
- FunctionDeclaration: enter,
1780
- "FunctionDeclaration:exit": exit,
1781
- FunctionExpression: enter,
1782
- "FunctionExpression:exit": exit,
1783
- ReturnStatement: (node) => {
1784
- update(frames, (stack) => pipe(last(stack), match$1({
1785
- onNone: () => stack,
1786
- onSome: (top) => append(dropRight(stack, 1), { returns: append(top.returns, node) })
1787
- })));
1788
- }
1789
- };
1790
- },
1791
- meta: { type: "problem" }
1997
+ meta: {
1998
+ fixable: "code",
1999
+ type: "problem"
2000
+ }
1792
2001
  });
1793
2002
  //#endregion
1794
2003
  //#region src/rules/no-redundant-state-type.ts
@@ -1852,18 +2061,17 @@ const noRedundantUseRefNullType = defineRule({
1852
2061
  //#region src/rules/no-redundant-variable-annotation.ts
1853
2062
  const noRedundantVariableAnnotation = defineRule({
1854
2063
  create: (context) => ({ VariableDeclarator: (node) => {
1855
- const annotation = node.id.typeAnnotation;
1856
- if (node.init === null || isNullish$1(annotation)) return;
2064
+ if (node.init === null || isNullish$1(node.id.typeAnnotation)) return;
1857
2065
  if (node.init.type === "ArrayExpression" && isArrayEmpty(node.init.elements)) {
1858
2066
  context.report({
1859
2067
  message: "Write Array.empty<T>() instead of annotating an empty array.",
1860
- node: annotation
2068
+ node: node.id.typeAnnotation
1861
2069
  });
1862
2070
  return;
1863
2071
  }
1864
- if (node.init.type === "TSAsExpression" && context.sourceCode.getText(node.init.typeAnnotation) === context.sourceCode.getText(annotation.typeAnnotation)) context.report({
2072
+ if (node.init.type === "TSAsExpression" && context.sourceCode.getText(node.init.typeAnnotation) === context.sourceCode.getText(node.id.typeAnnotation.typeAnnotation)) context.report({
1865
2073
  message: "Drop this annotation; inference gives the same type.",
1866
- node: annotation
2074
+ node: node.id.typeAnnotation
1867
2075
  });
1868
2076
  } }),
1869
2077
  meta: { type: "problem" }
@@ -1903,11 +2111,12 @@ const shipped = [
1903
2111
  }
1904
2112
  ];
1905
2113
  function schemaMember(input) {
1906
- return input.node.type === "MemberExpression" && importedMember({
2114
+ if (input.node.type !== "MemberExpression" || !importedMember({
1907
2115
  context: input.context,
1908
2116
  importedName: "Schema",
1909
2117
  node: input.node
1910
- }) ? memberName(input.node) : none();
2118
+ })) return none();
2119
+ return memberName(input.node);
1911
2120
  }
1912
2121
  function shippedSchema(input) {
1913
2122
  if (input.filter.type !== "CallExpression") return none();
@@ -1920,16 +2129,19 @@ function shippedSchema(input) {
1920
2129
  node: input.filter.callee
1921
2130
  });
1922
2131
  const [value, ...rest] = input.filter.arguments;
1923
- return pipe(shipped, findFirst((entry) => contains(base, entry.base) && contains(check, entry.check) && isArrayEmpty(rest) && match$1(fromUndefinedOr(entry.only), {
2132
+ return pipe(shipped, findFirst((entry) => contains(base, entry.base) && contains(check, entry.check) && isArrayEmpty(rest) && match(fromUndefinedOr(entry.only), {
1924
2133
  onNone: () => value === void 0,
1925
2134
  onSome: (only) => value?.type === "Literal" && value.value === only
1926
2135
  })), map((entry) => entry.schema));
1927
2136
  }
1928
2137
  function pipedBase(node) {
1929
- const parent = node.parent;
1930
- if (parent.type !== "CallExpression") return none();
1931
- if (parent.callee.type === "Identifier" && parent.callee.name === "pipe" && parent.arguments.length === 2) return parent.arguments[1] === node ? fromNullishOr(parent.arguments[0]) : none();
1932
- return parent.callee.type === "MemberExpression" && contains(memberName(parent.callee), "pipe") && parent.arguments.length === 1 ? some(parent.callee.object) : none();
2138
+ if (node.parent.type !== "CallExpression") return none();
2139
+ if (node.parent.callee.type === "Identifier" && node.parent.callee.name === "pipe" && node.parent.arguments.length === 2) {
2140
+ if (node.parent.arguments[1] !== node) return none();
2141
+ return fromNullishOr(node.parent.arguments[0]);
2142
+ }
2143
+ if (node.parent.callee.type !== "MemberExpression" || !contains(memberName(node.parent.callee), "pipe") || node.parent.arguments.length !== 1) return none();
2144
+ return some(node.parent.callee.object);
1933
2145
  }
1934
2146
  function reinventedSchema(input) {
1935
2147
  if (input.node.callee.type !== "MemberExpression" || !contains(memberName(input.node.callee), "check")) return none();
@@ -1938,11 +2150,14 @@ function reinventedSchema(input) {
1938
2150
  if (isSome(schemaMember({
1939
2151
  context: input.context,
1940
2152
  node: callee
1941
- }))) return pipe(pipedBase(input.node), flatMap((base) => input.node.arguments.length === 1 && filter !== void 0 ? shippedSchema({
1942
- base,
1943
- context: input.context,
1944
- filter
1945
- }) : none()));
2153
+ }))) {
2154
+ if (input.node.arguments.length !== 1 || filter === void 0) return none();
2155
+ return pipe(pipedBase(input.node), flatMap((base) => shippedSchema({
2156
+ base,
2157
+ context: input.context,
2158
+ filter
2159
+ })));
2160
+ }
1946
2161
  return findFirst(input.node.arguments, (argument) => shippedSchema({
1947
2162
  base: callee.object,
1948
2163
  context: input.context,
@@ -1965,9 +2180,13 @@ const noReinventedSchema = defineRule({
1965
2180
  });
1966
2181
  //#endregion
1967
2182
  //#region src/rules/no-renamed-import.ts
2183
+ function exportedName(node) {
2184
+ if (node.type === "Literal") return node.value;
2185
+ return node.name;
2186
+ }
1968
2187
  const noRenamedImport = defineRule({
1969
2188
  create: (context) => ({ ImportSpecifier: (node) => {
1970
- const imported = node.imported.type === "Literal" ? node.imported.value : node.imported.name;
2189
+ const imported = exportedName(node.imported);
1971
2190
  if (imported === node.local.name || imported === "it" && node.local.name === "test") return;
1972
2191
  context.report({
1973
2192
  message: `Import ${imported} under its own name.`,
@@ -1977,6 +2196,76 @@ const noRenamedImport = defineRule({
1977
2196
  meta: { type: "problem" }
1978
2197
  });
1979
2198
  //#endregion
2199
+ //#region src/rules/no-return-type.ts
2200
+ function boundName(node) {
2201
+ if (node.parent.type === "CallExpression" && node.parent.parent.type === "VariableDeclarator" && node.parent.parent.id.type === "Identifier") return some(node.parent.parent.id.name);
2202
+ return bindingName(node);
2203
+ }
2204
+ function functionScopes(input) {
2205
+ const scope = input.context.sourceCode.getScope(input.node);
2206
+ return filter$1([scope, ...scope.childScopes], (child) => child.block.range[0] >= input.node.range[0] && child.block.range[1] <= input.node.range[1]);
2207
+ }
2208
+ function propertyRead(reference) {
2209
+ return reference.identifier.parent.type === "MemberExpression" && reference.identifier.parent.object === reference.identifier && !(reference.identifier.parent.parent.type === "CallExpression" && reference.identifier.parent.parent.callee === reference.identifier.parent);
2210
+ }
2211
+ function reaches(input) {
2212
+ const reached = pipe(input.nodes, flatMap$1((node) => functionScopes({
2213
+ context: input.context,
2214
+ node
2215
+ })), flatMap$1((scope) => scope.through), filter$1((reference) => !propertyRead(reference)), flatMap$1((reference) => toArray$1(fromNullishOr(reference.resolved))), dedupeWith(strictEqual()));
2216
+ const known = containsWith(strictEqual());
2217
+ if (some$1(reached, (variable) => known(input.targets, variable))) return true;
2218
+ const next = filter$1(reached, (variable) => !known(input.visited, variable));
2219
+ if (isArrayEmpty(next)) return false;
2220
+ return reaches({
2221
+ ...input,
2222
+ nodes: pipe(next, flatMap$1((variable) => variable.defs), filter$1((definition) => definition.type === "FunctionName" || definition.type === "Variable"), map$1((definition) => definition.node)),
2223
+ visited: appendAll(input.visited, next)
2224
+ });
2225
+ }
2226
+ function selfMethodCall(input) {
2227
+ if (input.node.parent.type !== "MethodDefinition" || input.node.parent.key.type !== "Identifier") return false;
2228
+ return matches(new RegExp(`\\bthis\\.${replaceAll("$", "\\$")(input.node.parent.key.name)}\\(`, "u"))(input.context.sourceCode.getText(input.node));
2229
+ }
2230
+ function recursive(input) {
2231
+ const scope = input.context.sourceCode.getScope(input.node);
2232
+ const targets = pipe([boundName(input.node), fromNullishOr(input.node.id?.name)], getSomes, flatMap$1((name) => toArray$1(variableFromScope({
2233
+ name,
2234
+ scope
2235
+ }))), dedupeWith(strictEqual()));
2236
+ return selfMethodCall(input) || isArrayNonEmpty(targets) && reaches({
2237
+ context: input.context,
2238
+ nodes: [input.node],
2239
+ targets,
2240
+ visited: []
2241
+ });
2242
+ }
2243
+ const noReturnType = defineRule({
2244
+ create: (context) => {
2245
+ function check(node) {
2246
+ if (isNullish$1(node.returnType) || node.body === null || node.returnType.typeAnnotation.type === "TSTypePredicate" || node.parent.type === "CallExpression" && importedMember({
2247
+ context,
2248
+ importedName: "Schema",
2249
+ node: node.parent.callee,
2250
+ propertyName: "suspend"
2251
+ }) || recursive({
2252
+ context,
2253
+ node
2254
+ })) return;
2255
+ context.report({
2256
+ message: "Drop the return type and let inference supply it; check a returned object with satisfies.",
2257
+ node: node.returnType
2258
+ });
2259
+ }
2260
+ return {
2261
+ ArrowFunctionExpression: check,
2262
+ FunctionDeclaration: check,
2263
+ FunctionExpression: check
2264
+ };
2265
+ },
2266
+ meta: { type: "problem" }
2267
+ });
2268
+ //#endregion
1980
2269
  //#region src/rules/no-single-use-value.ts
1981
2270
  const repeating = [
1982
2271
  "ArrowFunctionExpression",
@@ -1989,16 +2278,14 @@ const repeating = [
1989
2278
  "WhileStatement"
1990
2279
  ];
1991
2280
  function runsOnce(input) {
1992
- const node = input.node;
1993
- const child = input.child;
1994
- if ((node.type === "ForOfStatement" || node.type === "ForInStatement") && node.right === child || node.type === "IfStatement" && node.test === child || node.type === "ConditionalExpression" && node.test === child || node.type === "LogicalExpression" && node.left === child) return climb({
2281
+ if ((input.node.type === "ForOfStatement" || input.node.type === "ForInStatement") && input.node.right === input.child || input.node.type === "IfStatement" && input.node.test === input.child || input.node.type === "ConditionalExpression" && input.node.test === input.child || input.node.type === "LogicalExpression" && input.node.left === input.child) return climb({
1995
2282
  ...input,
1996
- node
2283
+ node: input.node
1997
2284
  });
1998
- if (contains$1(repeating, node.type) || node.type === "IfStatement" || node.type === "ConditionalExpression" || node.type === "LogicalExpression" || node.type === "ChainExpression" || node.type === "SwitchStatement" || node.type === "TryStatement") return false;
2285
+ 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;
1999
2286
  return climb({
2000
2287
  ...input,
2001
- node
2288
+ node: input.node
2002
2289
  });
2003
2290
  }
2004
2291
  function climb(input) {
@@ -2019,9 +2306,23 @@ function insideConditional(input) {
2019
2306
  });
2020
2307
  }
2021
2308
  function candidate(node) {
2022
- const declaration = node.parent;
2023
- const init = node.init;
2024
- return declaration.type === "VariableDeclaration" && declaration.kind === "const" && declaration.declarations.length === 1 && declaration.parent.type === "BlockStatement" && node.id.type === "Identifier" && node.id.typeAnnotation === null && init !== null && !contains$1(["ArrowFunctionExpression", "FunctionExpression"], init.type) && !(init.type === "Literal" && !hasProperty(init, "regex")) && !(init.type === "TemplateLiteral" && isArrayEmpty(init.expressions));
2309
+ 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));
2310
+ }
2311
+ function unwrapped(node) {
2312
+ return pipe(typeWrapped(node), match({
2313
+ onNone: () => node,
2314
+ onSome: unwrapped
2315
+ }));
2316
+ }
2317
+ function fixable(input) {
2318
+ const read = outermost(input.read);
2319
+ return !(unwrapped(input.init).type === "ClassExpression" || read.parent?.type === "CallExpression" && read.parent.callee === read || read.parent?.type === "TaggedTemplateExpression" && read.parent.tag === read);
2320
+ }
2321
+ function inlined(input) {
2322
+ const value = `(${input.context.sourceCode.getText(input.init)})`;
2323
+ if (input.read.parent?.type === "Property" && input.read.parent.shorthand) return `${input.name}: ${value}`;
2324
+ if (input.read.range[0] === input.next.range[0]) return `;${value}`;
2325
+ return value;
2025
2326
  }
2026
2327
  function report(input) {
2027
2328
  const declaration = input.node.parent;
@@ -2038,17 +2339,33 @@ function report(input) {
2038
2339
  }) && !(init.type === "ConditionalExpression" && insideConditional({
2039
2340
  node: read,
2040
2341
  statement: next
2041
- })) && !some$1(input.effects, (effect) => effect.range[0] >= next.range[0] && effect.range[1] <= read.range[0])))), map(() => {
2042
- input.context.report({
2342
+ })) && !some$1(input.effects, (effect) => effect.range[0] >= next.range[0] && effect.range[1] <= read.range[0])), map((read) => ({
2343
+ next,
2344
+ read
2345
+ })))), match({
2346
+ onNone: constVoid,
2347
+ onSome: (found) => input.context.report({
2348
+ fix: (fixer) => {
2349
+ if (!fixable({
2350
+ init,
2351
+ read: found.read
2352
+ })) return [];
2353
+ return [fixer.remove(declaration), fixer.replaceText(found.read, inlined({
2354
+ context: input.context,
2355
+ init,
2356
+ name,
2357
+ ...found
2358
+ }))];
2359
+ },
2043
2360
  message: "Inline this value into the next statement, its only use.",
2044
2361
  node: input.node
2045
- });
2362
+ })
2046
2363
  }));
2047
2364
  }
2048
2365
  const noSingleUseValue = defineRule({
2049
2366
  create: (context) => {
2050
- const effects = make$2(empty());
2051
- const candidates = make$2(empty());
2367
+ const effects = make$3(empty());
2368
+ const candidates = make$3(empty());
2052
2369
  function effect(node) {
2053
2370
  update(effects, append(node));
2054
2371
  }
@@ -2072,7 +2389,10 @@ const noSingleUseValue = defineRule({
2072
2389
  YieldExpression: effect
2073
2390
  };
2074
2391
  },
2075
- meta: { type: "problem" }
2392
+ meta: {
2393
+ fixable: "code",
2394
+ type: "problem"
2395
+ }
2076
2396
  });
2077
2397
  //#endregion
2078
2398
  //#region src/rules/no-stored-schema-operation.ts
@@ -2109,21 +2429,60 @@ function parameterName(parameter) {
2109
2429
  if (parameter.type === "RestElement" && parameter.argument.type === "Identifier") return some(parameter.argument.name);
2110
2430
  return none();
2111
2431
  }
2112
- function forwardedCall(input) {
2113
- return input.node.arguments.length === input.names.length && every(input.node.arguments, (argument, index) => {
2432
+ function forwarded(input) {
2433
+ return input.args.length === input.names.length && every(input.args, (argument, index) => {
2114
2434
  const name = input.names[index];
2115
2435
  if (argument.type === "SpreadElement") return argument.argument.type === "Identifier" && argument.argument.name === name;
2116
2436
  return argument.type === "Identifier" && argument.name === name;
2117
2437
  });
2118
2438
  }
2119
- function exactForwardingFunction(node) {
2120
- const names = pipe(node.params, map$1(parameterName), getSomes);
2121
- const returned = returnedExpression(node);
2122
- if (isArrayEmpty(names) || names.length !== node.params.length || isNullish$1(returned)) return false;
2439
+ function callGroups(node) {
2440
+ if (node.type !== "CallExpression") return {
2441
+ callee: node,
2442
+ groups: []
2443
+ };
2444
+ const inner = callGroups(node.callee);
2445
+ return {
2446
+ callee: inner.callee,
2447
+ groups: append(inner.groups, node.arguments)
2448
+ };
2449
+ }
2450
+ function detachable(input) {
2451
+ if (input.node.type === "Identifier") return true;
2452
+ if (input.node.type !== "MemberExpression" || input.node.object.type !== "Identifier") return false;
2453
+ return pipe(rootName(input.node), flatMap((name) => variableFromScope({
2454
+ name,
2455
+ scope: input.context.sourceCode.getScope(input.node)
2456
+ })), exists((variable) => some$1(variable.defs, (definition) => definition.type === "ImportBinding" && definition.parent?.type === "ImportDeclaration" && (definition.parent.source.value === "effect" || definition.node.type === "ImportNamespaceSpecifier" && matches(/^effect\//u)(definition.parent.source.value)))));
2457
+ }
2458
+ function forwardedChain(input) {
2459
+ const chain = callGroups(input.returned);
2460
+ function fixed(node) {
2461
+ return node.type === "Literal" || exists(rootName(node), (root) => !contains$1(input.names, root));
2462
+ }
2463
+ return matchRight(chain.groups, {
2464
+ onEmpty: constFalse,
2465
+ onNonEmpty: (earlier, last) => fixed(chain.callee) && every(flatten(earlier), fixed) && forwarded({
2466
+ args: last,
2467
+ names: input.names
2468
+ }) && (isArrayNonEmpty(earlier) || detachable({
2469
+ context: input.context,
2470
+ node: chain.callee
2471
+ }))
2472
+ });
2473
+ }
2474
+ function exactForwardingFunction(input) {
2475
+ const names = pipe(input.node.params, map$1(parameterName), getSomes);
2476
+ const returned = returnedExpression(input.node);
2477
+ if (input.node.async || input.node.generator || isArrayEmpty(names) || names.length !== input.node.params.length || isNullish$1(returned)) return false;
2123
2478
  if (returned.type === "Identifier") return names.length === 1 && returned.name === names[0];
2124
- return (returned.type === "CallExpression" || returned.type === "NewExpression") && returned.callee.type === "Identifier" && forwardedCall({
2479
+ return returned.type === "NewExpression" && returned.callee.type === "Identifier" && forwarded({
2480
+ args: returned.arguments,
2481
+ names
2482
+ }) || forwardedChain({
2483
+ context: input.context,
2125
2484
  names,
2126
- node: returned
2485
+ returned
2127
2486
  });
2128
2487
  }
2129
2488
  function isIdentity(node) {
@@ -2131,8 +2490,11 @@ function isIdentity(node) {
2131
2490
  const returned = returnedExpression(node);
2132
2491
  return node.params.length === 1 && parameter?.type === "Identifier" && returned?.type === "Identifier" && returned.name === parameter.name;
2133
2492
  }
2134
- function indirectionMessage(node) {
2135
- return isIdentity(node) ? "Pass identity from effect instead of this function." : "Inline this function at its only use site.";
2493
+ function indirectionMessage(input) {
2494
+ if (isIdentity(input.node)) return "Pass identity from effect instead of this function.";
2495
+ const returned = returnedExpression(input.node);
2496
+ if (exactForwardingFunction(input) && returned?.type === "CallExpression") return `Use ${input.context.sourceCode.getText(returned.callee)} directly; this function only passes its parameters on.`;
2497
+ return "Inline this function at its only use site.";
2136
2498
  }
2137
2499
  function isExport(node) {
2138
2500
  return node?.type === "ExportNamedDeclaration" || node?.type === "ExportDefaultDeclaration";
@@ -2211,38 +2573,56 @@ function singleUseLayerPart(input) {
2211
2573
  const noTrivialIndirection = defineRule({
2212
2574
  create: (context) => ({
2213
2575
  ArrowFunctionExpression: (node) => {
2214
- if ((node.parent.type === "VariableDeclarator" || node.parent.type === "Property") && (exactForwardingFunction(node) || singleUseThunk({
2576
+ if ((node.parent.type === "VariableDeclarator" || node.parent.type === "Property") && (exactForwardingFunction({
2577
+ context,
2578
+ node
2579
+ }) || singleUseThunk({
2215
2580
  context,
2216
2581
  node
2217
2582
  }) || singleCallerWrapper({
2218
2583
  context,
2219
2584
  node
2220
2585
  }))) context.report({
2221
- message: indirectionMessage(node),
2586
+ message: indirectionMessage({
2587
+ context,
2588
+ node
2589
+ }),
2222
2590
  node
2223
2591
  });
2224
2592
  },
2225
2593
  FunctionDeclaration: (node) => {
2226
- if (exactForwardingFunction(node) || singleUseThunk({
2594
+ if (exactForwardingFunction({
2595
+ context,
2596
+ node
2597
+ }) || singleUseThunk({
2227
2598
  context,
2228
2599
  node
2229
2600
  }) || singleCallerWrapper({
2230
2601
  context,
2231
2602
  node
2232
2603
  })) context.report({
2233
- message: indirectionMessage(node),
2604
+ message: indirectionMessage({
2605
+ context,
2606
+ node
2607
+ }),
2234
2608
  node
2235
2609
  });
2236
2610
  },
2237
2611
  FunctionExpression: (node) => {
2238
- if ((node.parent.type === "VariableDeclarator" || node.parent.type === "Property" || node.parent.type === "MethodDefinition" && node.parent.override !== true) && (exactForwardingFunction(node) || singleUseThunk({
2612
+ if ((node.parent.type === "VariableDeclarator" || node.parent.type === "Property" || node.parent.type === "MethodDefinition" && node.parent.override !== true) && (exactForwardingFunction({
2613
+ context,
2614
+ node
2615
+ }) || singleUseThunk({
2239
2616
  context,
2240
2617
  node
2241
2618
  }) || singleCallerWrapper({
2242
2619
  context,
2243
2620
  node
2244
2621
  }))) context.report({
2245
- message: indirectionMessage(node),
2622
+ message: indirectionMessage({
2623
+ context,
2624
+ node
2625
+ }),
2246
2626
  node
2247
2627
  });
2248
2628
  },
@@ -2341,13 +2721,12 @@ function unknownJsonSchema(input) {
2341
2721
  node: input.node.arguments[0],
2342
2722
  propertyName: "Unknown"
2343
2723
  })) return false;
2344
- const parent = input.node.parent;
2345
- if (parent.type !== "CallExpression" || parent.arguments[0] !== input.node || parent.callee.type !== "MemberExpression") return false;
2724
+ if (input.node.parent.type !== "CallExpression" || input.node.parent.arguments[0] !== input.node || input.node.parent.callee.type !== "MemberExpression") return false;
2346
2725
  return importedMember({
2347
2726
  context: input.context,
2348
2727
  importedName: "Schema",
2349
- node: parent.callee
2350
- }) && pipe(memberName(parent.callee), exists(startsWith("decode")));
2728
+ node: input.node.parent.callee
2729
+ }) && pipe(memberName(input.node.parent.callee), exists(startsWith("decode")));
2351
2730
  }
2352
2731
  const noUnvalidatedJsonDecode = defineRule({
2353
2732
  create: (context) => ({ CallExpression: (node) => {
@@ -2436,7 +2815,6 @@ function reportSchemaVariable(input) {
2436
2815
  node: input.variable.init
2437
2816
  })) return;
2438
2817
  const name = input.variable.id.name;
2439
- const annotation = input.variable.id.typeAnnotation;
2440
2818
  const typeStatement = pipe(input.program.body, findFirstIndex((statement) => statement === input.statement), filter((index) => index > 0), flatMap((index) => get$1(input.program.body, index - 1)));
2441
2819
  if (contains$1(input.cycleNames, name)) {
2442
2820
  if (!pipe(namedTypeAlias({
@@ -2449,7 +2827,7 @@ function reportSchemaVariable(input) {
2449
2827
  message: `Write \`type ${name} = ...\` by hand immediately before this recursive Schema; typeof ${name}.Type is circular.`,
2450
2828
  node: input.variable
2451
2829
  });
2452
- if (isNotNullish(annotation)) input.context.report({
2830
+ if (isNotNullish(input.variable.id.typeAnnotation)) input.context.report({
2453
2831
  message: "Annotate the Schema.suspend thunk, not the recursive Schema.",
2454
2832
  node: input.variable.id
2455
2833
  });
@@ -2472,9 +2850,9 @@ function reportSchemaVariable(input) {
2472
2850
  message: "Infer this schema instead of restating Schema.Schema.",
2473
2851
  node: input.variable.init
2474
2852
  });
2475
- if (isNotNullish(annotation) && schemaSchemaType({
2853
+ if (isNotNullish(input.variable.id.typeAnnotation) && schemaSchemaType({
2476
2854
  context: input.context,
2477
- node: annotation.typeAnnotation
2855
+ node: input.variable.id.typeAnnotation.typeAnnotation
2478
2856
  })) input.context.report({
2479
2857
  message: "Infer this schema instead of annotating Schema.Schema.",
2480
2858
  node: input.variable.id
@@ -2512,7 +2890,40 @@ const reactLegacyApis = [
2512
2890
  ];
2513
2891
  const reactLegacyMessage = "Use React 19 function components with refs as props; React Compiler owns memoization.";
2514
2892
  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.";
2515
- const runMessage = "Run the entry point with NodeRuntime.runMain, or bridge a Promise an external contract demands once, where it is returned, with Effect.runPromiseWith(Context.empty()).";
2893
+ const reactHooks = [
2894
+ "use",
2895
+ "useActionState",
2896
+ "useContext",
2897
+ "useDebugValue",
2898
+ "useDeferredValue",
2899
+ "useEffect",
2900
+ "useEffectEvent",
2901
+ "useId",
2902
+ "useImperativeHandle",
2903
+ "useInsertionEffect",
2904
+ "useLayoutEffect",
2905
+ "useOptimistic",
2906
+ "useReducer",
2907
+ "useRef",
2908
+ "useState",
2909
+ "useSyncExternalStore",
2910
+ "useTransition"
2911
+ ];
2912
+ 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.";
2913
+ const runners = [
2914
+ "runCallback",
2915
+ "runCallbackWith",
2916
+ "runFork",
2917
+ "runForkWith",
2918
+ "runPromise",
2919
+ "runPromiseExit",
2920
+ "runPromiseExitWith",
2921
+ "runPromiseWith",
2922
+ "runSync",
2923
+ "runSyncExit",
2924
+ "runSyncExitWith",
2925
+ "runSyncWith"
2926
+ ];
2516
2927
  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.";
2517
2928
  const oxlint = defineConfig({
2518
2929
  categories: {
@@ -2611,6 +3022,7 @@ const oxlint = defineConfig({
2611
3022
  "@deslop/coding-standards/no-error-message-assertion": "error",
2612
3023
  "@deslop/coding-standards/no-fake-ref-state": "error",
2613
3024
  "@deslop/coding-standards/no-hand-written-guard": "error",
3025
+ "@deslop/coding-standards/no-in-operator": "error",
2614
3026
  "@deslop/coding-standards/no-let": "error",
2615
3027
  "@deslop/coding-standards/no-multiline-comment": "error",
2616
3028
  "@deslop/coding-standards/no-native-control": "error",
@@ -2618,13 +3030,14 @@ const oxlint = defineConfig({
2618
3030
  "@deslop/coding-standards/no-native-method-call": "error",
2619
3031
  "@deslop/coding-standards/no-nullish-ternary": "error",
2620
3032
  "@deslop/coding-standards/no-option-value-access": "error",
3033
+ "@deslop/coding-standards/no-property-alias": "error",
2621
3034
  "@deslop/coding-standards/no-readonly-type-syntax": "error",
2622
- "@deslop/coding-standards/no-redundant-return-type": "error",
2623
3035
  "@deslop/coding-standards/no-redundant-state-type": "error",
2624
3036
  "@deslop/coding-standards/no-redundant-use-ref-null-type": "error",
2625
3037
  "@deslop/coding-standards/no-redundant-variable-annotation": "error",
2626
3038
  "@deslop/coding-standards/no-reinvented-schema": "error",
2627
3039
  "@deslop/coding-standards/no-renamed-import": "error",
3040
+ "@deslop/coding-standards/no-return-type": "error",
2628
3041
  "@deslop/coding-standards/no-single-use-value": "error",
2629
3042
  "@deslop/coding-standards/no-stored-schema-operation": "error",
2630
3043
  "@deslop/coding-standards/no-switch-statement": "error",
@@ -2911,7 +3324,6 @@ const oxlint = defineConfig({
2911
3324
  "no-misleading-character-class": "error",
2912
3325
  "no-multi-assign": "error",
2913
3326
  "no-negated-condition": "error",
2914
- "no-nested-ternary": "error",
2915
3327
  "no-new": "error",
2916
3328
  "no-param-reassign": ["error", { props: true }],
2917
3329
  "no-plusplus": "error",
@@ -2991,31 +3403,11 @@ const oxlint = defineConfig({
2991
3403
  message: "Use Predicate.hasProperty.",
2992
3404
  property: "hasOwnProperty"
2993
3405
  },
2994
- {
2995
- message: runMessage,
2996
- object: "Effect",
2997
- property: "runFork"
2998
- },
2999
- {
3000
- message: runMessage,
3001
- object: "Effect",
3002
- property: "runPromise"
3003
- },
3004
- {
3406
+ ...map$1(runners, (property) => ({
3005
3407
  message: runMessage,
3006
3408
  object: "Effect",
3007
- property: "runPromiseExit"
3008
- },
3009
- {
3010
- message: runMessage,
3011
- object: "Effect",
3012
- property: "runSync"
3013
- },
3014
- {
3015
- message: runMessage,
3016
- object: "Effect",
3017
- property: "runSyncExit"
3018
- },
3409
+ property
3410
+ })),
3019
3411
  {
3020
3412
  message: runMessage,
3021
3413
  object: "ManagedRuntime",
@@ -3026,6 +3418,11 @@ const oxlint = defineConfig({
3026
3418
  object: "Math",
3027
3419
  property: "max"
3028
3420
  },
3421
+ {
3422
+ message: "Use Option.getOrUndefined; undefined marks an absent value.",
3423
+ object: "Option",
3424
+ property: "getOrNull"
3425
+ },
3029
3426
  {
3030
3427
  message: "Use Number.min.",
3031
3428
  object: "Math",
@@ -3041,6 +3438,11 @@ const oxlint = defineConfig({
3041
3438
  object: "React",
3042
3439
  property
3043
3440
  })),
3441
+ ...map$1(reactHooks, (property) => ({
3442
+ message: `Import ${property} by name from react.`,
3443
+ object: "React",
3444
+ property
3445
+ })),
3044
3446
  {
3045
3447
  message: "Use Schema.Struct.",
3046
3448
  object: "Schema",
@@ -3140,6 +3542,7 @@ const oxlint = defineConfig({
3140
3542
  "String"
3141
3543
  ] }],
3142
3544
  "no-sparse-arrays": "error",
3545
+ "no-ternary": "error",
3143
3546
  "no-throw-literal": "error",
3144
3547
  "no-unmodified-loop-condition": "error",
3145
3548
  "no-unneeded-ternary": "error",
@@ -3316,6 +3719,7 @@ var oxlint_default = definePlugin({
3316
3719
  "no-error-message-assertion": noErrorMessageAssertion,
3317
3720
  "no-fake-ref-state": noFakeRefState,
3318
3721
  "no-hand-written-guard": noHandWrittenGuard,
3722
+ "no-in-operator": noInOperator,
3319
3723
  "no-let": noLet,
3320
3724
  "no-multiline-comment": noMultilineComment,
3321
3725
  "no-native-control": noNativeControl,
@@ -3323,13 +3727,14 @@ var oxlint_default = definePlugin({
3323
3727
  "no-native-method-call": noNativeMethodCall,
3324
3728
  "no-nullish-ternary": noNullishTernary,
3325
3729
  "no-option-value-access": noOptionValueAccess,
3730
+ "no-property-alias": noPropertyAlias,
3326
3731
  "no-readonly-type-syntax": noReadonlyTypeSyntax,
3327
- "no-redundant-return-type": noRedundantReturnType,
3328
3732
  "no-redundant-state-type": noRedundantStateType,
3329
3733
  "no-redundant-use-ref-null-type": noRedundantUseRefNullType,
3330
3734
  "no-redundant-variable-annotation": noRedundantVariableAnnotation,
3331
3735
  "no-reinvented-schema": noReinventedSchema,
3332
3736
  "no-renamed-import": noRenamedImport,
3737
+ "no-return-type": noReturnType,
3333
3738
  "no-single-use-value": noSingleUseValue,
3334
3739
  "no-stored-schema-operation": noStoredSchemaOperation,
3335
3740
  "no-switch-statement": noSwitchStatement,