Skip to content

Commit

Permalink
fix: clarify return types of predefined predicates
Browse files Browse the repository at this point in the history
  • Loading branch information
unional committed Apr 24, 2022
1 parent 805b4c6 commit f5b9e3d
Show file tree
Hide file tree
Showing 24 changed files with 90 additions and 86 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
"eslint": "8.14.0",
"eslint-plugin-harmony": "^6.0.3",
"husky": "^7.0.4",
"is-ci": "^3.0.1",
"jest": "27.5.1",
"jest-validate": "27.5.1",
"jest-watch-suspend": "^1.1.2",
Expand Down
20 changes: 20 additions & 0 deletions ts/anything.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { anything } from './anything'
import { createSatisfier } from './createSatisfier'
import { testArrow, testFn, testSymbol } from './testPredicates'


test('matches against anything', () => {
const s = createSatisfier(anything)
expect(s.exec(undefined)).toBeUndefined()
expect(s.exec(null)).toBeUndefined()
expect(s.exec(false)).toBeUndefined()
expect(s.exec(1)).toBeUndefined()
expect(s.exec(1n)).toBeUndefined()
expect(s.exec('a')).toBeUndefined()
expect(s.exec(Symbol())).toBeUndefined()
expect(s.exec({})).toBeUndefined()
expect(s.exec([])).toBeUndefined()
expect(s.exec(testSymbol)).toBeUndefined()
expect(s.exec(testFn)).toBeUndefined()
expect(s.exec(testArrow)).toBeUndefined()
})
29 changes: 5 additions & 24 deletions ts/createSatisfier.spec.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,6 @@
import { assertType } from 'type-plus'
import { isType } from 'type-plus'
import { anything, createSatisfier } from '.'

const testSymbol = Symbol()
const testArrow = () => true
const testFn = function () { return true }
describe('anything', () => {
test('matches against anything', () => {
const s = createSatisfier(anything)
expect(s.exec(undefined)).toBeUndefined()
expect(s.exec(null)).toBeUndefined()
expect(s.exec(false)).toBeUndefined()
expect(s.exec(1)).toBeUndefined()
expect(s.exec(1n)).toBeUndefined()
expect(s.exec('a')).toBeUndefined()
expect(s.exec(Symbol())).toBeUndefined()
expect(s.exec({})).toBeUndefined()
expect(s.exec([])).toBeUndefined()
expect(s.exec(testFn)).toBeUndefined()
expect(s.exec(testArrow)).toBeUndefined()
})
})
import { testArrow, testFn, testSymbol } from './testPredicates'

