@deslop/coding-standards 0.1.1249 → 0.1.1252

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/lint.js +439 -28
  2. package/package.json +1 -1
package/dist/lint.js CHANGED
@@ -2307,6 +2307,19 @@ const succeed = (success) => new SuccessImpl(success);
2307
2307
  const fromOption$1 = /*#__PURE__*/ dual(2, (self, onNone) => isNone$1(self) ? fail(onNone()) : succeed(self.value));
2308
2308
  // ../../node_modules/.pnpm/effect@4.1.2/node_modules/effect/dist/Order.js
2309
2309
  /**
2310
+ * Defines comparison functions for ordered values.
2311
+ *
2312
+ * An `Order<A>` compares two `A` values and returns whether the first is less
2313
+ * than, equal to, or greater than the second. Orders are used for sorting,
2314
+ * choosing minimum or maximum values, checking ranges, and building ordered data
2315
+ * structures. This module includes built-in orders, constructors for custom
2316
+ * orders, tools for reversing and combining comparisons, tuple and struct
2317
+ * helpers, comparison predicates, clamping, and reducer support.
2318
+ *
2319
+ * @stability stable
2320
+ * @since 2.0.0
2321
+ */
2322
+ /**
2310
2323
  * Creates a new `Order` instance from a comparison function.
2311
2324
  *
2312
2325
  * **When to use**
@@ -2374,6 +2387,76 @@ function make$4(compare) {
2374
2387
  * @since 4.0.0
2375
2388
  */
2376
2389
  const String$2 = /*#__PURE__*/ make$4((self, that) => self < that ? -1 : 1);
2390
+ /**
2391
+ * Order instance for numbers that compares them numerically.
2392
+ *
2393
+ * **When to use**
2394
+ *
2395
+ * Use when you need numeric ordering for numbers.
2396
+ *
2397
+ * **Details**
2398
+ *
2399
+ * `0` is considered equal to `-0`. All `NaN` values are considered equal to
2400
+ * each other, and any `NaN` is considered less than any non-`NaN` number. All
2401
+ * other values use standard numeric comparison.
2402
+ *
2403
+ * **Example** (Ordering numbers)
2404
+ *
2405
+ * ```ts import.meta.vitest
2406
+ * import { Order } from "effect"
2407
+ *
2408
+ * Order.Number(1, 1) // => 0
2409
+ * Order.Number(1, 2) // => -1
2410
+ * Order.Number(2, 1) // => 1
2411
+ *
2412
+ * Order.Number(0, -0) // => 0
2413
+ * Order.Number(NaN, 1) // => -1
2414
+ * ```
2415
+ *
2416
+ * @see {@link mapInput} to compare objects by a number property
2417
+ * @see {@link BigInt} for bigint comparisons
2418
+ * @stability stable
2419
+ * @category instances
2420
+ * @since 4.0.0
2421
+ */
2422
+ const Number$2 = /*#__PURE__*/ make$4((self, that) => {
2423
+ if (globalThis.Number.isNaN(self) && globalThis.Number.isNaN(that)) return 0;
2424
+ if (globalThis.Number.isNaN(self)) return -1;
2425
+ if (globalThis.Number.isNaN(that)) return 1;
2426
+ return self < that ? -1 : 1;
2427
+ });
2428
+ /**
2429
+ * Returns the maximum of two values according to the given order. If they are equal, returns the first argument.
2430
+ *
2431
+ * **When to use**
2432
+ *
2433
+ * Use when you need to select the larger of two values according to an
2434
+ * `Order`.
2435
+ *
2436
+ * **Details**
2437
+ *
2438
+ * Returns the value that compares as greater than or equal to the other value.
2439
+ * If values are equal, the first argument is returned.
2440
+ *
2441
+ * **Example** (Selecting the maximum value)
2442
+ *
2443
+ * ```ts import.meta.vitest
2444
+ * import { Order } from "effect"
2445
+ *
2446
+ * const maxNumber = Order.max(Order.Number)
2447
+ *
2448
+ * maxNumber(1, 2) // => 2
2449
+ * maxNumber(2, 1) // => 2
2450
+ * maxNumber(1, 1) // => 1
2451
+ * ```
2452
+ *
2453
+ * @see {@link min} for the minimum of two values
2454
+ * @see {@link clamp} to clamp a value between min and max
2455
+ * @stability stable
2456
+ * @category comparisons
2457
+ * @since 2.0.0
2458
+ */
2459
+ const max$1 = (O) => dual(2, (self, that) => self === that || O(self, that) > -1 ? self : that);
2377
2460
  // ../../node_modules/.pnpm/effect@4.1.2/node_modules/effect/dist/Option.js
