All files / src/libraries component.tsx

85.25% Statements 52/61
72.22% Branches 26/36
85.71% Functions 6/7
86.96% Lines 40/46

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 120 121 122 123 124  4x 4x   4x               25x 25x   59x             59x 59x     59x               59x         59x 59x       59x     9x         9x 9x   9x   9x                             25x     25x   25x 25x 21x 17x 17x                 28x 28x 25x 25x 25x     28x 26x 12x     4x       11x 11x   11x 8x     11x                 4x  
/* eslint-disable @typescript-eslint/no-use-before-define */
import React from "react";
import { connect, error, warn } from "frontity";
import { Connect } from "frontity/types";
import parse from "./parse";
import Html2ReactType, {
  Component,
  HandleNodes,
  HandleNode,
  ApplyProcessors,
} from "../../types";
 
const applyProcessors: ApplyProcessors = ({ node, processors, ...payload }) => {
  for (const proc of processors) {
    // Add deprecation warning for process.
    Iif ((proc as any).process)
      warn(
        `The property 'process' has been deprecated.
Please use the new 'processor' property instead and check the documentation to see the additional changes of the new API:
https://docs.frontity.org/api-reference-1/frontity-html2react#create-your-own-processors`
      );
 
    const processor = proc.processor || (proc as any).process;
    let isMatch = false;
 
    // Check if test and processor are set.
    Iif (!proc.test || !processor)
      error(
        `The processor ${
          name || "(missing name)"
        } needs both a "test" and a "processor" properties.`
      );
 
    // Test processor.
    try {
      /**
       * Run the tester passing node and params merged for backward
       * compatibility.
       */
      const params = { node, ...payload };
      isMatch = proc.test({ ...node, ...params });
    } catch (e) {
      console.warn(e);
    }
    if (!isMatch) continue;
 
    // Apply processor.
    try {
      /**
       * Run the processor passing node and params merged, and payload as
       * a second argument for backward compatibility.
       */
      const params = { node, ...payload };
      const processed = processor({ ...node, ...params }, payload);
      // Return true if node was removed.
      Iif (!processed) return true;
      // Merge the nodes if the processor has applied changes.
      Iif (node !== processed) {
        /**
         * Remove props merged before process, just in case someone
         * has used the spread operator in a processor.
         */
        Object.keys(params).forEach((key) => delete processed[key]);
        // Assign returned props.
        Object.assign(node, processed);
      }
    } catch (e) {
      console.error(e);
    }
  }
 
  // Return false if node was not removed.
  return false;
};
 
const handleNode: HandleNode = ({ node, index, ...payload }) => {
  // `applyProcessors` returns true if node was removed.
  Iif (applyProcessors({ node, ...payload })) return null;
  if (node.type === "comment") return null;
  if (node.type === "text") return node.content;
  Eif (node.type === "element")
    return (
      <node.component {...{ key: index, ...node.props }}>
        {node.children
          ? handleNodes({ nodes: node.children, ...payload })
          : null}
      </node.component>
    );
};
 
const handleNodes: HandleNodes = ({ nodes, ...payload }) => {
  const handled = nodes.reduce((final: React.ReactNodeArray, node, index) => {
    const handledNode = handleNode({ node, index, ...payload });
    if (handledNode) final.push(handledNode);
    return final;
  }, []);
 
  if (handled.length > 1) return handled;
  if (handled.length === 1) return handled[0];
  return null;
};
 
export const Html2React: Component<Connect<
  Html2ReactType,
  { html: string }
>> = ({ html, state, libraries }) => {
  const { processors } = libraries.html2react;
  const root = parse(html);
 
  libraries.html2react.processors = processors.sort(
    (a, b) => (a.priority || 10) - (b.priority || 10)
  );
 
  return handleNodes({
    nodes: root,
    state,
    libraries,
    root,
    processors,
  }) as React.ReactElement;
};
 
export default connect(Html2React);