diff --git a/CHANGELOG.md b/CHANGELOG.md index 260a42a..f46af82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,9 @@ ## Unreleased -Nothing yet! +- Fix `GreenTea.string({ unicode = true })` accepting invalid UTF-8. The check called `utf8.graphemes` inside a `pcall` without iterating it, which never validates. It now uses `utf8.len`. +- Fix `countGraphemes` never returning `nil` for invalid UTF-8, so `GreenTea.string({ graphemes = ... })` reports a proper error instead of throwing. +- Add `GreenTea.Content`. ## 0.4.11 diff --git a/src/GreenTea.luau b/src/GreenTea.luau index 695a867..fdb1b1e 100644 --- a/src/GreenTea.luau +++ b/src/GreenTea.luau @@ -493,16 +493,8 @@ function Type.type(self: any): ...any return self end -local isStringUnicode - -if utf8.graphemes then - function isStringUnicode(str: string) - return pcall(utf8.graphemes, str) == true - end -else - function isStringUnicode(str: string) - return utf8.len(str) ~= nil - end +local function isStringUnicode(str: string) + return utf8.len(str) ~= nil end local function truncate(count: number, str: string) @@ -928,6 +920,7 @@ GreenTea.Rect = newBasicType("Rect") :: () -> Rect GreenTea.Region3 = newBasicType("Region3") :: () -> Region3 GreenTea.BrickColor = newBasicType("BrickColor") :: () -> BrickColor GreenTea.Font = newBasicType("Font") :: () -> Font +GreenTea.Content = newBasicType("Content") :: () -> Content GreenTea.Enum = newBasicType("Enum") :: () -> Enum GreenTea.EnumItem = newBasicType("EnumItem") :: () -> EnumItem @@ -1146,6 +1139,8 @@ end local function countGraphemes(str: string): number? if #str == 0 then return 0 + elseif not isStringUnicode(str) then + return nil else local count = 0 for _ in utf8.graphemes(str) do @@ -1285,7 +1280,7 @@ end --- @function types not listed here --- A few methods are not listed in the docs so that they don't clutter with basic types.\ --- Here's a list: userdata, Vector2, vector, Vector3, CFrame, Color3, UDim, UDim2, ---- Ray, Rect, Region3, BrickColor, Font, Enum, EnumItem.\ +--- Ray, Rect, Region3, BrickColor, Font, Content, Enum, EnumItem.\ --- For the most part, any Luau type you'd naturally write likely also exists under GreenTea. --- Less common types are excluded (for now) to not clutter the library. --- For the ones that don't exist, you can usually use `isTypeof` or `isType`. diff --git a/src/init.luau b/src/init.luau index 7f8d1d2..026fa20 100644 --- a/src/init.luau +++ b/src/init.luau @@ -43,6 +43,7 @@ export.Rect = GreenTea.Rect export.Region3 = GreenTea.Region3 export.BrickColor = GreenTea.BrickColor export.Font = GreenTea.Font +export.Content = GreenTea.Content export.Enum = GreenTea.Enum export.EnumItem = GreenTea.EnumItem diff --git a/src/tCompat.luau b/src/tCompat.luau index 8db1cf6..f3a6117 100644 --- a/src/tCompat.luau +++ b/src/tCompat.luau @@ -99,6 +99,7 @@ implicitConstructors.Vector2 = basicType("Vector2") implicitConstructors.Vector2int16 = basicType("Vector2int16") implicitConstructors.Vector3 = basicType("Vector3") implicitConstructors.Vector3int16 = basicType("Vector3int16") +implicitConstructors.Content = basicType("Content") t.type = function(typename: string): any return GreenTea.isType(typename) diff --git a/test/GreenTea.spec.luau b/test/GreenTea.spec.luau index 52efdc1..e9fdbc5 100644 --- a/test/GreenTea.spec.luau +++ b/test/GreenTea.spec.luau @@ -164,11 +164,13 @@ basicTest({ values = { true, false }, }) -local function basicBasicTest(name, value) +local function basicBasicTest(name, ...) + local values = { ... } + basicTest({ kind = name, fn = gt[name], - values = { value }, + values = values, }) basicTest({ @@ -176,7 +178,7 @@ local function basicBasicTest(name, value) fn = function() return gt.isTypeof(name) end, - values = { value }, + values = values, describeName = `gt.basic({name})`, }) end @@ -192,6 +194,7 @@ basicBasicTest("Ray", Ray.new(Vector3.new(0, 0, 0), Vector3.new(0, 0, 1))) basicBasicTest("Rect", Rect.new()) basicBasicTest("Region3", Region3.new(Vector3.new(0, 0, 0), Vector3.new(1, 1, 1))) basicBasicTest("BrickColor", BrickColor.new("Bright blue")) +basicBasicTest("Content", Content.fromAssetId(123), Content.none) basicTest({ kind = "nil",