Clean up registry implementation, so that it doesn't taint the entire codebase and stores a pointer to the registry in the type reference itself

master
Sven Slootweg 6 years ago
parent e15fe4504b
commit 6957b2216e

@ -12,14 +12,13 @@ const nullMissingFields = require("./util/null-missing-fields");
module.exports = function createTrait(name, schema, options = {}) {
let schemaDescriptors = mapObj(schema, (key, rule) => {
return generateDescriptor(rule, key, true, options._registry);
return generateDescriptor(rule, key, true);
});
let schemaKeys = getSchemaKeys(schema);
return typeRules._createTypeRule({
_isTrait: true,
_registry: options._registry,
_name: name,
applyImplementation: function (implementation) {
/* FIXME: Verify that there are no extraneous keys or unspecified values */
@ -44,9 +43,9 @@ module.exports = function createTrait(name, schema, options = {}) {
let implementationDescriptors = mapObj(implementation, (key, value) => {
if (value != null && value._isSlotRule === true) {
return generateDescriptor(schema[key], key, true, options._registry);
return generateDescriptor(schema[key], key, true);
} else {
return generateDescriptor(value, key, false, options._registry);
return generateDescriptor(value, key, false);
}
});

@ -9,17 +9,16 @@ const generateValidator = require("./generate-validator");
const getSchemaKeys = require("./util/get-schema-keys");
const nullMissingFields = require("./util/null-missing-fields");
module.exports = function createType(name, schema, options = {}) {
module.exports = function createType(name, schema) {
if (schema._isTypeRule === true) {
return typeRules._createTypeRule({
_typeName: name,
_isTypeAlias: true,
_alias: schema,
_registry: options._registry
_alias: schema
});
} else {
let propertyDescriptors = mapObj(schema, (key, rule) => {
return generateDescriptor(rule, key, false, options._registry);
return generateDescriptor(rule, key, false);
});
let protoProperties = {
@ -56,7 +55,6 @@ module.exports = function createType(name, schema, options = {}) {
proto._type = factory;
factory._registry = options._registry;
factory._schemaKeys = schemaKeys;
factory._isCustomType = true;
factory._name = name;

@ -4,9 +4,9 @@ const generateValidator = require("./generate-validator");
const guardedSet = require("./guarded-collections/set");
const guardedMap = require("./guarded-collections/map");
module.exports = function generateDescriptor(rule, key, allowSlot = false, registry) {
module.exports = function generateDescriptor(rule, key, allowSlot = false) {
if (rule._isTypeRule === true) {
let validator = generateValidator(rule, key, registry);
let validator = generateValidator(rule, key);
if (rule._collectionType != null) {
let guardedCollectionFactory;
@ -19,8 +19,8 @@ module.exports = function generateDescriptor(rule, key, allowSlot = false, regis
throw new Error(`Unknown collection type: ${rule._collectionType}`);
}
let valueGuard = generateValidator(rule._itemType, undefined, registry);
let keyGuard = (rule._keyType != null) ? generateValidator(rule._keyType, undefined, registry) : null;
let valueGuard = generateValidator(rule._itemType);
let keyGuard = (rule._keyType != null) ? generateValidator(rule._keyType) : null;
return [key, {
enumerable: true,

@ -12,7 +12,7 @@ const createUndefinedValidator = require("./validator-functions/undefined");
const getValueType = require("./util/get-value-type");
const errors = require("./errors");
module.exports = function generateValidator(rule, name = "<unknown>", registry) {
module.exports = function generateValidator(rule, name = "<unknown>") {
let baseRule;
if (rule._baseType != null) {
@ -37,7 +37,7 @@ module.exports = function generateValidator(rule, name = "<unknown>", registry)
baseRule = () => true; /* FIXME */
} else if (rule._modifierType != null) {
if (rule._modifierType === "either") {
let validators = rule._types.map((type) => generateValidator(type, undefined, registry));
let validators = rule._types.map((type) => generateValidator(type));
baseRule = function (value) {
let matched = false;
@ -60,7 +60,7 @@ module.exports = function generateValidator(rule, name = "<unknown>", registry)
throw new Error(`Unrecognized modifier: ${rule._modifierType}`);
}
} else if (rule._isTypeAlias === true) {
baseRule = generateValidator(rule._alias, name, registry);
baseRule = generateValidator(rule._alias, name);
} else if (rule._isCustomType === true) {
let validator = rule._validator;
@ -77,7 +77,7 @@ module.exports = function generateValidator(rule, name = "<unknown>", registry)
baseRule = function (value) {
/* FIXME: Better error when the type is unknown */
let actualType = registry._types.get(rule._name);
let actualType = rule._registry._types.get(rule._name);
if (actualType._isCustomType) {
if (actualType._validator.call(this, value) === true) {
@ -87,7 +87,7 @@ module.exports = function generateValidator(rule, name = "<unknown>", registry)
}
} else {
if (aliasValidator == null) {
aliasValidator = generateValidator(actualType._alias, name, registry);
aliasValidator = generateValidator(actualType._alias, name);
}
let validatorResult = aliasValidator.call(this, value);
@ -110,21 +110,17 @@ module.exports = function generateValidator(rule, name = "<unknown>", registry)
}
};
} else if (rule._isRegistryTrait === true) {
if (registry == null) {
throw new Error("Registry-based type rules can only be used within the context of a type registry");
} else {
baseRule = function (value) {
/* TODO: The below approach requires that traits be defined before the types that use them, and disallows trait registry references in `.implements` calls, due to _implementedTraits always needing to contain actual trait definitions; in the future, a better approach needs to be found for this such that trait registry references can be used everywhere. */
let actualRule = registry._traits.get(rule._name);
baseRule = function (value) {
/* TODO: The below approach requires that traits be defined before the types that use them, and disallows trait registry references in `.implements` calls, due to _implementedTraits always needing to contain actual trait definitions; in the future, a better approach needs to be found for this such that trait registry references can be used everywhere. */
let actualRule = rule._registry._traits.get(rule._name);
/* FIXME: Better error when the trait is unknown */
if (value._type != null && value._type._implementedTraits != null && value._type._implementedTraits.has(actualRule)) {
return true;
} else {
return new errors.ValidationError(`Expected object of a type with the ${rule._name} trait, got ${getValueType(value)} instead`);
}
};
}
/* FIXME: Better error when the trait is unknown */
if (value._type != null && value._type._implementedTraits != null && value._type._implementedTraits.has(actualRule)) {
return true;
} else {
return new errors.ValidationError(`Expected object of a type with the ${rule._name} trait, got ${getValueType(value)} instead`);
}
};
} else if (rule._isSelfRule === true) {
baseRule = function (value) {
if (value instanceof this._type) {
@ -195,7 +191,7 @@ module.exports = function generateValidator(rule, name = "<unknown>", registry)
});
}
} else {
/* FIXME: Possibly special-case (for better performance) if the only extra rule is a 'default value' rule? This would avoid a `for` loop in the case where a value is explicitly specified. */
/* TODO: Possibly special-case (for better performance) if the only extra rule is a 'default value' rule? This would avoid a `for` loop in the case where a value is explicitly specified. */
for (let rule of rules) {
let result = rule.call(this, value);

@ -2,12 +2,12 @@
const generateValidator = require("./generate-validator");
module.exports = function guardFunction(args, returnType, func, _registry) {
module.exports = function guardFunction(args, returnType, func) {
let rules = args.map((arg) => {
return generateValidator(arg, undefined, _registry);
return generateValidator(arg);
});
let returnValueValidator = generateValidator(returnType, undefined, _registry);
let returnValueValidator = generateValidator(returnType);
let guardedFunction = function (...params) {
let paramsWithDefaults = new Array(params.length);

@ -11,11 +11,7 @@ module.exports = function createRegistry() {
_traits: new Map(),
createType: function (name, schema, options = {}) {
if (!this._types.has(name)) {
let combinedOptions = Object.assign({
_registry: this
}, options);
let type = moduleAPI.createType(name, schema, combinedOptions);
let type = moduleAPI.createType(name, schema, options);
this._types.set(name, type);
return type;
} else {
@ -24,30 +20,25 @@ module.exports = function createRegistry() {
},
createTrait: function (name, schema, options = {}) {
if (!this._traits.has(name)) {
let combinedOptions = Object.assign({
_registry: this
}, options);
let trait = moduleAPI.createTrait(name, schema, combinedOptions);
let trait = moduleAPI.createTrait(name, schema, options);
this._traits.set(name, trait);
return trait;
} else {
throw new Error(`A trait named ${name} already exists in this registry`);
}
},
guardFunction: function (args, returnType, func) {
return moduleAPI.guardFunction(args, returnType, func, this);
},
type: function (typeName) {
return typeRules._createTypeRule({
_isCustomRegistryType: true,
_name: typeName
_name: typeName,
_registry: this
});
},
trait: function (traitName) {
return typeRules._createTypeRule({
_isRegistryTrait: true,
_name: traitName
_name: traitName,
_registry: this
});
},
createRegistry: undefined

@ -5,7 +5,6 @@ const expect = require("chai").expect;
const dm = require("../src");
/* FIXME: Disallow null/nothing/undefined in model definitions, as they make no semantic sense? But allow them for eg. function guards. */
/* FIXME: Registry */
/* FIXME: Test passing an already-guarded collection into a guarded collection factory - either stand-alone or in the context of a model? */
let Identity = dm.createType("Identity", {
label: dm.string(),

Loading…
Cancel
Save