2378
2461
  /**
2379
2462
  * Creates an `Option` representing the absence of a value.
@@ -4565,6 +4648,33 @@ const filter = /*#__PURE__*/ dual(2, (self, predicate) => {
4565
4648
  return out;
4566
4649
  });
4567
4650
  /**
4651
+ * Folds an iterable from left to right into a single value.
4652
+ *
4653
+ * **When to use**
4654
+ *
4655
+ * Use to combine all elements into one accumulated value from left to right.
4656
+ *
4657
+ * **Details**
4658
+ *
4659
+ * The function receives `(accumulator, element, index)`.
4660
+ *
4661
+ * **Example** (Summing an array)
4662
+ *
4663
+ * ```ts import.meta.vitest
4664
+ * import { Array } from "effect"
4665
+ *
4666
+ * Array.reduce([1, 2, 3], 0, (acc, n) => acc + n) // => 6
4667
+ * ```
4668
+ *
4669
+ * @see {@link reduceRight} — fold from right to left
4670
+ * @see {@link scan} — fold keeping intermediate values
4671
+ *
4672
+ * @stability stable
4673
+ * @category folding
4674
+ * @since 2.0.0
4675
+ */
4676
+ const reduce = /*#__PURE__*/ dual(3, (self, b, f) => fromIterable(self).reduce((b, a, i) => f(b, a, i), b));
4677
+ /**
4568
4678
  * Checks whether all elements satisfy the predicate. Supports refinements for
4569
4679
  * type narrowing.
4570
4680
  *
@@ -4832,6 +4942,28 @@ const TaggedError = TaggedError$1;
4832
4942
  */
4833
4943
  const Number$1 = globalThis.Number;
4834
4944
  /**
4945
+ * Returns the maximum between two `number`s.
4946
+ *
4947
+ * **When to use**
4948
+ *
4949
+ * Use to select the larger of two numbers.
4950
+ *
4951
+ * **Example** (Finding the maximum)
4952
+ *
4953
+ * ```ts import.meta.vitest
4954
+ * import { Number } from "effect"
4955
+ *
4956
+ * Number.max(2, 3) // => 3
4957
+ * ```
4958
+ *
4959
+ * @see {@link min} for selecting the smaller value
4960
+ *
4961
+ * @stability stable
4962
+ * @category math
4963
+ * @since 2.0.0
4964
+ */
4965
+ const max = /*#__PURE__*/ max$1(Number$2);
4966
+ /**
4835
4967
  * Parses a `number` from a `string` safely using the `Number()` function.
4836
4968
  * The following special string values are supported: "NaN", "Infinity", "-Infinity".
4837
4969
  *
@@ -4904,6 +5036,28 @@ const Order = String$2;
4904
5036
  */
4905
5037
  const toUpperCase = (self) => self.toUpperCase();
