UNPKG

semantic-network

Version:

A utility library for manipulating a list of links that form a semantic interface to a network of resources.

168 lines 8.17 kB
import { __awaiter } from "tslib"; import { RepresentationUtil } from './representationUtil'; import { LinkUtil } from 'semantic-link'; import { noopResolver } from '../representation/resourceMergeFactory'; import { SparseRepresentationFactory } from '../representation/sparseRepresentationFactory'; import { LinkRelation } from '../linkRelation'; import anylogger from 'anylogger'; import { LinkRelConvertUtil } from './linkRelConvertUtil'; import { FieldType } from '../types/formTypes'; import { instanceOfCollection } from './instanceOf/instanceOfCollection'; const log = anylogger('FormUtil'); export class FormUtil { static fieldsToAccept(form, defaultFields = []) { const fieldsFromForm = (form.items || []).map(x => x.name); const allFields = defaultFields === null || defaultFields === void 0 ? void 0 : defaultFields.concat(fieldsFromForm); const distinctFields = new Set(allFields); return Array.from(distinctFields); } /** * Pick all the fields to resolve in the document at that (a) exist in the form AND (b) exist on the document itself * or are defaults * @param document * @param form * @param defaultFields */ static fieldsToResolve(document, form, defaultFields = []) { // preparation: get all the fields to return back to the API const fieldsToReturn = FormUtil.fieldsToAccept(form, defaultFields); // pick all the fields as specified from the form const fields = RepresentationUtil.fields(document); // resolve return (fieldsToReturn ? fields.filter(fieldName => fieldsToReturn.includes(fieldName)) : fields); } /** * Pick all the fields to resolve in the document at that (a) exist in the form AND (b) exist on the document itself * or are defaults * @param document * @param form * @param defaultFields * @returns * */ static linksToResolve(document, form, defaultFields = []) { // preparation: get all the fields to return back to the API // pick only link rels that exist in the form // const relsToReturn = fieldsToReturn.map(field => LinkRelConvertUtil.camelToDash(field as string)); // link relations exist as a dashed form and fields/create forms use camel case // return (relsToReturn ? // relsToReturn.filter(fieldName => LinkUtil.matches(document as LinkedRepresentation, fieldName)) : // []) as P[]; return FormUtil.fieldsToAccept(form, defaultFields) .flatMap(field => LinkRelConvertUtil.camelToDash(field)) .filter(fieldName => LinkUtil.matches(document, fieldName)); } /** * Find a {@link FormItem} by matching its {@link FormItem.name} against a field name. A fieldname strategy * is camel cased * * @see LinkRelConvertUtil.dashToCamel * * TODO: field could accept RelationshipType {@see LinkRelConvertUtil.relTypeToCamel} * * @param form * @param field */ static findByField(form, field) { var _a; return (_a = form.items) === null || _a === void 0 ? void 0 : _a.find(item => item.name === field); } /** * A basic dirty check type function comparing an original resource with a new document. * @param resource original document * @param document updates to be made * @param form * @param defaultFields that require update * @returns fields to merge that actually requiring updating based on being a different value * * // TODO; return Omit<P, "links"> */ static fieldsRequiringUpdate(resource, document, form, defaultFields = []) { const fieldsToCheck = FormUtil.fieldsToAccept(form, defaultFields); // only return fields that are different return fieldsToCheck .filter(field => { // omit any fields that match // WARNING: This might have problems if the field is a 'multiple' <<<<<<<<<<<<<<<< ---- please review return !(RepresentationUtil.getProperty(resource, field) === RepresentationUtil.getProperty(document, field)); }); } /** * Returns a new object with only fields explicitly set in the form or default values * @param document * @param form * @param options */ static fieldsToReturnFromForm(document, form, options) { const { defaultFields = [] } = Object.assign({}, options); const fieldsToResolve = FormUtil.fieldsToResolve(document, form, defaultFields); const doc = {}; for (const field of fieldsToResolve) { // really not sure how to avoid indexer errors doc[field] = RepresentationUtil.getProperty(document, field); } return doc; } /** * A {@link FormItem} can have a lazy loaded {@link FieldType.Collection} on a {@link FieldType.Select} where the * {@link FormItem.id} is set to the uri of the collection that is resolved via an optional {@link MergeOptions.resourceResolver}. * This collection may or may not be resolved at the same time via an optional {@link MergeOptions.resolver}. * * Note: there is a current implicit polymorphism to be resolved. The {@link FormItem.items} can be both a {@link FormItem[]} * and a {@link CollectionRepresentation} where the code looks through to the Collection items. * * @param item form item that may optionally have a lazy loaded items collection * @param options contains the optional resolvers */ static resolveItemsFromCollection(item, options) { return __awaiter(this, void 0, void 0, function* () { if (item.type !== FieldType.Select) { log.warn('Only selects form type should be called but have called %s', item.type); } if (item.id) { // const { resourceResolver = undefined, resolver = noopResolver } = Object.assign({}, options); if (resourceResolver) { const uri = resolver.resolve(item.id); const representation = SparseRepresentationFactory.make(Object.assign(Object.assign({}, options), { uri })); log.debug('matching items collection with resource resolver \'%s\' on \'%s\' --> \'%s\'', item.name, item.id, uri); const resource = yield resourceResolver(item.name)(representation, options); if (instanceOfCollection(resource)) { // put the collection onto the items. // TODO: merge onto existing items // TODO: workout how to deal with Collection versus FormItem[] if (item.items) { log.warn('Potential conflict between existing form items and merged collection'); } item['items'] = resource; } else { if (resource) { log.error('Only a collection may be lazy loaded onto form items: %s', LinkUtil.getUri(resource, LinkRelation.Self)); } // do nothing to the items } } // else no resolver } // else no 'id' is just fine and do nothing // on a FormItem, items is optional but it is easier if instead of null, items is an empty list where the form type // is select if (!item.items) { item.items = []; } }); } /** * Take a form representation and return back a document based on the keys in the form representation. * * TODO: values are currently null but could include any defaults from the form */ static toEmptyDocument(form) { const formItems = form.items || []; const documentation = formItems.map(key => ({ [key.name]: null })); // ensure that it is cloned //?? check, shouldn't need this return Object.assign({}, ...documentation); } } //# sourceMappingURL=formUtil.js.map