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
    }
  }
}