All files single-spa-react.js

90.7% Statements 39/43
84.62% Branches 33/39
100% Functions 11/11
90.48% Lines 38/42

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 1101x                         12x 1x     11x         11x 2x     9x 1x     8x 1x     7x               7x       7x 7x   7x 1x     6x 6x   6x 6x 1x           2x     2x   2x       2x         8x 8x       8x       2x 2x 2x 2x                   9x 9x 2x 7x 1x   6x      
const defaultOpts = {
  // required opts
  React: null,
  ReactDOM: null,
  rootComponent: null,
  domElementGetter: null,
  suppressComponentDidCatchWarning: false,
 
  // optional opts
  domElementGetter: null, // only can be omitted if provided as a custom prop
}
 
export default function singleSpaReact(userOpts) {
  if (typeof userOpts !== 'object') {
    throw new Error(`single-spa-react requires a configuration object`);
  }
 
  const opts = {
    ...defaultOpts,
    ...userOpts,
  };
 
  if (!opts.React) {
    throw new Error(`single-spa-react must be passed opts.React`);
  }
 
  if (!opts.ReactDOM) {
    throw new Error(`single-spa-react must be passed opts.ReactDOM`);
  }
 
  if (!opts.rootComponent) {
    throw new Error(`single-spa-react must be passed opts.rootComponent`);
  }
 
  return {
    bootstrap: bootstrap.bind(null, opts),
    mount: mount.bind(null, opts),
    unmount: unmount.bind(null, opts),
  };
}
 
function bootstrap(opts) {
  return Promise.resolve();
}
 
function mount(opts, props) {
  return new Promise((resolve, reject) => {
    const domElementGetter = chooseDomElementGetter(opts, props)
 
    if (!domElementGetter) {
      throw new Error(`Cannot mount react application '${props.appName || props.name}' without a domElementGetter provided in either opts or props`)
    }
 
    const whenFinished = function() {
      resolve(this);
    };
    const renderedComponent = opts.ReactDOM.render(opts.React.createElement(opts.rootComponent, props), getRootDomEl(domElementGetter), whenFinished);
    if (!renderedComponent.componentDidCatch && !opts.suppressComponentDidCatchWarning && atLeastReact16(opts.React)) {
      console.warn(`single-spa-react: ${props.name || props.appName || props.childAppName}'s rootComponent should implement componentDidCatch to avoid accidentally unmounting the entire single-spa application.`);
    }
  })
}
 
function unmount(opts, props) {
  return Promise
    .resolve()
    .then(() => {
      const domElementGetter = chooseDomElementGetter(opts, props)
 
      Iif (!domElementGetter) {
        throw new Error(`Cannot unmount react application '${props.appName || props.name}' without a domElementGetter provided in either opts or props`)
      }
 
      opts.ReactDOM.unmountComponentAtNode(getRootDomEl(domElementGetter));
    })
}
 
function getRootDomEl(domElementGetter) {
  const el = domElementGetter();
  Iif (!el) {
    throw new Error(`single-spa-react: domElementGetter function did not return a valid dom element`);
  }
 
  return el;
}
 
function atLeastReact16(React) {
  Eif (React && typeof React.version === 'string' && React.version.indexOf('.') >= 0) {
    const majorVersionString = React.version.slice(0, React.version.indexOf('.'));
    try {
      return Number(majorVersionString) >= 16;
    } catch(err) {
      return false;
    }
  } else {
    return false;
  }
}
 
function chooseDomElementGetter(opts, props) {
  const customProps = props && props.customProps ? props.customProps : {}
  if (customProps.domElement) {
    return () => props.customProps.domElement
  } else if (customProps.domElementGetter) {
    return props.customProps.domElementGetter
  } else {
    return opts.domElementGetter
  }
}