Passed
Push — main ( 1ee933...792997 )
by Andrii
02:37
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
eloc 68
dl 0
loc 79
rs 4.8272
c 0
b 0
f 0
cc 11

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