@deslop/coding-standards 0.1.1082 → 0.1.1083

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 { $ 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";
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";
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";
@@ -890,6 +890,68 @@ function singleUseThunk(input) {
890
890
  })), exists((variable) => filter$1(variable.references, (reference) => reference.isRead()).length === 1));
891
891
  }
892
892
  //#endregion
893
+ //#region src/rules/explicit-effect-concurrency.ts
894
+ function statesConcurrency(node) {
895
+ if (node === void 0) return false;
896
+ if (node.type !== "ObjectExpression") return true;
897
+ return some$1(node.properties, (property) => property.type === "SpreadElement" || property.key.type === "Identifier" && property.key.name === "concurrency" || property.key.type === "Literal" && property.key.value === "concurrency");
898
+ }
899
+ function isFunction(node) {
900
+ return node?.type === "ArrowFunctionExpression" || node?.type === "FunctionExpression";
901
+ }
902
+ const explicitEffectConcurrency = defineRule({
903
+ create: (context) => ({ CallExpression: (node) => {
904
+ if (node.callee.type !== "MemberExpression" || !importedMember({
905
+ context,
906
+ importedName: "Effect",
907
+ node: node.callee
908
+ })) return;
909
+ const name = memberName(node.callee);
910
+ 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", {
912
+ onFalse: () => 2,
913
+ onTrue: () => 1
914
+ });
915
+ if (statesConcurrency(node.arguments[index])) return;
916
+ context.report({
917
+ message: "Choose the concurrency: {concurrency: 'unbounded'} for independent effects, {concurrency: 1} when order or a shared resource matters.",
918
+ node: node.callee
919
+ });
920
+ } }),
921
+ meta: { type: "problem" }
922
+ });
923
+ //#endregion
924
+ //#region src/rules/motion-limits.ts
925
+ function utility(token) {
926
+ return pipe(token, split(":"), last, getOrElse(() => token), replace(/^!|!$/gu, ""));
927
+ }
928
+ function amount(token, pattern) {
929
+ return pipe(utility(token), match$1(pattern), flatMap((match) => fromNullishOr(match[1])), map((value) => pipe(parse(value), getOrElse(() => 0))));
930
+ }
931
+ 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.");
933
+ 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.");
935
+ return none();
936
+ }
937
+ function check$1(context, node, text) {
938
+ pipe(split(text, /\s+/u), map$1(violation), getSomes, head, map((message) => context.report({
939
+ message,
940
+ node
941
+ })));
942
+ }
943
+ const motionLimits = defineRule({
944
+ create: (context) => ({
945
+ Literal: (node) => {
946
+ if (isString(node.value)) check$1(context, node, node.value);
947
+ },
948
+ TemplateElement: (node) => {
949
+ check$1(context, node, node.value.raw);
950
+ }
951
+ }),
952
+ meta: { type: "problem" }
953
+ });
954
+ //#endregion
893
955
  //#region src/rules/no-array-wrap-ternary.ts
