<commit_before>// @flow weak

import React, { Component, PropTypes } from 'react';

export const APPEAR = 'APPEAR';
export const UPDATE = 'UPDATE';
export const REMOVE = 'REMOVE';
export const REVIVE = 'REVIVE';

const keyToString = (d) => `key-${d}`;

const keyAccessor = (d, i) => {
  if (typeof d === 'number' || typeof d === 'string') {
    return keyToString(d);
  } else if (d.id) {
    return keyToString(d.id);
  } else if (d.udid) {
    return keyToString(d.udid);
  }

  return keyToString(i);
};

const composeNode = (data, type, udid) => {
  if (typeof data === 'number' || typeof data === 'string') {
    return { data, type, udid };
  }

  return { ...data, type, udid };
};

export default function withSelection(SelectionItem) {
  class Selection extends Component {
    constructor(props) {
      super(props);

      this.state = {
        nodes: [],
        udids: {},
      };
    }

    componentDidMount() {
      if (this.props.data) {
        this.updateNodes(this.props.data);
      }
    }

    componentWillReceiveProps(next) {
      if (this.props.data !== next.data) {
        this.updateNodes(next.data);
      }
    }

    updateNodes(data) {
      const nodes = [];
      const udids = {};

      let index = 0;

      for (let len = data.length; index < len; index++) {
        const udid = keyAccessor(data[index], index, data);

        let type = APPEAR;

        if (this.state.udids[udid]) {
          if (this.state.udids[udid].type === REMOVE) {
            type = REVIVE;
          } else {
            type = UPDATE;
          }
        }

        nodes.push(composeNode(data[index], type, udid));
        udids[udid] = { type, index };
      }


      for (let i = 0, len = this.state.nodes.length; i < len; i++) {
        const node = this.state.nodes[i];
        const type = REMOVE;

        if (!udids[node.udid] && node.type !== REMOVE) {
          nodes.push(composeNode(node, REMOVE, node.udid));
          udids[node.udid] = { type, index: index++ };
        }
      }

      this.setState({ nodes, udids });
    }

    removeNode(udid) {
      const { udids, nodes } = this.state;
      const { index } = udids[udid];

      delete udids[udid];     // mutating state for performance :/
      nodes.splice(index, 1); // mutating state for performance :/
    }

    render() {
      return (
        <g>
          {this.state.nodes.map((node) => {
            return (
              <SelectionItem<commit_msg>use immutable OrderedMap for state<commit_after>// @flow weak

import React, { Component, PropTypes } from 'react';
import Immutable from 'immutable';

export const APPEAR = 'APPEAR';
export const UPDATE = 'UPDATE';
export const REMOVE = 'REMOVE';
export const REVIVE = 'REVIVE';

const keyToString = (d) => `key-${d}`;

const keyAccessor = (d, i) => {
  if (typeof d === 'number' || typeof d === 'string') {
    return keyToString(d);
  } else if (d.id) {
    return keyToString(d.id);
  } else if (d.udid) {
    return keyToString(d.udid);
  }

  return keyToString(i);
};

const composeNode = (data, type, udid) => {
  if (typeof data === 'number' || typeof data === 'string') {
    return { data, type, udid };
  }

  return { ...data, type, udid };
};

export default function withSelection(SelectionItem) {
  class Selection extends Component {
    constructor(props) {
      super(props);

      this.state = {
        nodes: new Immutable.OrderedMap(),
      };
    }

    componentDidMount() {
      if (this.props.data) {
        this.updateNodes(this.props.data);
      }
    }

    componentWillReceiveProps(next) {
      if (this.props.data !== next.data) {
        this.updateNodes(next.data);
      }
    }

    updateNodes(data) {
      let nodes = new Immutable.OrderedMap();

      let index = 0;

      for (let len = data.length; index < len; index++) {
        const udid = keyAccessor(data[index], index, data);
        const node = this.state.nodes.get(udid);

        let type = APPEAR;

        if (node) {
          if (node.type === REMOVE) {
            type = REVIVE;
          } else {
            type = UPDATE;
          }
        }

        nodes = nodes.set(udid, composeNode(data[index], type, udid));
      }

      this.state.nodes.toSeq().forEach((node) => {
        if (!nodes.has(node.udid) && node.type !== REMOVE) {
          nodes = nodes.set(node.udid, composeNode(node, REMOVE, node.udid));
        }
      });

      this.setState({ nodes });
    }

    removeNode(udid) {
      const { nodes } = this.state;
      this.setState({ nodes: nodes.delete(udid) });
    }

    render() {
      return (
        <g>
          {this.state.nodes.toArray().map((node) => {
            return (
              <SelectionItem
{'fraction_non_alphanumeric': 0.1536668079694786, 'fraction_numerical': 0.000847816871555744, 'mean_word_length': 2.1251655629139075, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 14, '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': '683925', 'n_tokens_mistral': 1556, 'n_tokens_neox': 1508, 'n_words': 360}