Skip to content

Commit

Permalink
Remove definition parts from prototype. Closes #2014
Browse files Browse the repository at this point in the history
  • Loading branch information
hueniverse committed Aug 6, 2019
1 parent bb24da8 commit 38f4126
Show file tree
Hide file tree
Showing 20 changed files with 560 additions and 367 deletions.
219 changes: 19 additions & 200 deletions lib/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const Cache = require('./cache');
const Cast = require('./cast');
const Common = require('./common');
const Errors = require('./errors');
const Extend = require('./extend');
const Manifest = require('./manifest');
const Messages = require('./messages');
const Modify = require('./modify');
Expand All @@ -22,6 +23,7 @@ internals.Base = class {
constructor(type) {

this._type = type;
this._definition = {};
this._ids = new Modify.Ids();
this._preferences = null;
this._refs = new Ref.Manager();
Expand Down Expand Up @@ -104,7 +106,7 @@ internals.Base = class {

cast(to) {

Hoek.assert(to === false || this._casts[to], 'Type', this._type, 'does not support casting to', to);
Hoek.assert(to === false || this._definition.cast[to], 'Type', this._type, 'does not support casting to', to);

return this.setFlag('cast', to === false ? undefined : to);
}
Expand Down Expand Up @@ -477,11 +479,7 @@ internals.Base = class {
obj._inners[key] = obj._inners[key].concat(inners);
}

if (typeof obj._rebuild === 'function') {
obj._rebuild();
}

return obj;
return obj.rebuild();
}

createError(code, value, local, state, prefs, options = {}) {
Expand Down Expand Up @@ -600,127 +598,7 @@ internals.Base = class {

extend(options) {

const base = Object.getPrototypeOf(this);
const prototype = Hoek.clone(base);
const schema = this._assign(Object.create(prototype));
const def = Object.assign({}, options); // Shallow cloned

prototype._definition = def;

const parent = base._definition || {};
def.messages = Messages.merge(parent.messages, def.messages);
def.properties = Object.assign({}, parent.properties, def.properties);

// Initialize

schema._type = def.type;
schema._ids._reachable = def.properties.reachable;

if (def.initialize) {
def.initialize.call(schema);
}

if (!def.args) {
def.args = parent.args;
}

// Validate

def.validate = internals.validate(def.validate, parent.validate);

// Coerce

if (def.coerce) {
if (typeof def.coerce === 'function') {
def.coerce = { method: def.coerce };
}

if (def.coerce.from &&
!Array.isArray(def.coerce.from)) {

def.coerce = { method: def.coerce.method, from: [].concat(def.coerce.from) };
}
}

def.coerce = internals.coerce(def.coerce, parent.coerce);

// Rules

const rules = Object.assign({}, parent.rules);
if (def.rules) {
for (const name in def.rules) {
const rule = def.rules[name];
Hoek.assert(typeof rule === 'object', 'Invalid rule definition for', def.type, name);

let method = rule.method;
if (method === undefined) {
method = function () {

return this.addRule(name);
};
}

if (method) {
Hoek.assert(!prototype[name], 'Rule conflict in', def.type, name);
prototype[name] = method;
}

Hoek.assert(!rules[name], 'Rule conflict in', def.type, name);
rules[name] = rule;

if (rule.alias) {
const aliases = [].concat(rule.alias);
for (const alias of aliases) {
prototype[alias] = rule.method;
}
}

if (rule.args) {
rule.argsByName = new Map();
rule.args = rule.args.map((arg) => {

if (typeof arg === 'string') {
arg = { name: arg };
}

Hoek.assert(!rule.argsByName.has(arg.name), 'Duplicated argument name', arg.name);

rule.argsByName.set(arg.name, arg);
return arg;
});
}
}
}

def.rules = rules;

if (def.overrides) {
prototype.super = base;
Object.assign(prototype, def.overrides);
}

prototype._casts = Object.assign({}, prototype._casts);

if (def.cast) {
Object.assign(prototype._casts, def.cast.to);
if (def.cast.from) {
prototype._casts[Common.symbols.castFrom] = def.cast.from;
}
}

if (def.build) {
prototype._build = def.build;
}

if (def.modify) {
prototype._override = def.modify;
}

if (def.rebuild) {
prototype._rebuild = def.rebuild;
}

return schema;
return Extend.type(this, options);
}

setFlag(name, value, options = {}) {
Expand Down Expand Up @@ -856,6 +734,20 @@ internals.Base = class {
return rules;
}

rebuild() {

if (!this._definition.rebuild) {
return this;
}

Hoek.assert(!this._inRuleset(), 'Cannot add this rule inside a ruleset');

this._resetRegistrations();
this._definition.rebuild(this);
this._ruleset = false;
return this;
}

// Internals

_assign(target) {
Expand Down Expand Up @@ -1014,77 +906,4 @@ internals.Base.prototype.options = internals.Base.prototype.prefs;
internals.Base.prototype.preferences = internals.Base.prototype.prefs;


// Helpers

internals.coerce = function (child, parent) {

if (!child ||
!parent) {

return child || parent;
}

return {
from: child.from && parent.from ? [...new Set([...child.from, ...parent.from])] : null,
method: function (schema, value, helpers) {

let coerced;
if (!parent.from ||
parent.from.includes(typeof value)) {

coerced = parent.method(schema, value, helpers);
if (coerced) {
if (coerced.errors) {
return coerced;
}

value = coerced.value;
}
}

if (value !== undefined &&
(!child.from || child.from.includes(typeof value))) {

const own = child.method(schema, value, helpers);
if (own) {
if (own.errors) {
return own;
}

coerced = own;
}
}

return coerced;
}
};
};


internals.validate = function (child, parent) {

if (!child ||
!parent) {

return child || parent;
}

return function (schema, value, helpers) {

const result = parent(schema, value, helpers);
if (result) {
if (result.errors &&
(!Array.isArray(result.errors) || result.errors.length)) {

return result;
}

value = result.value;
}

return child(schema, value, helpers);
};
};


module.exports = new internals.Base();
1 change: 0 additions & 1 deletion lib/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ exports.defaults = {
exports.symbols = {
any: Marker('joi-any-base'), // Used to internally identify any-based types (shared with other joi versions)
arraySingle: Symbol('arraySingle'),
castFrom: Symbol('castFrom'),
deepDefault: Symbol('deepDefault'),
literal: Symbol('literal'),
prefs: Symbol('prefs'),
Expand Down
Loading

0 comments on commit 38f4126

Please sign in to comment.