composable-functions
Advanced tools
Comparing version 0.0.0-experimental-20240417-1 to 0.0.0-experimental-20240418-1
import { composable, failure, success } from './constructors.js'; | ||
import { ErrorList } from './errors.js'; | ||
/** | ||
@@ -113,2 +114,37 @@ * Merges a list of objects into a single object. | ||
/** | ||
* **NOTE :** Try to use [collect](collect) instead wherever possible since it is much safer. `merge` can create domain functions that will always fail in run-time or even overwrite data from successful constituent functions application. The `collect` function does not have these issues and serves a similar purpose. | ||
* @example | ||
* import { mdf, merge } from 'domain-functions' | ||
* | ||
* const a = mdf(z.object({}))(() => ({ a: 'a' })) | ||
* const b = mdf(z.object({}))(() => ({ b: 2 })) | ||
* const df = merge(a, b) | ||
* // ^? DomainFunction<{ a: string, b: number }> | ||
*/ | ||
function merge(...fns) { | ||
return map(all(...fns), mergeObjects); | ||
} | ||
/** | ||
* Creates a composite domain function that will return the result of the first successful constituent domain function. **It is important to notice** that all constituent domain functions will be executed in parallel, so be mindful of the side effects. | ||
* @example | ||
* import { mdf, first } from 'domain-functions' | ||
* | ||
* const a = mdf(z.object({ n: z.number() }))(({ n }) => n + 1) | ||
const b = mdf(z.object({ n: z.number() }))(({ n }) => String(n)) | ||
const df = first(a, b) | ||
// ^? DomainFunction<string | number> | ||
*/ | ||
function first(...fns) { | ||
return ((...args) => { | ||
return composable(async () => { | ||
const results = await Promise.all(fns.map((fn) => fn(...args))); | ||
const result = results.find((r) => r.success); | ||
if (!result) { | ||
throw new ErrorList(results.map(({ errors }) => errors).flat()); | ||
} | ||
return result.data; | ||
})(); | ||
}); | ||
} | ||
/** | ||
* Creates a new function that will try to recover from a resulting Failure. When the given function succeeds, its result is returned without changes. | ||
@@ -178,2 +214,2 @@ * @example | ||
} | ||
export { all, catchError, collect, map, mapError, mergeObjects, pipe, sequence, trace, }; | ||
export { all, catchError, collect, first, map, mapError, merge, mergeObjects, pipe, sequence, trace, }; |
import { mapError } from './combinators.js'; | ||
import { ErrorList } from './errors.js'; | ||
import { EnvironmentError, ErrorList, InputError } from './errors.js'; | ||
function success(data) { | ||
@@ -39,4 +39,17 @@ return { success: true, data, errors: [] }; | ||
} | ||
/** | ||
* It can be used to call a domain function from another domain function. It will return the output of the given domain function if it was successfull, otherwise it will throw a `ErrorList` that will bubble up to the parent function. | ||
* Also good to use it in successfull test cases. | ||
* @example | ||
* import { mdf, fromSuccess } from 'domain-functions' | ||
* | ||
* const add1 = mdf(z.number())((n) => n + 1) | ||
* const result = await add1(1) | ||
* // ^? Result<number> | ||
* const data = await fromSuccess(add1)(n) | ||
* // ^? number | ||
* expect(data).toBe(n + 1) | ||
*/ | ||
function fromSuccess(fn, onError = (e) => e) { | ||
return async (...args) => { | ||
return (async (...args) => { | ||
const result = await mapError(fn, onError)(...args); | ||
@@ -46,4 +59,57 @@ if (result.success) | ||
throw new ErrorList(result.errors); | ||
}); | ||
} | ||
/** | ||
* Creates a domain function. | ||
* After giving the input and environment schemas, you can pass a handler function that takes type safe input and environment. That function is gonna catch any errors and always return a Result. | ||
* @param inputSchema the schema for the input | ||
* @param environmentSchema the schema for the environment | ||
* @returns a handler function that takes type safe input and environment | ||
* @example | ||
* const safeFunction = withSchema( | ||
* z.object({ greeting: z.string() }), | ||
* z.object({ user: z.object({ name: z.string() }) }), | ||
* ) | ||
* const myDf = safeFunction(({ greeting }, { user }) => { | ||
* return { message: `${greeting} ${user.name}` } | ||
* }) | ||
*/ | ||
function withSchema(inputSchema, environmentSchema) { | ||
return function (handler) { | ||
return applySchema(composable(handler), inputSchema, environmentSchema); | ||
}; | ||
} | ||
export { composable, failure, fromSuccess, success }; | ||
function applySchema(fn, inputSchema, environmentSchema) { | ||
return async function (input, environment = {}) { | ||
const envResult = await (environmentSchema ?? objectSchema).safeParseAsync(environment); | ||
const result = await (inputSchema ?? alwaysUndefinedSchema).safeParseAsync(input); | ||
if (!result.success || !envResult.success) { | ||
const inputErrors = result.success | ||
? [] | ||
: result.error.issues.map((error) => new InputError(error.message, error.path)); | ||
const envErrors = envResult.success | ||
? [] | ||
: envResult.error.issues.map((error) => new EnvironmentError(error.message, error.path)); | ||
return failure([...inputErrors, ...envErrors]); | ||
} | ||
return fn(result.data, envResult.data); | ||
}; | ||
} | ||
const objectSchema = { | ||
safeParseAsync: (data) => { | ||
if (Object.prototype.toString.call(data) !== '[object Object]') { | ||
return Promise.resolve({ | ||
success: false, | ||
error: { issues: [{ path: [], message: 'Expected an object' }] }, | ||
}); | ||
} | ||
const someRecord = data; | ||
return Promise.resolve({ success: true, data: someRecord }); | ||
}, | ||
}; | ||
const alwaysUndefinedSchema = { | ||
safeParseAsync: (_data) => { | ||
return Promise.resolve({ success: true, data: undefined }); | ||
}, | ||
}; | ||
export { composable, failure, fromSuccess, success, withSchema, applySchema }; |
@@ -1,9 +0,9 @@ | ||
export { composable, failure, fromSuccess, success } from './constructors.js'; | ||
export { all, catchError, collect, map, mapError, mergeObjects, pipe, sequence, trace } from './combinators.js'; | ||
export { applySchema, composable, failure, fromSuccess, success, withSchema, } from './constructors.js'; | ||
export { all, catchError, collect, first, map, mapError, merge, mergeObjects, pipe, sequence, trace, } from './combinators.js'; | ||
export { inputFromForm, inputFromFormData, inputFromSearch, inputFromUrl, } from './input-resolvers.js'; | ||
export { toErrorPayload, serialize } from './serializer.js'; | ||
export { EnvironmentError, ErrorList, InputError } from './errors.js'; | ||
// DOMAIN FUNCTIONS | ||
export * as df from './df/index.js'; | ||
// FUNCTIONS WITH ENVIRONMENT | ||
export * as environment from './environment/index.js'; | ||
// COMPAT MODULE | ||
export * as compat from './compat/index.js'; |
{ | ||
"name": "composable-functions", | ||
"version": "0.0.0-experimental-20240417-1", | ||
"version": "0.0.0-experimental-20240418-1", | ||
"description": "Decouple your business logic from your controllers. With first-class type inference from end to end.", | ||
@@ -5,0 +5,0 @@ "author": "Seasoned", |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.trace = exports.sequence = exports.pipe = exports.mergeObjects = exports.mapError = exports.map = exports.collect = exports.catchError = exports.all = void 0; | ||
exports.trace = exports.sequence = exports.pipe = exports.mergeObjects = exports.merge = exports.mapError = exports.map = exports.first = exports.collect = exports.catchError = exports.all = void 0; | ||
const constructors_js_1 = require("./constructors.js"); | ||
const errors_js_1 = require("./errors.js"); | ||
/** | ||
@@ -122,2 +123,39 @@ * Merges a list of objects into a single object. | ||
/** | ||
* **NOTE :** Try to use [collect](collect) instead wherever possible since it is much safer. `merge` can create domain functions that will always fail in run-time or even overwrite data from successful constituent functions application. The `collect` function does not have these issues and serves a similar purpose. | ||
* @example | ||
* import { mdf, merge } from 'domain-functions' | ||
* | ||
* const a = mdf(z.object({}))(() => ({ a: 'a' })) | ||
* const b = mdf(z.object({}))(() => ({ b: 2 })) | ||
* const df = merge(a, b) | ||
* // ^? DomainFunction<{ a: string, b: number }> | ||
*/ | ||
function merge(...fns) { | ||
return map(all(...fns), mergeObjects); | ||
} | ||
exports.merge = merge; | ||
/** | ||
* Creates a composite domain function that will return the result of the first successful constituent domain function. **It is important to notice** that all constituent domain functions will be executed in parallel, so be mindful of the side effects. | ||
* @example | ||
* import { mdf, first } from 'domain-functions' | ||
* | ||
* const a = mdf(z.object({ n: z.number() }))(({ n }) => n + 1) | ||
const b = mdf(z.object({ n: z.number() }))(({ n }) => String(n)) | ||
const df = first(a, b) | ||
// ^? DomainFunction<string | number> | ||
*/ | ||
function first(...fns) { | ||
return ((...args) => { | ||
return (0, constructors_js_1.composable)(async () => { | ||
const results = await Promise.all(fns.map((fn) => fn(...args))); | ||
const result = results.find((r) => r.success); | ||
if (!result) { | ||
throw new errors_js_1.ErrorList(results.map(({ errors }) => errors).flat()); | ||
} | ||
return result.data; | ||
})(); | ||
}); | ||
} | ||
exports.first = first; | ||
/** | ||
* Creates a new function that will try to recover from a resulting Failure. When the given function succeeds, its result is returned without changes. | ||
@@ -124,0 +162,0 @@ * @example |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.success = exports.fromSuccess = exports.failure = exports.composable = void 0; | ||
exports.applySchema = exports.withSchema = exports.success = exports.fromSuccess = exports.failure = exports.composable = void 0; | ||
const combinators_js_1 = require("./combinators.js"); | ||
@@ -45,4 +45,17 @@ const errors_js_1 = require("./errors.js"); | ||
exports.composable = composable; | ||
/** | ||
* It can be used to call a domain function from another domain function. It will return the output of the given domain function if it was successfull, otherwise it will throw a `ErrorList` that will bubble up to the parent function. | ||
* Also good to use it in successfull test cases. | ||
* @example | ||
* import { mdf, fromSuccess } from 'domain-functions' | ||
* | ||
* const add1 = mdf(z.number())((n) => n + 1) | ||
* const result = await add1(1) | ||
* // ^? Result<number> | ||
* const data = await fromSuccess(add1)(n) | ||
* // ^? number | ||
* expect(data).toBe(n + 1) | ||
*/ | ||
function fromSuccess(fn, onError = (e) => e) { | ||
return async (...args) => { | ||
return (async (...args) => { | ||
const result = await (0, combinators_js_1.mapError)(fn, onError)(...args); | ||
@@ -52,4 +65,59 @@ if (result.success) | ||
throw new errors_js_1.ErrorList(result.errors); | ||
}); | ||
} | ||
exports.fromSuccess = fromSuccess; | ||
/** | ||
* Creates a domain function. | ||
* After giving the input and environment schemas, you can pass a handler function that takes type safe input and environment. That function is gonna catch any errors and always return a Result. | ||
* @param inputSchema the schema for the input | ||
* @param environmentSchema the schema for the environment | ||
* @returns a handler function that takes type safe input and environment | ||
* @example | ||
* const safeFunction = withSchema( | ||
* z.object({ greeting: z.string() }), | ||
* z.object({ user: z.object({ name: z.string() }) }), | ||
* ) | ||
* const myDf = safeFunction(({ greeting }, { user }) => { | ||
* return { message: `${greeting} ${user.name}` } | ||
* }) | ||
*/ | ||
function withSchema(inputSchema, environmentSchema) { | ||
return function (handler) { | ||
return applySchema(composable(handler), inputSchema, environmentSchema); | ||
}; | ||
} | ||
exports.fromSuccess = fromSuccess; | ||
exports.withSchema = withSchema; | ||
function applySchema(fn, inputSchema, environmentSchema) { | ||
return async function (input, environment = {}) { | ||
const envResult = await (environmentSchema ?? objectSchema).safeParseAsync(environment); | ||
const result = await (inputSchema ?? alwaysUndefinedSchema).safeParseAsync(input); | ||
if (!result.success || !envResult.success) { | ||
const inputErrors = result.success | ||
? [] | ||
: result.error.issues.map((error) => new errors_js_1.InputError(error.message, error.path)); | ||
const envErrors = envResult.success | ||
? [] | ||
: envResult.error.issues.map((error) => new errors_js_1.EnvironmentError(error.message, error.path)); | ||
return failure([...inputErrors, ...envErrors]); | ||
} | ||
return fn(result.data, envResult.data); | ||
}; | ||
} | ||
exports.applySchema = applySchema; | ||
const objectSchema = { | ||
safeParseAsync: (data) => { | ||
if (Object.prototype.toString.call(data) !== '[object Object]') { | ||
return Promise.resolve({ | ||
success: false, | ||
error: { issues: [{ path: [], message: 'Expected an object' }] }, | ||
}); | ||
} | ||
const someRecord = data; | ||
return Promise.resolve({ success: true, data: someRecord }); | ||
}, | ||
}; | ||
const alwaysUndefinedSchema = { | ||
safeParseAsync: (_data) => { | ||
return Promise.resolve({ success: true, data: undefined }); | ||
}, | ||
}; |
@@ -26,4 +26,5 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.compat = exports.df = exports.InputError = exports.ErrorList = exports.EnvironmentError = exports.serialize = exports.toErrorPayload = exports.inputFromUrl = exports.inputFromSearch = exports.inputFromFormData = exports.inputFromForm = exports.trace = exports.sequence = exports.pipe = exports.mergeObjects = exports.mapError = exports.map = exports.collect = exports.catchError = exports.all = exports.success = exports.fromSuccess = exports.failure = exports.composable = void 0; | ||
exports.compat = exports.environment = exports.InputError = exports.ErrorList = exports.EnvironmentError = exports.serialize = exports.toErrorPayload = exports.inputFromUrl = exports.inputFromSearch = exports.inputFromFormData = exports.inputFromForm = exports.trace = exports.sequence = exports.pipe = exports.mergeObjects = exports.merge = exports.mapError = exports.map = exports.first = exports.collect = exports.catchError = exports.all = exports.withSchema = exports.success = exports.fromSuccess = exports.failure = exports.composable = exports.applySchema = void 0; | ||
var constructors_js_1 = require("./constructors.js"); | ||
Object.defineProperty(exports, "applySchema", { enumerable: true, get: function () { return constructors_js_1.applySchema; } }); | ||
Object.defineProperty(exports, "composable", { enumerable: true, get: function () { return constructors_js_1.composable; } }); | ||
@@ -33,2 +34,3 @@ Object.defineProperty(exports, "failure", { enumerable: true, get: function () { return constructors_js_1.failure; } }); | ||
Object.defineProperty(exports, "success", { enumerable: true, get: function () { return constructors_js_1.success; } }); | ||
Object.defineProperty(exports, "withSchema", { enumerable: true, get: function () { return constructors_js_1.withSchema; } }); | ||
var combinators_js_1 = require("./combinators.js"); | ||
@@ -38,4 +40,6 @@ Object.defineProperty(exports, "all", { enumerable: true, get: function () { return combinators_js_1.all; } }); | ||
Object.defineProperty(exports, "collect", { enumerable: true, get: function () { return combinators_js_1.collect; } }); | ||
Object.defineProperty(exports, "first", { enumerable: true, get: function () { return combinators_js_1.first; } }); | ||
Object.defineProperty(exports, "map", { enumerable: true, get: function () { return combinators_js_1.map; } }); | ||
Object.defineProperty(exports, "mapError", { enumerable: true, get: function () { return combinators_js_1.mapError; } }); | ||
Object.defineProperty(exports, "merge", { enumerable: true, get: function () { return combinators_js_1.merge; } }); | ||
Object.defineProperty(exports, "mergeObjects", { enumerable: true, get: function () { return combinators_js_1.mergeObjects; } }); | ||
@@ -57,5 +61,5 @@ Object.defineProperty(exports, "pipe", { enumerable: true, get: function () { return combinators_js_1.pipe; } }); | ||
Object.defineProperty(exports, "InputError", { enumerable: true, get: function () { return errors_js_1.InputError; } }); | ||
// DOMAIN FUNCTIONS | ||
exports.df = __importStar(require("./df/index.js")); | ||
// FUNCTIONS WITH ENVIRONMENT | ||
exports.environment = __importStar(require("./environment/index.js")); | ||
// COMPAT MODULE | ||
exports.compat = __importStar(require("./compat/index.js")); |
@@ -41,3 +41,3 @@ import type { AllArguments, CollectArguments, Composable, First, MergeObjs, PipeArguments, PipeReturn, RecordToTuple, Result, UnpackAll, UnpackData } from './types.js'; | ||
*/ | ||
declare function all<T extends [Composable, ...Composable[]]>(...fns: T & AllArguments<T>): Composable<(...args: Parameters<AllArguments<T>[0]>) => { [key in keyof T]: UnpackData<ReturnType<Extract<T[key], Composable>>>; }>; | ||
declare function all<T extends Composable[]>(...fns: T & AllArguments<T>): Composable<(...args: Parameters<AllArguments<T>[0]>) => { [key in keyof T]: UnpackData<Extract<T[key], Composable>>; }>; | ||
/** | ||
@@ -53,3 +53,3 @@ * Receives a Record of Composables, runs them all in parallel and preserves the shape of this record for the data property in successful results. | ||
*/ | ||
declare function collect<T extends Record<string, Composable>>(fns: T & CollectArguments<T>): Composable<(...args: Parameters<AllArguments<RecordToTuple<T>>[0]>) => { [key in keyof T]: UnpackData<ReturnType<Extract<T[key], Composable>>>; }>; | ||
declare function collect<T extends Record<string, Composable>>(fns: T & CollectArguments<T>): Composable<(...args: Parameters<AllArguments<RecordToTuple<T>>[0]>) => { [key in keyof T]: UnpackData<Extract<T[key], Composable>>; }>; | ||
/** | ||
@@ -75,4 +75,28 @@ * Works like `pipe` but it will collect the output of every function in a tuple. | ||
*/ | ||
declare function map<T extends Composable, R>(fn: T, mapper: (res: UnpackData<ReturnType<T>>) => R): Composable<(...args: Parameters<T>) => R>; | ||
declare function map<T extends Composable, R>(fn: T, mapper: (res: UnpackData<T>) => R): Composable<(...args: Parameters<T>) => R>; | ||
/** | ||
* **NOTE :** Try to use [collect](collect) instead wherever possible since it is much safer. `merge` can create domain functions that will always fail in run-time or even overwrite data from successful constituent functions application. The `collect` function does not have these issues and serves a similar purpose. | ||
* @example | ||
* import { mdf, merge } from 'domain-functions' | ||
* | ||
* const a = mdf(z.object({}))(() => ({ a: 'a' })) | ||
* const b = mdf(z.object({}))(() => ({ b: 2 })) | ||
* const df = merge(a, b) | ||
* // ^? DomainFunction<{ a: string, b: number }> | ||
*/ | ||
declare function merge<T extends Composable[]>(...fns: T & AllArguments<T>): Composable<(...args: Parameters<AllArguments<T>[0]>) => MergeObjs<{ | ||
[key in keyof T]: UnpackData<Extract<T[key], Composable>>; | ||
}>>; | ||
/** | ||
* Creates a composite domain function that will return the result of the first successful constituent domain function. **It is important to notice** that all constituent domain functions will be executed in parallel, so be mindful of the side effects. | ||
* @example | ||
* import { mdf, first } from 'domain-functions' | ||
* | ||
* const a = mdf(z.object({ n: z.number() }))(({ n }) => n + 1) | ||
const b = mdf(z.object({ n: z.number() }))(({ n }) => String(n)) | ||
const df = first(a, b) | ||
// ^? DomainFunction<string | number> | ||
*/ | ||
declare function first<T extends Composable[]>(...fns: T & AllArguments<T>): Composable<(...args: Parameters<AllArguments<T>[0]>) => UnpackData<Extract<T[number], Composable>>>; | ||
/** | ||
* Creates a new function that will try to recover from a resulting Failure. When the given function succeeds, its result is returned without changes. | ||
@@ -87,3 +111,3 @@ * @example | ||
*/ | ||
declare function catchError<F extends Composable, C extends (err: Error[], ...originalInput: Parameters<F>) => any>(fn: F, catcher: C): Composable<(...args: Parameters<F>) => Awaited<ReturnType<C>> extends never[] ? UnpackData<ReturnType<F>> extends any[] ? UnpackData<ReturnType<F>> : Awaited<ReturnType<C>> | UnpackData<ReturnType<F>> : Awaited<ReturnType<C>> | UnpackData<ReturnType<F>>>; | ||
declare function catchError<F extends Composable, C extends (err: Error[], ...originalInput: Parameters<F>) => any>(fn: F, catcher: C): Composable<(...args: Parameters<F>) => Awaited<ReturnType<C>> extends never[] ? UnpackData<F> extends any[] ? UnpackData<F> : Awaited<ReturnType<C>> | UnpackData<F> : Awaited<ReturnType<C>> | UnpackData<F>>; | ||
/** | ||
@@ -115,2 +139,2 @@ * Creates a new function that will apply a transformation over a resulting Failure from the given function. When the given function succeeds, its result is returned without changes. | ||
declare function trace(traceFn: (result: Result<unknown>, ...originalInput: unknown[]) => Promise<void> | void): <C extends Composable>(fn: C) => C; | ||
export { all, catchError, collect, map, mapError, mergeObjects, pipe, sequence, trace, }; | ||
export { all, catchError, collect, first, map, mapError, merge, mergeObjects, pipe, sequence, trace, }; |
@@ -1,3 +0,3 @@ | ||
import { DomainFunction } from './index.js'; | ||
import type { Composable, Failure, Fn, Success } from './types.js'; | ||
import type { Composable, Failure, Fn, ParserSchema, Success } from './types.js'; | ||
import { UnpackData } from './types.js'; | ||
declare function success<const T>(data: T): Success<T>; | ||
@@ -24,5 +24,20 @@ declare function failure(errors: Error[]): Failure; | ||
*/ | ||
type OnError = (errors: Error[]) => Error[] | Promise<Error[]>; | ||
declare function fromSuccess<O, T extends Composable<(...a: any[]) => O>>(fn: T, onError?: OnError): T extends Composable<(...a: infer P) => infer O> ? (...args: P) => Promise<O> : never; | ||
declare function fromSuccess<O, T extends DomainFunction<O>>(fn: T, onError?: OnError): (...args: Parameters<DomainFunction>) => Promise<O>; | ||
export { composable, failure, fromSuccess, success }; | ||
declare function fromSuccess<O, T extends Composable<(...a: any[]) => O>>(fn: T, onError?: (errors: Error[]) => Error[] | Promise<Error[]>): T extends Composable<(...a: infer P) => infer O> ? (...args: P) => Promise<O> : never; | ||
/** | ||
* Creates a domain function. | ||
* After giving the input and environment schemas, you can pass a handler function that takes type safe input and environment. That function is gonna catch any errors and always return a Result. | ||
* @param inputSchema the schema for the input | ||
* @param environmentSchema the schema for the environment | ||
* @returns a handler function that takes type safe input and environment | ||
* @example | ||
* const safeFunction = withSchema( | ||
* z.object({ greeting: z.string() }), | ||
* z.object({ user: z.object({ name: z.string() }) }), | ||
* ) | ||
* const myDf = safeFunction(({ greeting }, { user }) => { | ||
* return { message: `${greeting} ${user.name}` } | ||
* }) | ||
*/ | ||
declare function withSchema<I, E>(inputSchema?: ParserSchema<I>, environmentSchema?: ParserSchema<E>): <Output>(handler: (input: I, environment: E) => Output) => Composable<(input?: unknown, environment?: unknown) => Awaited<Output>>; | ||
declare function applySchema<I, E, A extends Composable>(fn: A, inputSchema?: ParserSchema<I>, environmentSchema?: ParserSchema<E>): Composable<(input?: unknown, environment?: unknown) => UnpackData<A>>; | ||
export { composable, failure, fromSuccess, success, withSchema, applySchema }; |
@@ -1,9 +0,8 @@ | ||
export { composable, failure, fromSuccess, success } from './constructors.js'; | ||
export { all, catchError, collect, map, mapError, mergeObjects, pipe, sequence, trace } from './combinators.js'; | ||
export { applySchema, composable, failure, fromSuccess, success, withSchema, } from './constructors.js'; | ||
export { all, catchError, collect, first, map, mapError, merge, mergeObjects, pipe, sequence, trace, } from './combinators.js'; | ||
export { inputFromForm, inputFromFormData, inputFromSearch, inputFromUrl, } from './input-resolvers.js'; | ||
export { toErrorPayload, serialize } from './serializer.js'; | ||
export { EnvironmentError, ErrorList, InputError } from './errors.js'; | ||
export type { AtLeastOne, Composable, Failure, Last, MergeObjs, Result, SerializableError, SerializedResult, Success, TupleToUnion, UnpackAll, UnpackData, } from './types.js'; | ||
export * as df from './df/index.js'; | ||
export type { DomainFunction } from './df/index.js'; | ||
export type { Composable, Failure, Last, MergeObjs, Result, SerializableError, SerializedResult, Success, UnpackAll, UnpackData, } from './types.js'; | ||
export * as environment from './environment/index.js'; | ||
export * as compat from './compat/index.js'; |
@@ -36,8 +36,12 @@ declare namespace Internal { | ||
]> : never : never; | ||
type CommonSubType<A, B> = [A] extends [B] ? A : [B] extends [A] ? B : { | ||
type CommonSubType<A, B> = [A] extends [B] ? A : [B] extends [A] ? B : A extends Record<PropertyKey, any> ? B extends Record<PropertyKey, any> ? Prettify<A & B> : { | ||
'Incompatible arguments ': true; | ||
argument1: A; | ||
argument2: B; | ||
} : { | ||
'Incompatible arguments ': true; | ||
argument1: A; | ||
argument2: B; | ||
}; | ||
} | ||
export type { Internal }; |
@@ -27,15 +27,2 @@ import { Internal } from './internal/types.js'; | ||
/** | ||
* It is similar to Partial<T> but it requires at least one property to be defined. | ||
* @example | ||
* type MyType = AtLeastOne<{ a: string, b: number }> | ||
* const a: MyType = { a: 'hello' } | ||
* const b: MyType = { b: 123 } | ||
* const c: MyType = { a: 'hello', b: 123 } | ||
* // The following won't compile: | ||
* const d: MyType = {} | ||
*/ | ||
type AtLeastOne<T, U = { | ||
[K in keyof T]: Pick<T, K>; | ||
}> = Partial<T> & U[keyof U]; | ||
/** | ||
* Returns the last item of a tuple type. | ||
@@ -48,10 +35,2 @@ * @example | ||
type Last<T extends readonly unknown[]> = T extends [...infer _I, infer L] ? L : never; | ||
/** | ||
* Converts a tuple type to a union type. | ||
* @example | ||
* type MyTuple = [string, number] | ||
* type MyUnion = TupleToUnion<MyTuple> | ||
* // ^? string | number | ||
*/ | ||
type TupleToUnion<T extends unknown[]> = T[number]; | ||
type IsNever<A> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends never ? 1 : 2) ? true : false; | ||
@@ -61,5 +40,7 @@ type First<T extends readonly any[]> = T extends [infer F, ...infer _I] ? F : never; | ||
type Composable<T extends Fn = Fn> = (...args: Parameters<T>) => Promise<Result<Awaited<ReturnType<T>>>>; | ||
type UnpackData<T> = Awaited<T> extends Result<infer R> ? R : never; | ||
type UnpackData<T extends Composable> = Extract<Awaited<ReturnType<T>>, { | ||
success: true; | ||
}>['data']; | ||
type UnpackAll<List extends Composable[]> = { | ||
[K in keyof List]: UnpackData<ReturnType<List[K]>>; | ||
[K in keyof List]: UnpackData<List[K]>; | ||
}; | ||
@@ -81,3 +62,3 @@ type PipeReturn<Fns extends any[]> = Fns extends [ | ||
]> : ['Fail to compose', PA, 'does not fit in', PB] : [...Arguments, Composable<(...a: PA) => OA>] : never; | ||
type CollectArguments<T extends Record<string, Composable>> = {} extends Internal.Zip<Internal.Keys<T>, AllArguments<Internal.RecordValuesFromKeysTuple<T, Internal.Keys<T>>>> ? never : Internal.Zip<Internal.Keys<T>, AllArguments<Internal.RecordValuesFromKeysTuple<T, Internal.Keys<T>>>>; | ||
type CollectArguments<T extends Record<string, Composable>> = {} extends Internal.Zip<Internal.Keys<T>, AllArguments<Internal.RecordValuesFromKeysTuple<T, Internal.Keys<T>>>> ? never : AllArguments<Internal.RecordValuesFromKeysTuple<T, Internal.Keys<T>>> extends ['Fail to compose', ...any[]] ? AllArguments<Internal.RecordValuesFromKeysTuple<T, Internal.Keys<T>>> : Internal.Zip<Internal.Keys<T>, AllArguments<Internal.RecordValuesFromKeysTuple<T, Internal.Keys<T>>>>; | ||
type RecordToTuple<T extends Record<string, Composable>> = Internal.RecordValuesFromKeysTuple<T, Internal.Keys<T>>; | ||
@@ -94,2 +75,31 @@ type SerializableError<T extends Error = Error> = { | ||
}; | ||
export type { AllArguments, AtLeastOne, CollectArguments, Composable, Failure, First, Fn, Last, MergeObjs, PipeArguments, PipeReturn, RecordToTuple, Result, SerializableError, SerializedResult, Success, TupleToUnion, UnpackAll, UnpackData, }; | ||
/** | ||
* A parsing error when validating the input or environment schemas. | ||
* This will be transformed into an `InputError` before being returned from the domain function. | ||
* It is usually not visible to the end user unless one wants to write an adapter for a schema validator. | ||
*/ | ||
type ParserIssue = { | ||
path: PropertyKey[]; | ||
message: string; | ||
}; | ||
/** | ||
* The result of input or environment validation. | ||
* See the type `Result` for the return values of domain functions. | ||
* It is usually not visible to the end user unless one wants to write an adapter for a schema validator. | ||
*/ | ||
type ParserResult<T> = { | ||
success: true; | ||
data: T; | ||
} | { | ||
success: false; | ||
error: { | ||
issues: ParserIssue[]; | ||
}; | ||
}; | ||
/** | ||
* The object used to validate either input or environment when creating domain functions. | ||
*/ | ||
type ParserSchema<T extends unknown = unknown> = { | ||
safeParseAsync: (a: unknown) => Promise<ParserResult<T>>; | ||
}; | ||
export type { AllArguments, CollectArguments, Composable, Failure, First, Fn, Last, MergeObjs, ParserIssue, ParserResult, ParserSchema, PipeArguments, PipeReturn, RecordToTuple, Result, SerializableError, SerializedResult, Success, UnpackAll, UnpackData, }; |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
0
99616
47
2027