Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Promisify } from './interface';
export * from './interface';
export declare function async<Data>(getPromise: () => PromiseLike<Data>): Promisify<Data>;
export declare function async<Data>(getPromise: () => Data): Promisify<Data>;
export declare function async<Data>(promise: PromiseLike<Data>): Promisify<Data>;
export declare function async<Data>(data: Data): Promisify<Data>;
export declare function async<T>(getPromise: () => PromiseLike<T>): Promisify<T>;
export declare function async<T>(getPromise: () => T): Promisify<T>;
export declare function async<T>(promise: PromiseLike<T>): Promisify<T>;
export declare function async<T>(data: T): Promisify<T>;
125 changes: 32 additions & 93 deletions dist/index.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,3 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
Expand All @@ -59,65 +23,40 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
}
return to.concat(ar || Array.prototype.slice.call(from));
};
import { cast } from './utils';
import { cast, proxymify, isFunction } from './utils';
export * from './interface';
/**
* The function allows you to work flatly with promises using the `Proxy` object.
*
* The value you pass will be patched using the `Promisify` type in such a way that
* each of its members will be wrapped in a promise. However, you can still work with this value
* without worrying about the nested promises.
*
* @param value
* Can be any value or a function that returns any value.
* The final value will be wrapped in the `Promise`.
*
* @example
* ```typescript
* function getData(): Promise<Promise<number>[]> {
* return Promise.resolve([Promise.resolve(21)]);
* }
*
* // "21"
* const str1 = await flatAsync(getData)()[0].toFixed(1);
* // "21"
* const str2 = await flatAsync(getData())[0].toFixed(1);
* ```
*/
export function async(value) {
if (typeof value === 'function') {
return cast(proxymify(cast(value)));
if (isFunction(value)) {
return cast(proxymify(function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return Promise.resolve(value.apply(void 0, __spreadArray([], __read(args), false)));
}));
}
return cast(proxymify(function () { return Promise.resolve(value); }));
}
function proxymify(getData) {
var promise = getData();
return new Proxy(getData, {
get: function (_, prop) {
var _a;
return (_a = handleNativePromise(promise, prop)) !== null && _a !== void 0 ? _a : proxymifyNextValue(promise, prop);
},
apply: function (target, _, args) {
return proxymifyNextValueFromFunctionCall(cast(target), args);
},
});
}
function handleNativePromise(promise, prop) {
if (!Object.hasOwn(Promise.prototype, prop))
return;
var value = promise[cast(prop)];
if (typeof value === 'function') {
return value.bind(promise);
}
return value;
}
function proxymifyNextValue(promise, prop) {
return proxymify(function () { return getNextValueFromPrevPromise(promise, prop); });
}
function getNextValueFromPrevPromise(promise, prop) {
return __awaiter(this, void 0, void 0, function () {
var data, value;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, promise];
case 1:
data = _a.sent();
value = data[cast(prop)];
return [2 /*return*/, typeof value === 'function' ? value.bind(data) : value];
}
});
});
}
function proxymifyNextValueFromFunctionCall(getFn, args) {
return proxymify(function () { return getNextValueFromFunction(getFn, args); });
}
function getNextValueFromFunction(getFn, args) {
return __awaiter(this, void 0, void 0, function () {
var fn;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, getFn()];
case 1:
fn = _a.sent();
return [2 /*return*/, fn.apply(void 0, __spreadArray([], __read(args), false))];
}
});
});
}
139 changes: 127 additions & 12 deletions dist/interface.d.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,151 @@
declare type Fn<Return, Args extends any[]> = <R extends Return = Return, A extends Args = Args>(...args: A) => Promisify<R>;
declare type AnyFunction = (...params: any[]) => any;
declare type Overloads<T> = T extends () => infer R ? <Return extends R = R>() => Promisify<Return> : T extends {
/**
* Promisifies each function overload return type
*/
declare type Overloads<T> = T extends () => infer R ? T extends (...args: infer A) => any ? (...args: A) => Promisify<R> : () => Promisify<R> : T extends {
(...args: infer A0): infer R0;
(...args: infer A1): infer R1;
(...args: infer A2): infer R2;
(...args: infer A3): infer R3;
(...args: infer A4): infer R4;
(...args: infer A5): infer R5;
(...args: infer A6): infer R6;
} ? Fn<R1, A1> | Fn<R2, A2> | Fn<R3, A3> | Fn<R4, A4> | Fn<R5, A5> | Fn<R6, A6> : T extends {
(...args: infer A7): infer R7;
(...args: infer A8): infer R8;
(...args: infer A9): infer R9;
} ? {
(...args: A0): Promisify<R0>;
(...args: A1): Promisify<R1>;
(...args: A2): Promisify<R2>;
(...args: A3): Promisify<R3>;
(...args: A4): Promisify<R4>;
(...args: A5): Promisify<R5>;
(...args: A6): Promisify<R6>;
(...args: A7): Promisify<R7>;
(...args: A8): Promisify<R8>;
(...args: A9): Promisify<R9>;
} : T extends {
(...args: infer A0): infer R0;
(...args: infer A1): infer R1;
(...args: infer A2): infer R2;
(...args: infer A3): infer R3;
(...args: infer A4): infer R4;
(...args: infer A5): infer R5;
} ? Fn<R1, A1> | Fn<R2, A2> | Fn<R3, A3> | Fn<R4, A4> | Fn<R5, A5> : T extends {
(...args: infer A6): infer R6;
(...args: infer A7): infer R7;
(...args: infer A8): infer R8;
} ? {
(...args: A0): Promisify<R0>;
(...args: A1): Promisify<R1>;
(...args: A2): Promisify<R2>;
(...args: A3): Promisify<R3>;
(...args: A4): Promisify<R4>;
(...args: A5): Promisify<R5>;
(...args: A6): Promisify<R6>;
(...args: A7): Promisify<R7>;
(...args: A8): Promisify<R8>;
} : T extends {
(...args: infer A0): infer R0;
(...args: infer A1): infer R1;
(...args: infer A2): infer R2;
(...args: infer A3): infer R3;
(...args: infer A4): infer R4;
} ? Fn<R1, A1> | Fn<R2, A2> | Fn<R3, A3> | Fn<R4, A4> : T extends {
(...args: infer A5): infer R5;
(...args: infer A6): infer R6;
(...args: infer A7): infer R7;
} ? {
(...args: A0): Promisify<R0>;
(...args: A1): Promisify<R1>;
(...args: A2): Promisify<R2>;
(...args: A3): Promisify<R3>;
(...args: A4): Promisify<R4>;
(...args: A5): Promisify<R5>;
(...args: A6): Promisify<R6>;
(...args: A7): Promisify<R7>;
} : T extends {
(...args: infer A0): infer R0;
(...args: infer A1): infer R1;
(...args: infer A2): infer R2;
(...args: infer A3): infer R3;
} ? Fn<R1, A1> | Fn<R2, A2> | Fn<R3, A3> : T extends {
(...args: infer A4): infer R4;
(...args: infer A5): infer R5;
(...args: infer A6): infer R6;
} ? {
(...args: A0): Promisify<R0>;
(...args: A1): Promisify<R1>;
(...args: A2): Promisify<R2>;
(...args: A3): Promisify<R3>;
(...args: A4): Promisify<R4>;
(...args: A5): Promisify<R5>;
(...args: A6): Promisify<R6>;
} : T extends {
(...args: infer A0): infer R0;
(...args: infer A1): infer R1;
(...args: infer A2): infer R2;
} ? Fn<R1, A1> | Fn<R2, A2> : T extends (...args: infer A1) => infer R1 ? Fn<R1, A1> : never;
declare type UnionToIntersection<Fn> = (Fn extends any ? (fn: Fn) => void : never) extends (fn: infer F) => void ? F : never;
(...args: infer A3): infer R3;
(...args: infer A4): infer R4;
(...args: infer A5): infer R5;
} ? {
(...args: A0): Promisify<R0>;
(...args: A1): Promisify<R1>;
(...args: A2): Promisify<R2>;
(...args: A3): Promisify<R3>;
(...args: A4): Promisify<R4>;
(...args: A5): Promisify<R5>;
} : T extends {
(...args: infer A0): infer R0;
(...args: infer A1): infer R1;
(...args: infer A2): infer R2;
(...args: infer A3): infer R3;
(...args: infer A4): infer R4;
} ? {
(...args: A0): Promisify<R0>;
(...args: A1): Promisify<R1>;
(...args: A2): Promisify<R2>;
(...args: A3): Promisify<R3>;
(...args: A4): Promisify<R4>;
} : T extends {
(...args: infer A0): infer R0;
(...args: infer A1): infer R1;
(...args: infer A2): infer R2;
(...args: infer A3): infer R3;
} ? {
(...args: A0): Promisify<R0>;
(...args: A1): Promisify<R1>;
(...args: A2): Promisify<R2>;
(...args: A3): Promisify<R3>;
} : T extends {
(...args: infer A0): infer R0;
(...args: infer A1): infer R1;
(...args: infer A2): infer R2;
} ? {
(...args: A0): Promisify<R0>;
(...args: A1): Promisify<R1>;
(...args: A2): Promisify<R2>;
} : T extends {
(...args: infer A0): infer R0;
(...args: infer A1): infer R1;
} ? {
(...args: A0): Promisify<R0>;
(...args: A1): Promisify<R1>;
} : T extends (...args: infer A) => infer R ? (...args: A) => Promisify<R> : never;
/**
* Adds `Promise` properties to the specified value
*/
declare type WithPromise<Wrapped, Origin> = Wrapped & Promise<Origin>;
declare type GetSchema<Value> = Value extends string ? String : Value extends number ? Number : Value extends boolean ? Boolean : Value extends bigint ? BigInt : Value extends PromiseLike<infer Item> ? GetSchema<Item> : Value extends any[] ? WithPromise<Value, Value> : Value;
declare type PromisifySchema<Schema, Origin> = WithPromise<{
[Key in keyof Schema]: Schema[Key] extends AnyFunction ? UnionToIntersection<Overloads<Schema[Key]>> : Promisify<Schema[Key]>;
/**
* Maps primitive values to their object representation and "unwraps" `PromiseLike` objects
*/
declare type GetSchema<Value> = Value extends string ? String : Value extends number ? Number : Value extends boolean ? Boolean : Value extends bigint ? BigInt : Value extends symbol ? Symbol : Value extends PromiseLike<infer Item> ? GetSchema<Item> : Value;
/**
* Promisifies members of the specified schema by creating an object with the promisified properties
* or promisifying return type of each function overload
*/
declare type PromisifySchema<Schema, Origin> = Schema extends (...args: any[]) => any ? Overloads<Origin> : WithPromise<{
[Key in keyof Schema]: Promisify<Schema[Key]>;
}, Origin>;
/**
* Patches all members of the specified value in such a way that
* each of them will be wrapped in a promise but at the same time preserving its own properties
*/
export declare type Promisify<Value> = PromisifySchema<GetSchema<Value>, Value>;
export {};
20 changes: 20 additions & 0 deletions dist/utils.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1,21 @@
export declare function cast<T>(value: any): T;
/**
* Checks if provided value is a type of function
*
* @param value
*/
export declare function isFunction(value: any): value is ((...args: any[]) => any);
/**
* The function implements the logic of chaining promises flatly using the `Proxy` object.
* It creates a chain of promises where each next promise takes a value from the previous one.
*
* @param getPrevPromiseLike - the function that returns the previous `PromiseLike` in chain
*/
export declare function proxymify<T>(getPrevPromiseLike: (...args: unknown[]) => PromiseLike<T>): unknown;
declare type Fn<T> = (<V>() => V extends T ? 1 : 0);
declare type AreEquals<A, B> = Fn<A> extends Fn<B> ? unknown : never;
/**
* Util for checking two types equality
*/
export declare function expectType<A, B extends A & AreEquals<A, B>>(): void;
export {};
Loading