code: structure code in modules

This commit is contained in:
gvergnaud
2023-02-12 22:09:47 +01:00
parent 4057342c39
commit 6ea12e99b7
7 changed files with 3790 additions and 149 deletions

9
.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
.DS_Store
node_modules
npm-debug.log
lib
dist
notes.md
.vscode/
tracing_output_folder/
*.tgz

View File

@@ -1,156 +1,170 @@
/** export namespace HOT {
* Generic helpers export interface Fn {
*/ args: unknown[];
output: unknown;
interface Fn {
input: unknown;
output: unknown;
}
type Call<fn extends Fn, input> = (fn & { input: input })["output"];
type Stringifiable = string | number | boolean | bigint | null | undefined;
type SplitImpl<
str,
sep extends string,
output extends any[] = []
> = str extends `${infer first}${sep}${infer rest}`
? SplitImpl<rest, sep, [...output, first]>
: output;
/**
* Generic Array operations
*/
/**
* Reduce
*/
type Reduce<xs, acc, fn extends Fn> = xs extends [infer first, ...infer rest]
? Reduce<rest, Call<fn, { acc: acc; item: first }>, fn>
: acc;
/**
* Define Map in terms of Reduce
*/
interface MapFn<fn extends Fn> extends Fn {
output: this["input"] extends {
acc: infer acc extends any[];
item: infer item;
} }
? [...acc, Call<fn, item>]
: never;
}
interface FilterFn<fn extends Fn> extends Fn { export type Apply<fn extends HOT.Fn, args> = (fn & {
output: this["input"] extends { args: args;
acc: infer acc extends any[]; })["output"];
item: infer item;
}
? Call<fn, item> extends true
? [...acc, item]
: acc
: never;
}
interface TupleMap<fn extends Fn> extends Fn { export type Call<fn extends HOT.Fn, arg1> = (fn & {
output: Reduce<this["input"], [], MapFn<fn>>; args: [arg1];
} })["output"];
interface TupleReduce<init, fn extends Fn> extends Fn { export type Call2<fn extends HOT.Fn, arg1, arg2> = (fn & {
output: Reduce<this["input"], init, fn>; args: [arg1, arg2];
} })["output"];
interface TupleFilter<fn extends Fn> extends Fn { export type Call3<fn extends HOT.Fn, arg1, arg2, arg3> = (fn & {
output: Reduce<this["input"], [], FilterFn<fn>>; args: [arg1, arg2, arg3];
} })["output"];
/** export type Call4<fn extends HOT.Fn, arg1, arg2, arg3, arg4> = (fn & {
* Lets use that! args: [arg1, arg2, arg3, arg3];
*/ })["output"];
interface ToPhrase extends Fn { export type Reduce<xs, acc, fn extends HOT.Fn> = xs extends [
output: `number is ${Extract<this["input"], string | number | boolean>}`; infer first,
} ...infer rest
type ys = Call<TupleMap<ToPhrase>, [1, 2, 3]>;
// ^?
type MakeRange<n, acc extends any[] = []> = acc["length"] extends n
? acc
: MakeRange<n, [...acc, acc["length"]]>;
type AddNumbers<a, b> = [...MakeRange<a>, ...MakeRange<b>]["length"];
type StringToNumber<str> = str extends `${infer n extends number}` ? n : never;
interface Add2 extends Fn {
output: this["input"] extends {
acc: infer acc;
item: infer item;
}
? AddNumbers<acc, item>
: never;
}
interface JoinReducer<sep extends string> extends Fn {
output: this["input"] extends {
acc: infer acc extends Stringifiable;
item: infer item extends Stringifiable;
}
? `${acc extends "" ? "" : `${acc}${sep}`}${item}`
: never;
}
interface PipeFn extends Fn {
output: this["input"] extends {
acc: infer acc;
item: infer fn extends Fn;
}
? Call<fn, acc>
: never;
}
type Pipe<init, xs extends Fn[]> = Reduce<xs, init, PipeFn>;
interface Add<n> extends Fn {
output: AddNumbers<this["input"], n>;
}
interface MapAdd<n> extends Fn {
output: Call<TupleMap<Add<n>>, this["input"]>;
}
interface Join<sep extends string> extends Fn {
output: Reduce<this["input"], "", JoinReducer<sep>>;
}
interface Split<sep extends string> extends Fn {
output: SplitImpl<this["input"], sep>;
}
interface ToNumber extends Fn {
output: this["input"] extends `${infer n extends number}` ? n : never;
}
interface MapToNumber extends Fn {
output: Call<TupleMap<ToNumber>, this["input"]>;
}
interface Sum extends Fn {
output: Reduce<this["input"], 0, Add2>;
}
// prettier-ignore
type result = Pipe<
// ^?
[1, 2, 3, 4, 3, 4],
[
TupleMap<Add<3>>,
Join<'.'>,
Split<'.'>,
TupleMap<ToNumber>,
TupleMap<Add<10>>,
Sum
] ]
>; ? Reduce<rest, HOT.Call2<fn, acc, first>, fn>
: acc;
export type ReduceRight<xs, acc, fn extends HOT.Fn> = xs extends [
...infer rest,
infer last
]
? ReduceRight<rest, HOT.Call2<fn, acc, last>, fn>
: acc;
interface PipeFn extends HOT.Fn {
output: this["args"] extends [infer acc, infer fn extends HOT.Fn]
? HOT.Call<fn, acc>
: never;
}
export type Pipe<init, xs extends HOT.Fn[]> = HOT.Reduce<xs, init, PipeFn>;
interface PipeRightFn extends HOT.Fn {
output: this["args"] extends [infer acc, infer fn extends HOT.Fn]
? HOT.Call<fn, acc>
: never;
}
export type PipeRight<xs extends HOT.Fn[], init> = HOT.ReduceRight<
xs,
init,
PipeRightFn
>;
}
/**
* Strings
*/
export namespace Strings {
export type Stringifiable =
| string
| number
| boolean
| bigint
| null
| undefined;
type SplitImpl<
str,
sep extends string,
output extends any[] = []
> = str extends `${infer first}${sep}${infer rest}`
? SplitImpl<rest, sep, [...output, first]>
: output;
interface JoinReducer<sep extends string> extends HOT.Fn {
output: this["args"] extends [
infer acc extends Strings.Stringifiable,
infer item extends Strings.Stringifiable
]
? `${acc extends "" ? "" : `${acc}${sep}`}${item}`
: never;
}
export interface Join<sep extends string> extends HOT.Fn {
output: HOT.Reduce<this["args"][0], "", JoinReducer<sep>>;
}
export interface Split<sep extends string> extends HOT.Fn {
output: SplitImpl<this["args"][0], sep>;
}
export interface ToNumber extends HOT.Fn {
output: this["args"][0] extends `${infer n extends number}` ? n : never;
}
}
/**
* Numbers
*/
export namespace Numbers {
type Add2Impl<a, b> = [...Tuples.Range<a>, ...Tuples.Range<b>]["length"];
export interface Add<n> extends HOT.Fn {
output: Add2Impl<this["args"][0], n>;
}
export interface Add2 extends HOT.Fn {
output: this["args"] extends [infer acc, infer item]
? Add2Impl<acc, item>
: never;
}
}
/**
* Tuples
*/
export namespace Tuples {
interface MapFn<fn extends HOT.Fn> extends HOT.Fn {
output: this["args"] extends [infer acc extends any[], infer item]
? [...acc, HOT.Call<fn, item>]
: never;
}
interface FilterFn<fn extends HOT.Fn> extends HOT.Fn {
output: this["args"] extends [infer acc extends any[], infer item]
? HOT.Call<fn, item> extends true
? [...acc, item]
: acc
: never;
}
export interface Map<fn extends HOT.Fn> extends HOT.Fn {
output: HOT.Reduce<this["args"][0], [], MapFn<fn>>;
}
export interface Reduce<init, fn extends HOT.Fn> extends HOT.Fn {
output: HOT.Reduce<this["args"][0], init, fn>;
}
export interface Filter<fn extends HOT.Fn> extends HOT.Fn {
output: HOT.Reduce<this["args"][0], [], FilterFn<fn>>;
}
export interface Sum extends HOT.Fn {
output: HOT.Reduce<this["args"][0], 0, Numbers.Add2>;
}
export type Range<n, acc extends any[] = []> = acc["length"] extends n
? acc
: Range<n, [...acc, acc["length"]]>;
}
/**
* Objects
*/
export namespace Objects {}
/**
* Unions
*/
export namespace Unions {}

