Skip to content

Instantly share code, notes, and snippets.


Tom Rogers tomprogers

  • Minneapolis, MN
View GitHub Profile
tomprogers /
Last active Jun 1, 2021
javascript coding guidelines

Javascript coding guidelines

These are listed in no particular order, but are numbered so they can referenced more easily.

  1. No interface should accept data that is not necessary for it to do its job. "Interface" includes: HTTP APIs (e.g. REST), function & method signatures, and React Component props, among others.
  2. Functions and methods should never mutate their arguments. Avoid patterns that rely on mutation of arguments.
  3. Prefer "flatter" codepaths. Nesting lots of if / else statements is hard to follow and re-organize. Bail early using return instead of nesting subsequent code.
  4. Prefer flat data structures instead of deeply nested objects.
  5. If the majority of a routine is inside a loop, extract the core of the loop into a separate routine that operates on a single item.
  6. Extract magic strings and numbers from logic. At minimum, they should be declared as constants at the top of the file that uses them. Ideally, constants that influence observable behavior should be provided by a const
tomprogers / sublime-project-study.js
Created Oct 16, 2018
Script that reads all *.sublime-project files in a directory and aggregates their values
View sublime-project-study.js
const FS = require('fs')
async function readdir(path) {
return new Promise((resolve, reject) => {
FS.readdir(path, (err, data) => {
if(err) reject(err)
else resolve(data)
tomprogers / song-parser.js
Last active Jul 27, 2018
Script for parsing the list of favorite songs on into TSV format
View song-parser.js
// Step 1: open somafm player
// Step 2: click "Favorite Songs"
// Step 3: drag-select all the text from the first song title to shopping cart on last row
// Step 4: copy & paste that text into text2tsv in JS console
// Step 5: paste result into Google Docs and you have a spreadsheet
const text2tsv = (text) => text.split('\n\n \n')
.map( r => r.trim().split('\n\n') )
.map( t => ({ artist: String(t[0]).trim(), title: String(t[1]).trim() }) )
.map( t => `${t.artist}\t${t.title}` )
tomprogers / css-transform-rotate3d.css
Created Jan 14, 2018
micro explainer of CSS 3D transform
View css-transform-rotate3d.css
// x : lean back
// y : revolving door from front
// z : twist clockwise
// transform: rotate3d(0,1,1,45deg);
tomprogers /
Created May 15, 2017
needless eloquence

one of those moments of programming eloquence you hope for, discovered to be unneeded immediately upon finishing it

the final code:

handleWordClick = (word, event) => {
	let isShiftClick = (this.state.shiftActive);
	let [ hasClickFn , hasShiftClickFn ] = [ 'onClick', 'onShiftClick' ].map((p) => (typeof this.props[p] === 'function'));
tomprogers / auto-persister.js
Last active Apr 30, 2017
I wish this existed so I could use it in my Electron app
View auto-persister.js
import Path from 'path';
import AppPaths from 'app-paths';
import Persist from 'auto-persister';
let settings = Persist.manageFile({
path: Path.join(ApPaths.ConfigFile, 'default.myapp-settings'),
json: true, // read & write will marshall JSON automatically
autocreate: true, // file (and parent dirs) will be immediately created if they don't already exist
initialData: DefaultSettings, // value that will be returned if file doesn't exist, and that will be written if autocreate true
tomprogers / browser.js
Last active Jan 19, 2017
I wanted to find out which HTTP status codes cause fetch to resolve, and which to reject
View browser.js
* Map HTTP error codes to fetch's .then/.catch behavior
* List based on
let codes = [
{"code": "100", "text": "Continue"},
{"code": "101", "text": "Switching Protocol"},
{"code": "200", "text": "OK"},
{"code": "201", "text": "Created"},
tomprogers / item-property-tallies.js
Created Aug 24, 2016
algorithm for counting the names and datatypes of properties of a set of (hopefully) similarly-shaped object
View item-property-tallies.js
// before running this, define ITEMS as an array of objects whose props you wish to examine
items.reduce((tallies, asset) => {
.forEach((prop) => {
if(tallies.hasOwnProperty(`${prop} (${typeof asset[prop]})`)) {
console.log(`has ${prop} (${typeof asset[prop]})`);
tallies[`${prop} (${typeof asset[prop]})`] += 1;
tomprogers / react-native-list-view-clone-args.js
Created May 20, 2016
An explanation of the structures and interpretations of the arguments to cloneWithRowsAndSections
View react-native-list-view-clone-args.js
// somewhere, you had to set this up
const LVDS = new ListView.DataSource({
getSectionHeaderData: (blob, sectionId) => blob.sectionData[sectionId],
getRowData: (blob, sectionId, rowId) => blob.rowData[rowId]
// ... and then you had to feed data into it with this:
let newListData = LVDS.cloneWithRowsAndSections(blob, sectionIds, rowIdsBySection)
// but what do blob, sectionIds, and rowIdsBySection look like, and how are they used internally by ListView?
tomprogers / react-native-list-view-eg.js
Last active May 20, 2016
Example code showing how to work with react-native's ListView, with sticky headers and lots of explanatory comments
View react-native-list-view-eg.js
// NOTE: I'm using a few ES6 features, like Arrow Functions and default argument values
// Hopefully they don't trip you up while reading this.
import React, { Component, ListView } from 'react-native';
import Moment from 'moment'; // only needed for my example
// I reuse this configuration everywhere. As a rule, each component creates just one of them,
// and since changing the dataset doesn't require mutating this object, I define it as a const.