# All files / src/lib/markdown-it/plugins/markdown-it-block-embed tokenizer.js

86.15% Statements 56/65
75% Branches 24/32
100% Functions 3/3
94.11% Lines 48/51

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

    17x
    85x

    40x
    40x
    40x

    40x

    39x
    39x

    39x
    39x
    39x
    39x

    560x
    560x

    560x

    560x
    281x
    281x
    281x

    298x
    297x

    22x
    21x

    20x

    20x

    20x
    20x

    19x
    19x

    19x

    19x

    19x
    19x

    19x

    19x
    3x
    3x
    3x

    19x

    19x
    19x
    19x
    19x
    19x

    19x

    19x

    19x

    17x
     // Copyright (c) Rotorz Limited and portions by original markdown-it-video authors
    // Licensed under the MIT license. See LICENSE file in the project root.

    "use strict";

    const SYNTAX_CHARS = "@[]()".split("");
    const SYNTAX_CODES = SYNTAX_CHARS.map(char => char.charCodeAt(0));

    function advanceToSymbol(state, endLine, symbol, pointer) {
      let maxPos = null;
      let symbolLine = pointer.line;
      let symbolIndex = state.src.indexOf(symbol, pointer.pos);

      if (symbolIndex === -1) return false;

      maxPos = state.eMarks[pointer.line];
      while (symbolIndex >= maxPos) {
        ++symbolLine;
        maxPos = state.eMarks[symbolLine];

        if (symbolLine >= endLine) return false;
      }

      pointer.prevPos = pointer.pos;
      pointer.pos = symbolIndex;
      pointer.line = symbolLine;
      return true;
    }

    function tokenizer(state, startLine, endLine, silent) {
      let startPos = state.bMarks[startLine] + state.tShift[startLine];
      let maxPos = state.eMarks[startLine];

      let pointer = { line: startLine, pos: startPos };

      // Block embed must be at start of input or the previous line must be blank.
      if (startLine !== 0) {
        let prevLineStartPos = state.bMarks[startLine - 1] + state.tShift[startLine - 1];
        let prevLineMaxPos = state.eMarks[startLine - 1];
        if (prevLineMaxPos > prevLineStartPos) return false;
      }

      // Identify as being a potential block embed.
      if (maxPos - startPos < 2) return false;
      if (SYNTAX_CODES[0] !== state.src.charCodeAt(pointer.pos++)) return false;

      // Read service name from within square brackets.
      if (SYNTAX_CODES[1] !== state.src.charCodeAt(pointer.pos++)) return false;
      if (!advanceToSymbol(state, endLine, "]", pointer)) return false;

      let serviceName = state.src
        .substr(pointer.prevPos, pointer.pos - pointer.prevPos)
        .trim()
        .toLowerCase();

      ++pointer.pos;

      // Lookup service; if unknown, then this is not a known embed!
      let service = this.services[serviceName];
      if (!service) return false;

      // Read embed reference from within parenthesis.
      Iif (SYNTAX_CODES[3] !== state.src.charCodeAt(pointer.pos++)) return false;
      Iif (!advanceToSymbol(state, endLine, ")", pointer)) return false;

      let videoReference = state.src
        .substr(pointer.prevPos, pointer.pos - pointer.prevPos)
        .trim();

      ++pointer.pos;

      // Do not recognize as block element when there is trailing text.
      maxPos = state.eMarks[pointer.line];
      let trailingText = state.src
        .substr(pointer.pos, maxPos - pointer.pos)
        .trim();
      Iif (trailingText !== "") return false;

      // Block embed must be at end of input or the next line must be blank.
      if (endLine !== pointer.line + 1) {
        let nextLineStartPos = state.bMarks[pointer.line + 1] + state.tShift[pointer.line + 1];
        let nextLineMaxPos = state.eMarks[pointer.line + 1];
        Iif (nextLineMaxPos > nextLineStartPos) return false;
      }

      Iif (pointer.line >= endLine) return false;

      Eif (!silent) {
        let token = state.push("video", "div", 0);
        token.markup = state.src.slice(startPos, pointer.pos);
        token.block = true;
        token.info = {
          serviceName: serviceName,
          service: service,
          videoReference: videoReference,
          videoID: service.extractVideoID(videoReference)
        };
        token.map = [ startLine, pointer.line + 1 ];

        state.line = pointer.line + 1;
      }

      return true;
    }

    module.exports = tokenizer;