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