import { get } from '@ember/object'; import { expandProperties } from '@ember/object/computed'; /* * * @param modelClass DS.Model * @param attributeNames Array[String] * @param prefixName String * @param map Map * @returns Array[Object] * * A function that takes a model and an array of attributes * and expands them in-place to an array of metadata about the attributes * * if passed a Model with attributes `foo` and `bar` and the array ['foo', 'bar'] * the returned array would take the form of: * * [ * { * name: 'foo', * type: 'string', * options: { * defaultValue: 'Foo' * } * }, * { * name: 'bar', * type: 'string', * options: { * defaultValue: 'Bar', * editType: 'textarea', * label: 'The Bar Field' * } * }, * ] * */ export const expandAttributeMeta = function (modelClass, attributeNames, namePrefix, map) { let fields = []; // expand all attributes attributeNames.forEach((field) => expandProperties(field, (x) => fields.push(x))); let attributeMap = map || new Map(); modelClass.eachAttribute((name, meta) => { let fieldName = namePrefix ? namePrefix + name : name; let maybeFragment = get(modelClass, fieldName); if (meta.isFragment && maybeFragment) { // pass the fragment and all fields that start with // the fragment name down to get extracted from the Fragment expandAttributeMeta( maybeFragment, fields.filter((f) => f.startsWith(fieldName)), fieldName + '.', attributeMap ); return; } attributeMap.set(fieldName, meta); }); // we have all of the attributes in the map now, // so we'll replace each key in `fields` with the expanded meta fields = fields.map((field) => { let meta = attributeMap.get(field); if (meta) { var { type, options } = meta; } return { // using field name here because it is the full path, // name on the attribute meta will be relative to the fragment it's on name: field, type: type, options: options, }; }); return fields; }; /* * * @param modelClass DS.Model * @param fieldGroups Array[Object] * @returns Array * * A function meant for use on an Ember Data Model * * The function takes a array of groups, each group * being a list of attributes on the model, for example * `fieldGroups` could look like this * * [ * { default: ['commonName', 'format'] }, * { Options: ['altNames', 'ipSans', 'ttl', 'excludeCnFromSans'] }, * ] * * The array will get mapped over producing a new array with each attribute replaced with that attribute's metadata from the attr declaration */ export default function (modelClass, fieldGroups) { return fieldGroups.map((group) => { const groupKey = Object.keys(group)[0]; const fields = expandAttributeMeta(modelClass, group[groupKey]); return { [groupKey]: fields }; }); }