<commit_before>/**
 * @jsx React.DOM
 * @preventMunge
 * @copyright Prometheus Research, LLC 2014
 */
'use strict';

var {Vector, Map, OrderedMap, Record}            = require('immutable');
var {isSchema, isList, isMapping, isScalar}      = require('./schema');
var ValidationResult                             = require('./ValidationResult');
var mergeInto                                    = require('./mergeInto');
var merge                                        = require('./merge');
var invariant                                    = require('./invariant');
var validate                                     = require('./validate');
var emptyFunction                                = require('./emptyFunction');
var toArray                                      = require('./toArray');

var DIRTY_KEY = '__react_forms_dirty__';

/**
 * Serves as a immutable container for form value attributes.
 */
var ValueAttributes = Record({
  schema: null,
  value: null,
  validation: null,
  externalValidation: null,
  serialized: null
}, 'ValueAttributes');

/**
 * Reference to the current form value.
 */
class Value {

  constructor(attributes, root, path) {
    this._attributes = attributes;
    this._root = root;
    this._cache = {};
    this._schema = null;
    this.path = path;
  }

  equals(other) {
    return (
      this.path.toString() === other.path.toString() &&
      this.schema.equals(other.schema) &&
      (
        this.value && this.value.equals ?
        this.value.equals(other.value) :
        this.value === other.value
      ) &&
      (
        this.serialized && this.serialized.equals ?
        this.serialized.equals(other.serialized) :
        this.serialized === other.serialized
      ) &&
      this.validation.equals(other.validation) &&
      this.externalValidation.equals(other.externalValidation) &&
      this.dirty === other.dirty &&
      this._root.get('onUpdate') === other._root.get('onUpdate')
    );
  }

  _child(key) {
    if (this._cache[key]) {
      return this._cache[key];
    }

    var schema = this.schema.child(key);
    var value = this.value.get(key);
    var schemaInstance = instantiateSchema(schema, value);
    var serialized = this.serialized.get(key);
    var validation = this.validation.child(key);
    var externalValidation = this.externalValidation.child(key);

    var attributes;
    if (value === undefined) {
      value = _defaultValue(schemaInstance);
      attributes = makeAttributes({schema, value, serialized, validation, externalValidation});
    } else {
      attributes = {schema, value, serialized, validation, externalValidation};
    }

    var ctor = _getCtor(schemaInstance);
    return (this._cache[key] = new ctor(
      this._attributes.merge(attributes),
      this._root,
      this.path.concat(key)
    ));
  }

  child(...key) {
    var value = this;
    for (var i = 0, len = key.length; i < len; i++) {
      value = value._child(key[i]);
    }
    return value;
  }

  childIn(keyPath) {
    return this.child.apply(this, keyPath);
  }

  update(newValue) {
    var trace = valueTraceByPath(this.root, this.path);
    var attributes;
    for (var i = 0, len = trace.length; i < len; i++) {
      var value = trace[i];
      if (i === 0) {
        attributes = makeAttributes({schema: value.schema, value: newValue});
      } else {
        attributes = value.onChildUpdate(prevValue.key, attributes);
      }
      var prevValue = value;
    }
    var dirty = this._makeDirty();
    var root;
    var pendingRootRef = () => root;
    root = new this.root.constructor(
      this.root._attributes.merge(attributes),
      this._root.merge({dirty, pendingRootRef}),
      []
    );
    var n = root.childIn(this.path);
    return n;
  }

  onChildUpdate(key, {value, validation, serialized}) {
    value = this.value.set(key, value);

    var schema = this.schema;
    var newSchema = instantiateSchema(this._attributes.schema, value);
    if (!schema.equals(newSchema)) {
      return makeAttributes({schema: newSchema, value}, {strip: true});
    }
    validation = this.validation.updateChild(key, validation);
    validation = validate(this.schema, value, validation.children).validation;
    serialized = this.serialized.set(key, serialized);
    return this._attributes.merge({value, serialized, validation});
  }

