This commit is contained in:
lx
2026-07-06 14:01:11 -04:00
commit c4f97d729d
16468 changed files with 935321 additions and 0 deletions
@@ -0,0 +1,5 @@
# Generated by Rotriever. Format subject to change in future releases.
name = "roblox/t"
version = "1.2.5"
commit = "5d6ee3e23a658b12bc433b0837184215618e233e"
source = "url+https://github.com/roblox/t"
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,560 @@
return function()
local t = require(script.Parent)
it("should support basic types", function()
assert(t.any(""))
assert(t.boolean(true))
assert(t.none(nil))
assert(t.number(1))
assert(t.string("foo"))
assert(t.table({}))
assert(not (t.any(nil)))
assert(not (t.boolean("true")))
assert(not (t.none(1)))
assert(not (t.number(true)))
assert(not (t.string(true)))
assert(not (t.table(82)))
end)
it("should support special number types", function()
local maxTen = t.numberMax(10)
local minTwo = t.numberMin(2)
local maxTenEx = t.numberMaxExclusive(10)
local minTwoEx = t.numberMinExclusive(2)
local constrainedEightToEleven = t.numberConstrained(8, 11)
local constrainedEightToElevenEx = t.numberConstrainedExclusive(8, 11)
assert(maxTen(5))
assert(maxTen(10))
assert(not (maxTen(11)))
assert(not (maxTen()))
assert(minTwo(5))
assert(minTwo(2))
assert(not (minTwo(1)))
assert(not (minTwo()))
assert(maxTenEx(5))
assert(maxTenEx(9))
assert(not (maxTenEx(10)))
assert(not (maxTenEx()))
assert(minTwoEx(5))
assert(minTwoEx(3))
assert(not (minTwoEx(2)))
assert(not (minTwoEx()))
assert(not (constrainedEightToEleven(7)))
assert(constrainedEightToEleven(8))
assert(constrainedEightToEleven(9))
assert(constrainedEightToEleven(11))
assert(not (constrainedEightToEleven(12)))
assert(not (constrainedEightToEleven()))
assert(not (constrainedEightToElevenEx(7)))
assert(not (constrainedEightToElevenEx(8)))
assert(constrainedEightToElevenEx(9))
assert(not (constrainedEightToElevenEx(11)))
assert(not (constrainedEightToElevenEx(12)))
assert(not (constrainedEightToElevenEx()))
end)
it("should support optional types", function()
local check = t.optional(t.string)
assert(check(""))
assert(check())
assert(not (check(1)))
end)
it("should support tuple types", function()
local myTupleCheck = t.tuple(t.number, t.string, t.optional(t.number))
assert(myTupleCheck(1, "2", 3))
assert(myTupleCheck(1, "2"))
assert(not (myTupleCheck(1, "2", "3")))
end)
it("should support union types", function()
local numberOrString = t.union(t.number, t.string)
assert(numberOrString(1))
assert(numberOrString("1"))
assert(not (numberOrString(nil)))
end)
it("should support literal types", function()
local checkSingle = t.literal("foo")
local checkUnion = t.union(t.literal("foo"), t.literal("bar"), t.literal("oof"))
assert(checkSingle("foo"))
assert(checkUnion("foo"))
assert(checkUnion("bar"))
assert(checkUnion("oof"))
assert(not (checkSingle("FOO")))
assert(not (checkUnion("FOO")))
assert(not (checkUnion("BAR")))
assert(not (checkUnion("OOF")))
end)
it("should support multiple literal types", function()
local checkSingle = t.literal("foo")
local checkUnion = t.literal("foo", "bar", "oof")
assert(checkSingle("foo"))
assert(checkUnion("foo"))
assert(checkUnion("bar"))
assert(checkUnion("oof"))
assert(not (checkSingle("FOO")))
assert(not (checkUnion("FOO")))
assert(not (checkUnion("BAR")))
assert(not (checkUnion("OOF")))
end)
it("should support intersection types", function()
local integerMax5000 = t.intersection(t.integer, t.numberMax(5000))
assert(integerMax5000(1))
assert(not (integerMax5000(5001)))
assert(not (integerMax5000(1.1)))
assert(not (integerMax5000("1")))
end)
describe("array", function()
it("should support array types", function()
local stringArray = t.array(t.string)
local anyArray = t.array(t.any)
local stringValues = t.values(t.string)
assert(not (anyArray("foo")))
assert(anyArray({1, "2", 3}))
assert(not (stringArray({1, "2", 3})))
assert(not (stringArray()))
assert(not (stringValues()))
assert(anyArray({"1", "2", "3"}, t.string))
assert(not (anyArray({
foo = "bar"
})))
assert(not (anyArray({
[1] = "non",
[5] = "sequential"
})))
end)
it("should not be fooled by sparse arrays", function()
local anyArray = t.array(t.any)
assert(not (anyArray({
[1] = 1,
[2] = 2,
[4] = 4,
})))
end)
end)
it("should support map types", function()
local stringNumberMap = t.map(t.string, t.number)
assert(stringNumberMap({}))
assert(stringNumberMap({a = 1}))
assert(not (stringNumberMap({[1] = "a"})))
assert(not (stringNumberMap({a = "a"})))
assert(not (stringNumberMap()))
end)
it("should support interface types", function()
local IVector3 = t.interface({
x = t.number,
y = t.number,
z = t.number,
})
assert(IVector3({
w = 0,
x = 1,
y = 2,
z = 3,
}))
assert(not (IVector3({
w = 0,
x = 1,
y = 2,
})))
end)
it("should support strict interface types", function()
local IVector3 = t.strictInterface({
x = t.number,
y = t.number,
z = t.number,
})
assert(not (IVector3(0)))
assert(not (IVector3({
w = 0,
x = 1,
y = 2,
z = 3,
})))
assert(not (IVector3({
w = 0,
x = 1,
y = 2,
})))
assert(IVector3({
x = 1,
y = 2,
z = 3,
}))
end)
it("should support deep interface types", function()
local IPlayer = t.interface({
name = t.string,
inventory = t.interface({
size = t.number
})
})
assert(IPlayer({
name = "TestPlayer",
inventory = {
size = 1
}
}))
assert(not (IPlayer({
inventory = {
size = 1
}
})))
assert(not (IPlayer({
name = "TestPlayer",
inventory = {
}
})))
assert(not (IPlayer({
name = "TestPlayer",
})))
end)
it("should support deep optional interface types", function()
local IPlayer = t.interface({
name = t.string,
inventory = t.optional(t.interface({
size = t.number
}))
})
assert(IPlayer({
name = "TestPlayer"
}))
assert(not (IPlayer({
name = "TestPlayer",
inventory = {
}
})))
assert(IPlayer({
name = "TestPlayer",
inventory = {
size = 1
}
}))
end)
it("should support Roblox Instance types", function()
local stringValueCheck = t.instanceOf("StringValue")
local stringValue = Instance.new("StringValue")
local boolValue = Instance.new("BoolValue")
assert(stringValueCheck(stringValue))
assert(not (stringValueCheck(boolValue)))
assert(not (stringValueCheck()))
end)
it("should support Roblox Instance types inheritance", function()
local guiObjectCheck = t.instanceIsA("GuiObject")
local frame = Instance.new("Frame")
local textLabel = Instance.new("TextLabel")
local stringValue = Instance.new("StringValue")
assert(guiObjectCheck(frame))
assert(guiObjectCheck(textLabel))
assert(not (guiObjectCheck(stringValue)))
assert(not (guiObjectCheck()))
end)
it("should support Roblox Enum types", function()
local sortOrderEnumCheck = t.enum(Enum.SortOrder)
assert(t.Enum(Enum.SortOrder))
assert(not (t.Enum("Enum.SortOrder")))
assert(t.EnumItem(Enum.SortOrder.Name))
assert(not (t.EnumItem("Enum.SortOrder.Name")))
assert(sortOrderEnumCheck(Enum.SortOrder.Name))
assert(sortOrderEnumCheck(Enum.SortOrder.Custom))
assert(not (sortOrderEnumCheck(Enum.EasingStyle.Linear)))
assert(not (sortOrderEnumCheck()))
end)
it("should support Roblox RBXScriptSignal", function()
assert(t.RBXScriptSignal(game.ChildAdded))
assert(not (t.RBXScriptSignal(nil)))
assert(not (t.RBXScriptSignal(Vector3.new())))
end)
-- TODO: Add this back when Lemur supports it
-- it("should support Roblox RBXScriptConnection", function()
-- local conn = game.ChildAdded:Connect(function() end)
-- assert(t.RBXScriptConnection(conn))
-- assert(not (t.RBXScriptConnection(nil)))
-- assert(not (t.RBXScriptConnection(Vector3.new())))
-- end)
it("should support wrapping function types", function()
local checkFoo = t.tuple(t.string, t.number, t.optional(t.string))
local foo = t.wrap(function(a, b, c)
local result = string.format("%s %d", a, b)
if c then
result = result .. " " .. c
end
return result
end, checkFoo)
assert(not (pcall(foo)))
assert(not (pcall(foo, "a")))
assert(not (pcall(foo, 2)))
assert(pcall(foo, "a", 1))
assert(pcall(foo, "a", 1, "b"))
end)
it("should support strict types", function()
local myType = t.strict(t.tuple(t.string, t.number))
assert(not (pcall(function()
myType("a", "b")
end)))
assert(pcall(function()
myType("a", 1)
end))
end)
it("should support common OOP types", function()
local MyClass = {}
MyClass.__index = MyClass
function MyClass.new()
local self = setmetatable({}, MyClass)
return self
end
local function instanceOfClass(class)
return function(value)
local tableSuccess, tableErrMsg = t.table(value)
if not tableSuccess then
return false, tableErrMsg or ""
end
local mt = getmetatable(value)
if not mt or mt.__index ~= class then
return false, "bad member of class"
end
return true
end
end
local instanceOfMyClass = instanceOfClass(MyClass)
local myObject = MyClass.new()
assert(instanceOfMyClass(myObject))
assert(not (instanceOfMyClass({})))
assert(not (instanceOfMyClass()))
end)
it("should not treat NaN as numbers", function()
assert(t.number(1))
assert(not (t.number(0/0)))
assert(not (t.number("1")))
end)
it("should not treat numbers as NaN", function()
assert(not (t.nan(1)))
assert(t.nan(0/0))
assert(not (t.nan("1")))
end)
it("should allow union of number and NaN", function()
local numberOrNaN = t.union(t.number, t.nan)
assert(numberOrNaN(1))
assert(numberOrNaN(0/0))
assert(not (numberOrNaN("1")))
end)
it("should support non-string keys for interfaces", function()
local key = {}
local myInterface = t.interface({ [key] = t.number })
assert(myInterface({ [key] = 1 }))
assert(not (myInterface({ [key] = "1" })))
end)
it("should support failing on non-string keys for strict interfaces", function()
local myInterface = t.strictInterface({ a = t.number })
assert(not (myInterface({ a = 1, [{}] = 2 })))
end)
it("should support children", function()
local myInterface = t.interface({
buttonInFrame = t.intersection(t.instanceOf("Frame"), t.children({
MyButton = t.instanceOf("ImageButton")
}))
})
assert(not (t.children({})(5)))
assert(not (myInterface({ buttonInFrame = Instance.new("Frame") })))
do
local frame = Instance.new("Frame")
local button = Instance.new("ImageButton", frame)
button.Name = "MyButton"
assert(myInterface({ buttonInFrame = frame }))
end
do
local frame = Instance.new("Frame")
local button = Instance.new("ImageButton", frame)
button.Name = "NotMyButton"
assert(not (myInterface({ buttonInFrame = frame })))
end
do
local frame = Instance.new("Frame")
local button = Instance.new("TextButton", frame)
button.Name = "MyButton"
assert(not (myInterface({ buttonInFrame = frame })))
end
do
local frame = Instance.new("Frame")
local button1 = Instance.new("ImageButton", frame)
button1.Name = "MyButton"
local button2 = Instance.new("ImageButton", frame)
button2.Name = "MyButton"
assert(not (myInterface({ buttonInFrame = frame })))
end
end)
it("should support t.instanceOf shorthand", function()
local myInterface = t.interface({
buttonInFrame = t.instanceOf("Frame", {
MyButton = t.instanceOf("ImageButton")
})
})
assert(not (t.children({})(5)))
assert(not (myInterface({ buttonInFrame = Instance.new("Frame") })))
do
local frame = Instance.new("Frame")
local button = Instance.new("ImageButton", frame)
button.Name = "MyButton"
assert(myInterface({ buttonInFrame = frame }))
end
do
local frame = Instance.new("Frame")
local button = Instance.new("ImageButton", frame)
button.Name = "NotMyButton"
assert(not (myInterface({ buttonInFrame = frame })))
end
do
local frame = Instance.new("Frame")
local button = Instance.new("TextButton", frame)
button.Name = "MyButton"
assert(not (myInterface({ buttonInFrame = frame })))
end
do
local frame = Instance.new("Frame")
local button1 = Instance.new("ImageButton", frame)
button1.Name = "MyButton"
local button2 = Instance.new("ImageButton", frame)
button2.Name = "MyButton"
assert(not (myInterface({ buttonInFrame = frame })))
end
end)
it("should support t.instanceIsA shorthand", function()
local myInterface = t.interface({
buttonInFrame = t.instanceIsA("Frame", {
MyButton = t.instanceIsA("ImageButton")
})
})
assert(not (t.children({})(5)))
assert(not (myInterface({ buttonInFrame = Instance.new("Frame") })))
do
local frame = Instance.new("Frame")
local button = Instance.new("ImageButton", frame)
button.Name = "MyButton"
assert(myInterface({ buttonInFrame = frame }))
end
do
local frame = Instance.new("Frame")
local button = Instance.new("ImageButton", frame)
button.Name = "NotMyButton"
assert(not (myInterface({ buttonInFrame = frame })))
end
do
local frame = Instance.new("Frame")
local button = Instance.new("TextButton", frame)
button.Name = "MyButton"
assert(not (myInterface({ buttonInFrame = frame })))
end
do
local frame = Instance.new("Frame")
local button1 = Instance.new("ImageButton", frame)
button1.Name = "MyButton"
local button2 = Instance.new("ImageButton", frame)
button2.Name = "MyButton"
assert(not (myInterface({ buttonInFrame = frame })))
end
end)
it("should support t.match", function()
local check = t.match("%d+")
assert(check("123"))
assert(not (check("abc")))
assert(not (check()))
end)
it("should support t.keyOf", function()
local myNewEnum = {
OptionA = {},
OptionB = {},
}
local check = t.keyOf(myNewEnum)
assert(check("OptionA"))
assert(not (check("OptionC")))
end)
it("should support t.valueOf", function()
local myNewEnum = {
OptionA = {},
OptionB = {},
}
local check = t.valueOf(myNewEnum)
assert(check(myNewEnum.OptionA))
assert(not (check(1010)))
end)
end
@@ -0,0 +1,214 @@
/** checks to see if `value` is a T */
type check<T> = (value: unknown) => value is T;
interface t {
// lua types
/** checks to see if `value` is an any */
any: check<any>;
/** checks to see if `value` is a boolean */
boolean: check<boolean>;
/** checks to see if `value` is a thread */
thread: check<thread>;
/** checks to see if `value` is a Function */
callback: check<Function>;
/** checks to see if `value` is undefined */
none: check<undefined>;
/** checks to see if `value` is a number, will _not_ match NaN */
number: check<number>;
/** checks to see if `value` is NaN */
nan: check<number>;
/** checks to see if `value` is a string */
string: check<string>;
/** checks to see if `value` is an object */
table: check<object>;
/** checks to see if `value` is a userdata */
userdata: check<object>;
// roblox types
/** checks to see if `value` is an Axes */
Axes: check<Axes>;
/** checks to see if `value` is a BrickColor */
BrickColor: check<BrickColor>;
/** checks to see if `value` is a CFrame */
CFrame: check<CFrame>;
/** checks to see if `value` is a Color3 */
Color3: check<Color3>;
/** checks to see if `value` is a ColorSequence */
ColorSequence: check<ColorSequence>;
/** checks to see if `value` is a ColorSequenceKeypoint */
ColorSequenceKeypoint: check<ColorSequenceKeypoint>;
/** checks to see if `value` is a DockWidgetPluginGuiInfo */
DockWidgetPluginGuiInfo: check<DockWidgetPluginGuiInfo>;
/** checks to see if `value` is a Faces */
Faces: check<Faces>;
/** checks to see if `value` is an Instance */
Instance: check<Instance>;
/** checks to see if `value` is a NumberRange */
NumberRange: check<NumberRange>;
/** checks to see if `value` is a NumberSequence */
NumberSequence: check<NumberSequence>;
/** checks to see if `value` is a NumberSequenceKeypoint */
NumberSequenceKeypoint: check<NumberSequenceKeypoint>;
/** checks to see if `value` is a PathWaypoint */
PathWaypoint: check<PathWaypoint>;
/** checks to see if `value` is a PhysicalProperties */
PhysicalProperties: check<PhysicalProperties>;
/** checks to see if `value` is a Random */
Random: check<Random>;
/** checks to see if `value` is a Ray */
Ray: check<Ray>;
/** checks to see if `value` is a Rect */
Rect: check<Rect>;
/** checks to see if `value` is a Region3 */
Region3: check<Region3>;
/** checks to see if `value` is a Region3int16 */
Region3int16: check<Region3int16>;
/** checks to see if `value` is a TweenInfo */
TweenInfo: check<TweenInfo>;
/** checks to see if `value` is a UDim */
UDim: check<UDim>;
/** checks to see if `value` is a UDim2 */
UDim2: check<UDim2>;
/** checks to see if `value` is a Vector2 */
Vector2: check<Vector2>;
/** checks to see if `value` is a Vector3 */
Vector3: check<Vector3>;
/** checks to see if `value` is a Vector3int16 */
Vector3int16: check<Vector3int16>;
/** checks to see if `value` is a RBXScriptSignal */
RBXScriptSignal: check<RBXScriptSignal>;
/** checks to see if `value` is a RBXScriptConnection */
RBXScriptConnection: check<RBXScriptConnection>;
/**
* checks to see if `value == literalValue`
*/
literal<T extends string | number | boolean | undefined>(this: void, literalValue: T): check<T>;
literal<T extends Array<any>>(
this: void,
...args: T
): T extends [infer A]
? (value: unknown) => value is A
: T extends [infer A, infer B]
? check<A | B>
: T extends [infer A, infer B, infer C]
? check<A | B | C>
: T extends [infer A, infer B, infer C, infer D]
? check<A | B | C | D>
: T extends [infer A, infer B, infer C, infer D, infer E]
? check<A | B | C | D | E>
: T extends [infer A, infer B, infer C, infer D, infer E, infer F]
? check<A | B | C | D | E | F>
: never;
literal<T>(this: void, literalValue: T): (value: unknown) => value is T;
/** Returns a t.union of each key in the table as a t.literal */
keyOf: <T>(valueTable: T) => check<keyof T>;
/** Returns a t.union of each value in the table as a t.literal */
valueOf: <T>(valueTable: T) => T extends { [P in keyof T]: infer U } ? check<U> : never;
/** checks to see if `value` is an integer */
integer: (value: unknown) => value is number;
/** checks to see if `value` is a number and is more than or equal to `min` */
numberMin: (min: number) => (value: unknown) => value is number;
/** checks to see if `value` is a number and is less than or equal to `max` */
numberMax: (max: number) => (value: unknown) => value is number;
/** checks to see if `value` is a number and is more than `min` */
numberMinExclusive: (min: number) => (value: unknown) => value is number;
/** checks to see if `value` is a number and is less than `max` */
numberMaxExclusive: (max: number) => (value: unknown) => value is number;
/** checks to see if `value` is a number and is more than 0 */
numberPositive: (value: unknown) => value is number;
/** checks to see if `value` is a number and is less than 0 */
numberNegative: (value: unknown) => value is number;
/** checks to see if `value` is a number and `min <= value <= max` */
numberConstrained: (min: number, max: number) => (value: unknown) => value is number;
/** checks to see if `value` is a number and `min < value < max` */
numberConstrainedExclusive: (min: number, max: number) => (value: unknown) => value is number;
/** checks `t.string` and determines if value matches the pattern via `string.match(value, pattern)` */
match: (pattern: string) => check<string>;
/** checks to see if `value` is either nil or passes `check` */
optional: <T>(check: (value: unknown) => value is T) => check<T | undefined>;
/** checks to see if `value` is a table and if its keys match against `check */
keys: <T>(check: (value: unknown) => value is T) => check<Map<T, unknown>>;
/** checks to see if `value` is a table and if its values match against `check` */
values: <T>(check: (value: unknown) => value is T) => check<Map<unknown, T>>;
/** checks to see if `value` is a table and all of its keys match against `keyCheck` and all of its values match against `valueCheck` */
map: <K, V>(
keyCheck: (value: unknown) => value is K,
valueCheck: (value: unknown) => value is V
) => check<Map<K, V>>;
/** checks to see if `value` is an array and all of its keys are sequential integers and all of its values match `check` */
array: <T>(check: (value: unknown) => value is T) => check<Array<T>>;
/** checks to see if `value` matches any given check */
union: <T extends Array<any>>(
...args: T
) => T extends [check<infer A>]
? (value: unknown) => value is A
: T extends [check<infer A>, check<infer B>]
? check<A | B>
: T extends [check<infer A>, check<infer B>, check<infer C>]
? check<A | B | C>
: T extends [check<infer A>, check<infer B>, check<infer C>, check<infer D>]
? check<A | B | C | D>
: T extends [check<infer A>, check<infer B>, check<infer C>, check<infer D>, check<infer E>]
? check<A | B | C | D | E>
: T extends [check<infer A>, check<infer B>, check<infer C>, check<infer D>, check<infer E>, check<infer F>]
? check<A | B | C | D | E | F>
: never;
/** checks to see if `value` matches all given checks */
intersection: <T extends Array<any>>(
...args: T
) => T extends [check<infer A>]
? (value: unknown) => value is A
: T extends [check<infer A>, check<infer B>]
? check<A & B>
: T extends [check<infer A>, check<infer B>, check<infer C>]
? check<A & B & C>
: T extends [check<infer A>, check<infer B>, check<infer C>, check<infer D>]
? check<A & B & C & D>
: T extends [check<infer A>, check<infer B>, check<infer C>, check<infer D>, check<infer E>]
? check<A & B & C & D & E>
: T extends [check<infer A>, check<infer B>, check<infer C>, check<infer D>, check<infer E>, check<infer F>]
? check<A & B & C & D & E & F>
: never;
/** checks to see if `value` matches a given interface definition */
interface: <T extends { [index: string]: (value: unknown) => value is any }>(
checkTable: T
) => check<{ [P in keyof T]: t.static<T[P]> }>;
/** checks to see if `value` matches a given interface definition with no extra members */
strictInterface: <T extends { [index: string]: (value: unknown) => value is any }>(
checkTable: T
) => check<{ [P in keyof T]: t.static<T[P]> }>;
instanceOf<S extends keyof Instances>(this: void, className: S): check<Instances[S]>;
instanceOf<S extends keyof Instances, T extends { [index: string]: (value: unknown) => value is any }>(
this: void,
className: S,
checkTable: T
): check<Instances[S] & { [P in keyof T]: t.static<T[P]> }>;
instanceIsA<S extends keyof Instances>(this: void, className: S): check<Instances[S]>;
instanceIsA<S extends keyof Instances, T extends { [index: string]: (value: unknown) => value is any }>(
this: void,
className: S,
checkTable: T
): check<Instances[S] & { [P in keyof T]: t.static<T[P]> }>;
children: <T extends { [index: string]: (value: unknown) => value is any }>(
checkTable: T
) => check<Instance & { [P in keyof T]: t.static<T[P]> }>;
}
declare namespace t {
/** creates a static type from a t-defined type */
export type static<T> = T extends check<infer U> ? U : never;
}
declare const t: t;
export = t;
@@ -0,0 +1,554 @@
-- t: a runtime typechecker for Roblox
-- regular lua compatibility
local typeof = typeof or type
local function primitive(typeName)
return function(value)
local valueType = typeof(value)
if valueType == typeName then
return true
else
return false
end
end
end
local t = {}
function t.any(value)
if value ~= nil then
return true
else
return false
end
end
--Lua primitives
t.boolean = primitive("boolean")
t.thread = primitive("thread")
t.callback = primitive("function")
t.none = primitive("nil")
t.string = primitive("string")
t.table = primitive("table")
t.userdata = primitive("userdata")
function t.number(value)
local valueType = typeof(value)
if valueType == "number" then
if value == value then
return true
else
return false
end
else
return false
end
end
function t.nan(value)
if value ~= value then
return true
else
return false
end
end
-- roblox types
t.Axes = primitive("Axes")
t.BrickColor = primitive("BrickColor")
t.CFrame = primitive("CFrame")
t.Color3 = primitive("Color3")
t.ColorSequence = primitive("ColorSequence")
t.ColorSequenceKeypoint = primitive("ColorSequenceKeypoint")
t.DockWidgetPluginGuiInfo = primitive("DockWidgetPluginGuiInfo")
t.Faces = primitive("Faces")
t.Instance = primitive("Instance")
t.NumberRange = primitive("NumberRange")
t.NumberSequence = primitive("NumberSequence")
t.NumberSequenceKeypoint = primitive("NumberSequenceKeypoint")
t.PathWaypoint = primitive("PathWaypoint")
t.PhysicalProperties = primitive("PhysicalProperties")
t.Random = primitive("Random")
t.Ray = primitive("Ray")
t.Rect = primitive("Rect")
t.Region3 = primitive("Region3")
t.Region3int16 = primitive("Region3int16")
t.TweenInfo = primitive("TweenInfo")
t.UDim = primitive("UDim")
t.UDim2 = primitive("UDim2")
t.Vector2 = primitive("Vector2")
t.Vector3 = primitive("Vector3")
t.Vector3int16 = primitive("Vector3int16")
t.Enum = primitive("Enum")
t.EnumItem = primitive("EnumItem")
t.RBXScriptSignal = primitive("RBXScriptSignal")
t.RBXScriptConnection = primitive("RBXScriptConnection")
function t.literal(...)
local size = select("#", ...)
if size == 1 then
local literal = ...
return function(value)
if value ~= literal then
return false
end
return true
end
else
local literals = {}
for i = 1, size do
local value = select(i, ...)
literals[i] = t.literal(value)
end
return t.union(unpack(literals))
end
end
t.exactly = t.literal
function t.keyOf(keyTable)
local keys = {}
for key in pairs(keyTable) do
keys[#keys + 1] = key
end
return t.literal(unpack(keys))
end
function t.valueOf(valueTable)
local values = {}
for _, value in pairs(valueTable) do
values[#values + 1] = value
end
return t.literal(unpack(values))
end
function t.integer(value)
local success = t.number(value)
if not success then
return false
end
if value%1 == 0 then
return true
else
return false
end
end
function t.numberMin(min)
return function(value)
local success = t.number(value)
if not success then
return false
end
if value >= min then
return true
else
return false
end
end
end
function t.numberMax(max)
return function(value)
local success = t.number(value)
if not success then
return false
end
if value <= max then
return true
else
return false
end
end
end
function t.numberMinExclusive(min)
return function(value)
local success = t.number(value)
if not success then
return false
end
if min < value then
return true
else
return false
end
end
end
function t.numberMaxExclusive(max)
return function(value)
local success = t.number(value)
if not success then
return false
end
if value < max then
return true
else
return false
end
end
end
t.numberPositive = t.numberMinExclusive(0)
t.numberNegative = t.numberMaxExclusive(0)
function t.numberConstrained(min, max)
assert(t.number(min) and t.number(max))
local minCheck = t.numberMin(min)
local maxCheck = t.numberMax(max)
return function(value)
local minSuccess = minCheck(value)
if not minSuccess then
return false
end
local maxSuccess = maxCheck(value)
if not maxSuccess then
return false
end
return true
end
end
function t.numberConstrainedExclusive(min, max)
assert(t.number(min) and t.number(max))
local minCheck = t.numberMinExclusive(min)
local maxCheck = t.numberMaxExclusive(max)
return function(value)
local minSuccess = minCheck(value)
if not minSuccess then
return false
end
local maxSuccess = maxCheck(value)
if not maxSuccess then
return false
end
return true
end
end
function t.match(pattern)
assert(t.string(pattern))
return function(value)
local stringSuccess = t.string(value)
if not stringSuccess then
return false
end
if string.match(value, pattern) == nil then
return false
end
return true
end
end
function t.optional(check)
assert(t.callback(check))
return function(value)
if value == nil then
return true
end
local success = check(value)
if success then
return true
else
return false
end
end
end
function t.tuple(...)
local checks = {...}
return function(...)
local args = {...}
for i = 1, #checks do
local success = checks[i](args[i])
if success == false then
return false
end
end
return true
end
end
function t.keys(check)
assert(t.callback(check))
return function(value)
local tableSuccess = t.table(value)
if tableSuccess == false then
return false
end
for key in pairs(value) do
local success = check(key)
if success == false then
return false
end
end
return true
end
end
function t.values(check)
assert(t.callback(check))
return function(value)
local tableSuccess = t.table(value)
if tableSuccess == false then
return false
end
for _, val in pairs(value) do
local success = check(val)
if success == false then
return false
end
end
return true
end
end
function t.map(keyCheck, valueCheck)
assert(t.callback(keyCheck), t.callback(valueCheck))
local keyChecker = t.keys(keyCheck)
local valueChecker = t.values(valueCheck)
return function(value)
local keySuccess = keyChecker(value)
if not keySuccess then
return false
end
local valueSuccess = valueChecker(value)
if not valueSuccess then
return false
end
return true
end
end
do
local arrayKeysCheck = t.keys(t.integer)
function t.array(check)
assert(t.callback(check))
local valuesCheck = t.values(check)
return function(value)
local keySuccess = arrayKeysCheck(value)
if keySuccess == false then
return false
end
-- # is unreliable for sparse arrays
-- Count upwards using ipairs to avoid false positives from the behavior of #
local arraySize = 0
for _, _ in ipairs(value) do
arraySize = arraySize + 1
end
for key in pairs(value) do
if key < 1 or key > arraySize then
return false
end
end
local valueSuccess = valuesCheck(value)
if not valueSuccess then
return false
end
return true
end
end
end
do
local callbackArray = t.array(t.callback)
function t.union(...)
local checks = {...}
assert(callbackArray(checks))
return function(value)
for _, check in pairs(checks) do
if check(value) then
return true
end
end
return false
end
end
function t.intersection(...)
local checks = {...}
assert(callbackArray(checks))
return function(value)
for _, check in pairs(checks) do
local success = check(value)
if not success then
return false
end
end
return true
end
end
end
do
local checkInterface = t.map(t.any, t.callback)
function t.interface(checkTable)
assert(checkInterface(checkTable))
return function(value)
local tableSuccess = t.table(value)
if tableSuccess == false then
return false
end
for key, check in pairs(checkTable) do
local success = check(value[key])
if success == false then
return false
end
end
return true
end
end
function t.strictInterface(checkTable)
assert(checkInterface(checkTable))
return function(value)
local tableSuccess = t.table(value)
if tableSuccess == false then
return false
end
for key, check in pairs(checkTable) do
local success = check(value[key])
if success == false then
return false
end
end
for key in pairs(value) do
if not checkTable[key] then
return false
end
end
return true
end
end
end
function t.instanceOf(className)
assert(t.string(className))
return function(value)
local instanceSuccess = t.Instance(value)
if not instanceSuccess then
return false
end
if value.ClassName ~= className then
return false
end
return true
end
end
t.instance = t.instanceOf
function t.instanceIsA(className)
assert(t.string(className))
return function(value)
local instanceSuccess = t.Instance(value)
if not instanceSuccess then
return false
end
if not value:IsA(className) then
return false
end
return true
end
end
function t.enum(enum)
assert(t.Enum(enum))
return function(value)
local enumItemSuccess = t.EnumItem(value)
if not enumItemSuccess then
return false
end
if value.EnumType == enum then
return true
else
return false
end
end
end
do
local checkWrap = t.tuple(t.callback, t.callback)
function t.wrap(callback, checkArgs)
assert(checkWrap(callback, checkArgs))
return function(...)
assert(checkArgs(...))
return callback(...)
end
end
end
function t.strict(check)
return function(...)
assert(check(...))
end
end
do
local checkChildren = t.map(t.string, t.callback)
function t.children(checkTable)
assert(checkChildren(checkTable))
return function(value)
local instanceSuccess = t.Instance(value)
if not instanceSuccess then
return false
end
local childrenByName = {}
for _, child in pairs(value:GetChildren()) do
local name = child.Name
if checkTable[name] then
if childrenByName[name] then
return false
end
childrenByName[name] = child
end
end
for name, check in pairs(checkTable) do
local success = check(childrenByName[name])
if not success then
return false
end
end
return true
end
end
end
return t