# All files / lib/node create.js

98.31% Statements 117/119
94.44% Branches 17/18
100% Functions 1/1
98.31% Lines 117/119

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
    119
    1202x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    637x
    637x
    5x
    5x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    283x
    283x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    295x
    295x
    295x
    1x
    1x
    637x
    637x
    637x
    637x
    637x

    637x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    637x
    348x
    133x
    133x
    348x
    348x
    1x
    1x
    348x
    348x
    8x
    8x
    206x
    206x
    206x
    206x
    348x
    348x
    348x
    8x
    8x
    8x
    8x
    348x
    349x
    349x
    349x
    349x
    349x
    349x
    637x
    73x
    73x
    73x
    73x
    73x
    73x
    349x
    349x
    637x
     import process from '../util/process';
    import globalThis from '../util/global';
    import {
      NodeCache,
      CreateNodeHookCache,
      VTreeLike,
      VTree,
      ValidNode,
      EMPTY,
    } from '../util/types';
    import createTree from '../tree/create';

    const namespace = 'http://www.w3.org/2000/svg';

    /**
     * Takes in a Virtual Tree Element (VTree) and creates a DOM Node from it.
     * Sets the node into the Node cache. If this VTree already has an
     * associated node, it will reuse that.
     *
     * @param {VTreeLike} vTreeLike - A Virtual Tree Element or VTree-like element
     * @param {Document=} ownerDocument - Document to create Nodes in, defaults to document
     * @param {Boolean=} isSVG - Indicates if the root element is SVG
     * @return {ValidNode | null} A DOM Node matching the vTree
     */
    export default function createNode(vTreeLike, ownerDocument = globalThis.document, isSVG) {
      if (process.env.NODE_ENV !== 'production') {
        if (!vTreeLike) {
          throw new Error('Missing VTree when trying to create DOM Node');
        }
      }

      const vTree = createTree(vTreeLike);
      const existingNode = NodeCache.get(vTree);

      // If the DOM Node was already created, reuse the existing node. This is
      // required to ensure that passed in DOM Nodes are preserved, and to ensure
      // that elements are not constantly created with the same VTree instance.
      if (existingNode) {
        return existingNode;
      }

      const {
        nodeName,
        rawNodeName = nodeName,
        childNodes = /** @type {VTree[]} */ ([]),
      } = vTree;

      isSVG = isSVG || nodeName === 'svg';

      /** @type {ValidNode | null} */
      let domNodeCheck = null;

      /** @type {ValidNode | null | void} */
      let retVal = null;

      CreateNodeHookCache.forEach((fn) => {
        // Invoke all the `createNodeHook` functions passing along the vTree as the
        // only argument. These functions must return a valid DOM Node value.
        if (retVal = fn(vTree)) {
          domNodeCheck = retVal;
        }
      });

      // It is not possible to continue if this object is falsy. By returning null,
      // patching can gracefully no-op.
      if (!ownerDocument) {
        return domNodeCheck;
      }

      /**
       * If no DOM Node was provided by CreateNode hooks, we must create it
       * ourselves.
       *
       * @type {ValidNode | null}
       */
      let domNode = domNodeCheck;

      // Create empty text elements. They will get filled in during the patch
      // process.
      if (!domNode) {
        if (nodeName === '#text') {
          domNode = ownerDocument.createTextNode(vTree.nodeValue || EMPTY.STR);
        }
        // Support dynamically creating document fragments.
        else if (nodeName === '#document-fragment') {
          domNode = ownerDocument.createDocumentFragment();
        }
        // Support SVG.
        else if (isSVG) {
          domNode = ownerDocument.createElementNS(namespace, rawNodeName);
        }
        // If not a Text or SVG Node, then create with the standard method.
        else {
          domNode = ownerDocument.createElement(rawNodeName);
        }

        // Do not execute scripts by default.
        if (nodeName === 'script') {
          // Set the type to 'no-execute'. This will be toggled after patching,
          // unless disabled by the consumer.
          /** @type {any} */(domNode).type = 'no-execute';
        }
      }

      // Add to the domNodes cache.
      NodeCache.set(vTree, domNode);

      // Append all the children into the domNode, making sure to run them
      // through this `createNode` function as well.
      for (let i = 0; i < childNodes.length; i++) {
        const validChildNode = createNode(childNodes[i], ownerDocument, isSVG);

        if (domNode && validChildNode) {
          domNode.appendChild(validChildNode);
        }
      }

      return domNode;
    }