Skip to content
e280Public

About

πŸ‚ my typescript everyday carry

Resources

Stars

0 stars

Watchers

1 watching

Forks

Latest commit

Β 

History

464 Commits

Folders and files

Repository files navigation

πŸ‚ @e280/stz

my typescript everyday carry

environment-agnostic zero-dependency tools and utilities. by https://e280.org/

🍴 utensils
⏳ async/fns
πŸ“£ subby
🧹 housekeeping
🎲 rand
βœ… ok, err, result
🧬 hex and more


npm install @e280/stz
import {got, subby, Rand, hex} from "@e280/stz"


🍴 utensils

  • got β€” throw an error if the value is null or undefined.
    const value = got(nullableValue)
  • need β€” return a Map value, or throw an error if missing.
    const value = need(map, "my_key")
  • guarantee β€” get-or-create a Map value.
    const value = guarantee(map, "my_key", () => 123)
  • setEntries β€” set many Map entries at once.
    setEntries(map, [["my_key1", 123], ["my_key2", 234]])
  • count β€” iterate numbers.
    for (const i of count(4))
      console.log(i)
  • grid β€” iterate columns and rows.
    for (const [x, y] of grid(2, 4))
      console.log(x, y)
  • arraylimit β€” limit array length by dropping oldest.
    const trimmed = arraylimit(["a", "b", "c", "d"], 2)
      // ["c", "d"]
      // returns new array if trimming happens,
      // otherwise returns the same array unchanged.
  • pipe β€” run data through several fns.
    const result = pipe(rawData)
      .to(parse)
      .to(validate)
      .to(normalize)
      .done()
  • obmap β€” map over object entries.
    const alpha = {alpha: 1, bravo: 2, charlie: 3}
    obmap(alpha, n => n * 10)
      // {alpha: 10, bravo: 20, charlie: 30}
  • obfilter β€” filter object entries.
    obfilter(alpha, n => n > 1)
      // {bravo: 2, charlie: 3}
  • deepFreeze β€” recursively Object.freeze an object tree.
    const freezie = deepFreeze({alpha: 123})
    
    freezie.alpha = 5 // throws error
  • deepEqual β€” check if two object trees have the same primitive values.
    deepEqual({alpha: 123}, {alpha: 123})
      // true
  • 'is' type guards β€” check the identity of things with proper type guards.
    isHappy(0) // true if not null nor undefined.
    isSad(undefined) // true if null or undefined.
    isBoolean(true) // true
    isNumber(123) // true
    isString("hello") // true
    isBigint(123n) // true
    isArray([]) // true
    isObject({}) // true
    isFn(() => {}) // true
    isSymbol(Symbol()) // true
  • time β€” durations and timestamps.
    durations:
    seconds(1) // 1000
    minutes(1)
    hours(1)
    days(1)
    timestamps after Date.now:
    futureSeconds(1)
    futureMinutes(1)
    futureHours(1)
    futureDays(1)
    timestamps before Date.now:
    pastSeconds(1)
    pastMinutes(1)
    pastHours(1)
    pastDays(1)


⏳ async/fns

  • nap β€” return a promise that resolves later.
    await nap(1000) // sleep for one second.
  • cycle β€” repeatedly call the fn back-to-back.
    const stop = cycle(async() => {
      console.log("hello!", Date.now())
      await nap(1000) // once per second.
    })
    stop() // cancel the cycle.
  • concurrent β€” await a group of named promises.
    const {user, settings} = await concurrent({
      user: myFetchUser(),
      settings: myFetchSettings(),
    })
  • defer β€” a promise you can resolve/reject from outside.
    const ready = defer<string>()
    
    ready.resolve("hello")
    
    await ready
      // "hello"
    ready.reject(new Error("rejected"))
  • collect β€” async iterable to array.
    const entries = await collect(kv.entries())
  • once β€” only execute the fn one time.
    const init = once(() => connect())
    init()
    init() // doesn't initialize twice.
  • queue β€” make async fn calls work one-at-a-time.
    const save = queue(async(myData: string) => myWriteData(myData))
    
    await Promise.all([save("a"), save("b"), save("c")])
      // actually executes sequentially.
  • deadline β€” add an expiry timeout.
    const connection = await deadline(10_000, connect)
      // throw DeadlineError after 10s unless connect resolves.
      // connect can be a promise or an async fn.
  • debounce β€” dedupe calls over timeframe.
    const search = debounce(250, async(s: string) => query(s))
    
    search("l")
    search("lo")
    await search("lol") // last one actually runs.
  • microbounce β€” dedupe calls in this microtask.
    let count = 0
    const run = microbounce(() => count++)
    
    const done = run()
    run()
    run()
    
    await done
    count // 1


