Home Manual Reference Source Test

src/main.js

// import React, { createElement, } from 'react';
import React from 'react';
import ReactDOM from 'react-dom';
import ReactDOMServer from 'react-dom/server';
import useGlobalHook from 'use-global-hook';

import * as jsonxComponents from './components';
import * as jsonxProps from './props';
import * as jsonxChildren from './children';
import * as jsonxUtils from './utils';
const createElement = React.createElement;
const { componentMap, getComponentFromMap, getBoundedComponents, DynamicComponent, } = jsonxComponents;
const { getComputedProps, } = jsonxProps;
const { getJSONXChildren, } = jsonxChildren;
const { displayComponent, } = jsonxUtils;
export let renderIndex = 0;

/**
 * Use JSONX without any configuration to render JSONX JSON to HTML and insert JSONX into querySelector using ReactDOM.render
 * @example
 * // Uses react to create <!DOCTYPE html><body><div id="myApp"><div class="jsonx-generated"><p style="color:red;">hello world</p></div></div></body>
 * jsonx.jsonxRender({ jsonx: { component: 'div', props:{className:'jsonx-generated',children:[{ component:'p',props:{style:{color:'red'}}, children:'hello world' }]}}, querySelector:'#myApp', });
 * @param {object} config - options used to inject html via ReactDOM.render
 * @param {object} config.jsonx - any valid JSONX JSON object
 * @param {object} config.resources - any additional resource used for asynchronous properties
 * @param {string} config.querySelector - selector for document.querySelector
 * @property {object} this - options for getReactElementFromJSONX
 */
export function jsonxRender(config = {}) {
  const { jsonx, resources, querySelector, options, DOM, portal, } = config;
  const Render = portal ? ReactDOM.createPortal : ReactDOM.render;
  Render(
    getReactElementFromJSONX.call(this || {}, jsonx, resources, options),
    DOM || document.querySelector(querySelector)
  );
}

/**
 * Use ReactDOMServer.renderToString to render html from JSONX
 * @example
 * // Uses react to create <div class="jsonx-generated"><p style="color:red;">hello world</p></div>
 * jsonx.outputHTML({ jsonx: { component: 'div', props:{className:'jsonx-generated',children:[{ component:'p',props:{style:{color:'red'}}, children:'hello world' }]}}, });
 * @param {object} config - options used to inject html via ReactDOM.render
 * @param {object} config.jsonx - any valid JSONX JSON object
 * @param {object} config.resources - any additional resource used for asynchronous properties
 * @property {object} this - options for getReactElementFromJSONX
 * @returns {string} React genereated html via JSONX JSON
 */
export function outputHTML(config = {}) {
  const { jsonx, resources, } = config;
  
  return (this && this.useJSON)
    ? ReactDOMServer.renderToString(getReactElementFromJSON.call(this || {}, jsonx, resources))
    : ReactDOMServer.renderToString(getReactElementFromJSONX.call(this || {}, jsonx, resources));
}

/**
 * Use React.createElement and JSONX JSON to create React elements
 * @example
 * // Uses react to create the equivalent JSX <myComponent style={{color:blue}}>hello world</myComponent>
 * jsonx.getReactElementFromJSONX({component:'myCompnent',props:{style:{color:'blue'}},children:'hello world'})
 * @param {object} jsonx - any valid JSONX JSON object
 * @param {object} resources - any additional resource used for asynchronous properties
 * @property {object} this - options for getReactElementFromJSONX
 * @property {Object} [this.componentLibraries] - react components to render with JSONX
 * @property {boolean} [this.debug=false] - use debug messages
 * @property {boolean} [this.returnJSON=false] - return json object of {type,props,children} instead of react element
 * @property {boolean} [this.disableRenderIndexKey=false] - disables auto assign a key prop
 * @property {function} [this.logError=console.error] - error logging function
 * @property {string[]} [this.boundedComponents=[]] - list of components that require a bound this context (usefult for redux router)
 * @returns {function} React element via React.createElement
 */
export function getReactElementFromJSONX(jsonx = {}, resources = {}) {
  // eslint-disable-next-line
  const { componentLibraries = {}, debug = false, returnJSON=false, logError = console.error, boundedComponents = [], disableRenderIndexKey = true, } = this || {};
  // const componentLibraries = this.componentLibraries;
  if (!jsonx) return null;
  if (jsonx.type) jsonx.component = jsonx.type;
  if (jsonxUtils.validSimpleJSONXSyntax(jsonx)) jsonx = jsonxUtils.simpleJSONXSyntax(jsonx);
  if (!jsonx.component) return createElement('span', {}, debug ? 'Error: Missing Component Object' : '');
  try {
    const components = Object.assign({ DynamicComponent: DynamicComponent.bind(this), }, componentMap, this.reactComponents);

    const reactComponents = (boundedComponents.length)
      ? getBoundedComponents.call(this, { boundedComponents, reactComponents: components, })
      : components;
    renderIndex++;
    const element = getComponentFromMap({ jsonx, reactComponents, componentLibraries, debug, logError, });
    const props = getComputedProps.call(this, { jsonx, resources, renderIndex, componentLibraries, debug, logError, disableRenderIndexKey, });
    const displayElement = (jsonx.comparisonprops)
      ? displayComponent.call(this, { jsonx, props, renderIndex, componentLibraries, debug, })
      : true;
    if (displayElement) {
      const children = getJSONXChildren.call(this, { jsonx, props, resources, renderIndex, });
      if (returnJSON) return { type:element, props, children, };
      return createElement(element, props, children);
    } else {
      return null;
    }
  } catch (e) {
    if (debug) {
      logError({ jsonx, resources, }, 'this', this);
      logError(e, (e.stack) ? e.stack : 'no stack');
    }
    throw e;
  }
}