View File

@@ -17,3 +17,48 @@ type result = Pipe<
] ]
>; >;
``` ```
## TODO
- [ ] Composition
- [ ] Pipe
- [ ] Compose
- [ ] Tuples
- [ ] Head
- [ ] Tail
- [ ] Map
- [ ] FlatMap
- [ ] Filter
- [ ] Reduce
- [ ] Find
- [ ] Zip
- [ ] Partition
- [ ] Drop n
- [ ] Take n
- [ ] TakeWhile
- [ ] Join separator
- [ ] Object
- [ ] Assign
- [ ] FromEntries
- [ ] Entries
- [ ] Pick
- [ ] PickBy
- [ ] Omit
- [ ] OmitBy
- [ ] Union
- [ ] Assign
- [ ] FromEntries
- [ ] Entries
- [ ] Extract
- [ ] ExtractBy
- [ ] Exclude
- [ ] ExcludeBy
- [ ] String
- [ ] Concat
- [ ] Uppercase
- [ ] Lowercase
- [ ] Capitalize
- [ ] Uncapitalize
- [ ] Split separator
- [ ] Words
- [ ] Reduce

3492
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -15,5 +15,10 @@
"bugs": { "bugs": {
"url": "https://github.com/gvergnaud/PipeScript/issues" "url": "https://github.com/gvergnaud/PipeScript/issues"
}, },
"homepage": "https://github.com/gvergnaud/PipeScript#readme" "homepage": "https://github.com/gvergnaud/PipeScript#readme",
"devDependencies": {
"@types/jest": "^29.4.0",
"jest": "^29.4.2",
"typescript": "^4.9.5"
}
} }