894
956
  function testedValue(node) {
895
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();
@@ -937,6 +999,63 @@ const noArrayWrapTernary = defineRule({
937
999
  meta: { type: "problem" }
938
1000
  });
939
1001
  //#endregion
1002
+ //#region src/rules/no-barrel-module.ts
1003
+ const noBarrelModule = defineRule({
1004
+ create: (context) => ({
1005
+ ExportAllDeclaration: (node) => {
1006
+ context.report({
1007
+ message: "Import from the module that defines each name; never re-export a whole module.",
1008
+ node
1009
+ });
1010
+ },
1011
+ Program: (node) => {
1012
+ const statements = filter$1(node.body, (statement) => statement.type !== "ImportDeclaration");
1013
+ if (isArrayEmpty(statements) || !every(statements, (statement) => statement.type === "ExportNamedDeclaration" && statement.source !== null)) return;
1014
+ context.report({
1015
+ message: "Import from the defining modules instead of a file that only re-exports them.",
1016
+ node
1017
+ });
1018
+ }
1019
+ }),
1020
+ meta: { type: "problem" }
1021
+ });
1022
+ //#endregion
1023
+ //#region src/rules/no-compiler-opt-out.ts
1024
+ const noCompilerOptOut = defineRule({
1025
+ create: (context) => ({ ExpressionStatement: (node) => {
1026
+ if (node.directive !== "use no memo" && node.directive !== "use no forget") return;
1027
+ context.report({
1028
+ message: "Fix the code React Compiler rejects instead of opting the function out of compilation.",
1029
+ node
1030
+ });
1031
+ } }),
1032
+ meta: { type: "problem" }
1033
+ });
1034
+ //#endregion
1035
+ //#region src/rules/no-component-atom-allocation.ts
1036
+ const componentOrHook = matches(/^(?:[A-Z]|use[A-Z])/u);
1037
+ const readsOrWrites = matches(/^(?:is[A-Z]|get|set$|update$|modify$|refresh$|mount$|batch$|toStream)/u);
1038
+ function renderingFunction(node) {
1039
+ return pipe(fromNullishOr(node.parent), flatMap((parent) => {
1040
+ if ((parent.type === "FunctionDeclaration" || parent.type === "FunctionExpression" || parent.type === "ArrowFunctionExpression") && exists(bindingName(parent), componentOrHook)) return some(parent);
1041
+ return renderingFunction(parent);
1042
+ }));
1043
+ }
1044
+ const noComponentAtomAllocation = defineRule({
1045
+ create: (context) => ({ CallExpression: (node) => {
1046
+ if (node.callee.type !== "MemberExpression" || node.callee.object.type !== "Identifier" || node.callee.object.name !== "Atom" || !isImportBinding({
1047
+ context,
1048
+ node: node.callee.object,
1049
+ source: /reactivity|atom/u
1050
+ }) || exists(memberName(node.callee), readsOrWrites) || isNone(renderingFunction(node))) return;
1051
+ context.report({
1052
+ message: "Declare the atom at module level, or in Atom.family keyed by the prop; an atom made during render is a new atom on every render.",
1053
+ node
1054
+ });
1055
+ } }),
1056
+ meta: { type: "problem" }
1057
+ });
1058
+ //#endregion
940
1059
  //#region src/rules/no-constant-function.ts
941
1060
  function isConstantFunction(input) {
942
1061
  if (input.node.async || input.node.generator || isArrayNonEmpty(input.node.params) || isNotNullish(input.node.typeParameters)) return false;
@@ -1186,6 +1305,80 @@ const noEffectPropertyArrow = defineRule({
1186
1305
  meta: { type: "problem" }
1187
1306
  });
1188
1307
  //#endregion
1308
+ //#region src/rules/no-empty-recovery.ts
1309
+ function calleeOf(node) {
1310
+ if (node.type === "CallExpression" && node.callee.type !== "Super") return node.callee;
1311
+ return node;
1312
+ }
1313
+ function isEffectEmpty(input) {
1314
+ const member = calleeOf(input.node);
1315
+ return member.type === "MemberExpression" && member.object.type === "Identifier" && contains(memberName(member), "empty") && isImportBinding({
1316
+ context: input.context,
1317
+ node: member.object,
1318
+ source: "effect"
1319
+ });
1320
+ }
1321
+ function isEmptyValue(input) {
1322
+ if (isNullish$1(input.node)) return false;
1323
+ if (input.node.type === "Identifier") return input.node.name === "undefined";
1324
+ if (input.node.type === "Literal") return input.node.value === null || input.node.value === "";
1325
+ if (input.node.type === "ArrayExpression") return isArrayEmpty(input.node.elements);
1326
+ if (input.node.type === "ObjectExpression") return isArrayEmpty(input.node.properties);
1327
+ if (input.node.type === "TemplateLiteral") return isArrayEmpty(input.node.expressions) && every(input.node.quasis, (quasi) => quasi.value.raw === "");
1328
+ return isEffectEmpty({
1329
+ context: input.context,
1330
+ node: input.node
1331
+ });
1332
+ }
1333
+ function isEmptySuccess(input) {
1334
+ if (isNullish$1(input.node)) return false;
1335
+ if (importedMember({
1336
+ context: input.context,
1337
+ importedName: "Effect",
1338
+ node: input.node,
1339
+ propertyName: "void"
1340
+ })) return true;
1341
+ return input.node.type === "CallExpression" && input.node.callee.type !== "Super" && importedMember({
1342
+ context: input.context,
1343
+ importedName: "Effect",
1344
+ node: input.node.callee,
1345
+ propertyName: "succeed"
1346
+ }) && every(input.node.arguments, (argument) => argument.type !== "SpreadElement" && isEmptyValue({
1347
+ context: input.context,
1348
+ node: argument
1349
+ }));
1350
+ }
1351
+ function recoversEmpty(input) {
1352
+ if (input.name === "orElseSucceed") return isEmptyValue({
1353
+ context: input.context,
1354
+ node: input.node
1355
+ });
1356
+ return isEmptySuccess({
1357
+ context: input.context,
1358
+ node: input.node
1359
+ });
1360
+ }
1361
+ const noEmptyRecovery = defineRule({
1362
+ create: (context) => ({ CallExpression: (node) => {
1363
+ if (node.callee.type !== "MemberExpression" || !importedMember({
1364
+ context,
1365
+ importedName: "Effect",
1366
+ node: node.callee
1367
+ })) return;
1368
+ const name = pipe(memberName(node.callee), getOrElse(() => ""));
1369
+ if (!pipe(name, startsWith("catch")) && !pipe(name, startsWith("orElse"))) return;
1370
+ for (const argument of node.arguments) if ((argument.type === "ArrowFunctionExpression" || argument.type === "FunctionExpression") && recoversEmpty({
1371
+ context,
1372
+ name,
1373
+ node: returnedExpression(argument)
1374
+ })) context.report({
1375
+ message: "Let the failure flow, or map it to the service’s error; an empty value hides that the work failed.",
1376
+ node: argument
1377
+ });
1378
+ } }),
1379
+ meta: { type: "problem" }
1380
+ });
1381
+ //#endregion
1189
1382
  //#region src/rules/no-error-message-assertion.ts
1190
1383
  function receiverName(node) {
1191
1384
  if (node.type === "Identifier") return some(node.name);
@@ -1256,6 +1449,26 @@ const noFakeRefState = defineRule({
1256
1449
  meta: { type: "problem" }
1257
1450
  });
1258
1451
  //#endregion
1452
+ //#region src/rules/no-gradient.ts
1453
+ const gradient = /(?:^|[\s:])bg-(?:linear|radial|conic|gradient)(?:-|$|\s)|gradient\(/u;
1454
+ function report$4(context, node) {
1455
+ context.report({
1456
+ message: "Use a flat theme color; gradients are never part of the design.",
1457
+ node
1458
+ });
1459
+ }
1460
+ const noGradient = defineRule({
1461
+ create: (context) => ({
1462
+ Literal: (node) => {
1463
+ if (isString(node.value) && gradient.test(node.value)) report$4(context, node);
1464
+ },
1465
+ TemplateElement: (node) => {
1466
+ if (gradient.test(node.value.raw)) report$4(context, node);
1467
+ }
1468
+ }),
1469
+ meta: { type: "problem" }
1470
+ });
1471
+ //#endregion
1259
1472
  //#region src/rules/no-hand-written-guard.ts
1260
1473
  function isSubject(input) {
1261
1474
  return input.node.type === "Identifier" && input.node.name === input.name;
@@ -1308,7 +1521,7 @@ function check(input) {
1308
1521
  subject: input.node.right
1309
1522
  })]), map(of));
1310
1523
  }
