@synstack/resolved 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1 +1,103 @@
1
1
  # @synstack/resolved
2
+
3
+ Type-safe piping of synchronous or asynchronous values while preserving sync state
4
+
5
+ > [!WARNING]
6
+ > This package is included in the [@synstack/synscript](../synscript/README.md) package. It is not recommended to install both packages at the same time.
7
+
8
+ > [!NOTE]
9
+ > This package may be merged with the [@synstack/pipe](../pipe/README.md) package in the future.
10
+
11
+ ## What is it for?
12
+
13
+ When working with functions that can return either synchronous or asynchronous values, this package helps maintain type safety and provides a clean API for handling both cases and maintaining type safety:
14
+
15
+ ```typescript
16
+ import { pipe } from "@synstack/resolved";
17
+
18
+ // Sync operations remain sync
19
+ const syncResult = pipe("Hello World")._((v) => v.toUpperCase()).$;
20
+ console.log(syncResult); // "HELLO WORLD"
21
+
22
+ // Async operations return promises
23
+ const asyncResult = pipe(Promise.resolve("Hello World"))._((v) =>
24
+ v.toUpperCase(),
25
+ ).$;
26
+ console.log(await asyncResult); // "HELLO WORLD"
27
+
28
+ // Mixed operations maintain type safety
29
+ const mixedResult = pipe("Hello World")._((v) =>
30
+ Promise.resolve(v.toUpperCase()),
31
+ ).$;
32
+ console.log(await mixedResult); // "HELLO WORLD"
33
+ ```
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ # Using npm
39
+ npm install @synstack/resolved
40
+
41
+ # Using yarn
42
+ yarn add @synstack/resolved
43
+
44
+ # Using pnpm
45
+ pnpm add @synstack/resolved
46
+ ```
47
+
48
+ ## Features
49
+
50
+ ### Value Piping
51
+
52
+ The `pipe` function creates a chainable interface for working with resolvable values:
53
+
54
+ ```typescript
55
+ import { pipe } from "@synstack/resolved";
56
+
57
+ // Sync operations
58
+ const value = pipe("hello")
59
+ ._((v) => v.toUpperCase())
60
+ ._((v) => v + "!").$;
61
+
62
+ // Async operations
63
+ const asyncValue = pipe(Promise.resolve("hello"))
64
+ ._((v) => v.toUpperCase())
65
+ ._((v) => Promise.resolve(v + "!")).$;
66
+ ```
67
+
68
+ ### Array Resolution
69
+
70
+ The `resolveAll` function handles arrays of resolvable values:
71
+
72
+ ```typescript
73
+ import { resolveAll } from "@synstack/resolved";
74
+
75
+ // Sync array remains sync
76
+ const syncArray = resolveAll(["a", "b", "c"]);
77
+
78
+ // Array with promises becomes a promise
79
+ const asyncArray = resolveAll([
80
+ Promise.resolve("a"),
81
+ "b",
82
+ Promise.resolve("c"),
83
+ ]);
84
+ ```
85
+
86
+ ### Type Inference
87
+
88
+ The package provides type utilities for working with resolvable values:
89
+
90
+ ```typescript
91
+ import type { Resolvable } from "@synstack/resolved";
92
+
93
+ // Infer resolved type
94
+ type ResolvedValue = Resolvable.Infer<Promise<string>>; // string
95
+
96
+ // Check if value is a promise
97
+ type IsPromise = Resolvable.IsPromise<Promise<string>>; // true
98
+ type NotPromise = Resolvable.IsPromise<string>; // never
99
+
100
+ // Work with arrays
101
+ type ArrayValue = Resolvable.ArrayOf<string>; // Array<string | Promise<string>>
102
+ type ResolvedArray = Resolvable.ArrayOf.Infer<[Promise<string>, number]>; // [string, number]
103
+ ```
@@ -1,4 +1,4 @@
1
- import { R as Resolvable } from '../resolvable.lib-D1t15KWc.cjs';
1
+ import { a as Resolvable } from '../resolvable.lib-CH4uXiBW.cjs';
2
2
 
3
3
  type Callable<T> = T | (() => T);
4
4
  declare namespace Callable {
@@ -1,4 +1,4 @@
1
- import { R as Resolvable } from '../resolvable.lib-D1t15KWc.js';
1
+ import { a as Resolvable } from '../resolvable.lib-CH4uXiBW.js';
2
2
 
3
3
  type Callable<T> = T | (() => T);
4
4
  declare namespace Callable {
@@ -62,4 +62,4 @@ declare class Resolver<T extends Resolvable<any>> {
62
62
  */
63
63
  declare const pipe: <T>(value: T) => Resolver<T>;
64
64
 
65
- export { Resolvable as R, Resolver as a, pipe as p, resolveAll as r };
65
+ export { Resolver as R, Resolvable as a, pipe as p, resolveAll as r };
@@ -62,4 +62,4 @@ declare class Resolver<T extends Resolvable<any>> {
62
62
  */
63
63
  declare const pipe: <T>(value: T) => Resolver<T>;
64
64
 
65
- export { Resolvable as R, Resolver as a, pipe as p, resolveAll as r };
65
+ export { Resolver as R, Resolvable as a, pipe as p, resolveAll as r };
@@ -20,19 +20,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/resolved.index.ts
21
21
  var resolved_index_exports = {};
22
22
  __export(resolved_index_exports, {
23
+ Resolver: () => Resolver,
23
24
  pipe: () => pipe,
24
25
  resolvable: () => resolved_bundle_exports,
25
26
  resolveAll: () => resolveAll
26
27
  });
27
28
  module.exports = __toCommonJS(resolved_index_exports);
28
29
 
29
- // src/resolved.bundle.ts
30
- var resolved_bundle_exports = {};
31
- __export(resolved_bundle_exports, {
32
- pipe: () => pipe,
33
- resolveAll: () => resolveAll
34
- });
35
-
36
30
  // src/resolvable.lib.ts
37
31
  var resolveAll = (value) => {
38
32
  if (!Array.isArray(value)) throw new Error("Expected an array");
@@ -79,8 +73,16 @@ var Resolver = class _Resolver {
79
73
  var pipe = (value) => {
80
74
  return new Resolver(value);
81
75
  };
76
+
77
+ // src/resolved.bundle.ts
78
+ var resolved_bundle_exports = {};
79
+ __export(resolved_bundle_exports, {
80
+ pipe: () => pipe,
81
+ resolveAll: () => resolveAll
82
+ });
82
83
  // Annotate the CommonJS export names for ESM import in node:
83
84
  0 && (module.exports = {
85
+ Resolver,
84
86
  pipe,
85
87
  resolvable,
86
88
  resolveAll
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/resolved.index.ts","../src/resolved.bundle.ts","../src/resolvable.lib.ts"],"sourcesContent":["export type { Resolvable, Resolver } from \"./resolvable.lib.ts\";\nexport * from \"./resolved.bundle.ts\";\nexport * as resolvable from \"./resolved.bundle.ts\";\n","export { pipe, resolveAll } from \"./resolvable.lib.ts\";\n","export type Resolvable<T> = Promise<T> | T;\n\nexport declare namespace Resolvable {\n export type Infer<T> = Awaited<T>;\n export type IsPromise<T> = T extends Promise<any> ? true : never;\n\n export type ArrayOf<T> = Array<Resolvable<T>>;\n\n export namespace ArrayOf {\n export type Infer<T> = T extends readonly any[]\n ? {\n [K in keyof T]: Resolvable.Infer<T[K]>;\n }\n : never;\n\n export type HasPromise<T> = T extends readonly any[]\n ? {\n [K in keyof T]: Resolvable.IsPromise<T[K]>;\n }[number]\n : never;\n }\n\n export type MaybeArray<T> = Resolvable.ArrayOf<T> | Resolvable<T>;\n\n export namespace MaybeArray {\n export type Infer<T> = T extends readonly any[]\n ? { [K in keyof T]: Resolvable.Infer<T[K]> }\n : Resolvable.Infer<T>;\n\n export type IsPromise<T> = T extends readonly any[]\n ? { [K in keyof T]: Resolvable.IsPromise<T[K]> }[number]\n : Resolvable.IsPromise<T>;\n }\n}\n\n/**\n * Resolves all values in the array in parallel\n * @param value The array to resolve\n * @returns If the array contains promises, a promise of an array of values. Otherwise, the array.\n */\nexport const resolveAll = <U extends readonly any[]>(\n value: U,\n): true extends Resolvable.ArrayOf.HasPromise<U>\n ? Promise<Resolvable.ArrayOf.Infer<U>>\n : U => {\n if (!Array.isArray(value)) throw new Error(\"Expected an array\");\n // @ts-expect-error - We know that the value is not a promise\n if (value.some((v) => v instanceof Promise)) return Promise.all(value);\n // @ts-expect-error - We know that the value is not a promise\n return value;\n};\n\nexport class Resolver<T extends Resolvable<any>> {\n private readonly _value: T;\n\n public constructor(value: T) {\n this._value = value;\n }\n\n /**\n * Get the value of the resolver\n * @returns The value or a single promise of the value\n *\n * - If the value is an array containing promises, the array will be resolved with `Promise.all`\n */\n public get $(): T extends readonly any[]\n ? true extends Resolvable.ArrayOf.HasPromise<T>\n ? Promise<Resolvable.ArrayOf.Infer<T>>\n : T\n : T {\n if (Array.isArray(this._value)) {\n // @ts-expect-error - We know that the value is an array\n return resolveAll(this._value);\n }\n // @ts-expect-error - We know that the value is not an array\n return this._value;\n }\n\n public valueOf(): T {\n return this._value;\n }\n\n /**\n * Apply a function to the value\n * @param fn the function to apply to the value\n * @returns a new Resolver instance with the result of the function, either a value or a promise of a value\n */\n public _<R>(\n fn: (value: Resolvable.MaybeArray.Infer<T>) => R,\n ): true extends Resolvable.MaybeArray.IsPromise<T>\n ? true extends Resolvable.MaybeArray.IsPromise<R>\n ? Resolver<R>\n : Resolver<Promise<R>>\n : Resolver<R> {\n if (Array.isArray(this._value)) {\n const hasPromise = this._value.some((v) => v instanceof Promise);\n if (hasPromise)\n // @ts-expect-error - We know that the value is a promise\n return new Resolver(Promise.all(this._value).then(fn));\n // @ts-expect-error - We know that the value is not a promise\n return new Resolver(fn(this._value));\n }\n if (this._value instanceof Promise)\n // @ts-expect-error - We know that the value is a promise\n return new Resolver(this._value.then(fn));\n // @ts-expect-error - We know that the value is not a promise\n return new Resolver(fn(this._value as Resolvable.Infer<T>));\n }\n}\n\n/**\n * A piping utility which preserves the sync/async state of the value\n * @param value The value to pipe\n * @returns A new Resolver instance\n *\n * ```ts\n * import { pipe } from \"@synstack/resolved\";\n *\n * // Sync\n * const value: string = pipe(\"Hello World\")._((v) => v.toUpperCase()).$;\n *\n * // Async\n * const promiseValue: Promise<string> = pipe(\"Hello World\")._((v) => Promise.resolve(v.toUpperCase())).$;\n * ```\n */\nexport const pipe = <T>(value: T) => {\n return new Resolver<T>(value);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;;;ACwCO,IAAM,aAAa,CACxB,UAGO;AACP,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,OAAM,IAAI,MAAM,mBAAmB;AAE9D,MAAI,MAAM,KAAK,CAAC,MAAM,aAAa,OAAO,EAAG,QAAO,QAAQ,IAAI,KAAK;AAErE,SAAO;AACT;AAEO,IAAM,WAAN,MAAM,UAAoC;AAAA,EAC9B;AAAA,EAEV,YAAY,OAAU;AAC3B,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAW,IAIL;AACJ,QAAI,MAAM,QAAQ,KAAK,MAAM,GAAG;AAE9B,aAAO,WAAW,KAAK,MAAM;AAAA,IAC/B;AAEA,WAAO,KAAK;AAAA,EACd;AAAA,EAEO,UAAa;AAClB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,EACL,IAKc;AACd,QAAI,MAAM,QAAQ,KAAK,MAAM,GAAG;AAC9B,YAAM,aAAa,KAAK,OAAO,KAAK,CAAC,MAAM,aAAa,OAAO;AAC/D,UAAI;AAEF,eAAO,IAAI,UAAS,QAAQ,IAAI,KAAK,MAAM,EAAE,KAAK,EAAE,CAAC;AAEvD,aAAO,IAAI,UAAS,GAAG,KAAK,MAAM,CAAC;AAAA,IACrC;AACA,QAAI,KAAK,kBAAkB;AAEzB,aAAO,IAAI,UAAS,KAAK,OAAO,KAAK,EAAE,CAAC;AAE1C,WAAO,IAAI,UAAS,GAAG,KAAK,MAA6B,CAAC;AAAA,EAC5D;AACF;AAiBO,IAAM,OAAO,CAAI,UAAa;AACnC,SAAO,IAAI,SAAY,KAAK;AAC9B;","names":[]}
1
+ {"version":3,"sources":["../src/resolved.index.ts","../src/resolvable.lib.ts","../src/resolved.bundle.ts"],"sourcesContent":["export { Resolver, type Resolvable } from \"./resolvable.lib.ts\";\nexport * from \"./resolved.bundle.ts\";\nexport * as resolvable from \"./resolved.bundle.ts\";\n","export type Resolvable<T> = Promise<T> | T;\n\nexport declare namespace Resolvable {\n export type Infer<T> = Awaited<T>;\n export type IsPromise<T> = T extends Promise<any> ? true : never;\n\n export type ArrayOf<T> = Array<Resolvable<T>>;\n\n export namespace ArrayOf {\n export type Infer<T> = T extends readonly any[]\n ? {\n [K in keyof T]: Resolvable.Infer<T[K]>;\n }\n : never;\n\n export type HasPromise<T> = T extends readonly any[]\n ? {\n [K in keyof T]: Resolvable.IsPromise<T[K]>;\n }[number]\n : never;\n }\n\n export type MaybeArray<T> = Resolvable.ArrayOf<T> | Resolvable<T>;\n\n export namespace MaybeArray {\n export type Infer<T> = T extends readonly any[]\n ? { [K in keyof T]: Resolvable.Infer<T[K]> }\n : Resolvable.Infer<T>;\n\n export type IsPromise<T> = T extends readonly any[]\n ? { [K in keyof T]: Resolvable.IsPromise<T[K]> }[number]\n : Resolvable.IsPromise<T>;\n }\n}\n\n/**\n * Resolves all values in the array in parallel\n * @param value The array to resolve\n * @returns If the array contains promises, a promise of an array of values. Otherwise, the array.\n */\nexport const resolveAll = <U extends readonly any[]>(\n value: U,\n): true extends Resolvable.ArrayOf.HasPromise<U>\n ? Promise<Resolvable.ArrayOf.Infer<U>>\n : U => {\n if (!Array.isArray(value)) throw new Error(\"Expected an array\");\n // @ts-expect-error - We know that the value is not a promise\n if (value.some((v) => v instanceof Promise)) return Promise.all(value);\n // @ts-expect-error - We know that the value is not a promise\n return value;\n};\n\nexport class Resolver<T extends Resolvable<any>> {\n private readonly _value: T;\n\n public constructor(value: T) {\n this._value = value;\n }\n\n /**\n * Get the value of the resolver\n * @returns The value or a single promise of the value\n *\n * - If the value is an array containing promises, the array will be resolved with `Promise.all`\n */\n public get $(): T extends readonly any[]\n ? true extends Resolvable.ArrayOf.HasPromise<T>\n ? Promise<Resolvable.ArrayOf.Infer<T>>\n : T\n : T {\n if (Array.isArray(this._value)) {\n // @ts-expect-error - We know that the value is an array\n return resolveAll(this._value);\n }\n // @ts-expect-error - We know that the value is not an array\n return this._value;\n }\n\n public valueOf(): T {\n return this._value;\n }\n\n /**\n * Apply a function to the value\n * @param fn the function to apply to the value\n * @returns a new Resolver instance with the result of the function, either a value or a promise of a value\n */\n public _<R>(\n fn: (value: Resolvable.MaybeArray.Infer<T>) => R,\n ): true extends Resolvable.MaybeArray.IsPromise<T>\n ? true extends Resolvable.MaybeArray.IsPromise<R>\n ? Resolver<R>\n : Resolver<Promise<R>>\n : Resolver<R> {\n if (Array.isArray(this._value)) {\n const hasPromise = this._value.some((v) => v instanceof Promise);\n if (hasPromise)\n // @ts-expect-error - We know that the value is a promise\n return new Resolver(Promise.all(this._value).then(fn));\n // @ts-expect-error - We know that the value is not a promise\n return new Resolver(fn(this._value));\n }\n if (this._value instanceof Promise)\n // @ts-expect-error - We know that the value is a promise\n return new Resolver(this._value.then(fn));\n // @ts-expect-error - We know that the value is not a promise\n return new Resolver(fn(this._value as Resolvable.Infer<T>));\n }\n}\n\n/**\n * A piping utility which preserves the sync/async state of the value\n * @param value The value to pipe\n * @returns A new Resolver instance\n *\n * ```ts\n * import { pipe } from \"@synstack/resolved\";\n *\n * // Sync\n * const value: string = pipe(\"Hello World\")._((v) => v.toUpperCase()).$;\n *\n * // Async\n * const promiseValue: Promise<string> = pipe(\"Hello World\")._((v) => Promise.resolve(v.toUpperCase())).$;\n * ```\n */\nexport const pipe = <T>(value: T) => {\n return new Resolver<T>(value);\n};\n","export { pipe, resolveAll } from \"./resolvable.lib.ts\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACwCO,IAAM,aAAa,CACxB,UAGO;AACP,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,OAAM,IAAI,MAAM,mBAAmB;AAE9D,MAAI,MAAM,KAAK,CAAC,MAAM,aAAa,OAAO,EAAG,QAAO,QAAQ,IAAI,KAAK;AAErE,SAAO;AACT;AAEO,IAAM,WAAN,MAAM,UAAoC;AAAA,EAC9B;AAAA,EAEV,YAAY,OAAU;AAC3B,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAW,IAIL;AACJ,QAAI,MAAM,QAAQ,KAAK,MAAM,GAAG;AAE9B,aAAO,WAAW,KAAK,MAAM;AAAA,IAC/B;AAEA,WAAO,KAAK;AAAA,EACd;AAAA,EAEO,UAAa;AAClB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,EACL,IAKc;AACd,QAAI,MAAM,QAAQ,KAAK,MAAM,GAAG;AAC9B,YAAM,aAAa,KAAK,OAAO,KAAK,CAAC,MAAM,aAAa,OAAO;AAC/D,UAAI;AAEF,eAAO,IAAI,UAAS,QAAQ,IAAI,KAAK,MAAM,EAAE,KAAK,EAAE,CAAC;AAEvD,aAAO,IAAI,UAAS,GAAG,KAAK,MAAM,CAAC;AAAA,IACrC;AACA,QAAI,KAAK,kBAAkB;AAEzB,aAAO,IAAI,UAAS,KAAK,OAAO,KAAK,EAAE,CAAC;AAE1C,WAAO,IAAI,UAAS,GAAG,KAAK,MAA6B,CAAC;AAAA,EAC5D;AACF;AAiBO,IAAM,OAAO,CAAI,UAAa;AACnC,SAAO,IAAI,SAAY,KAAK;AAC9B;;;AC/HA;AAAA;AAAA;AAAA;AAAA;","names":[]}
@@ -1,5 +1,5 @@
1
- import { p as pipe, r as resolveAll } from './resolvable.lib-D1t15KWc.cjs';
2
- export { R as Resolvable, a as Resolver } from './resolvable.lib-D1t15KWc.cjs';
1
+ import { p as pipe, r as resolveAll } from './resolvable.lib-CH4uXiBW.cjs';
2
+ export { a as Resolvable, R as Resolver } from './resolvable.lib-CH4uXiBW.cjs';
3
3
 
4
4
  declare const resolved_bundle_pipe: typeof pipe;
5
5
  declare const resolved_bundle_resolveAll: typeof resolveAll;
@@ -1,5 +1,5 @@
1
- import { p as pipe, r as resolveAll } from './resolvable.lib-D1t15KWc.js';
2
- export { R as Resolvable, a as Resolver } from './resolvable.lib-D1t15KWc.js';
1
+ import { p as pipe, r as resolveAll } from './resolvable.lib-CH4uXiBW.js';
2
+ export { a as Resolvable, R as Resolver } from './resolvable.lib-CH4uXiBW.js';
3
3
 
4
4
  declare const resolved_bundle_pipe: typeof pipe;
5
5
  declare const resolved_bundle_resolveAll: typeof resolveAll;
@@ -4,13 +4,6 @@ var __export = (target, all) => {
4
4
  __defProp(target, name, { get: all[name], enumerable: true });
5
5
  };
6
6
 
7
- // src/resolved.bundle.ts
8
- var resolved_bundle_exports = {};
9
- __export(resolved_bundle_exports, {
10
- pipe: () => pipe,
11
- resolveAll: () => resolveAll
12
- });
13
-
14
7
  // src/resolvable.lib.ts
15
8
  var resolveAll = (value) => {
16
9
  if (!Array.isArray(value)) throw new Error("Expected an array");
@@ -57,7 +50,15 @@ var Resolver = class _Resolver {
57
50
  var pipe = (value) => {
58
51
  return new Resolver(value);
59
52
  };
53
+
54
+ // src/resolved.bundle.ts
55
+ var resolved_bundle_exports = {};
56
+ __export(resolved_bundle_exports, {
57
+ pipe: () => pipe,
58
+ resolveAll: () => resolveAll
59
+ });
60
60
  export {
61
+ Resolver,
61
62
  pipe,
62
63
  resolved_bundle_exports as resolvable,
63
64
  resolveAll
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/resolved.bundle.ts","../src/resolvable.lib.ts"],"sourcesContent":["export { pipe, resolveAll } from \"./resolvable.lib.ts\";\n","export type Resolvable<T> = Promise<T> | T;\n\nexport declare namespace Resolvable {\n export type Infer<T> = Awaited<T>;\n export type IsPromise<T> = T extends Promise<any> ? true : never;\n\n export type ArrayOf<T> = Array<Resolvable<T>>;\n\n export namespace ArrayOf {\n export type Infer<T> = T extends readonly any[]\n ? {\n [K in keyof T]: Resolvable.Infer<T[K]>;\n }\n : never;\n\n export type HasPromise<T> = T extends readonly any[]\n ? {\n [K in keyof T]: Resolvable.IsPromise<T[K]>;\n }[number]\n : never;\n }\n\n export type MaybeArray<T> = Resolvable.ArrayOf<T> | Resolvable<T>;\n\n export namespace MaybeArray {\n export type Infer<T> = T extends readonly any[]\n ? { [K in keyof T]: Resolvable.Infer<T[K]> }\n : Resolvable.Infer<T>;\n\n export type IsPromise<T> = T extends readonly any[]\n ? { [K in keyof T]: Resolvable.IsPromise<T[K]> }[number]\n : Resolvable.IsPromise<T>;\n }\n}\n\n/**\n * Resolves all values in the array in parallel\n * @param value The array to resolve\n * @returns If the array contains promises, a promise of an array of values. Otherwise, the array.\n */\nexport const resolveAll = <U extends readonly any[]>(\n value: U,\n): true extends Resolvable.ArrayOf.HasPromise<U>\n ? Promise<Resolvable.ArrayOf.Infer<U>>\n : U => {\n if (!Array.isArray(value)) throw new Error(\"Expected an array\");\n // @ts-expect-error - We know that the value is not a promise\n if (value.some((v) => v instanceof Promise)) return Promise.all(value);\n // @ts-expect-error - We know that the value is not a promise\n return value;\n};\n\nexport class Resolver<T extends Resolvable<any>> {\n private readonly _value: T;\n\n public constructor(value: T) {\n this._value = value;\n }\n\n /**\n * Get the value of the resolver\n * @returns The value or a single promise of the value\n *\n * - If the value is an array containing promises, the array will be resolved with `Promise.all`\n */\n public get $(): T extends readonly any[]\n ? true extends Resolvable.ArrayOf.HasPromise<T>\n ? Promise<Resolvable.ArrayOf.Infer<T>>\n : T\n : T {\n if (Array.isArray(this._value)) {\n // @ts-expect-error - We know that the value is an array\n return resolveAll(this._value);\n }\n // @ts-expect-error - We know that the value is not an array\n return this._value;\n }\n\n public valueOf(): T {\n return this._value;\n }\n\n /**\n * Apply a function to the value\n * @param fn the function to apply to the value\n * @returns a new Resolver instance with the result of the function, either a value or a promise of a value\n */\n public _<R>(\n fn: (value: Resolvable.MaybeArray.Infer<T>) => R,\n ): true extends Resolvable.MaybeArray.IsPromise<T>\n ? true extends Resolvable.MaybeArray.IsPromise<R>\n ? Resolver<R>\n : Resolver<Promise<R>>\n : Resolver<R> {\n if (Array.isArray(this._value)) {\n const hasPromise = this._value.some((v) => v instanceof Promise);\n if (hasPromise)\n // @ts-expect-error - We know that the value is a promise\n return new Resolver(Promise.all(this._value).then(fn));\n // @ts-expect-error - We know that the value is not a promise\n return new Resolver(fn(this._value));\n }\n if (this._value instanceof Promise)\n // @ts-expect-error - We know that the value is a promise\n return new Resolver(this._value.then(fn));\n // @ts-expect-error - We know that the value is not a promise\n return new Resolver(fn(this._value as Resolvable.Infer<T>));\n }\n}\n\n/**\n * A piping utility which preserves the sync/async state of the value\n * @param value The value to pipe\n * @returns A new Resolver instance\n *\n * ```ts\n * import { pipe } from \"@synstack/resolved\";\n *\n * // Sync\n * const value: string = pipe(\"Hello World\")._((v) => v.toUpperCase()).$;\n *\n * // Async\n * const promiseValue: Promise<string> = pipe(\"Hello World\")._((v) => Promise.resolve(v.toUpperCase())).$;\n * ```\n */\nexport const pipe = <T>(value: T) => {\n return new Resolver<T>(value);\n};\n"],"mappings":";;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACwCO,IAAM,aAAa,CACxB,UAGO;AACP,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,OAAM,IAAI,MAAM,mBAAmB;AAE9D,MAAI,MAAM,KAAK,CAAC,MAAM,aAAa,OAAO,EAAG,QAAO,QAAQ,IAAI,KAAK;AAErE,SAAO;AACT;AAEO,IAAM,WAAN,MAAM,UAAoC;AAAA,EAC9B;AAAA,EAEV,YAAY,OAAU;AAC3B,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAW,IAIL;AACJ,QAAI,MAAM,QAAQ,KAAK,MAAM,GAAG;AAE9B,aAAO,WAAW,KAAK,MAAM;AAAA,IAC/B;AAEA,WAAO,KAAK;AAAA,EACd;AAAA,EAEO,UAAa;AAClB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,EACL,IAKc;AACd,QAAI,MAAM,QAAQ,KAAK,MAAM,GAAG;AAC9B,YAAM,aAAa,KAAK,OAAO,KAAK,CAAC,MAAM,aAAa,OAAO;AAC/D,UAAI;AAEF,eAAO,IAAI,UAAS,QAAQ,IAAI,KAAK,MAAM,EAAE,KAAK,EAAE,CAAC;AAEvD,aAAO,IAAI,UAAS,GAAG,KAAK,MAAM,CAAC;AAAA,IACrC;AACA,QAAI,KAAK,kBAAkB;AAEzB,aAAO,IAAI,UAAS,KAAK,OAAO,KAAK,EAAE,CAAC;AAE1C,WAAO,IAAI,UAAS,GAAG,KAAK,MAA6B,CAAC;AAAA,EAC5D;AACF;AAiBO,IAAM,OAAO,CAAI,UAAa;AACnC,SAAO,IAAI,SAAY,KAAK;AAC9B;","names":[]}
1
+ {"version":3,"sources":["../src/resolvable.lib.ts","../src/resolved.bundle.ts"],"sourcesContent":["export type Resolvable<T> = Promise<T> | T;\n\nexport declare namespace Resolvable {\n export type Infer<T> = Awaited<T>;\n export type IsPromise<T> = T extends Promise<any> ? true : never;\n\n export type ArrayOf<T> = Array<Resolvable<T>>;\n\n export namespace ArrayOf {\n export type Infer<T> = T extends readonly any[]\n ? {\n [K in keyof T]: Resolvable.Infer<T[K]>;\n }\n : never;\n\n export type HasPromise<T> = T extends readonly any[]\n ? {\n [K in keyof T]: Resolvable.IsPromise<T[K]>;\n }[number]\n : never;\n }\n\n export type MaybeArray<T> = Resolvable.ArrayOf<T> | Resolvable<T>;\n\n export namespace MaybeArray {\n export type Infer<T> = T extends readonly any[]\n ? { [K in keyof T]: Resolvable.Infer<T[K]> }\n : Resolvable.Infer<T>;\n\n export type IsPromise<T> = T extends readonly any[]\n ? { [K in keyof T]: Resolvable.IsPromise<T[K]> }[number]\n : Resolvable.IsPromise<T>;\n }\n}\n\n/**\n * Resolves all values in the array in parallel\n * @param value The array to resolve\n * @returns If the array contains promises, a promise of an array of values. Otherwise, the array.\n */\nexport const resolveAll = <U extends readonly any[]>(\n value: U,\n): true extends Resolvable.ArrayOf.HasPromise<U>\n ? Promise<Resolvable.ArrayOf.Infer<U>>\n : U => {\n if (!Array.isArray(value)) throw new Error(\"Expected an array\");\n // @ts-expect-error - We know that the value is not a promise\n if (value.some((v) => v instanceof Promise)) return Promise.all(value);\n // @ts-expect-error - We know that the value is not a promise\n return value;\n};\n\nexport class Resolver<T extends Resolvable<any>> {\n private readonly _value: T;\n\n public constructor(value: T) {\n this._value = value;\n }\n\n /**\n * Get the value of the resolver\n * @returns The value or a single promise of the value\n *\n * - If the value is an array containing promises, the array will be resolved with `Promise.all`\n */\n public get $(): T extends readonly any[]\n ? true extends Resolvable.ArrayOf.HasPromise<T>\n ? Promise<Resolvable.ArrayOf.Infer<T>>\n : T\n : T {\n if (Array.isArray(this._value)) {\n // @ts-expect-error - We know that the value is an array\n return resolveAll(this._value);\n }\n // @ts-expect-error - We know that the value is not an array\n return this._value;\n }\n\n public valueOf(): T {\n return this._value;\n }\n\n /**\n * Apply a function to the value\n * @param fn the function to apply to the value\n * @returns a new Resolver instance with the result of the function, either a value or a promise of a value\n */\n public _<R>(\n fn: (value: Resolvable.MaybeArray.Infer<T>) => R,\n ): true extends Resolvable.MaybeArray.IsPromise<T>\n ? true extends Resolvable.MaybeArray.IsPromise<R>\n ? Resolver<R>\n : Resolver<Promise<R>>\n : Resolver<R> {\n if (Array.isArray(this._value)) {\n const hasPromise = this._value.some((v) => v instanceof Promise);\n if (hasPromise)\n // @ts-expect-error - We know that the value is a promise\n return new Resolver(Promise.all(this._value).then(fn));\n // @ts-expect-error - We know that the value is not a promise\n return new Resolver(fn(this._value));\n }\n if (this._value instanceof Promise)\n // @ts-expect-error - We know that the value is a promise\n return new Resolver(this._value.then(fn));\n // @ts-expect-error - We know that the value is not a promise\n return new Resolver(fn(this._value as Resolvable.Infer<T>));\n }\n}\n\n/**\n * A piping utility which preserves the sync/async state of the value\n * @param value The value to pipe\n * @returns A new Resolver instance\n *\n * ```ts\n * import { pipe } from \"@synstack/resolved\";\n *\n * // Sync\n * const value: string = pipe(\"Hello World\")._((v) => v.toUpperCase()).$;\n *\n * // Async\n * const promiseValue: Promise<string> = pipe(\"Hello World\")._((v) => Promise.resolve(v.toUpperCase())).$;\n * ```\n */\nexport const pipe = <T>(value: T) => {\n return new Resolver<T>(value);\n};\n","export { pipe, resolveAll } from \"./resolvable.lib.ts\";\n"],"mappings":";;;;;;;AAwCO,IAAM,aAAa,CACxB,UAGO;AACP,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,OAAM,IAAI,MAAM,mBAAmB;AAE9D,MAAI,MAAM,KAAK,CAAC,MAAM,aAAa,OAAO,EAAG,QAAO,QAAQ,IAAI,KAAK;AAErE,SAAO;AACT;AAEO,IAAM,WAAN,MAAM,UAAoC;AAAA,EAC9B;AAAA,EAEV,YAAY,OAAU;AAC3B,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAW,IAIL;AACJ,QAAI,MAAM,QAAQ,KAAK,MAAM,GAAG;AAE9B,aAAO,WAAW,KAAK,MAAM;AAAA,IAC/B;AAEA,WAAO,KAAK;AAAA,EACd;AAAA,EAEO,UAAa;AAClB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,EACL,IAKc;AACd,QAAI,MAAM,QAAQ,KAAK,MAAM,GAAG;AAC9B,YAAM,aAAa,KAAK,OAAO,KAAK,CAAC,MAAM,aAAa,OAAO;AAC/D,UAAI;AAEF,eAAO,IAAI,UAAS,QAAQ,IAAI,KAAK,MAAM,EAAE,KAAK,EAAE,CAAC;AAEvD,aAAO,IAAI,UAAS,GAAG,KAAK,MAAM,CAAC;AAAA,IACrC;AACA,QAAI,KAAK,kBAAkB;AAEzB,aAAO,IAAI,UAAS,KAAK,OAAO,KAAK,EAAE,CAAC;AAE1C,WAAO,IAAI,UAAS,GAAG,KAAK,MAA6B,CAAC;AAAA,EAC5D;AACF;AAiBO,IAAM,OAAO,CAAI,UAAa;AACnC,SAAO,IAAI,SAAY,KAAK;AAC9B;;;AC/HA;AAAA;AAAA;AAAA;AAAA;","names":[]}
package/package.json CHANGED
@@ -4,7 +4,14 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "1.2.0",
7
+ "description": "Type-safe piping of synchronous or asynchronous values",
8
+ "keywords": [
9
+ "synstack",
10
+ "resolved",
11
+ "pipe",
12
+ "typescript"
13
+ ],
14
+ "version": "1.2.1",
8
15
  "author": {
9
16
  "name": "pAIrprog",
10
17
  "url": "https://pairprog.io"
@@ -57,5 +64,5 @@
57
64
  "!src/**/*.test.ts",
58
65
  "dist/**/*"
59
66
  ],
60
- "gitHead": "348d1987aba7aee8fbc5469d071e3c71663fc775"
67
+ "gitHead": "2868de5f8935b959b5b5faa6606a2fa9fcad27ab"
61
68
  }
@@ -1,3 +1,3 @@
1
- export type { Resolvable, Resolver } from "./resolvable.lib.ts";
1
+ export { Resolver, type Resolvable } from "./resolvable.lib.ts";
2
2
  export * from "./resolved.bundle.ts";
3
3
  export * as resolvable from "./resolved.bundle.ts";