aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/DEPENDENCY_INFO.md2
-rw-r--r--contrib/lua-tableshape/tableshape.lua828
2 files changed, 642 insertions, 188 deletions
diff --git a/contrib/DEPENDENCY_INFO.md b/contrib/DEPENDENCY_INFO.md
index 49eca0992..745b60d76 100644
--- a/contrib/DEPENDENCY_INFO.md
+++ b/contrib/DEPENDENCY_INFO.md
@@ -17,7 +17,7 @@
| lua-lpeg | 1.0 | MIT | YES | rspamd text + alloc|
| lua-moses | ? | MIT | NO | |
| lua-lupa | ? | MIT | NO | |
-| lua-tableshape | ae67256 | MIT | NO | |
+| lua-tableshape | 2.6.0 | MIT | NO | |
| mumhash | ? | MIT | NO | |
| ngx-http-parser | 2.2.0 | MIT | YES | spamc support |
| Mozilla-PublicSuffix | ? | MIT | NO | |
diff --git a/contrib/lua-tableshape/tableshape.lua b/contrib/lua-tableshape/tableshape.lua
index 0f1f710f6..ccc735519 100644
--- a/contrib/lua-tableshape/tableshape.lua
+++ b/contrib/lua-tableshape/tableshape.lua
@@ -1,4 +1,5 @@
-local OptionalType, TaggedType, types
+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
@@ -22,11 +23,9 @@ clone_state = function(state_obj)
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
+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
@@ -34,13 +33,23 @@ describe_literal = function(val)
else
return "`" .. tostring(val) .. "`"
end
+ elseif BaseType:is_base_type(val) then
+ return val:_describe()
else
- if BaseType:is_base_type(val) then
- return val:_describe()
- else
- return tostring(val)
+ 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)
@@ -66,13 +75,6 @@ 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,
@@ -83,20 +85,46 @@ do
return _with_0
end
end,
- __mul = function(self, right)
- return SequenceNode(self, right)
+ __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(self, right)
- if self.__class == FirstOfNode then
+ __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(self.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(self, right)
+ 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,
@@ -141,25 +169,8 @@ do
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
+ clone_opts = function(self)
+ return error("clone_opts is not longer supported")
end,
__call = function(self, ...)
return self:check_value(...)
@@ -167,11 +178,7 @@ do
}
_base_0.__index = _base_0
_class_0 = setmetatable({
- __init = function(self)
- if self.opts then
- self._describe = self.opts.describe
- end
- end,
+ __init = function(self, opts) end,
__base = _base_0,
__name = "BaseType"
}, {
@@ -185,35 +192,24 @@ do
_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
+ 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 self:is_base_type(cls.__parent)
+ return false
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
+ cls.__base.__unm = self.__unm
+ cls.__base.__tostring = self.__tostring
end
BaseType = _class_0
end
@@ -274,8 +270,6 @@ do
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
@@ -293,11 +287,7 @@ do
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
+ _accum_0[_len_0] = describe_type(i)
_len_0 = _len_0 + 1
end
item_names = _accum_0
@@ -346,8 +336,6 @@ do
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
@@ -365,11 +353,7 @@ do
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
+ _accum_0[_len_0] = describe_type(i)
_len_0 = _len_0 + 1
end
item_names = _accum_0
@@ -421,8 +405,6 @@ do
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
@@ -502,6 +484,66 @@ do
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
@@ -549,13 +591,16 @@ do
end,
_describe = function(self)
local base_description = self.base_type:_describe()
- return tostring(base_description) .. " tagged " .. tostring(describe_literal(self.tag))
+ 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)
@@ -673,10 +718,9 @@ do
_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")
+ __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",
@@ -761,7 +805,7 @@ do
_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))
+ return FailedTransform, "expected type " .. tostring(describe_type(self.t)) .. ", got " .. tostring(describe_type(got))
end
if self.length_type then
local len = #value
@@ -780,12 +824,12 @@ do
else
l = types.range(left, right)
end
- return Type(self.t, self:clone_opts({
+ return Type(self.t, {
length = l
- }))
+ })
end,
_describe = function(self)
- local t = "type " .. tostring(describe_literal(self.t))
+ local t = "type " .. tostring(describe_type(self.t))
if self.length_type then
t = t .. " length_type " .. tostring(self.length_type:_describe())
end
@@ -796,11 +840,12 @@ do
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
+ self.t = t
+ if opts then
+ if opts.length then
+ self.length_type = assert(coerce_literal(opts.length))
+ end
end
- return _class_0.__parent.__init(self)
end,
__base = _base_0,
__name = "Type",
@@ -847,7 +892,7 @@ do
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))
+ return FailedTransform, "non array index, got " .. tostring(describe_type(i)) .. " but expected " .. tostring(describe_type(k))
end
k = k + 1
end
@@ -857,9 +902,8 @@ do
_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)
+ __init = function(self, ...)
+ return _class_0.__parent.__init(self, ...)
end,
__base = _base_0,
__name = "ArrayType",
@@ -904,7 +948,7 @@ do
if type(i) == "table" and i._describe then
_accum_0[_len_0] = i:_describe()
else
- _accum_0[_len_0] = describe_literal(i)
+ _accum_0[_len_0] = describe_type(i)
end
_len_0 = _len_0 + 1
end
@@ -947,9 +991,8 @@ do
_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)
+ __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
@@ -1004,11 +1047,7 @@ do
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
+ _accum_0[_len_0] = describe_type(i)
_len_0 = _len_0 + 1
end
item_names = _accum_0
@@ -1030,9 +1069,8 @@ do
_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)
+ __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
@@ -1073,7 +1111,7 @@ do
local _parent_0 = BaseType
local _base_0 = {
_describe = function(self)
- return "array of " .. tostring(describe_literal(self.expected))
+ return "array of " .. tostring(describe_type(self.expected))
end,
_transform = function(self, value, state)
local pass, err = types.table(value)
@@ -1095,7 +1133,7 @@ do
local transformed_item
if is_literal then
if self.expected ~= item then
- return FailedTransform, "array item " .. tostring(idx) .. ": expected " .. tostring(describe_literal(self.expected))
+ return FailedTransform, "array item " .. tostring(idx) .. ": expected " .. tostring(describe_type(self.expected))
else
transformed_item = item
end
@@ -1139,12 +1177,13 @@ do
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
+ 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
- return _class_0.__parent.__init(self)
end,
__base = _base_0,
__name = "ArrayOf",
@@ -1175,11 +1214,130 @@ do
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
@@ -1196,7 +1354,7 @@ do
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))
+ return FailedTransform, "map key expected " .. tostring(describe_type(self.expected_key))
end
else
new_k, state = self.expected_key:_transform(k, state)
@@ -1206,7 +1364,7 @@ do
end
if value_literal then
if v ~= self.expected_value then
- return FailedTransform, "map value expected " .. tostring(describe_literal(self.expected_value))
+ return FailedTransform, "map value expected " .. tostring(describe_type(self.expected_value))
end
else
new_v, state = self.expected_value:_transform(v, state)
@@ -1234,9 +1392,9 @@ do
_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)
+ __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",
@@ -1270,10 +1428,13 @@ do
local _class_0
local _parent_0 = BaseType
local _base_0 = {
+ open = false,
+ check_all = false,
is_open = function(self)
- return Shape(self.shape, self:clone_opts({
- open = true
- }))
+ return Shape(self.shape, {
+ open = true,
+ check_all = self.check_all or nil
+ })
end,
_describe = function(self)
local parts
@@ -1281,7 +1442,7 @@ 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))
+ _accum_0[_len_0] = tostring(describe_type(k)) .. " = " .. tostring(describe_type(v))
_len_0 = _len_0 + 1
end
parts = _accum_0
@@ -1317,11 +1478,11 @@ do
if shape_val == item_value then
new_val, state = item_value, state
else
- new_val, state = FailedTransform, "expected " .. tostring(describe_literal(shape_val))
+ new_val, state = FailedTransform, "expected " .. tostring(describe_type(shape_val))
end
end
if new_val == FailedTransform then
- err = "field " .. tostring(describe_literal(shape_key)) .. ": " .. tostring(state)
+ err = "field " .. tostring(describe_type(shape_key)) .. ": " .. tostring(state)
if check_all then
if errors then
table.insert(errors, err)
@@ -1353,7 +1514,7 @@ do
[k] = item_value
}, state)
if tuple == FailedTransform then
- err = "field " .. tostring(describe_literal(k)) .. ": " .. tostring(state)
+ err = "field " .. tostring(describe_type(k)) .. ": " .. tostring(state)
if check_all then
if errors then
table.insert(errors, err)
@@ -1387,7 +1548,7 @@ do
local _accum_0 = { }
local _len_0 = 1
for key in pairs(remaining_keys) do
- _accum_0[_len_0] = describe_literal(key)
+ _accum_0[_len_0] = describe_type(key)
_len_0 = _len_0 + 1
end
names = _accum_0
@@ -1416,13 +1577,15 @@ do
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)
+ self.shape = shape
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 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
@@ -1460,31 +1623,77 @@ do
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_literal(self.pattern))
+ return "pattern " .. tostring(describe_type(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))
+ 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
- if self.opts and self.opts.coerce then
- value = tostring(value)
- end
- local t_res, err = types.string(value)
+ local t_res, err = types.string(test_value)
if not (t_res) then
return FailedTransform, err
end
- if value:match(self.pattern) then
+ if test_value:match(self.pattern) then
return value, state
else
return FailedTransform, "doesn't match " .. tostring(self:_describe())
@@ -1495,8 +1704,12 @@ do
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)
+ 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",
@@ -1525,13 +1738,12 @@ do
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)
+ return describe_type(self.value)
end,
_transform = function(self, value, state)
if self.value ~= value then
@@ -1543,9 +1755,8 @@ do
_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)
+ __init = function(self, value)
+ self.value = value
end,
__base = _base_0,
__name = "Literal",
@@ -1580,7 +1791,7 @@ do
local _parent_0 = BaseType
local _base_0 = {
_describe = function(self)
- return self.opts and self.opts.describe or "custom checker " .. tostring(self.fn)
+ return "custom checker " .. tostring(self.fn)
end,
_transform = function(self, value, state)
local pass, err = self.fn(value, state)
@@ -1593,9 +1804,9 @@ do
_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)
+ __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",
@@ -1630,6 +1841,9 @@ do
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
@@ -1641,9 +1855,8 @@ do
_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)
+ __init = function(self, val)
+ self.val = val
end,
__base = _base_0,
__name = "Equivalent",
@@ -1732,9 +1945,8 @@ do
_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)
+ __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,
@@ -1780,8 +1992,8 @@ do
_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
+ __init = function(self, fn)
+ self.fn = fn
end,
__base = _base_0,
__name = "Proxy",
@@ -1810,33 +2022,285 @@ do
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"),
+ number = type_number,
+ ["function"] = type_function,
+ func = type_function,
boolean = Type("boolean"),
userdata = Type("userdata"),
- ["nil"] = Type("nil"),
+ ["nil"] = type_nil,
+ null = type_nil,
table = Type("table"),
array = ArrayType(),
+ clone = CloneType(),
integer = Pattern("^%d+$", {
- coerce = true,
- initial_type = "number"
+ 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
+ proxy = Proxy,
+ assert = AssertType,
+ annotate = AnnotateNode,
+ metatable_is = MetatableIsType
}, {
__index = function(self, fn_name)
return error("Type checker does not exist: `" .. tostring(fn_name) .. "`")
@@ -1847,24 +2311,14 @@ 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"
+ VERSION = "2.6.0"
}