"use strict"; const mapObj = require("map-obj"); const filterObj = require("filter-obj"); const typeRules = require("./type-rules"); const generateDescriptor = require("./generate-descriptor"); const getSchemaKeys = require("./util/get-schema-keys"); const nullMissingFields = require("./util/null-missing-fields"); /* TODO: Traits implementing traits */ module.exports = function createTrait(name, schema, options = {}) { let schemaDescriptors = mapObj(schema, (key, rule) => { return generateDescriptor(rule, key, true); }); let schemaKeys = getSchemaKeys(schema); return typeRules._createTypeRule({ _isTrait: true, _name: name, _schema: schema, applyImplementation: function (implementation) { /* FIXME: Verify that there are no extraneous keys or unspecified values */ let validatedImplementation = Object.create({ _data: {} }, schemaDescriptors); let implementationWithoutSlots = filterObj(implementation, (key, value) => { return (value == null || value._isSlotRule !== true); }); let nullFields = nullMissingFields(implementation, schemaKeys); Object.assign(validatedImplementation, implementationWithoutSlots, nullFields); let implementationSchema = mapObj(implementation, (key, value) => { if (value != null && value._isSlotRule === true) { return [key, { isSlot: true, rule: schema[key] }]; } else { return [key, { isSlot: false, rule: value }]; } }); let implementationDescriptors = mapObj(implementationSchema, (key, value) => { return generateDescriptor(value.rule, key, value.isSlot); }); let slotSchemaKeys = Object.keys(filterObj(implementationSchema, (key, value) => { return value.isSlot; })); return {implementationSchema, implementationDescriptors, slotSchemaKeys}; } }); };