Repository URL to install this package:
Version:
1.2.17 ▾
|
import { overStaticMethods } from '../../deps'
import {
fromArgumentsToArray as argumentsToArray,
toArray,
} from 'exotic/dist/types/array'
import { isObjWithKeys } from 'exotic/dist/types/obj'
import { hasIn } from 'exotic/dist/types/attributes/properties'
const DEBUGS = []
const DEBUG = x => DEBUGS.push(x)
// const toCoercer = x => (isFunction(x) ? x : Typed(x).coerce)
// @TODO should add check to see if IT HAS A DEFAULT first
// then check the `is`
// then use the default accordingly - at least use default when empty?
const toCoercer = x => Typed(x).coerce
const isClassLike = Klass => isObjWithKeys(Klass)
// possible uses
// 1. wrapping function args
// 2. wrapping NTH function arg
// 3. wrapping Class methods (static, proto)
// 4. defaulting ALL or N args, ignoring HOW MANY args are passed in
// 5. coercing & defaulting args ONLY when they are passed in
// 6. coerceIf ?
function Shape(types) {
// curried, but better api because shape can be arguments style not array
function wrapFunction(fn) {
// arity(fn.length)
// this is the actual wrapping function
return function coersionWrapper() {
const args = argumentsToArray.apply(null, arguments)
// console.log({args}, 'coersionWrapper')
const evolved = args.map((arg, index) => {
// const arg = args[index]
const type = types[index]
const evolver = toCoercer(type)
// console.log({
// evolver,
// arg,
// typeof: typeof type,
// index,
// type,
// typed: Typed(type),
// })
const evolution = evolver(arg)
// @NOTE defaulting
return !evolution && type
? type.empty
? type.empty(arg, index)
: type
: evolution
})
return fn.apply(this, evolved)
}
}
const wrapMethods = (shape, Klass) => {
const updateMethod = (method, methodName, index) => {
if (hasIn(shape, method)) {
// DEBUG('shape has method')
return wrapFunction(shape[method])(method)
} else {
// DEBUG('no method for shape')
return method
}
}
return overStaticMethods(Klass, updateMethod)
}
const wrapFunctionOrKlass = (shape, functionOrKlass) => {
// DEBUG({shape, functionOrKlass})
if (isClassLike(functionOrKlass)) {
// DEBUG('isClassLike')
return wrapMethods(shape, functionOrKlass)
} else {
// DEBUG('function')
return wrapFunction(functionOrKlass)
}
}
// scoped function class
function shaper(fn) {
return wrapFunctionOrKlass(types, fn)
}
shaper.types = types
shaper.changeByExample = shaper
shaper.wrap = wrapFunctionOrKlass
shaper.wrapMethods = wrapMethods
shaper.wrapFunction = wrapFunction
return shaper
}
// @TODO and this will allow shaping a shema with `Typed` first too
const toShape = function() {
return Shape(
arguments.length === 1
? toArray(arguments[0])
: argumentsToArray.apply(this, arguments)
)
}
export { toShape, Shape }
export default toShape