Add type registry support
parent
e16224604a
commit
7118d696bb
@ -0,0 +1,14 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const typeRules = require("./type-rules");
|
||||||
|
const createType = require("./create-type");
|
||||||
|
const createTrait = require("./create-trait");
|
||||||
|
const guardFunction = require("./guard-function");
|
||||||
|
const errors = require("./errors");
|
||||||
|
|
||||||
|
module.exports = Object.assign({
|
||||||
|
createType: createType,
|
||||||
|
createTrait: createTrait,
|
||||||
|
guard: guardFunction,
|
||||||
|
ValidationError: errors.ValidationError
|
||||||
|
}, typeRules);
|
@ -0,0 +1,47 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const moduleAPI = require("./module-api");
|
||||||
|
const typeRules = require("./type-rules");
|
||||||
|
|
||||||
|
/* FIXME: Disallow usage of registry.type-style references from one registry in types of another? Or perhaps embed the registry in the reference, instead of passing it through functions by means of scope? */
|
||||||
|
|
||||||
|
module.exports = function createRegistry() {
|
||||||
|
return Object.assign({}, moduleAPI, {
|
||||||
|
_types: new Map(),
|
||||||
|
_traits: new Map(),
|
||||||
|
createType: function (name, schema, options = {}) {
|
||||||
|
let combinedOptions = Object.assign({
|
||||||
|
_registry: this
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
let type = moduleAPI.createType(name, schema, combinedOptions);
|
||||||
|
this._types.set(name, type);
|
||||||
|
return type;
|
||||||
|
},
|
||||||
|
createTrait: function (name, schema, options = {}) {
|
||||||
|
let combinedOptions = Object.assign({
|
||||||
|
_registry: this
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
let trait = moduleAPI.createTrait(name, schema, combinedOptions);
|
||||||
|
this._traits.set(name, trait);
|
||||||
|
return trait;
|
||||||
|
},
|
||||||
|
guardFunction: function (args, returnType, func) {
|
||||||
|
return moduleAPI.guardFunction(args, returnType, func, this);
|
||||||
|
},
|
||||||
|
type: function (typeName) {
|
||||||
|
return typeRules._createTypeRule({
|
||||||
|
_isCustomRegistryType: true,
|
||||||
|
_name: typeName
|
||||||
|
});
|
||||||
|
},
|
||||||
|
trait: function (traitName) {
|
||||||
|
return typeRules._createTypeRule({
|
||||||
|
_isRegistryTrait: true,
|
||||||
|
_name: traitName
|
||||||
|
});
|
||||||
|
},
|
||||||
|
createRegistry: undefined
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,127 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const expect = require("chai").expect;
|
||||||
|
|
||||||
|
const dm = require("../src");
|
||||||
|
|
||||||
|
describe("registry", () => {
|
||||||
|
let registry = dm.createRegistry();
|
||||||
|
|
||||||
|
describe("registry API", () => {
|
||||||
|
it("should not expose registry-specific methods on the primary module API", () => {
|
||||||
|
expect(dm.type).to.equal(undefined);
|
||||||
|
expect(dm.trait).to.equal(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should expose the createRegistry method on the primary module API", () => {
|
||||||
|
expect(dm.createRegistry).to.be.a("function");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should expose registry-specific methods on the registry API", () => {
|
||||||
|
expect(registry.type).to.be.a("function");
|
||||||
|
expect(registry.trait).to.be.a("function");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not expose the createRegistry method on the registry API", () => {
|
||||||
|
expect(registry.createRegistry).to.equal(undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("registry usage", () => {
|
||||||
|
it("should work correctly for types", () => {
|
||||||
|
let Person = registry.createType("Person", {
|
||||||
|
name: dm.string(),
|
||||||
|
favouriteGift: registry.type("Gift").optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
let Gift = registry.createType("Gift", {
|
||||||
|
description: dm.string(),
|
||||||
|
from: registry.type("Person"),
|
||||||
|
to: registry.type("Person")
|
||||||
|
});
|
||||||
|
|
||||||
|
let joe = Person({
|
||||||
|
name: "Joe"
|
||||||
|
});
|
||||||
|
|
||||||
|
let jane = Person({
|
||||||
|
name: "Jane"
|
||||||
|
});
|
||||||
|
|
||||||
|
let flowers = Gift({
|
||||||
|
description: "Flowers",
|
||||||
|
from: jane,
|
||||||
|
to: joe
|
||||||
|
});
|
||||||
|
|
||||||
|
joe.favouriteGift = flowers;
|
||||||
|
|
||||||
|
expect(joe.favouriteGift).to.equal(flowers);
|
||||||
|
expect(flowers.to).to.equal(joe);
|
||||||
|
expect(flowers.from).to.equal(jane);
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
jane.favouriteGift = "not a gift";
|
||||||
|
}).to.throw("Expected an instance of Gift, got a string instead");
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
flowers.to = "not a person";
|
||||||
|
}).to.throw("Expected an instance of Person, got a string instead");
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
flowers.to = flowers;
|
||||||
|
}).to.throw("Expected an instance of Person, got an instance of Gift instead");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should work correctly for traits", () => {
|
||||||
|
let Givable = registry.createTrait("Givable", {
|
||||||
|
from: registry.type("Person"),
|
||||||
|
to: registry.type("Person")
|
||||||
|
});
|
||||||
|
|
||||||
|
let Person = registry.createType("Person", {
|
||||||
|
name: dm.string(),
|
||||||
|
favouriteGift: registry.trait("Givable").optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
let Gift = registry.createType("Gift", {
|
||||||
|
description: dm.string()
|
||||||
|
}).implements(Givable, {
|
||||||
|
from: dm.slot(),
|
||||||
|
to: dm.slot()
|
||||||
|
});
|
||||||
|
|
||||||
|
let joe = Person({
|
||||||
|
name: "Joe"
|
||||||
|
});
|
||||||
|
|
||||||
|
let jane = Person({
|
||||||
|
name: "Jane"
|
||||||
|
});
|
||||||
|
|
||||||
|
let flowers = Gift({
|
||||||
|
description: "Flowers",
|
||||||
|
from: jane,
|
||||||
|
to: joe
|
||||||
|
});
|
||||||
|
|
||||||
|
joe.favouriteGift = flowers;
|
||||||
|
|
||||||
|
expect(joe.favouriteGift).to.equal(flowers);
|
||||||
|
expect(flowers.to).to.equal(joe);
|
||||||
|
expect(flowers.from).to.equal(jane);
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
jane.favouriteGift = "not a gift";
|
||||||
|
}).to.throw("Expected object of a type with the Givable trait, got a string instead");
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
flowers.to = "not a person";
|
||||||
|
}).to.throw("Expected an instance of Person, got a string instead");
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
flowers.to = flowers;
|
||||||
|
}).to.throw("Expected an instance of Person, got an instance of Gift instead");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue