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

23.07% Statements 15/65
18.75% Branches 6/32
66.66% Functions 2/3
23.52% Lines 12/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

    21x
    105x

    524x
    524x

    524x

    524x
    248x
    248x
    248x

    282x
    282x

    21x
     // 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.
      Iif (maxPos - startPos < 2) return false;
      Eif (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.
      if (SYNTAX_CODES[3] !== state.src.charCodeAt(pointer.pos++)) return false;
      if (!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();
      if (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];
        if (nextLineMaxPos > nextLineStartPos) return false;
      }

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

      if (!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;