@deslop/coding-standards 0.1.1248 → 0.1.1250

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 +301 -10
  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)
@@ -6909,8 +7063,8 @@ function amount(token, pattern) {
6909
7063
  function violation(token) {
6910
7064
  const name = pipe(token, split(":"), last, getOrElse(() => token), replaceAll(/^!|!$/gu, ""));
6911
7065
  if (exists(amount(name, /^duration-(\d+)$/u), (value) => value >= 300)) return some$1("Keep a tween under 300 ms, such as duration-200.");
6912
- if (matches(/^zoom-(?:in|out)$/u)(name) || exists(amount(name, /^zoom-(?:in|out)-(\d+)$/u), (value) => value < 90)) return some$1("Enter from 0.9 scale or more: zoom-in-90 or zoom-in-95.");
6913
- if (pipe(token, split(":"), dropRight(1), contains("starting")) && exists(amount(name, /^scale-(\d+)$/u), (value) => value < 90)) return some$1("Enter from 0.9 scale or more: starting:scale-90 or starting:scale-95.");
7066
+ if (matches(/^zoom-(?:in|out)$/u)(name) || exists(amount(name, /^zoom-(?:in|out)-(\d+)$/u), (value) => value < 90)) return some$1("Enter from 0.95 scale with opacity: zoom-in-95.");
7067
+ if (pipe(token, split(":"), dropRight(1), contains("starting")) && exists(amount(name, /^scale-(\d+)$/u), (value) => value < 90)) return some$1("Enter from 0.95 scale with opacity: starting:scale-95.");
6914
7068
  return none();
6915
7069
  }
6916
7070
  function check$2(context, node, text) {
@@ -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",
@@ -10409,6 +10696,7 @@ const RULES = {
10409
10696
  "no-option-value-access": noOptionValueAccess,
10410
10697
  "no-pipe-method": noPipeMethod,
10411
10698
  "no-polling-test": noPollingTest,
10699
+ "no-primitive-restyle": noPrimitiveRestyle,
10412
10700
  "no-property-alias": noPropertyAlias,
10413
10701
  "no-redundant-state-type": noRedundantStateType,
10414
10702
  "no-redundant-use-ref-null-type": noRedundantUseRefNullType,
@@ -11315,7 +11603,10 @@ const lint = {
11315
11603
  "typescript/no-confusing-void-expression": ["error", { ignoreVoidReturningFunctions: true }],
11316
11604
  "typescript/no-deprecated": "error",
11317
11605
  "typescript/no-duplicate-type-constituents": "error",
11318
- "typescript/no-floating-promises": "error",
11606
+ "typescript/no-floating-promises": ["error", { allowForKnownSafeCalls: [{
11607
+ from: "file",
11608
+ name: "navigate"
11609
+ }] }],
11319
11610
  "typescript/no-for-in-array": "error",
11320
11611
  "typescript/no-generated-empty-object-type": "error",
11321
11612
  "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.1248",
3
+ "version": "0.1.1250",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/MP281X/deslop.git",