Passed
Push — main ( cafa69...3c9e73 )
by Andrii
02:00
created

ctx.ts ➔ classNamingCtx   B

Complexity

Conditions 5

Size

Total Lines 57
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 39
dl 0
loc 57
rs 8.4773
c 0
b 0
f 0

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 { ClassNamingContext, ClassNamed, ClassNamesMap, ClassHash } from "./defs"
2
import {joinWithLead, resolver, wrapper} from "./core"
3
import { emptize } from "./utils"
4
5
const stackedKey = Symbol("stacked")
6
7
emptize(classNamingCtx)
8
9
/**
10
 * Makes `className` string from imported CSS
11
 * @example <div className={`${classNamingBasic({ClassName})}`} />
12
 * @example <div {...classNamingBasic({ClassName})} />
13
 * @example const cn = classNamingBasic({C1})({C2}); <div {...cn({C3})({C4})} />
14
 */
15
interface ClassNamingCall<
16
  //TODO `extends ReactRelated`
17
  Source extends ClassNamesMap
18
> {
19
/**
20
   * @example classes(true) === props.className
21
   * @example classes({class1: true, class2: false}) === "class1"
22
   * @example classes(true, {class1: true, class2: false})
23
  */
24
  (
25
    arg0?: ClassNamingContext<Source> | true | string | ActionsMap<Source>,
26
    arg1?: [Extract<typeof arg0, true|string>] extends [never]
27
    ? never 
28
    : ActionsMap<Source>
29
  ): ClassNaming<Source>
30
  // Using overloads will make error not in certain argument but on all call - 'No overload found'
31
  // (propagateClassName: true): ClassNaming<Source>
32
  // (expression: ToggleMap<Source>): ClassNaming<Source>
33
  // (propagateClassName: true, expression: ToggleMap<Source>): ClassNaming<Source>
34
}
35
36
//TODO no `className` - no first `true`
37
interface ClassNaming<Source extends ClassNamesMap> extends ClassNamed, ClassNamingCall<Source> {}
38
39
type ClassNamingThis<Source extends ClassNamesMap> = ClassNamingContext<Source> & {
40
  //TODO change to Symbol
41
  [stackedKey]: string|undefined
42
}
43
44
type ActionsMap<K extends ClassNamesMap> = {[k in keyof K]?: ClassHash|boolean}
45
// type SubMap<K extends ClassNamesMap> = {[k in keyof K]?: ClassHash}
46
// type ToggleMap<K extends ClassNamesMap> = {[k in keyof K]?: boolean}
47
48
export default classNamingCtx
49
50
/**
51
 * @example const classes = classNamingCtx(this.props)
52
 * @example const classes = classNamingCtx({className, classnames})
53
 * @example const classes = classNamingCtx({classnames})
54
 */
55
56
function classNamingCtx<
57
  //TODO `extends ReactRelated`
58
  Source extends ClassNamesMap
59
>(
60
  this: void | ClassNamingThis<Source>,
61
  // arg0?: typeof this extends void ? ClassNamingContext<Source> : (true | ToggleMap<Source>),
62
  // arg1?: typeof this extends void ? never : typeof arg0 extends true ? ToggleMap<Source> : never,
63
  arg0?: ClassNamingContext<Source> | (string | true | ActionsMap<Source>),
64
  arg1?: [Extract<typeof arg0, true|string>] extends [never] ? never : ActionsMap<Source>
65
): ClassNaming<Source> {
66
  // istanbul ignore next //TODO Solve TS tricks with context
67
  const thisArg = this || {}
68
  
69
  context_assign:
70
  if (
71
    !(stackedKey in thisArg)
72
    && typeof arg0 === "object"
73
  ) {
74
    const {classnames, className} = arg0 // as ClassNamingContext<Source>
75
    if (
76
      classnames !== null && typeof classnames === "object"
77
      && (
78
        className === undefined  || typeof className === "string" 
79
      )  
80
    ) {
81
      emptize(classnames)
82
      const host: ClassNamingCall<Source> = classNamingCtx.bind({classnames, className, [stackedKey]: undefined}) 
83
84
      return wrapper(host, className)
85
    }
86
  }
87
88
  const {
89
    className,
90
    classnames,
91
    [stackedKey]: preStacked,
92
  } = thisArg as ClassNamingThis<Source>
93
  , withPropagation = arg0 === true  
94
  , source = typeof arg0 === "object" ? arg0 as ActionsMap<Source>: arg1
95
  , allowed = source && resolver(classnames, source)
96
  , withInjection = typeof arg0 !== "string" ? preStacked : joinWithLead(preStacked, arg0)
97
  , stacked = joinWithLead(withInjection, allowed)
98
  , result = joinWithLead(withPropagation && className, stacked)
99
  , host: ClassNamingCall<Source> = classNamingCtx.bind({classnames, className, [stackedKey]: stacked})
100
101
  classnames && emptize(classnames)
102
103
  return wrapper(
104
    host,
105
    result,
106
  )
107
}   
108
109