4906
5038
  /**
5039
+ * Replaces matches in a string using `String.prototype.replace`.
5040
+ *
5041
+ * **Details**
5042
+ *
5043
+ * String search values and non-global regular expressions replace the first
5044
+ * match; global regular expressions replace every match.
5045
+ *
5046
+ * **Example** (Replacing a substring)
5047
+ *
5048
+ * ```ts import.meta.vitest
5049
+ * import { pipe, String } from "effect"
5050
+ *
5051
+ * pipe("abc", String.replace("b", "d")) // => "adc"
5052
+ * pipe("hello world", String.replace("world", "Effect")) // => "hello Effect"
5053
+ * ```
5054
+ *
5055
+ * @stability stable
5056
+ * @category transforming
5057
+ * @since 2.0.0
5058
+ */
5059
+ const replace = (searchValue, replaceValue) => (self) => self.replace(searchValue, replaceValue);
5060
+ /**
4907
5061
  * Removes whitespace from both ends of a string.
4908
5062
  *
4909
5063
  * **Example** (Trimming whitespace)
@@ -7691,7 +7845,7 @@ const noFloatingDerivedType = defineRule({
7691
7845
  });
7692
7846
  // src/rules/no-gradient.ts
7693
7847
  const GRADIENT = /(?:^|[\s:])bg-(?:linear|radial|conic|gradient)(?:-|$|\s)|gradient\(/u;
7694
- function report$5(context, node) {
7848
+ function report$6(context, node) {
7695
7849
  context.report({
7696
7850
  message: "Use a flat theme token such as bg-card or bg-muted; gradients are never part of the design.",
7697
7851
  node
@@ -7700,10 +7854,10 @@ function report$5(context, node) {
7700
7854
  const noGradient = defineRule({
7701
7855
  create: (context) => ({
7702
7856
  Literal: (node) => {
7703
- if (isString(node.value) && GRADIENT.test(node.value)) report$5(context, node);
7857
+ if (isString(node.value) && GRADIENT.test(node.value)) report$6(context, node);
7704
7858
  },
7705
7859
  TemplateElement: (node) => {
7706
- if (GRADIENT.test(node.value.raw)) report$5(context, node);
7860
+ if (GRADIENT.test(node.value.raw)) report$6(context, node);
7707
7861
  }
7708
7862
  }),
7709
7863
  meta: { type: "problem" }
@@ -7791,7 +7945,7 @@ function replaceableGuard(node) {
7791
7945
  "typeof === undefined": "isUndefined"
7792
7946
  }, key)));
7793
7947
  }
7794
- function report$4(input) {
7948
+ function report$5(input) {
7795
7949
  map$1(replaceableGuard(input.node), (guard) => input.context.report({
7796
7950
  message: `Use Predicate.${guard} instead of this hand-written type guard.`,
7797
7951
  node: input.node
@@ -7800,19 +7954,19 @@ function report$4(input) {
7800
7954
  const noHandWrittenGuard = defineRule({
7801
7955
  create: (context) => ({
7802
7956
  ArrowFunctionExpression: (node) => {
7803
- report$4({
7957
+ report$5({
7804
7958
  context,
7805
7959
  node
7806
7960
  });
7807
7961
  },
7808
7962
  FunctionDeclaration: (node) => {
7809
- report$4({
7963
+ report$5({
7810
7964
  context,
7811
7965
  node
7812
7966
  });
7813
7967
  },
7814
7968
  FunctionExpression: (node) => {
7815
- report$4({
7969
+ report$5({
7816
7970
  context,
7817
7971
  node
7818
7972
  });
@@ -7863,14 +8017,14 @@ const PRIMITIVES = {
7863
8017
  textarea: "Textarea"
7864
8018
  };
7865
8019
  const CONTROL_STYLE = /(?:^|:)(?:hover|focus|focus-visible|active):|(?:^|:)(?:rounded|shadow|ring)(?:-|$)|(?:^|:)p[blrtxy]?-(?!0$)|(?:^|:)bg-(?!transparent$)|(?:^|:)border(?:-[blrtxy])?$|(?:^|:)border-(?!0$|[blrtxy]-0$)/u;
7866
- function classStrings(node) {
8020
+ function classStrings$1(node) {
7867
8021
  if (node.type === "Literal") return filter([node.value], isString);
7868
8022
  if (node.type === "TemplateLiteral") return map(node.quasis, (quasi) => quasi.value.raw);
7869
- if (node.type === "JSXExpressionContainer") return classStrings(node.expression);
7870
- if (node.type === "CallExpression") return flatMap(node.arguments, classStrings);
7871
- if (node.type === "ConditionalExpression") return flatMap([node.consequent, node.alternate], classStrings);
7872
- if (node.type === "LogicalExpression") return classStrings(node.right);
7873
- if (node.type === "ArrayExpression") return flatMap(filter(node.elements, isNotNull), classStrings);
8023
+ if (node.type === "JSXExpressionContainer") return classStrings$1(node.expression);
8024
+ if (node.type === "CallExpression") return flatMap(node.arguments, classStrings$1);
8025
+ if (node.type === "ConditionalExpression") return flatMap([node.consequent, node.alternate], classStrings$1);
8026
+ if (node.type === "LogicalExpression") return classStrings$1(node.right);
8027
+ if (node.type === "ArrayExpression") return flatMap(filter(node.elements, isNotNull), classStrings$1);
7874
8028
  return empty$2();
7875
8029
  }
7876
8030
  const noNativeControl = defineRule({
@@ -7880,7 +8034,7 @@ const noNativeControl = defineRule({
7880
8034
  map$1(get$3(PRIMITIVES, name), (primitive) => {
7881
8035
  const styled = pipe(node.attributes, findFirst((attribute) => attribute.type === "JSXAttribute" && attribute.name.type === "JSXIdentifier" && attribute.name.name === "className"), map$1((attribute) => {
7882
8036
  if (attribute.type !== "JSXAttribute" || attribute.value === null) return empty$2();
7883
- return classStrings(attribute.value);
8037
+ return classStrings$1(attribute.value);
7884
8038
  }), exists((values) => some(values, (value) => some(split(value, /\s+/u), matches(CONTROL_STYLE)))));
7885
8039
  if (name !== "select" && !styled) return;
7886
8040
  context.report({
@@ -8304,6 +8458,139 @@ const noPollingTest = defineRule({
8304
8458
  },
8305
8459
  meta: { type: "problem" }
8306
8460
  });
8461
+ // src/rules/no-primitive-restyle.ts
8462
+ const UI_MODULES = ["@deslop/components-web/ui/", "#components/ui/"];
8463
+ const PLACEMENT_PREFIXES = [
8464
+ "m-",
8465
+ "mx-",
8466
+ "my-",
8467
+ "mt-",
8468
+ "mr-",
8469
+ "mb-",
8470
+ "ml-",
8471
+ "ms-",
8472
+ "me-",
8473
+ "w-",
8474
+ "h-",
8475
+ "size-",
8476
+ "min-w-",
8477
+ "min-h-",
8478
+ "max-w-",
8479
+ "max-h-",
8480
+ "basis-",
8481
+ "order-",
8482
+ "col-span-",
8483
+ "col-start-",
8484
+ "col-end-",
8485
+ "row-span-",
8486
+ "row-start-",
8487
+ "row-end-",
8488
+ "self-",
8489
+ "justify-self-",
8490
+ "place-self-",
8491
+ "inset-",
8492
+ "inset-x-",
8493
+ "inset-y-",
8494
+ "top-",
8495
+ "right-",
8496
+ "bottom-",
8497
+ "left-",
8498
+ "start-",
8499
+ "end-",
8500
+ "z-",
8501
+ "translate-",
8502
+ "pointer-events-"
8503
+ ];
8504
+ const PLACEMENT_EXACT = [
8505
+ "flex-1",
8506
+ "flex-auto",
8507
+ "flex-none",
8508
+ "grow",
8509
+ "grow-0",
8510
+ "shrink",
8511
+ "shrink-0",
8512
+ "relative",
8513
+ "absolute",
8514
+ "fixed",
8515
+ "sticky",
8516
+ "hidden",
8517
+ "block",
8518
+ "flex",
8519
+ "inline-flex",
8520
+ "grid",
8521
+ "sr-only"
8522
+ ];
8523
+ const RESTYLE = "A shadcn component keeps its shipped look: className only places it (margin, size, position, flex or grid placement). Pick a variant or change the composition instead of restyling.";
8524
+ function uiImport(program) {
8525
+ return flatMap(program.body, (statement) => {
8526
+ if (statement.type !== "ImportDeclaration") return empty$2();
8527
+ if (!some(UI_MODULES, (prefix) => startsWith(prefix)(statement.source.value))) return empty$2();
8528
+ return map(statement.specifiers, (specifier) => specifier.local.name);
8529
+ });
8530
+ }
8531
+ function classStrings(node) {
8532
+ if (node.type === "Literal") return filter([node.value], isString);
8533
+ if (node.type === "TemplateLiteral") return map(node.quasis, (quasi) => quasi.value.raw);
8534
+ if (node.type === "JSXExpressionContainer") return classStrings(node.expression);
8535
+ if (node.type === "CallExpression" && node.callee.type === "Identifier" && node.callee.name === "cn") return flatMap(node.arguments, (argument) => classStrings(argument));
8536
+ return empty$2();
8537
+ }
8538
+ function utility(token) {
8539
+ const scanned = reduce(split("")(token), {
8540
+ depth: 0,
8541
+ end: 0,
8542
+ index: 0
8543
+ }, (state, character) => {
8544
+ const index = state.index + 1;
8545
+ if (character === "[") return {
8546
+ depth: state.depth + 1,
8547
+ end: state.end,
8548
+ index
8549
+ };
8550
+ if (character === "]") return {
8551
+ depth: max(0, state.depth - 1),
8552
+ end: state.end,
8553
+ index
8554
+ };
8555
+ if (character === ":" && state.depth === 0) return {
8556
+ depth: state.depth,
8557
+ end: index,
8558
+ index
8559
+ };
8560
+ return {
8561
+ depth: state.depth,
8562
+ end: state.end,
8563
+ index
8564
+ };
8565
+ });
8566
+ return pipe(token, slice(scanned.end), replaceAll(/^!|!$/gu, ""), replace(/^-/u, ""));
8567
+ }
8568
+ function places(token) {
8569
+ const name = utility(token);
8570
+ return contains(PLACEMENT_EXACT, name) || some(PLACEMENT_PREFIXES, (prefix) => startsWith(prefix)(name));
8571
+ }
8572
+ function restyled(attribute) {
8573
+ if (attribute.value === null) return false;
8574
+ return pipe(classStrings(attribute.value), flatMap((value) => split(value, /\s+/u)), filter(isNonEmpty), some((token) => !places(token)));
8575
+ }
8576
+ const noPrimitiveRestyle = defineRule({
8577
+ create: (context) => {
8578
+ const file = { primitives: empty$2() };
8579
+ return {
8580
+ JSXOpeningElement: (node) => {
8581
+ if (node.name.type !== "JSXIdentifier" || !contains(file.primitives, node.name.name)) return;
8582
+ pipe(findFirst(node.attributes, (attribute) => attribute.type === "JSXAttribute" && attribute.name.type === "JSXIdentifier" && attribute.name.name === "className"), filter$1((attribute) => attribute.type === "JSXAttribute" && restyled(attribute)), map$1((attribute) => context.report({
8583
+ message: RESTYLE,
8584
+ node: attribute
8585
+ })));
8586
+ },
8587
+ Program: (node) => {
8588
+ file.primitives = uiImport(node);
8589
+ }
8590
+ };
8591
+ },
8592
+ meta: { type: "problem" }
8593
+ });
8307
8594
  // src/rules/no-property-alias.ts
8308
8595
  const FUNCTIONS = [
8309
8596
  "ArrowFunctionExpression",
@@ -8400,7 +8687,7 @@ function replacement(input) {
8400
8687
  if (input.read.parent?.type === "Property" && input.read.parent.shorthand) return `${input.name}: ${input.text}`;
8401
8688
  return input.text;
8402
8689
  }
8403
- function report$3(input) {
8690
+ function report$4(input) {
8404
8691
  const reads = pipe(input.variable.references, filter((reference) => reference.isRead()), map((reference) => reference.identifier));
8405
8692
  const text = input.context.sourceCode.getText(input.init);
8406
8693
  const aliasRequired = needsAlias({
@@ -8479,7 +8766,7 @@ const noPropertyAlias = defineRule({
8479
8766
  scope: context.sourceCode.getScope(candidate.node)
8480
8767
  }), match$2({
8481
8768
  onNone: constVoid,
8482
- onSome: (variable) => report$3({
8769
+ onSome: (variable) => report$4({
8483
8770
  ...candidate,
8484
8771
  context,
8485
8772
  variable,
@@ -8675,7 +8962,7 @@ const shipped = [
8675
8962
  schema: "Natural"
8676
8963
  }
8677
8964
  ];
8678
- function schemaMember$1(input) {
8965
+ function schemaMember$2(input) {
8679
8966
  if (input.node.type !== "MemberExpression" || !importedMember({
8680
8967
  context: input.context,
8681
8968
  importedName: "Schema",
@@ -8685,11 +8972,11 @@ function schemaMember$1(input) {
8685
8972
  }
8686
8973
  function shippedSchema(input) {
8687
8974
  if (input.filter.type !== "CallExpression") return none();
8688
- const base = schemaMember$1({
8975
+ const base = schemaMember$2({
8689
8976
  context: input.context,
8690
8977
  node: input.base
8691
8978
  });
8692
- const check = schemaMember$1({
8979
+ const check = schemaMember$2({
8693
8980
  context: input.context,
8694
8981
  node: input.filter.callee
8695
8982
  });
@@ -8712,7 +8999,7 @@ function reinventedSchema(input) {
8712
8999
  if (input.node.callee.type !== "MemberExpression" || !contains$1(memberName(input.node.callee), "check")) return none();
8713
9000
  const callee = input.node.callee;
8714
9001
  const [filter] = input.node.arguments;
8715
- if (isSome(schemaMember$1({
9002
+ if (isSome(schemaMember$2({
8716
9003
  context: input.context,
8717
9004
  node: callee
8718
9005
  }))) {
@@ -9275,7 +9562,7 @@ function executes(context, node) {
9275
9562
  function receiver(read) {
9276
9563
  return read.parent?.type === "MemberExpression" && read.parent.object === read && read.parent.parent.type === "CallExpression" && read.parent.parent.callee === read.parent;
9277
9564
  }
9278
- function report$2(input) {
9565
+ function report$3(input) {
9279
9566
  const declaration = input.node.parent;
9280
9567
  const init = input.node.init;
9281
9568
  if (declaration.type !== "VariableDeclaration" || declaration.parent.type !== "BlockStatement" || input.node.id.type !== "Identifier" || init === null) return;
@@ -9332,7 +9619,7 @@ const noSingleUseValue = defineRule({
9332
9619
  NewExpression: effect,
9333
9620
  "Program:exit": () => {
9334
9621
  const nodes = toArray(effects);
9335
- for (const node of toArray(candidates)) report$2({
9622
+ for (const node of toArray(candidates)) report$3({
9336
9623
  context,
9337
9624
  effects: nodes,
9338
9625
  node
@@ -9639,7 +9926,7 @@ const noTestTimeout = defineRule({
9639
9926
  meta: { type: "problem" }
9640
9927
  });
9641
9928
  // src/rules/no-type-from-value.ts
9642
- function schemaMember(name) {
9929
+ function schemaMember$1(name) {
9643
9930
  return name.type === "TSQualifiedName" && contains([
9644
9931
  "Encoded",
9645
9932
  "Type",
@@ -9652,7 +9939,7 @@ function schemaMember(name) {
9652
9939
  function valueQuery(node) {
9653
9940
  if (node.type === "TSParenthesizedType") return valueQuery(node.typeAnnotation);
9654
9941
  if (node.type === "TSIndexedAccessType") return valueQuery(node.objectType);
9655
- return node.type === "TSTypeQuery" && (node.exprName.type === "Identifier" || node.exprName.type === "TSQualifiedName" && !schemaMember(node.exprName));
9942
+ return node.type === "TSTypeQuery" && (node.exprName.type === "Identifier" || node.exprName.type === "TSQualifiedName" && !schemaMember$1(node.exprName));
9656
9943
  }
9657
9944
  function nestedObject(node) {
9658
9945
  return node.parent?.type === "TSIndexedAccessType" && node.parent.objectType === node;
@@ -10001,7 +10288,7 @@ function fix(input) {
10001
10288
  return some$1([input.fixer.replaceTextRange([open.range[0], close.range[1]], "(cause)"), insertion]);
10002
10289
  }), () => []);
10003
10290
  }
10004
- function report$1(context, node) {
10291
+ function report$2(context, node) {
10005
10292
  context.report({
10006
10293
  fix: (fixer) => fix({
10007
10294
  context,
@@ -10014,7 +10301,7 @@ function report$1(context, node) {
10014
10301
  }
10015
10302
  function reportOption(context, key, bare, options) {
10016
10303
  if (options?.type !== "ObjectExpression") return;
10017
- for (const property of options.properties) if (property.type === "Property" && property.key.type === "Identifier" && property.key.name === key && dropsCause(context, property.value, bare)) report$1(context, property.value);
10304
+ for (const property of options.properties) if (property.type === "Property" && property.key.type === "Identifier" && property.key.name === key && dropsCause(context, property.value, bare)) report$2(context, property.value);
10018
10305
  }
10019
10306
  const preserveErrorCause = defineRule({
10020
10307
  create: (context) => ({ CallExpression: (node) => {
@@ -10024,7 +10311,7 @@ const preserveErrorCause = defineRule({
10024
10311
  });
10025
10312
  if (contains$1(name, "mapError")) {
10026
10313
  const bare = detailedFailure(context, node);
10027
- forEach(filter(node.arguments, (argument) => dropsCause(context, argument, bare)), (callback) => report$1(context, callback));
10314
+ forEach(filter(node.arguments, (argument) => dropsCause(context, argument, bare)), (callback) => report$2(context, callback));
10028
10315
  return;
10029
10316
  }
10030
10317
  if (contains$1(name, "mapBoth")) {
@@ -10275,6 +10562,125 @@ const schemaTypePair = defineRule({
10275
10562
  type: "problem"
10276
10563
  }
10277
10564
  });
10565
+ // src/rules/service-schema-file.ts
10566
+ const SERVICE_PATH = /[/\\]src[/\\]services[/\\][^/\\]+[/\\]/u;
10567
+ const SCHEMA_FILE = /[/\\]schema\.ts$/u;
10568
+ const SCHEMA_CLASSES = [
10569
+ "Class",
10570
+ "TaggedClass",
10571
+ "TaggedError",
10572
+ "TaggedRequest"
10573
+ ];
10574
+ const DERIVED = matches(/^(?:is|to)[A-Z]/u);
10575
+ const FILTER = matches(/^makeFilter(?:Group)?$/u);
10576
+ function schemaMember(input) {
10577
+ if (input.node.type === "CallExpression" && input.node.callee.type !== "Super") return schemaMember({
10578
+ context: input.context,
10579
+ node: input.node.callee
10580
+ });
10581
+ if (input.node.type === "ChainExpression") return schemaMember({
10582
+ context: input.context,
10583
+ node: input.node.expression
10584
+ });
10585
+ if (input.node.type === "TSInstantiationExpression") return schemaMember({
10586
+ context: input.context,
10587
+ node: input.node.expression
10588
+ });
10589
+ if (input.node.type === "TSSatisfiesExpression") return schemaMember({
10590
+ context: input.context,
10591
+ node: input.node.expression
10592
+ });
10593
+ if (input.node.type === "MemberExpression") {
10594
+ if (input.node.object.type === "Identifier") return some$1(input.node);
10595
+ if (input.node.object.type !== "Super") return schemaMember({
10596
+ context: input.context,
10597
+ node: input.node.object
10598
+ });
10599
+ }
10600
+ return none();
10601
+ }
10602
+ function constructorMember(input) {
10603
+ return importedMember({
10604
+ context: input.context,
10605
+ importedName: "Schema",
10606
+ node: input.node
10607
+ }) && pipe(memberName(input.node), exists((name) => !isSchemaOperationName(name) && !DERIVED(name) && !FILTER(name)));
10608
+ }
10609
+ function definesSchema(input) {
10610
+ if (input.node.type === "CallExpression" && input.node.callee.type === "Identifier" && isImportBinding({
10611
+ context: input.context,
10612
+ importedName: "pipe",
10613
+ node: input.node.callee,
10614
+ source: "effect"
10615
+ })) {
10616
+ const [first] = input.node.arguments;
10617
+ return first !== void 0 && first.type !== "SpreadElement" && definesSchema({
10618
+ ...input,
10619
+ node: first
10620
+ });
10621
+ }
10622
+ return pipe(schemaMember(input), exists((member) => constructorMember({
10623
+ context: input.context,
10624
+ node: member
10625
+ })));
10626
+ }
10627
+ function schemaClass(input) {
10628
+ if (input.node.type === "CallExpression" && input.node.callee.type !== "Super") return schemaClass({
10629
+ context: input.context,
10630
+ node: input.node.callee
10631
+ });
10632
+ if (input.node.type === "TSInstantiationExpression") return schemaClass({
10633
+ context: input.context,
10634
+ node: input.node.expression
10635
+ });
10636
+ if (input.node.type === "MemberExpression" && input.node.object.type === "Identifier" && importedMember({
10637
+ context: input.context,
10638
+ importedName: "Schema",
10639
+ node: input.node
10640
+ })) return pipe(memberName(input.node), exists((name) => contains(SCHEMA_CLASSES, name)));
10641
+ return false;
10642
+ }
10643
+ function extendsSchema(input) {
10644
+ return input.node.superClass !== null && schemaClass({
10645
+ context: input.context,
10646
+ node: input.node.superClass
10647
+ });
10648
+ }
10649
+ function report$1(context, node) {
10650
+ context.report({
10651
+ message: "Move this schema into the service's schema.ts and import it.",
10652
+ node
10653
+ });
10654
+ }
10655
+ function exported(statement) {
10656
+ if (statement.type === "ExportDefaultDeclaration") return statement.declaration;
10657
+ return statementDeclaration(statement);
10658
+ }
10659
+ function definitions(context, declaration) {
10660
+ if (declaration?.type === "VariableDeclaration" && declaration.kind === "const") return flatMap(declaration.declarations, (variable) => {
10661
+ if (variable.init === null) return empty$2();
10662
+ if (variable.init.type === "ClassExpression") return filter([variable.init], (node) => extendsSchema({
10663
+ context,
10664
+ node
10665
+ }));
10666
+ return filter([variable.init], (node) => definesSchema({
10667
+ context,
10668
+ node
10669
+ }));
10670
+ });
10671
+ if (declaration?.type === "ClassDeclaration" || declaration?.type === "ClassExpression") return filter([declaration], (node) => extendsSchema({
10672
+ context,
10673
+ node
10674
+ }));
10675
+ return empty$2();
10676
+ }
10677
+ const serviceSchemaFile = defineRule({
10678
+ create: (context) => ({ Program: (program) => {
10679
+ if (!SERVICE_PATH.test(context.filename) || SCHEMA_FILE.test(context.filename) || isTestFile(context)) return;
10680
+ for (const node of flatMap(program.body, (statement) => definitions(context, exported(statement)))) report$1(context, node);
10681
+ } }),
10682
+ meta: { type: "problem" }
10683
+ });
10278
10684
  // src/rules/swiftui-theme-values.ts
10279
10685
  const PAINTS = [
10280
10686
  "background",
@@ -10409,6 +10815,7 @@ const RULES = {
10409
10815
  "no-option-value-access": noOptionValueAccess,
10410
10816
  "no-pipe-method": noPipeMethod,
10411
10817
  "no-polling-test": noPollingTest,
10818
+ "no-primitive-restyle": noPrimitiveRestyle,
10412
10819
  "no-property-alias": noPropertyAlias,
10413
10820
  "no-redundant-state-type": noRedundantStateType,
10414
10821
  "no-redundant-use-ref-null-type": noRedundantUseRefNullType,
@@ -10435,6 +10842,7 @@ const RULES = {
10435
10842
  "preserve-error-cause": preserveErrorCause,
10436
10843
  "require-unicode-regexp": requireUnicodeRegexp,
10437
10844
  "schema-type-pair": schemaTypePair,
10845
+ "service-schema-file": serviceSchemaFile,
10438
10846
  "swiftui-theme-values": swiftuiThemeValues
10439
10847
  };
10440
10848
  const lint = {
@@ -11315,7 +11723,10 @@ const lint = {
11315
11723
  "typescript/no-confusing-void-expression": ["error", { ignoreVoidReturningFunctions: true }],
11316
11724
  "typescript/no-deprecated": "error",
11317
11725
  "typescript/no-duplicate-type-constituents": "error",
11318
- "typescript/no-floating-promises": "error",
11726
+ "typescript/no-floating-promises": ["error", { allowForKnownSafeCalls: [{
11727
+ from: "file",
11728
+ name: "navigate"
11729
+ }] }],
11319
11730
  "typescript/no-for-in-array": "error",
11320
11731
  "typescript/no-generated-empty-object-type": "error",
11321
11732
  "typescript/no-misused-promises": ["error", { checksVoidReturn: { attributes: false } }],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deslop/coding-standards",
3
- "version": "0.1.1249",
3
+ "version": "0.1.1252",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/MP281X/deslop.git",