I've been spending some free time refactoring an OSS project I took over when the original dev sold the Chrome store app to a malware company; users have been asking for new features.

joshperry/Tab-Manager
The source code of the google chrome extension “Tab Manager” - joshperry/Tab-Manager

It was suffering from severe bitrot (react v0.12) and a raft of antipatterns (forceUpdate * 20) so I figured it would be a good candidate to help people and sharpen my frontend skills at the same time.

As I was working on some refactoring I noticed that some of my code was beginning to get rather terse and difficult to reason about. Terseness is nice, but code that can't be maintained is a liability, not an asset.

So I decided to kata on a single piece of functionality to help polish my feel for balance in the force.

// Tab was closed, remove tab from models if !isWindowClosing
chrome.tabs.onRemoved.addListener((rid, ri) => ri.isWindowClosing || setCache(cache =>
  cache.map(w => ({ ...w,  ...w.id === ri.windowId && { tabs: w.tabs.filter(t => t.id !== rid) } }))
))
clever, but what does this even do?

Almost maximum expansion of the same logic, and much more readable. However, I realized that I also need some of this functionality in a few other places.

// Tab was closed
chrome.tabs.onRemoved.addListener((tabid, removeInfo) => {
  // If the window is closing, window handler will nuke this data
  if(!removeInfo.isWindowClosing) {
    // Update the cache state by filtering out the removed tab
    setCache(wincache => wincache.map(window => {
      if(window.id === removeInfo.windowId) {
        window.tabs = window.tabs.filter(tab => tab.id !== tabid)
      }
      return window
    }))
  }
})
my eyes no longer bleed

As I began to extract a couple blobs of the logic for reuse, I started feeling again the pull to the dark side of functional programming.

// Maps a function on a parameter according to a predicate, identity otherwise
const mapIf = (pred, func) => param => pred(param) ? func(param) : param

// Takes an object and filters a specd array property given a predicate
const filterProp = (prop, pred) => obj => ({ ...obj, [prop]: obj[prop].filter(pred) })

// Takes a window and filters its tabs based on a predicate
const filterTabsProp = pred => filterProp('tabs', pred)

// Update the cache state by filtering out the removed tab
const removeTab = (windowid, tabid) =>
  setCache(cache => cache.map(
    mapIf(
      window => window.id === windowid,
      filterTabsProp(tab => tab.id !== tabid)
    )
  ))
  
// Tab was closed
chrome.tabs.onRemoved.addListener((tabid, removeInfo) =>
  // If the window is closing, window handler will nuke this data
  removeInfo.isWindowClosing || removeTab(tabid, removeInfo.windowId)
)
yes, I always remember how fp makes me feel

Hrrrm... npm i ramda

import { pipe, when, lensProp, over, reject } from 'ramda'

// Lens to the tabs object property for a window model
const tabsLens = lensProp('tabs')
// Execute some operation over the tabs lens
const overTabs = over(tabsLens)

// Update the cache by filtering out the removed tab
const removeTab = tab => map(
  when(
    window => window.id === tab.windowId,
    overTabs(reject(t => t.id === tab.id))
  )
)
  
// Tab was closed
chrome.tabs.onRemoved.addListener((tabid, removeInfo) =>
  // If the window is closing, window handler will nuke this data
  removeInfo.isWindowClosing ||
    setCache(removeTab({ id: tabid, windowId: removeInfo.windowId }))
)
I don't even see the code

📷: https://www.feastingathome.com/stuffed-butternut-three-ways