'use strict';
// Load modules
const Any = require('../any');
const Hoek = require('hoek');
// Declare internals
const internals = {};
internals.Lazy = class extends Any {
constructor() {
super();
this._type = 'lazy';
this._flags.once = true;
this._cache = null;
}
_init(fn, options) {
return this.set(fn, options);
}
_base(value, state, options) {
let schema;
if (this._cache) {
schema = this._cache;
}
else {
const result = { value };
const lazy = this._flags.lazy;
if (!lazy) {
result.errors = this.createError('lazy.base', null, state, options);
return result;
}
schema = lazy();
if (!(schema instanceof Any)) {
result.errors = this.createError('lazy.schema', { schema }, state, options);
return result;
}
if (this._flags.once) {
this._cache = schema;
}
}
return schema._validate(value, state, options);
}
set(fn, options) {
Hoek.assert(typeof fn === 'function', 'You must provide a function as first argument');
Hoek.assert(options === undefined || (options && typeof options === 'object' && !Array.isArray(options)), `Options must be an object`);
if (options) {
const unknownOptions = Object.keys(options).filter((key) => !['once'].includes(key));
Hoek.assert(unknownOptions.length === 0, `Options contain unknown keys: ${unknownOptions}`);
Hoek.assert(options.once === undefined || typeof options.once === 'boolean', 'Option "once" must be a boolean');
}
const obj = this.clone();
obj._flags.lazy = fn;
if (options && options.once !== obj._flags.once) {
obj._flags.once = options.once;
}
return obj;
}
};
module.exports = new internals.Lazy();