All files parsers.js

100% Statements 62/62
100% Branches 51/51
100% Functions 5/5
100% Lines 53/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 115 116 117 118      215x 215x 409x                     1x   1x 108x           108x           1x 109x   108x 108x 108x   108x   56x 381x 381x 381x 381x     56x   55x           1x 108x   107x 107x 107x 107x     107x 107x 6x 6x     101x 835x 835x 835x 835x     101x   100x   100x 20x 20x   20x 11x 11x 11x         106x   106x           1x 108x   106x   106x 50x           56x     1x  
'use strict'
 
function skipws (str) {
  let i = 0
  do {
    if (str[i] !== ' ' && str[i] !== '\t') { return i }
  } while (++i < str.length)
  // When not trimming, `str` will always end with a newline, and when
  //  trimming, will end with end-of-string, so this `return` is not
  //  really needed
  /* istanbul ignore next */
  return i
}
 
/* ------- default parsers ------- */
 
const PARSERS = {}
 
PARSERS.parse_tag = function parse_tag (str) {
  const result = str.match(/^\s*@(\S+)/)
 
  // If there is no at-sign or not followed by non-whitespace, won't get here
  /* istanbul ignore next */
  if (!result) { throw new Error('Invalid `@tag`, missing @ symbol') }
 
  return {
    source: result[0],
    data: { tag: result[1] }
  }
}
 
PARSERS.parse_type = function parse_type (str, data) {
  if (data.errors && data.errors.length) { return null }
 
  let pos = skipws(str)
  let res = ''
  let curlies = 0
 
  if (str[pos] !== '{') { return null }
 
  while (pos < str.length) {
    curlies += (str[pos] === '{' ? 1 : (str[pos] === '}' ? -1 : 0))
    res += str[pos]
    pos++
    if (curlies === 0) { break }
  }
 
  if (curlies !== 0) { throw new Error('Invalid `{type}`, unpaired curlies') }
 
  return {
    source: str.slice(0, pos),
    data: { type: res.slice(1, -1) }
  }
}
 
PARSERS.parse_name = function parse_name (str, data) {
  if (data.errors && data.errors.length) { return null }
 
  let pos = skipws(str)
  let name = ''
  let brackets = 0
  let res = { optional: false }
 
  // if it starts with quoted group assume it is a literal
  const quotedGroups = str.slice(pos).split('"')
  if (quotedGroups.length > 1 && quotedGroups[0] === '' && quotedGroups.length % 2 === 1) {
    name = quotedGroups[1]
    pos += name.length + 2
  // assume name is non-space string or anything wrapped into brackets
  } else {
    while (pos < str.length) {
      brackets += (str[pos] === '[' ? 1 : (str[pos] === ']' ? -1 : 0))
      name += str[pos]
      pos++
      if (brackets === 0 && /\s/.test(str[pos])) { break }
    }
 
    if (brackets !== 0) { throw new Error('Invalid `name`, unpaired brackets') }
 
    res = { name: name, optional: false }
 
    if (name[0] === '[' && name[name.length - 1] === ']') {
      res.optional = true
      name = name.slice(1, -1)
 
      if (name.indexOf('=') !== -1) {
        const parts = name.split('=')
        name = parts[0]
        res.default = parts[1].replace(/^(["'])(.+)(\1)$/, '$2')
      }
    }
  }
 
  res.name = name
 
  return {
    source: str.slice(0, pos),
    data: res
  }
}
 
PARSERS.parse_description = function parse_description (str, data) {
  if (data.errors && data.errors.length) { return null }
 
  const result = str.match(/^\s+((.|\s)+)?/)
 
  if (result) {
    return {
      source: result[0],
      data: { description: result[1] === undefined ? '' : result[1] }
    }
  }
 
  return null
}
 
module.exports = PARSERS