Source: registry.js

/**
 * Internal. This is the core of react-cmf.
 * The registry will register everything from a react component to redux action.
 * @module react-cmf/lib/registry
 */
/* eslint no-underscore-dangle: ["error", {"allow": ["_registry", "_isLocked"] }] */

/**
 * @typedef {Object<string, *>} Registry
 */

/**
 * The registry that will have the singleton
 * - getRegistry() -> the registry which is a simple key/value POJO
 * @type {Registry}
 */
const Registry = {
	_registry: {},
	_isLocked: false,
	getRegistry() {
		return this._registry;
	},
	lock() {
		this._isLocked = true;
	},
	isLocked() {
		return this._isLocked;
	},
};

/**
 * Returns the global registry if no context found. If count is found it returns
 * the context.registry
 * @param {object} context React context
 * @return {Registry} the registry singleton instance
 */
function getRegistry(context) {
	if (context && context.registry) {
		return context.registry;
	}
	return Registry.getRegistry();
}

/**
 * Internal. Call this one to add anything you want into the registry.
 * It will be added only if not locked.
 * Be warned any existing content will be overridden.
 * You should use this to add a new configurable concept to CMF.
 * By default it's internally used to register expression, component and actionCreator
 * @param {string} id Where you want it to store in the registry to get it later
 * @param {any} item Everything you want, a function, an object or whatever
 */
function addToRegistry(id, item, context) {
	if (Registry.isLocked()) {
		throw new Error(
			`CMF: The registry is locked, you cannot therefore add '${id}' in it. ` +
				'Please check your CMF configuration, it should not move after the initial ' +
				'configuration before bootstrap.',
		);
	}

	const registry = getRegistry(context);
	if (registry[id]) {
		// eslint-disable-next-line no-console
		console.warn(
			`CMF: The '${id}' object is registered, overriding an existing '${id}' object. ` +
				'Please check your CMF configuration, you might not want that.',
		);
	}
	if (item === undefined) {
		throw new Error(
			`CMF: you can't register undefined in '${id}'.
			You may have an import error in your configuration`,
		);
	}
	registry[id] = item;
}

/**
 * Internal: return element registred under the ID.
 * @param  {string} id the object's id in the registry you want to get
 * @param  {object} context cmf context
 * @return {any}    the object you are looking for
 */
function getFromRegistry(id, context) {
	return getRegistry(context)[id];
}

/**
 * This function is a curry that return a generic function to register components in registry
 * @param {function} registerFn a function that register a item in the registry
 */
function getRegisterMany(registerFn) {
	return (itemsToRegister, context) => {
		Object.keys(itemsToRegister).forEach(key => {
			registerFn(key, itemsToRegister[key], context);
		});
	};
}

const registerMany = getRegisterMany(addToRegistry);

/**
 * Lock the registry
 */
function lock() {
	Registry.lock();
}

export default {
	Registry,
	addToRegistry,
	getRegistry,
	getFromRegistry,
	getRegisterMany,
	lock,
	registerMany,
};