All files index.ts

100% Statements 53/53
100% Branches 24/24
100% Functions 7/7
100% Lines 50/50

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120                    6x     3x     6x       34x 1x     33x       7x 2x 1x   1x       5x 5x   5x       25x   25x 13x 3x   10x       12x 12x   12x       11x       24x   22x   22x 40x 40x   40x 17x 17x     23x 21x 25x 19x       2x       20x       39x   39x 59x 59x   59x 37x 37x     22x 21x 38x 29x       1x       38x       6x  
type QBemConditionalKeys =
  | string
  | {
      [key: string]: boolean
    }
 
type ClassesInput = QBemConditionalKeys[]
type BlockModifiers = QBemConditionalKeys[] | undefined | null
 
const QBEM_ERROR_MODIFIER_TYPE_VIOLATION =
  'QBem: modifier type violation => modifiers must be strings or objects!'
 
function throModifierTypeViolationError() {
  throw new Error(QBEM_ERROR_MODIFIER_TYPE_VIOLATION)
}
 
export class QBem {
  private _b: string
 
  constructor(block: string) {
    if (!block) {
      throw new Error('qbem: block name undefined')
    }
 
    this._b = block
  }
 
  public block(modifiers?: BlockModifiers, ...classes: ClassesInput): string {
    if (!modifiers) {
      if (!classes.length) {
        return this._b
      } else {
        return `${this._b} ${QBem.classes(...classes)}`
      }
    }
 
    const outputModifiers = QBem.modifiers(this._b, ...modifiers)
    const outputClasses = QBem.classes(...classes)
 
    return [this._b, outputModifiers, outputClasses].filter(Boolean).join(' ')
  }
 
  public element(element: string, modifiers?: BlockModifiers, ...classes: ClassesInput): string {
    const base = `${this._b}__${element}`
 
    if (!modifiers) {
      if (!classes.length) {
        return base
      } else {
        return `${base} ${QBem.classes(...classes)}`
      }
    }
 
    const outputModifiers = QBem.modifiers(base, ...modifiers)
    const outputClasses = QBem.classes(...classes)
 
    return [base, outputModifiers, outputClasses].filter(Boolean).join(' ')
  }
 
  public elem(element: string, modifiers?: BlockModifiers, ...classes: ClassesInput): string {
    return this.element(element, modifiers, ...classes)
  }
 
  public static modifiers(base: string, ...modifiers: QBemConditionalKeys[]) {
    if (!modifiers.length) return base
 
    let modified = ''
 
    for (let i = 0; i < modifiers.length; i++) {
      const currModifier = modifiers[i]
      const modifierType = typeof currModifier
 
      if (modifierType === 'string') {
        modified += modified ? ` ${base}--${currModifier}` : `${base}--${currModifier}`
        continue
      }
 
      if (modifierType === 'object') {
        for (const [key, value] of Object.entries(currModifier)) {
          if (value === true) {
            modified += modified ? ` ${base}--${key}` : `${base}--${key}`
          }
        }
      } else {
        throModifierTypeViolationError()
      }
    }
 
    return modified.trim()
  }
 
  public static classes(...classes: ClassesInput) {
    let classnames = ''
 
    for (let i = 0; i < classes.length; i++) {
      const currClass = classes[i]
      const modifierType = typeof currClass
 
      if (modifierType === 'string') {
        classnames += classnames ? ` ${currClass}` : currClass
        continue
      }
 
      if (modifierType === 'object') {
        for (const [key, value] of Object.entries(currClass)) {
          if (value === true) {
            classnames += classnames ? ` ${key}` : key
          }
        }
      } else {
        throModifierTypeViolationError()
      }
    }
 
    return classnames
  }
}
 
export default QBem