<commit_before>import { TabInstances, TabData, TabDataSave, TabInstance } from "common/types";
import { actions } from "common/actions";
import reducer from "common/reducers/reducer";

import { omit, each, size } from "underscore";

const initialState: TabInstances = {};

const emptyObj = {} as any;
const maxHistorySize = 50;

function trimHistory(ti: TabInstance): TabInstance {
  if (!ti || !ti.history) {
    return ti;
  }

  const historySize = size(ti.history);
  if (historySize <= maxHistorySize) {
    return ti;
  }

  let offset = maxHistorySize - historySize;
  let newIndex = ti.currentIndex - offset;
  let newHistory = ti.history.slice(offset);
  if (newIndex < 0 || newIndex >= size(newHistory)) {
    newIndex = size(newHistory) - 1;
  }

  return {
    ...ti,
    currentIndex: newIndex,
    history: newHistory,
  };
}

let deepFields = ["web"];

function merge(
  a: TabData,
  b: TabData,
  { shallow }: { shallow?: boolean }
): TabData {
  if (shallow) {
    return { ...a, ...b };
  }

  const res = {
    ...a,
    ...b,
  };
  for (const df of deepFields) {
    (res as any)[df] = {
      ...((a as any)[df] || emptyObj),
      ...((b as any)[df] || emptyObj),
    };
  }
  return res;
}

export default reducer<TabInstances>(initialState, on => {
  on(actions.windOpened, (state, action) => {
    const { initialURL } = action.payload;
    return {
      ...state,
      ["initial-tab"]: {
        history: [{ url: initialURL }],
        currentIndex: 0,
        sleepy: true,
        sequence: 0,
        data: {},
      },
    };
  });

  on(actions.tabDataFetched, (state, action) => {
    const { tab, data, shallow } = action.payload;
    const oldInstance = state[tab];
    if (!oldInstance) {
      // ignore fresh data for closed tabs
      return state;
    }

    let newData = merge(oldInstance.data, data, { shallow });

    return {
      ...state,
      [tab]: {<commit_msg>Keep TabInstance ref-equal if it was deep-equal (simplifies stuff on the renderer side..)<commit_after>import { TabInstances, TabData, TabDataSave, TabInstance } from "common/types";
import { actions } from "common/actions";
import reducer from "common/reducers/reducer";

import { omit, each, size } from "underscore";
import deepEqual from "deep-equal";

const initialState: TabInstances = {};

const emptyObj = {} as any;
const maxHistorySize = 50;

function trimHistory(ti: TabInstance): TabInstance {
  if (!ti || !ti.history) {
    return ti;
  }

  const historySize = size(ti.history);
  if (historySize <= maxHistorySize) {
    return ti;
  }

  let offset = maxHistorySize - historySize;
  let newIndex = ti.currentIndex - offset;
  let newHistory = ti.history.slice(offset);
  if (newIndex < 0 || newIndex >= size(newHistory)) {
    newIndex = size(newHistory) - 1;
  }

  return {
    ...ti,
    currentIndex: newIndex,
    history: newHistory,
  };
}

let deepFields = ["web"];

function merge(
  a: TabData,
  b: TabData,
  { shallow }: { shallow?: boolean }
): TabData {
  if (shallow) {
    return { ...a, ...b };
  }

  const res = {
    ...a,
    ...b,
  };
  for (const df of deepFields) {
    (res as any)[df] = {
      ...((a as any)[df] || emptyObj),
      ...((b as any)[df] || emptyObj),
    };
  }
  return res;
}

export default reducer<TabInstances>(initialState, on => {
  on(actions.windOpened, (state, action) => {
    const { initialURL } = action.payload;
    return {
      ...state,
      ["initial-tab"]: {
        history: [{ url: initialURL }],
        currentIndex: 0,
        sleepy: true,
        sequence: 0,
        data: {},
      },
    };
  });

  on(actions.tabDataFetched, (state, action) => {
    const { tab, data, shallow } = action.payload;
    const oldInstance = state[tab];
    if (!oldInstance) {
      // ignore fresh data for closed tabs
      return state;
    }

    let newData = merge(oldInstance.data, data, { shallow });
    if (deepEqual(oldInstance.data, newData)) {
      return state;
    }

    return {
      ...state,
      [tab]: {
{'fraction_non_alphanumeric': 0.1525634644101543, 'fraction_numerical': 0.0029865604778496766, 'mean_word_length': 2.6142086330935252, 'pattern_counts': {'":': 0, '<': 9, '<?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': '6427198', 'n_tokens_mistral': 1342, 'n_tokens_neox': 1305, 'n_words': 351}