<commit_before>import _, {atom, derive, transact} from 'havelock'
import imut, {fromJS} from 'immutable'
import React from 'react'

/*** Global App State ***/
const nextId = atom(0);
function getNextId () {
  return _.swap(nextId, x => x+1);
}

const todos = atom(fromJS([]));
const hash = atom(window.location.hash);
const newTodoName = atom("");

window.addEventListener('hashchange', () => {
  hash.set(window.location.hash);
});

{
  let existingTodos;
  if ((existingTodos = localStorage['todos'])) {
    todos.set(fromJS(JSON.parse(existingTodos)).map(x => x.set('id', getNextId())));
  }
}

todos.react(todos => {
  localStorage['todos'] = JSON.stringify(todos.toJS());
});

/*** Business Logic ***/
function newTodo (todos, description) {
  if (description.trim().length === 0) {
    return todos;
  } else {
    let id = nextId.get();
    nextId.set(id + 1);
    return todos.push(fromJS({
      description,
      id: id,
      complete: false,
      editing: false
    }));
  }
}

function clearCompleted (todos) {
  return todos.filter(t => t.complete);
}

function toggleComplete (todos, idx) {
  return todos.updateIn([idx, 'complete'], x => !x);
}

function deleteTodo (todos, idx) {
  return todos.delete(idx);
}

function editingTodo (todos, idx, editing) {
  return todos.setIn([idx, 'editing'], editing);
}

function editTodo (todos, idx, newDescription) {
  if (newDescription.trim().length === 0) {
    return deleteTodo(todos, idx);
  } else {
    return todos.setIn([idx, 'description'], newDescription);
  }
}

function markAll (todos, complete) {
  return todos.map(t => t.set('complete', complete));
}


/*** Derived Data ***/

const numTodos = todos.derive(ts => ts.size);

const numRemaining = todos.derive(ts => ts.filter(t => !t.get("complete")).size);

const allComplete = numTodos.and(numRemaining.not());
const allIncomplete = numTodos.is(numRemaining);

const showing = hash.switch(
  "#/active", "active",
  "#/completed", "completed",
  "all"
);


/*** VIEW ***/

// helpers<commit_msg>todo: fix a few smells<commit_after>import _, {atom, derive, transact} from 'havelock'
import imut, {fromJS} from 'immutable'
import React from 'react'

/*** Global App State ***/
const nextId = atom(0); // uids for the list items to make react happy
function getNextId () {
  return _.swap(nextId, x => x+1);
}

const todos = atom(fromJS([]));
const hash = atom(window.location.hash);
const newTodoName = atom("");

window.addEventListener('hashchange', () => {
  hash.set(window.location.hash);
});

{
  let existingTodos;
  if ((existingTodos = localStorage['todos'])) {
    todos.set(fromJS(JSON.parse(existingTodos))
                .map(x => x.set('id', getNextId()))
                .toList());
  }
}

todos.react(todos => {
  localStorage['todos'] = JSON.stringify(todos.toJS());
});

/*** Business Logic ***/
function newTodo (todos, description) {
  if (description.trim().length === 0) {
    return todos;
  } else {
    return todos.push(fromJS({
      description,
      id: getNextId(),
      complete: false,
      editing: false
    }));
  }
}

function clearCompleted (todos) {
  return todos.filter(t => t.complete).toList();
}

function toggleComplete (todos, idx) {
  return todos.updateIn([idx, 'complete'], x => !x);
}

function deleteTodo (todos, idx) {
  return todos.delete(idx);
}

function editingTodo (todos, idx, editing) {
  return todos.setIn([idx, 'editing'], editing);
}

function editTodo (todos, idx, newDescription) {
  if (newDescription.trim().length === 0) {
    return deleteTodo(todos, idx);
  } else {
    return todos.setIn([idx, 'description'], newDescription);
  }
}

function markAll (todos, complete) {
  return todos.map(t => t.set('complete', complete)).toList();
}


/*** Derived Data ***/

const numTodos = todos.derive(ts => ts.size);

const numRemaining = todos.derive(ts => ts.filter(t => !t.get("complete")).size);

const allComplete = numTodos.and(numRemaining.not());
const allIncomplete = numTodos.is(numRemaining);

const showing = hash.switch(
  "#/active", "active",
  "#/completed", "completed",
  "all"
);


/*** VIEW ***/

// helpers
{'fraction_non_alphanumeric': 0.18159747511531926, 'fraction_numerical': 0.0021849963583394027, 'mean_word_length': 3.993939393939394, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 23, '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': '7421894', 'n_tokens_mistral': 1451, 'n_tokens_neox': 1452, 'n_words': 321}