@autometa/assertions
Advanced tools
| import type { MatcherContext } from "../core/context"; | ||
| type EnsureTypeOf = "string" | "number" | "boolean" | "bigint" | "symbol" | "undefined" | "object" | "function"; | ||
| export declare function assertToBeTypeOf<T>(ctx: MatcherContext<T>, expected: EnsureTypeOf): void; | ||
| export {}; |
+23
-0
| export interface EnsureOptions { | ||
| readonly label?: string; | ||
| } | ||
| export interface EnsureEachOptions<T> { | ||
| readonly label?: string | ((details: { | ||
| readonly index: number; | ||
| readonly value: T; | ||
| }) => string); | ||
| } | ||
| export interface EnsureTapContext<Negated extends boolean> { | ||
| readonly isNot: Negated; | ||
| readonly label?: string; | ||
| } | ||
| type EnsureTypeOf = "string" | "number" | "boolean" | "bigint" | "symbol" | "undefined" | "object" | "function"; | ||
| type TypeOfResult<T extends EnsureTypeOf> = T extends "string" ? string : T extends "number" ? number : T extends "boolean" ? boolean : T extends "bigint" ? bigint : T extends "symbol" ? symbol : T extends "undefined" ? undefined : T extends "function" ? (...args: never[]) => unknown : T extends "object" ? object | null : never; | ||
| type NarrowByTypeOf<T, Expected extends EnsureTypeOf> = [ | ||
| Extract<T, TypeOfResult<Expected>> | ||
| ] extends [never] ? TypeOfResult<Expected> : Extract<T, TypeOfResult<Expected>>; | ||
| type NarrowToArray<T> = [Extract<T, readonly unknown[]>] extends [never] ? readonly unknown[] : Extract<T, readonly unknown[]>; | ||
| type Toggle<Negated extends boolean> = Negated extends true ? false : true; | ||
@@ -8,2 +24,8 @@ interface EnsureChainInternal<T, Negated extends boolean> { | ||
| readonly not: EnsureChainInternal<T, Toggle<Negated>>; | ||
| tap(fn: (value: T, context: EnsureTapContext<Negated>) => void): EnsureChainInternal<T, Negated>; | ||
| map<U, Arr extends readonly unknown[]>(this: EnsureChainInternal<Arr, Negated>, selector: (value: Arr[number], index: number, array: Arr) => U, options?: EnsureOptions): EnsureChainInternal<U[], Negated>; | ||
| each<Arr extends readonly unknown[]>(this: EnsureChainInternal<Arr, Negated>, fn: (value: EnsureChainInternal<Arr[number], Negated>, index: number) => void, options?: EnsureEachOptions<Arr[number]>): EnsureChainInternal<Arr, Negated>; | ||
| pluck<Arr extends readonly object[], K extends keyof Arr[number]>(this: EnsureChainInternal<Arr, Negated>, key: K, options?: EnsureOptions): EnsureChainInternal<Array<Arr[number][K]>, Negated>; | ||
| prop<Obj extends object, K extends keyof Obj>(this: EnsureChainInternal<Obj, Negated>, key: K, options?: EnsureOptions): EnsureChainInternal<Obj[K], Negated>; | ||
| toBeTypeOf<Expected extends EnsureTypeOf>(expected: Expected): EnsureChainInternal<Negated extends true ? T : NarrowByTypeOf<T, Expected>, Negated>; | ||
| toBe(expected: T): EnsureChainInternal<T, Negated>; | ||
@@ -22,2 +44,3 @@ toEqual(expected: unknown): EnsureChainInternal<T, Negated>; | ||
| toBeCloseTo(expected: number, precision?: number): EnsureChainInternal<Negated extends true ? T : Extract<T, number>, Negated>; | ||
| toBeInstanceOf(ctor: ArrayConstructor): EnsureChainInternal<Negated extends true ? T : NarrowToArray<T>, Negated>; | ||
| toBeInstanceOf<Ctor extends abstract new (...args: never[]) => unknown>(ctor: Ctor): EnsureChainInternal<Negated extends true ? T : InstanceType<Ctor>, Negated>; | ||
@@ -24,0 +47,0 @@ toBeObjectContaining<Shape extends Record<PropertyKey, unknown>>(shape: Shape): EnsureChainInternal<T, Negated>; |
+142
-0
@@ -500,2 +500,20 @@ 'use strict'; | ||
| // src/matchers/type-of.ts | ||
| function assertToBeTypeOf(ctx, expected) { | ||
| const actualType = typeof ctx.value; | ||
| const pass = actualType === expected; | ||
| if (ctx.negated ? pass : !pass) { | ||
| const baseMessage = ctx.negated ? `Expected value not to be of type ${expected}` : `Expected value to be of type ${expected}`; | ||
| ctx.fail("toBeTypeOf", { | ||
| message: buildFailureMessage("toBeTypeOf", baseMessage, { | ||
| expected, | ||
| actual: ctx.value, | ||
| extra: [`Received type: ${actualType}`] | ||
| }), | ||
| expected, | ||
| actual: ctx.value | ||
| }); | ||
| } | ||
| } | ||
| // src/matchers/truthiness.ts | ||
@@ -554,2 +572,111 @@ function assertToBeTruthy(ctx) { | ||
| } | ||
| tap(fn) { | ||
| fn(this.state.value, { | ||
| isNot: this.state.negated, | ||
| ...this.state.label !== void 0 ? { label: this.state.label } : {} | ||
| }); | ||
| return this; | ||
| } | ||
| map(selector, options = {}) { | ||
| const chain = this; | ||
| const current = chain.state.value; | ||
| if (!Array.isArray(current)) { | ||
| chain.fail("map", { | ||
| message: "Expected value to be an array in order to use ensure(...).map(...)", | ||
| actual: chain.state.value, | ||
| expected: "array" | ||
| }); | ||
| } | ||
| const values = current; | ||
| const mapped = values.map( | ||
| (value, index, array) => selector(value, index, array) | ||
| ); | ||
| const nextState = { | ||
| value: mapped, | ||
| negated: chain.state.negated, | ||
| ...options.label !== void 0 ? { label: options.label } : chain.state.label !== void 0 ? { label: chain.state.label } : {} | ||
| }; | ||
| return new _EnsureChainImpl( | ||
| nextState | ||
| ); | ||
| } | ||
| each(fn, options = {}) { | ||
| const chain = this; | ||
| const current = chain.state.value; | ||
| if (!Array.isArray(current)) { | ||
| chain.fail("each", { | ||
| message: "Expected value to be an array in order to use ensure(...).each(...)", | ||
| actual: chain.state.value, | ||
| expected: "array" | ||
| }); | ||
| } | ||
| const values = current; | ||
| for (let index = 0; index < values.length; index += 1) { | ||
| const element = values[index]; | ||
| const elementLabel = chain.buildEachLabel(element, index, options); | ||
| const elementState = { | ||
| value: element, | ||
| negated: chain.state.negated, | ||
| ...elementLabel !== void 0 ? { label: elementLabel } : {} | ||
| }; | ||
| fn( | ||
| new _EnsureChainImpl( | ||
| elementState | ||
| ), | ||
| index | ||
| ); | ||
| } | ||
| return this; | ||
| } | ||
| pluck(key, options = {}) { | ||
| const chain = this; | ||
| const current = chain.state.value; | ||
| if (!Array.isArray(current)) { | ||
| chain.fail("pluck", { | ||
| message: "Expected value to be an array in order to use ensure(...).pluck(...)", | ||
| actual: chain.state.value, | ||
| expected: "array" | ||
| }); | ||
| } | ||
| const values = current; | ||
| const mapped = values.map((element, index) => { | ||
| if (typeof element !== "object" && typeof element !== "function" || element === null) { | ||
| chain.fail("pluck", { | ||
| message: `Expected element at index ${index} to be an object in order to pluck "${String( | ||
| key | ||
| )}"`, | ||
| actual: element, | ||
| expected: "object" | ||
| }); | ||
| } | ||
| return element[key]; | ||
| }); | ||
| const nextState = { | ||
| value: mapped, | ||
| negated: chain.state.negated, | ||
| ...options.label !== void 0 ? { label: options.label } : chain.state.label !== void 0 ? { label: chain.state.label } : {} | ||
| }; | ||
| return new _EnsureChainImpl( | ||
| nextState | ||
| ); | ||
| } | ||
| prop(key, options = {}) { | ||
| const chain = this; | ||
| const current = chain.state.value; | ||
| if (typeof current !== "object" && typeof current !== "function" || current === null) { | ||
| chain.fail("prop", { | ||
| message: "Expected value to be an object in order to use ensure(...).prop(...)", | ||
| actual: chain.state.value, | ||
| expected: "object" | ||
| }); | ||
| } | ||
| const nextState = { | ||
| value: current[key], | ||
| negated: chain.state.negated, | ||
| ...options.label !== void 0 ? { label: options.label } : chain.state.label !== void 0 ? { label: chain.state.label } : {} | ||
| }; | ||
| return new _EnsureChainImpl( | ||
| nextState | ||
| ); | ||
| } | ||
| toBe(expected) { | ||
@@ -590,2 +717,7 @@ assertToBe(this.createContext(), expected); | ||
| } | ||
| toBeTypeOf(expected) { | ||
| assertToBeTypeOf(this.createContext(), expected); | ||
| const next = this.state.negated ? this : this.rewrap(this.state.value); | ||
| return next; | ||
| } | ||
| toBeGreaterThan(expected) { | ||
@@ -663,2 +795,12 @@ const actual = assertToBeGreaterThan(this.createContext(), expected); | ||
| } | ||
| buildEachLabel(value, index, options) { | ||
| if (typeof options.label === "function") { | ||
| return options.label({ index, value }); | ||
| } | ||
| const baseLabel = options.label ?? this.state.label; | ||
| if (!baseLabel) { | ||
| return void 0; | ||
| } | ||
| return `${baseLabel} (index ${index})`; | ||
| } | ||
| fail(matcher, details) { | ||
@@ -665,0 +807,0 @@ const errorDetails = { |
+1
-1
| export { EnsureError } from "./assertion-error"; | ||
| export { ensure, type EnsureChain, type EnsureOptions } from "./ensure"; | ||
| export { ensure, type EnsureChain, type EnsureEachOptions, type EnsureOptions, type EnsureTapContext, } from "./ensure"; | ||
| export { createDefaultEnsureFactory, createEnsureFactory, type EnsurePluginFacets, type AssertionPlugin, type AssertionPluginContext, type EnsureFacade, type EnsureFactory, type EnsureInvoke, type EnsureInvokeWithAlways, type EnsureInvoker, } from "./plugins"; | ||
| export { runtimeAssertionsPlugin, type RuntimeAssertions, } from "./plugins/runtime-assertions-plugin"; |
+142
-0
@@ -498,2 +498,20 @@ import { inspect } from 'node:util'; | ||
| // src/matchers/type-of.ts | ||
| function assertToBeTypeOf(ctx, expected) { | ||
| const actualType = typeof ctx.value; | ||
| const pass = actualType === expected; | ||
| if (ctx.negated ? pass : !pass) { | ||
| const baseMessage = ctx.negated ? `Expected value not to be of type ${expected}` : `Expected value to be of type ${expected}`; | ||
| ctx.fail("toBeTypeOf", { | ||
| message: buildFailureMessage("toBeTypeOf", baseMessage, { | ||
| expected, | ||
| actual: ctx.value, | ||
| extra: [`Received type: ${actualType}`] | ||
| }), | ||
| expected, | ||
| actual: ctx.value | ||
| }); | ||
| } | ||
| } | ||
| // src/matchers/truthiness.ts | ||
@@ -552,2 +570,111 @@ function assertToBeTruthy(ctx) { | ||
| } | ||
| tap(fn) { | ||
| fn(this.state.value, { | ||
| isNot: this.state.negated, | ||
| ...this.state.label !== void 0 ? { label: this.state.label } : {} | ||
| }); | ||
| return this; | ||
| } | ||
| map(selector, options = {}) { | ||
| const chain = this; | ||
| const current = chain.state.value; | ||
| if (!Array.isArray(current)) { | ||
| chain.fail("map", { | ||
| message: "Expected value to be an array in order to use ensure(...).map(...)", | ||
| actual: chain.state.value, | ||
| expected: "array" | ||
| }); | ||
| } | ||
| const values = current; | ||
| const mapped = values.map( | ||
| (value, index, array) => selector(value, index, array) | ||
| ); | ||
| const nextState = { | ||
| value: mapped, | ||
| negated: chain.state.negated, | ||
| ...options.label !== void 0 ? { label: options.label } : chain.state.label !== void 0 ? { label: chain.state.label } : {} | ||
| }; | ||
| return new _EnsureChainImpl( | ||
| nextState | ||
| ); | ||
| } | ||
| each(fn, options = {}) { | ||
| const chain = this; | ||
| const current = chain.state.value; | ||
| if (!Array.isArray(current)) { | ||
| chain.fail("each", { | ||
| message: "Expected value to be an array in order to use ensure(...).each(...)", | ||
| actual: chain.state.value, | ||
| expected: "array" | ||
| }); | ||
| } | ||
| const values = current; | ||
| for (let index = 0; index < values.length; index += 1) { | ||
| const element = values[index]; | ||
| const elementLabel = chain.buildEachLabel(element, index, options); | ||
| const elementState = { | ||
| value: element, | ||
| negated: chain.state.negated, | ||
| ...elementLabel !== void 0 ? { label: elementLabel } : {} | ||
| }; | ||
| fn( | ||
| new _EnsureChainImpl( | ||
| elementState | ||
| ), | ||
| index | ||
| ); | ||
| } | ||
| return this; | ||
| } | ||
| pluck(key, options = {}) { | ||
| const chain = this; | ||
| const current = chain.state.value; | ||
| if (!Array.isArray(current)) { | ||
| chain.fail("pluck", { | ||
| message: "Expected value to be an array in order to use ensure(...).pluck(...)", | ||
| actual: chain.state.value, | ||
| expected: "array" | ||
| }); | ||
| } | ||
| const values = current; | ||
| const mapped = values.map((element, index) => { | ||
| if (typeof element !== "object" && typeof element !== "function" || element === null) { | ||
| chain.fail("pluck", { | ||
| message: `Expected element at index ${index} to be an object in order to pluck "${String( | ||
| key | ||
| )}"`, | ||
| actual: element, | ||
| expected: "object" | ||
| }); | ||
| } | ||
| return element[key]; | ||
| }); | ||
| const nextState = { | ||
| value: mapped, | ||
| negated: chain.state.negated, | ||
| ...options.label !== void 0 ? { label: options.label } : chain.state.label !== void 0 ? { label: chain.state.label } : {} | ||
| }; | ||
| return new _EnsureChainImpl( | ||
| nextState | ||
| ); | ||
| } | ||
| prop(key, options = {}) { | ||
| const chain = this; | ||
| const current = chain.state.value; | ||
| if (typeof current !== "object" && typeof current !== "function" || current === null) { | ||
| chain.fail("prop", { | ||
| message: "Expected value to be an object in order to use ensure(...).prop(...)", | ||
| actual: chain.state.value, | ||
| expected: "object" | ||
| }); | ||
| } | ||
| const nextState = { | ||
| value: current[key], | ||
| negated: chain.state.negated, | ||
| ...options.label !== void 0 ? { label: options.label } : chain.state.label !== void 0 ? { label: chain.state.label } : {} | ||
| }; | ||
| return new _EnsureChainImpl( | ||
| nextState | ||
| ); | ||
| } | ||
| toBe(expected) { | ||
@@ -588,2 +715,7 @@ assertToBe(this.createContext(), expected); | ||
| } | ||
| toBeTypeOf(expected) { | ||
| assertToBeTypeOf(this.createContext(), expected); | ||
| const next = this.state.negated ? this : this.rewrap(this.state.value); | ||
| return next; | ||
| } | ||
| toBeGreaterThan(expected) { | ||
@@ -661,2 +793,12 @@ const actual = assertToBeGreaterThan(this.createContext(), expected); | ||
| } | ||
| buildEachLabel(value, index, options) { | ||
| if (typeof options.label === "function") { | ||
| return options.label({ index, value }); | ||
| } | ||
| const baseLabel = options.label ?? this.state.label; | ||
| if (!baseLabel) { | ||
| return void 0; | ||
| } | ||
| return `${baseLabel} (index ${index})`; | ||
| } | ||
| fail(matcher, details) { | ||
@@ -663,0 +805,0 @@ const errorDetails = { |
+5
-5
| { | ||
| "name": "@autometa/assertions", | ||
| "version": "1.0.0-rc.4", | ||
| "version": "1.0.0-rc.5", | ||
| "description": "Runner-agnostic assertion helpers powered by ensure(value) matcher chains.", | ||
@@ -25,7 +25,7 @@ "type": "module", | ||
| "tslib": "^2.6.2", | ||
| "@autometa/cucumber-expressions": "1.0.0-rc.2", | ||
| "@autometa/gherkin": "1.0.0-rc.2", | ||
| "@autometa/injection": "1.0.0-rc.2", | ||
| "@autometa/executor": "1.0.0-rc.4", | ||
| "@autometa/scopes": "1.0.0-rc.1", | ||
| "@autometa/cucumber-expressions": "1.0.0-rc.2", | ||
| "@autometa/injection": "1.0.0-rc.2" | ||
| "@autometa/scopes": "1.0.0-rc.1" | ||
| }, | ||
@@ -42,4 +42,4 @@ "devDependencies": { | ||
| "vitest": "1.4.0", | ||
| "tsup-config": "0.1.0", | ||
| "eslint-config-custom": "0.6.0", | ||
| "tsup-config": "0.1.0", | ||
| "tsconfig": "0.7.0" | ||
@@ -46,0 +46,0 @@ }, |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
256124
17.61%27
3.85%2353
15.17%