# 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