Skip to content

Instantly share code, notes, and snippets.

Avatar
💭
Copying and pasting from StackOverflow

Cameron Nokes ccnokes

💭
Copying and pasting from StackOverflow
View GitHub Profile
@ccnokes
ccnokes / heic_to_jpeg.sh
Last active Jun 28, 2020
Bash script that converts .HEIC to .jpg files
View heic_to_jpeg.sh
#!/bin/bash
set -eu -o pipefail
count=$(find . -depth 1 -name "*.HEIC" | wc -l | sed 's/[[:space:]]*//')
echo "converting $count files .HEIC files to .jpg"
magick mogrify -monitor -format jpg *.HEIC
echo "Remove .HEIC files? [y/n]"
@ccnokes
ccnokes / useCallIfMounted.tsx
Last active Apr 6, 2020
React hook that only runs a function if the component is still mounted. React says this is an anti-pattern, but vanilla Promises and async DOM APIs don't give you a way to cancel async actions 🤷‍♂️.
View useCallIfMounted.tsx
function useCallIfMounted() {
let isMounted = React.useRef(false);
React.useEffect(() => {
isMounted.current = true;
return () => isMounted.current = false;
}, [isMounted]);
return React.useCallback((fn) => isMounted.current && fn(), [isMounted]);
}
@ccnokes
ccnokes / memoize.ts
Last active Jul 9, 2020
A memoize function is only as good as its cache
View memoize.ts
// NOTE can't use lodash.memoize because we need 2 caches and v2 doesn't support replacing the cache implementation
// TS type note: the below type is inspired by Lodash v4 types
function memoize<T extends (...args: any) => any>(fn: T, resolver?: (...args: any[]) => any) {
let objectCache = new WeakMap<any, any>(); // WeakMap can only store objects as keys and allows the objects to get GC'ed out
let primitiveCache = new Map<any, any>(); // Map can store anything as a key but no auto GC
return function(...args: Parameters<T>): ReturnType<T> {
// just in case things got out of hand, dump the cache if too many entries
if (primitiveCache.size > 10000) {
primitiveCache.clear();
}
@ccnokes
ccnokes / check-for-electron-apps.sh
Last active May 16, 2020
Bash script that checks for apps that use Electron. Detailed a bit more here: https://cameronnokes.com/blog/how-to-know-if-a-desktop-app-uses-electron/
View check-for-electron-apps.sh
#!/bin/bash
target="${1:-/Applications}"
check() {
stat "$1/Contents/Frameworks/Electron Framework.framework" &> /dev/null
if [[ $? = 0 ]]; then
echo "$1 uses Electron"
fi
}
@ccnokes
ccnokes / ObservableMap.ts
Last active Nov 5, 2019
A Map class with built-in event emitter that emits a `update` event whenever something changes
View ObservableMap.ts
class ObservableMap<K, V> extends Map<K, V> {
readonly events = new EventEmitter();
set(key: K, value: V) {
let previousValue = this.get(key);
super.set(key, value);
this.events.emit("update", {
key,
action: "set",
previousValue,
currentValue: this.get(key)
View event-emitter.js
class EventEmitter {
constructor() {
this.target = new EventTarget();
}
on(eventName, listener) {
return this.target.addEventListener(eventName, listener);
}
once(eventName, listener) {
return this.target.addEventListener(eventName, listener, { once: true });
}
@ccnokes
ccnokes / event-emitter.js
Created Oct 30, 2019
Event emitter using the native DOM APIs: EventTarget and CustomEvent
View event-emitter.js
// Who needs eventemitter3, mitt, or some other library when you can use native DOM APIs? 😁
let eventEmitter = new EventTarget();
eventEmitter.addEventListener('test', console.log); // CustomEvent { type: 'test', detail: 123, ... }
eventEmitter.dispatchEvent(new CustomEvent('test', { detail: 123 }));
@ccnokes
ccnokes / wait-with-abortsignal.js
Last active Sep 11, 2019
Use AbortController to implement custom async task cancelling logic. Expounded upon here: https://cameronnokes.com/blog/cancelling-async-tasks-with-abortcontroller/
View wait-with-abortsignal.js
function wait(ms, opts = {}) {
return new Promise((resolve, reject) => {
let timerId = setTimeout(resolve, ms);
if (opts.signal) {
// implement aborting logic for our async operation
opts.signal.addEventListener('abort', event => {
clearTimeout(timerId);
reject(event);
});
}
@ccnokes
ccnokes / AbortController.ts
Last active Mar 24, 2020
Minimal AbortController implementation for node.js that doesn't have to shim DOM stuff
View AbortController.ts
import { EventEmitter } from 'events';
class AbortSignal {
private events = new EventEmitter();
constructor(
private getIsAborted: () => boolean
) {}
get aborted(): boolean {
@ccnokes
ccnokes / idObj.ts
Last active Aug 22, 2019
Sometimes in React you need a unique `key` to represent an object's identity. Instead of generating an id when you fetch it from an API or generating an id on the fly or using indexes (both will lead to bugs), you can use this which gives you a stable, unique id for an object. Demo: https://codesandbox.io/s/nice-gauss-h424o. Demo with React: htt…
View idObj.ts
let map = new WeakMap(); // weakly holds all object refs (works in IE11+)
let n = 0; // global counter for ids
export function idObj(obj: any) {
if (map.has(obj)) {
return map.get(obj);
} else {
let key = String(++n);
map.set(obj, key);
return key;
You can’t perform that action at this time.