Skip to content

Instantly share code, notes, and snippets.

View christophemarois's full-sized avatar

Christophe Marois christophemarois

  • Pathway Medical
  • Montreal
View GitHub Profile
@christophemarois
christophemarois / chain.ts
Last active January 9, 2023 19:58
Polymorphic sync/async typed chain explorations
import { orderBy } from 'lodash'
function chain<OriginalValue>(originalValue?: OriginalValue) {
let fns: Array<(val: any) => any> = []
function step<CurrentValue>(currentValue: CurrentValue) {
const methods = {
do<NextValue>(fn: (val: CurrentValue) => NextValue) {
fns.push(fn)
return step<Awaited<NextValue>>(
# Install brew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install nvm
brew install nvm
# Install node 18
nvm install node 18
nvm alias default node 18
@christophemarois
christophemarois / custom-error.ts
Last active November 25, 2022 14:14
Extend built-in error
export class ResponseNotOkError extends Error {
constructor(public response: Response) {
super(`HTTP ${response.status}`)
// These lines can be added to further mimic Error magic properties.
// Never needed them, though.
this.name = this.constructor.name
Object.setPrototypeOf(this, ResponseNotOkError.prototype)
}
}
interface Serializable {
toString: () => string;
}
function groupBy<T>(els: T[], fn: (el: T) => Serializable) {
let out: Record<string, T[]> = {};
for (const el of els) {
const k = fn(el).toString();
@christophemarois
christophemarois / diyPromiseAll.ts
Last active August 11, 2022 15:53
My answer to a technical JS question: build your own Promise.all
/*
My answer to a technical JS question: build your own Promise.all
I decided to build my implementation, diyPromiseAll, using typescript
and to ensure that all type signatures are the same as the real Promise.all
of lib.es2015.
Following spec, diyPromiseAll:
- accepts any iterable of values of known or unknown size
- accepts values of mixed promises and non-promises (and thus nested instances of itself)
@christophemarois
christophemarois / node-fsReadLinesIterator.ts
Created February 23, 2022 18:23
Async Iterator that reads files line by line in a very efficient manner
import fs from 'node:fs'
export function fsReadLinesIterator(filepath: string, chunkSize: number) {
return {
async *[Symbol.asyncIterator](): AsyncGenerator<string> {
let line = ''
// Read utf8 chars in chunks of chunkSize
const stream = fs.createReadStream(filepath, {
highWaterMark: chunkSize,
@christophemarois
christophemarois / async-iterators.ts
Last active February 18, 2022 15:46
Async Iterators explorations in Typescript
class ArticleManager {
urls: string[] = []
async *[Symbol.asyncIterator](): AsyncGenerator<[string, string]> {
for (const url of this.urls) {
const html = await fetch(url).then(resp => resp.text())
yield [url, html]
}
}
}
@christophemarois
christophemarois / pad-to-fit.ts
Created January 16, 2022 05:09
Pad a number with zero to fit the digit space of a max target value. Useful for sequential filenames.
function padToFit(x: number, target: number) {
const pad =
Math.floor(Math.log10(Math.max(1, Math.floor(Math.abs(target))))) + 1
return x.toFixed(0).padStart(pad, '0')
}
padToFit(4, 9827) // => 0004
padToFit(4, 22) // => 04
@christophemarois
christophemarois / ts-node-shebang.ts
Created December 21, 2021 06:50
ts-node shebang
#!/usr/bin/env -S npx ts-node --transpile-only
console.log('hi' as string)
@christophemarois
christophemarois / transform-recipe-amounts.js
Created September 3, 2021 02:22
Match and transform all amounts in a recipe
const fractionalExp = /(?:(?:(\d+)\s+)?(\d)\/(\d))/
const floatExp = /(\d+(?:\.\d+)?)/
const matcherExp = new RegExp(
`(${fractionalExp.source}|${floatExp.source})`,
'g'
)
function transformAmounts(str, fn) {
return str.replace(matcherExp, (part) => {
const fractionalMatch = part.match(fractionalExp)