123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- 'use strict';
- const Clone = require('@hapi/hoek/lib/clone');
- const Reach = require('@hapi/hoek/lib/reach');
- const Common = require('./common');
- const internals = {
- value: Symbol('value')
- };
- module.exports = internals.State = class {
- constructor(path, ancestors, state) {
- this.path = path;
- this.ancestors = ancestors; // [parent, ..., root]
- this.mainstay = state.mainstay;
- this.schemas = state.schemas; // [current, ..., root]
- this.debug = null;
- }
- localize(path, ancestors = null, schema = null) {
- const state = new internals.State(path, ancestors, this);
- if (schema &&
- state.schemas) {
- state.schemas = [internals.schemas(schema), ...state.schemas];
- }
- return state;
- }
- nest(schema, debug) {
- const state = new internals.State(this.path, this.ancestors, this);
- state.schemas = state.schemas && [internals.schemas(schema), ...state.schemas];
- state.debug = debug;
- return state;
- }
- shadow(value, reason) {
- this.mainstay.shadow = this.mainstay.shadow || new internals.Shadow();
- this.mainstay.shadow.set(this.path, value, reason);
- }
- snapshot() {
- if (this.mainstay.shadow) {
- this._snapshot = Clone(this.mainstay.shadow.node(this.path));
- }
- this.mainstay.snapshot();
- }
- restore() {
- if (this.mainstay.shadow) {
- this.mainstay.shadow.override(this.path, this._snapshot);
- this._snapshot = undefined;
- }
- this.mainstay.restore();
- }
- commit() {
- if (this.mainstay.shadow) {
- this.mainstay.shadow.override(this.path, this._snapshot);
- this._snapshot = undefined;
- }
- this.mainstay.commit();
- }
- };
- internals.schemas = function (schema) {
- if (Common.isSchema(schema)) {
- return { schema };
- }
- return schema;
- };
- internals.Shadow = class {
- constructor() {
- this._values = null;
- }
- set(path, value, reason) {
- if (!path.length) { // No need to store root value
- return;
- }
- if (reason === 'strip' &&
- typeof path[path.length - 1] === 'number') { // Cannot store stripped array values (due to shift)
- return;
- }
- this._values = this._values || new Map();
- let node = this._values;
- for (let i = 0; i < path.length; ++i) {
- const segment = path[i];
- let next = node.get(segment);
- if (!next) {
- next = new Map();
- node.set(segment, next);
- }
- node = next;
- }
- node[internals.value] = value;
- }
- get(path) {
- const node = this.node(path);
- if (node) {
- return node[internals.value];
- }
- }
- node(path) {
- if (!this._values) {
- return;
- }
- return Reach(this._values, path, { iterables: true });
- }
- override(path, node) {
- if (!this._values) {
- return;
- }
- const parents = path.slice(0, -1);
- const own = path[path.length - 1];
- const parent = Reach(this._values, parents, { iterables: true });
- if (node) {
- parent.set(own, node);
- return;
- }
- if (parent) {
- parent.delete(own);
- }
- }
- };
|