export const getRenderedJSON = getReactElementFromJSONX;
export const getReactElement = getReactElementFromJSONX;

/** converts a json object {type,props,children} into a react element 
 * @example
 * jsonx.getReactElementFromJSON({type:'div',props:{title:'some title attribute'},children:'inner html text'})
 * @param {Object|String} options.type - 'div' or react component
 * @param {Object} options.props - props for react element
 * @param {String|[Object]} options.children - children elements
 * @returns {function} React element via React.createElement
*/
export function getReactElementFromJSON({ type, props, children, }) {
  return createElement(type, props, Array.isArray(children)
    ? children.map(getReactElementFromJSON)
    : children);
}

/** converts a jsonx json object into a react function component 
 * @example
 * jsonx.compile({jsonx:{component:'div',props:{title:'some title attribute'},children:'inner html text'}}) //=>React Function Component
 * @param {Object} jsonx - valid JSONX JSON
 * @param {Object} resources - props for react element
 * @returns {function} React element via React.createElement
*/
export function compile(jsonx, resources) {
  const context = Object.assign({}, this, { returnJSON: true, });
  const json = getReactElementFromJSONX.call(context, jsonx, resources);
  const func = function compiledJSONX(props) {
    json.props = Object.assign({}, json.props, props);
    return getReactElementFromJSON(json);
  };
  Object.defineProperty(func, 'name', { value: this.name, });
  return func;
}

/**
 * converts JSONX JSON IR to JSX
 * @example
 * jsonx.jsonToJSX({ type: 'div', props: { key: 5, title: 'test' }, children: 'hello' }) // => '<div key={5} title="test">hello</div>'
 * @param {Object} json - {type,props,children}
 * @returns {String} jsx string
 */
export function outputJSX(jsonx, resources) {
  const context = Object.assign({}, this, { returnJSON: true, });
  const json = getReactElementFromJSONX.call(context, jsonx, resources);
  return jsonToJSX(json);
}

/**
 * Compiles JSONX into JSON IR format for react create element
 * @example
 * jsonx.outputJSON({ component: 'div', props: { title: 'test', }, children: 'hello', }); //=> { type: 'div',
 props: { key: 5, title: 'test' },
 children: 'hello' }
 * @property {object} this - options for getReactElementFromJSONX
 * @param {object} jsonx - any valid JSONX JSON object
 * @param {object} resources - any additional resource used for asynchronous properties
 * @returns {Object} json - {type,props,children}
 */
export function outputJSON(jsonx, resources) {
  const context = Object.assign({}, this, { returnJSON: true, });
  return getReactElementFromJSONX.call(context, jsonx, resources);
}
export const jsonxHTMLString = outputHTML;

/**
 * converts JSONX JSON IR to JSX
 * @example
 * jsonx.jsonToJSX({ type: 'div', props: { key: 5, title: 'test' }, children: 'hello' }) // => '<div key={5} title="test">hello</div>'
 * @param {Object} json - {type,props,children}
 * @returns {String} jsx string
 */
export function jsonToJSX(json) {
  const propsString = json.props
    ? Object.keys(json.props)
      .filter(prop => prop.includes('__eval_') === false)
      .reduce((propString, prop) => {
        propString += ` ${prop.toString()}=${
          typeof json.props[ prop ] === 'string'
            ? `"${json.props[ prop ].toString()}"`
            : `{${(json.props[ `__eval_${prop}` ]||json.props[ prop ]).toString()}}`
        }`;
        return propString;
      }, '')
    : '';
  return Array.isArray(json.children)
    ? `<${json.type} ${propsString}>
  ${json.children.map(jsonToJSX)}
</${json.type}>`
    : `<${json.type}${propsString}>${json.children}</${json.type}>`;
}
/**
 * Exposes react module used in JSONX
 * @returns {Object} React
 */
export function __getReact() {
  return React;
}

/**
 * Exposes react dom module used in JSONX
 * @returns {Object} ReactDOM
 */
export function __getReactDOM() {
  return ReactDOM;
}

/**
 * Exposes global hook used in JSONX
 * @returns {Object} useGlobalHook
 */
export function __getUseGlobalHook() {
  return useGlobalHook;
}

export const _jsonxChildren = jsonxChildren;
export const _jsonxComponents = jsonxComponents;
export const _jsonxProps = jsonxProps;
export const _jsonxUtils = jsonxUtils;
export { __express, __express as renderFile, } from './express';

export default getReactElementFromJSONX;