1
Fork 0

typescript(monadic): feat: basic stuff

Signed-off-by: prescientmoon <git@moonythm.dev>
This commit is contained in:
Matei Adriel 2020-04-24 17:00:36 +03:00 committed by prescientmoon
parent 7bdf572b2d
commit fd81cf068e
Signed by: prescientmoon
SSH key fingerprint: SHA256:UUF9JT2s8Xfyv76b8ZuVL7XrmimH4o49p4b+iexbVH4
29 changed files with 2553 additions and 299 deletions

View file

@ -0,0 +1,42 @@
import { IterableEmitter } from './iterableEmitter';
export type EnvConfig<T, S, A> = {
render: (template: T, parent: HTMLElement) => void;
parent: HTMLElement;
component: Component<T, S, A>;
initialState: S;
};
export type Component<T, S, A> = {
render: (state: S, dispatch: (a: A) => () => void) => T;
handleActions: (action: A, state: S) => S;
};
async function* runComponent<T, S, A>(
component: Component<T, S, A>,
initialState: S
): AsyncGenerator<T> {
const emitter = new IterableEmitter(initialState);
const dispatch = (state: S) => (action: A) => {
const newState = component.handleActions(action, state);
return () => {
emitter.next(newState);
};
};
for await (const state of emitter) {
yield component.render(state, dispatch(state));
}
}
export const runUi = async <T, S, A>(
config: EnvConfig<T, S, A>
): Promise<void> => {
const component = runComponent(config.component, config.initialState);
for await (const template of component) {
config.render(template, config.parent);
}
};

View file

@ -0,0 +1,110 @@
declare const index: unique symbol;
/**
* Placeholder representing an indexed type variable.
*/
export interface _<N extends number = 0> {
[index]: N;
}
export type _0 = _<0>;
export type _1 = _<1>;
export type _2 = _<2>;
export type _3 = _<3>;
export type _4 = _<4>;
export type _5 = _<5>;
export type _6 = _<6>;
export type _7 = _<7>;
export type _8 = _<8>;
export type _9 = _<9>;
declare const fixed: unique symbol;
/**
* Marks a type to be ignored by the application operator `$`. This is used to protect
* bound type parameters.
*/
export interface Fixed<T> {
[fixed]: T;
}
/**
* Type application (simultaneously substitutes all placeholders within the target type)
*/
// prettier-ignore
export type $<T, S extends any[]> = (
T extends Fixed<infer U> ? { [indirect]: U } :
T extends _<infer N> ? { [indirect]: S[N] } :
T extends undefined | null | boolean | string | number ? { [indirect]: T } :
T extends (infer A)[] & { length: infer L } ? {
[indirect]: L extends keyof TupleTable
? TupleTable<T, S>[L]
: $<A, S>[]
} :
T extends (...x: infer I) => infer O ? { [indirect]: (...x: $<I, S>) => $<O, S> } :
T extends object ? { [indirect]: { [K in keyof T]: $<T[K], S> } } :
{ [indirect]: T }
)[typeof indirect];
/**
* Used as a level of indirection to avoid circularity errors.
*/
declare const indirect: unique symbol;
/**
* Allows looking up the type for a tuple based on its `length`, instead of trying
* each possibility one by one in a single long conditional.
*/
// prettier-ignore
type TupleTable<T extends any[] = any, S extends any[] = any> = {
0: [];
1: T extends [
infer A0
] ? [
$<A0, S>
] : never
2: T extends [
infer A0, infer A1
] ? [
$<A0, S>, $<A1, S>
] : never
3: T extends [
infer A0, infer A1, infer A2
] ? [
$<A0, S>, $<A1, S>, $<A2, S>
] : never
4: T extends [
infer A0, infer A1, infer A2, infer A3
] ? [
$<A0, S>, $<A1, S>, $<A2, S>, $<A3, S>
] : never
5: T extends [
infer A0, infer A1, infer A2, infer A3, infer A4
] ? [
$<A0, S>, $<A1, S>, $<A2, S>, $<A3, S>, $<A4, S>
] : never
6: T extends [
infer A0, infer A1, infer A2, infer A3, infer A4, infer A5
] ? [
$<A0, S>, $<A1, S>, $<A2, S>, $<A3, S>, $<A4, S>, $<A5, S>
] : never
7: T extends [
infer A0, infer A1, infer A2, infer A3, infer A4, infer A5, infer A6
] ? [
$<A0, S>, $<A1, S>, $<A2, S>, $<A3, S>, $<A4, S>, $<A5, S>, $<A6, S>
] : never
8: T extends [
infer A0, infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, infer A7
] ? [
$<A0, S>, $<A1, S>, $<A2, S>, $<A3, S>, $<A4, S>, $<A5, S>, $<A6, S>, $<A7, S>
] : never
9: T extends [
infer A0, infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, infer A7, infer A8
] ? [
$<A0, S>, $<A1, S>, $<A2, S>, $<A3, S>, $<A4, S>, $<A5, S>, $<A6, S>, $<A7, S>, $<A8, S>
] : never
10: T extends [
infer A0, infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, infer A7, infer A8, infer A9
] ? [
$<A0, S>, $<A1, S>, $<A2, S>, $<A3, S>, $<A4, S>, $<A5, S>, $<A6, S>, $<A7, S>, $<A8, S>, $<A9, S>
] : never
}

View file

@ -1,6 +1 @@
export const sum = (a: number, b: number) => {
if ('development' === process.env.NODE_ENV) {
console.log('boop');
}
return a + b;
};
export * from './environment';

View file

@ -0,0 +1,34 @@
// An event emitter which can be used
// with for of loops
export class IterableEmitter<T> {
// The generation of the emitter
// Used to avoid trying to resolve a promise twice
private generation = 0;
// Set the state
public next = (_: T) => {};
public constructor(private state: T) {}
async *[Symbol.asyncIterator](): AsyncGenerator<T> {
const createPromise = () =>
new Promise<T>(resolve => {
const generation = this.generation;
this.next = (value: T) => {
if (generation !== this.generation) {
throw new Error('Cannot resolve the same generation twice');
}
this.generation++;
resolve(value);
};
});
yield this.state;
while (true) {
yield createPromise();
}
}
}