import { Func0, Func1, Func2, Func3, constant } from '@cotto/utils.ts' const debounce = require('debounce') export const defer: (f: Func0) => Promise = Promise.resolve() .then.bind(Promise.resolve()) export function toKebabCase(s: string) { return s.replace(/[A-Z]/g, _tokebabe) } function _tokebabe(s: string, offset: number) { s = s.toLowerCase() return offset <= 0 ? s : '-' + s } export function invokeCallback(..._args: any[]) { let i = arguments.length while (i--) { if (typeof arguments[i] === 'function') { arguments[i]() } } } export function proxy(filter: Func0): (...funcs: Func0[]) => Func0 export function proxy(filter: Func1): (...funcs: Func1[]) => Func1 export function proxy(filter: Func2): (...funcs: Func2[]) => Func2 export function proxy(filter: Func3): (...funcs: Func3[]) => Func3 export function proxy(filter: Function) { return (...funcs: Function[]) => function (this: any) { if (filter.apply(this, arguments)) { for (let i = 0; i < funcs.length; i++) { funcs[i].apply(this, arguments) } } } } export function cond(...pairs: [Function, Function][]): (a: any, b?: any, c?: any) => any { return function invoke(this: any) { for (const pair of pairs) { if (pair[0].apply(this, arguments)) { return pair[1].apply(this, arguments) } } } } export namespace cond { export interface Pred { (value: any, ...args: any[]): value is T } export interface Task { (value: T, ...args: any[]): void } export function when(pred: Pred, task: Task): [Pred, Task] { return [pred, task] } } export function attach(key: K, creator: (value: T, a?: any, b?: any) => T[K]) { return function (this: any, value: T, ..._extra: any[]) { value[key] = creator.apply(this, arguments) return value } } export interface Visitor { (node: T, parent: T | null, context?: C): R } export interface Director extends Visitor { /* */ } export interface Walker { (node: T, parent: T | null, context?: C, director?: Director): T } export interface Node { children: T[] } export function createTreeWalker, C = any>(...visitor: Visitor[]): Walker { const len = visitor.length const _director = constant(true) return function walk(node, parent, context = undefined, director = _director) { const ch = node.children for (let i = 0; i < len; i++) { visitor[i](node, parent, context) if (director(node, parent, context)) { for (let j = 0; j < ch.length; j++) { walk(ch[j], node, context, director) } } } return node } } export function createQueue( scheduler: (f: Function) => void = setTimeout, debounceTime = 100, maxDebounceSize = 1000, ) { let funcs: Function[] = [] const debounced = debounce(run, debounceTime) return { enqueue, process: process as typeof run, } function enqueue(f: Function) { funcs.push(f) return f } function run(done?: any) { let list = typeof done === 'function' ? [...funcs, done] : funcs funcs = [] list.forEach(scheduler) } function process(done: any) { if (funcs.length > maxDebounceSize) { debounced.flush(done) } else { debounced(done) } } } export function html(strings: TemplateStringsArray, ...values: any[]) { return strings.raw.reduce((acc, s, i) => { let value = values[i - 1] if (Array.isArray(values[i - 1])) { value = value.join('') } return acc + value + s }).replace(/(\s{2,})|(\n)/g, '') }