<commit_before>'use strict';

import invariant from 'invariant';
import { Seq, List } from 'immutable';
import Cursor from 'immutable/contrib/cursor'

import { ancestorKinds } from '../data/element';

import { forAction, forKindAndType } from './';

import readReducer from '../read/reducer';

/**
 * Main application reducer.
 *
 * @param cursor The cursor representing the state.
 * @param action The action.
 * @returns {*} The new state represented by updated cursor.
 */
export default function(cursor, action) {
  // console.log('Reducer: action:', action);
  invariant(
    cursor != null && cursor._keyPath != null,
    "The reducer is meant to work only with cursors");

  const fromKind = action.fromKind;
  const fromPath = action.fromPath;
  if (fromKind && fromPath) {
    const type = action.type;

    // handle reads
    if (type.startsWith('READ')) {
      return readReducer(cursor, action);
    }

    // handle global updates
    if (type.startsWith('.')) {
      const resultFromLookup = parents(cursor.getIn(fromPath))
        .filter(parent => !!parent.get('kind'))
        .map(parent => {
          const parentKind = parent.get('kind');
          const updatesPerAncestor = ancestorKinds(parentKind)
            .map(ancestorKind => forKindAndType(ancestorKind, type))
            .filter(update => !!update);
          return {
            element: parent,
            update: updatesPerAncestor.first()
          }
        })
        .filter(parent => !!parent.update)
        .first();
      if (resultFromLookup) {
        const { element, update } = resultFromLookup;
        if (element && update) {
          return cursor.setIn(element._keyPath, update(element.deref(), action));
        }
      }
      return cursor;
    }

    // handle local updates
    const update = forAction(action);
    if (update) {
      const element = cursor.getIn(fromPath);
      return cursor.setIn(fromPath, update(element.deref(), action));
    }

  }
  return cursor;
}

/**
 * Gets the parent value of this cursor. returns null if this is the root cursors.
 */
function parent(cursor: any): any {
  if (cursor == null) {
    return null;
  }
<commit_msg>fix(core): Safe-guard local updates in cases where element has changed.<commit_after>'use strict';

import invariant from 'invariant';
import { Seq, List } from 'immutable';
import Cursor from 'immutable/contrib/cursor'

import { ancestorKinds } from '../data/element';

import { forAction, forKindAndType } from './';

import readReducer from '../read/reducer';

/**
 * Main application reducer.
 *
 * @param cursor The cursor representing the state.
 * @param action The action.
 * @returns {*} The new state represented by updated cursor.
 */
export default function(cursor, action) {
  // console.log('Reducer: action:', action);
  invariant(
    cursor != null && cursor._keyPath != null,
    "The reducer is meant to work only with cursors");

  const fromKind = action.fromKind;
  const fromPath = action.fromPath;
  if (fromKind && fromPath) {
    const type = action.type;

    // handle reads
    if (type.startsWith('READ')) {
      return readReducer(cursor, action);
    }

    // handle global updates
    if (type.startsWith('.')) {
      const resultFromLookup = parents(cursor.getIn(fromPath))
        .filter(parent => !!parent.get('kind'))
        .map(parent => {
          const parentKind = parent.get('kind');
          const updatesPerAncestor = ancestorKinds(parentKind)
            .map(ancestorKind => forKindAndType(ancestorKind, type))
            .filter(update => !!update);
          return {
            element: parent,
            update: updatesPerAncestor.first()
          }
        })
        .filter(parent => !!parent.update)
        .first();
      if (resultFromLookup) {
        const { element, update } = resultFromLookup;
        if (element && update) {
          return cursor.setIn(element._keyPath, update(element.deref(), action));
        }
      }
      return cursor;
    }

    // handle local updates
    const update = forAction(action);
    const element = cursor.getIn(fromPath);
    if (element && update) {
      return cursor.setIn(fromPath, update(element.deref(), action));
    } else {
      console.warn("Unable to perform local update, element has changed in meantime...");
      return cursor;
    }
  }
  return cursor;
}

/**
 * Gets the parent value of this cursor. returns null if this is the root cursors.
 */
function parent(cursor: any): any {
  if (cursor == null) {
    return null;
  }

{'fraction_non_alphanumeric': 0.1277533039647577, 'fraction_numerical': 0.0, 'mean_word_length': 2.691869918699187, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7539499', 'n_tokens_mistral': 1309, 'n_tokens_neox': 1287, 'n_words': 373}