Skip to content

Commit

Permalink
feat: add satisfies() function (#84)
Browse files Browse the repository at this point in the history
  • Loading branch information
unional authored Nov 17, 2019
1 parent 892cb80 commit 2b742bb
Show file tree
Hide file tree
Showing 7 changed files with 354 additions and 325 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@ A purposely loose comparison tool.
- no spread on array, use `has()/some()` or `every()`
- `undefined` now checks against `undefined` instead of a placeholder for anything. Use `anything` for the previous behavior.

## satisfies(actual, expected)

The simplest way to use `satisfier`.

```ts
import { satisfies } from 'satisfier'

satisfies(1, 1) // true
satisfies({ a: 1 }, { a: v => v === 1}) // true
satisfies([{ a: { b: 'b' }}], [{ a: { b: v => v === 'b' } }]) // true
```

Code completion is available to help you quickly creating your expectation.

## createSatisfier(expectation)

Each property in `expectation` can be a value, a `RegExp`, or a predicate function.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"tersify": "^3.0.6"
},
"devDependencies": {
"@unional/devpkg-node": "^1.4.1",
"@unional/devpkg-node": "^1.4.2",
"assertron": "^7.1.2",
"codecov": "^3.6.1",
"eslint-plugin-harmony": "^3.0.0",
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ export * from './isInInterval';
export * from './isInRange';
export * from './isTypeOf';
export * from './none';
export * from './satisfies';
export * from './some';
export * from './startsWith';
2 changes: 1 addition & 1 deletion src/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Tersible } from 'tersify'

export type Predicate = (value: any, path: (string | number)[]) => boolean | Diff[]
export type Predicate<V = any> = (value: V, path: (string | number)[]) => boolean | Diff[]

export type TersiblePredicate = Tersible<Predicate>

Expand Down
50 changes: 50 additions & 0 deletions src/satisfies.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { satisfies } from '.'

test('expected can be value', () => {
expect(satisfies(false, false)).toBe(true)
expect(satisfies(1, 1)).toBe(true)
expect(satisfies('a', 'a')).toBe(true)
})

test('expected can be predicate', () => {
expect(satisfies(1, v => v === 1)).toBe(true)
})

describe('when actual is object', () => {
test('expected can be object', () => {
expect(satisfies({ a: 1 }, { a: 1 })).toBe(true)
expect(satisfies({ a: 1 }, {})).toBe(true)
})

test('expected can be predicate', () => {
expect(satisfies({ a: 1 }, v => !!v)).toBe(true)
})

test('expected property can be predicate', () => {
expect(satisfies({ a: 1 }, { a: v => v === 1 })).toBe(true)
})

test('deep expected property can be object', () => {
expect(satisfies({ a: { b: 'foo' } }, { a: { b: 'boo' } })).toBe(false)
expect(satisfies({ a: { b: 'foo' } }, { a: {} })).toBe(true)
})

test('deep expected property can be predicate', () => {
expect(satisfies({ a: { b: 'foo' } }, { a: { b: v => v === 'foo' } })).toBe(true)
})
})

describe('when actual is array', () => {
test('expected can be array', () => {
expect(satisfies([{ a: 1 }], [])).toBe(false)
expect(satisfies([{ a: 1 }], [{ a: 1 }])).toBe(true)
})

test('expected can be predicate', () => {
expect(satisfies([{ a: 1 }], v => !!v)).toBe(true)
})

test('expected entry can be predicate', () => {
expect(satisfies([{ a: 1 }], [v => v.a === 1])).toBe(true)
})
});
12 changes: 12 additions & 0 deletions src/satisfies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createSatisfier } from './createSatisfier';
import { Predicate } from './interfaces';

export type TargetedExpectation<T = any> = (
T extends Array<infer R> ? Array<TargetedExpectation<R>> :
T extends object ? { [k in keyof T]?: TargetedExpectation<T[k]> } :
T
) | Predicate<T>

export function satisfies<T = any>(actual: T, expected: TargetedExpectation<T>): boolean {
return createSatisfier(expected as any).test(actual)
}
Loading

0 comments on commit 2b742bb

Please sign in to comment.