describe('undefined', () => {
test('matches only undefined', () => {
Expand Down Expand Up @@ -306,7 +287,7 @@ describe('object', () => {
const predicate = (e: any) => e && e.every((x: any) => x.login)
const s = createSatisfier({
data: predicate
});
})

expect(s.exec({ data: [{ login: 'a' }] })).toBeUndefined()
expect(s.exec({ data: [{ login: 'a' }, { login: 'b' }] })).toBeUndefined()
Expand Down Expand Up @@ -375,7 +356,7 @@ describe('predicate function', () => {
})

test('apply property predicate', () => {
const s = createSatisfier({ data: v => v === 1 });
const s = createSatisfier({ data: v => v === 1 })

expect(s.exec({ data: 1 })).toBeUndefined()
expect(s.exec({ data: 2 })).toEqual([{ path: ['data'], expected: s.expected.data, actual: 2 }])
Expand All @@ -386,7 +367,7 @@ describe('predicate function', () => {
test('use generic to lock in the type of the input', () => {
const s = createSatisfier<{ a: number }>(undefined)
const y: Parameters<typeof s.exec> = {} as any
assertType<{ a: number }>(y[0])
isType.equal<true, { a: number }, typeof y[0]>()
})

describe('test()', () => {
Expand Down
4 changes: 1 addition & 3 deletions ts/createSatisfier.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { anything } from './anything'
import { Diff, Predicate, Satisfier } from './interfaces'

export interface ExpectionArray extends Array<Expectation> { }

export type Expectation = symbol | undefined | null | boolean | number | bigint |
string | RegExp | ExpectionArray | { [key: string]: Expectation } | Predicate
string | RegExp | Array<Expectation> | { [key: string]: Expectation } | Predicate

export function createSatisfier<T = any>(expected: Expectation): Satisfier<T> {
return {
Expand Down
5 changes: 3 additions & 2 deletions ts/every.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { tersible, tersify } from 'tersify'
import { Tersible, tersible, tersify } from 'tersify'
import { createSatisfier } from './createSatisfier'
import { Predicate } from './interfaces'

/**
* Check if every entry in the array satisfies the expectation.
* @param expectation expectation
*/
export function every(expectation: any) {
export function every(expectation: any): Tersible<Predicate> {
const s = createSatisfier(expectation)
return tersible((e: any) => e && Array.isArray(e) && e.reduce((p, v, i) => {
const d = s.exec(v)
Expand Down
2 changes: 1 addition & 1 deletion ts/formatDiffs.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createSatisfier, every, formatDiffs, has } from '.';
import { createSatisfier, every, formatDiffs, has } from '.'

test('index is wrapped with []', () => {
const diffs = createSatisfier(every({ a: { b: { c: /foo/ } } })).exec([{ a: {} }, { a: { b: {} } }, { a: { b: { c: 'boo' } } }])
Expand Down
4 changes: 2 additions & 2 deletions ts/formatDiffs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { tersify } from 'tersify';
import { Diff } from './interfaces';
import { tersify } from 'tersify'
import { Diff } from './interfaces'

export function formatDiffs(diffs: Diff[] | undefined) {
if (!diffs) return ''
Expand Down
6 changes: 3 additions & 3 deletions ts/has.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import t from 'assert';
import a from 'assertron';
import { createSatisfier, has } from '.';
import t from 'assert'
import a from 'assertron'
import { createSatisfier, has } from '.'

test('non array returns false', () => {
a.false(createSatisfier(has(1)).test(undefined))
Expand Down
5 changes: 3 additions & 2 deletions ts/has.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { tersible, tersify } from 'tersify'
import { Tersible, tersible, tersify } from 'tersify'
import { createSatisfier } from './createSatisfier'
import { Predicate } from './interfaces'

/**
* Check if an array has entries satisfy the expectations in order.
*/
export function has(...expectations: any[]) {
export function has(...expectations: any[]): Tersible<Predicate> {
return tersible((arr: any) => {
if (!Array.isArray(arr)) return false
let index = 0
Expand Down
26 changes: 13 additions & 13 deletions ts/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
export * from './anything';
export * from './createSatisfier';
export * from './every';
export * from './formatDiffs';
export * from './has';
export * from './interfaces';
export * from './isInInterval';
export * from './isInRange';
export * from './isTypeOf';
export * from './none';
export * from './satisfies';
export * from './some';
export * from './startsWith';
export * from './anything'
export * from './createSatisfier'
export * from './every'
export * from './formatDiffs'
export * from './has'
export * from './interfaces'
export * from './isInInterval'
export * from './isInRange'
export * from './isTypeOf'
export * from './none'
export * from './satisfies'
export * from './some'
export * from './startsWith'
6 changes: 3 additions & 3 deletions ts/isInInterval.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import t from 'assert';
import a from 'assertron';
import { createSatisfier, isInClosedInterval, isInLeftClosedInterval, isInOpenInterval, isInRightClosedInterval } from '.';
import t from 'assert'
import a from 'assertron'
import { createSatisfier, isInClosedInterval, isInLeftClosedInterval, isInOpenInterval, isInRightClosedInterval } from '.'

test('open interval', () => {
a.false(createSatisfier(isInOpenInterval(1, 3)).test(1))
Expand Down
11 changes: 6 additions & 5 deletions ts/isInInterval.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { tersible } from 'tersify'
import { Tersible, tersible } from 'tersify'
import { Predicate } from './interfaces'

export function isInOpenInterval(start: number, end: number) {
export function isInOpenInterval(start: number, end: number): Tersible<Predicate> {
return tersible((a: any) => a > start && (a < end), () => `(${start}...${end})`)
}
export function isInClosedInterval(start: number, end: number) {
export function isInClosedInterval(start: number, end: number): Tersible<Predicate> {
return tersible((a: any) => a >= start && a <= end, () => `[${start}...${end}]`)
}

export function isInLeftClosedInterval(start: number, end: number) {
export function isInLeftClosedInterval(start: number, end: number): Tersible<Predicate> {
return tersible((a: any) => a >= start && (a < end), () => `[${start}...${end})`)
}

export function isInRightClosedInterval(start: number, end: number) {
export function isInRightClosedInterval(start: number, end: number): Tersible<Predicate> {
return tersible((a: any) => a > start && a <= end, () => `(${start}...${end}]`)
}
5 changes: 3 additions & 2 deletions ts/isInRange.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { tersible } from 'tersify'
import { Tersible, tersible } from 'tersify'
import { Predicate } from './interfaces'

export function isInRange(start: number, end: number) {
export function isInRange(start: number, end: number): Tersible<Predicate> {
return tersible((a: any) => a >= start && a <= end, () => `[${start}...${end}]`)
}
5 changes: 3 additions & 2 deletions ts/isTypeOf.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { tersible } from 'tersify'
import { Tersible, tersible } from 'tersify'
import { Predicate } from './interfaces'

export function isTypeOf(x: 'number' | 'boolean' | 'string') {
export function isTypeOf(x: 'number' | 'boolean' | 'string'): Tersible<Predicate>{
return tersible(
// tslint:disable-next-line:strict-type-predicates
(a: any) => typeof a === x,
Expand Down
6 changes: 3 additions & 3 deletions ts/none.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import t from 'assert';
import a from 'assertron';
import { createSatisfier, none } from '.';
import t from 'assert'
import a from 'assertron'
import { createSatisfier, none } from '.'

test('non array returns false', () => {
a.false(createSatisfier(none({ a: 1 })).test(true))
Expand Down
5 changes: 3 additions & 2 deletions ts/none.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { tersible, tersify } from 'tersify'
import { Tersible, tersible, tersify } from 'tersify'
import { createSatisfier } from './createSatisfier'
import { Predicate } from './interfaces'

/**
* Check if an array have no entry satisfying the expectation.
* @param expectation expectation
*/
export function none(expectation: any) {
export function none(expectation: any): Tersible<Predicate> {
const s = createSatisfier(expectation)
return tersible((e: any) => e && Array.isArray(e) && !e.some(v => s.test(v)), () => `none(${tersify(expectation)})`)
}
2 changes: 1 addition & 1 deletion ts/satisfies.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@ describe('when actual is array', () => {
test('expected entry can be predicate', () => {
expect(satisfies([{ a: 1 }], [v => v.a === 1])).toBe(true)
})
});
})
4 changes: 2 additions & 2 deletions ts/satisfies.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createSatisfier } from './createSatisfier';
import { Predicate } from './interfaces';
import { createSatisfier } from './createSatisfier'
import { Predicate } from './interfaces'

export type TargetedExpectation<T = any> = (
T extends Array<infer R> ? Array<TargetedExpectation<R>> :
Expand Down
4 changes: 2 additions & 2 deletions ts/some.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import t from 'assert'
import a from 'assertron'

import { createSatisfier, some } from '.'
import { createSatisfier, satisfies, some } from '.'

test('non array returns false', () => {
a.false(createSatisfier(some({ a: 1 })).test(true))
Expand Down Expand Up @@ -29,5 +29,5 @@ test('tersify()', () => {
})

test('match second', () => {
a.satisfies(['first', 'second'], some('second'))
satisfies(['first', 'second'], some('second'))
})
5 changes: 3 additions & 2 deletions ts/some.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { tersible, tersify } from 'tersify'
import { Tersible, tersible, tersify } from 'tersify'
import { createSatisfier, Expectation } from './createSatisfier'
import { Predicate } from './interfaces'

/**
* Check if an array have at least one entry satisfying the expectation.
* @param expectation expectation
*/
export function some<E extends Expectation>(expectation: E) {
export function some<E extends Expectation>(expectation: E): Tersible<Predicate> {
const s = createSatisfier(expectation)
return tersible((e: any) => e && Array.isArray(e) && e.some(v => s.test(v)), () => `some(${tersify(expectation)})`)
}
3 changes: 1 addition & 2 deletions ts/startsWith.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { createSatisfier } from 'satisfier'
import { startsWith } from '.'
import { createSatisfier, startsWith } from '.'

test('non array returns false', () => {
expect(createSatisfier(startsWith([{ a: 1 }])).test(undefined)).toBe(false)
Expand Down
4 changes: 2 additions & 2 deletions ts/startsWith.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { tersible, tersify } from 'tersify';
import { createSatisfier } from './createSatisfier';
import { tersible, tersify } from 'tersify'
import { createSatisfier } from './createSatisfier'


/**
Expand Down
7 changes: 7 additions & 0 deletions ts/testPredicates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* internal for testing
*/

export const testSymbol = Symbol()
export const testArrow = () => true
export const testFn = function () { return true }
7 changes: 0 additions & 7 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3665,13 +3665,6 @@ is-callable@^1.1.4, is-callable@^1.2.4:
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945"
integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==

is-ci@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.1.tgz#db6ecbed1bd659c43dac0f45661e7674103d1867"
integrity sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==
dependencies:
ci-info "^3.2.0"

is-core-module@^2.2.0, is-core-module@^2.5.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548"
Expand Down

0 comments on commit f5b9e3d

Please sign in to comment.