πŸ“£ subby

  • subby β€” create a subscriber fn.
    const on = subby<[number]>()
    const off = on(x => console.log(x))
    on.publish(123)
      // 123
    off() // stop listening.
  • pubby β€” create a publisher fn.
    const publish = pubby<[number]>()
    const off = publish.on(x => console.log(x))
    publish(123)
      // 123
    off() // stop listening.
  • πŸ§™β€β™‚οΈ 'subby' and 'pubby' give you the same goody-bag.
    // limited 'on' and 'publish' fns without whole toolkit.
    const {on, publish} = subby()
    const {publishAsync} = subby()
    
    await publishAsync(123)
      // awaits every listener (they can be async).
    const [value] = await on.next() // wait for the next publish.
      // value is 123
    on.set.size // direct access to the set of listeners.


🧹 housekeeping

  • ev β€” event listeners.
    import {ev} from "@e280/stz"
    
    const off = ev(window, {
        keydown: event => console.log(event),
        keyup: event => console.log(event),
    })
    
    off() // removes both listeners
  • disposer β€” cleanup resources.
    const dispose = disposer()
    
    dispose.schedule(() => console.log("dispose 1"))
    dispose.schedule(() => console.log("dispose 2"))
    dispose.schedule(cycle(myGameloop))
    dispose.schedule(ev(window, {keydown: myKeydown}))
    
    dispose() // dispose everything backwards
      // *dispose ev*
      // *dispose cycle*
      // "dispose 2"
      // "dispose 1"
    more disposer tricks.
    const myThing = dispose.own(new MyThing(), t => t.dispose())
      // create a thing and schedule its dispose
    const myThing = dispose.disposable(new MyThing())
      // return and schedule a Disposable thing
    const {dispose, schedule, own, disposable} = disposer()
    
    schedule(cycle(myGameloop))
    const myThing = disposable(new MyThing)
    
    dispose()


🎲 rand

  • Rand β€” random utility.
    const rand = new Rand(Math.random)
    const rand = new Rand(mulberry(123))
      // seeded pseudo-random number generator
    rand.u32() // get a random unsigned 32-bit integer.
      // 3286174905
    
    rand.roll(0.25) // 25% chance of true.
      // false
    
    rand.range(10, 20) // random float between two numbers.
      // 14.8591238
    
    rand.integerRange(1, 6) // inclusive integer range.
      // 4
    
    rand.index(7) // given array length, pick an array index.
      // 5
    
    rand.pick(["a", "b", "c"]) // pick your poison.
      // "c"
    
    rand.select(2, ["a", "b", "c"]) // pick multiple.
      // ["a", "c"]
    
    rand.yoink(["a", "b", "c"]) // remove and return one array element.
      // "a"
    
    rand.extract(2, ["a", "b", "c"]) // yoink multiple.
      // ["b", "c"]
    
    rand.shuffle(["a", "b", "c"]) // random-sort array in-place.
      // ["c", "a", "b"]
  • mulberry β€” seeded pseudo-random number generator.
    const random = mulberry(123)
    
    random()
      // 0.7872516233474016
    
    random()
      // 0.1785435655619949
  • rand32 β€” crypto-random unsigned 32-bit integer.
    rand32()
      // 3948271056
  • hash32 β€” mix entropy into a 32-bit integer (fast, non-cryptographic).
    hash32(123, "hello", 234, "world")
      // 1012994381


βœ… ok, err, result

  • ok β€” Ok<Value> β€” indicate success.
    ok(123)
      // {ok: true, value: 123}
  • err β€” Err<E> β€” indicate failure.
    err("fail")
      // {ok: false, error: "fail"}
  • Result<Value, E> β€” indicate something might succeed or fail.
    let result: Result<number, "fail"> = ok(123)
    
    result = err("fail")
  • getOk/getErr β€” get the value, or undefined.
    getOk(ok(123)) // 123
    getOk(err("fail")) // undefined
    
    getErr(ok(123)) // undefined
    getErr(err("fail")) // "fail"
  • gotOk/gotErr β€” get the value, or throw.
    gotOk(ok(123)) // 123
    gotOk(err("fail")) // throws Error("fail")
    
    gotErr(ok(123)) // throws error
    gotErr(err("fail")) // "fail"


🧬 hex and more

  • hex β€” encode/decode hexadecimal data.
    hex(bytes) // encode Uint8Array bytes to string.
    hex.toBytes(string) // decode string to bytes.
    hex.toInteger(string) // decode string as integer.
    hex.fromInteger(n) // encode integer as a string.
    hex.random(32) // generate random encoded string, 32 bytes.
    // we have more than just hex.
    hex(bytes) // string
    base2(bytes) // string
    base36(bytes) // string
    base58(bytes) // string
    base62(bytes) // string
    base64(bytes) // string
    base64url(bytes) // string
  • txt β€” text data.
    txt(bytes) // convert utf8 bytes to string.
    txt.toBytes("hello") // convert string to utf8 bytes.
  • bytes β€” uint8array utilities.
    bytes.eq(bytesA, bytesB) // true if they're equal.
    bytes.random(32) // get 32 crypto-random bytes.



πŸ§‘β€πŸ’» https://e280.org/

About

πŸ‚ my typescript everyday carry

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages