From cef0f0568058e73cc5e2a43ee18f9c090eb5e80f Mon Sep 17 00:00:00 2001 From: bogotolec Date: Wed, 15 Oct 2025 03:19:13 +0300 Subject: [PATCH 01/17] First iteration: - made core and logic - made root with nil and number - added IsGreater method for number - test for check is lib is working --- default.project.json | 1 - src/Core/init.lua | 51 +++++++++++++++++++++++++++++++++++++ src/Helpers/init.lua | 17 +++++++++++++ src/Nil/NilChecks.lua | 9 +++++++ src/Nil/init.lua | 26 +++++++++++++++++++ src/Number/NumberChecks.lua | 17 +++++++++++++ src/Number/init.lua | 49 +++++++++++++++++++++++++++++++++++ src/Root/init.lua | 13 ++++++++++ src/Validator.spec.luau | 17 +++++++++++++ src/ValidatorTypes.lua | 32 +++++++++++++++++++++++ src/init.lua | 11 ++++++++ 11 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 src/Core/init.lua create mode 100644 src/Helpers/init.lua create mode 100644 src/Nil/NilChecks.lua create mode 100644 src/Nil/init.lua create mode 100644 src/Number/NumberChecks.lua create mode 100644 src/Number/init.lua create mode 100644 src/Root/init.lua create mode 100644 src/Validator.spec.luau create mode 100644 src/ValidatorTypes.lua diff --git a/default.project.json b/default.project.json index c33ddbb..2385a21 100644 --- a/default.project.json +++ b/default.project.json @@ -1,6 +1,5 @@ { "name": "Validator", - "globIgnorePaths": ["**.spec.luau"], "tree": { "$path": "src" } diff --git a/src/Core/init.lua b/src/Core/init.lua new file mode 100644 index 0000000..7c9556d --- /dev/null +++ b/src/Core/init.lua @@ -0,0 +1,51 @@ +--!strict + +local ValidatorTypes = require(script.Parent.ValidatorTypes) + +local CoreValidator = {} +CoreValidator.__index = CoreValidator + +local rootValidatorClass: ValidatorTypes.PrivateRootValidator + +function CoreValidator.new(): ValidatorTypes.PrivateValidator + local self = { + _checksGroups = { {} }, + } + + local validator = setmetatable(self :: any, CoreValidator) + + return validator +end + +function CoreValidator.Check(self: ValidatorTypes.PrivateValidator, value: any): boolean + for _, group in pairs(self._checksGroups) do + local passed = if next(group) then true else false + + for _, check in pairs(group) do + if not check._func(value, table.unpack(check._params)) then + passed = false + break + end + end + + if passed then + return true + end + end + + return false +end + +function CoreValidator.Or( + self: ValidatorTypes.PrivateValidator +): ValidatorTypes.PrivateRootValidator + table.insert(self._checksGroups, {}) + local new = setmetatable(self :: any, rootValidatorClass) + return new +end + +function CoreValidator._Setup(rootValidator: ValidatorTypes.PrivateRootValidator) + rootValidatorClass = rootValidator +end + +return CoreValidator diff --git a/src/Helpers/init.lua b/src/Helpers/init.lua new file mode 100644 index 0000000..12d823a --- /dev/null +++ b/src/Helpers/init.lua @@ -0,0 +1,17 @@ +--!strict +local ValidatorTypes = require(script.Parent.ValidatorTypes) + +local Helpers = {} + +function Helpers.AddCheck( + validator: ValidatorTypes.PrivateValidator, + func: (any, ...any) -> boolean, + ... +) + table.insert(validator._checksGroups[#validator._checksGroups], { + _func = func, + _params = table.pack(...), + }) +end + +return Helpers diff --git a/src/Nil/NilChecks.lua b/src/Nil/NilChecks.lua new file mode 100644 index 0000000..df10d83 --- /dev/null +++ b/src/Nil/NilChecks.lua @@ -0,0 +1,9 @@ +--!strict + +local NilChecks = {} + +function NilChecks.IsNil(value: number): boolean + return value == nil +end + +return NilChecks diff --git a/src/Nil/init.lua b/src/Nil/init.lua new file mode 100644 index 0000000..1c45408 --- /dev/null +++ b/src/Nil/init.lua @@ -0,0 +1,26 @@ +--!strict + +local NilChecks = require(script.NilChecks) +local CoreValidator = require(script.Parent.Core) +local Helpers = require(script.Parent.Helpers) +local ValidatorTypes = require(script.Parent.ValidatorTypes) + +local NilValidator = {} +setmetatable(NilValidator, CoreValidator) +NilValidator.__index = NilValidator + +function NilValidator.new(): ValidatorTypes.PublicNilValidator + local self = setmetatable(CoreValidator.new() :: any, NilValidator) + Helpers.AddCheck(self, NilChecks.IsNil) + return self +end + +function NilValidator.IsNil( + self: ValidatorTypes.PrivateValidator +): ValidatorTypes.PublicNilValidator + local new = setmetatable(self :: any, NilValidator) + Helpers.AddCheck(new, NilChecks.IsNil) + return new +end + +return NilValidator diff --git a/src/Number/NumberChecks.lua b/src/Number/NumberChecks.lua new file mode 100644 index 0000000..1f21eaa --- /dev/null +++ b/src/Number/NumberChecks.lua @@ -0,0 +1,17 @@ +--!strict + +local NumberChecks = {} + +function NumberChecks.IsNumber(value: any): boolean + return typeof(value) == "number" +end + +function NumberChecks.IsInteger(value: any): boolean + return NumberChecks.IsNumber(value) and (value % 1 == 0) +end + +function NumberChecks.IsGreater(value: number, param: number): boolean + return value > param +end + +return NumberChecks diff --git a/src/Number/init.lua b/src/Number/init.lua new file mode 100644 index 0000000..2faec98 --- /dev/null +++ b/src/Number/init.lua @@ -0,0 +1,49 @@ +--!strict + +local NumberChecks = require(script.NumberChecks) +local CoreValidator = require(script.Parent.Core) +local Helpers = require(script.Parent.Helpers) +local ValidatorTypes = require(script.Parent.ValidatorTypes) + +local NumberValidator = {} +setmetatable(NumberValidator, CoreValidator) +NumberValidator.__index = NumberValidator + +export type PrivateValidator = ValidatorTypes.PrivateValidator +export type PrivateNumberValidator = ValidatorTypes.PrivateNumberValidator + +function NumberValidator.newIsNumber(): ValidatorTypes.PublicNumberValidator + local self = setmetatable(CoreValidator.new() :: any, NumberValidator) + Helpers.AddCheck(self, NumberChecks.IsNumber) + return self +end + +function NumberValidator.newIsInteger(): ValidatorTypes.PublicNumberValidator + local self = setmetatable(CoreValidator.new() :: any, NumberValidator) + Helpers.AddCheck(self, NumberChecks.IsInteger) + return self +end + +function NumberValidator.IsNumber(self: PrivateValidator): PrivateNumberValidator + local new = setmetatable(self :: any, NumberValidator) + Helpers.AddCheck(new, NumberChecks.IsNumber) + return new +end + +function NumberValidator.IsInteger( + self: ValidatorTypes.PrivateValidator? +): ValidatorTypes.PrivateNumberValidator + local new = setmetatable(self :: any, NumberValidator) + Helpers.AddCheck(new, NumberChecks.IsInteger) + return new +end + +function NumberValidator.IsGreater( + self: ValidatorTypes.PrivateNumberValidator, + than: number +): ValidatorTypes.PrivateNumberValidator + Helpers.AddCheck(self, NumberChecks.IsGreater, than) + return self +end + +return NumberValidator diff --git a/src/Root/init.lua b/src/Root/init.lua new file mode 100644 index 0000000..aba638e --- /dev/null +++ b/src/Root/init.lua @@ -0,0 +1,13 @@ +--!strict + +local NilValidator = require(script.Parent.Nil) +local NumberValidator = require(script.Parent.Number) + +local RootValidator = {} +RootValidator.__index = RootValidator + +RootValidator.IsNumber = NumberValidator.IsNumber +RootValidator.IsInteger = NumberValidator.IsInteger +RootValidator.IsNil = NilValidator.IsNil + +return RootValidator diff --git a/src/Validator.spec.luau b/src/Validator.spec.luau new file mode 100644 index 0000000..c39916c --- /dev/null +++ b/src/Validator.spec.luau @@ -0,0 +1,17 @@ +--!strict + +local Validator = require(script.Parent) + +return function() + describe("Validator", function() + it("Should work", function() + local validator = Validator.IsInteger():IsGreater(5):Or():IsNil() + + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check(5)).to.be.equal(false) + expect(validator:Check(10)).to.be.equal(true) + expect(validator:Check(nil)).to.be.equal(true) + expect(validator:Check("10")).to.be.equal(false) + end) + end) +end diff --git a/src/ValidatorTypes.lua b/src/ValidatorTypes.lua new file mode 100644 index 0000000..d288116 --- /dev/null +++ b/src/ValidatorTypes.lua @@ -0,0 +1,32 @@ +--!strict + +export type Check = { + _func: (any, ...any) -> boolean, + _params: typeof(table.pack(...)), +} + +export type PublicValidator = typeof(setmetatable({}, {})) & { + Check: (self: PublicValidator, data: any) -> boolean, + Or: (self: PublicValidator) -> PublicRootValidator, +} +export type PrivateValidator = PublicValidator & { + _checksGroups: { { Check } }, +} + +export type RootMethods = { + IsNumber: (self: PublicValidator) -> PublicNumberValidator, + IsInteger: (self: PublicValidator) -> PublicNumberValidator, + IsNil: (self: PublicValidator) -> PublicNilValidator, +} +export type PublicRootValidator = PublicValidator & RootMethods +export type PrivateRootValidator = PublicRootValidator & PrivateValidator + +export type PublicNumberValidator = PublicValidator & { + IsGreater: (self: PublicNumberValidator, than: number) -> PublicNumberValidator, +} +export type PrivateNumberValidator = PublicNumberValidator & PrivateValidator + +export type PublicNilValidator = PublicValidator & {} +export type PrivateNilValidator = PublicNilValidator & PrivateValidator + +return {} diff --git a/src/init.lua b/src/init.lua index 6653a2a..7a15009 100644 --- a/src/init.lua +++ b/src/init.lua @@ -1,5 +1,16 @@ --!strict +local CoreValidator = require(script.Core) +local RootValidator = require(script.Root) +local NilValidator = require(script.Nil) +local NumberValidator = require(script.Number) + local Validator = {} +CoreValidator._Setup(RootValidator :: any) + +Validator.IsNumber = NumberValidator.newIsNumber +Validator.IsInteger = NumberValidator.newIsInteger +Validator.IsNil = NilValidator.new + return Validator From 37da62d00db27c50af6715ae4fa07155414f304e Mon Sep 17 00:00:00 2001 From: bogotolec Date: Thu, 16 Oct 2025 01:27:07 +0300 Subject: [PATCH 02/17] Created .Not and .Or operations - .Not negates the following check - .Or creates a new check group --- src/Core/init.lua | 14 +++++++++++++- src/Helpers/init.lua | 18 ++++++++++++++++++ src/Number/init.lua | 8 ++++---- src/Validator.spec.luau | 3 ++- src/ValidatorTypes.lua | 11 +++++++---- 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/Core/init.lua b/src/Core/init.lua index 7c9556d..6b02681 100644 --- a/src/Core/init.lua +++ b/src/Core/init.lua @@ -21,11 +21,23 @@ function CoreValidator.Check(self: ValidatorTypes.PrivateValidator, value: any): for _, group in pairs(self._checksGroups) do local passed = if next(group) then true else false + local isNegated = false + for _, check in pairs(group) do - if not check._func(value, table.unpack(check._params)) then + if not check then + isNegated = not isNegated + continue + end + + assert(type(check) == "table", "Check is not table, which is not possible.") + + local res = check._func(value, table.unpack(check._params)) + + if (isNegated and res) or (not isNegated and not res) then passed = false break end + isNegated = false end if passed then diff --git a/src/Helpers/init.lua b/src/Helpers/init.lua index 12d823a..f77cd29 100644 --- a/src/Helpers/init.lua +++ b/src/Helpers/init.lua @@ -1,4 +1,6 @@ --!strict + +local Core = require(script.Parent.Core) local ValidatorTypes = require(script.Parent.ValidatorTypes) local Helpers = {} @@ -14,4 +16,20 @@ function Helpers.AddCheck( }) end +function Helpers.CreateIndex(c: T): (ValidatorTypes.PrivateValidator, string) -> any + assert(typeof(c) == "table", `Expected {c} to be a table.`) + return function(self: ValidatorTypes.PrivateValidator, key: string): any + if key == "Not" then + table.insert(self._checksGroups[#self._checksGroups], false) + return self + end + + if key == "Or" then + return Core.Or(self) + end + + return c[key] + end +end + return Helpers diff --git a/src/Number/init.lua b/src/Number/init.lua index 2faec98..0b69515 100644 --- a/src/Number/init.lua +++ b/src/Number/init.lua @@ -5,13 +5,13 @@ local CoreValidator = require(script.Parent.Core) local Helpers = require(script.Parent.Helpers) local ValidatorTypes = require(script.Parent.ValidatorTypes) -local NumberValidator = {} -setmetatable(NumberValidator, CoreValidator) -NumberValidator.__index = NumberValidator - export type PrivateValidator = ValidatorTypes.PrivateValidator export type PrivateNumberValidator = ValidatorTypes.PrivateNumberValidator +local NumberValidator = {} +setmetatable(NumberValidator, CoreValidator) +NumberValidator.__index = Helpers.CreateIndex(NumberValidator) + function NumberValidator.newIsNumber(): ValidatorTypes.PublicNumberValidator local self = setmetatable(CoreValidator.new() :: any, NumberValidator) Helpers.AddCheck(self, NumberChecks.IsNumber) diff --git a/src/Validator.spec.luau b/src/Validator.spec.luau index c39916c..b0632c4 100644 --- a/src/Validator.spec.luau +++ b/src/Validator.spec.luau @@ -5,11 +5,12 @@ local Validator = require(script.Parent) return function() describe("Validator", function() it("Should work", function() - local validator = Validator.IsInteger():IsGreater(5):Or():IsNil() + local validator = Validator.IsInteger():IsGreater(5).Not:IsGreater(14).Or:IsNil() expect(validator:Check(0)).to.be.equal(false) expect(validator:Check(5)).to.be.equal(false) expect(validator:Check(10)).to.be.equal(true) + expect(validator:Check(15)).to.be.equal(false) expect(validator:Check(nil)).to.be.equal(true) expect(validator:Check("10")).to.be.equal(false) end) diff --git a/src/ValidatorTypes.lua b/src/ValidatorTypes.lua index d288116..ba2a40f 100644 --- a/src/ValidatorTypes.lua +++ b/src/ValidatorTypes.lua @@ -1,13 +1,13 @@ --!strict -export type Check = { +export type Check = false | { _func: (any, ...any) -> boolean, _params: typeof(table.pack(...)), } export type PublicValidator = typeof(setmetatable({}, {})) & { Check: (self: PublicValidator, data: any) -> boolean, - Or: (self: PublicValidator) -> PublicRootValidator, + Or: PublicRootValidator, } export type PrivateValidator = PublicValidator & { _checksGroups: { { Check } }, @@ -21,8 +21,11 @@ export type RootMethods = { export type PublicRootValidator = PublicValidator & RootMethods export type PrivateRootValidator = PublicRootValidator & PrivateValidator -export type PublicNumberValidator = PublicValidator & { - IsGreater: (self: PublicNumberValidator, than: number) -> PublicNumberValidator, +export type NumberValidatorMethods = { + IsGreater: (self: NumberValidatorMethods, than: number) -> PublicNumberValidator, +} +export type PublicNumberValidator = PublicValidator & NumberValidatorMethods & { + Not: NumberValidatorMethods, } export type PrivateNumberValidator = PublicNumberValidator & PrivateValidator From e1e2bdfa1d8badfa0a59b22653eb7c733f2561f5 Mon Sep 17 00:00:00 2001 From: bogotolec Date: Thu, 16 Oct 2025 22:36:54 +0300 Subject: [PATCH 03/17] Changed style from .Or and .Not to :Or() and :Not() to be more consistent --- src/Core/init.lua | 5 +++++ src/Helpers/init.lua | 17 ----------------- src/Number/init.lua | 2 +- src/Validator.spec.luau | 2 +- src/ValidatorTypes.lua | 4 ++-- 5 files changed, 9 insertions(+), 21 deletions(-) diff --git a/src/Core/init.lua b/src/Core/init.lua index 6b02681..50dab98 100644 --- a/src/Core/init.lua +++ b/src/Core/init.lua @@ -56,6 +56,11 @@ function CoreValidator.Or( return new end +function CoreValidator.Not(self: ValidatorTypes.PrivateValidator): ValidatorTypes.PrivateValidator + table.insert(self._checksGroups[#self._checksGroups], false) + return self +end + function CoreValidator._Setup(rootValidator: ValidatorTypes.PrivateRootValidator) rootValidatorClass = rootValidator end diff --git a/src/Helpers/init.lua b/src/Helpers/init.lua index f77cd29..a2db2a2 100644 --- a/src/Helpers/init.lua +++ b/src/Helpers/init.lua @@ -1,6 +1,5 @@ --!strict -local Core = require(script.Parent.Core) local ValidatorTypes = require(script.Parent.ValidatorTypes) local Helpers = {} @@ -16,20 +15,4 @@ function Helpers.AddCheck( }) end -function Helpers.CreateIndex(c: T): (ValidatorTypes.PrivateValidator, string) -> any - assert(typeof(c) == "table", `Expected {c} to be a table.`) - return function(self: ValidatorTypes.PrivateValidator, key: string): any - if key == "Not" then - table.insert(self._checksGroups[#self._checksGroups], false) - return self - end - - if key == "Or" then - return Core.Or(self) - end - - return c[key] - end -end - return Helpers diff --git a/src/Number/init.lua b/src/Number/init.lua index 0b69515..6feeccf 100644 --- a/src/Number/init.lua +++ b/src/Number/init.lua @@ -10,7 +10,7 @@ export type PrivateNumberValidator = ValidatorTypes.PrivateNumberValidator local NumberValidator = {} setmetatable(NumberValidator, CoreValidator) -NumberValidator.__index = Helpers.CreateIndex(NumberValidator) +NumberValidator.__index = NumberValidator function NumberValidator.newIsNumber(): ValidatorTypes.PublicNumberValidator local self = setmetatable(CoreValidator.new() :: any, NumberValidator) diff --git a/src/Validator.spec.luau b/src/Validator.spec.luau index b0632c4..3d3a6c9 100644 --- a/src/Validator.spec.luau +++ b/src/Validator.spec.luau @@ -5,7 +5,7 @@ local Validator = require(script.Parent) return function() describe("Validator", function() it("Should work", function() - local validator = Validator.IsInteger():IsGreater(5).Not:IsGreater(14).Or:IsNil() + local validator = Validator.IsInteger():IsGreater(5):Not():IsGreater(14):Or():IsNil() expect(validator:Check(0)).to.be.equal(false) expect(validator:Check(5)).to.be.equal(false) diff --git a/src/ValidatorTypes.lua b/src/ValidatorTypes.lua index ba2a40f..a9ac888 100644 --- a/src/ValidatorTypes.lua +++ b/src/ValidatorTypes.lua @@ -7,7 +7,7 @@ export type Check = false | { export type PublicValidator = typeof(setmetatable({}, {})) & { Check: (self: PublicValidator, data: any) -> boolean, - Or: PublicRootValidator, + Or: (self: PublicValidator) -> PublicRootValidator, } export type PrivateValidator = PublicValidator & { _checksGroups: { { Check } }, @@ -25,7 +25,7 @@ export type NumberValidatorMethods = { IsGreater: (self: NumberValidatorMethods, than: number) -> PublicNumberValidator, } export type PublicNumberValidator = PublicValidator & NumberValidatorMethods & { - Not: NumberValidatorMethods, + Not: (self: PublicValidator) -> NumberValidatorMethods, } export type PrivateNumberValidator = PublicNumberValidator & PrivateValidator From 6668288863dd78f4b33b4d742b182663e5872236 Mon Sep 17 00:00:00 2001 From: bogotolec Date: Thu, 16 Oct 2025 22:48:54 +0300 Subject: [PATCH 04/17] Added :Freeze() method for locking the validator --- src/Core/init.lua | 5 +++++ src/Validator.spec.luau | 3 ++- src/ValidatorTypes.lua | 8 ++++++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Core/init.lua b/src/Core/init.lua index 50dab98..661f64b 100644 --- a/src/Core/init.lua +++ b/src/Core/init.lua @@ -48,6 +48,11 @@ function CoreValidator.Check(self: ValidatorTypes.PrivateValidator, value: any): return false end +function CoreValidator.Freeze(self: ValidatorTypes.PrivateValidator): ValidatorTypes.Checker + -- TODO add actual freeze (prohibit calling other methods) + return self +end + function CoreValidator.Or( self: ValidatorTypes.PrivateValidator ): ValidatorTypes.PrivateRootValidator diff --git a/src/Validator.spec.luau b/src/Validator.spec.luau index 3d3a6c9..1b767c7 100644 --- a/src/Validator.spec.luau +++ b/src/Validator.spec.luau @@ -5,7 +5,8 @@ local Validator = require(script.Parent) return function() describe("Validator", function() it("Should work", function() - local validator = Validator.IsInteger():IsGreater(5):Not():IsGreater(14):Or():IsNil() + local validator = + Validator.IsInteger():IsGreater(5):Not():IsGreater(14):Or():IsNil():Freeze() expect(validator:Check(0)).to.be.equal(false) expect(validator:Check(5)).to.be.equal(false) diff --git a/src/ValidatorTypes.lua b/src/ValidatorTypes.lua index a9ac888..1b8e954 100644 --- a/src/ValidatorTypes.lua +++ b/src/ValidatorTypes.lua @@ -5,9 +5,13 @@ export type Check = false | { _params: typeof(table.pack(...)), } -export type PublicValidator = typeof(setmetatable({}, {})) & { - Check: (self: PublicValidator, data: any) -> boolean, +export type Checker = typeof(setmetatable({}, {})) & { + Check: (self: Checker, data: any) -> boolean, +} + +export type PublicValidator = Checker & { Or: (self: PublicValidator) -> PublicRootValidator, + Freeze: (self: PublicValidator) -> Checker, } export type PrivateValidator = PublicValidator & { _checksGroups: { { Check } }, From 01f89cde3e80cdc839cd429a1a6242ef413a01d5 Mon Sep 17 00:00:00 2001 From: bogotolec Date: Thu, 16 Oct 2025 23:00:02 +0300 Subject: [PATCH 05/17] Added :Assert method --- src/Core/init.lua | 12 ++++++++++++ src/Validator.spec.luau | 14 ++++++++++++++ src/ValidatorTypes.lua | 1 + 3 files changed, 27 insertions(+) diff --git a/src/Core/init.lua b/src/Core/init.lua index 661f64b..a4d0cf3 100644 --- a/src/Core/init.lua +++ b/src/Core/init.lua @@ -48,6 +48,18 @@ function CoreValidator.Check(self: ValidatorTypes.PrivateValidator, value: any): return false end +function CoreValidator.Assert( + self: ValidatorTypes.PrivateValidator, + value: any, + message: string? +): any + if not self:Check(value) then + error(message or `Value {value} does not satisfy the validator checks.`) + end + + return value +end + function CoreValidator.Freeze(self: ValidatorTypes.PrivateValidator): ValidatorTypes.Checker -- TODO add actual freeze (prohibit calling other methods) return self diff --git a/src/Validator.spec.luau b/src/Validator.spec.luau index 1b767c7..f21dec9 100644 --- a/src/Validator.spec.luau +++ b/src/Validator.spec.luau @@ -14,6 +14,20 @@ return function() expect(validator:Check(15)).to.be.equal(false) expect(validator:Check(nil)).to.be.equal(true) expect(validator:Check("10")).to.be.equal(false) + + local success, value = pcall(function() + return validator:Assert(0, "Error") + end) + + expect(success).to.be.equal(false) + expect(value).never.to.be.equal(0) + + success, value = pcall(function() + return validator:Assert(10, "Error") + end) + + expect(success).to.be.equal(true) + expect(value).to.be.equal(10) end) end) end diff --git a/src/ValidatorTypes.lua b/src/ValidatorTypes.lua index 1b8e954..b8c083f 100644 --- a/src/ValidatorTypes.lua +++ b/src/ValidatorTypes.lua @@ -7,6 +7,7 @@ export type Check = false | { export type Checker = typeof(setmetatable({}, {})) & { Check: (self: Checker, data: any) -> boolean, + Assert: (self: Checker, data: any, message: string?) -> any, } export type PublicValidator = Checker & { From 628af65c681b47544b83a169d1ba268940cd8694 Mon Sep 17 00:00:00 2001 From: bogotolec Date: Fri, 17 Oct 2025 01:02:54 +0300 Subject: [PATCH 06/17] Added String root --- src/Root/init.lua | 2 ++ src/String/StringChecks.lua | 9 +++++++++ src/String/init.lua | 27 +++++++++++++++++++++++++++ src/Validator.spec.luau | 16 +++++++++++++++- src/ValidatorTypes.lua | 9 +++++++++ src/init.lua | 2 ++ 6 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/String/StringChecks.lua create mode 100644 src/String/init.lua diff --git a/src/Root/init.lua b/src/Root/init.lua index aba638e..038c880 100644 --- a/src/Root/init.lua +++ b/src/Root/init.lua @@ -2,6 +2,7 @@ local NilValidator = require(script.Parent.Nil) local NumberValidator = require(script.Parent.Number) +local StringValidator = require(script.Parent.String) local RootValidator = {} RootValidator.__index = RootValidator @@ -9,5 +10,6 @@ RootValidator.__index = RootValidator RootValidator.IsNumber = NumberValidator.IsNumber RootValidator.IsInteger = NumberValidator.IsInteger RootValidator.IsNil = NilValidator.IsNil +RootValidator.IsString = StringValidator.IsString return RootValidator diff --git a/src/String/StringChecks.lua b/src/String/StringChecks.lua new file mode 100644 index 0000000..b8038f1 --- /dev/null +++ b/src/String/StringChecks.lua @@ -0,0 +1,9 @@ +--!strict + +local StringChecks = {} + +function StringChecks.IsString(value: any): boolean + return type(value) == "string" +end + +return StringChecks diff --git a/src/String/init.lua b/src/String/init.lua new file mode 100644 index 0000000..6606898 --- /dev/null +++ b/src/String/init.lua @@ -0,0 +1,27 @@ +--!strict + +local StringChecks = require(script.StringChecks) +local CoreValidator = require(script.Parent.Core) +local Helpers = require(script.Parent.Helpers) +local ValidatorTypes = require(script.Parent.ValidatorTypes) + +export type PrivateValidator = ValidatorTypes.PrivateValidator +export type PrivateNumberValidator = ValidatorTypes.PrivateNumberValidator + +local StringValidator = {} +setmetatable(StringValidator, CoreValidator) +StringValidator.__index = StringValidator + +function StringValidator.new(): ValidatorTypes.PublicNumberValidator + local self = setmetatable(CoreValidator.new() :: any, StringValidator) + Helpers.AddCheck(self, StringChecks.IsString) + return self +end + +function StringValidator.IsString(self: PrivateValidator): PrivateNumberValidator + local new = setmetatable(self :: any, StringValidator) + Helpers.AddCheck(new, StringChecks.IsString) + return new +end + +return StringValidator diff --git a/src/Validator.spec.luau b/src/Validator.spec.luau index f21dec9..c88bb8c 100644 --- a/src/Validator.spec.luau +++ b/src/Validator.spec.luau @@ -4,7 +4,7 @@ local Validator = require(script.Parent) return function() describe("Validator", function() - it("Should work", function() + it("00. Check if it works", function() local validator = Validator.IsInteger():IsGreater(5):Not():IsGreater(14):Or():IsNil():Freeze() @@ -29,5 +29,19 @@ return function() expect(success).to.be.equal(true) expect(value).to.be.equal(10) end) + + it("01. Test strings", function() + local validator = Validator.IsString():Freeze() + + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check("0")).to.be.equal(true) + expect(validator:Check(nil)).to.be.equal(false) + + validator = Validator.IsNumber():Or():IsString():Freeze() + + expect(validator:Check(0)).to.be.equal(true) + expect(validator:Check("0")).to.be.equal(true) + expect(validator:Check(nil)).to.be.equal(false) + end) end) end diff --git a/src/ValidatorTypes.lua b/src/ValidatorTypes.lua index b8c083f..348ce44 100644 --- a/src/ValidatorTypes.lua +++ b/src/ValidatorTypes.lua @@ -22,6 +22,7 @@ export type RootMethods = { IsNumber: (self: PublicValidator) -> PublicNumberValidator, IsInteger: (self: PublicValidator) -> PublicNumberValidator, IsNil: (self: PublicValidator) -> PublicNilValidator, + IsString: (self: PublicValidator) -> PublicStringValidator, } export type PublicRootValidator = PublicValidator & RootMethods export type PrivateRootValidator = PublicRootValidator & PrivateValidator @@ -37,4 +38,12 @@ export type PrivateNumberValidator = PublicNumberValidator & PrivateValidator export type PublicNilValidator = PublicValidator & {} export type PrivateNilValidator = PublicNilValidator & PrivateValidator +export type StringValidatorMethods = { + IsGreater: (self: NumberValidatorMethods, than: number) -> PublicNumberValidator, +} +export type PublicStringValidator = PublicValidator & StringValidatorMethods & { + Not: (self: PublicValidator) -> StringValidatorMethods, +} +export type PrivateStringValidator = PublicStringValidator & PrivateValidator + return {} diff --git a/src/init.lua b/src/init.lua index 7a15009..89c9eaa 100644 --- a/src/init.lua +++ b/src/init.lua @@ -4,6 +4,7 @@ local CoreValidator = require(script.Core) local RootValidator = require(script.Root) local NilValidator = require(script.Nil) local NumberValidator = require(script.Number) +local StringValidator = require(script.String) local Validator = {} @@ -12,5 +13,6 @@ CoreValidator._Setup(RootValidator :: any) Validator.IsNumber = NumberValidator.newIsNumber Validator.IsInteger = NumberValidator.newIsInteger Validator.IsNil = NilValidator.new +Validator.IsString = StringValidator.new return Validator From a373ecc9eb89810b344706bac1bc108510ccee7f Mon Sep 17 00:00:00 2001 From: bogotolec Date: Fri, 17 Oct 2025 01:08:19 +0300 Subject: [PATCH 07/17] Changed typization to show correct available methods after :Or() --- src/ValidatorTypes.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ValidatorTypes.lua b/src/ValidatorTypes.lua index 348ce44..e222032 100644 --- a/src/ValidatorTypes.lua +++ b/src/ValidatorTypes.lua @@ -11,7 +11,7 @@ export type Checker = typeof(setmetatable({}, {})) & { } export type PublicValidator = Checker & { - Or: (self: PublicValidator) -> PublicRootValidator, + Or: (self: PublicValidator) -> RootMethods, Freeze: (self: PublicValidator) -> Checker, } export type PrivateValidator = PublicValidator & { @@ -19,10 +19,10 @@ export type PrivateValidator = PublicValidator & { } export type RootMethods = { - IsNumber: (self: PublicValidator) -> PublicNumberValidator, - IsInteger: (self: PublicValidator) -> PublicNumberValidator, - IsNil: (self: PublicValidator) -> PublicNilValidator, - IsString: (self: PublicValidator) -> PublicStringValidator, + IsNumber: (self: RootMethods) -> PublicNumberValidator, + IsInteger: (self: RootMethods) -> PublicNumberValidator, + IsNil: (self: RootMethods) -> PublicNilValidator, + IsString: (self: RootMethods) -> PublicStringValidator, } export type PublicRootValidator = PublicValidator & RootMethods export type PrivateRootValidator = PublicRootValidator & PrivateValidator From c6c3f1612ed5627be86e2b67d5aff5de90f815de Mon Sep 17 00:00:00 2001 From: bogotolec Date: Fri, 17 Oct 2025 01:25:25 +0300 Subject: [PATCH 08/17] Added boolean root --- src/Boolean/BooleanChecks.lua | 9 +++++++++ src/Boolean/init.lua | 26 ++++++++++++++++++++++++++ src/Root/init.lua | 2 ++ src/Validator.spec.luau | 16 ++++++++++++++++ src/ValidatorTypes.lua | 32 +++++++++++++++++++++++++++++--- src/init.lua | 2 ++ 6 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 src/Boolean/BooleanChecks.lua create mode 100644 src/Boolean/init.lua diff --git a/src/Boolean/BooleanChecks.lua b/src/Boolean/BooleanChecks.lua new file mode 100644 index 0000000..2cbb30a --- /dev/null +++ b/src/Boolean/BooleanChecks.lua @@ -0,0 +1,9 @@ +--!strict + +local BooleanChecks = {} + +function BooleanChecks.IsBoolean(value: any): boolean + return typeof(value) == "boolean" +end + +return BooleanChecks diff --git a/src/Boolean/init.lua b/src/Boolean/init.lua new file mode 100644 index 0000000..5836a5c --- /dev/null +++ b/src/Boolean/init.lua @@ -0,0 +1,26 @@ +--!strict + +local BooleanChecks = require(script.BooleanChecks) +local CoreValidator = require(script.Parent.Core) +local Helpers = require(script.Parent.Helpers) +local ValidatorTypes = require(script.Parent.ValidatorTypes) + +local BooleanValidator = {} +setmetatable(BooleanValidator, CoreValidator) +BooleanValidator.__index = BooleanValidator + +function BooleanValidator.new(): ValidatorTypes.PublicBooleanValidator + local self = setmetatable(CoreValidator.new() :: any, BooleanValidator) + Helpers.AddCheck(self, BooleanChecks.IsBoolean) + return self +end + +function BooleanValidator.IsBoolean( + self: ValidatorTypes.PrivateValidator +): ValidatorTypes.PublicBooleanValidator + local new = setmetatable(self :: any, BooleanValidator) + Helpers.AddCheck(new, BooleanChecks.IsBoolean) + return new +end + +return BooleanValidator diff --git a/src/Root/init.lua b/src/Root/init.lua index 038c880..9984d07 100644 --- a/src/Root/init.lua +++ b/src/Root/init.lua @@ -1,5 +1,6 @@ --!strict +local BooleanValidator = require(script.Parent.Boolean) local NilValidator = require(script.Parent.Nil) local NumberValidator = require(script.Parent.Number) local StringValidator = require(script.Parent.String) @@ -11,5 +12,6 @@ RootValidator.IsNumber = NumberValidator.IsNumber RootValidator.IsInteger = NumberValidator.IsInteger RootValidator.IsNil = NilValidator.IsNil RootValidator.IsString = StringValidator.IsString +RootValidator.IsBoolean = BooleanValidator.IsBoolean return RootValidator diff --git a/src/Validator.spec.luau b/src/Validator.spec.luau index c88bb8c..5d8c00c 100644 --- a/src/Validator.spec.luau +++ b/src/Validator.spec.luau @@ -43,5 +43,21 @@ return function() expect(validator:Check("0")).to.be.equal(true) expect(validator:Check(nil)).to.be.equal(false) end) + + it("02. Test booleans", function() + local validator = Validator.IsBoolean():Freeze() + + expect(validator:Check(true)).to.be.equal(true) + expect(validator:Check(false)).to.be.equal(true) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check(nil)).to.be.equal(false) + + validator = Validator.IsNumber():Or():IsBoolean():Freeze() + + expect(validator:Check(true)).to.be.equal(true) + expect(validator:Check(false)).to.be.equal(true) + expect(validator:Check(0)).to.be.equal(true) + expect(validator:Check(nil)).to.be.equal(false) + end) end) end diff --git a/src/ValidatorTypes.lua b/src/ValidatorTypes.lua index e222032..dd2cc54 100644 --- a/src/ValidatorTypes.lua +++ b/src/ValidatorTypes.lua @@ -1,5 +1,7 @@ --!strict +--#region Core + export type Check = false | { _func: (any, ...any) -> boolean, _params: typeof(table.pack(...)), @@ -18,15 +20,24 @@ export type PrivateValidator = PublicValidator & { _checksGroups: { { Check } }, } +--#endregion + +--#region Root + export type RootMethods = { IsNumber: (self: RootMethods) -> PublicNumberValidator, IsInteger: (self: RootMethods) -> PublicNumberValidator, IsNil: (self: RootMethods) -> PublicNilValidator, IsString: (self: RootMethods) -> PublicStringValidator, + IsBoolean: (self: RootMethods) -> PublicBooleanValidator, } export type PublicRootValidator = PublicValidator & RootMethods export type PrivateRootValidator = PublicRootValidator & PrivateValidator +--#endregion + +--#region Number + export type NumberValidatorMethods = { IsGreater: (self: NumberValidatorMethods, than: number) -> PublicNumberValidator, } @@ -35,15 +46,30 @@ export type PublicNumberValidator = PublicValidator & NumberValidatorMethods & { } export type PrivateNumberValidator = PublicNumberValidator & PrivateValidator +--#endregion + +--#region Nil + export type PublicNilValidator = PublicValidator & {} export type PrivateNilValidator = PublicNilValidator & PrivateValidator -export type StringValidatorMethods = { - IsGreater: (self: NumberValidatorMethods, than: number) -> PublicNumberValidator, -} +--#endregion + +--#region String + +export type StringValidatorMethods = {} export type PublicStringValidator = PublicValidator & StringValidatorMethods & { Not: (self: PublicValidator) -> StringValidatorMethods, } export type PrivateStringValidator = PublicStringValidator & PrivateValidator +--#endregion + +--#region Boolean + +export type PublicBooleanValidator = PublicValidator & {} +export type PrivateBooleanValidator = PublicBooleanValidator & PrivateValidator + +--#endregion + return {} diff --git a/src/init.lua b/src/init.lua index 89c9eaa..e1ed2eb 100644 --- a/src/init.lua +++ b/src/init.lua @@ -1,5 +1,6 @@ --!strict +local BooleanValidator = require(script.Boolean) local CoreValidator = require(script.Core) local RootValidator = require(script.Root) local NilValidator = require(script.Nil) @@ -14,5 +15,6 @@ Validator.IsNumber = NumberValidator.newIsNumber Validator.IsInteger = NumberValidator.newIsInteger Validator.IsNil = NilValidator.new Validator.IsString = StringValidator.new +Validator.IsBoolean = BooleanValidator.new return Validator From e6e9531816c355757f426227c8001a14f4602b17 Mon Sep 17 00:00:00 2001 From: bogotolec Date: Fri, 17 Oct 2025 02:03:22 +0300 Subject: [PATCH 09/17] Added nan root --- src/Nan/NanChecks.lua | 9 +++++++++ src/Nan/init.lua | 26 ++++++++++++++++++++++++++ src/Number/NumberChecks.lua | 2 +- src/Root/init.lua | 2 ++ src/Validator.spec.luau | 31 +++++++++++++++++++++++++++++++ src/ValidatorTypes.lua | 8 ++++++++ src/init.lua | 2 ++ 7 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 src/Nan/NanChecks.lua create mode 100644 src/Nan/init.lua diff --git a/src/Nan/NanChecks.lua b/src/Nan/NanChecks.lua new file mode 100644 index 0000000..62bf660 --- /dev/null +++ b/src/Nan/NanChecks.lua @@ -0,0 +1,9 @@ +--!strict + +local NanChecks = {} + +function NanChecks.IsNan(value: any): boolean + return typeof(value) == "number" and value ~= value -- NaN check +end + +return NanChecks diff --git a/src/Nan/init.lua b/src/Nan/init.lua new file mode 100644 index 0000000..030baf4 --- /dev/null +++ b/src/Nan/init.lua @@ -0,0 +1,26 @@ +--!strict + +local NanChecks = require(script.NanChecks) +local CoreValidator = require(script.Parent.Core) +local Helpers = require(script.Parent.Helpers) +local ValidatorTypes = require(script.Parent.ValidatorTypes) + +local NanValidator = {} +setmetatable(NanValidator, CoreValidator) +NanValidator.__index = NanValidator + +function NanValidator.new(): ValidatorTypes.PublicNanValidator + local self = setmetatable(CoreValidator.new() :: any, NanValidator) + Helpers.AddCheck(self, NanChecks.IsNan) + return self +end + +function NanValidator.IsNan( + self: ValidatorTypes.PrivateValidator +): ValidatorTypes.PublicNanValidator + local new = setmetatable(self :: any, NanValidator) + Helpers.AddCheck(new, NanChecks.IsNan) + return new +end + +return NanValidator diff --git a/src/Number/NumberChecks.lua b/src/Number/NumberChecks.lua index 1f21eaa..6d65534 100644 --- a/src/Number/NumberChecks.lua +++ b/src/Number/NumberChecks.lua @@ -3,7 +3,7 @@ local NumberChecks = {} function NumberChecks.IsNumber(value: any): boolean - return typeof(value) == "number" + return typeof(value) == "number" and value == value -- NaN check end function NumberChecks.IsInteger(value: any): boolean diff --git a/src/Root/init.lua b/src/Root/init.lua index 9984d07..e9d946a 100644 --- a/src/Root/init.lua +++ b/src/Root/init.lua @@ -1,6 +1,7 @@ --!strict local BooleanValidator = require(script.Parent.Boolean) +local NanValidator = require(script.Parent.Nan) local NilValidator = require(script.Parent.Nil) local NumberValidator = require(script.Parent.Number) local StringValidator = require(script.Parent.String) @@ -13,5 +14,6 @@ RootValidator.IsInteger = NumberValidator.IsInteger RootValidator.IsNil = NilValidator.IsNil RootValidator.IsString = StringValidator.IsString RootValidator.IsBoolean = BooleanValidator.IsBoolean +RootValidator.IsNan = NanValidator.IsNan return RootValidator diff --git a/src/Validator.spec.luau b/src/Validator.spec.luau index 5d8c00c..83895b1 100644 --- a/src/Validator.spec.luau +++ b/src/Validator.spec.luau @@ -59,5 +59,36 @@ return function() expect(validator:Check(0)).to.be.equal(true) expect(validator:Check(nil)).to.be.equal(false) end) + + it("03. Test numbers and nans", function() + local nan = 0 / 0 + local validator = Validator.IsNan():Freeze() + + expect(validator:Check(nan)).to.be.equal(true) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check(0.5)).to.be.equal(false) + expect(validator:Check("0")).to.be.equal(false) + + validator = Validator.IsNumber():Freeze() + + expect(validator:Check(nan)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(true) + expect(validator:Check(0.5)).to.be.equal(true) + expect(validator:Check("0")).to.be.equal(false) + + validator = Validator.IsInteger():Freeze() + + expect(validator:Check(nan)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(true) + expect(validator:Check(0.5)).to.be.equal(false) + expect(validator:Check("0")).to.be.equal(false) + + validator = Validator.IsNumber():Or():IsNan():Freeze() + + expect(validator:Check(nan)).to.be.equal(true) + expect(validator:Check(0)).to.be.equal(true) + expect(validator:Check(0.5)).to.be.equal(true) + expect(validator:Check("0")).to.be.equal(false) + end) end) end diff --git a/src/ValidatorTypes.lua b/src/ValidatorTypes.lua index dd2cc54..fbe7be4 100644 --- a/src/ValidatorTypes.lua +++ b/src/ValidatorTypes.lua @@ -30,6 +30,7 @@ export type RootMethods = { IsNil: (self: RootMethods) -> PublicNilValidator, IsString: (self: RootMethods) -> PublicStringValidator, IsBoolean: (self: RootMethods) -> PublicBooleanValidator, + IsNan: (self: RootMethods) -> PublicNanValidator, } export type PublicRootValidator = PublicValidator & RootMethods export type PrivateRootValidator = PublicRootValidator & PrivateValidator @@ -72,4 +73,11 @@ export type PrivateBooleanValidator = PublicBooleanValidator & PrivateValidator --#endregion +--#region Boolean + +export type PublicNanValidator = PublicValidator & {} +export type PrivateNanValidator = PublicNanValidator & PrivateValidator + +--#endregion + return {} diff --git a/src/init.lua b/src/init.lua index e1ed2eb..ed8d87d 100644 --- a/src/init.lua +++ b/src/init.lua @@ -2,6 +2,7 @@ local BooleanValidator = require(script.Boolean) local CoreValidator = require(script.Core) +local NanValidator = require(script.Nan) local RootValidator = require(script.Root) local NilValidator = require(script.Nil) local NumberValidator = require(script.Number) @@ -16,5 +17,6 @@ Validator.IsInteger = NumberValidator.newIsInteger Validator.IsNil = NilValidator.new Validator.IsString = StringValidator.new Validator.IsBoolean = BooleanValidator.new +Validator.IsNan = NanValidator.new return Validator From b3f7cef073f924e8d38964719028a2ae61b865f8 Mon Sep 17 00:00:00 2001 From: bogotolec Date: Fri, 17 Oct 2025 02:26:18 +0300 Subject: [PATCH 10/17] Added Instance root --- src/Instance/InstanceChecks.lua | 13 ++++++++++ src/Instance/init.lua | 46 +++++++++++++++++++++++++++++++++ src/Root/init.lua | 3 +++ src/Validator.spec.luau | 13 ++++++++++ src/ValidatorTypes.lua | 10 +++++++ src/init.lua | 3 +++ 6 files changed, 88 insertions(+) create mode 100644 src/Instance/InstanceChecks.lua create mode 100644 src/Instance/init.lua diff --git a/src/Instance/InstanceChecks.lua b/src/Instance/InstanceChecks.lua new file mode 100644 index 0000000..9467fef --- /dev/null +++ b/src/Instance/InstanceChecks.lua @@ -0,0 +1,13 @@ +--!strict + +local InstanceChecks = {} + +function InstanceChecks.IsA(value: any, instanceClass: string): boolean + return typeof(value) == "Instance" and value:IsA(instanceClass) +end + +function InstanceChecks.IsClass(value: any, instanceClass: string): boolean + return typeof(value) == "Instance" and value.ClassName == instanceClass +end + +return InstanceChecks diff --git a/src/Instance/init.lua b/src/Instance/init.lua new file mode 100644 index 0000000..22626c5 --- /dev/null +++ b/src/Instance/init.lua @@ -0,0 +1,46 @@ +--!strict + +local InstanceChecks = require(script.InstanceChecks) +local CoreValidator = require(script.Parent.Core) +local Helpers = require(script.Parent.Helpers) +local ValidatorTypes = require(script.Parent.ValidatorTypes) + +local InstanceValidator = {} +setmetatable(InstanceValidator, CoreValidator) +InstanceValidator.__index = InstanceValidator + +function InstanceValidator.newIsAnInstance( + instanceClass: string +): ValidatorTypes.PublicInstanceValidator + local self = setmetatable(CoreValidator.new() :: any, InstanceValidator) + Helpers.AddCheck(self, InstanceChecks.IsA, instanceClass) + return self +end + +function InstanceValidator.newIsAnInstanceStrict( + instanceClass: string +): ValidatorTypes.PublicInstanceValidator + local self = setmetatable(CoreValidator.new() :: any, InstanceValidator) + Helpers.AddCheck(self, InstanceChecks.IsClass, instanceClass) + return self +end + +function InstanceValidator.IsAnInstance( + self: ValidatorTypes.PrivateValidator, + instanceClass: string +): ValidatorTypes.PrivateInstanceValidator + local new = setmetatable(self :: any, InstanceValidator) + Helpers.AddCheck(new, InstanceChecks.IsA, instanceClass) + return new +end + +function InstanceValidator.IsAnInstanceStrict( + self: ValidatorTypes.PrivateValidator, + instanceClass: string +): ValidatorTypes.PrivateInstanceValidator + local new = setmetatable(self :: any, InstanceValidator) + Helpers.AddCheck(new, InstanceChecks.IsClass, instanceClass) + return new +end + +return InstanceValidator diff --git a/src/Root/init.lua b/src/Root/init.lua index e9d946a..7c8b11f 100644 --- a/src/Root/init.lua +++ b/src/Root/init.lua @@ -1,6 +1,7 @@ --!strict local BooleanValidator = require(script.Parent.Boolean) +local InstanceValidator = require(script.Parent.Instance) local NanValidator = require(script.Parent.Nan) local NilValidator = require(script.Parent.Nil) local NumberValidator = require(script.Parent.Number) @@ -15,5 +16,7 @@ RootValidator.IsNil = NilValidator.IsNil RootValidator.IsString = StringValidator.IsString RootValidator.IsBoolean = BooleanValidator.IsBoolean RootValidator.IsNan = NanValidator.IsNan +RootValidator.IsAnInstance = InstanceValidator.IsAnInstance +RootValidator.IsAnInstanceStrict = InstanceValidator.IsAnInstanceStrict return RootValidator diff --git a/src/Validator.spec.luau b/src/Validator.spec.luau index 83895b1..6b6d8d7 100644 --- a/src/Validator.spec.luau +++ b/src/Validator.spec.luau @@ -90,5 +90,18 @@ return function() expect(validator:Check(0.5)).to.be.equal(true) expect(validator:Check("0")).to.be.equal(false) end) + + it("04. Test instances", function() + local part = Instance.new("Part") + part.Parent = workspace + + local validator = Validator.IsAnInstance("BasePart"):Freeze() + local validatorStrict = Validator.IsAnInstanceStrict("BasePart"):Freeze() + + expect(validator:Check(part)).to.be.equal(true) + expect(validatorStrict:Check(part)).to.be.equal(false) + + part:Destroy() + end) end) end diff --git a/src/ValidatorTypes.lua b/src/ValidatorTypes.lua index fbe7be4..b47322c 100644 --- a/src/ValidatorTypes.lua +++ b/src/ValidatorTypes.lua @@ -31,6 +31,8 @@ export type RootMethods = { IsString: (self: RootMethods) -> PublicStringValidator, IsBoolean: (self: RootMethods) -> PublicBooleanValidator, IsNan: (self: RootMethods) -> PublicNanValidator, + IsAnInstance: (self: RootMethods, instanceClass: string) -> PublicInstanceValidator, + IsAnInstanceStrict: (self: RootMethods, instanceClass: string) -> PublicInstanceValidator, } export type PublicRootValidator = PublicValidator & RootMethods export type PrivateRootValidator = PublicRootValidator & PrivateValidator @@ -80,4 +82,12 @@ export type PrivateNanValidator = PublicNanValidator & PrivateValidator --#endregion +--#region Instance + +export type InstanceValidatorMethods = {} +export type PublicInstanceValidator = PublicValidator & InstanceValidatorMethods & {} +export type PrivateInstanceValidator = PublicInstanceValidator & PrivateValidator + +--#endregion + return {} diff --git a/src/init.lua b/src/init.lua index ed8d87d..cff5e9c 100644 --- a/src/init.lua +++ b/src/init.lua @@ -2,6 +2,7 @@ local BooleanValidator = require(script.Boolean) local CoreValidator = require(script.Core) +local InstanceValidator = require(script.Instance) local NanValidator = require(script.Nan) local RootValidator = require(script.Root) local NilValidator = require(script.Nil) @@ -18,5 +19,7 @@ Validator.IsNil = NilValidator.new Validator.IsString = StringValidator.new Validator.IsBoolean = BooleanValidator.new Validator.IsNan = NanValidator.new +Validator.IsAnInstance = InstanceValidator.newIsAnInstance +Validator.IsAnInstanceStrict = InstanceValidator.newIsAnInstanceStrict return Validator From 1501512303f71d55b3295c2cc93a86e81099acf7 Mon Sep 17 00:00:00 2001 From: bogotolec Date: Fri, 17 Oct 2025 19:17:29 +0300 Subject: [PATCH 11/17] Added Table root --- src/Root/init.lua | 3 ++ src/Table/TableChecks.lua | 43 +++++++++++++++++++++ src/Table/init.lua | 46 +++++++++++++++++++++++ src/Validator.spec.luau | 78 +++++++++++++++++++++++++++++++++++++++ src/ValidatorTypes.lua | 10 +++++ src/init.lua | 3 ++ 6 files changed, 183 insertions(+) create mode 100644 src/Table/TableChecks.lua create mode 100644 src/Table/init.lua diff --git a/src/Root/init.lua b/src/Root/init.lua index 7c8b11f..7a39ac3 100644 --- a/src/Root/init.lua +++ b/src/Root/init.lua @@ -6,6 +6,7 @@ local NanValidator = require(script.Parent.Nan) local NilValidator = require(script.Parent.Nil) local NumberValidator = require(script.Parent.Number) local StringValidator = require(script.Parent.String) +local TableValidator = require(script.Parent.Table) local RootValidator = {} RootValidator.__index = RootValidator @@ -18,5 +19,7 @@ RootValidator.IsBoolean = BooleanValidator.IsBoolean RootValidator.IsNan = NanValidator.IsNan RootValidator.IsAnInstance = InstanceValidator.IsAnInstance RootValidator.IsAnInstanceStrict = InstanceValidator.IsAnInstanceStrict +RootValidator.IsTable = TableValidator.IsTable +RootValidator.IsTableStrict = TableValidator.IsTableStrict return RootValidator diff --git a/src/Table/TableChecks.lua b/src/Table/TableChecks.lua new file mode 100644 index 0000000..7b3de71 --- /dev/null +++ b/src/Table/TableChecks.lua @@ -0,0 +1,43 @@ +--!strict + +local ValidatorTypes = require(script.Parent.Parent.ValidatorTypes) + +local TableChecks = {} + +function TableChecks.IsTable(value: any, schema: { [any]: ValidatorTypes.Checker }?) + if typeof(value) ~= "table" then + return false + end + + if not schema then + return true + end + + for k, checker in pairs(schema) do + if not checker:Check(value[k]) then + return false + end + end + + return true +end + +function TableChecks.IsTableStrict(value: any, schema: { [any]: ValidatorTypes.Checker }?) + if not TableChecks.IsTable(value, schema) then + return false + end + + if not schema then + return true + end + + for k, _ in pairs(value) do + if not schema[k] then + return false + end + end + + return true +end + +return TableChecks diff --git a/src/Table/init.lua b/src/Table/init.lua new file mode 100644 index 0000000..4f63378 --- /dev/null +++ b/src/Table/init.lua @@ -0,0 +1,46 @@ +--!strict + +local TableChecks = require(script.TableChecks) +local CoreValidator = require(script.Parent.Core) +local Helpers = require(script.Parent.Helpers) +local ValidatorTypes = require(script.Parent.ValidatorTypes) + +local TableValidator = {} +setmetatable(TableValidator, CoreValidator) +TableValidator.__index = TableValidator + +function TableValidator.newIsTable( + schema: { [any]: ValidatorTypes.Checker }? +): ValidatorTypes.PublicTableValidator + local self = setmetatable(CoreValidator.new() :: any, TableValidator) + Helpers.AddCheck(self, TableChecks.IsTable, schema) + return self +end + +function TableValidator.newIsTableStrict( + schema: { [any]: ValidatorTypes.Checker }? +): ValidatorTypes.PublicTableValidator + local self = setmetatable(CoreValidator.new() :: any, TableValidator) + Helpers.AddCheck(self, TableChecks.IsTableStrict, schema) + return self +end + +function TableValidator.IsTable( + self: ValidatorTypes.PrivateValidator, + schema: { [any]: ValidatorTypes.Checker }? +): ValidatorTypes.PrivateTableValidator + local new = setmetatable(self :: any, TableValidator) + Helpers.AddCheck(new, TableChecks.IsTable, schema) + return new +end + +function TableValidator.IsTableStrict( + self: ValidatorTypes.PrivateValidator, + schema: { [any]: ValidatorTypes.Checker }? +): ValidatorTypes.PrivateTableValidator + local new = setmetatable(self :: any, TableValidator) + Helpers.AddCheck(new, TableChecks.IsTableStrict, schema) + return new +end + +return TableValidator diff --git a/src/Validator.spec.luau b/src/Validator.spec.luau index 6b6d8d7..af23398 100644 --- a/src/Validator.spec.luau +++ b/src/Validator.spec.luau @@ -103,5 +103,83 @@ return function() part:Destroy() end) + + it("05. Test tables", function() + local table1 = { + a = 10, + } + local table2 = { + a = 20, + } + local table3 = { + a = 10, + b = 20, + } + + local validator = Validator.IsTable():Freeze() + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check({})).to.be.equal(true) + expect(validator:Check(table1)).to.be.equal(true) + expect(validator:Check(table2)).to.be.equal(true) + expect(validator:Check(table3)).to.be.equal(true) + expect(validator:Check(0)).to.be.equal(false) + + validator = Validator.IsTable({ + a = Validator.IsInteger():IsGreater(15), + }):Freeze() + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check({})).to.be.equal(false) + expect(validator:Check(table1)).to.be.equal(false) + expect(validator:Check(table2)).to.be.equal(true) + expect(validator:Check(table3)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(false) + + validator = Validator.IsTable({ + a = Validator.IsInteger(), + }):Freeze() + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check({})).to.be.equal(false) + expect(validator:Check(table1)).to.be.equal(true) + expect(validator:Check(table2)).to.be.equal(true) + expect(validator:Check(table3)).to.be.equal(true) + expect(validator:Check(0)).to.be.equal(false) + + validator = Validator.IsTableStrict({ + a = Validator.IsInteger(), + }):Freeze() + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check({})).to.be.equal(false) + expect(validator:Check(table1)).to.be.equal(true) + expect(validator:Check(table2)).to.be.equal(true) + expect(validator:Check(table3)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(false) + + validator = Validator.IsNumber():Or():IsTable():Freeze() + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check({})).to.be.equal(true) + expect(validator:Check(table1)).to.be.equal(true) + expect(validator:Check(table2)).to.be.equal(true) + expect(validator:Check(table3)).to.be.equal(true) + expect(validator:Check(0)).to.be.equal(true) + + validator = Validator.IsNumber() + :Or() + :IsTableStrict({ + a = Validator.IsInteger(), + }) + :Freeze() + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check({})).to.be.equal(false) + expect(validator:Check(table1)).to.be.equal(true) + expect(validator:Check(table2)).to.be.equal(true) + expect(validator:Check(table3)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(true) + end) end) end diff --git a/src/ValidatorTypes.lua b/src/ValidatorTypes.lua index b47322c..03a3ff8 100644 --- a/src/ValidatorTypes.lua +++ b/src/ValidatorTypes.lua @@ -33,6 +33,8 @@ export type RootMethods = { IsNan: (self: RootMethods) -> PublicNanValidator, IsAnInstance: (self: RootMethods, instanceClass: string) -> PublicInstanceValidator, IsAnInstanceStrict: (self: RootMethods, instanceClass: string) -> PublicInstanceValidator, + IsTable: (self: RootMethods, schema: { [any]: Checker }?) -> PublicTableValidator, + IsTableStrict: (self: RootMethods, schema: { [any]: Checker }?) -> PublicTableValidator, } export type PublicRootValidator = PublicValidator & RootMethods export type PrivateRootValidator = PublicRootValidator & PrivateValidator @@ -90,4 +92,12 @@ export type PrivateInstanceValidator = PublicInstanceValidator & PrivateValidato --#endregion +--#region Table + +export type TableValidatorMethods = {} +export type PublicTableValidator = PublicValidator & TableValidatorMethods & {} +export type PrivateTableValidator = PublicTableValidator & PrivateValidator + +--#endregion + return {} diff --git a/src/init.lua b/src/init.lua index cff5e9c..2ccdd97 100644 --- a/src/init.lua +++ b/src/init.lua @@ -8,6 +8,7 @@ local RootValidator = require(script.Root) local NilValidator = require(script.Nil) local NumberValidator = require(script.Number) local StringValidator = require(script.String) +local TableValidator = require(script.Table) local Validator = {} @@ -21,5 +22,7 @@ Validator.IsBoolean = BooleanValidator.new Validator.IsNan = NanValidator.new Validator.IsAnInstance = InstanceValidator.newIsAnInstance Validator.IsAnInstanceStrict = InstanceValidator.newIsAnInstanceStrict +Validator.IsTable = TableValidator.newIsTable +Validator.IsTableStrict = TableValidator.newIsTableStrict return Validator From 0c688a7bc0bb5b8162c8e9a3b23a5d8259f2a5d1 Mon Sep 17 00:00:00 2001 From: bogotolec Date: Fri, 17 Oct 2025 19:39:27 +0300 Subject: [PATCH 12/17] Added Type root --- src/Root/init.lua | 2 ++ src/Type/TypeChecks.lua | 9 +++++++++ src/Type/init.lua | 27 +++++++++++++++++++++++++++ src/Validator.spec.luau | 18 ++++++++++++++++++ src/ValidatorTypes.lua | 9 +++++++++ src/init.lua | 2 ++ 6 files changed, 67 insertions(+) create mode 100644 src/Type/TypeChecks.lua create mode 100644 src/Type/init.lua diff --git a/src/Root/init.lua b/src/Root/init.lua index 7a39ac3..7ed566c 100644 --- a/src/Root/init.lua +++ b/src/Root/init.lua @@ -7,6 +7,7 @@ local NilValidator = require(script.Parent.Nil) local NumberValidator = require(script.Parent.Number) local StringValidator = require(script.Parent.String) local TableValidator = require(script.Parent.Table) +local TypeValidator = require(script.Parent.Type) local RootValidator = {} RootValidator.__index = RootValidator @@ -21,5 +22,6 @@ RootValidator.IsAnInstance = InstanceValidator.IsAnInstance RootValidator.IsAnInstanceStrict = InstanceValidator.IsAnInstanceStrict RootValidator.IsTable = TableValidator.IsTable RootValidator.IsTableStrict = TableValidator.IsTableStrict +RootValidator.IsTypeOf = TypeValidator.IsTypeOf return RootValidator diff --git a/src/Type/TypeChecks.lua b/src/Type/TypeChecks.lua new file mode 100644 index 0000000..0fcc560 --- /dev/null +++ b/src/Type/TypeChecks.lua @@ -0,0 +1,9 @@ +--!strict + +local TypeChecks = {} + +function TypeChecks.IsTypeOf(value: any, type: string): boolean + return typeof(value) == type +end + +return TypeChecks diff --git a/src/Type/init.lua b/src/Type/init.lua new file mode 100644 index 0000000..25b75ea --- /dev/null +++ b/src/Type/init.lua @@ -0,0 +1,27 @@ +--!strict + +local TypeChecks = require(script.TypeChecks) +local CoreValidator = require(script.Parent.Core) +local Helpers = require(script.Parent.Helpers) +local ValidatorTypes = require(script.Parent.ValidatorTypes) + +local TypeValidator = {} +setmetatable(TypeValidator, CoreValidator) +TypeValidator.__index = TypeValidator + +function TypeValidator.new(type: string): ValidatorTypes.PublicTypeValidator + local self = setmetatable(CoreValidator.new() :: any, TypeValidator) + Helpers.AddCheck(self, TypeChecks.IsTypeOf, type) + return self +end + +function TypeValidator.IsTypeOf( + self: ValidatorTypes.PrivateValidator, + type: string +): ValidatorTypes.PublicTypeValidator + local new = setmetatable(self :: any, TypeValidator) + Helpers.AddCheck(new, TypeChecks.IsTypeOf, type) + return new +end + +return TypeValidator diff --git a/src/Validator.spec.luau b/src/Validator.spec.luau index af23398..20dc530 100644 --- a/src/Validator.spec.luau +++ b/src/Validator.spec.luau @@ -181,5 +181,23 @@ return function() expect(validator:Check(table3)).to.be.equal(false) expect(validator:Check(0)).to.be.equal(true) end) + + it("06. Test types", function() + local validator = Validator.IsTypeOf("Vector3"):Freeze() + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(Vector3.new(10, 20, 30))).to.be.equal(true) + expect(validator:Check(Vector3.zero)).to.be.equal(true) + expect(validator:Check(UDim2.new())).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(false) + + validator = Validator.IsNumber():Or():IsTypeOf("Vector3"):Freeze() + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(Vector3.new(10, 20, 30))).to.be.equal(true) + expect(validator:Check(Vector3.zero)).to.be.equal(true) + expect(validator:Check(UDim2.new())).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(true) + end) end) end diff --git a/src/ValidatorTypes.lua b/src/ValidatorTypes.lua index 03a3ff8..ffae1d7 100644 --- a/src/ValidatorTypes.lua +++ b/src/ValidatorTypes.lua @@ -35,6 +35,7 @@ export type RootMethods = { IsAnInstanceStrict: (self: RootMethods, instanceClass: string) -> PublicInstanceValidator, IsTable: (self: RootMethods, schema: { [any]: Checker }?) -> PublicTableValidator, IsTableStrict: (self: RootMethods, schema: { [any]: Checker }?) -> PublicTableValidator, + IsTypeOf: (self: RootMethods, type: string) -> PublicTypeValidator, } export type PublicRootValidator = PublicValidator & RootMethods export type PrivateRootValidator = PublicRootValidator & PrivateValidator @@ -100,4 +101,12 @@ export type PrivateTableValidator = PublicTableValidator & PrivateValidator --#endregion +--#region Type + +export type TypeValidatorMethods = {} +export type PublicTypeValidator = PublicValidator & TypeValidatorMethods & {} +export type PrivateTypeValidator = PublicTypeValidator & PrivateValidator + +--#endregion + return {} diff --git a/src/init.lua b/src/init.lua index 2ccdd97..47f8626 100644 --- a/src/init.lua +++ b/src/init.lua @@ -9,6 +9,7 @@ local NilValidator = require(script.Nil) local NumberValidator = require(script.Number) local StringValidator = require(script.String) local TableValidator = require(script.Table) +local TypeValidator = require(script.Type) local Validator = {} @@ -24,5 +25,6 @@ Validator.IsAnInstance = InstanceValidator.newIsAnInstance Validator.IsAnInstanceStrict = InstanceValidator.newIsAnInstanceStrict Validator.IsTable = TableValidator.newIsTable Validator.IsTableStrict = TableValidator.newIsTableStrict +Validator.IsTypeOf = TypeValidator.new return Validator From b26e59e47df457c371a7e0965425cb20aac94f5e Mon Sep 17 00:00:00 2001 From: bogotolec Date: Fri, 17 Oct 2025 20:00:13 +0300 Subject: [PATCH 13/17] Added Enum root --- src/Enum/EnumChecks.lua | 17 +++++++++++++++++ src/Enum/init.lua | 27 +++++++++++++++++++++++++++ src/Root/init.lua | 2 ++ src/Validator.spec.luau | 30 ++++++++++++++++++++++++++++++ src/ValidatorTypes.lua | 9 +++++++++ src/init.lua | 2 ++ 6 files changed, 87 insertions(+) create mode 100644 src/Enum/EnumChecks.lua create mode 100644 src/Enum/init.lua diff --git a/src/Enum/EnumChecks.lua b/src/Enum/EnumChecks.lua new file mode 100644 index 0000000..82c8033 --- /dev/null +++ b/src/Enum/EnumChecks.lua @@ -0,0 +1,17 @@ +--!strict + +local EnumChecks = {} + +function EnumChecks.IsEnumItem(value: any, enum: Enum?) + if typeof(value) ~= "EnumItem" then + return false + end + + if not enum or table.find(enum:GetEnumItems(), value) then + return true + end + + return false +end + +return EnumChecks diff --git a/src/Enum/init.lua b/src/Enum/init.lua new file mode 100644 index 0000000..cd55590 --- /dev/null +++ b/src/Enum/init.lua @@ -0,0 +1,27 @@ +--!strict + +local EnumChecks = require(script.EnumChecks) +local CoreValidator = require(script.Parent.Core) +local Helpers = require(script.Parent.Helpers) +local ValidatorTypes = require(script.Parent.ValidatorTypes) + +local EnumValidator = {} +setmetatable(EnumValidator, CoreValidator) +EnumValidator.__index = EnumValidator + +function EnumValidator.new(enum: Enum?): ValidatorTypes.PublicEnumValidator + local self = setmetatable(CoreValidator.new() :: any, EnumValidator) + Helpers.AddCheck(self, EnumChecks.IsEnumItem, enum) + return self +end + +function EnumValidator.IsEnumItem( + self: ValidatorTypes.PrivateValidator, + enum: Enum? +): ValidatorTypes.PrivateEnumValidator + local new = setmetatable(self :: any, EnumValidator) + Helpers.AddCheck(new, EnumChecks.IsEnumItem, enum) + return new +end + +return EnumValidator diff --git a/src/Root/init.lua b/src/Root/init.lua index 7ed566c..1590e0c 100644 --- a/src/Root/init.lua +++ b/src/Root/init.lua @@ -1,6 +1,7 @@ --!strict local BooleanValidator = require(script.Parent.Boolean) +local EnumValidator = require(script.Parent.Enum) local InstanceValidator = require(script.Parent.Instance) local NanValidator = require(script.Parent.Nan) local NilValidator = require(script.Parent.Nil) @@ -23,5 +24,6 @@ RootValidator.IsAnInstanceStrict = InstanceValidator.IsAnInstanceStrict RootValidator.IsTable = TableValidator.IsTable RootValidator.IsTableStrict = TableValidator.IsTableStrict RootValidator.IsTypeOf = TypeValidator.IsTypeOf +RootValidator.IsEnumItem = EnumValidator.IsEnumItem return RootValidator diff --git a/src/Validator.spec.luau b/src/Validator.spec.luau index 20dc530..82e51a5 100644 --- a/src/Validator.spec.luau +++ b/src/Validator.spec.luau @@ -199,5 +199,35 @@ return function() expect(validator:Check(UDim2.new())).to.be.equal(false) expect(validator:Check(0)).to.be.equal(true) end) + + it("07. Test enums", function() + local validator = Validator.IsEnumItem():Freeze() + + expect(validator:Check(1)).to.be.equal(false) + expect(validator:Check("1")).to.be.equal(false) + expect(validator:Check(Enum.KeyCode.A)).to.be.equal(true) + expect(validator:Check(Enum.PartType.Ball)).to.be.equal(true) + + validator = Validator.IsEnumItem(Enum.KeyCode):Freeze() + + expect(validator:Check(1)).to.be.equal(false) + expect(validator:Check("1")).to.be.equal(false) + expect(validator:Check(Enum.KeyCode.A)).to.be.equal(true) + expect(validator:Check(Enum.PartType.Ball)).to.be.equal(false) + + validator = Validator.IsNumber():Or():IsEnumItem():Freeze() + + expect(validator:Check(1)).to.be.equal(true) + expect(validator:Check("1")).to.be.equal(false) + expect(validator:Check(Enum.KeyCode.A)).to.be.equal(true) + expect(validator:Check(Enum.PartType.Ball)).to.be.equal(true) + + validator = Validator.IsNumber():Or():IsEnumItem(Enum.KeyCode):Freeze() + + expect(validator:Check(1)).to.be.equal(true) + expect(validator:Check("1")).to.be.equal(false) + expect(validator:Check(Enum.KeyCode.A)).to.be.equal(true) + expect(validator:Check(Enum.PartType.Ball)).to.be.equal(false) + end) end) end diff --git a/src/ValidatorTypes.lua b/src/ValidatorTypes.lua index ffae1d7..a07c159 100644 --- a/src/ValidatorTypes.lua +++ b/src/ValidatorTypes.lua @@ -36,6 +36,7 @@ export type RootMethods = { IsTable: (self: RootMethods, schema: { [any]: Checker }?) -> PublicTableValidator, IsTableStrict: (self: RootMethods, schema: { [any]: Checker }?) -> PublicTableValidator, IsTypeOf: (self: RootMethods, type: string) -> PublicTypeValidator, + IsEnumItem: (self: RootMethods, enum: Enum?) -> PublicEnumValidator, } export type PublicRootValidator = PublicValidator & RootMethods export type PrivateRootValidator = PublicRootValidator & PrivateValidator @@ -109,4 +110,12 @@ export type PrivateTypeValidator = PublicTypeValidator & PrivateValidator --#endregion +--#region Enum + +export type EnumValidatorMethods = {} +export type PublicEnumValidator = PublicValidator & EnumValidatorMethods & {} +export type PrivateEnumValidator = PublicEnumValidator & PrivateValidator + +--#endregion + return {} diff --git a/src/init.lua b/src/init.lua index 47f8626..c82e036 100644 --- a/src/init.lua +++ b/src/init.lua @@ -2,6 +2,7 @@ local BooleanValidator = require(script.Boolean) local CoreValidator = require(script.Core) +local EnumValidator = require(script.Enum) local InstanceValidator = require(script.Instance) local NanValidator = require(script.Nan) local RootValidator = require(script.Root) @@ -26,5 +27,6 @@ Validator.IsAnInstanceStrict = InstanceValidator.newIsAnInstanceStrict Validator.IsTable = TableValidator.newIsTable Validator.IsTableStrict = TableValidator.newIsTableStrict Validator.IsTypeOf = TypeValidator.new +Validator.IsEnumItem = EnumValidator.new return Validator From e11a20442d23ef901af1a8779f6b5e4f499f9951 Mon Sep 17 00:00:00 2001 From: bogotolec Date: Fri, 17 Oct 2025 20:32:14 +0300 Subject: [PATCH 14/17] Added core methods :IsEqual(), :IsKeyOf() and IsInTable() + some typization fixes --- src/Core/CoreChecks.lua | 23 ++++++++++++++++ src/Core/init.lua | 26 ++++++++++++++++++ src/String/init.lua | 9 +++--- src/Validator.spec.luau | 38 +++++++++++++++++++++++++ src/ValidatorTypes.lua | 61 +++++++++++++++++++++++++++++++++-------- 5 files changed, 141 insertions(+), 16 deletions(-) create mode 100644 src/Core/CoreChecks.lua diff --git a/src/Core/CoreChecks.lua b/src/Core/CoreChecks.lua new file mode 100644 index 0000000..aaa06be --- /dev/null +++ b/src/Core/CoreChecks.lua @@ -0,0 +1,23 @@ +--!strict + +local CoreChecks = {} + +function CoreChecks.IsInTable(value: any, t: { [any]: any }): boolean + for _, v in pairs(t) do + if v == value then + return true + end + end + + return false +end + +function CoreChecks.IsKeyOf(value: any, t: { [any]: any }): boolean + return if t[value] ~= nil then true else false +end + +function CoreChecks.IsEqual(value: any, otherValue: any): boolean + return value == otherValue +end + +return CoreChecks diff --git a/src/Core/init.lua b/src/Core/init.lua index a4d0cf3..f68d02c 100644 --- a/src/Core/init.lua +++ b/src/Core/init.lua @@ -1,5 +1,7 @@ --!strict +local CoreChecks = require(script.CoreChecks) +local Helpers = require(script.Parent.Helpers) local ValidatorTypes = require(script.Parent.ValidatorTypes) local CoreValidator = {} @@ -78,6 +80,30 @@ function CoreValidator.Not(self: ValidatorTypes.PrivateValidator): ValidatorType return self end +function CoreValidator.IsInTable( + self: ValidatorTypes.PrivateValidator, + t: { [any]: any } +): ValidatorTypes.PrivateValidator + Helpers.AddCheck(self, CoreChecks.IsInTable, t) + return self +end + +function CoreValidator.IsKeyOf( + self: ValidatorTypes.PrivateValidator, + t: { [any]: any } +): ValidatorTypes.PrivateValidator + Helpers.AddCheck(self, CoreChecks.IsKeyOf, t) + return self +end + +function CoreValidator.IsEqual( + self: ValidatorTypes.PrivateValidator, + otherValue: any +): ValidatorTypes.PrivateValidator + Helpers.AddCheck(self, CoreChecks.IsEqual, otherValue) + return self +end + function CoreValidator._Setup(rootValidator: ValidatorTypes.PrivateRootValidator) rootValidatorClass = rootValidator end diff --git a/src/String/init.lua b/src/String/init.lua index 6606898..3f9084f 100644 --- a/src/String/init.lua +++ b/src/String/init.lua @@ -5,20 +5,19 @@ local CoreValidator = require(script.Parent.Core) local Helpers = require(script.Parent.Helpers) local ValidatorTypes = require(script.Parent.ValidatorTypes) -export type PrivateValidator = ValidatorTypes.PrivateValidator -export type PrivateNumberValidator = ValidatorTypes.PrivateNumberValidator - local StringValidator = {} setmetatable(StringValidator, CoreValidator) StringValidator.__index = StringValidator -function StringValidator.new(): ValidatorTypes.PublicNumberValidator +function StringValidator.new(): ValidatorTypes.PublicStringValidator local self = setmetatable(CoreValidator.new() :: any, StringValidator) Helpers.AddCheck(self, StringChecks.IsString) return self end -function StringValidator.IsString(self: PrivateValidator): PrivateNumberValidator +function StringValidator.IsString( + self: ValidatorTypes.PrivateValidator +): ValidatorTypes.PrivateStringValidator local new = setmetatable(self :: any, StringValidator) Helpers.AddCheck(new, StringChecks.IsString) return new diff --git a/src/Validator.spec.luau b/src/Validator.spec.luau index 82e51a5..80170f5 100644 --- a/src/Validator.spec.luau +++ b/src/Validator.spec.luau @@ -229,5 +229,43 @@ return function() expect(validator:Check(Enum.KeyCode.A)).to.be.equal(true) expect(validator:Check(Enum.PartType.Ball)).to.be.equal(false) end) + + it("08. Test core methods.", function() + local validator = Validator.IsString():Not():IsEqual("aaa"):Freeze() + + expect(validator:Check(1)).to.be.equal(false) + expect(validator:Check("1")).to.be.equal(true) + expect(validator:Check("aaa")).to.be.equal(false) + expect(validator:Check(nil)).to.be.equal(false) + + local values = { + "aaa", + "bbb", + "ccc", + } + + validator = Validator.IsString():IsInTable(values):Freeze() + + expect(validator:Check(1)).to.be.equal(false) + expect(validator:Check("1")).to.be.equal(false) + expect(validator:Check("aaa")).to.be.equal(true) + expect(validator:Check(nil)).to.be.equal(false) + + validator = Validator.IsString():Not():IsInTable(values):Freeze() + + expect(validator:Check(1)).to.be.equal(false) + expect(validator:Check("1")).to.be.equal(true) + expect(validator:Check("aaa")).to.be.equal(false) + expect(validator:Check(nil)).to.be.equal(false) + + validator = Validator.IsInteger():IsKeyOf(values):Freeze() + + expect(validator:Check(1)).to.be.equal(true) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check(4)).to.be.equal(false) + expect(validator:Check("1")).to.be.equal(false) + expect(validator:Check("aaa")).to.be.equal(false) + expect(validator:Check(nil)).to.be.equal(false) + end) end) end diff --git a/src/ValidatorTypes.lua b/src/ValidatorTypes.lua index a07c159..e0a42de 100644 --- a/src/ValidatorTypes.lua +++ b/src/ValidatorTypes.lua @@ -47,6 +47,10 @@ export type PrivateRootValidator = PublicRootValidator & PrivateValidator export type NumberValidatorMethods = { IsGreater: (self: NumberValidatorMethods, than: number) -> PublicNumberValidator, + + IsInTable: (self: NumberValidatorMethods, table: { [any]: any }) -> PublicNumberValidator, + IsKeyOf: (self: NumberValidatorMethods, table: { [any]: any }) -> PublicNumberValidator, + IsEqual: (self: NumberValidatorMethods, otherValue: any) -> PublicNumberValidator, } export type PublicNumberValidator = PublicValidator & NumberValidatorMethods & { Not: (self: PublicValidator) -> NumberValidatorMethods, @@ -64,7 +68,11 @@ export type PrivateNilValidator = PublicNilValidator & PrivateValidator --#region String -export type StringValidatorMethods = {} +export type StringValidatorMethods = { + IsInTable: (self: StringValidatorMethods, table: { [any]: any }) -> PublicStringValidator, + IsKeyOf: (self: StringValidatorMethods, table: { [any]: any }) -> PublicStringValidator, + IsEqual: (self: StringValidatorMethods, otherValue: any) -> PublicStringValidator, +} export type PublicStringValidator = PublicValidator & StringValidatorMethods & { Not: (self: PublicValidator) -> StringValidatorMethods, } @@ -74,12 +82,19 @@ export type PrivateStringValidator = PublicStringValidator & PrivateValidator --#region Boolean -export type PublicBooleanValidator = PublicValidator & {} +export type BooleanValidatorMethods = { + IsInTable: (self: BooleanValidatorMethods, table: { [any]: any }) -> PublicBooleanValidator, + IsKeyOf: (self: BooleanValidatorMethods, table: { [any]: any }) -> PublicBooleanValidator, + IsEqual: (self: BooleanValidatorMethods, otherValue: any) -> PublicBooleanValidator, +} +export type PublicBooleanValidator = PublicValidator & { + Not: (self: PublicValidator) -> BooleanValidatorMethods, +} export type PrivateBooleanValidator = PublicBooleanValidator & PrivateValidator --#endregion ---#region Boolean +--#region Nan export type PublicNanValidator = PublicValidator & {} export type PrivateNanValidator = PublicNanValidator & PrivateValidator @@ -88,32 +103,56 @@ export type PrivateNanValidator = PublicNanValidator & PrivateValidator --#region Instance -export type InstanceValidatorMethods = {} -export type PublicInstanceValidator = PublicValidator & InstanceValidatorMethods & {} +export type InstanceValidatorMethods = { + IsInTable: (self: InstanceValidatorMethods, table: { [any]: any }) -> PublicInstanceValidator, + IsKeyOf: (self: InstanceValidatorMethods, table: { [any]: any }) -> PublicInstanceValidator, + IsEqual: (self: InstanceValidatorMethods, otherValue: any) -> PublicInstanceValidator, +} +export type PublicInstanceValidator = PublicValidator & InstanceValidatorMethods & { + Not: (self: PublicValidator) -> InstanceValidatorMethods, +} export type PrivateInstanceValidator = PublicInstanceValidator & PrivateValidator --#endregion --#region Table -export type TableValidatorMethods = {} -export type PublicTableValidator = PublicValidator & TableValidatorMethods & {} +export type TableValidatorMethods = { + IsInTable: (self: TableValidatorMethods, table: { [any]: any }) -> PublicTableValidator, + IsKeyOf: (self: TableValidatorMethods, table: { [any]: any }) -> PublicTableValidator, + IsEqual: (self: TableValidatorMethods, otherValue: any) -> PublicTableValidator, +} +export type PublicTableValidator = PublicValidator & TableValidatorMethods & { + Not: (self: PublicValidator) -> TableValidatorMethods, +} export type PrivateTableValidator = PublicTableValidator & PrivateValidator --#endregion --#region Type -export type TypeValidatorMethods = {} -export type PublicTypeValidator = PublicValidator & TypeValidatorMethods & {} +export type TypeValidatorMethods = { + IsInTable: (self: TypeValidatorMethods, table: { [any]: any }) -> PublicTypeValidator, + IsKeyOf: (self: TypeValidatorMethods, table: { [any]: any }) -> PublicTypeValidator, + IsEqual: (self: TypeValidatorMethods, otherValue: any) -> PublicTypeValidator, +} +export type PublicTypeValidator = PublicValidator & TypeValidatorMethods & { + Not: (self: PublicValidator) -> TypeValidatorMethods, +} export type PrivateTypeValidator = PublicTypeValidator & PrivateValidator --#endregion --#region Enum -export type EnumValidatorMethods = {} -export type PublicEnumValidator = PublicValidator & EnumValidatorMethods & {} +export type EnumValidatorMethods = { + IsInTable: (self: EnumValidatorMethods, table: { [any]: any }) -> PublicEnumValidator, + IsKeyOf: (self: EnumValidatorMethods, table: { [any]: any }) -> PublicEnumValidator, + IsEqual: (self: EnumValidatorMethods, otherValue: any) -> PublicEnumValidator, +} +export type PublicEnumValidator = PublicValidator & EnumValidatorMethods & { + Not: (self: PublicValidator) -> EnumValidatorMethods, +} export type PrivateEnumValidator = PublicEnumValidator & PrivateValidator --#endregion From 0bcd162391e4c7e6943307549a090b53c2f17f21 Mon Sep 17 00:00:00 2001 From: bogotolec Date: Fri, 17 Oct 2025 20:52:16 +0300 Subject: [PATCH 15/17] Added 5 new methods to string - IsUTF8 - MaxLen - MinLen - MaxUTF8Len - MinUTF8Len --- src/String/StringChecks.lua | 22 +++++++++++++++++++++ src/String/init.lua | 39 +++++++++++++++++++++++++++++++++++++ src/Validator.spec.luau | 29 +++++++++++++++++++++++++++ src/ValidatorTypes.lua | 6 ++++++ 4 files changed, 96 insertions(+) diff --git a/src/String/StringChecks.lua b/src/String/StringChecks.lua index b8038f1..c69860d 100644 --- a/src/String/StringChecks.lua +++ b/src/String/StringChecks.lua @@ -6,4 +6,26 @@ function StringChecks.IsString(value: any): boolean return type(value) == "string" end +function StringChecks.IsUTF8(value: string): boolean + return if utf8.len(value) then true else false +end + +function StringChecks.MaxLen(value: any, len: number): boolean + return string.len(value) <= len +end + +function StringChecks.MinLen(value: any, len: number): boolean + return string.len(value) >= len +end + +function StringChecks.MaxUTF8Len(value: any, len: number): boolean + local result = utf8.len(value) + return if result then result <= len else false +end + +function StringChecks.MinUTF8Len(value: any, len: number): boolean + local result = utf8.len(value) + return if result then result >= len else false +end + return StringChecks diff --git a/src/String/init.lua b/src/String/init.lua index 3f9084f..86f16b1 100644 --- a/src/String/init.lua +++ b/src/String/init.lua @@ -23,4 +23,43 @@ function StringValidator.IsString( return new end +function StringValidator.IsUTF8( + self: ValidatorTypes.PrivateStringValidator +): ValidatorTypes.PrivateStringValidator + Helpers.AddCheck(self, StringChecks.IsUTF8) + return self +end + +function StringValidator.MaxLen( + self: ValidatorTypes.PrivateStringValidator, + len: number +): ValidatorTypes.PrivateStringValidator + Helpers.AddCheck(self, StringChecks.MaxLen, len) + return self +end + +function StringValidator.MinLen( + self: ValidatorTypes.PrivateStringValidator, + len: number +): ValidatorTypes.PrivateStringValidator + Helpers.AddCheck(self, StringChecks.MinLen, len) + return self +end + +function StringValidator.MaxUTF8Len( + self: ValidatorTypes.PrivateStringValidator, + len: number +): ValidatorTypes.PrivateStringValidator + Helpers.AddCheck(self, StringChecks.MaxUTF8Len, len) + return self +end + +function StringValidator.MinUTF8Len( + self: ValidatorTypes.PrivateStringValidator, + len: number +): ValidatorTypes.PrivateStringValidator + Helpers.AddCheck(self, StringChecks.MinUTF8Len, len) + return self +end + return StringValidator diff --git a/src/Validator.spec.luau b/src/Validator.spec.luau index 80170f5..0712446 100644 --- a/src/Validator.spec.luau +++ b/src/Validator.spec.luau @@ -36,12 +36,41 @@ return function() expect(validator:Check(0)).to.be.equal(false) expect(validator:Check("0")).to.be.equal(true) expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(string.pack("BBBB", 0xFF, 0xFE, 0x00, 0x80))).to.be.equal(true) validator = Validator.IsNumber():Or():IsString():Freeze() expect(validator:Check(0)).to.be.equal(true) expect(validator:Check("0")).to.be.equal(true) expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(string.pack("BBBB", 0xFF, 0xFE, 0x00, 0x80))).to.be.equal(true) + + validator = Validator.IsString():IsUTF8():Freeze() + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check("abcde")).to.be.equal(true) + expect(validator:Check(string.pack("BBBB", 0xFF, 0xFE, 0x00, 0x80))).to.be.equal(false) + + validator = Validator.IsString():MinLen(5):MaxLen(10):Freeze() + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check("abcd")).to.be.equal(false) + expect(validator:Check("abcde")).to.be.equal(true) + expect(validator:Check("abcdeabcde")).to.be.equal(true) + expect(validator:Check("abcdeabcdef")).to.be.equal(false) + expect(validator:Check("абвгдеёжзи")).to.be.equal(false) + + validator = Validator.IsString():MinUTF8Len(5):MaxUTF8Len(10):Freeze() + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check("abcd")).to.be.equal(false) + expect(validator:Check("abcde")).to.be.equal(true) + expect(validator:Check("abcdeabcde")).to.be.equal(true) + expect(validator:Check("abcdeabcdef")).to.be.equal(false) + expect(validator:Check("абвгдеёжзи")).to.be.equal(true) end) it("02. Test booleans", function() diff --git a/src/ValidatorTypes.lua b/src/ValidatorTypes.lua index e0a42de..99a370f 100644 --- a/src/ValidatorTypes.lua +++ b/src/ValidatorTypes.lua @@ -69,6 +69,12 @@ export type PrivateNilValidator = PublicNilValidator & PrivateValidator --#region String export type StringValidatorMethods = { + IsUTF8: (self: StringValidatorMethods) -> PublicStringValidator, + MaxLen: (self: StringValidatorMethods, len: number) -> PublicStringValidator, + MinLen: (self: StringValidatorMethods, len: number) -> PublicStringValidator, + MaxUTF8Len: (self: StringValidatorMethods, len: number) -> PublicStringValidator, + MinUTF8Len: (self: StringValidatorMethods, len: number) -> PublicStringValidator, + IsInTable: (self: StringValidatorMethods, table: { [any]: any }) -> PublicStringValidator, IsKeyOf: (self: StringValidatorMethods, table: { [any]: any }) -> PublicStringValidator, IsEqual: (self: StringValidatorMethods, otherValue: any) -> PublicStringValidator, From 883e1cab2f5e989b26a9e55b66700169784221cb Mon Sep 17 00:00:00 2001 From: bogotolec Date: Fri, 17 Oct 2025 21:21:34 +0300 Subject: [PATCH 16/17] Refactor tests to be more modular --- src/Validator.spec.luau | 308 +++++++++++++++++++++++++++------------- 1 file changed, 207 insertions(+), 101 deletions(-) diff --git a/src/Validator.spec.luau b/src/Validator.spec.luau index 0712446..1ab18bb 100644 --- a/src/Validator.spec.luau +++ b/src/Validator.spec.luau @@ -3,8 +3,15 @@ local Validator = require(script.Parent) return function() - describe("Validator", function() - it("00. Check if it works", function() + describe("00. Core", function() + it("00. Creates, freezes and checks", function() + local validator = Validator.IsNumber():Freeze() + + expect(validator:Check(0)).to.be.equal(true) + expect(validator:Check(nil)).to.be.equal(false) + end) + + it("01. Combines complex expressions", function() local validator = Validator.IsInteger():IsGreater(5):Not():IsGreater(14):Or():IsNil():Freeze() @@ -14,6 +21,11 @@ return function() expect(validator:Check(15)).to.be.equal(false) expect(validator:Check(nil)).to.be.equal(true) expect(validator:Check("10")).to.be.equal(false) + end) + + it("02. Asserts", function() + local validator = + Validator.IsInteger():IsGreater(5):Not():IsGreater(14):Or():IsNil():Freeze() local success, value = pcall(function() return validator:Assert(0, "Error") @@ -30,29 +42,85 @@ return function() expect(value).to.be.equal(10) end) - it("01. Test strings", function() + it("03. Methods: IsEqual", function() + local validator = Validator.IsString():Not():IsEqual("aaa"):Freeze() + + expect(validator:Check(1)).to.be.equal(false) + expect(validator:Check("1")).to.be.equal(true) + expect(validator:Check("aaa")).to.be.equal(false) + expect(validator:Check(nil)).to.be.equal(false) + end) + + it("04. Methods: IsInTable", function() + local values = { + "aaa", + "bbb", + "ccc", + } + + local validator = Validator.IsString():IsInTable(values):Freeze() + + expect(validator:Check(1)).to.be.equal(false) + expect(validator:Check("1")).to.be.equal(false) + expect(validator:Check("aaa")).to.be.equal(true) + expect(validator:Check(nil)).to.be.equal(false) + + validator = Validator.IsString():Not():IsInTable(values):Freeze() + + expect(validator:Check(1)).to.be.equal(false) + expect(validator:Check("1")).to.be.equal(true) + expect(validator:Check("aaa")).to.be.equal(false) + expect(validator:Check(nil)).to.be.equal(false) + end) + + it("05. Methods: IsKeyOf", function() + local values = { + "aaa", + "bbb", + "ccc", + } + + local validator = Validator.IsInteger():IsKeyOf(values):Freeze() + + expect(validator:Check(1)).to.be.equal(true) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check(4)).to.be.equal(false) + expect(validator:Check("1")).to.be.equal(false) + expect(validator:Check("aaa")).to.be.equal(false) + expect(validator:Check(nil)).to.be.equal(false) + end) + end) + + describe("01. Strings", function() + it("00. Creates", function() local validator = Validator.IsString():Freeze() expect(validator:Check(0)).to.be.equal(false) expect(validator:Check("0")).to.be.equal(true) expect(validator:Check(nil)).to.be.equal(false) expect(validator:Check(string.pack("BBBB", 0xFF, 0xFE, 0x00, 0x80))).to.be.equal(true) + end) - validator = Validator.IsNumber():Or():IsString():Freeze() + it("01. Combines", function() + local validator = Validator.IsNumber():Or():IsString():Freeze() expect(validator:Check(0)).to.be.equal(true) expect(validator:Check("0")).to.be.equal(true) expect(validator:Check(nil)).to.be.equal(false) expect(validator:Check(string.pack("BBBB", 0xFF, 0xFE, 0x00, 0x80))).to.be.equal(true) + end) - validator = Validator.IsString():IsUTF8():Freeze() + it("02. Methods: IsUTF8", function() + local validator = Validator.IsString():IsUTF8():Freeze() expect(validator:Check(nil)).to.be.equal(false) expect(validator:Check(0)).to.be.equal(false) expect(validator:Check("abcde")).to.be.equal(true) expect(validator:Check(string.pack("BBBB", 0xFF, 0xFE, 0x00, 0x80))).to.be.equal(false) + end) - validator = Validator.IsString():MinLen(5):MaxLen(10):Freeze() + it("03. Methods: MinLen and MaxLen", function() + local validator = Validator.IsString():MinLen(5):MaxLen(10):Freeze() expect(validator:Check(nil)).to.be.equal(false) expect(validator:Check(0)).to.be.equal(false) @@ -61,8 +129,10 @@ return function() expect(validator:Check("abcdeabcde")).to.be.equal(true) expect(validator:Check("abcdeabcdef")).to.be.equal(false) expect(validator:Check("абвгдеёжзи")).to.be.equal(false) + end) - validator = Validator.IsString():MinUTF8Len(5):MaxUTF8Len(10):Freeze() + it("04. Methods: MinUTF8Len and MaxUTF8Len", function() + local validator = Validator.IsString():MinUTF8Len(5):MaxUTF8Len(10):Freeze() expect(validator:Check(nil)).to.be.equal(false) expect(validator:Check(0)).to.be.equal(false) @@ -72,79 +142,140 @@ return function() expect(validator:Check("abcdeabcdef")).to.be.equal(false) expect(validator:Check("абвгдеёжзи")).to.be.equal(true) end) + end) - it("02. Test booleans", function() + describe("02. Booleans", function() + it("00. Creates", function() local validator = Validator.IsBoolean():Freeze() expect(validator:Check(true)).to.be.equal(true) expect(validator:Check(false)).to.be.equal(true) expect(validator:Check(0)).to.be.equal(false) expect(validator:Check(nil)).to.be.equal(false) + end) - validator = Validator.IsNumber():Or():IsBoolean():Freeze() + it("01. Combines", function() + local validator = Validator.IsNumber():Or():IsBoolean():Freeze() expect(validator:Check(true)).to.be.equal(true) expect(validator:Check(false)).to.be.equal(true) expect(validator:Check(0)).to.be.equal(true) expect(validator:Check(nil)).to.be.equal(false) end) + end) - it("03. Test numbers and nans", function() - local nan = 0 / 0 - local validator = Validator.IsNan():Freeze() + describe("03. Numbers and NaNs", function() + local nan = 0 / 0 + it("00. Creates and combines IsNumber", function() + local validator = Validator.IsNumber():Freeze() - expect(validator:Check(nan)).to.be.equal(true) - expect(validator:Check(0)).to.be.equal(false) - expect(validator:Check(0.5)).to.be.equal(false) + expect(validator:Check(nan)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(true) + expect(validator:Check(0.5)).to.be.equal(true) expect(validator:Check("0")).to.be.equal(false) - validator = Validator.IsNumber():Freeze() + validator = Validator.IsString():Or():IsNumber():Freeze() expect(validator:Check(nan)).to.be.equal(false) expect(validator:Check(0)).to.be.equal(true) expect(validator:Check(0.5)).to.be.equal(true) + expect(validator:Check("0")).to.be.equal(true) + end) + + it("01. Creates and combines IsInteger", function() + local validator = Validator.IsInteger():Freeze() + + expect(validator:Check(nan)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(true) + expect(validator:Check(0.5)).to.be.equal(false) expect(validator:Check("0")).to.be.equal(false) - validator = Validator.IsInteger():Freeze() + validator = Validator.IsString():Or():IsInteger():Freeze() expect(validator:Check(nan)).to.be.equal(false) expect(validator:Check(0)).to.be.equal(true) expect(validator:Check(0.5)).to.be.equal(false) + expect(validator:Check("0")).to.be.equal(true) + end) + + it("02. Creates and combines IsNan", function() + local validator = Validator.IsNan():Freeze() + + expect(validator:Check(nan)).to.be.equal(true) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check(0.5)).to.be.equal(false) expect(validator:Check("0")).to.be.equal(false) - validator = Validator.IsNumber():Or():IsNan():Freeze() + validator = Validator.IsString():Or():IsNan():Freeze() expect(validator:Check(nan)).to.be.equal(true) - expect(validator:Check(0)).to.be.equal(true) - expect(validator:Check(0.5)).to.be.equal(true) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check(0.5)).to.be.equal(false) + expect(validator:Check("0")).to.be.equal(true) + end) + + it("03. Methods: IsGreater", function() + local validator = Validator.IsNumber():IsGreater(5):Freeze() + + expect(validator:Check(nan)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check(0.5)).to.be.equal(false) + expect(validator:Check(5)).to.be.equal(false) + expect(validator:Check(5.00001)).to.be.equal(true) + expect(validator:Check(6)).to.be.equal(true) + expect(validator:Check(-math.huge)).to.be.equal(false) + expect(validator:Check(math.huge)).to.be.equal(true) expect(validator:Check("0")).to.be.equal(false) end) + end) - it("04. Test instances", function() - local part = Instance.new("Part") - part.Parent = workspace + describe("04. Instances", function() + local part = Instance.new("Part") + local model = Instance.new("Model") + local decal = Instance.new("Decal") - local validator = Validator.IsAnInstance("BasePart"):Freeze() - local validatorStrict = Validator.IsAnInstanceStrict("BasePart"):Freeze() + it("00. Creates and combines IsAnInstance", function() + local validator = Validator.IsAnInstance("PVInstance"):Freeze() + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(false) expect(validator:Check(part)).to.be.equal(true) - expect(validatorStrict:Check(part)).to.be.equal(false) - - part:Destroy() + expect(validator:Check(model)).to.be.equal(true) + expect(validator:Check(decal)).to.be.equal(false) end) - it("05. Test tables", function() - local table1 = { - a = 10, - } - local table2 = { - a = 20, - } - local table3 = { - a = 10, - b = 20, - } + it("01. Creates and combines IsAnInstanceStrict", function() + local validator = Validator.IsAnInstanceStrict("PVInstance"):Freeze() + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check(part)).to.be.equal(false) + expect(validator:Check(model)).to.be.equal(false) + expect(validator:Check(decal)).to.be.equal(false) + + validator = Validator.IsAnInstanceStrict("Part"):Freeze() + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check(part)).to.be.equal(true) + expect(validator:Check(model)).to.be.equal(false) + expect(validator:Check(decal)).to.be.equal(false) + end) + end) + describe("05. Tables", function() + local table1 = { + a = 10, + } + local table2 = { + a = 20, + } + local table3 = { + a = 10, + b = 20, + } + + it("00. Creates and combines", function() local validator = Validator.IsTable():Freeze() expect(validator:Check(nil)).to.be.equal(false) @@ -154,7 +285,18 @@ return function() expect(validator:Check(table3)).to.be.equal(true) expect(validator:Check(0)).to.be.equal(false) - validator = Validator.IsTable({ + validator = Validator.IsNumber():Or():IsTable():Freeze() + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check({})).to.be.equal(true) + expect(validator:Check(table1)).to.be.equal(true) + expect(validator:Check(table2)).to.be.equal(true) + expect(validator:Check(table3)).to.be.equal(true) + expect(validator:Check(0)).to.be.equal(true) + end) + + it("01. Creates and combines with schema", function() + local validator = Validator.IsTable({ a = Validator.IsInteger():IsGreater(15), }):Freeze() @@ -165,18 +307,23 @@ return function() expect(validator:Check(table3)).to.be.equal(false) expect(validator:Check(0)).to.be.equal(false) - validator = Validator.IsTable({ - a = Validator.IsInteger(), - }):Freeze() + validator = Validator.IsNumber() + :Or() + :IsTable({ + a = Validator.IsInteger():IsGreater(15), + }) + :Freeze() expect(validator:Check(nil)).to.be.equal(false) expect(validator:Check({})).to.be.equal(false) - expect(validator:Check(table1)).to.be.equal(true) + expect(validator:Check(table1)).to.be.equal(false) expect(validator:Check(table2)).to.be.equal(true) - expect(validator:Check(table3)).to.be.equal(true) - expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check(table3)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(true) + end) - validator = Validator.IsTableStrict({ + it("02. Creates and combines with schema strict", function() + local validator = Validator.IsTableStrict({ a = Validator.IsInteger(), }):Freeze() @@ -187,15 +334,6 @@ return function() expect(validator:Check(table3)).to.be.equal(false) expect(validator:Check(0)).to.be.equal(false) - validator = Validator.IsNumber():Or():IsTable():Freeze() - - expect(validator:Check(nil)).to.be.equal(false) - expect(validator:Check({})).to.be.equal(true) - expect(validator:Check(table1)).to.be.equal(true) - expect(validator:Check(table2)).to.be.equal(true) - expect(validator:Check(table3)).to.be.equal(true) - expect(validator:Check(0)).to.be.equal(true) - validator = Validator.IsNumber() :Or() :IsTableStrict({ @@ -210,8 +348,10 @@ return function() expect(validator:Check(table3)).to.be.equal(false) expect(validator:Check(0)).to.be.equal(true) end) + end) - it("06. Test types", function() + describe("06. Types", function() + it("00. Creates and combines", function() local validator = Validator.IsTypeOf("Vector3"):Freeze() expect(validator:Check(nil)).to.be.equal(false) @@ -228,8 +368,10 @@ return function() expect(validator:Check(UDim2.new())).to.be.equal(false) expect(validator:Check(0)).to.be.equal(true) end) + end) - it("07. Test enums", function() + describe("07. Enums", function() + it("00. Creates and combines", function() local validator = Validator.IsEnumItem():Freeze() expect(validator:Check(1)).to.be.equal(false) @@ -237,64 +379,28 @@ return function() expect(validator:Check(Enum.KeyCode.A)).to.be.equal(true) expect(validator:Check(Enum.PartType.Ball)).to.be.equal(true) - validator = Validator.IsEnumItem(Enum.KeyCode):Freeze() - - expect(validator:Check(1)).to.be.equal(false) - expect(validator:Check("1")).to.be.equal(false) - expect(validator:Check(Enum.KeyCode.A)).to.be.equal(true) - expect(validator:Check(Enum.PartType.Ball)).to.be.equal(false) - validator = Validator.IsNumber():Or():IsEnumItem():Freeze() expect(validator:Check(1)).to.be.equal(true) expect(validator:Check("1")).to.be.equal(false) expect(validator:Check(Enum.KeyCode.A)).to.be.equal(true) expect(validator:Check(Enum.PartType.Ball)).to.be.equal(true) - - validator = Validator.IsNumber():Or():IsEnumItem(Enum.KeyCode):Freeze() - - expect(validator:Check(1)).to.be.equal(true) - expect(validator:Check("1")).to.be.equal(false) - expect(validator:Check(Enum.KeyCode.A)).to.be.equal(true) - expect(validator:Check(Enum.PartType.Ball)).to.be.equal(false) end) - it("08. Test core methods.", function() - local validator = Validator.IsString():Not():IsEqual("aaa"):Freeze() - - expect(validator:Check(1)).to.be.equal(false) - expect(validator:Check("1")).to.be.equal(true) - expect(validator:Check("aaa")).to.be.equal(false) - expect(validator:Check(nil)).to.be.equal(false) - - local values = { - "aaa", - "bbb", - "ccc", - } - - validator = Validator.IsString():IsInTable(values):Freeze() + it("01. Creates and combines with given Enum", function() + local validator = Validator.IsEnumItem(Enum.KeyCode):Freeze() expect(validator:Check(1)).to.be.equal(false) expect(validator:Check("1")).to.be.equal(false) - expect(validator:Check("aaa")).to.be.equal(true) - expect(validator:Check(nil)).to.be.equal(false) - - validator = Validator.IsString():Not():IsInTable(values):Freeze() - - expect(validator:Check(1)).to.be.equal(false) - expect(validator:Check("1")).to.be.equal(true) - expect(validator:Check("aaa")).to.be.equal(false) - expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(Enum.KeyCode.A)).to.be.equal(true) + expect(validator:Check(Enum.PartType.Ball)).to.be.equal(false) - validator = Validator.IsInteger():IsKeyOf(values):Freeze() + validator = Validator.IsNumber():Or():IsEnumItem(Enum.KeyCode):Freeze() expect(validator:Check(1)).to.be.equal(true) - expect(validator:Check(0)).to.be.equal(false) - expect(validator:Check(4)).to.be.equal(false) expect(validator:Check("1")).to.be.equal(false) - expect(validator:Check("aaa")).to.be.equal(false) - expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(Enum.KeyCode.A)).to.be.equal(true) + expect(validator:Check(Enum.PartType.Ball)).to.be.equal(false) end) end) end From 0939de14e6308b74b0dd673ebcfb7ca405d7940c Mon Sep 17 00:00:00 2001 From: bogotolec Date: Fri, 17 Oct 2025 21:46:06 +0300 Subject: [PATCH 17/17] Added 3 new methods to Instance - IsProperty - IsAttribute - HasTag --- src/Instance/InstanceChecks.lua | 25 +++++++++++++++ src/Instance/init.lua | 26 +++++++++++++++ src/Validator.spec.luau | 57 +++++++++++++++++++++++++++++++++ src/ValidatorTypes.lua | 12 +++++++ 4 files changed, 120 insertions(+) diff --git a/src/Instance/InstanceChecks.lua b/src/Instance/InstanceChecks.lua index 9467fef..8671660 100644 --- a/src/Instance/InstanceChecks.lua +++ b/src/Instance/InstanceChecks.lua @@ -1,5 +1,7 @@ --!strict +local ValidatorTypes = require(script.Parent.Parent.ValidatorTypes) + local InstanceChecks = {} function InstanceChecks.IsA(value: any, instanceClass: string): boolean @@ -10,4 +12,27 @@ function InstanceChecks.IsClass(value: any, instanceClass: string): boolean return typeof(value) == "Instance" and value.ClassName == instanceClass end +function InstanceChecks.IsProperty( + value: Instance, + property: string, + checker: ValidatorTypes.Checker +): boolean + local success, result = pcall(function(): boolean + return checker:Check((value :: any)[property]) + end) + return if success and result then true else false +end + +function InstanceChecks.IsAttribute( + value: Instance, + attribute: string, + checker: ValidatorTypes.Checker +): boolean + return checker:Check(value:GetAttribute(attribute)) +end + +function InstanceChecks.HasTag(value: Instance, tag: string): boolean + return value:HasTag(tag) +end + return InstanceChecks diff --git a/src/Instance/init.lua b/src/Instance/init.lua index 22626c5..9f62c65 100644 --- a/src/Instance/init.lua +++ b/src/Instance/init.lua @@ -43,4 +43,30 @@ function InstanceValidator.IsAnInstanceStrict( return new end +function InstanceValidator.IsProperty( + self: ValidatorTypes.PrivateInstanceValidator, + property: string, + checker: ValidatorTypes.Checker +): ValidatorTypes.PrivateInstanceValidator + Helpers.AddCheck(self, InstanceChecks.IsProperty, property, checker) + return self +end + +function InstanceValidator.IsAttribute( + self: ValidatorTypes.PrivateInstanceValidator, + attribute: string, + checker: ValidatorTypes.Checker +): ValidatorTypes.PrivateInstanceValidator + Helpers.AddCheck(self, InstanceChecks.IsAttribute, attribute, checker) + return self +end + +function InstanceValidator.HasTag( + self: ValidatorTypes.PrivateInstanceValidator, + tag: string +): ValidatorTypes.PrivateInstanceValidator + Helpers.AddCheck(self, InstanceChecks.HasTag, tag) + return self +end + return InstanceValidator diff --git a/src/Validator.spec.luau b/src/Validator.spec.luau index 1ab18bb..153bf3c 100644 --- a/src/Validator.spec.luau +++ b/src/Validator.spec.luau @@ -231,8 +231,16 @@ return function() describe("04. Instances", function() local part = Instance.new("Part") + part.Transparency = 0.6 + part:SetAttribute("test", "Hello") + local model = Instance.new("Model") + model:SetAttribute("test", 5) + model:AddTag("Test") + local decal = Instance.new("Decal") + decal.Transparency = 0.4 + decal:SetAttribute("test", false) it("00. Creates and combines IsAnInstance", function() local validator = Validator.IsAnInstance("PVInstance"):Freeze() @@ -261,6 +269,55 @@ return function() expect(validator:Check(model)).to.be.equal(false) expect(validator:Check(decal)).to.be.equal(false) end) + + it("02. Methods: IsProperty", function() + local validator = Validator.IsAnInstance("Object") + :IsProperty("Transparency", Validator.IsNumber():IsGreater(0.5)) + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check(part)).to.be.equal(true) + expect(validator:Check(model)).to.be.equal(false) + expect(validator:Check(decal)).to.be.equal(false) + + validator = Validator.IsAnInstance("Object") + :IsProperty("Transparency", Validator.IsNumber():IsGreater(0)) + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check(part)).to.be.equal(true) + expect(validator:Check(model)).to.be.equal(false) + expect(validator:Check(decal)).to.be.equal(true) + end) + + it("03. Methods: IsAttribute", function() + local validator = Validator.IsAnInstance("Object") + :IsAttribute("test", Validator.IsNumber():Or():IsBoolean()) + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check(part)).to.be.equal(false) + expect(validator:Check(model)).to.be.equal(true) + expect(validator:Check(decal)).to.be.equal(true) + + validator = Validator.IsAnInstance("Object"):IsAttribute("test", Validator.IsNumber()) + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check(part)).to.be.equal(false) + expect(validator:Check(model)).to.be.equal(true) + expect(validator:Check(decal)).to.be.equal(false) + end) + + it("04. Methods: HasTag", function() + local validator = Validator.IsAnInstance("Object"):HasTag("Test") + + expect(validator:Check(nil)).to.be.equal(false) + expect(validator:Check(0)).to.be.equal(false) + expect(validator:Check(part)).to.be.equal(false) + expect(validator:Check(model)).to.be.equal(true) + expect(validator:Check(decal)).to.be.equal(false) + end) end) describe("05. Tables", function() diff --git a/src/ValidatorTypes.lua b/src/ValidatorTypes.lua index 99a370f..8472367 100644 --- a/src/ValidatorTypes.lua +++ b/src/ValidatorTypes.lua @@ -110,6 +110,18 @@ export type PrivateNanValidator = PublicNanValidator & PrivateValidator --#region Instance export type InstanceValidatorMethods = { + IsProperty: ( + self: InstanceValidatorMethods, + property: string, + checker: Checker + ) -> PublicInstanceValidator, + IsAttribute: ( + self: InstanceValidatorMethods, + attribute: string, + checker: Checker + ) -> PublicInstanceValidator, + HasTag: (self: InstanceValidatorMethods, tag: string) -> PublicInstanceValidator, + IsInTable: (self: InstanceValidatorMethods, table: { [any]: any }) -> PublicInstanceValidator, IsKeyOf: (self: InstanceValidatorMethods, table: { [any]: any }) -> PublicInstanceValidator, IsEqual: (self: InstanceValidatorMethods, otherValue: any) -> PublicInstanceValidator,