From 1c295a4402bacd3d5a5c547a3b492caef74b7c33 Mon Sep 17 00:00:00 2001 From: Sven Slootweg Date: Wed, 8 Aug 2018 11:17:39 +0200 Subject: [PATCH] Add support for registry-based type aliases --- src/create-type.js | 1 + src/generate-validator.js | 28 ++++++++++++++++++++++++---- test/registry.js | 22 ++++++++++++++++++++++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/create-type.js b/src/create-type.js index cfeb898..4346c48 100644 --- a/src/create-type.js +++ b/src/create-type.js @@ -5,6 +5,7 @@ const mapObj = require("map-obj"); const typeRules = require("./type-rules"); const generateDescriptor = require("./generate-descriptor"); +const generateValidator = require("./generate-validator"); const getSchemaKeys = require("./util/get-schema-keys"); const nullMissingFields = require("./util/null-missing-fields"); diff --git a/src/generate-validator.js b/src/generate-validator.js index a5f335a..38f27b2 100644 --- a/src/generate-validator.js +++ b/src/generate-validator.js @@ -72,13 +72,33 @@ module.exports = function generateValidator(rule, name = "", registry) } }; } else if (rule._isCustomRegistryType) { + /* HACK: We performantly memoize the validator for a registry-stored alias, by storing it in the validator generation scope. */ + let aliasValidator; + baseRule = function (value) { /* FIXME: Better error when the type is unknown */ - if (registry._types.get(rule._name)._validator.call(this, value) === true) { - return true; + let actualType = registry._types.get(rule._name); + + if (actualType._isCustomType) { + if (actualType._validator.call(this, value) === true) { + return true; + } else { + return new errors.ValidationError(`Expected ${getValueType(rule)}, got ${getValueType(value)} instead`); + } } else { - /* FIXME: Add support for registry rules to getValueType */ - return new errors.ValidationError(`Expected ${getValueType(rule)}, got ${getValueType(value)} instead`); + if (aliasValidator == null) { + aliasValidator = generateValidator(actualType._alias, name, registry); + } + + let validatorResult = aliasValidator.call(this, value); + + if (validatorResult === true) { + return true; + } else { + // return new errors.ValidationError(`Expected ${getValueType(actualType._alias)}, got ${getValueType(value)} instead`); + /* FIXME: Possible this is done wrong elsewhere too, swallowing the actual validation error? */ + return validatorResult; + } } }; } else if (rule._isTrait === true) { diff --git a/test/registry.js b/test/registry.js index 05dfdbe..93e55e7 100644 --- a/test/registry.js +++ b/test/registry.js @@ -4,6 +4,8 @@ const expect = require("chai").expect; const dm = require("../src"); +/* FIXME: setOf/mapOf? */ + describe("registry", () => { let registry = dm.createRegistry(); @@ -123,5 +125,25 @@ describe("registry", () => { flowers.to = flowers; }).to.throw("Expected an instance of Person, got an instance of Gift instead"); }); + + it("should work correctly for type aliases", () => { + let CheckedString = registry.createType("CheckedString", dm.string({ matches: /^[a-z]+$/ })); + + let SomeType = registry.createType("SomeType", { + value: registry.type("CheckedString") + }); + + let instance = SomeType({ + value: "foo" + }); + + expect(instance.value).to.equal("foo"); + + expect(() => { + SomeType({ + value: "bar42" + }); + }).to.throw("Value for property 'value' failed `matches` condition"); + }) }); });