parse/interface/data.js

import {chain, chainAsync} from './chain'

const flatten = array => [].concat(...array)

// Different registers to store parsers in
const parsers = {}
const asyncParsers = {}
const nativeParsers = {
  '@csl/object': input => [input],
  '@csl/list+object': input => input,
  '@else/list+object': input => flatten(input.map(chain)),
  '@invalid': () => []
}
const nativeAsyncParsers = {
  '@else/list+object': async input => flatten(await Promise.all(input.map(chainAsync)))
}

/**
 * @access public
 * @memberof Cite.plugins.input
 *
 * @param {InputData} input - input data
 * @param {Cite.plugins.input~format} type - input type
 *
 * @return {*} parsed data
 * @return {Null} if no parser available
 */
export const data = (input, type) => {
  if (parsers.hasOwnProperty(type)) {
    return parsers[type](input)
  } else if (nativeParsers.hasOwnProperty(type)) {
    return nativeParsers[type](input)
  } else {
    logger.error('[set]', `No synchronous parser found for ${type}`)
    return null
  }
}

/**
 * @access public
 * @memberof Cite.plugins.input
 *
 * @param {InputData} input - input data
 * @param {Cite.plugins.input~format} type - input type
 *
 * @return {Promise} parsed data
 * @return {Promise<Null>} if no parser available
 */
export const dataAsync = async (input, type) => {
  if (asyncParsers.hasOwnProperty(type)) {
    return asyncParsers[type](input)
  } else if (nativeAsyncParsers.hasOwnProperty(type)) {
    return nativeAsyncParsers[type](input)
  } else if (hasDataParser(type, false)) {
    return data(input, type)
  } else {
    logger.error('[set]', `No parser found for ${type}`)
    return null
  }
}

/**
 * @access protected
 * @memberof Cite.plugins.input
 *
 * @param {Cite.plugins.input~format} format
 * @param {Cite.plugins.input~parse|Cite.plugins.input~parseAsync} parser
 * @param {Object} [options={}]
 * @param {Boolean} [options.async=false]
 */
export const addDataParser = (format, {parser, async}) => {
  if (async) {
    asyncParsers[format] = parser
  } else {
    parsers[format] = parser
  }
}

/**
 * @access public
 * @memberof Cite.plugins.input
 *
 * @param {Cite.plugins.input~format} type
 * @param {Boolean} [async=false] - check only for async, or only sync
 *
 * @return {Boolean} parser exists
 */
export const hasDataParser = (type, async) => async
  ? asyncParsers[type] || nativeAsyncParsers[type]
  : parsers[type] || nativeParsers[type]

/**
 * @access public
 * @memberof Cite.plugins.input
 *
 * @param {Cite.plugins.input~format} type
 * @param {Boolean} [async=false]
 */
export const removeDataParser = (type, async) => { delete (async ? asyncParsers : parsers)[type] }

/**
 * @access public
 * @memberof Cite.plugins.input
 *
 * @param {Boolean} [async=false]
 */
export const listDataParser = (async) => Object.keys(async ? asyncParsers : parsers)