Source: data-engine-js-components-web/src/main/resources/META-INF/resources/js/core/hooks/useDataView.es.js

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

import {DataDefinitionSchema} from '../schema/DataDefinition.es';
import {DataLayoutSchema} from '../schema/DataLayout.es';
import {SYMBOL_RAW} from '../schema/Schema.es';

const SCHEMAS_DICTIONARY = {
	dataDefinition: DataDefinitionSchema,
	dataLayout: DataLayoutSchema,
};

/**
 * Context stores all instances of schemas created by key to avoid recreating
 * a new instance of the same Schema in different components.
 */
const context = {};

const getProps = (props, keys) =>
	keys.reduce((prev, key) => {
		prev[key] = props[key];

		return prev;
	}, {});

/**
 * Compare the values of the properties at the reference level, the properties
 * should only be for readonly, the raw object and props will always be different
 * objects because props contain all the properties of the store but raw only
 * the properties that the schema needs.
 */
const isStaleRaw = (key, props, schema) =>
	SCHEMAS_DICTIONARY[key].props.some(
		(key) => props[key] !== schema[SYMBOL_RAW][key]
	);

const createSchema = (key, props) => {
	const Schema = SCHEMAS_DICTIONARY[key];

	const raw = getProps(props, Schema.props);
	const instance = new Schema(raw);

	context[key] = instance;

	return instance;
};

const getSchema = (key, props) => {
	if (key in context) {
		if (isStaleRaw(key, props, context[key])) {
			delete context[key];

			return createSchema(key, props);
		}

		return context[key];
	}
	else {
		return createSchema(key, props);
	}
};

const parseSchema = (props, schema) =>
	schema.reduce((prev, key) => {
		const Schema = getSchema(key, props);

		prev[key] = Schema;

		return prev;
	}, {});

/**
 * UseDataView creates a representation of the data based on the passed
 * schema otherwise nothing is done. It should not be used directly, it
 * is exposed through `useFormState`.
 */
export function useDataView(props, schema) {
	return schema ? parseSchema(props, schema) : props;
}