Passed
Push — main ( b7e3d1...276544 )
by Andrii
01:56
created

double-shape.ts ➔ _doubleShape   D

Complexity

Conditions 11

Size

Total Lines 79
Code Lines 68

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 68
dl 0
loc 79
rs 4.8272
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like double-shape.ts ➔ _doubleShape often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import { ClassValue, Falsy } from "../defs"
2
3
type ClassNamesDirect<K extends string = string> = Record<K, ClassValue>
4
// type ClassNamesToggle<K extends string = string> = Record<K, boolean>
5
6
type ClassNamingContext<S extends string, U extends string> = {
7
  className?: undefined|string
8
  classnames: ClassNamesDirect<S>
9
  applied?: Record<U, ClassValue|boolean>[]
10
}
11
12
export {
13
  _doubleShape
14
}
15
16
function _doubleShape<
17
  // A extends {[K in Exclude<S, U>]?: boolean} | {[K in Exclude<S, U>]?: ClassValue},
18
  A extends {[K in Exclude<S, U>]?: ClassValue | boolean},
19
  S extends string,
20
  U extends string = never,
21
>(
22
  ctx: ClassNamingContext<S, U>,
23
  withClassName: boolean,
24
  injection: undefined|string,
25
  ...args: (Falsy | A)[]
26
) {
27
  const {applied, classnames, className} = ctx  
28
  //@ts-expect-error
29
  , nextApplied = !applied ? [] : applied.push(...args.filter(Boolean)) as Record<U | keyof A, ClassValue|boolean>[] 
30
31
  , host = <
32
      // T extends {[K in Exclude<S, U | keyof A>]?: boolean} | {[K in Exclude<S, U | keyof A>]?: ClassValue}
33
      T extends {[K in Exclude<S, U>]?: ClassValue | boolean},
34
    >(
35
    withClassName: boolean,
36
    injection: undefined|string,  
37
    ...args: (Falsy | T)[]
38
  ) => _doubleShape(
39
    {classnames, className, applied: nextApplied},
40
    withClassName,
41
    injection,
42
    ...args
43
  )
44
45
  for (let i = args.length; i--; ) {
46
    const arg = args[i]
47
    if (!arg) {
48
      delete args[i]
49
      continue
50
    }
51
52
    const keys = Object.keys(arg) as (keyof typeof arg)[]
53
    for (let i = keys.length; i--;) {
54
      const key = keys[i]
55
      , v = arg[key]
56
57
      switch (v) {
58
        case undefined:
59
          break
60
        case false:
61
          delete keys[i]
62
          break
63
        case true:
64
          //@ts-expect-error
65
          keys[i] = classnames?.[key as unknown as S] ?? key
66
          break
67
        default:
68
          if (typeof v === "string")
69
            //@ts-expect-error
70
            keys[i] = v
71
      }
72
    }  
73
    
74
    const chunk = keys.flat().join(" ")
75
    if (!chunk)
76
      delete args[i]
77
    else
78
      //@ts-expect-error
79
      args[i] = chunk
80
  }
81
82
  const calced = [
83
    withClassName && className,
84
    injection,
85
    args.flat().join(" ")
86
  ].filter(Boolean)
87
  .join(" ")
88
89
  host["className"] = calced
90
91
  Object.defineProperty(host, Symbol.toPrimitive, {value: () => calced})
92
93
  return host
94
}