57
test/HOTScript.test.ts Normal file
View File

@@ -0,0 +1,57 @@
import { HOT, Numbers, Strings, Tuples } from "../HOTScript";
import { Equal, Expect } from "./helpers";
describe("HOTScript", () => {
describe("Composition", () => {
describe("Pipe", () => {
type res1 = HOT.Pipe<
// ^?
[1, 2, 3, 4, 3, 4],
[
Tuples.Map<Numbers.Add<3>>,
Strings.Join<".">,
Strings.Split<".">,
Tuples.Map<Strings.ToNumber>,
Tuples.Map<Numbers.Add<10>>,
Tuples.Sum
]
>;
type tes1 = Expect<Equal<res1, 78>>;
});
describe("PipeRight", () => {
type res1 = HOT.PipeRight<
// ^?
[
Tuples.Sum,
Tuples.Map<Numbers.Add<10>>,
Tuples.Map<Strings.ToNumber>,
Strings.Split<".">,
Strings.Join<".">,
Tuples.Map<Numbers.Add<3>>
],
[1, 2, 3, 4, 3, 4]
>;
type tes1 = Expect<Equal<res1, 78>>;
});
});
describe("Tuples", () => {
describe("Map", () => {
interface ToPhrase extends HOT.Fn {
output: `number is ${Extract<
this["args"][0],
string | number | boolean
>}`;
}
type res1 = HOT.Call<Tuples.Map<ToPhrase>, [1, 2, 3]>;
// ^?
type tes1 = Expect<
Equal<res1, ["number is 1", "number is 2", "number is 3"]>
>;
});
});
});

19
test/helpers.ts Normal file
View File

@@ -0,0 +1,19 @@
export type Equal<a, b> = (<T>() => T extends a ? 1 : 2) extends <
T
>() => T extends b ? 1 : 2
? true
: false;
export type Expect<a extends true> = a;
export type Some<bools extends boolean[]> = true extends bools[number]
? true
: false;
export type Every<bools extends boolean[]> = bools[number] extends true
? true
: false;
export type Extends<a, b> = [a] extends [b] ? true : false;
export type Not<a extends boolean> = a extends true ? false : true;