  updateChild(key, newValue) {
    return this.child(key).update(newValue).root();
  }

  updateChildIn(keyPath, newValue) {
    return this.childIn(keyPath).update(newValue).root();
  }

  updateSchema(newSchema) {
    // TODO: Should we try to keep serialized for unchanged parts of schema?
    var {_attributes: {value, externalValidation, dirty, onUpdate, rootRef}} = this.root;
    return make(newSchema, value, externalValidation, onUpdate, dirty, rootRef);
  }

  updateExternalValidation(newExternalValidation) {
    // TODO: Should we try to keep serialized for unchanged parts of schema?
    var {_attributes: {schema, value, dirty, onUpdate, rootRef}} = this.root;
    return make(schema, value, newExternalValidation, onUpdate, dirty, rootRef);
  }

  _makeDirty() {
    var dirty = this._root.get('dirty');
    return dirty.updateIn(this.path.concat(DIRTY_KEY), () => true);
  }

  markDirty() {
    var dirty = this._makeDirty();
    var root;
    var pendingRootRef = () => root;
    root = new this.root.constructor(
      this.root._attributes,
      this.root._root.merge({dirty, pendingRootRef}),
      []
    );
    return root.childIn(this.path);
  }

  markAsConsistent() {
    return new this.constructor(
      this._attributes,
      this._root.merge({pendingRootRef: null}),
      this.path
    );
  }

  notify() {
    var onUpdate = this._root.get('onUpdate', emptyFunction)
    onUpdate(this);
    return this;
  }
}

Object.defineProperty(Value.prototype, 'key', {
  get: function() {
    if (this.path.length === 0) {
      return null;
    } else {
      return this.path[this.path.length - 1];
    }
  }
});

