Skip to content

Commit

Permalink
Add ValueAssertion
Browse files Browse the repository at this point in the history
  • Loading branch information
chuigda committed Oct 13, 2021
1 parent a86953f commit 9498112
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 17 deletions.
65 changes: 56 additions & 9 deletions typeAssert.cjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict'

/* eslint-disable no-extend-native, no-use-before-define, func-names, no-shadow, no-throw-literal */
const TypeStrings = {
String: typeof '',
Symbol: typeof Symbol(''),
Expand Down Expand Up @@ -28,6 +29,12 @@ const typeAssertError = (path, message) => {
throw errMsg
}

const assertEquals = (path, expected, got) => {
if (expected !== got) {
typeAssertError(path, `expected value "${expected}", got "${got}"`)
}
}

const assertTypeEqImpl = (path, expected, got) => {
if (expected !== got) {
typeAssertError(path, `expected type "${expected}", got "${got}"`)
Expand Down Expand Up @@ -83,7 +90,7 @@ const typeAssertImpl = (path, object, assertion) => {
assertTypeEqImpl2(path, RegExp.prototype.constructor, object.constructor, type)
return
default:
// fall through
// fall through
}
}

Expand Down Expand Up @@ -115,6 +122,8 @@ const typeAssertImpl = (path, object, assertion) => {
for (const partIdx in assertion.types) {
typeAssertImpl(`${path}:<${partIdx}>`, object, assertion.types[partIdx])
}
} else if (assertion.constructor === ValueAssertion.prototype.constructor) {
assertEquals(`${path}:value`, object, assertion.value)
} else if (object === undefined) {
typeAssertError(path, 'unexpected "undefined" value')
} else if (object === null) {
Expand All @@ -131,7 +140,7 @@ const typeAssertImpl = (path, object, assertion) => {
typeAssertError(path, '"array" type assertion should only have one element')
}
} else if (assertionType === TypeStrings.Object
&& assertion.constructor === Object.prototype.constructor) {
&& assertion.constructor === Object.prototype.constructor) {
for (const [field, fieldAssertion] of Object.entries(assertion)) {
typeAssertImpl(`${path}.${field}`, object[field], fieldAssertion)
}
Expand Down Expand Up @@ -166,16 +175,32 @@ const ChainType = (function () {
return ChainType
}())

const ValueAssertion = (function() {
function ValueAssertion(value) {
this.value = value
}

return ValueAssertion
}())

const enableChainAPI = methodNames => {
let orNullName = 'orNull'
let sumWithName = 'sumWith'
let chainWithName = 'chainWith'
let assertValueName = 'assertValue'

if (methodNames !== null && methodNames !== undefined) {
const { orNull, sumWith, chainWith } = methodNames
orNullName = orNull
sumWithName = sumWith
chainWithName = chainWith
const { orNull, sumWith, chainWith, assertValue } = methodNames
orNullName = orNull ? orNull : orNullName
sumWithName = sumWith ? sumWith : sumWithName
chainWithName = chainWith ? chainWith : chainWithName
assertValueName = assertValue ? assertValue : assertValueName
}

const checkChainNotEndedByValueAssertion = types => {
if (types[this.types.length - 1].constructor === ValueAssertion.prototype.constructor) {
typeAssertError('<onbuild> ChainType.prototype.orNull', `should append any assertion after ${assertValueName}`)
}
}

Object.defineProperty(Object.prototype, orNullName, {
Expand Down Expand Up @@ -222,7 +247,7 @@ const enableChainAPI = methodNames => {
configurable: false,
writable: false,
value(that) {
return (new SumType([this])).sumWith(that)
return (new SumType([this]))[sumWithName](that)
}
})

Expand All @@ -231,7 +256,7 @@ const enableChainAPI = methodNames => {
configurable: false,
writable: false,
value(that) {
return (new SumType([`${this}`])).sumWith(that)
return (new SumType([`${this}`]))[sumWithName](that)
}
})

Expand All @@ -240,6 +265,8 @@ const enableChainAPI = methodNames => {
configurable: false,
writable: false,
value(that) {
checkChainNotEndedByValueAssertion(this.types)

if (that.constructor === ChainType.prototype.constructor) {
return new ChainType([...this.types, ...that.types])
} else {
Expand All @@ -253,7 +280,26 @@ const enableChainAPI = methodNames => {
configurable: false,
writable: false,
value(that) {
return (new ChainType([this])).chainWith(that)
return (new ChainType([this]))[chainWithName](that)
}
})

Object.defineProperty(Object.prototype, assertValueName, {
enumerable: false,
configurable: false,
writable: false,
value(that) {
return new ChainType([this, new ValueAssertion(that)])
}
})

Object.defineProperty(ChainType.prototype, assertValueName, {
enumerable: false,
configurable: false,
writable: false,
value(that) {
checkChainNotEndedByValueAssertion(this.types)
return new ChainType([...this.types, new ValueAssertion(that)])
}
})
}
Expand All @@ -264,5 +310,6 @@ module.exports = {
NullableType,
SumType,
ChainType,
ValueAssertion,
enableChainAPI
}
62 changes: 54 additions & 8 deletions typeAssert.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable no-extend-native, no-use-before-define, func-names, no-shadow, no-throw-literal */
'use strict'

/* eslint-disable no-extend-native, no-use-before-define, func-names, no-shadow, no-throw-literal */
export const TypeStrings = {
String: typeof '',
Symbol: typeof Symbol(''),
Expand Down Expand Up @@ -28,6 +29,12 @@ const typeAssertError = (path, message) => {
throw errMsg
}

const assertEquals = (path, expected, got) => {
if (expected !== got) {
typeAssertError(path, `expected value "${expected}", got "${got}"`)
}
}

const assertTypeEqImpl = (path, expected, got) => {
if (expected !== got) {
typeAssertError(path, `expected type "${expected}", got "${got}"`)
Expand Down Expand Up @@ -115,6 +122,8 @@ const typeAssertImpl = (path, object, assertion) => {
for (const partIdx in assertion.types) {
typeAssertImpl(`${path}:<${partIdx}>`, object, assertion.types[partIdx])
}
} else if (assertion.constructor === ValueAssertion.prototype.constructor) {
assertEquals(`${path}:value`, object, assertion.value)
} else if (object === undefined) {
typeAssertError(path, 'unexpected "undefined" value')
} else if (object === null) {
Expand Down Expand Up @@ -166,16 +175,32 @@ export const ChainType = (function () {
return ChainType
}())

export const ValueAssertion = (function() {
function ValueAssertion(value) {
this.value = value
}

return ValueAssertion
}())

export const enableChainAPI = methodNames => {
let orNullName = 'orNull'
let sumWithName = 'sumWith'
let chainWithName = 'chainWith'
let assertValueName = 'assertValue'

if (methodNames !== null && methodNames !== undefined) {
const { orNull, sumWith, chainWith } = methodNames
orNullName = orNull
sumWithName = sumWith
chainWithName = chainWith
const { orNull, sumWith, chainWith, assertValue } = methodNames
orNullName = orNull ? orNull : orNullName
sumWithName = sumWith ? sumWith : sumWithName
chainWithName = chainWith ? chainWith : chainWithName
assertValueName = assertValue ? assertValue : assertValueName
}

const checkChainNotEndedByValueAssertion = types => {
if (types[this.types.length - 1].constructor === ValueAssertion.prototype.constructor) {
typeAssertError('<onbuild> ChainType.prototype.orNull', `should append any assertion after ${assertValueName}`)
}
}

Object.defineProperty(Object.prototype, orNullName, {
Expand Down Expand Up @@ -222,7 +247,7 @@ export const enableChainAPI = methodNames => {
configurable: false,
writable: false,
value(that) {
return (new SumType([this])).sumWith(that)
return (new SumType([this]))[sumWithName](that)
}
})

Expand All @@ -231,7 +256,7 @@ export const enableChainAPI = methodNames => {
configurable: false,
writable: false,
value(that) {
return (new SumType([`${this}`])).sumWith(that)
return (new SumType([`${this}`]))[sumWithName](that)
}
})

Expand All @@ -240,6 +265,8 @@ export const enableChainAPI = methodNames => {
configurable: false,
writable: false,
value(that) {
checkChainNotEndedByValueAssertion(this.types)

if (that.constructor === ChainType.prototype.constructor) {
return new ChainType([...this.types, ...that.types])
} else {
Expand All @@ -253,7 +280,26 @@ export const enableChainAPI = methodNames => {
configurable: false,
writable: false,
value(that) {
return (new ChainType([this])).chainWith(that)
return (new ChainType([this]))[chainWithName](that)
}
})

Object.defineProperty(Object.prototype, assertValueName, {
enumerable: false,
configurable: false,
writable: false,
value(that) {
return new ChainType([this, new ValueAssertion(that)])
}
})

Object.defineProperty(ChainType.prototype, assertValueName, {
enumerable: false,
configurable: false,
writable: false,
value(that) {
checkChainNotEndedByValueAssertion(this.types)
return new ChainType([...this.types, new ValueAssertion(that)])
}
})
}

0 comments on commit 9498112

Please sign in to comment.