From: Vsevolod Stakhov Date: Wed, 19 Sep 2018 10:51:58 +0000 (+0100) Subject: [Minor] Add tableshape library from https://github.com/leafo/tableshape X-Git-Tag: 1.8.0~68 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=a89eebf63a20059148655a4c5563e74eb5bee061;p=rspamd.git [Minor] Add tableshape library from https://github.com/leafo/tableshape --- diff --git a/CMakeLists.txt b/CMakeLists.txt index e75e85d7b..b9313d30c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1376,6 +1376,7 @@ ENDFOREACH(LUA_LIB) # Install lua fun library INSTALL(FILES "contrib/lua-fun/fun.lua" DESTINATION ${LUALIBDIR}) INSTALL(FILES "contrib/lua-argparse/argparse.lua" DESTINATION ${LUALIBDIR}) +INSTALL(FILES "contrib/lua-tableshape/tableshape.lua" DESTINATION ${LUALIBDIR}) IF(ENABLE_TORCH MATCHES "ON") INSTALL(FILES "contrib/lua-moses/moses.lua" DESTINATION ${LUALIBDIR}) diff --git a/contrib/DEPENDENCY_INFO.md b/contrib/DEPENDENCY_INFO.md index 3b5401360..f3996eed6 100644 --- a/contrib/DEPENDENCY_INFO.md +++ b/contrib/DEPENDENCY_INFO.md @@ -1,16 +1,17 @@ # Rspamd Dependency Info -- aho-corasick Version: ? License: LGPL-3.0 Patched: ? -- cdb Version: 1.1.0 License: Public Domain / CC0 Patched: ? -- hiredis Version: 0.13.3 License: BSD-3-Clause Patched: ? -- lc-btrie Version: ? License: BSD-3-Clause Patched: ? -- lgpl Version: ? License: LGPL-2.1 Patched: ? -- libottery Version: ? License: Public Domain / CC0 Patched: ? +- aho-corasick Version: ? License: LGPL-3.0 Patched: YES +- cdb Version: 1.1.0 License: Public Domain / CC0 Patched: NO +- hiredis Version: 0.13.3 License: BSD-3-Clause Patched: YES +- lc-btrie Version: ? License: BSD-3-Clause Patched: YES +- lgpl Version: ? License: LGPL-2.1 Patched: NO +- libottery Version: ? License: Public Domain / CC0 Patched: YES - librdns Version: ? License: BSD-2-Clause Patched: ? - libucl Version: ? License: BSD-2-Clause Patched: ? - linenoise Version: 1.0 License: BSD-2-Clause Patched: ? -- lpeg: Version: 1.0 License: MIT Patched: ? -- lua-fun Version: ? License: MIT Patched: ? +- lpeg: Version: 1.0 License: MIT Patched: NO +- lua-fun Version: ? License: MIT Patched: NO +- lua-tableshape Version: ae67256 License: MIT Patched: NO - moses Version: ? License: MIT Patched: ? - mumhash Version: ? License: MIT Patched: ? - ngx-http-parser Version: 2.2.0 License: MIT Patched: ? @@ -18,7 +19,7 @@ Version: ? License: MIT Patched: ? - snowball Version: ? License: BSD-3-Clause Patched: ? - t1ha Version: ? License: Zlib Patched: ? -- torch Version: ? License: ASL-2.0 v BSD-3-Clause Patched: ? +- torch Version: ? License: ASL-2.0 v BSD-3-Clause Patched: YES - uthash Version: 1.9.8 License: BSD Patched: ? - xxhash Version: ? License: BSD Patched: ? -- zstd Version: 1.3.1 License: BSD Patched: ? +- zstd Version: 1.3.1 License: BSD Patched: NO diff --git a/contrib/lua-tableshape/LICENSE b/contrib/lua-tableshape/LICENSE new file mode 100644 index 000000000..38ba5fced --- /dev/null +++ b/contrib/lua-tableshape/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2018 by Leaf Corcoran + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/contrib/lua-tableshape/tableshape.lua b/contrib/lua-tableshape/tableshape.lua new file mode 100644 index 000000000..0f1f710f6 --- /dev/null +++ b/contrib/lua-tableshape/tableshape.lua @@ -0,0 +1,1870 @@ +local OptionalType, TaggedType, types +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 BaseType, TransformNode, SequenceNode, FirstOfNode, DescribeNode +local describe_literal +describe_literal = function(val) + local _exp_0 = type(val) + if "string" == _exp_0 then + if not val:match('"') then + return "\"" .. tostring(val) .. "\"" + elseif not val:match("'") then + return "'" .. tostring(val) .. "'" + else + return "`" .. tostring(val) .. "`" + end + else + if BaseType:is_base_type(val) then + return val:_describe() + else + return tostring(val) + end + end +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 = { + __eq = function(self, other) + if BaseType:is_base_type(other) then + return other(self) + else + return self(other[1]) + end + end, + __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(self, right) + return SequenceNode(self, right) + end, + __add = function(self, right) + if self.__class == FirstOfNode then + local options = { + unpack(self.options) + } + table.insert(options, right) + return FirstOfNode(unpack(options)) + else + return FirstOfNode(self, right) + end + 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, merge) + local opts + if self.opts then + do + local _tbl_0 = { } + for k, v in pairs(self.opts) do + _tbl_0[k] = v + end + opts = _tbl_0 + end + else + opts = { } + end + if merge then + for k, v in pairs(merge) do + opts[k] = v + end + end + return opts + end, + __call = function(self, ...) + return self:check_value(...) + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self) + if self.opts then + self._describe = self.opts.describe + end + 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) + if not (type(val) == "table") then + return false + end + local cls = val and val.__class + if not (cls) then + return false + end + if BaseType == cls then + return true + end + return self:is_base_type(cls.__parent) + end + self.__inherited = function(self, cls) + cls.__base.__call = cls.__call + cls.__base.__eq = self.__eq + cls.__base.__div = self.__div + cls.__base.__mod = self.__mod + cls.__base.__mul = self.__mul + cls.__base.__add = self.__add + local mt = getmetatable(cls) + local create = mt.__call + mt.__call = function(cls, ...) + local ret = create(cls, ...) + if ret.opts and ret.opts.optional then + return ret:is_optional() + else + return ret + end + end + 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 + local self = _class_0 + self.transformer = true + 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] + if type(i) == "table" and i._describe then + _accum_0[_len_0] = i:_describe() + else + _accum_0[_len_0] = describe_literal(i) + end + _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 + local self = _class_0 + self.transformer = true + 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] + if type(i) == "table" and i._describe then + _accum_0[_len_0] = i:_describe() + else + _accum_0[_len_0] = describe_literal(i) + end + _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 + local self = _class_0 + self.transformer = true + 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 +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_literal(self.tag)) + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self, base_type, opts) + 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, opts) + self.base_type, self.opts = base_type, opts + _class_0.__parent.__init(self) + return assert(BaseType:is_base_type(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_literal(self.t)) .. ", got " .. tostring(describe_literal(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, self:clone_opts({ + length = l + })) + end, + _describe = function(self) + local t = "type " .. tostring(describe_literal(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, self.opts = t, opts + if self.opts then + self.length_type = self.opts.length + end + return _class_0.__parent.__init(self) + 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_literal(i)) .. " but expected " .. tostring(describe_literal(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, opts) + self.opts = opts + 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_literal(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, opts) + self.options, self.opts = options, opts + _class_0.__parent.__init(self) + 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] + if type(i) == "table" and i._describe then + _accum_0[_len_0] = i:_describe() + else + _accum_0[_len_0] = describe_literal(i) + end + _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, opts) + self.types, self.opts = types, opts + _class_0.__parent.__init(self) + 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_literal(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_literal(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, self.opts = expected, opts + if self.opts then + self.keep_nils = self.opts.keep_nils + self.length_type = self.opts.length + end + return _class_0.__parent.__init(self) + 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 MapOf +do + local _class_0 + local _parent_0 = BaseType + local _base_0 = { + _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_literal(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_literal(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, opts) + self.expected_key, self.expected_value, self.opts = expected_key, expected_value, opts + return _class_0.__parent.__init(self) + 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 = { + is_open = function(self) + return Shape(self.shape, self:clone_opts({ + open = true + })) + 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_literal(k)) .. " = " .. tostring(describe_literal(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_literal(shape_val)) + end + end + if new_val == FailedTransform then + err = "field " .. tostring(describe_literal(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_literal(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_literal(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, self.opts = shape, opts + _class_0.__parent.__init(self) + assert(type(self.shape) == "table", "expected table for shape") + if self.opts then + self.extra_fields_type = self.opts.extra_fields + self.open = self.opts.open + self.check_all = self.opts.check_all + 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 Pattern +do + local _class_0 + local _parent_0 = BaseType + local _base_0 = { + _describe = function(self) + return "pattern " .. tostring(describe_literal(self.pattern)) + end, + _transform = function(self, value, state) + do + local initial = self.opts and self.opts.initial_type + if initial then + if not (type(value) == initial) then + return FailedTransform, "expected " .. tostring(describe_literal(initial)) + end + end + end + if self.opts and self.opts.coerce then + value = tostring(value) + end + local t_res, err = types.string(value) + if not (t_res) then + return FailedTransform, err + end + if 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, self.opts = pattern, opts + return _class_0.__parent.__init(self) + 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 +local Literal +do + local _class_0 + local _parent_0 = BaseType + local _base_0 = { + _describe = function(self) + return describe_literal(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, opts) + self.value, self.opts = value, opts + return _class_0.__parent.__init(self) + 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 self.opts and self.opts.describe or "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, opts) + self.fn, self.opts = fn, opts + return _class_0.__parent.__init(self) + 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 = { + _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, opts) + self.val, self.opts = val, opts + return _class_0.__parent.__init(self) + 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, opts) + self.left, self.right, self.opts = left, right, opts + _class_0.__parent.__init(self) + 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, opts) + self.fn, self.opts = fn, opts + 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 +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"), + table = Type("table"), + array = ArrayType(), + integer = Pattern("^%d+$", { + coerce = true, + initial_type = "number" + }), + one_of = OneOf, + all_of = AllOf, + shape = Shape, + pattern = Pattern, + array_of = ArrayOf, + map_of = MapOf, + literal = Literal, + range = Range, + equivalent = Equivalent, + custom = Custom, + scope = TagScopeType, + proxy = Proxy +}, { + __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 +local is_type +is_type = function(val) + return BaseType:is_base_type(val) +end +local type_switch +type_switch = function(val) + return setmetatable({ + val + }, { + __eq = BaseType.__eq + }) +end +return { + check_shape = check_shape, + types = types, + is_type = is_type, + type_switch = type_switch, + BaseType = BaseType, + FailedTransform = FailedTransform, + VERSION = "2.0.0" +}