Object.defineProperty(Value.prototype, 'root', {
  get: function() {
    var ref = this._root.get('pendingRootRef');<commit_msg>Value: fix schema update<commit_after>/**
 * @jsx React.DOM
 * @preventMunge
 * @copyright Prometheus Research, LLC 2014
 */
'use strict';

var {Vector, Map, OrderedMap, Record}            = require('immutable');
var {isSchema, isList, isMapping, isScalar}      = require('./schema');
var ValidationResult                             = require('./ValidationResult');
var mergeInto                                    = require('./mergeInto');
var merge                                        = require('./merge');
var invariant                                    = require('./invariant');
var validate                                     = require('./validate');
var emptyFunction                                = require('./emptyFunction');
var toArray                                      = require('./toArray');

var DIRTY_KEY = '__react_forms_dirty__';

/**
 * Serves as a immutable container for form value attributes.
 */
var ValueAttributes = Record({
  schema: null,
  value: null,
  validation: null,
  externalValidation: null,
  serialized: null
}, 'ValueAttributes');

/**
 * Reference to the current form value.
 */
class Value {

  constructor(attributes, root, path) {
    this._attributes = attributes;
    this._root = root;
    this._cache = {};
    this._schema = null;
    this.path = path;
  }

  equals(other) {
    return (
      this.path.toString() === other.path.toString() &&
      this.schema.equals(other.schema) &&
      (
        this.value && this.value.equals ?
        this.value.equals(other.value) :
        this.value === other.value
      ) &&
      (
        this.serialized && this.serialized.equals ?
        this.serialized.equals(other.serialized) :
        this.serialized === other.serialized
      ) &&
      this.validation.equals(other.validation) &&
      this.externalValidation.equals(other.externalValidation) &&
      this.dirty === other.dirty &&
      this._root.get('onUpdate') === other._root.get('onUpdate')
    );
  }

  _child(key) {
    if (this._cache[key]) {
      return this._cache[key];
    }

    var schema = this.schema.child(key);
    var value = this.value.get(key);
    var schemaInstance = instantiateSchema(schema, value);
    var serialized = this.serialized.get(key);
    var validation = this.validation.child(key);
    var externalValidation = this.externalValidation.child(key);

    var attributes;
    if (value === undefined) {
      value = _defaultValue(schemaInstance);
      attributes = makeAttributes({schema, value, serialized, validation, externalValidation});
    } else {
      attributes = {schema, value, serialized, validation, externalValidation};
    }

    var ctor = _getCtor(schemaInstance);
    return (this._cache[key] = new ctor(
      this._attributes.merge(attributes),
      this._root,
      this.path.concat(key)
    ));
  }

  child(...key) {
    var value = this;
    for (var i = 0, len = key.length; i < len; i++) {
      value = value._child(key[i]);
    }
    return value;
  }

  childIn(keyPath) {
    return this.child.apply(this, keyPath);
  }

  update(newValue) {
    var trace = valueTraceByPath(this.root, this.path);
    var attributes;
    for (var i = 0, len = trace.length; i < len; i++) {
      var value = trace[i];
      if (i === 0) {
        attributes = makeAttributes({schema: value.schema, value: newValue});
      } else {
        attributes = value.onChildUpdate(prevValue.key, attributes);
      }
      var prevValue = value;
    }
    var dirty = this._makeDirty();
    var root;
    var pendingRootRef = () => root;
    root = new this.root.constructor(
      this.root._attributes.merge(attributes),
      this._root.merge({dirty, pendingRootRef}),
      []
    );
    var n = root.childIn(this.path);
    return n;
  }

  onChildUpdate(key, {value, validation, serialized}) {
    value = this.value.set(key, value);

    var schema = this.schema;
    var newSchema = instantiateSchema(this._attributes.schema, value);
    if (!schema.equals(newSchema)) {
      return makeAttributes({schema: newSchema, value}, {strip: true});
    }
    validation = this.validation.updateChild(key, validation);
    validation = validate(this.schema, value, validation.children).validation;
    serialized = this.serialized.set(key, serialized);
    return this._attributes.merge({value, serialized, validation});
  }

  updateChild(key, newValue) {
    return this.child(key).update(newValue).root();
  }

  updateChildIn(keyPath, newValue) {
    return this.childIn(keyPath).update(newValue).root();
  }

  updateSchema(newSchema) {
    // TODO: Should we try to keep serialized for unchanged parts of schema?
    var {_attributes: {value, externalValidation}} = this.root;
    return make(
      newSchema, value, externalValidation,
      this._root.get('onUpdate'),
      this._root.get('dirty'),
      this._root.get('rootRef'));
  }

  updateExternalValidation(newExternalValidation) {
    // TODO: Should we try to keep serialized for unchanged parts of schema?
    var {_attributes: {schema, value}} = this.root;
    return make(
      schema, value, newExternalValidation,
      this._root.get('onUpdate'),
      this._root.get('dirty'),
      this._root.get('rootRef'));
  }

  _makeDirty() {
    var dirty = this._root.get('dirty');
    return dirty.updateIn(this.path.concat(DIRTY_KEY), () => true);
  }

  markDirty() {
    var dirty = this._makeDirty();
    var root;
    var pendingRootRef = () => root;
    root = new this.root.constructor(
      this.root._attributes,
      this.root._root.merge({dirty, pendingRootRef}),
      []
    );
    return root.childIn(this.path);
  }

  markAsConsistent() {
    return new this.constructor(
      this._attributes,
      this._root.merge({pendingRootRef: null}),
      this.path
    );
  }

  notify() {
    var onUpdate = this._root.get('onUpdate', emptyFunction);
    onUpdate(this);
    return this;
  }
}

Object.defineProperty(Value.prototype, 'key', {
  get: function() {
    if (this.path.length === 0) {
      return null;
    } else {
      return this.path[this.path.length - 1];
    }
  }
});

Object.defineProperty(Value.prototype, 'root', {
  get: function() {
    var ref = this._root.get('pendingRootRef');
{'fraction_non_alphanumeric': 0.13723577235772358, 'fraction_numerical': 0.0014634146341463415, 'mean_word_length': 2.632900177200236, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2519224', 'n_tokens_mistral': 3615, 'n_tokens_neox': 3542, 'n_words': 796}