1311
- function report$2(input) {
1524
+ function report$3(input) {
1312
1525
  const predicate = input.node.returnType?.typeAnnotation;
1313
1526
  const returned = returnedExpression(input.node);
1314
1527
  if (predicate?.type !== "TSTypePredicate" || predicate.asserts || predicate.parameterName.type !== "Identifier" || isNullish$1(returned)) return;
@@ -1348,19 +1561,19 @@ function report$2(input) {
1348
1561
  const noHandWrittenGuard = defineRule({
1349
1562
  create: (context) => ({
1350
1563
  ArrowFunctionExpression: (node) => {
1351
- report$2({
1564
+ report$3({
1352
1565
  context,
1353
1566
  node
1354
1567
  });
1355
1568
  },
1356
1569
  FunctionDeclaration: (node) => {
1357
- report$2({
1570
+ report$3({
1358
1571
  context,
1359
1572
  node
1360
1573
  });
1361
1574
  },
1362
1575
  FunctionExpression: (node) => {
1363
- report$2({
1576
+ report$3({
1364
1577
  context,
1365
1578
  node
1366
1579
  });
@@ -1422,15 +1635,25 @@ const primitives = {
1422
1635
  textarea: "Textarea"
1423
1636
  };
1424
1637
  const controlStyle = /(?:^|:)(?:hover|focus|focus-visible|active):|(?:^|:)(?:rounded|shadow|ring)(?:-|$)|(?:^|:)p[blrtxy]?-(?!0$)|(?:^|:)bg-(?!transparent$)|(?:^|:)border(?:-[blrtxy])?$|(?:^|:)border-(?!0$|[blrtxy]-0$)/u;
1638
+ function classStrings(node) {
1639
+ if (node.type === "Literal") return filter$1([node.value], isString);
1640
+ if (node.type === "TemplateLiteral") return map$1(node.quasis, (quasi) => quasi.value.raw);
1641
+ if (node.type === "JSXExpressionContainer") return classStrings(node.expression);
1642
+ if (node.type === "CallExpression") return flatMap$1(node.arguments, classStrings);
1643
+ if (node.type === "ConditionalExpression") return flatMap$1([node.consequent, node.alternate], classStrings);
1644
+ if (node.type === "LogicalExpression") return classStrings(node.right);
1645
+ if (node.type === "ArrayExpression") return flatMap$1(filter$1(node.elements, isNotNull), classStrings);
1646
+ return empty();
1647
+ }
1425
1648
  const noNativeControl = defineRule({
1426
1649
  create: (context) => ({ JSXOpeningElement: (node) => {
1427
1650
  if (node.name.type !== "JSXIdentifier") return;
1428
1651
  const name = node.name.name;
1429
1652
  map(get$2(primitives, name), (primitive) => {
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))));
1653
+ const styled = pipe(node.attributes, findFirst((attribute) => attribute.type === "JSXAttribute" && attribute.name.type === "JSXIdentifier" && attribute.name.name === "className"), map((attribute) => {
1654
+ if (attribute.type !== "JSXAttribute" || attribute.value === null) return empty();
1655
+ return classStrings(attribute.value);
1656
+ }), exists((values) => some$1(values, (value) => some$1(split(value, /\s+/u), matches(controlStyle)))));
1434
1657
  if (name !== "select" && !styled) return;
1435
1658
  context.report({
1436
1659
  message: `Use the ${primitive} UI primitive instead of a styled native control.`,
@@ -1532,13 +1755,49 @@ function freshRegExpFlags(input) {
1532
1755
  if (flags.type !== "Literal" || !isString(flags.value)) return some(none());
1533
1756
  return some(some(flags.value));
1534
1757
  }
1758
+ const nativeGlobals = [
1759
+ "Object",
1760
+ "Promise",
1761
+ "RegExp"
1762
+ ];
1763
+ function memberRoot(node) {
1764
+ if (node.type === "MemberExpression") return memberRoot(node.object);
1765
+ return node;
1766
+ }
1767
+ function chainRoot(node) {
1768
+ if (node.type === "MemberExpression") return chainRoot(node.object);
1769
+ if (node.type === "CallExpression" && node.callee.type !== "Super") return chainRoot(node.callee);
1770
+ if (node.type === "ParenthesizedExpression") return chainRoot(node.expression);
1771
+ return node;
1772
+ }
1773
+ function isYieldedService(node) {
1774
+ if (node?.type !== "YieldExpression" || !node.delegate || isNullish$1(node.argument)) return false;
1775
+ if (node.argument.type === "Identifier") return matches(/^[A-Z]/u)(node.argument.name);
1776
+ return node.argument.type === "MemberExpression" && exists(memberName(node.argument), (name) => matches(/^[A-Z]/u)(name));
1777
+ }
1778
+ const effectPackage = matches(/^(?:effect(?:\/|$)|@effect\/)/u);
1779
+ const localPath = matches(/^[.#~/]|^@\//u);
1780
+ function ownsMethod(input) {
1781
+ const root = chainRoot(input.receiver);
1782
+ const throughCall = root !== memberRoot(input.receiver);
1783
+ if (isYieldedService(root)) return true;
1784
+ if (root.type !== "Identifier") return false;
1785
+ if (root.name === "path") return !throughCall;
1786
+ 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),
1788
+ onSome: (variable) => some$1(variable.defs, (definition) => {
1789
+ if (definition.node.type === "VariableDeclarator") return !throughCall && isYieldedService(definition.node.init);
1790
+ if (definition.type !== "ImportBinding" || definition.parent?.type !== "ImportDeclaration") return false;
1791
+ return !localPath(definition.parent.source.value) && !(throughCall && effectPackage(definition.parent.source.value));
1792
+ })
1793
+ }));
1794
+ }
1535
1795
  const noNativeMethodCall = defineRule({
1536
1796
  create: (context) => ({ CallExpression: (node) => {
1537
- if (node.callee.type !== "MemberExpression" || node.callee.object.type === "Identifier" && (node.callee.object.name === "path" || isImportBinding({
1797
+ if (node.callee.type !== "MemberExpression" || ownsMethod({
1538
1798
  context,
1539
- node: node.callee.object,
1540
- source: /^(?:effect(?:\/|$)|@effect\/)/u
1541
- }))) return;
1799
+ receiver: node.callee.object
1800
+ })) return;
1542
1801
  const receiver = node.callee.object;
1543
1802
  const regExpFlags = freshRegExpFlags({
1544
1803
  context,
@@ -1555,12 +1814,10 @@ const noNativeMethodCall = defineRule({
1555
1814
  "entries",
1556
1815
  "keys",
1557
1816
  "values"
1558
- ], name) || isArrayEmpty(node.arguments) || receiver.type === "Identifier" && receiver.name === "Object"), map((name) => {
1559
- context.report({
1560
- 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.`,
1561
- node: node.callee
1562
- });
1563
- }));
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.`,
1819
+ node: node.callee
1820
+ })));
1564
1821
  } }),
1565
1822
  meta: { type: "problem" }
1566
1823
  });
@@ -1751,7 +2008,7 @@ function replacement(input) {
1751
2008
  if (input.read.parent?.type === "Property" && input.read.parent.shorthand) return `${input.name}: ${input.text}`;
1752
2009
  return input.text;
1753
2010
  }
1754
- function report$1(input) {
2011
+ function report$2(input) {
1755
2012
  const reads = pipe(input.variable.references, filter$1((reference) => reference.isRead()), map$1((reference) => reference.identifier));
1756
2013
  const text = input.context.sourceCode.getText(input.init);
1757
2014
  pipe(rootName(input.init), filter((root) => isArrayNonEmpty(reads) && every(reads, (read) => {
@@ -1810,7 +2067,7 @@ const noPropertyAlias = defineRule({
1810
2067
  scope: context.sourceCode.getScope(candidate.node)
1811
2068
  }), match({
1812
2069
  onNone: constVoid,
1813
- onSome: (variable) => report$1({
2070
+ onSome: (variable) => report$2({
1814
2071
  ...candidate,
1815
2072
  context,
1816
2073
  variable,
@@ -2324,7 +2581,7 @@ function inlined(input) {
2324
2581
  if (input.read.range[0] === input.next.range[0]) return `;${value}`;
2325
2582
  return value;
2326
2583
  }
2327
- function report(input) {
2584
+ function report$1(input) {
2328
2585
  const declaration = input.node.parent;
2329
2586
  const init = input.node.init;
2330
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;
@@ -2375,7 +2632,7 @@ const noSingleUseValue = defineRule({
2375
2632
  CallExpression: effect,
2376
2633
  NewExpression: effect,
2377
2634
  "Program:exit": () => {
2378
- for (const node of get$3(candidates)) report({
2635
+ for (const node of get$3(candidates)) report$1({
2379
2636
  context,
2380
2637
  effects: get$3(effects),
2381
2638
  node
@@ -2741,6 +2998,44 @@ const noUnvalidatedJsonDecode = defineRule({
2741
2998
  meta: { type: "problem" }
2742
2999
  });
2743
3000
  //#endregion
3001
+ //#region src/rules/preserve-error-cause.ts
3002
+ function constructedFields(node) {
3003
+ if (node?.type !== "CallExpression" && node?.type !== "NewExpression") return none();
3004
+ const constructs = node.type === "NewExpression" || node.callee.type === "MemberExpression" && contains(memberName(node.callee), "make");
3005
+ const fields = node.arguments[0];
3006
+ if (!constructs || fields?.type !== "ObjectExpression") return none();
3007
+ return some(fields);
3008
+ }
3009
+ function dropsCause(node) {
3010
+ if (node.type !== "ArrowFunctionExpression" && node.type !== "FunctionExpression" || isArrayEmpty(node.params)) return false;
3011
+ return exists(constructedFields(returnedExpression(node)), (fields) => every(fields.properties, (property) => property.type === "SpreadElement" || !(property.key.type === "Identifier" && property.key.name === "cause")));
3012
+ }
3013
+ function report(context, node) {
3014
+ context.report({
3015
+ message: "Keep the original failure as the new error’s cause: X.make({cause, message}).",
3016
+ node
3017
+ });
3018
+ }
3019
+ const preserveErrorCause = defineRule({
3020
+ create: (context) => ({ CallExpression: (node) => {
3021
+ if (node.callee.type !== "MemberExpression" || !importedMember({
3022
+ context,
3023
+ importedName: "Effect",
3024
+ node: node.callee
3025
+ })) return;
3026
+ const name = memberName(node.callee);
3027
+ if (contains(name, "mapError")) {
3028
+ forEach(filter$1(node.arguments, dropsCause), (callback) => report(context, callback));
3029
+ return;
3030
+ }
3031
+ if (!exists(name, (method) => method === "try" || method === "tryPromise")) return;
3032
+ const options = node.arguments[0];
3033
+ if (options?.type !== "ObjectExpression") return;
3034
+ for (const property of options.properties) if (property.type === "Property" && property.key.type === "Identifier" && property.key.name === "catch" && dropsCause(property.value)) report(context, property.value);
3035
+ } }),
3036
+ meta: { type: "problem" }
3037
+ });
3038
+ //#endregion
2744
3039
  //#region src/rules/schema-type-pair.ts
2745
3040
  function expressionRoot(node) {
2746
3041
  if (node.type === "MemberExpression") return expressionRoot(node.object);
@@ -2808,6 +3103,31 @@ function isSchemaDefinition(input) {
2808
3103
  function namedTypeAlias(input) {
2809
3104
  return pipe(input.typeStatement, flatMap(typeAlias), filter((declaration) => declaration.id.name === input.name));
2810
3105
  }
3106
+ function exportedNames(input) {
3107
+ return flatMap$1(input.program.body, (statement) => {
3108
+ if (statement.type !== "ExportNamedDeclaration" || statement.declaration !== null || statement.source !== null) return empty();
3109
+ return flatMap$1(statement.specifiers, (specifier) => {
3110
+ const typeOnly = statement.exportKind === "type" || specifier.exportKind === "type";
3111
+ if (specifier.local.type !== "Identifier" || typeOnly !== input.typeOnly) return empty();
3112
+ return [specifier.local.name];
3113
+ });
3114
+ });
3115
+ }
3116
+ function exportLists(program) {
3117
+ return {
3118
+ types: exportedNames({
3119
+ program,
3120
+ typeOnly: true
3121
+ }),
3122
+ values: exportedNames({
3123
+ program,
3124
+ typeOnly: false
3125
+ })
3126
+ };
3127
+ }
3128
+ 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);
3130
+ }
2811
3131
  function reportSchemaVariable(input) {
2812
3132
  if (input.variable.id.type !== "Identifier" || !matches(/^[A-Z]/u)(input.variable.id.name)) return;
2813
3133
  if (input.variable.init === null || !isSchemaDefinition({
@@ -2843,6 +3163,20 @@ function reportSchemaVariable(input) {
2843
3163
  message: `Place \`type ${name} = typeof ${name}.Type\` immediately before this Schema.`,
2844
3164
  node: input.variable
2845
3165
  });
3166
+ else if (isExported({
3167
+ exports: input.exports,
3168
+ name,
3169
+ statement: input.statement,
3170
+ typeOnly: false
3171
+ }) !== exists(typeStatement, (statement) => isExported({
3172
+ exports: input.exports,
3173
+ name,
3174
+ statement,
3175
+ typeOnly: true
3176
+ }))) input.context.report({
3177
+ message: `Export both \`type ${name}\` and the \`${name}\` Schema, or neither.`,
3178
+ node: input.variable
3179
+ });
2846
3180
  if (input.variable.init.type === "TSSatisfiesExpression" && schemaSchemaType({
2847
3181
  context: input.context,
2848
3182
  node: input.variable.init.typeAnnotation
@@ -2864,11 +3198,13 @@ const schemaTypePair = defineRule({
2864
3198
  context,
2865
3199
  program
2866
3200
  });
3201
+ const exports = exportLists(program);
2867
3202
  for (const statement of program.body) {
2868
3203
  const declaration = statementDeclaration(statement);
2869
3204
  if (declaration?.type === "VariableDeclaration") for (const variable of declaration.declarations) reportSchemaVariable({
2870
3205
  context,
2871
3206
  cycleNames,
3207
+ exports,
2872
3208
  program,
2873
3209
  statement,
2874
3210
  variable
@@ -2969,6 +3305,10 @@ const oxlint = defineConfig({
2969
3305
  ],
2970
3306
  rules: { "import/no-default-export": "off" }
2971
3307
  },
3308
+ {
3309
+ files: ["**/app.plugin.js"],
3310
+ rules: { "@deslop/coding-standards/no-barrel-module": "off" }
3311
+ },
2972
3312
  {
2973
3313
  files: ["**/components/ui/**"],
2974
3314
  rules: {
@@ -2981,7 +3321,9 @@ const oxlint = defineConfig({
2981
3321
  rules: {
2982
3322
  "@deslop/coding-standards/no-destructured-parameter": "off",
2983
3323
  "@deslop/coding-standards/no-native-control": "off",
2984
- "@deslop/coding-standards/no-renamed-import": "off"
3324
+ "@deslop/coding-standards/no-renamed-import": "off",
3325
+ "jsx-a11y/click-events-have-key-events": "off",
3326
+ "jsx-a11y/label-has-associated-control": "off"
2985
3327
  }
2986
3328
  },
2987
3329
  {
@@ -3008,19 +3350,27 @@ const oxlint = defineConfig({
3008
3350
  "typescript",
3009
3351
  "oxc",
3010
3352
  "import",
3353
+ "jsx-a11y",
3011
3354
  "react",
3012
3355
  "unicorn"
3013
3356
  ],
3014
3357
  rules: {
3358
+ "@deslop/coding-standards/explicit-effect-concurrency": "error",
3359
+ "@deslop/coding-standards/motion-limits": "error",
3015
3360
  "@deslop/coding-standards/no-array-wrap-ternary": "error",
3361
+ "@deslop/coding-standards/no-barrel-module": "error",
3362
+ "@deslop/coding-standards/no-compiler-opt-out": "error",
3363
+ "@deslop/coding-standards/no-component-atom-allocation": "error",
3016
3364
  "@deslop/coding-standards/no-constant-function": "error",
3017
3365
  "@deslop/coding-standards/no-deep-pipe": "error",
3018
3366
  "@deslop/coding-standards/no-destructured-parameter": "error",
3019
3367
  "@deslop/coding-standards/no-discarded-failure": "error",
3020
3368
  "@deslop/coding-standards/no-double-nullish-check": "error",
3021
3369
  "@deslop/coding-standards/no-effect-property-arrow": "error",
3370
+ "@deslop/coding-standards/no-empty-recovery": "error",
3022
3371
  "@deslop/coding-standards/no-error-message-assertion": "error",
3023
3372
  "@deslop/coding-standards/no-fake-ref-state": "error",
3373
+ "@deslop/coding-standards/no-gradient": "error",
3024
3374
  "@deslop/coding-standards/no-hand-written-guard": "error",
3025
3375
  "@deslop/coding-standards/no-in-operator": "error",
3026
3376
  "@deslop/coding-standards/no-let": "error",
@@ -3046,6 +3396,7 @@ const oxlint = defineConfig({
3046
3396
  "@deslop/coding-standards/no-undestructured-use-state": "error",
3047
3397
  "@deslop/coding-standards/no-unexplained-disable": "error",
3048
3398
  "@deslop/coding-standards/no-unvalidated-json-decode": "error",
3399
+ "@deslop/coding-standards/preserve-error-cause": "error",
3049
3400
  "@deslop/coding-standards/schema-type-pair": "error",
3050
3401
  "effecttsgo/abort-controller-in-effect": "error",
3051
3402
  "effecttsgo/crypto-random-uuid": "error",
@@ -3178,7 +3529,7 @@ const oxlint = defineConfig({
3178
3529
  "typescript/no-import-type-side-effects": "error",
3179
3530
  "typescript/no-inferrable-types": "error",
3180
3531
  "typescript/no-invalid-void-type": "error",
3181
- "typescript/no-misused-promises": ["error", { checksVoidReturn: false }],
3532
+ "typescript/no-misused-promises": ["error", { checksVoidReturn: { attributes: false } }],
3182
3533
  "typescript/no-misused-spread": "error",
3183
3534
  "typescript/no-namespace": ["error", { allowDeclarations: true }],
3184
3535
  "typescript/no-non-null-assertion": "error",
@@ -3210,6 +3561,7 @@ const oxlint = defineConfig({
3210
3561
  "typescript/restrict-plus-operands": "error",
3211
3562
  "typescript/restrict-template-expressions": "error",
3212
3563
  "typescript/strict-boolean-expressions": ["error", {
3564
+ allowNullableObject: false,
3213
3565
  allowNumber: false,
3214
3566
  allowString: false
3215
3567
  }],
@@ -3303,6 +3655,7 @@ const oxlint = defineConfig({
3303
3655
  }
3304
3656
  ]
3305
3657
  }],
3658
+ "array-callback-return": "error",
3306
3659
  "max-depth": ["error", 3],
3307
3660
  "max-nested-callbacks": ["error", 6],
3308
3661
  "no-cond-assign": "error",
@@ -3576,6 +3929,12 @@ const oxlint = defineConfig({
3576
3929
  "prefer-const": ["error", { destructuring: "all" }],
3577
3930
  "prefer-template": "error",
3578
3931
  "require-unicode-regexp": "error",
3932
+ "jsx-a11y/autocomplete-valid": "error",
3933
+ "jsx-a11y/click-events-have-key-events": "error",
3934
+ "jsx-a11y/control-has-associated-label": "error",
3935
+ "jsx-a11y/interactive-supports-focus": "error",
3936
+ "jsx-a11y/label-has-associated-control": "error",
3937
+ "react-doctor/no-aria-invalid-without-description": "error",
3579
3938
  "react-doctor/no-call-component-as-function": "error",
3580
3939
  "react-doctor/no-controlled-input-value-without-state-update": "error",
3581
3940
  "react-doctor/no-create-context-in-render": "error",
@@ -3583,12 +3942,18 @@ const oxlint = defineConfig({
3583
3942
  "react-doctor/no-inline-exhaustive-style": "error",
3584
3943
  "react-doctor/no-jsx-element-type": "error",
3585
3944
  "react-doctor/no-many-boolean-props": "error",
3945
+ "react-doctor/no-nested-card-surface": "error",
3946
+ "react-doctor/no-placeholder-only-field": "error",
3586
3947
  "react-doctor/no-prop-types": "error",
3587
3948
  "react-doctor/no-uncontrolled-input": "error",
3949
+ "react-doctor/shadcn-dialog-content-requires-title": "error",
3588
3950
  "react-doctor/shadcn-icon-button-requires-label": "error",
3589
3951
  "react-doctor/effect-listener-cleanup-mismatch": "error",
3952
+ "react-doctor/effect-needs-cleanup": "error",
3953
+ "react-doctor/no-adjust-state-on-prop-change": "error",
3590
3954
  "react-doctor/no-async-effect-callback": "error",
3591
3955
  "react-doctor/no-create-object-url-without-revoke": "error",
3956
+ "react-doctor/no-derived-state": "error",
3592
3957
  "react-doctor/no-derived-useState": "error",
3593
3958
  "react-doctor/no-effect-event-in-deps": "error",
3594
3959
  "react-doctor/no-effect-with-fresh-deps": "error",
@@ -3616,10 +3981,10 @@ const oxlint = defineConfig({
3616
3981
  "react-doctor/no-large-animated-blur": "error",
3617
3982
  "react-doctor/no-layout-property-animation": "error",
3618
3983
  "react-doctor/no-layout-transition-inline": "error",
3619
- "react-doctor/no-long-transition-duration": "error",
3620
3984
  "react-doctor/no-outline-none": "error",
3621
- "react-doctor/no-scale-from-zero": "error",
3985
+ "react-doctor/no-reduced-motion-content-removal": "error",
3622
3986
  "react-doctor/no-transition-all": "error",
3987
+ "react-doctor/no-ungated-tailwind-animation": "error",
3623
3988
  "react/button-has-type": "error",
3624
3989
  "react/checked-requires-onchange-or-readonly": "error",
3625
3990
  "react/exhaustive-deps": "error",
@@ -3649,6 +4014,7 @@ const oxlint = defineConfig({
3649
4014
  "react/preserve-manual-memoization": "error",
3650
4015
  "react/purity": "error",
3651
4016
  "react/refs": "error",
4017
+ "react/rule-suppression": "error",
3652
4018
  "react/rules-of-hooks": "error",
3653
4019
  "react/self-closing-comp": "error",
3654
4020
  "react/set-state-in-effect": "error",
@@ -3689,6 +4055,8 @@ const oxlint = defineConfig({
3689
4055
  "typescript/no-unnecessary-type-assertion": "error",
3690
4056
  "typescript/no-useless-default-assignment": "error",
3691
4057
  "unicorn/filename-case": "error",
4058
+ "unicorn/no-abusive-eslint-disable": "error",
4059
+ "unicorn/no-empty-file": "error",
3692
4060
  "unicorn/no-immediate-mutation": "error",
3693
4061
  "unicorn/no-null": "error",
3694
4062
  "unicorn/no-object-as-default-parameter": "error",
@@ -3702,6 +4070,12 @@ const oxlint = defineConfig({
3702
4070
  "use-isnan": "error"
3703
4071
  },
3704
4072
  settings: {
4073
+ "jsx-a11y": { components: {
4074
+ Button: "button",
4075
+ Input: "input",
4076
+ Label: "label",
4077
+ Textarea: "textarea"
4078
+ } },
3705
4079
  react: { version: "19.0" },
3706
4080
  shadcn: { ui: ["@deslop/components-web/ui", "@dual/ui/components"] }
3707
4081
  }
@@ -3709,15 +4083,22 @@ const oxlint = defineConfig({
3709
4083
  var oxlint_default = definePlugin({
3710
4084
  meta: { name: "@deslop/coding-standards" },
3711
4085
  rules: {
4086
+ "explicit-effect-concurrency": explicitEffectConcurrency,
4087
+ "motion-limits": motionLimits,
3712
4088
  "no-array-wrap-ternary": noArrayWrapTernary,
4089
+ "no-barrel-module": noBarrelModule,
4090
+ "no-compiler-opt-out": noCompilerOptOut,
4091
+ "no-component-atom-allocation": noComponentAtomAllocation,
3713
4092
  "no-constant-function": noConstantFunction,
3714
4093
  "no-deep-pipe": noDeepPipe,
3715
4094
  "no-destructured-parameter": noDestructuredParameter,
3716
4095
  "no-discarded-failure": noDiscardedFailure,
3717
4096
  "no-double-nullish-check": noDoubleNullishCheck,
3718
4097
  "no-effect-property-arrow": noEffectPropertyArrow,
4098
+ "no-empty-recovery": noEmptyRecovery,
3719
4099
  "no-error-message-assertion": noErrorMessageAssertion,
3720
4100
  "no-fake-ref-state": noFakeRefState,
4101
+ "no-gradient": noGradient,
3721
4102
  "no-hand-written-guard": noHandWrittenGuard,
3722
4103
  "no-in-operator": noInOperator,
3723
4104
  "no-let": noLet,
@@ -3743,6 +4124,7 @@ var oxlint_default = definePlugin({
3743
4124
  "no-undestructured-use-state": noUndestructuredUseState,
3744
4125
  "no-unexplained-disable": noUnexplainedDisable,
3745
4126
  "no-unvalidated-json-decode": noUnvalidatedJsonDecode,
4127
+ "preserve-error-cause": preserveErrorCause,
3746
4128
  "schema-type-pair": schemaTypePair
3747
4129
  }
3748
4130
  });