# All files stringifier.js

93.22% Statements 55/59
78.57% Branches 33/42
100% Functions 12/12
94.34% Lines 50/53

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
    1152x

    2x

    9x

    78x

    9x
    9x

    8x
    8x
    8x

    8x
    6x
    6x

    6x
    1x

    6x

    2x
    2x

    31x
    31x

    31x
    2x

    31x

    24x

    6x
    6x

    6x
    6x

    6x

    36x

    36x
    69x

    69x
    69x
    3x

    69x
    69x

    30x
    30x
    30x

    69x
    69x
    47x
    47x

    69x

    52x

    60x
    60x
    60x
    2x

    58x

     const DEFAULT_RAWS = {
      colon: ': ',
      indent: '  ',
      commentLeft: ' ',
      commentRight: ' '
    }

    module.exports = class Stringifier {
      constructor(builder) {
        this.builder = builder
      }

      stringify(node, semicolon) {
        this[node.type](node, semicolon)
      }

      root(node) {
        this.body(node)
        if (node.raws.after) this.builder(node.raws.after)
      }

      comment(node) {
        let left = DEFAULT_RAWS.commentLeft
        let right = DEFAULT_RAWS.commentRight
        Eif (this.has(node.raws.left)) left = node.raws.left

        if (node.raws.inline) {
          Eif (this.has(node.raws.inlineRight)) {
            right = node.raws.inlineRight
          } else {
            right = ''
          }
          if (node.raws.extraIndent) {
            this.builder(node.raws.extraIndent)
          }
          this.builder('//' + left + node.text + right, node)
        } else {
          Iif (this.has(node.raws.right)) right = node.raws.right
          this.builder('/*' + left + node.text + right + '*/', node)
        }
      }

      decl(node) {
        let between = node.raws.between || DEFAULT_RAWS.colon
        let string = node.prop + between + this.rawValue(node, 'value')

        if (node.important) {
          string += node.raws.important || ' !important'
        }

        this.builder(string, node)
      }

      rule(node) {
        this.block(node, this.rawValue(node, 'selector'))
      }

      atrule(node) {
        let name = '@' + node.name
        let params = node.params ? this.rawValue(node, 'params') : ''

        Eif (this.has(node.raws.afterName)) {
          name += node.raws.afterName
        } else if (params) {
          name += ' '
        }

        this.block(node, name + params)
      }

      body(node) {
        let indent = node.root().raws.indent || DEFAULT_RAWS.indent

        for (let i = 0; i < node.nodes.length; i++) {
          let child = node.nodes[i]
          let before =
            child.raws.before.replace(/[^\n]*$/, '') + this.indent(node, indent)
          if (child.type === 'comment' && !child.raws.before.includes('\n')) {
            before = child.raws.before
          }
          if (before) this.builder(before)
          this.stringify(child)
        }
      }

      block(node, start) {
        let between = node.raws.sssBetween || ''
        this.builder(start + between, node, 'start')
        if (this.has(node.nodes)) this.body(node)
      }

      indent(node, step) {
        let result = ''
        while (node.parent) {
          result += step
          node = node.parent
        }
        return result
      }

      has(value) {
        return typeof value !== 'undefined'
      }

      rawValue(node, prop) {
        let value = node[prop]
        let raw = node.raws[prop]
        if (raw && raw.value === value) {
          return raw.sss || raw.raw
        } else {
          return value
        }
      }
    }