# all files / src/ streamReaders.js

100% Statements 44/44
80% Branches 24/30
100% Functions 6/6
100% Lines 39/39

    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
    1124×

    4×

    1×
    3×
    3×
    2×

    1×
    30×
    30×

    1×
    80×
    80×
    80×
    80×
    79×
    79×
    79×

    79×
    43×
    1×
    42×
    1×
    1×

    41×

    43×

    79×

    1×
    15×
    15×
    15×

    15×

    10×
    10×
    10×

    1×
    42×
    42×
    41×

     import {CommentToken, CharsToken, StartTagToken,
        AtomicTagToken, EndTagToken} from './tokens';

    /**
     * Regular Expressions for parsing tags and attributes
     *
     * @type {Object}
     */
    const REGEXES = {
      startTag: /^<([\-A-Za-z0-9_!:]+)((?:\s+[\w\-]+(?:\s*=?\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,
      endTag: /^<\/([\-A-Za-z0-9_:]+)[^>]*>/,
      attr: /(?:([\-A-Za-z0-9_]+)\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))|(?:([\-A-Za-z0-9_]+)(\s|$)+)/g,
      fillAttr: /^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noresize|noshade|nowrap|readonly|selected)$/i
    };

    /**
     * Reads a comment token
     *
     * @param {string} stream The input stream
     * @returns {CommentToken}
     */
    export function comment(stream) {
      const index = stream.indexOf('-->');
      if (index >= 0) {
        return new CommentToken(stream.substr(4, index - 1), index + 3);
      }
    }

    /**
     * Reads non-tag characters.
     *
     * @param {string} stream The input stream
     * @returns {CharsToken}
     */
    export function chars(stream) {
      const index = stream.indexOf('<');
      return new CharsToken(index >= 0 ? index : stream.length);
    }

    /**
     * Reads start tag token.
     *
     * @param {string} stream The input stream
     * @returns {StartTagToken}
     */
    export function startTag(stream) {
      const endTagIndex = stream.indexOf('>');
      Eif (endTagIndex !== -1) {
        const match = stream.match(REGEXES.startTag);
        if (match) {
          const attrs = {};
          const booleanAttrs = {};
          let rest = match[2];

          match[2].replace(REGEXES.attr, function(match, name) {
            if (!(arguments[2] || arguments[3] || arguments[4] || arguments[5])) {
              attrs[name] = '';
            } else if (arguments[5]) {
              attrs[arguments[5]] = '';
              booleanAttrs[arguments[5]] = true;
            } else {
              attrs[name] = arguments[2] || arguments[3] || arguments[4] ||
                REGEXES.fillAttr.test(name) && name || '';
            }

            rest = rest.replace(match, '');
          });

          return new StartTagToken(match[1], match[0].length, attrs,
            booleanAttrs, !!match[3],
            rest.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''));
        }
      }
    }

    /**
     * Reads atomic tag token.
     *
     * @param {string} stream The input stream
     * @returns {AtomicTagToken}
     */
    export function atomicTag(stream) {
      const start = startTag(stream);
      Eif (start) {
        const rest = stream.slice(start.length);
        // for optimization, we check first just for the end tag
        if (rest.match(new RegExp('<\/\\s*' + start.tagName + '\\s*>', 'i'))) {
          // capturing the content is inefficient, so we do it inside the if
          const match = rest.match(new RegExp('([\\s\\S]*?)<\/\\s*' + start.tagName + '\\s*>', 'i'));
          Eif (match) {
            return new AtomicTagToken(start.tagName,
              match[0].length + start.length,
              start.attrs, start.booleanAttrs, match[1]);
          }
        }
      }
    }

    /**
     * Reads an end tag token.
     *
     * @param {string} stream The input stream
     * @returns {EndTagToken}
     */
    export function endTag(stream) {
      const match = stream.match(REGEXES.endTag);
      if (match) {
        return new EndTagToken(match[1], match[0].length);
      }
    }