Commit d57a418d authored by Nicolas Biri's avatar Nicolas Biri

Add InstanceOf Type

parent d80bd59b
Pipeline #980 passed with stage
in 1 minute and 31 seconds
......@@ -35,10 +35,12 @@ module.exports =
, Date: _.isDate
, Array: _.isArray
, Object: _.isObject
, Function: _.isFunction
, InstanceOf: function(cls) {
return function InstanceOf(x) {return x.constructor === cls}
const self = x => x.constructor === cls
Object.assign(self, {typeName: 'InstanceOf', class: cls})
return self
}
, Function: _.isFunction
, Range: function(min, max) {
const self = x => x >= min && x <= max
Object.assign(self, {typeName: 'Range', min, max})
......@@ -61,3 +63,66 @@ module.exports.normalizeType = function normalizeType(t) {
}
}
function decomposeParametricType(t) {
switch (t.typeName) {
case 'Range': return `Range(${t.min}, ${t.max})`
case 'InstanceOf': return `InstanceOf(${t.class})`
default: throw new Error(`Unknown type: ${t}`)
}
}
module.exports.stringifyType = function(t) {
switch (t) {
case module.exports.Number: return 'Number'
case module.exports.Positive: return 'Positive'
case module.exports.Negative: return 'Negative'
case module.exports.String: return 'String'
case module.exports.Boolean: return 'Boolean'
case module.exports.Date: return 'Date'
case module.exports.Array: return 'Array'
case module.exports.Function: return 'Function'
case module.exports.Object: return 'Object'
case module.exports.Any: return 'Any'
default: return decomposeParametricType(t)
}
}
function checkRange(t) {
const rangeRegex = /Range\((\d+(?:\.\d+)?), *(\d+(?:\.\d+)?)\)/
const res = rangeRegex.exec(t)
if (res != null) {
return module.exports.Range(res[1], res[2])
}
}
function checkInstanceOf(t) {
const instanceRegex = /InstanceOf\(.*\)/
const res = instanceRegex.exec(t)
if (res != null) {
return module.exports.Object
}
}
module.exports.parseType = function (t) {
switch (t) {
case 'Number': return module.exports.Number
case 'Positive': return module.exports.Positive
case 'Negative': return module.exports.Negative
case 'String': return module.exports.String
case 'Boolean': return module.exports.Boolean
case 'Date': return module.exports.Date
case 'Array': return module.exports.Array
case 'Function': return module.exports.Function
case 'Object': return module.exports.Object
case 'Any': return module.exports.Any
default:
let res = checkRange(t) || checkInstanceOf(t)
if (res !== undefined) {
return res
} else {
throw new Error(`Unknown type: ${t}`)
}
}
}
......@@ -71,32 +71,47 @@ describe('InstanceOf', done => {
it('accepts valid instance', done => {
function Foo(x) {this.x = x}
const r = new JSMF.InstanceOf(Foo)
const r = JSMF.InstanceOf(Foo)
r(new Foo(2)).should.be.true()
done()
})
it('refuses the class itself instance', done => {
function Foo(x) {this.x = x}
const r = new JSMF.InstanceOf(Foo)
const r = JSMF.InstanceOf(Foo)
r(Foo).should.be.false()
done()
})
it('refuses duck typing', done => {
function Foo(x) {this.x = x}
const r = new JSMF.InstanceOf(Foo)
const r = JSMF.InstanceOf(Foo)
r({x: 12}).should.be.false()
done()
})
it('ends up as Object after strigification and parsing', done => {
function Foo(x) {this.x = x}
const r = new JSMF.InstanceOf(Foo)
JSMF.parseType(JSMF.stringifyType(r)).should.be.eql(JSMF.Object)
done()
})
})
describe('normalizeType', done => {
it ('transform Number to JSMF.Number', done => {
JSMF.normalizeType(Number).should.be.eql(JSMF.Number)
JSMF.normalizeType(String)(2).should.be.false()
done()
})
it ('transform String to JSMF.String', done => {
JSMF.normalizeType(String).should.be.eql(JSMF.String)
done()
})
it ('transform Boolean to JSMF.Boolean', done => {
JSMF.normalizeType(Boolean).should.be.eql(JSMF.Boolean)
done()
})
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment