Passed
Push — main ( 4c1518...bb24f5 )
by Andrii
01:58
created

ctx.ts ➔ classNamer   B

Complexity

Conditions 7

Size

Total Lines 59
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 45
dl 0
loc 59
rs 7.4
c 0
b 0
f 0
cc 7

How to fix   Long Method   

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:

1
import type { Falsy, ToggleMap, ClassValue, ClassNamer, ClassNamed, ClassNamesMap, EmptyObject } from "./defs"
2
import { emptize, stringifyClassNamed, truthyKeys } from "./utils"
3
4
emptize(classNamer)
5
6
//TODO no `className` - no first `true`
7
interface tClassNaming<
8
  ClassKeys extends string,
9
  withClassNames extends boolean | undefined
10
> {
11
  /**
12
   * @example classes(true) === props.className
13
   * @example classes({class1: true, class2: false}) === "class1"
14
   * @example classes("class3", false && "class4") === "class3"
15
   * @example classes(true, {class1: true, class2: false}, "class3", false && "class4") === `${props.className} class1 class3`
16
  */
17
 // Using overloads will make error not in certain argument but on all call - 'No overload found'
18
  (
19
    propagate_or_map_or_expression?: true | ToggleMap<ClassKeys> | ClassKeys | Falsy,
20
    map_or_expression?: (
21
      [Extract<typeof propagate_or_map_or_expression, true>] extends [never]
22
      ? never
23
      : ToggleMap<ClassKeys>
24
    ) | ClassKeys | Falsy,
25
    ...expressions: (ClassKeys | Falsy)[]
26
  ) : ClassNamed & (
27
    withClassNames extends true
28
    ? {classNames: ClassNamesMap<ClassKeys>}
29
    : EmptyObject
30
  ) 
31
}
32
33
export default classNamingCtx
34
35
/**
36
 * @example const classes = classNamingCtx(this.props)
37
 * @example const classes = classNamingCtx({className, classNames})
38
 * @example const classes = classNamingCtx({classNames})
39
 */
40
function classNamingCtx<
41
  ClassKeys extends string,
42
  withClassNames extends boolean|undefined
43
>(
44
  {classNames, className}: ClassNamer<ClassKeys>,
45
  options?: ClassNamerOptions<withClassNames>
46
) {
47
  return classNamer.bind({classNames, className, ...options}) as tClassNaming<ClassKeys, withClassNames>
48
}
49
50
type ClassNamerOptions<
51
  withClassNames extends undefined|boolean
52
> = Partial<{
53
  withClassNames: withClassNames
54
  // withSelf: boolean
55
}>
56
57
function classNamer<
58
  ClassKeys extends string,
59
  withClassNames extends boolean|undefined
60
>(
61
  this: Partial<ClassNamer<ClassKeys> & ClassNamerOptions<withClassNames>>,
62
  arg0?: true | ToggleMap<ClassKeys> | ClassKeys,
63
  arg1?: ToggleMap<ClassKeys> | ClassKeys,
64
  ...args: (ClassKeys | Falsy)[]
65
): ClassNamed & Partial<Pick<typeof this, "classNames">> {
66
  const {
67
    className: _propagated,
68
    classNames,
69
    withClassNames,
70
    // withSelf
71
  } = this
72
  , withPropagation = arg0 === true
73
  , allowed: ClassKeys[] = truthyKeys(arg0 === true ? false : arg0)
74
  .concat(truthyKeys(arg1))
75
  //@ts-expect-error
76
  .concat(args)
77
  .filter<ClassKeys>(
78
    //@ts-expect-error
79
    Boolean
80
  )
81
  
82
  emptize(classNames)
83
84
  for (let i = allowed.length; i--;) {
85
    const key = allowed[i]
86
    , hash: ClassValue = classNames?.[key]
87
    
88
    if (hash !== undefined)
89
      //@ts-expect-error
90
      allowed[i] = hash
91
  }
92
  
93
  const allowedString = allowed.join(" ")
94
  , propagated = withPropagation && _propagated || ""
95
  
96
  //TODO Consider undefined|empty|never for type error
97
  , className = `${
98
    propagated
99
  }${
100
    propagated && allowedString
101
    ? " "
102
    : ""
103
  }${
104
    allowedString
105
  }`
106
  
107
  if (!withClassNames) {
108
    return stringifyClassNamed({
109
      className
110
    })
111
  } else {
112
    return stringifyClassNamed({
113
      className,
114
      classNames
115
    })
116
  }
117
}