]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Minor] Update lua-tableshape to 2.6.0
authorVsevolod Stakhov <vsevolod@rspamd.com>
Sun, 9 Apr 2023 11:42:03 +0000 (12:42 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Sun, 9 Apr 2023 11:42:03 +0000 (12:42 +0100)
Issue: #4455

contrib/DEPENDENCY_INFO.md
contrib/lua-tableshape/tableshape.lua

index 49eca09924282f16d02c9d0e52bd74baf26cf02c..745b60d76a62aa22cd5a83d944796c4463be9a7f 100644 (file)
@@ -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      |                    |
index 0f1f710f68fc0d621883da80eff51eb7a625fcd5..ccc73551904773bfeb89fb9a3edfbc7b241d3a28 100644 (file)
@@ -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",
   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",
   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"
 }