Skip to content

Commit

Permalink
#2 Adds Optional and Nullable types.
Browse files Browse the repository at this point in the history
  • Loading branch information
thebearingedge committed Sep 11, 2016
1 parent 4ff72d9 commit 07ff896
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 3 deletions.
13 changes: 11 additions & 2 deletions src/diff.js
@@ -1,10 +1,20 @@
import { isNull, isUndefined, isPlainObject, isArray, difference } from 'lodash'
import types from './types'
import { types, Optional, Nullable } from './types'

export default function diff(Shape, obj, options = {}) {

const { strict } = Object.assign({}, { strict: true }, options)

if (Shape instanceof Optional) {
if (isUndefined(obj)) return null
return diff(Shape.Shape, obj, { strict })
}

if (Shape instanceof Nullable) {
if (isNull(obj)) return null
return diff(Shape.Shape, obj, { strict })
}

if (isArray(Shape)) {

if (!isArray(obj)) {
Expand All @@ -28,7 +38,6 @@ export default function diff(Shape, obj, options = {}) {
if (strict) {
const objKeys = Object.keys(obj)
const extraKeys = difference(objKeys, shapeKeys)
.filter(key => !shapeKeys.includes(key))
if (extraKeys.length) {
return extraKeys.reduce((extra, key) => Object.assign(extra, {
[key]: {
Expand Down
57 changes: 57 additions & 0 deletions src/diff.test.js
@@ -1,6 +1,7 @@
import { describe, it } from 'global'
import { expect } from 'chai'
import diff from '../src/diff'
import { Optional, Nullable } from './types'

describe('diff(Shape, obj)', () => {

Expand All @@ -15,13 +16,56 @@ describe('diff(Shape, obj)', () => {
})
})

it('diffs a simple Optional value', () => {
const Shape = Optional(String)
const obj = 1
const result = diff(Shape, obj)
expect(result).to.deep.equal({
actual: 'Number',
expected: 'String',
value: 1
})
})

it('diffs a simple Nullable value', () => {
const Shape = Nullable(String)
const obj = 1
const result = diff(Shape, obj)
expect(result).to.deep.equal({
actual: 'Number',
expected: 'String',
value: 1
})
})

it('ignores a missing Optional value', () => {
const Shape = Optional(String)
const obj = undefined
const result = diff(Shape, obj)
expect(result).to.be.null
})

it('diffs a correct shallow Shape', () => {
const Shape = { name: String }
const obj = { name: 'John Doe' }
const result = diff(Shape, obj)
expect(result).to.be.null
})

it('diffs an Optional shallow Shape', () => {
const Shape = { name: Optional(String) }
const obj = { name: undefined }
const result = diff(Shape, obj)
expect(result).to.be.null
})

it('diffs a Nullable shallow Shape', () => {
const Shape = { name: Nullable(String) }
const obj = { name: null }
const result = diff(Shape, obj)
expect(result).to.be.null
})

it('diffs a shallow shape with unexpected properties', () => {
const Shape = { name: String }
const obj = { id: 1, name: 'John Doe' }
Expand Down Expand Up @@ -54,6 +98,19 @@ describe('diff(Shape, obj)', () => {
})
})

it('diffs an incorrect Optional shallow Shape', () => {
const Shape = { id: Optional(Number) }
const obj = { id: '1' }
const result = diff(Shape, obj)
expect(result).to.deep.equal({
id: {
actual: 'String',
expected: 'Number',
value: '1'
}
})
})

it('diffs a Shape with correct nested Objects', () => {
const Shape = {
id: Number,
Expand Down
1 change: 1 addition & 0 deletions src/index.js
@@ -1,3 +1,4 @@
export diff from './diff'
export matches from './matches'
export assertTypes from './assert-types'
export { Optional, Nullable } from './types'
16 changes: 15 additions & 1 deletion src/types.js
Expand Up @@ -5,7 +5,21 @@ import { isString,
isArray,
isDate } from 'lodash'

export default new Map([
export function Optional(Shape) {
if (!(this instanceof Optional)) {
return new Optional(Shape)
}
this.Shape = Shape
}

export function Nullable(Shape) {
if (!(this instanceof Nullable)) {
return new Nullable(Shape)
}
this.Shape = Shape
}

export const types = new Map([
[String, isString],
[Number, isNumber],
[Boolean, isBoolean],
Expand Down

0 comments on commit 07ff896

Please sign in to comment.