summaryrefslogtreecommitdiffstats
path: root/contrib/lua-tableshape/tableshape.lua
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--contrib/lua-tableshape/tableshape.lua2324
1 files changed, 2324 insertions, 0 deletions
diff --git a/contrib/lua-tableshape/tableshape.lua b/contrib/lua-tableshape/tableshape.lua
new file mode 100644
index 0000000..ccc7355
--- /dev/null
+++ b/contrib/lua-tableshape/tableshape.lua
@@ -0,0 +1,2324 @@
+local OptionalType, TaggedType, types, is_type
+local BaseType, TransformNode, SequenceNode, FirstOfNode, DescribeNode, NotType, Literal
+local FailedTransform = { }
+local unpack = unpack or table.unpack
+local clone_state
+clone_state = function(state_obj)
+ if type(state_obj) ~= "table" then
+ return { }
+ end
+ local out
+ do
+ local _tbl_0 = { }
+ for k, v in pairs(state_obj) do
+ _tbl_0[k] = v
+ end
+ out = _tbl_0
+ end
+ do
+ local mt = getmetatable(state_obj)
+ if mt then
+ setmetatable(out, mt)
+ end
+ end
+ return out
+end
+local describe_type
+describe_type = function(val)
+ if type(val) == "string" then
+ if not val:match('"') then
+ return "\"" .. tostring(val) .. "\""
+ elseif not val:match("'") then
+ return "'" .. tostring(val) .. "'"
+ else
+ return "`" .. tostring(val) .. "`"
+ end
+ elseif BaseType:is_base_type(val) then
+ return val:_describe()
+ else
+ return tostring(val)
+ end
+end
+local coerce_literal
+coerce_literal = function(value)
+ local _exp_0 = type(value)
+ if "string" == _exp_0 or "number" == _exp_0 or "boolean" == _exp_0 then
+ return Literal(value)
+ elseif "table" == _exp_0 then
+ if BaseType:is_base_type(value) then
+ return value
+ end
+ end
+ return nil, "failed to coerce literal into type, use types.literal() to test for literal value"
+end
+local join_names
+join_names = function(items, sep, last_sep)
+ if sep == nil then
+ sep = ", "
+ end
+ local count = #items
+ local chunks = { }
+ for idx, name in ipairs(items) do
+ if idx > 1 then
+ local current_sep
+ if idx == count then
+ current_sep = last_sep or sep
+ else
+ current_sep = sep
+ end
+ table.insert(chunks, current_sep)
+ end
+ table.insert(chunks, name)
+ end
+ return table.concat(chunks)
+end
+do
+ local _class_0
+ local _base_0 = {
+ __div = function(self, fn)
+ return TransformNode(self, fn)
+ end,
+ __mod = function(self, fn)
+ do
+ local _with_0 = TransformNode(self, fn)
+ _with_0.with_state = true
+ return _with_0
+ end
+ end,
+ __mul = function(_left, _right)
+ local left, err = coerce_literal(_left)
+ if not (left) then
+ error("left hand side of multiplication: " .. tostring(_left) .. ": " .. tostring(err))
+ end
+ local right
+ right, err = coerce_literal(_right)
+ if not (right) then
+ error("right hand side of multiplication: " .. tostring(_right) .. ": " .. tostring(err))
+ end
+ return SequenceNode(left, right)
+ end,
+ __add = function(_left, _right)
+ local left, err = coerce_literal(_left)
+ if not (left) then
+ error("left hand side of addition: " .. tostring(_left) .. ": " .. tostring(err))
+ end
+ local right
+ right, err = coerce_literal(_right)
+ if not (right) then
+ error("right hand side of addition: " .. tostring(_right) .. ": " .. tostring(err))
+ end
+ if left.__class == FirstOfNode then
+ local options = {
+ unpack(left.options)
+ }
+ table.insert(options, right)
+ return FirstOfNode(unpack(options))
+ elseif right.__class == FirstOfNode then
+ return FirstOfNode(left, unpack(right.options))
+ else
+ return FirstOfNode(left, right)
+ end
+ end,
+ __unm = function(self, right)
+ return NotType(right)
+ end,
+ __tostring = function(self)
+ return self:_describe()
+ end,
+ _describe = function(self)
+ return error("Node missing _describe: " .. tostring(self.__class.__name))
+ end,
+ check_value = function(self, ...)
+ local value, state_or_err = self:_transform(...)
+ if value == FailedTransform then
+ return nil, state_or_err
+ end
+ if type(state_or_err) == "table" then
+ return state_or_err
+ else
+ return true
+ end
+ end,
+ transform = function(self, ...)
+ local value, state_or_err = self:_transform(...)
+ if value == FailedTransform then
+ return nil, state_or_err
+ end
+ if type(state_or_err) == "table" then
+ return value, state_or_err
+ else
+ return value
+ end
+ end,
+ repair = function(self, ...)
+ return self:transform(...)
+ end,
+ on_repair = function(self, fn)
+ return (self + types.any / fn * self):describe(function()
+ return self:_describe()
+ end)
+ end,
+ is_optional = function(self)
+ return OptionalType(self)
+ end,
+ describe = function(self, ...)
+ return DescribeNode(self, ...)
+ end,
+ tag = function(self, name)
+ return TaggedType(self, {
+ tag = name
+ })
+ end,
+ clone_opts = function(self)
+ return error("clone_opts is not longer supported")
+ end,
+ __call = function(self, ...)
+ return self:check_value(...)
+ end
+ }
+ _base_0.__index = _base_0
+ _class_0 = setmetatable({
+ __init = function(self, opts) end,
+ __base = _base_0,
+ __name = "BaseType"
+ }, {
+ __index = _base_0,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ local self = _class_0
+ self.is_base_type = function(self, val)
+ do
+ local mt = type(val) == "table" and getmetatable(val)
+ if mt then
+ if mt.__class then
+ return mt.__class.is_base_type == BaseType.is_base_type
+ end
+ end
+ end
+ return false
+ end
+ self.__inherited = function(self, cls)
+ cls.__base.__call = cls.__call
+ cls.__base.__div = self.__div
+ cls.__base.__mod = self.__mod
+ cls.__base.__mul = self.__mul
+ cls.__base.__add = self.__add
+ cls.__base.__unm = self.__unm
+ cls.__base.__tostring = self.__tostring
+ end
+ BaseType = _class_0
+end
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _describe = function(self)
+ return self.node:_describe()
+ end,
+ _transform = function(self, value, state)
+ local state_or_err
+ value, state_or_err = self.node:_transform(value, state)
+ if value == FailedTransform then
+ return FailedTransform, state_or_err
+ else
+ local out
+ local _exp_0 = type(self.t_fn)
+ if "function" == _exp_0 then
+ if self.with_state then
+ out = self.t_fn(value, state_or_err)
+ else
+ out = self.t_fn(value)
+ end
+ else
+ out = self.t_fn
+ end
+ return out, state_or_err
+ end
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, node, t_fn)
+ self.node, self.t_fn = node, t_fn
+ return assert(self.node, "missing node for transform")
+ end,
+ __base = _base_0,
+ __name = "TransformNode",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ TransformNode = _class_0
+end
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _describe = function(self)
+ local item_names
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ local _list_0 = self.sequence
+ for _index_0 = 1, #_list_0 do
+ local i = _list_0[_index_0]
+ _accum_0[_len_0] = describe_type(i)
+ _len_0 = _len_0 + 1
+ end
+ item_names = _accum_0
+ end
+ return join_names(item_names, " then ")
+ end,
+ _transform = function(self, value, state)
+ local _list_0 = self.sequence
+ for _index_0 = 1, #_list_0 do
+ local node = _list_0[_index_0]
+ value, state = node:_transform(value, state)
+ if value == FailedTransform then
+ break
+ end
+ end
+ return value, state
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, ...)
+ self.sequence = {
+ ...
+ }
+ end,
+ __base = _base_0,
+ __name = "SequenceNode",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ SequenceNode = _class_0
+end
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _describe = function(self)
+ local item_names
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ local _list_0 = self.options
+ for _index_0 = 1, #_list_0 do
+ local i = _list_0[_index_0]
+ _accum_0[_len_0] = describe_type(i)
+ _len_0 = _len_0 + 1
+ end
+ item_names = _accum_0
+ end
+ return join_names(item_names, ", ", ", or ")
+ end,
+ _transform = function(self, value, state)
+ if not (self.options[1]) then
+ return FailedTransform, "no options for node"
+ end
+ local _list_0 = self.options
+ for _index_0 = 1, #_list_0 do
+ local node = _list_0[_index_0]
+ local new_val, new_state = node:_transform(value, state)
+ if not (new_val == FailedTransform) then
+ return new_val, new_state
+ end
+ end
+ return FailedTransform, "expected " .. tostring(self:_describe())
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, ...)
+ self.options = {
+ ...
+ }
+ end,
+ __base = _base_0,
+ __name = "FirstOfNode",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ FirstOfNode = _class_0
+end
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _transform = function(self, input, ...)
+ local value, state = self.node:_transform(input, ...)
+ if value == FailedTransform then
+ local err
+ if self.err_handler then
+ err = self.err_handler(input, state)
+ else
+ err = "expected " .. tostring(self:_describe())
+ end
+ return FailedTransform, err
+ end
+ return value, state
+ end,
+ describe = function(self, ...)
+ return DescribeNode(self.node, ...)
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, node, describe)
+ self.node = node
+ local err_message
+ if type(describe) == "table" then
+ describe, err_message = describe.type, describe.error
+ end
+ if type(describe) == "string" then
+ self._describe = function()
+ return describe
+ end
+ else
+ self._describe = describe
+ end
+ if err_message then
+ if type(err_message) == "string" then
+ self.err_handler = function()
+ return err_message
+ end
+ else
+ self.err_handler = err_message
+ end
+ end
+ end,
+ __base = _base_0,
+ __name = "DescribeNode",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ DescribeNode = _class_0
+end
+local AnnotateNode
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ format_error = function(self, value, err)
+ return tostring(tostring(value)) .. ": " .. tostring(err)
+ end,
+ _transform = function(self, value, state)
+ local new_value, state_or_err = self.base_type:_transform(value, state)
+ if new_value == FailedTransform then
+ return FailedTransform, self:format_error(value, state_or_err)
+ else
+ return new_value, state_or_err
+ end
+ end,
+ _describe = function(self)
+ if self.base_type._describe then
+ return self.base_type:_describe()
+ end
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, base_type, opts)
+ self.base_type = assert(coerce_literal(base_type))
+ if opts then
+ if opts.format_error then
+ self.format_error = assert(types.func:transform(opts.format_error))
+ end
+ end
+ end,
+ __base = _base_0,
+ __name = "AnnotateNode",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ AnnotateNode = _class_0
+end
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ update_state = function(self, state, value, ...)
+ local out = clone_state(state)
+ if self.tag_type == "function" then
+ if select("#", ...) > 0 then
+ self.tag_name(out, ..., value)
+ else
+ self.tag_name(out, value)
+ end
+ else
+ if self.tag_array then
+ local existing = out[self.tag_name]
+ if type(existing) == "table" then
+ local copy
+ do
+ local _tbl_0 = { }
+ for k, v in pairs(existing) do
+ _tbl_0[k] = v
+ end
+ copy = _tbl_0
+ end
+ table.insert(copy, value)
+ out[self.tag_name] = copy
+ else
+ out[self.tag_name] = {
+ value
+ }
+ end
+ else
+ out[self.tag_name] = value
+ end
+ end
+ return out
+ end,
+ _transform = function(self, value, state)
+ value, state = self.base_type:_transform(value, state)
+ if value == FailedTransform then
+ return FailedTransform, state
+ end
+ state = self:update_state(state, value)
+ return value, state
+ end,
+ _describe = function(self)
+ local base_description = self.base_type:_describe()
+ return tostring(base_description) .. " tagged " .. tostring(describe_type(self.tag_name))
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, base_type, opts)
+ if opts == nil then
+ opts = { }
+ end
+ self.base_type = base_type
+ self.tag_name = assert(opts.tag, "tagged type missing tag")
+ self.tag_type = type(self.tag_name)
+ if self.tag_type == "string" then
+ if self.tag_name:match("%[%]$") then
+ self.tag_name = self.tag_name:sub(1, -3)
+ self.tag_array = true
+ end
+ end
+ end,
+ __base = _base_0,
+ __name = "TaggedType",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ TaggedType = _class_0
+end
+local TagScopeType
+do
+ local _class_0
+ local _parent_0 = TaggedType
+ local _base_0 = {
+ create_scope_state = function(self, state)
+ return nil
+ end,
+ _transform = function(self, value, state)
+ local scope
+ value, scope = self.base_type:_transform(value, self:create_scope_state(state))
+ if value == FailedTransform then
+ return FailedTransform, scope
+ end
+ if self.tag_name then
+ state = self:update_state(state, scope, value)
+ end
+ return value, state
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, base_type, opts)
+ if opts then
+ return _class_0.__parent.__init(self, base_type, opts)
+ else
+ self.base_type = base_type
+ end
+ end,
+ __base = _base_0,
+ __name = "TagScopeType",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ TagScopeType = _class_0
+end
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _transform = function(self, value, state)
+ if value == nil then
+ return value, state
+ end
+ return self.base_type:_transform(value, state)
+ end,
+ is_optional = function(self)
+ return self
+ end,
+ _describe = function(self)
+ if self.base_type._describe then
+ local base_description = self.base_type:_describe()
+ return "optional " .. tostring(base_description)
+ end
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, base_type)
+ self.base_type = base_type
+ return assert(BaseType:is_base_type(self.base_type), "expected a type checker")
+ end,
+ __base = _base_0,
+ __name = "OptionalType",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ OptionalType = _class_0
+end
+local AnyType
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _transform = function(self, v, state)
+ return v, state
+ end,
+ _describe = function(self)
+ return "anything"
+ end,
+ is_optional = function(self)
+ return self
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, ...)
+ return _class_0.__parent.__init(self, ...)
+ end,
+ __base = _base_0,
+ __name = "AnyType",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ AnyType = _class_0
+end
+local Type
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _transform = function(self, value, state)
+ local got = type(value)
+ if self.t ~= got then
+ return FailedTransform, "expected type " .. tostring(describe_type(self.t)) .. ", got " .. tostring(describe_type(got))
+ end
+ if self.length_type then
+ local len = #value
+ local res
+ res, state = self.length_type:_transform(len, state)
+ if res == FailedTransform then
+ return FailedTransform, tostring(self.t) .. " length " .. tostring(state) .. ", got " .. tostring(len)
+ end
+ end
+ return value, state
+ end,
+ length = function(self, left, right)
+ local l
+ if BaseType:is_base_type(left) then
+ l = left
+ else
+ l = types.range(left, right)
+ end
+ return Type(self.t, {
+ length = l
+ })
+ end,
+ _describe = function(self)
+ local t = "type " .. tostring(describe_type(self.t))
+ if self.length_type then
+ t = t .. " length_type " .. tostring(self.length_type:_describe())
+ end
+ return t
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, t, opts)
+ self.t = t
+ if opts then
+ if opts.length then
+ self.length_type = assert(coerce_literal(opts.length))
+ end
+ end
+ end,
+ __base = _base_0,
+ __name = "Type",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ Type = _class_0
+end
+local ArrayType
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _describe = function(self)
+ return "an array"
+ end,
+ _transform = function(self, value, state)
+ if not (type(value) == "table") then
+ return FailedTransform, "expecting table"
+ end
+ local k = 1
+ for i, v in pairs(value) do
+ if not (type(i) == "number") then
+ return FailedTransform, "non number field: " .. tostring(i)
+ end
+ if not (i == k) then
+ return FailedTransform, "non array index, got " .. tostring(describe_type(i)) .. " but expected " .. tostring(describe_type(k))
+ end
+ k = k + 1
+ end
+ return value, state
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, ...)
+ return _class_0.__parent.__init(self, ...)
+ end,
+ __base = _base_0,
+ __name = "ArrayType",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ ArrayType = _class_0
+end
+local OneOf
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _describe = function(self)
+ local item_names
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ local _list_0 = self.options
+ for _index_0 = 1, #_list_0 do
+ local i = _list_0[_index_0]
+ if type(i) == "table" and i._describe then
+ _accum_0[_len_0] = i:_describe()
+ else
+ _accum_0[_len_0] = describe_type(i)
+ end
+ _len_0 = _len_0 + 1
+ end
+ item_names = _accum_0
+ end
+ return tostring(join_names(item_names, ", ", ", or "))
+ end,
+ _transform = function(self, value, state)
+ if self.options_hash then
+ if self.options_hash[value] then
+ return value, state
+ end
+ else
+ local _list_0 = self.options
+ for _index_0 = 1, #_list_0 do
+ local _continue_0 = false
+ repeat
+ local item = _list_0[_index_0]
+ if item == value then
+ return value, state
+ end
+ if BaseType:is_base_type(item) then
+ local new_value, new_state = item:_transform(value, state)
+ if new_value == FailedTransform then
+ _continue_0 = true
+ break
+ end
+ return new_value, new_state
+ end
+ _continue_0 = true
+ until true
+ if not _continue_0 then
+ break
+ end
+ end
+ end
+ return FailedTransform, "expected " .. tostring(self:_describe())
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, options)
+ self.options = options
+ assert(type(self.options) == "table", "expected table for options in one_of")
+ local fast_opts = types.array_of(types.number + types.string)
+ if fast_opts(self.options) then
+ do
+ local _tbl_0 = { }
+ local _list_0 = self.options
+ for _index_0 = 1, #_list_0 do
+ local v = _list_0[_index_0]
+ _tbl_0[v] = true
+ end
+ self.options_hash = _tbl_0
+ end
+ end
+ end,
+ __base = _base_0,
+ __name = "OneOf",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ OneOf = _class_0
+end
+local AllOf
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _describe = function(self)
+ local item_names
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ local _list_0 = self.types
+ for _index_0 = 1, #_list_0 do
+ local i = _list_0[_index_0]
+ _accum_0[_len_0] = describe_type(i)
+ _len_0 = _len_0 + 1
+ end
+ item_names = _accum_0
+ end
+ return join_names(item_names, " and ")
+ end,
+ _transform = function(self, value, state)
+ local _list_0 = self.types
+ for _index_0 = 1, #_list_0 do
+ local t = _list_0[_index_0]
+ value, state = t:_transform(value, state)
+ if value == FailedTransform then
+ return FailedTransform, state
+ end
+ end
+ return value, state
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, types)
+ self.types = types
+ assert(type(self.types) == "table", "expected table for first argument")
+ local _list_0 = self.types
+ for _index_0 = 1, #_list_0 do
+ local checker = _list_0[_index_0]
+ assert(BaseType:is_base_type(checker), "all_of expects all type checkers")
+ end
+ end,
+ __base = _base_0,
+ __name = "AllOf",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ AllOf = _class_0
+end
+local ArrayOf
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _describe = function(self)
+ return "array of " .. tostring(describe_type(self.expected))
+ end,
+ _transform = function(self, value, state)
+ local pass, err = types.table(value)
+ if not (pass) then
+ return FailedTransform, err
+ end
+ if self.length_type then
+ local len = #value
+ local res
+ res, state = self.length_type:_transform(len, state)
+ if res == FailedTransform then
+ return FailedTransform, "array length " .. tostring(state) .. ", got " .. tostring(len)
+ end
+ end
+ local is_literal = not BaseType:is_base_type(self.expected)
+ local copy, k
+ for idx, item in ipairs(value) do
+ local skip_item = false
+ local transformed_item
+ if is_literal then
+ if self.expected ~= item then
+ return FailedTransform, "array item " .. tostring(idx) .. ": expected " .. tostring(describe_type(self.expected))
+ else
+ transformed_item = item
+ end
+ else
+ local item_val
+ item_val, state = self.expected:_transform(item, state)
+ if item_val == FailedTransform then
+ return FailedTransform, "array item " .. tostring(idx) .. ": " .. tostring(state)
+ end
+ if item_val == nil and not self.keep_nils then
+ skip_item = true
+ else
+ transformed_item = item_val
+ end
+ end
+ if transformed_item ~= item or skip_item then
+ if not (copy) then
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ local _max_0 = idx - 1
+ for _index_0 = 1, _max_0 < 0 and #value + _max_0 or _max_0 do
+ local i = value[_index_0]
+ _accum_0[_len_0] = i
+ _len_0 = _len_0 + 1
+ end
+ copy = _accum_0
+ end
+ k = idx
+ end
+ end
+ if copy and not skip_item then
+ copy[k] = transformed_item
+ k = k + 1
+ end
+ end
+ return copy or value, state
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, expected, opts)
+ self.expected = expected
+ if opts then
+ self.keep_nils = opts.keep_nils and true
+ if opts.length then
+ self.length_type = assert(coerce_literal(opts.length))
+ end
+ end
+ end,
+ __base = _base_0,
+ __name = "ArrayOf",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ local self = _class_0
+ self.type_err_message = "expecting table"
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ ArrayOf = _class_0
+end
+local ArrayContains
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ short_circuit = true,
+ keep_nils = false,
+ _describe = function(self)
+ return "array containing " .. tostring(describe_type(self.contains))
+ end,
+ _transform = function(self, value, state)
+ local pass, err = types.table(value)
+ if not (pass) then
+ return FailedTransform, err
+ end
+ local is_literal = not BaseType:is_base_type(self.contains)
+ local contains = false
+ local copy, k
+ for idx, item in ipairs(value) do
+ local skip_item = false
+ local transformed_item
+ if is_literal then
+ if self.contains == item then
+ contains = true
+ end
+ transformed_item = item
+ else
+ local item_val, new_state = self.contains:_transform(item, state)
+ if item_val == FailedTransform then
+ transformed_item = item
+ else
+ state = new_state
+ contains = true
+ if item_val == nil and not self.keep_nils then
+ skip_item = true
+ else
+ transformed_item = item_val
+ end
+ end
+ end
+ if transformed_item ~= item or skip_item then
+ if not (copy) then
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ local _max_0 = idx - 1
+ for _index_0 = 1, _max_0 < 0 and #value + _max_0 or _max_0 do
+ local i = value[_index_0]
+ _accum_0[_len_0] = i
+ _len_0 = _len_0 + 1
+ end
+ copy = _accum_0
+ end
+ k = idx
+ end
+ end
+ if copy and not skip_item then
+ copy[k] = transformed_item
+ k = k + 1
+ end
+ if contains and self.short_circuit then
+ if copy then
+ for kdx = idx + 1, #value do
+ copy[k] = value[kdx]
+ k = k + 1
+ end
+ end
+ break
+ end
+ end
+ if not (contains) then
+ return FailedTransform, "expected " .. tostring(self:_describe())
+ end
+ return copy or value, state
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, contains, opts)
+ self.contains = contains
+ assert(self.contains, "missing contains")
+ if opts then
+ self.short_circuit = opts.short_circuit and true
+ self.keep_nils = opts.keep_nils and true
+ end
+ end,
+ __base = _base_0,
+ __name = "ArrayContains",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ local self = _class_0
+ self.type_err_message = "expecting table"
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ ArrayContains = _class_0
+end
+local MapOf
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _describe = function(self)
+ return "map of " .. tostring(self.expected_key:_describe()) .. " -> " .. tostring(self.expected_value:_describe())
+ end,
+ _transform = function(self, value, state)
+ local pass, err = types.table(value)
+ if not (pass) then
+ return FailedTransform, err
+ end
+ local key_literal = not BaseType:is_base_type(self.expected_key)
+ local value_literal = not BaseType:is_base_type(self.expected_value)
+ local transformed = false
+ local out = { }
+ for k, v in pairs(value) do
+ local _continue_0 = false
+ repeat
+ local new_k = k
+ local new_v = v
+ if key_literal then
+ if k ~= self.expected_key then
+ return FailedTransform, "map key expected " .. tostring(describe_type(self.expected_key))
+ end
+ else
+ new_k, state = self.expected_key:_transform(k, state)
+ if new_k == FailedTransform then
+ return FailedTransform, "map key " .. tostring(state)
+ end
+ end
+ if value_literal then
+ if v ~= self.expected_value then
+ return FailedTransform, "map value expected " .. tostring(describe_type(self.expected_value))
+ end
+ else
+ new_v, state = self.expected_value:_transform(v, state)
+ if new_v == FailedTransform then
+ return FailedTransform, "map value " .. tostring(state)
+ end
+ end
+ if new_k ~= k or new_v ~= v then
+ transformed = true
+ end
+ if new_k == nil then
+ _continue_0 = true
+ break
+ end
+ out[new_k] = new_v
+ _continue_0 = true
+ until true
+ if not _continue_0 then
+ break
+ end
+ end
+ return transformed and out or value, state
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, expected_key, expected_value)
+ self.expected_key = coerce_literal(expected_key)
+ self.expected_value = coerce_literal(expected_value)
+ end,
+ __base = _base_0,
+ __name = "MapOf",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ MapOf = _class_0
+end
+local Shape
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ open = false,
+ check_all = false,
+ is_open = function(self)
+ return Shape(self.shape, {
+ open = true,
+ check_all = self.check_all or nil
+ })
+ end,
+ _describe = function(self)
+ local parts
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ for k, v in pairs(self.shape) do
+ _accum_0[_len_0] = tostring(describe_type(k)) .. " = " .. tostring(describe_type(v))
+ _len_0 = _len_0 + 1
+ end
+ parts = _accum_0
+ end
+ return "{ " .. tostring(table.concat(parts, ", ")) .. " }"
+ end,
+ _transform = function(self, value, state)
+ local pass, err = types.table(value)
+ if not (pass) then
+ return FailedTransform, err
+ end
+ local check_all = self.check_all
+ local remaining_keys
+ do
+ local _tbl_0 = { }
+ for key in pairs(value) do
+ _tbl_0[key] = true
+ end
+ remaining_keys = _tbl_0
+ end
+ local errors
+ local dirty = false
+ local out = { }
+ for shape_key, shape_val in pairs(self.shape) do
+ local item_value = value[shape_key]
+ if remaining_keys then
+ remaining_keys[shape_key] = nil
+ end
+ local new_val
+ if BaseType:is_base_type(shape_val) then
+ new_val, state = shape_val:_transform(item_value, state)
+ else
+ if shape_val == item_value then
+ new_val, state = item_value, state
+ else
+ new_val, state = FailedTransform, "expected " .. tostring(describe_type(shape_val))
+ end
+ end
+ if new_val == FailedTransform then
+ err = "field " .. tostring(describe_type(shape_key)) .. ": " .. tostring(state)
+ if check_all then
+ if errors then
+ table.insert(errors, err)
+ else
+ errors = {
+ err
+ }
+ end
+ else
+ return FailedTransform, err
+ end
+ else
+ if new_val ~= item_value then
+ dirty = true
+ end
+ out[shape_key] = new_val
+ end
+ end
+ if remaining_keys and next(remaining_keys) then
+ if self.open then
+ for k in pairs(remaining_keys) do
+ out[k] = value[k]
+ end
+ elseif self.extra_fields_type then
+ for k in pairs(remaining_keys) do
+ local item_value = value[k]
+ local tuple
+ tuple, state = self.extra_fields_type:_transform({
+ [k] = item_value
+ }, state)
+ if tuple == FailedTransform then
+ err = "field " .. tostring(describe_type(k)) .. ": " .. tostring(state)
+ if check_all then
+ if errors then
+ table.insert(errors, err)
+ else
+ errors = {
+ err
+ }
+ end
+ else
+ return FailedTransform, err
+ end
+ else
+ do
+ local nk = tuple and next(tuple)
+ if nk then
+ if nk ~= k then
+ dirty = true
+ elseif tuple[nk] ~= item_value then
+ dirty = true
+ end
+ out[nk] = tuple[nk]
+ else
+ dirty = true
+ end
+ end
+ end
+ end
+ else
+ local names
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ for key in pairs(remaining_keys) do
+ _accum_0[_len_0] = describe_type(key)
+ _len_0 = _len_0 + 1
+ end
+ names = _accum_0
+ end
+ err = "extra fields: " .. tostring(table.concat(names, ", "))
+ if check_all then
+ if errors then
+ table.insert(errors, err)
+ else
+ errors = {
+ err
+ }
+ end
+ else
+ return FailedTransform, err
+ end
+ end
+ end
+ if errors and next(errors) then
+ return FailedTransform, table.concat(errors, "; ")
+ end
+ return dirty and out or value, state
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, shape, opts)
+ self.shape = shape
+ assert(type(self.shape) == "table", "expected table for shape")
+ if opts then
+ if opts.extra_fields then
+ assert(BaseType:is_base_type(opts.extra_fields), "extra_fields_type must be type checker")
+ self.extra_fields_type = opts.extra_fields
+ end
+ self.open = opts.open and true
+ self.check_all = opts.check_all and true
+ if self.open then
+ assert(not self.extra_fields_type, "open can not be combined with extra_fields")
+ end
+ if self.extra_fields_type then
+ return assert(not self.open, "extra_fields can not be combined with open")
+ end
+ end
+ end,
+ __base = _base_0,
+ __name = "Shape",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ local self = _class_0
+ self.type_err_message = "expecting table"
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ Shape = _class_0
+end
+local Partial
+do
+ local _class_0
+ local _parent_0 = Shape
+ local _base_0 = {
+ open = true,
+ is_open = function(self)
+ return error("is_open has no effect on Partial")
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, ...)
+ return _class_0.__parent.__init(self, ...)
+ end,
+ __base = _base_0,
+ __name = "Partial",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ Partial = _class_0
+end
+local Pattern
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _describe = function(self)
+ return "pattern " .. tostring(describe_type(self.pattern))
+ end,
+ _transform = function(self, value, state)
+ local test_value
+ if self.coerce then
+ if BaseType:is_base_type(self.coerce) then
+ local c_res, err = self.coerce:_transform(value)
+ if c_res == FailedTransform then
+ return FailedTransform, err
+ end
+ test_value = c_res
+ else
+ test_value = tostring(value)
+ end
+ else
+ test_value = value
+ end
+ local t_res, err = types.string(test_value)
+ if not (t_res) then
+ return FailedTransform, err
+ end
+ if test_value:match(self.pattern) then
+ return value, state
+ else
+ return FailedTransform, "doesn't match " .. tostring(self:_describe())
+ end
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, pattern, opts)
+ self.pattern = pattern
+ assert(type(self.pattern) == "string", "Pattern must be a string")
+ if opts then
+ self.coerce = opts.coerce
+ return assert(opts.initial_type == nil, "initial_type has been removed from types.pattern (got: " .. tostring(opts.initial_type) .. ")")
+ end
+ end,
+ __base = _base_0,
+ __name = "Pattern",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ Pattern = _class_0
+end
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _describe = function(self)
+ return describe_type(self.value)
+ end,
+ _transform = function(self, value, state)
+ if self.value ~= value then
+ return FailedTransform, "expected " .. tostring(self:_describe())
+ end
+ return value, state
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, value)
+ self.value = value
+ end,
+ __base = _base_0,
+ __name = "Literal",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ Literal = _class_0
+end
+local Custom
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _describe = function(self)
+ return "custom checker " .. tostring(self.fn)
+ end,
+ _transform = function(self, value, state)
+ local pass, err = self.fn(value, state)
+ if not (pass) then
+ return FailedTransform, err or "failed custom check"
+ end
+ return value, state
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, fn)
+ self.fn = fn
+ return assert(type(self.fn) == "function", "custom checker must be a function")
+ end,
+ __base = _base_0,
+ __name = "Custom",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ Custom = _class_0
+end
+local Equivalent
+do
+ local _class_0
+ local values_equivalent
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _describe = function(self)
+ return "equivalent to " .. tostring(describe_type(self.val))
+ end,
+ _transform = function(self, value, state)
+ if values_equivalent(self.val, value) then
+ return value, state
+ else
+ return FailedTransform, "not equivalent to " .. tostring(self.val)
+ end
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, val)
+ self.val = val
+ end,
+ __base = _base_0,
+ __name = "Equivalent",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ local self = _class_0
+ values_equivalent = function(a, b)
+ if a == b then
+ return true
+ end
+ if type(a) == "table" and type(b) == "table" then
+ local seen_keys = { }
+ for k, v in pairs(a) do
+ seen_keys[k] = true
+ if not (values_equivalent(v, b[k])) then
+ return false
+ end
+ end
+ for k, v in pairs(b) do
+ local _continue_0 = false
+ repeat
+ if seen_keys[k] then
+ _continue_0 = true
+ break
+ end
+ if not (values_equivalent(v, a[k])) then
+ return false
+ end
+ _continue_0 = true
+ until true
+ if not _continue_0 then
+ break
+ end
+ end
+ return true
+ else
+ return false
+ end
+ end
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ Equivalent = _class_0
+end
+local Range
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _transform = function(self, value, state)
+ local res
+ res, state = self.value_type:_transform(value, state)
+ if res == FailedTransform then
+ return FailedTransform, "range " .. tostring(state)
+ end
+ if value < self.left then
+ return FailedTransform, "not in " .. tostring(self:_describe())
+ end
+ if value > self.right then
+ return FailedTransform, "not in " .. tostring(self:_describe())
+ end
+ return value, state
+ end,
+ _describe = function(self)
+ return "range from " .. tostring(self.left) .. " to " .. tostring(self.right)
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, left, right)
+ self.left, self.right = left, right
+ assert(self.left <= self.right, "left range value should be less than right range value")
+ self.value_type = assert(types[type(self.left)], "couldn't figure out type of range boundary")
+ end,
+ __base = _base_0,
+ __name = "Range",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ Range = _class_0
+end
+local Proxy
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _transform = function(self, ...)
+ return assert(self.fn(), "proxy missing transformer"):_transform(...)
+ end,
+ _describe = function(self, ...)
+ return assert(self.fn(), "proxy missing transformer"):_describe(...)
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, fn)
+ self.fn = fn
+ end,
+ __base = _base_0,
+ __name = "Proxy",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ Proxy = _class_0
+end
+local AssertType
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ assert = assert,
+ _transform = function(self, value, state)
+ local state_or_err
+ value, state_or_err = self.base_type:_transform(value, state)
+ self.assert(value ~= FailedTransform, state_or_err)
+ return value, state_or_err
+ end,
+ _describe = function(self)
+ if self.base_type._describe then
+ local base_description = self.base_type:_describe()
+ return "assert " .. tostring(base_description)
+ end
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, base_type)
+ self.base_type = base_type
+ return assert(BaseType:is_base_type(self.base_type), "expected a type checker")
+ end,
+ __base = _base_0,
+ __name = "AssertType",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ AssertType = _class_0
+end
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _transform = function(self, value, state)
+ local out, _ = self.base_type:_transform(value, state)
+ if out == FailedTransform then
+ return value, state
+ else
+ return FailedTransform, "expected " .. tostring(self:_describe())
+ end
+ end,
+ _describe = function(self)
+ if self.base_type._describe then
+ local base_description = self.base_type:_describe()
+ return "not " .. tostring(base_description)
+ end
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, base_type)
+ self.base_type = base_type
+ return assert(BaseType:is_base_type(self.base_type), "expected a type checker")
+ end,
+ __base = _base_0,
+ __name = "NotType",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ NotType = _class_0
+end
+local CloneType
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ _transform = function(self, value, state)
+ local _exp_0 = type(value)
+ if "nil" == _exp_0 or "string" == _exp_0 or "number" == _exp_0 or "boolean" == _exp_0 then
+ return value, state
+ elseif "table" == _exp_0 then
+ local clone_value
+ do
+ local _tbl_0 = { }
+ for k, v in pairs(value) do
+ _tbl_0[k] = v
+ end
+ clone_value = _tbl_0
+ end
+ do
+ local mt = getmetatable(value)
+ if mt then
+ setmetatable(clone_value, mt)
+ end
+ end
+ return clone_value, state
+ else
+ return FailedTransform, tostring(describe_type(value)) .. " is not cloneable"
+ end
+ end,
+ _describe = function(self)
+ return "cloneable value"
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, ...)
+ return _class_0.__parent.__init(self, ...)
+ end,
+ __base = _base_0,
+ __name = "CloneType",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ CloneType = _class_0
+end
+local MetatableIsType
+do
+ local _class_0
+ local _parent_0 = BaseType
+ local _base_0 = {
+ allow_metatable_update = false,
+ _transform = function(self, value, state)
+ local state_or_err
+ value, state_or_err = types.table:_transform(value, state)
+ if value == FailedTransform then
+ return FailedTransform, state_or_err
+ end
+ local mt = getmetatable(value)
+ local new_mt
+ new_mt, state_or_err = self.metatable_type:_transform(mt, state_or_err)
+ if new_mt == FailedTransform then
+ return FailedTransform, "metatable expected: " .. tostring(state_or_err)
+ end
+ if new_mt ~= mt then
+ if self.allow_metatable_update then
+ setmetatable(value, new_mt)
+ else
+ return FailedTransform, "metatable was modified by a type but { allow_metatable_update = true } is not enabled"
+ end
+ end
+ return value, state_or_err
+ end,
+ _describe = function(self)
+ return "has metatable " .. tostring(describe_type(self.metatable_type))
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, metatable_type, opts)
+ if BaseType:is_base_type(metatable_type) then
+ self.metatable_type = metatable_type
+ else
+ self.metatable_type = Literal(metatable_type)
+ end
+ if opts then
+ self.allow_metatable_update = opts.allow_metatable_update and true
+ end
+ end,
+ __base = _base_0,
+ __name = "MetatableIsType",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ MetatableIsType = _class_0
+end
+local type_nil = Type("nil")
+local type_function = Type("function")
+local type_number = Type("number")
+types = setmetatable({
+ any = AnyType(),
+ string = Type("string"),
+ number = type_number,
+ ["function"] = type_function,
+ func = type_function,
+ boolean = Type("boolean"),
+ userdata = Type("userdata"),
+ ["nil"] = type_nil,
+ null = type_nil,
+ table = Type("table"),
+ array = ArrayType(),
+ clone = CloneType(),
+ integer = Pattern("^%d+$", {
+ coerce = type_number / tostring
+ }),
+ one_of = OneOf,
+ all_of = AllOf,
+ shape = Shape,
+ partial = Partial,
+ pattern = Pattern,
+ array_of = ArrayOf,
+ array_contains = ArrayContains,
+ map_of = MapOf,
+ literal = Literal,
+ range = Range,
+ equivalent = Equivalent,
+ custom = Custom,
+ scope = TagScopeType,
+ proxy = Proxy,
+ assert = AssertType,
+ annotate = AnnotateNode,
+ metatable_is = MetatableIsType
+}, {
+ __index = function(self, fn_name)
+ return error("Type checker does not exist: `" .. tostring(fn_name) .. "`")
+ end
+})
+local check_shape
+check_shape = function(value, shape)
+ assert(shape.check_value, "missing check_value method from shape")
+ return shape:check_value(value)
+end
+is_type = function(val)
+ return BaseType:is_base_type(val)
+end
+return {
+ check_shape = check_shape,
+ types = types,
+ is_type = is_type,
+ BaseType = BaseType,
+ FailedTransform = FailedTransform,
+ VERSION = "2.6.0"
+}