Skip to content

Instantly share code, notes, and snippets.

@getify
Last active November 10, 2025 21:10
Show Gist options
  • Select an option

  • Save getify/e1837be7f3084e6ece78e9031b59bd68 to your computer and use it in GitHub Desktop.

Select an option

Save getify/e1837be7f3084e6ece78e9031b59bd68 to your computer and use it in GitHub Desktop.

Revisions

  1. getify revised this gist Oct 14, 2025. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion todoovy-preview-1.js
    Original file line number Diff line number Diff line change
    @@ -35,7 +35,7 @@ function saveNewTodo(newTodoText){
    var { value: newTodoEntry } = yield applyState(
    State.do(function*(){
    var todoID = yield nextTodoID;
    var todoRecord = yield makeTodoRecord(newTodoText)(todoID);
    var todoRecord = makeTodoRecord(newTodoText)(todoID);
    return appendTodoRecord(todoRecord);
    })
    );
  2. getify revised this gist Oct 12, 2025. 2 changed files with 40 additions and 41 deletions.
    18 changes: 8 additions & 10 deletions todoovy-preview-1.js
    Original file line number Diff line number Diff line change
    @@ -30,17 +30,15 @@ function appendTodoRecord(newTodoRecord) {
    }

    function saveNewTodo(newTodoText){
    return IO.do(function*({ state: curState }){
    var {
    value: newTodoEntry,
    state: newState
    } = (
    nextTodoID
    .map(makeTodoRecord(newTodoText))
    .chain(appendTodoRecord)
    .evaluate(curState)
    return IO.do(function*(){
    // update state
    var { value: newTodoEntry } = yield applyState(
    State.do(function*(){
    var todoID = yield nextTodoID;
    var todoRecord = yield makeTodoRecord(newTodoText)(todoID);
    return appendTodoRecord(todoRecord);
    })
    );
    yield saveState(newState);
    return newTodoEntry;
    });
    }
    63 changes: 32 additions & 31 deletions todoovy-preview-2.js
    Original file line number Diff line number Diff line change
    @@ -1,45 +1,46 @@
    // ..

    function toggleTodoComplete(todoID) {
    return IO.doEither(function*({ state: curState }){
    // note: "throws" if not found
    var [ todoRecordIdx, todoRecord ] = (
    yield expectTodoEntry(todoID)
    );
    return IO.do(function*(){
    // update state
    var { state: newState } = yield applyState(
    State.do(function*(){
    // find Todo record (throws if not found)
    var [ todoRecordIdx, todoRecord ] = (
    yield expectTodoEntry(
    todoID,
    `Todo (${todoID}) state record not found`
    )
    );

    // update and preserve state
    var { state: newState } = (
    State.of(todoRecord)
    .map(todoRec => ({
    ...todoRec,
    // update Todo record
    var updatedTodoRecord = {
    ...todoRecord,

    // toggle complete flag
    complete: !todoRec.complete
    }))
    .chain(updatedTodoRecord => State(st => ({
    state: {
    ...st,
    complete: !todoRecord.complete
    };

    // update state
    return State.modify(state => ({
    ...state,

    // splice in updated Todo record
    todos: [
    ...st.todos.slice(0,todoRecordIdx),
    updatedTodoRecord,
    ...st.todos.slice(todoRecordIdx + 1)
    ]
    }
    })))
    .evaluate(curState)
    // splice in updated Todo record
    todos: [
    ...state.todos.slice(0,todoRecordIdx),
    updatedTodoRecord,
    ...state.todos.slice(todoRecordIdx + 1)
    ]
    }));
    })
    );
    yield saveState(newState);

    // toggle completed visual marking for Todo element
    return (
    expectPresent(
    querySelector(`li[data-id='${todoID}']`)(curState.todosEl),
    `Todo (${todoID}) element not found`
    )
    .chain(tapIO(toggleClass("complete")))
    var todoElement = yield expectElement(
    querySelector(`li[data-id='${todoID}']`)(newState.todosEl),
    `Todo (${todoID}) element not found`
    );
    return toggleClass("complete")(todoElement);
    });
    }

  3. getify revised this gist Oct 9, 2025. 1 changed file with 24 additions and 17 deletions.
    41 changes: 24 additions & 17 deletions todoovy-preview-2.js
    Original file line number Diff line number Diff line change
    @@ -1,34 +1,41 @@
    // ..

    function toggleTodoComplete(todoID) {
    return IO.doEither(function*({ state }){
    return IO.doEither(function*({ state: curState }){
    // note: "throws" if not found
    var [ todoRecordIdx, todoRecord ] = (
    yield expectTodoEntry(todoID)
    );

    // toggle complete flag
    todoRecord = {
    ...todoRecord,
    complete: !todoRecord.complete
    };
    // update and preserve state
    var { state: newState } = (
    State.of(todoRecord)
    .map(todoRec => ({
    ...todoRec,

    // preserve updated state
    yield saveState({
    ...state,
    // toggle complete flag
    complete: !todoRec.complete
    }))
    .chain(updatedTodoRecord => State(st => ({
    state: {
    ...st,

    // splice in updated Todo record
    todos: [
    ...state.todos.slice(0,todoRecordIdx),
    todoRecord,
    ...state.todos.slice(todoRecordIdx + 1)
    ]
    });
    // splice in updated Todo record
    todos: [
    ...st.todos.slice(0,todoRecordIdx),
    updatedTodoRecord,
    ...st.todos.slice(todoRecordIdx + 1)
    ]
    }
    })))
    .evaluate(curState)
    );
    yield saveState(newState);

    // toggle completed visual marking for Todo element
    return (
    expectPresent(
    querySelector(`li[data-id='${todoID}']`)(state.todosEl),
    querySelector(`li[data-id='${todoID}']`)(curState.todosEl),
    `Todo (${todoID}) element not found`
    )
    .chain(tapIO(toggleClass("complete")))
  4. getify revised this gist Oct 9, 2025. 1 changed file with 30 additions and 25 deletions.
    55 changes: 30 additions & 25 deletions todoovy-preview-1.js
    Original file line number Diff line number Diff line change
    @@ -1,42 +1,47 @@
    // ..

    const nextTodoID = State(st => {
    var todoCounter = (st.todoCounter ?? 0) + 1;
    const nextTodoID = State(state => {
    var todoCounter = (state.todoCounter ?? 0) + 1;
    return {
    value: todoCounter,
    state: {
    ...st,
    ...state,
    todoCounter
    }
    };
    });

    function getNextTodoID() {
    return IO(({ state }) => nextTodoID.evaluate(state));
    function makeTodoRecord(newTodoText) {
    return todoID => ({
    id: todoID,
    todo: newTodoText,
    complete: false
    });
    }

    function appendTodoRecord(newTodoRecord) {
    return State(state => ({
    value: newTodoRecord,
    state: {
    ...state,
    todos: [ ...state.todos, newTodoRecord ]
    }
    }));
    }

    function saveNewTodo(newTodo) {
    // compute and add new todo entry
    return IO.do(function*(){
    function saveNewTodo(newTodoText){
    return IO.do(function*({ state: curState }){
    var {
    value: todoID,
    value: newTodoEntry,
    state: newState
    } = yield getNextTodoID();

    var newTodoRecord = {
    id: todoID,
    todo: newTodo,
    complete: false
    };

    // preserve updated state
    yield saveState({
    ...newState,

    todos: [ ...newState.todos, newTodoRecord ]
    });

    return newTodoRecord;
    } = (
    nextTodoID
    .map(makeTodoRecord(newTodoText))
    .chain(appendTodoRecord)
    .evaluate(curState)
    );
    yield saveState(newState);
    return newTodoEntry;
    });
    }

  5. getify revised this gist Oct 9, 2025. 2 changed files with 19 additions and 13 deletions.
    26 changes: 14 additions & 12 deletions todoovy-preview-1.js
    Original file line number Diff line number Diff line change
    @@ -1,25 +1,27 @@
    // ..

    const nextTodoID = State(st => {
    var todoCounter = (st.todoCounter ?? 0) + 1;
    return {
    value: todoCounter,
    state: {
    ...st,
    todoCounter
    }
    };
    });

    function getNextTodoID() {
    return State(st => {
    var todoCounter = (st.todoCounter ?? 0) + 1;
    return {
    value: todoCounter,
    state: {
    ...st,
    todoCounter
    }
    };
    });
    return IO(({ state }) => nextTodoID.evaluate(state));
    }

    function saveNewTodo(newTodo) {
    // compute and add new todo entry
    return IO.do(function*({ state }){
    return IO.do(function*(){
    var {
    value: todoID,
    state: newState
    } = getNextTodoID().evaluate(state);
    } = yield getNextTodoID();

    var newTodoRecord = {
    id: todoID,
    6 changes: 5 additions & 1 deletion todoovy-preview-2.js
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    // ..

    function toggleTodoComplete(todoID) {
    return IO.doEither(function*({ state }){
    // note: "throws" if not found
    @@ -32,4 +34,6 @@ function toggleTodoComplete(todoID) {
    .chain(tapIO(toggleClass("complete")))
    );
    });
    }
    }

    // ..
  6. getify revised this gist Oct 9, 2025. 2 changed files with 35 additions and 0 deletions.
    File renamed without changes.
    35 changes: 35 additions & 0 deletions todoovy-preview-2.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,35 @@
    function toggleTodoComplete(todoID) {
    return IO.doEither(function*({ state }){
    // note: "throws" if not found
    var [ todoRecordIdx, todoRecord ] = (
    yield expectTodoEntry(todoID)
    );

    // toggle complete flag
    todoRecord = {
    ...todoRecord,
    complete: !todoRecord.complete
    };

    // preserve updated state
    yield saveState({
    ...state,

    // splice in updated Todo record
    todos: [
    ...state.todos.slice(0,todoRecordIdx),
    todoRecord,
    ...state.todos.slice(todoRecordIdx + 1)
    ]
    });

    // toggle completed visual marking for Todo element
    return (
    expectPresent(
    querySelector(`li[data-id='${todoID}']`)(state.todosEl),
    `Todo (${todoID}) element not found`
    )
    .chain(tapIO(toggleClass("complete")))
    );
    });
    }
  7. getify created this gist Oct 9, 2025.
    41 changes: 41 additions & 0 deletions todoovy-preview.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,41 @@
    // ..

    function getNextTodoID() {
    return State(st => {
    var todoCounter = (st.todoCounter ?? 0) + 1;
    return {
    value: todoCounter,
    state: {
    ...st,
    todoCounter
    }
    };
    });
    }

    function saveNewTodo(newTodo) {
    // compute and add new todo entry
    return IO.do(function*({ state }){
    var {
    value: todoID,
    state: newState
    } = getNextTodoID().evaluate(state);

    var newTodoRecord = {
    id: todoID,
    todo: newTodo,
    complete: false
    };

    // preserve updated state
    yield saveState({
    ...newState,

    todos: [ ...newState.todos, newTodoRecord ]
    });

    return newTodoRecord;
    });
    }

    // ..