From 3d67ed4c7e186994051da584d6ad4b706b69180f Mon Sep 17 00:00:00 2001 From: Guy Kedem Date: Thu, 24 Oct 2024 14:08:18 +0700 Subject: [PATCH 01/14] functions-module --- deno.json | 52 ++++++- functions/curry.ts | 77 ++++++++++ functions/deno.json | 9 ++ functions/mod.ts | 32 ++++ functions/pipe.ts | 31 ++++ functions/set_arguments.ts | 295 +++++++++++++++++++++++++++++++++++++ 6 files changed, 495 insertions(+), 1 deletion(-) create mode 100644 functions/curry.ts create mode 100644 functions/deno.json create mode 100644 functions/mod.ts create mode 100644 functions/pipe.ts create mode 100644 functions/set_arguments.ts diff --git a/deno.json b/deno.json index 32b8da129dd5..1ecfbe7db091 100644 --- a/deno.json +++ b/deno.json @@ -6,7 +6,56 @@ "noImplicitOverride": true, "noUncheckedIndexedAccess": true }, +<<<<<<< HEAD + "imports": { + "@deno/doc": "jsr:@deno/doc@0.137", + "@deno/graph": "jsr:@deno/graph@^0.74", + "@std/archive": "jsr:@std/archive@^0.225.0", + "@std/assert": "jsr:@std/assert@^1.0.2", + "@std/async": "jsr:@std/async@^1.0.3", + "@std/bytes": "jsr:@std/bytes@^1.0.2-rc.3", + "@std/cli": "jsr:@std/cli@^1.0.3", + "@std/collections": "jsr:@std/collections@^1.0.5", + "@std/crypto": "jsr:@std/crypto@^1.0.2-rc.1", + "@std/csv": "jsr:@std/csv@^1.0.1", + "@std/data-structures": "jsr:@std/data-structures@^1.0.1", + "@std/datetime": "jsr:@std/datetime@^0.224.5", + "@std/dotenv": "jsr:@std/dotenv@^0.225.0", + "@std/encoding": "jsr:@std/encoding@^1.0.1", + "@std/expect": "jsr:@std/expect@^1.0.0", + "@std/fmt": "jsr:@std/fmt@^1.0.0", + "@std/front-matter": "jsr:@std/front-matter@^1.0.1", + "@std/fs": "jsr:@std/fs@^1.0.1", + "@std/html": "jsr:@std/html@^1.0.1", + "@std/http": "jsr:@std/http@^1.0.2", + "@std/ini": "jsr:@std/ini@^1.0.0-rc.3", + "@std/internal": "jsr:@std/internal@^1.0.1", + "@std/io": "jsr:@std/io@^0.224.4", + "@std/json": "jsr:@std/json@^1.0.0", + "@std/jsonc": "jsr:@std/jsonc@^1.0.0", + "@std/log": "jsr:@std/log@^0.224.5", + "@std/media-types": "jsr:@std/media-types@^1.0.2", + "@std/msgpack": "jsr:@std/msgpack@^1.0.0", + "@std/net": "jsr:@std/net@^1.0.0", + "@std/path": "jsr:@std/path@^1.0.2", + "@std/regexp": "jsr:@std/regexp@^1.0.0", + "@std/semver": "jsr:@std/semver@^1.0.1", + "@std/streams": "jsr:@std/streams@^1.0.1", + "@std/testing": "jsr:@std/testing@^1.0.0", + "@std/text": "jsr:@std/text@^1.0.2", + "@std/toml": "jsr:@std/toml@^1.0.0", + "@std/ulid": "jsr:@std/ulid@^1.0.0", + "@std/url": "jsr:@std/url@^0.225.0", + "@std/uuid": "jsr:@std/uuid@^1.0.0", + "@std/webgpu": "jsr:@std/webgpu@^0.224.5", + "@std/yaml": "jsr:@std/yaml@^1.0.2", + "automation/": "https://raw.githubusercontent.com/denoland/automation/0.10.0/", + "graphviz": "npm:node-graphviz@^0.1.1", + "npm:/typescript": "npm:typescript@5.4.4" + }, +======= "importMap": "./import_map.json", +>>>>>>> 05b6d7eedd8e441cb8fa22078f377a6a37b4fa88 "tasks": { "test": "deno test --unstable-http --unstable-webgpu --doc --allow-all --parallel --coverage --trace-leaks --clean", "test:browser": "git grep --name-only \"This module is browser compatible.\" | grep -v deno.json | grep -v .github/workflows | grep -v _tools | grep -v encoding/README.md | grep -v media_types/vendor/update.ts | xargs deno check --config browser-compat.tsconfig.json", @@ -89,6 +138,7 @@ "./ulid", "./uuid", "./webgpu", - "./yaml" + "./yaml", + "./functions" ] } diff --git a/functions/curry.ts b/functions/curry.ts new file mode 100644 index 000000000000..dc0207fb6ead --- /dev/null +++ b/functions/curry.ts @@ -0,0 +1,77 @@ +// deno-lint-ignore no-explicit-any +type AnyFunction = (...args: any[]) => any; + +type Curried1Function = { + (p1: P1): T; +}; +type Curried2Function = { + (p1: P1): Curried1Function; + (p1: P1, p2: P2): T; +}; +type Curried3Function = { + (p1: P1): Curried2Function; + (p1: P1, p2: P2): Curried1Function; + (p1: P1, p2: P2, p3: P3): T; +}; +type Curried4Function = { + (p1: P1): Curried3Function; + (p1: P1, p2: P2): Curried2Function; + (p1: P1, p2: P2, p3: P3): Curried1Function; + (p1: P1, p2: P2, p3: P3, p4: P4): T; +}; + +/** + * A function that returns a curried version of a given function + * + * @param {(p1: P1, p2: P2, … pn: Pn) => T} fn - The function to be curried. + * @returns - A function which can be provided with only some of the arguments of the given function at each invocation, once all arguments have been provided the given function is called. + * @example Usage + * function add(a: number, b: number, c: number) { + * return a + b + c + d; + * } + * + * const curriedAdd = curry(add); + * console.log(curriedAdd(1)(2)(3)); // 6 + * console.log(curriedAdd(1, 2)(3)); // 6 + * console.log(curriedAdd(1, 2, 3)); // 6 + */ + +export function curry( + fn: () => T, +): () => T; +export function curry( + fn: (p1: P1) => T, +): (p1: P1) => T; +export function curry( + fn: (p1: P1, p2: P2) => T, +): Curried2Function; +export function curry( + fn: (p1: P1, p2: P2, p3: P3) => T, +): Curried3Function; +export function curry( + fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, +): Curried4Function; +export function curry(fn: AnyFunction) { + return function curried(...args: any[]): any { + if (args.length >= fn.length) { + return fn(...args); + } else { + return (...moreArgs: any[]) => curried(...args, ...moreArgs); + } + }; +} + +function add(a: number, b: number, c: number, d: number) { + return a + b + c + d; +} + +const curriedAdd = curry(add); + +if (import.meta.main) { + const fnn = curriedAdd(1, 2); + console.log(curriedAdd(1)(2)(3)(4)); + console.log(curriedAdd(1, 2)(3)(4)); + console.log(curriedAdd(1, 2, 3)(4)); + console.log(curriedAdd(1, 2, 3, 4)); + console.log(curriedAdd(1, 2, 3, 4)); +} diff --git a/functions/deno.json b/functions/deno.json new file mode 100644 index 000000000000..17e15210ebc8 --- /dev/null +++ b/functions/deno.json @@ -0,0 +1,9 @@ +{ + "name": "@std/functions", + "version": "0.1.0", + "exports": { + ".": "./mod.ts", + "./curry": "./curry.ts", + "./pipe": "./pipe.ts" + } +} diff --git a/functions/mod.ts b/functions/mod.ts new file mode 100644 index 000000000000..b121a95548c1 --- /dev/null +++ b/functions/mod.ts @@ -0,0 +1,32 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. + +/** + * Pure functions for common tasks around collection types like arrays and + * objects. + * + * Inspired by + * {@link https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/ | Kotlin's Collections} + * package and {@link https://lodash.com/ | Lodash}. + * + * ```ts + * import { intersect, sample, pick } from "@std/collections"; + * import { assertEquals, assertArrayIncludes } from "@std/assert"; + * + * const lisaInterests = ["Cooking", "Music", "Hiking"]; + * const kimInterests = ["Music", "Tennis", "Cooking"]; + * + * assertEquals(intersect(lisaInterests, kimInterests), ["Cooking", "Music"]); + * + * assertArrayIncludes(lisaInterests, [sample(lisaInterests)]); + * + * const cat = { name: "Lulu", age: 3, breed: "Ragdoll" }; + * + * assertEquals(pick(cat, ["name", "breed"]), { name: "Lulu", breed: "Ragdoll"}); + * ``` + * + * @module + */ + +export * from "./curry.ts"; +export * from "./pipe.ts"; diff --git a/functions/pipe.ts b/functions/pipe.ts new file mode 100644 index 000000000000..e5c755b5cf97 --- /dev/null +++ b/functions/pipe.ts @@ -0,0 +1,31 @@ +// deno-lint-ignore-file no-explicit-any +type AnyFunc = (...arg: any) => any; + +type LastFnReturnType, Else = never> = F extends [ + ...any[], + (...arg: any) => infer R, +] ? R + : Else; + +// inspired by https://dev.to/ecyrbe/how-to-use-advanced-typescript-to-define-a-pipe-function-381h +type PipeArgs = F extends [ + (...args: infer A) => infer B, +] ? [...Acc, (...args: A) => B] + : F extends [(...args: infer A) => any, ...infer Tail] + ? Tail extends [(arg: infer B) => any, ...any[]] + ? PipeArgs B]> + : Acc + : Acc; + +export function pipe( + firstFn: FirstFn, + ...fns: PipeArgs extends F ? F : PipeArgs +): (arg: Parameters[0]) => LastFnReturnType> { + return (arg: Parameters[0]) => + (fns as AnyFunc[]).reduce((acc, fn) => fn(acc), firstFn(arg)); +} + +if (import.meta.main) { + const res = pipe(Math.abs, Math.sqrt, Math.floor); + res(-2); // 1 +} diff --git a/functions/set_arguments.ts b/functions/set_arguments.ts new file mode 100644 index 000000000000..6302e20a79de --- /dev/null +++ b/functions/set_arguments.ts @@ -0,0 +1,295 @@ +export function set_arguments(fn: (p1: P1) => T, p1: P1): () => T; +export function set_arguments( + fn: (p1: P1, p2: P2) => T, + p1: P1, + p2: undefined, +): (p2: P2) => T; +export function set_arguments( + fn: (p1: P1, p2: P2) => T, + p1: undefined, + p2: P2, +): (p1: P1) => T; +export function set_arguments( + fn: (p1: P1, p2: P2) => T, + p1: P1, + p2: P2, +): () => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3) => T, + p1: P1, + p2: P2, + p3: undefined, +): (p3: P3) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3) => T, + p1: P1, + p2: undefined, + p3: P3, +): (p2: P2) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3) => T, + p1: undefined, + p2: P2, + p3: P3, +): (p1: P1) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3) => T, + p1: P1, + p2: undefined, + p3: undefined, +): (p2: P2, p3: P3) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3) => T, + p1: undefined, + p2: P2, + p3: undefined, +): (p1: P1, p3: P3) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3) => T, + p1: undefined, + p2: undefined, + p3: P3, +): (p1: P1, p2: P2) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3) => T, + p1: P1, + p2: P2, + p3: P3, +): () => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, + p1: P1, + p2: P2, + p3: P3, + p4: undefined, +): (p4: P4) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, + p1: P1, + p2: P2, + p3: undefined, + p4: P4, +): (p3: P3) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, + p1: P1, + p2: undefined, + p3: P3, + p4: P4, +): (p2: P2) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, + p1: undefined, + p2: P2, + p3: P3, + p4: P4, +): (p1: P1) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, + p1: P1, + p2: P2, + p3: undefined, + p4: undefined, +): (p3: P3, p4: P4) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, + p1: P1, + p2: undefined, + p3: P3, + p4: undefined, +): (p2: P2, p4: P4) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, + p1: undefined, + p2: P2, + p3: undefined, + p4: P4, +): (p1: P1, p3: P3) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, + p1: undefined, + p2: undefined, + p3: P3, + p4: P4, +): (p1: P1, p2: P2) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, + p1: undefined, + p2: P2, + p3: P3, + p4: undefined, +): (p1: P1, p4: P4) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, + p1: P1, + p2: undefined, + p3: undefined, + p4: P4, +): (p2: P2, p3: P3) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, + p1: undefined, + p2: undefined, + p3: undefined, + p4: P4, +): (p1: P1, p2: P2, p3: P3) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, + p1: P1, + p2: P2, + p3: P3, + p4: P4, +): () => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: undefined, +): (p5: P5) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, + p1: P1, + p2: P2, + p3: P3, + p4: undefined, + p5: P5, +): (p4: P4) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, + p1: P1, + p2: P2, + p3: undefined, + p4: P4, + p5: P5, +): (p3: P3) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, + p1: P1, + p2: undefined, + p3: P3, + p4: P4, + p5: P5, +): (p2: P2) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, + p1: undefined, + p2: P2, + p3: P3, + p4: P4, + p5: P5, +): (p1: P1) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, + p1: P1, + p2: P2, + p3: P3, + p4: undefined, + p5: undefined, +): (p4: P4, p5: P5) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, + p1: P1, + p2: P2, + p3: undefined, + p4: P4, + p5: undefined, +): (p3: P3, p5: P5) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, + p1: P1, + p2: undefined, + p3: P3, + p4: undefined, + p5: P5, +): (p2: P2, p4: P4) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, + p1: undefined, + p2: P2, + p3: P3, + p4: undefined, + p5: P5, +): (p1: P1, p4: P4) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, + p1: P1, + p2: undefined, + p3: undefined, + p4: P4, + p5: P5, +): (p2: P2, p3: P3) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, + p1: undefined, + p2: P2, + p3: undefined, + p4: P4, + p5: P5, +): (p1: P1, p3: P3) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, + p1: undefined, + p2: undefined, + p3: P3, + p4: P4, + p5: P5, +): (p1: P1, p2: P2) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, + p1: undefined, + p2: P2, + p3: P3, + p4: P4, + p5: undefined, +): (p1: P1, p5: P5) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, + p1: P1, + p2: undefined, + p3: undefined, + p4: P4, + p5: undefined, +): (p2: P2, p3: P3, p5: P5) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, + p1: undefined, + p2: undefined, + p3: P3, + p4: P4, + p5: undefined, +): (p1: P1, p2: P2, p5: P5) => T; +export function set_arguments( + fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, +): () => T; +export function set_arguments( + fn: (...args: any[]) => any, + ...setArgs: any[] +) { + // ensure setArgs at least as long as the function's arguments + while (setArgs.length < fn.length) { + setArgs.push(undefined); + } + + return (...providedArgs: any[]) => { + // insert each argument at the index of undefined + const mergedArgs = setArgs.map((arg) => + arg === undefined ? providedArgs.shift() : arg + ); + + return fn(...mergedArgs); + }; +} + +if (import.meta.main) { + const divide = (a: number, b: number) => a / b; + const invert = set_arguments(divide, 1, undefined); + const r = invert(2); + console.log(r); // 1/2 +} From 3a08d69f994bc23c2efaea848ae056702aa28769 Mon Sep 17 00:00:00 2001 From: Guy Kedem Date: Wed, 18 Dec 2024 13:35:41 +0700 Subject: [PATCH 02/14] limit pr to pipe() and adding tests --- deno.json | 4 - functions/curry.ts | 77 ---------- functions/deno.json | 1 - functions/mod.ts | 1 - functions/pipe.ts | 16 +- functions/pipe_test.ts | 32 ++++ functions/set_arguments.ts | 295 ------------------------------------- 7 files changed, 42 insertions(+), 384 deletions(-) delete mode 100644 functions/curry.ts create mode 100644 functions/pipe_test.ts delete mode 100644 functions/set_arguments.ts diff --git a/deno.json b/deno.json index 1ecfbe7db091..a24ee15a614c 100644 --- a/deno.json +++ b/deno.json @@ -6,7 +6,6 @@ "noImplicitOverride": true, "noUncheckedIndexedAccess": true }, -<<<<<<< HEAD "imports": { "@deno/doc": "jsr:@deno/doc@0.137", "@deno/graph": "jsr:@deno/graph@^0.74", @@ -53,9 +52,6 @@ "graphviz": "npm:node-graphviz@^0.1.1", "npm:/typescript": "npm:typescript@5.4.4" }, -======= - "importMap": "./import_map.json", ->>>>>>> 05b6d7eedd8e441cb8fa22078f377a6a37b4fa88 "tasks": { "test": "deno test --unstable-http --unstable-webgpu --doc --allow-all --parallel --coverage --trace-leaks --clean", "test:browser": "git grep --name-only \"This module is browser compatible.\" | grep -v deno.json | grep -v .github/workflows | grep -v _tools | grep -v encoding/README.md | grep -v media_types/vendor/update.ts | xargs deno check --config browser-compat.tsconfig.json", diff --git a/functions/curry.ts b/functions/curry.ts deleted file mode 100644 index dc0207fb6ead..000000000000 --- a/functions/curry.ts +++ /dev/null @@ -1,77 +0,0 @@ -// deno-lint-ignore no-explicit-any -type AnyFunction = (...args: any[]) => any; - -type Curried1Function = { - (p1: P1): T; -}; -type Curried2Function = { - (p1: P1): Curried1Function; - (p1: P1, p2: P2): T; -}; -type Curried3Function = { - (p1: P1): Curried2Function; - (p1: P1, p2: P2): Curried1Function; - (p1: P1, p2: P2, p3: P3): T; -}; -type Curried4Function = { - (p1: P1): Curried3Function; - (p1: P1, p2: P2): Curried2Function; - (p1: P1, p2: P2, p3: P3): Curried1Function; - (p1: P1, p2: P2, p3: P3, p4: P4): T; -}; - -/** - * A function that returns a curried version of a given function - * - * @param {(p1: P1, p2: P2, … pn: Pn) => T} fn - The function to be curried. - * @returns - A function which can be provided with only some of the arguments of the given function at each invocation, once all arguments have been provided the given function is called. - * @example Usage - * function add(a: number, b: number, c: number) { - * return a + b + c + d; - * } - * - * const curriedAdd = curry(add); - * console.log(curriedAdd(1)(2)(3)); // 6 - * console.log(curriedAdd(1, 2)(3)); // 6 - * console.log(curriedAdd(1, 2, 3)); // 6 - */ - -export function curry( - fn: () => T, -): () => T; -export function curry( - fn: (p1: P1) => T, -): (p1: P1) => T; -export function curry( - fn: (p1: P1, p2: P2) => T, -): Curried2Function; -export function curry( - fn: (p1: P1, p2: P2, p3: P3) => T, -): Curried3Function; -export function curry( - fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, -): Curried4Function; -export function curry(fn: AnyFunction) { - return function curried(...args: any[]): any { - if (args.length >= fn.length) { - return fn(...args); - } else { - return (...moreArgs: any[]) => curried(...args, ...moreArgs); - } - }; -} - -function add(a: number, b: number, c: number, d: number) { - return a + b + c + d; -} - -const curriedAdd = curry(add); - -if (import.meta.main) { - const fnn = curriedAdd(1, 2); - console.log(curriedAdd(1)(2)(3)(4)); - console.log(curriedAdd(1, 2)(3)(4)); - console.log(curriedAdd(1, 2, 3)(4)); - console.log(curriedAdd(1, 2, 3, 4)); - console.log(curriedAdd(1, 2, 3, 4)); -} diff --git a/functions/deno.json b/functions/deno.json index 17e15210ebc8..7cb527aba535 100644 --- a/functions/deno.json +++ b/functions/deno.json @@ -3,7 +3,6 @@ "version": "0.1.0", "exports": { ".": "./mod.ts", - "./curry": "./curry.ts", "./pipe": "./pipe.ts" } } diff --git a/functions/mod.ts b/functions/mod.ts index b121a95548c1..7aa800e41fca 100644 --- a/functions/mod.ts +++ b/functions/mod.ts @@ -28,5 +28,4 @@ * @module */ -export * from "./curry.ts"; export * from "./pipe.ts"; diff --git a/functions/pipe.ts b/functions/pipe.ts index e5c755b5cf97..542068d29a72 100644 --- a/functions/pipe.ts +++ b/functions/pipe.ts @@ -17,15 +17,19 @@ type PipeArgs = F extends [ : Acc : Acc; +export function pipe(): (arg: T) => T; export function pipe( firstFn: FirstFn, ...fns: PipeArgs extends F ? F : PipeArgs -): (arg: Parameters[0]) => LastFnReturnType> { +): (arg: Parameters[0]) => LastFnReturnType>; + +export function pipe( + firstFn?: FirstFn, + ...fns: PipeArgs extends F ? F : PipeArgs +): any { + if (!firstFn) { + return (arg: T) => arg; + } return (arg: Parameters[0]) => (fns as AnyFunc[]).reduce((acc, fn) => fn(acc), firstFn(arg)); } - -if (import.meta.main) { - const res = pipe(Math.abs, Math.sqrt, Math.floor); - res(-2); // 1 -} diff --git a/functions/pipe_test.ts b/functions/pipe_test.ts new file mode 100644 index 000000000000..7632928fc8ab --- /dev/null +++ b/functions/pipe_test.ts @@ -0,0 +1,32 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +import { assertEquals, assertThrows } from "@std/assert"; +import { pipe } from "./mod.ts"; + +Deno.test("pipe() handles mixed types", () => { + const inputPipe = pipe( + Math.abs, + Math.sqrt, + Math.floor, + (num) => `result: ${num}`, + ); + assertEquals(inputPipe(-2), "result: 1"); +}); + +Deno.test("en empty pipe is the identity function", () => { + const inputPipe = pipe(); + assertEquals(inputPipe("hello"), "hello"); +}); + +Deno.test("pipe() throws an exceptions when a function throws an exception", () => { + const inputPipe = pipe( + Math.abs, + Math.sqrt, + Math.floor, + (num) => { + throw new Error("This is an error for " + num); + }, + (num) => `result: ${num}`, + ); + assertThrows(() => inputPipe(-2)); +}); diff --git a/functions/set_arguments.ts b/functions/set_arguments.ts deleted file mode 100644 index 6302e20a79de..000000000000 --- a/functions/set_arguments.ts +++ /dev/null @@ -1,295 +0,0 @@ -export function set_arguments(fn: (p1: P1) => T, p1: P1): () => T; -export function set_arguments( - fn: (p1: P1, p2: P2) => T, - p1: P1, - p2: undefined, -): (p2: P2) => T; -export function set_arguments( - fn: (p1: P1, p2: P2) => T, - p1: undefined, - p2: P2, -): (p1: P1) => T; -export function set_arguments( - fn: (p1: P1, p2: P2) => T, - p1: P1, - p2: P2, -): () => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3) => T, - p1: P1, - p2: P2, - p3: undefined, -): (p3: P3) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3) => T, - p1: P1, - p2: undefined, - p3: P3, -): (p2: P2) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3) => T, - p1: undefined, - p2: P2, - p3: P3, -): (p1: P1) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3) => T, - p1: P1, - p2: undefined, - p3: undefined, -): (p2: P2, p3: P3) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3) => T, - p1: undefined, - p2: P2, - p3: undefined, -): (p1: P1, p3: P3) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3) => T, - p1: undefined, - p2: undefined, - p3: P3, -): (p1: P1, p2: P2) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3) => T, - p1: P1, - p2: P2, - p3: P3, -): () => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, - p1: P1, - p2: P2, - p3: P3, - p4: undefined, -): (p4: P4) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, - p1: P1, - p2: P2, - p3: undefined, - p4: P4, -): (p3: P3) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, - p1: P1, - p2: undefined, - p3: P3, - p4: P4, -): (p2: P2) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, - p1: undefined, - p2: P2, - p3: P3, - p4: P4, -): (p1: P1) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, - p1: P1, - p2: P2, - p3: undefined, - p4: undefined, -): (p3: P3, p4: P4) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, - p1: P1, - p2: undefined, - p3: P3, - p4: undefined, -): (p2: P2, p4: P4) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, - p1: undefined, - p2: P2, - p3: undefined, - p4: P4, -): (p1: P1, p3: P3) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, - p1: undefined, - p2: undefined, - p3: P3, - p4: P4, -): (p1: P1, p2: P2) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, - p1: undefined, - p2: P2, - p3: P3, - p4: undefined, -): (p1: P1, p4: P4) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, - p1: P1, - p2: undefined, - p3: undefined, - p4: P4, -): (p2: P2, p3: P3) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, - p1: undefined, - p2: undefined, - p3: undefined, - p4: P4, -): (p1: P1, p2: P2, p3: P3) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4) => T, - p1: P1, - p2: P2, - p3: P3, - p4: P4, -): () => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, - p1: P1, - p2: P2, - p3: P3, - p4: P4, - p5: undefined, -): (p5: P5) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, - p1: P1, - p2: P2, - p3: P3, - p4: undefined, - p5: P5, -): (p4: P4) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, - p1: P1, - p2: P2, - p3: undefined, - p4: P4, - p5: P5, -): (p3: P3) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, - p1: P1, - p2: undefined, - p3: P3, - p4: P4, - p5: P5, -): (p2: P2) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, - p1: undefined, - p2: P2, - p3: P3, - p4: P4, - p5: P5, -): (p1: P1) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, - p1: P1, - p2: P2, - p3: P3, - p4: undefined, - p5: undefined, -): (p4: P4, p5: P5) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, - p1: P1, - p2: P2, - p3: undefined, - p4: P4, - p5: undefined, -): (p3: P3, p5: P5) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, - p1: P1, - p2: undefined, - p3: P3, - p4: undefined, - p5: P5, -): (p2: P2, p4: P4) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, - p1: undefined, - p2: P2, - p3: P3, - p4: undefined, - p5: P5, -): (p1: P1, p4: P4) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, - p1: P1, - p2: undefined, - p3: undefined, - p4: P4, - p5: P5, -): (p2: P2, p3: P3) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, - p1: undefined, - p2: P2, - p3: undefined, - p4: P4, - p5: P5, -): (p1: P1, p3: P3) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, - p1: undefined, - p2: undefined, - p3: P3, - p4: P4, - p5: P5, -): (p1: P1, p2: P2) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, - p1: undefined, - p2: P2, - p3: P3, - p4: P4, - p5: undefined, -): (p1: P1, p5: P5) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, - p1: P1, - p2: undefined, - p3: undefined, - p4: P4, - p5: undefined, -): (p2: P2, p3: P3, p5: P5) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, - p1: undefined, - p2: undefined, - p3: P3, - p4: P4, - p5: undefined, -): (p1: P1, p2: P2, p5: P5) => T; -export function set_arguments( - fn: (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T, - p1: P1, - p2: P2, - p3: P3, - p4: P4, - p5: P5, -): () => T; -export function set_arguments( - fn: (...args: any[]) => any, - ...setArgs: any[] -) { - // ensure setArgs at least as long as the function's arguments - while (setArgs.length < fn.length) { - setArgs.push(undefined); - } - - return (...providedArgs: any[]) => { - // insert each argument at the index of undefined - const mergedArgs = setArgs.map((arg) => - arg === undefined ? providedArgs.shift() : arg - ); - - return fn(...mergedArgs); - }; -} - -if (import.meta.main) { - const divide = (a: number, b: number) => a / b; - const invert = set_arguments(divide, 1, undefined); - const r = invert(2); - console.log(r); // 1/2 -} From 9fc723a338413c7747487047637fd0f4cf8237a9 Mon Sep 17 00:00:00 2001 From: Guy Kedem Date: Wed, 18 Dec 2024 14:14:18 +0700 Subject: [PATCH 03/14] adding copyright notice --- functions/pipe.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/functions/pipe.ts b/functions/pipe.ts index 542068d29a72..dec8733f9907 100644 --- a/functions/pipe.ts +++ b/functions/pipe.ts @@ -1,3 +1,5 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + // deno-lint-ignore-file no-explicit-any type AnyFunc = (...arg: any) => any; From be5e5dff3c8e7f59d4751dc374f48ae52ab7a39c Mon Sep 17 00:00:00 2001 From: Guy Kedem Date: Thu, 19 Dec 2024 12:39:53 +0700 Subject: [PATCH 04/14] module description and jsdoc --- deno.json | 4 ++-- functions/mod.ts | 27 ++++++++------------------- functions/pipe.ts | 17 +++++++++++++++++ 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/deno.json b/deno.json index a24ee15a614c..020842acb0d9 100644 --- a/deno.json +++ b/deno.json @@ -111,6 +111,7 @@ "./fmt", "./front_matter", "./fs", + "./functions", "./html", "./http", "./ini", @@ -134,7 +135,6 @@ "./ulid", "./uuid", "./webgpu", - "./yaml", - "./functions" + "./yaml" ] } diff --git a/functions/mod.ts b/functions/mod.ts index 7aa800e41fca..51d58b77123e 100644 --- a/functions/mod.ts +++ b/functions/mod.ts @@ -2,27 +2,16 @@ // This module is browser compatible. /** - * Pure functions for common tasks around collection types like arrays and - * objects. - * - * Inspired by - * {@link https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/ | Kotlin's Collections} - * package and {@link https://lodash.com/ | Lodash}. + * Utilities for working with functions. * * ```ts - * import { intersect, sample, pick } from "@std/collections"; - * import { assertEquals, assertArrayIncludes } from "@std/assert"; - * - * const lisaInterests = ["Cooking", "Music", "Hiking"]; - * const kimInterests = ["Music", "Tennis", "Cooking"]; - * - * assertEquals(intersect(lisaInterests, kimInterests), ["Cooking", "Music"]); - * - * assertArrayIncludes(lisaInterests, [sample(lisaInterests)]); - * - * const cat = { name: "Lulu", age: 3, breed: "Ragdoll" }; - * - * assertEquals(pick(cat, ["name", "breed"]), { name: "Lulu", breed: "Ragdoll"}); + * const myPipe = pipe( + * Math.abs, + * Math.sqrt, + * Math.floor, + * (num) => `result: ${num}`, + * ); + * assertEquals(myPipe(-2), "result: 1"); * ``` * * @module diff --git a/functions/pipe.ts b/functions/pipe.ts index dec8733f9907..f64f8358c474 100644 --- a/functions/pipe.ts +++ b/functions/pipe.ts @@ -19,6 +19,23 @@ type PipeArgs = F extends [ : Acc : Acc; +/** + * Composes functions from left to right, the output of each function is the input for the next. + * + * @example Usage + * ```ts + * const myPipe = pipe( + * Math.abs, + * Math.sqrt, + * Math.floor, + * (num) => `result: ${num}`, + * ); + * assertEquals(myPipe(-2), "result: 1"); + * ``` + * + * @param input The functions to be composed + * @returns A function composed of the input functions, from left to right + */ export function pipe(): (arg: T) => T; export function pipe( firstFn: FirstFn, From 817e9d1ba41283a49cbdf2e3d2ff7b1619e53aa5 Mon Sep 17 00:00:00 2001 From: Guy Kedem Date: Sat, 28 Dec 2024 15:03:08 +0700 Subject: [PATCH 05/14] adding accidentally removed import_map.json --- deno.json | 1 + 1 file changed, 1 insertion(+) diff --git a/deno.json b/deno.json index 020842acb0d9..fa1db143b9d9 100644 --- a/deno.json +++ b/deno.json @@ -52,6 +52,7 @@ "graphviz": "npm:node-graphviz@^0.1.1", "npm:/typescript": "npm:typescript@5.4.4" }, + "importMap": "./import_map.json", "tasks": { "test": "deno test --unstable-http --unstable-webgpu --doc --allow-all --parallel --coverage --trace-leaks --clean", "test:browser": "git grep --name-only \"This module is browser compatible.\" | grep -v deno.json | grep -v .github/workflows | grep -v _tools | grep -v encoding/README.md | grep -v media_types/vendor/update.ts | xargs deno check --config browser-compat.tsconfig.json", From 6b02456f72a696a81dbd6a9aa5ffa4d9927c53fd Mon Sep 17 00:00:00 2001 From: Guy Kedem Date: Sat, 28 Dec 2024 16:44:18 +0700 Subject: [PATCH 06/14] adding functions scope to title lint --- .github/workflows/title.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/title.yml b/.github/workflows/title.yml index 689f7b948464..cab67d33b351 100644 --- a/.github/workflows/title.yml +++ b/.github/workflows/title.yml @@ -53,6 +53,7 @@ jobs: fmt(/unstable)? front-matter(/unstable)? fs(/unstable)? + functions(/unstable)? html(/unstable)? http(/unstable)? ini(/unstable)? From 0f81c00b230d8bb33387b3fd752af694bd85b54b Mon Sep 17 00:00:00 2001 From: Guy Kedem Date: Mon, 30 Dec 2024 14:59:03 +0700 Subject: [PATCH 07/14] adding the functions module to import_map.json --- import_map.json | 1 + 1 file changed, 1 insertion(+) diff --git a/import_map.json b/import_map.json index 2802de3c8a4a..47455b402190 100644 --- a/import_map.json +++ b/import_map.json @@ -23,6 +23,7 @@ "@std/fmt": "jsr:@std/fmt@^1.0.2", "@std/front-matter": "jsr:@std/front-matter@^1.0.5", "@std/fs": "jsr:@std/fs@^1.0.3", + "@std/functions": "jsr:@std/functions@^0.1.0", "@std/html": "jsr:@std/html@^1.0.3", "@std/http": "jsr:@std/http@^1.0.6", "@std/ini": "jsr:@std/ini@^1.0.0-rc.4", From df3f24248e8b55e0b5a5ec1d12b984035a416209 Mon Sep 17 00:00:00 2001 From: Guy Kedem Date: Wed, 1 Jan 2025 14:19:04 +0700 Subject: [PATCH 08/14] :types lint fix --- functions/mod.ts | 2 +- functions/pipe.ts | 2 +- functions/pipe_test.ts | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/functions/mod.ts b/functions/mod.ts index 51d58b77123e..25e57da63b69 100644 --- a/functions/mod.ts +++ b/functions/mod.ts @@ -9,7 +9,7 @@ * Math.abs, * Math.sqrt, * Math.floor, - * (num) => `result: ${num}`, + * (num: number) => `result: ${num}`, * ); * assertEquals(myPipe(-2), "result: 1"); * ``` diff --git a/functions/pipe.ts b/functions/pipe.ts index f64f8358c474..bce742580e03 100644 --- a/functions/pipe.ts +++ b/functions/pipe.ts @@ -28,7 +28,7 @@ type PipeArgs = F extends [ * Math.abs, * Math.sqrt, * Math.floor, - * (num) => `result: ${num}`, + * (num: number) => `result: ${num}`, * ); * assertEquals(myPipe(-2), "result: 1"); * ``` diff --git a/functions/pipe_test.ts b/functions/pipe_test.ts index 7632928fc8ab..501d11a9db7d 100644 --- a/functions/pipe_test.ts +++ b/functions/pipe_test.ts @@ -1,14 +1,14 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. import { assertEquals, assertThrows } from "@std/assert"; -import { pipe } from "./mod.ts"; +import { pipe } from "./pipe.ts"; Deno.test("pipe() handles mixed types", () => { const inputPipe = pipe( Math.abs, Math.sqrt, Math.floor, - (num) => `result: ${num}`, + (num: number) => `result: ${num}`, ); assertEquals(inputPipe(-2), "result: 1"); }); @@ -23,10 +23,10 @@ Deno.test("pipe() throws an exceptions when a function throws an exception", () Math.abs, Math.sqrt, Math.floor, - (num) => { + (num: number) => { throw new Error("This is an error for " + num); }, - (num) => `result: ${num}`, + (num: number) => `result: ${num}`, ); assertThrows(() => inputPipe(-2)); }); From e03206bb545386d3f368d27755750efb4ac9d032 Mon Sep 17 00:00:00 2001 From: Guy Kedem Date: Wed, 1 Jan 2025 14:19:04 +0700 Subject: [PATCH 09/14] jsdoc code examples & typings lint fix --- functions/mod.ts | 6 ++++-- functions/pipe.ts | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/functions/mod.ts b/functions/mod.ts index 25e57da63b69..4f400428111f 100644 --- a/functions/mod.ts +++ b/functions/mod.ts @@ -5,6 +5,9 @@ * Utilities for working with functions. * * ```ts + * import { pipe } from "@std/functions"; + * import { assertEquals } from "@std/assert"; + * * const myPipe = pipe( * Math.abs, * Math.sqrt, @@ -16,5 +19,4 @@ * * @module */ - -export * from "./pipe.ts"; +export { pipe } from "./pipe.ts"; diff --git a/functions/pipe.ts b/functions/pipe.ts index bce742580e03..ae5c800103a1 100644 --- a/functions/pipe.ts +++ b/functions/pipe.ts @@ -24,6 +24,9 @@ type PipeArgs = F extends [ * * @example Usage * ```ts + * import { assertEquals } from "@std/assert"; + * import { pipe } from "@std/functions"; + * * const myPipe = pipe( * Math.abs, * Math.sqrt, From 28f449d5eef5ac0dd7218a4b574cd5db3afeafc2 Mon Sep 17 00:00:00 2001 From: Guy Kedem Date: Wed, 1 Jan 2025 15:49:37 +0700 Subject: [PATCH 10/14] updating copyright message to 2025 --- functions/mod.ts | 2 +- functions/pipe.ts | 2 +- functions/pipe_test.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/functions/mod.ts b/functions/mod.ts index 4f400428111f..c43c2af38825 100644 --- a/functions/mod.ts +++ b/functions/mod.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. All rights reserved. MIT license. // This module is browser compatible. /** diff --git a/functions/pipe.ts b/functions/pipe.ts index ae5c800103a1..0b1c80b3e360 100644 --- a/functions/pipe.ts +++ b/functions/pipe.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. All rights reserved. MIT license. // deno-lint-ignore-file no-explicit-any type AnyFunc = (...arg: any) => any; diff --git a/functions/pipe_test.ts b/functions/pipe_test.ts index 501d11a9db7d..603711d87947 100644 --- a/functions/pipe_test.ts +++ b/functions/pipe_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. All rights reserved. MIT license. import { assertEquals, assertThrows } from "@std/assert"; import { pipe } from "./pipe.ts"; From d388d3b3dbb674030a48281520e4fe52fe485533 Mon Sep 17 00:00:00 2001 From: Guy Kedem Date: Thu, 2 Jan 2025 13:00:35 +0700 Subject: [PATCH 11/14] fixing export to wildcard --- functions/mod.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/mod.ts b/functions/mod.ts index c43c2af38825..50c9f5c432b0 100644 --- a/functions/mod.ts +++ b/functions/mod.ts @@ -19,4 +19,4 @@ * * @module */ -export { pipe } from "./pipe.ts"; +export * from "./pipe.ts"; From a943aebad24da9570c20a50c770e55da5017cec8 Mon Sep 17 00:00:00 2001 From: Guy Kedem Date: Thu, 2 Jan 2025 13:04:13 +0700 Subject: [PATCH 12/14] removing imports field --- deno.json | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) diff --git a/deno.json b/deno.json index 7ea14228a719..7070d5994c63 100644 --- a/deno.json +++ b/deno.json @@ -6,52 +6,6 @@ "noImplicitOverride": true, "noUncheckedIndexedAccess": true }, - "imports": { - "@deno/doc": "jsr:@deno/doc@0.137", - "@deno/graph": "jsr:@deno/graph@^0.74", - "@std/archive": "jsr:@std/archive@^0.225.0", - "@std/assert": "jsr:@std/assert@^1.0.2", - "@std/async": "jsr:@std/async@^1.0.3", - "@std/bytes": "jsr:@std/bytes@^1.0.2-rc.3", - "@std/cli": "jsr:@std/cli@^1.0.3", - "@std/collections": "jsr:@std/collections@^1.0.5", - "@std/crypto": "jsr:@std/crypto@^1.0.2-rc.1", - "@std/csv": "jsr:@std/csv@^1.0.1", - "@std/data-structures": "jsr:@std/data-structures@^1.0.1", - "@std/datetime": "jsr:@std/datetime@^0.224.5", - "@std/dotenv": "jsr:@std/dotenv@^0.225.0", - "@std/encoding": "jsr:@std/encoding@^1.0.1", - "@std/expect": "jsr:@std/expect@^1.0.0", - "@std/fmt": "jsr:@std/fmt@^1.0.0", - "@std/front-matter": "jsr:@std/front-matter@^1.0.1", - "@std/fs": "jsr:@std/fs@^1.0.1", - "@std/html": "jsr:@std/html@^1.0.1", - "@std/http": "jsr:@std/http@^1.0.2", - "@std/ini": "jsr:@std/ini@^1.0.0-rc.3", - "@std/internal": "jsr:@std/internal@^1.0.1", - "@std/io": "jsr:@std/io@^0.224.4", - "@std/json": "jsr:@std/json@^1.0.0", - "@std/jsonc": "jsr:@std/jsonc@^1.0.0", - "@std/log": "jsr:@std/log@^0.224.5", - "@std/media-types": "jsr:@std/media-types@^1.0.2", - "@std/msgpack": "jsr:@std/msgpack@^1.0.0", - "@std/net": "jsr:@std/net@^1.0.0", - "@std/path": "jsr:@std/path@^1.0.2", - "@std/regexp": "jsr:@std/regexp@^1.0.0", - "@std/semver": "jsr:@std/semver@^1.0.1", - "@std/streams": "jsr:@std/streams@^1.0.1", - "@std/testing": "jsr:@std/testing@^1.0.0", - "@std/text": "jsr:@std/text@^1.0.2", - "@std/toml": "jsr:@std/toml@^1.0.0", - "@std/ulid": "jsr:@std/ulid@^1.0.0", - "@std/url": "jsr:@std/url@^0.225.0", - "@std/uuid": "jsr:@std/uuid@^1.0.0", - "@std/webgpu": "jsr:@std/webgpu@^0.224.5", - "@std/yaml": "jsr:@std/yaml@^1.0.2", - "automation/": "https://raw.githubusercontent.com/denoland/automation/0.10.0/", - "graphviz": "npm:node-graphviz@^0.1.1", - "npm:/typescript": "npm:typescript@5.4.4" - }, "importMap": "./import_map.json", "tasks": { "test": "deno test --unstable-http --unstable-webgpu --doc --allow-all --parallel --coverage --trace-leaks --clean", From 8ba6adddff146f45932f355825daad403c9a07b8 Mon Sep 17 00:00:00 2001 From: Guy Kedem Date: Mon, 6 Jan 2025 11:31:39 +0700 Subject: [PATCH 13/14] new copyright line phrasing --- functions/mod.ts | 3 ++- functions/pipe.ts | 2 +- functions/pipe_test.ts | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/functions/mod.ts b/functions/mod.ts index 50c9f5c432b0..a2f74fe008e2 100644 --- a/functions/mod.ts +++ b/functions/mod.ts @@ -1,4 +1,5 @@ -// Copyright 2018-2025 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + // This module is browser compatible. /** diff --git a/functions/pipe.ts b/functions/pipe.ts index 0b1c80b3e360..a9adf56f168a 100644 --- a/functions/pipe.ts +++ b/functions/pipe.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2025 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-explicit-any type AnyFunc = (...arg: any) => any; diff --git a/functions/pipe_test.ts b/functions/pipe_test.ts index 603711d87947..1986442a1d14 100644 --- a/functions/pipe_test.ts +++ b/functions/pipe_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2025 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertThrows } from "@std/assert"; import { pipe } from "./pipe.ts"; From aa42c90b56e0280cfb0c5944069a75ba26aaa7ae Mon Sep 17 00:00:00 2001 From: Guy Kedem Date: Mon, 20 Jan 2025 19:22:50 +0700 Subject: [PATCH 14/14] argument typing of pipe --- functions/pipe.ts | 93 +++++++++++++++++++++++++++++++++++++++--- functions/pipe_test.ts | 16 ++++++-- 2 files changed, 100 insertions(+), 9 deletions(-) diff --git a/functions/pipe.ts b/functions/pipe.ts index a9adf56f168a..bbf23c0d27d8 100644 --- a/functions/pipe.ts +++ b/functions/pipe.ts @@ -40,18 +40,101 @@ type PipeArgs = F extends [ * @returns A function composed of the input functions, from left to right */ export function pipe(): (arg: T) => T; +export function pipe< + Fn1 extends AnyFunc, + Fn2 extends (arg: ReturnType) => any, +>( + firstFunction: Fn1, + function2: Fn2, +): (...args: Parameters) => ReturnType; + +export function pipe< + Fn1 extends AnyFunc, + Fn2 extends (arg: ReturnType) => any, + Fn3 extends (arg: ReturnType) => any, +>( + firstFunction: Fn1, + function2: Fn2, + function3: Fn3, +): (...args: Parameters) => ReturnType; + +export function pipe< + Fn1 extends AnyFunc, + Fn2 extends (arg: ReturnType) => any, + Fn3 extends (arg: ReturnType) => any, + Fn4 extends (arg: ReturnType) => any, +>( + firstFunction: Fn1, + function2: Fn2, + function3: Fn3, + function4: Fn4, +): (...args: Parameters) => ReturnType; + +export function pipe< + Fn1 extends AnyFunc, + Fn2 extends (arg: ReturnType) => any, + Fn3 extends (arg: ReturnType) => any, + Fn4 extends (arg: ReturnType) => any, + Fn5 extends (arg: ReturnType) => any, +>( + firstFunction: Fn1, + function2: Fn2, + function3: Fn3, + function4: Fn4, + function5: Fn5, +): (...args: Parameters) => ReturnType; + +export function pipe< + Fn1 extends AnyFunc, + Fn2 extends (arg: ReturnType) => any, + Fn3 extends (arg: ReturnType) => any, + Fn4 extends (arg: ReturnType) => any, + Fn5 extends (arg: ReturnType) => any, + Fn6 extends (arg: ReturnType) => any, +>( + firstFunction: Fn1, + function2: Fn2, + function3: Fn3, + function4: Fn4, + function5: Fn5, + function6: Fn6, +): (...args: Parameters) => ReturnType; + +export function pipe< + Fn1 extends AnyFunc, + Fn2 extends (arg: ReturnType) => any, + Fn3 extends (arg: ReturnType) => any, + Fn4 extends (arg: ReturnType) => any, + Fn5 extends (arg: ReturnType) => any, + Fn6 extends (arg: ReturnType) => any, + Fn7 extends (arg: ReturnType) => any, +>( + firstFunction: Fn1, + function2: Fn2, + function3: Fn3, + function4: Fn4, + function5: Fn5, + function6: Fn6, + function7: Fn7, +): (...args: Parameters) => ReturnType; + export function pipe( - firstFn: FirstFn, + firstFunction: FirstFn, ...fns: PipeArgs extends F ? F : PipeArgs ): (arg: Parameters[0]) => LastFnReturnType>; export function pipe( - firstFn?: FirstFn, + firstFunction?: FirstFn, ...fns: PipeArgs extends F ? F : PipeArgs ): any { - if (!firstFn) { + if (!firstFunction) { return (arg: T) => arg; } - return (arg: Parameters[0]) => - (fns as AnyFunc[]).reduce((acc, fn) => fn(acc), firstFn(arg)); + + return (...arg: Parameters) => { + return (fns as AnyFunc[]).reduce( + (acc, fn) => fn(acc), + firstFunction(...arg), + ); + }; } diff --git a/functions/pipe_test.ts b/functions/pipe_test.ts index 1986442a1d14..12088433f8f3 100644 --- a/functions/pipe_test.ts +++ b/functions/pipe_test.ts @@ -6,11 +6,19 @@ import { pipe } from "./pipe.ts"; Deno.test("pipe() handles mixed types", () => { const inputPipe = pipe( Math.abs, - Math.sqrt, - Math.floor, - (num: number) => `result: ${num}`, + (num) => `result: ${num}`, + ); + assertEquals(inputPipe(-2), "result: 2"); +}); +Deno.test("pipe() handles first function with two arguments", () => { + function add(a: number, b: number): number { + return a + b; + } + const inputPipe = pipe( + add, + (num) => `result: ${num}`, ); - assertEquals(inputPipe(-2), "result: 1"); + assertEquals(inputPipe(3, 2), "result: 5"); }); Deno.test("en empty pipe is the identity function", () => {