Skip to content

Instantly share code, notes, and snippets.

View sstur's full-sized avatar

Simon Sturmer sstur

View GitHub Profile
type Listener<T extends Array<unknown>> = (...args: T) => void;
export class EventEmitter<
E extends Record<string, Array<unknown>> = Record<never, []>
> {
private listenerMap: { [K in keyof E]?: Set<Listener<E[K]>> } = {};
on<K extends keyof E>(key: K, listener: Listener<E[K]>) {
return this.addListener(key, listener);
}
@sstur
sstur / dom-to-json.js
Last active October 8, 2023 04:17
Stringify DOM nodes using JSON (and revive again)
function toJSON(node) {
let propFix = { for: 'htmlFor', class: 'className' };
let specialGetters = {
style: (node) => node.style.cssText,
};
let attrDefaultValues = { style: '' };
let obj = {
nodeType: node.nodeType,
};
if (node.tagName) {
@sstur
sstur / upload.ts
Last active January 9, 2023 08:05
type ReqInit = {
method?: 'PUT' | 'POST';
headers?: HeadersInit;
body: Blob | BufferSource | FormData | URLSearchParams | string;
signal?: AbortSignal;
onProgress?: (bytesLoaded: number, bytesTotal: number) => void;
};
export function upload(url: string, init: ReqInit) {
const { signal, onProgress, body } = init;

Polyfill ReadableStream making it always an async iterator:

ReadableStream.prototype[Symbol.asyncIterator] = function() {
  const reader = this.getReader();
  return {
    next: () => reader.read(),
    return: () => {
      reader.releaseLock();
    },
 };
import { useRef, useEffect, useCallback } from 'react';
export function useGetLatestValue<T>(value: T): () => T {
const valueRef = useRef(value);
useEffect(() => {
valueRef.current = value;
}, [value]);
return useCallback(() => valueRef.current, []);
}
function createErrorSubclass<T = string>(
name: string,
getMessage: (param: T | undefined) => string | undefined = (input) =>
input === undefined ? undefined : String(input),
ErrorClass: new () => Error = Error,
) {
if (!name.endsWith('Error')) {
throw new Error(`Invalid name "${name}"`);
}
return Object.defineProperties(
export function useStableCallback<T extends Array<unknown>, R>(
callback: (...args: T) => R,
): (...args: T) => R {
let ref = useRef(callback);
useLayoutEffect(() => {
ref.current = callback;
});
let stableCallback = useCallback((...args: T) => {
return ref.current(...args);
}, []);
@sstur
sstur / clone.js
Created November 21, 2013 06:31
Deep-copy an object, similar to calling JSON.parse(JSON.stringify(obj)) but preserves dates and undefined
function clone(obj) {
if (Object(obj) !== obj) return obj;
if (typeof obj.toJSON == 'function') {
return obj.toJSON();
}
var type = toString.call(obj).slice(8, -1);
if (type in CLONE) {
return CLONE[type].call(obj, clone);
}
var copy = {};
import crypto from 'crypto';
export function getRandomBytes(numBytes: number): Promise<Buffer> {
return new Promise((resolve, reject) => {
crypto.randomBytes(numBytes, (error, result) => {
error ? reject(error) : resolve(result);
});
});
}
@sstur
sstur / mysql_escape_string.js
Created September 20, 2013 19:13
Escape string for MySQL
function mysql_escape_string(str) {
return str.replace(/[\0\x08\x09\x1a\n\r"'\\\%]/g, function(ch) {
switch (ch) {
case "\0":
return "\\0";
case "\x08":
return "\\b";
case "\x09":
return "\\t";
case "\x1a":