@quenty/string 3.3.7 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/deploy.nevermore.json +10 -0
- package/package.json +7 -2
- package/src/Shared/String.lua +2 -2
- package/src/Shared/String.spec.lua +235 -0
- package/src/jest.config.lua +3 -0
- package/src/node_modules.project.json +7 -0
- package/test/default.project.json +25 -0
- package/test/scripts/Server/ServerMain.server.lua +14 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [3.4.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/string@3.4.0...@quenty/string@3.4.1) (2026-08-14)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @quenty/string
|
|
9
|
+
|
|
10
|
+
# [3.4.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/string@3.3.7...@quenty/string@3.4.0) (2026-07-23)
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
- Add unit tests to string package ([f15f2f2](https://github.com/Quenty/NevermoreEngine/commit/f15f2f2892d782bed552a882e31f3b5d07975184))
|
|
15
|
+
|
|
6
16
|
## [3.3.7](https://github.com/Quenty/NevermoreEngine/compare/@quenty/string@3.3.6...@quenty/string@3.3.7) (2026-05-30)
|
|
7
17
|
|
|
8
18
|
**Note:** Version bump only for package @quenty/string
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/string",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.1",
|
|
4
4
|
"description": "This module provides utility functions for strings",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -25,11 +25,16 @@
|
|
|
25
25
|
"scripts": {
|
|
26
26
|
"preinstall": "npx only-allow pnpm"
|
|
27
27
|
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@quenty/loader": "10.11.1",
|
|
30
|
+
"@quenty/nevermore-test-runner": "1.5.1",
|
|
31
|
+
"@quentystudios/jest-lua": "3.10.0-quenty.2"
|
|
32
|
+
},
|
|
28
33
|
"contributors": [
|
|
29
34
|
"Quenty"
|
|
30
35
|
],
|
|
31
36
|
"publishConfig": {
|
|
32
37
|
"access": "public"
|
|
33
38
|
},
|
|
34
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "f084360c3729ea424d49d9bc42f8f0d1c128fa82"
|
|
35
40
|
}
|
package/src/Shared/String.lua
CHANGED
|
@@ -102,10 +102,10 @@ end
|
|
|
102
102
|
|
|
103
103
|
--[=[
|
|
104
104
|
Checks if a string is empty or nil
|
|
105
|
-
@param str string
|
|
105
|
+
@param str string?
|
|
106
106
|
@return boolean
|
|
107
107
|
]=]
|
|
108
|
-
function String.isEmptyOrWhitespaceOrNil(str: string): boolean
|
|
108
|
+
function String.isEmptyOrWhitespaceOrNil(str: string?): boolean
|
|
109
109
|
return type(str) ~= "string" or str == "" or String.isWhitespace(str)
|
|
110
110
|
end
|
|
111
111
|
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[[
|
|
3
|
+
@class String.spec.lua
|
|
4
|
+
]]
|
|
5
|
+
|
|
6
|
+
local require = require(script.Parent.loader).load(script)
|
|
7
|
+
|
|
8
|
+
local Jest = require("Jest")
|
|
9
|
+
local String = require("String")
|
|
10
|
+
|
|
11
|
+
local describe = Jest.Globals.describe
|
|
12
|
+
local expect = Jest.Globals.expect
|
|
13
|
+
local it = Jest.Globals.it
|
|
14
|
+
|
|
15
|
+
describe("String.trim", function()
|
|
16
|
+
it("trims leading and trailing whitespace by default", function()
|
|
17
|
+
expect(String.trim(" hello ")).toEqual("hello")
|
|
18
|
+
end)
|
|
19
|
+
|
|
20
|
+
it("trims tabs and newlines", function()
|
|
21
|
+
expect(String.trim("\t\nhello world\n\t")).toEqual("hello world")
|
|
22
|
+
end)
|
|
23
|
+
|
|
24
|
+
it("leaves interior whitespace untouched", function()
|
|
25
|
+
expect(String.trim(" a b ")).toEqual("a b")
|
|
26
|
+
end)
|
|
27
|
+
|
|
28
|
+
it("returns an empty string for all-whitespace input", function()
|
|
29
|
+
expect(String.trim(" ")).toEqual("")
|
|
30
|
+
end)
|
|
31
|
+
|
|
32
|
+
it("is a no-op when there is nothing to trim", function()
|
|
33
|
+
expect(String.trim("hello")).toEqual("hello")
|
|
34
|
+
end)
|
|
35
|
+
|
|
36
|
+
it("trims a custom pattern", function()
|
|
37
|
+
expect(String.trim("xxhelloxx", "x")).toEqual("hello")
|
|
38
|
+
end)
|
|
39
|
+
end)
|
|
40
|
+
|
|
41
|
+
describe("String.trimFront", function()
|
|
42
|
+
it("trims only the leading whitespace by default", function()
|
|
43
|
+
expect(String.trimFront(" hello ")).toEqual("hello ")
|
|
44
|
+
end)
|
|
45
|
+
|
|
46
|
+
it("leaves a string without a leading match untouched", function()
|
|
47
|
+
expect(String.trimFront("hello ")).toEqual("hello ")
|
|
48
|
+
end)
|
|
49
|
+
|
|
50
|
+
it("trims a custom leading pattern", function()
|
|
51
|
+
expect(String.trimFront("xxhello", "x")).toEqual("hello")
|
|
52
|
+
end)
|
|
53
|
+
end)
|
|
54
|
+
|
|
55
|
+
describe("String.toCamelCase", function()
|
|
56
|
+
it("converts snake_case to UpperCamelCase", function()
|
|
57
|
+
expect(String.toCamelCase("hello_world")).toEqual("HelloWorld")
|
|
58
|
+
end)
|
|
59
|
+
|
|
60
|
+
it("converts YELL_CASE to UpperCamelCase", function()
|
|
61
|
+
expect(String.toCamelCase("YELL_CASE")).toEqual("YellCase")
|
|
62
|
+
end)
|
|
63
|
+
|
|
64
|
+
it("converts space separated words to UpperCamelCase", function()
|
|
65
|
+
expect(String.toCamelCase("hello world")).toEqual("HelloWorld")
|
|
66
|
+
end)
|
|
67
|
+
|
|
68
|
+
it("capitalizes the first letter of a single lowercase word", function()
|
|
69
|
+
expect(String.toCamelCase("hello")).toEqual("Hello")
|
|
70
|
+
end)
|
|
71
|
+
|
|
72
|
+
it("strips remaining punctuation", function()
|
|
73
|
+
expect(String.toCamelCase("foo-bar")).toEqual("Foobar")
|
|
74
|
+
end)
|
|
75
|
+
end)
|
|
76
|
+
|
|
77
|
+
describe("String.toLowerCamelCase", function()
|
|
78
|
+
it("converts snake_case to lowerCamelCase", function()
|
|
79
|
+
expect(String.toLowerCamelCase("hello_world")).toEqual("helloWorld")
|
|
80
|
+
end)
|
|
81
|
+
|
|
82
|
+
it("converts YELL_CASE to lowerCamelCase", function()
|
|
83
|
+
expect(String.toLowerCamelCase("YELL_CASE")).toEqual("yellCase")
|
|
84
|
+
end)
|
|
85
|
+
|
|
86
|
+
it("keeps the first letter lowercase", function()
|
|
87
|
+
expect(String.toLowerCamelCase("hello")).toEqual("hello")
|
|
88
|
+
end)
|
|
89
|
+
end)
|
|
90
|
+
|
|
91
|
+
describe("String.uppercaseFirstLetter", function()
|
|
92
|
+
it("uppercases the first letter", function()
|
|
93
|
+
expect(String.uppercaseFirstLetter("hello")).toEqual("Hello")
|
|
94
|
+
end)
|
|
95
|
+
|
|
96
|
+
it("leaves an already-uppercase first letter untouched", function()
|
|
97
|
+
expect(String.uppercaseFirstLetter("Hello")).toEqual("Hello")
|
|
98
|
+
end)
|
|
99
|
+
|
|
100
|
+
it("is a no-op when the first character is not a letter", function()
|
|
101
|
+
expect(String.uppercaseFirstLetter("123abc")).toEqual("123abc")
|
|
102
|
+
end)
|
|
103
|
+
end)
|
|
104
|
+
|
|
105
|
+
describe("String.toPrivateCase", function()
|
|
106
|
+
it("prefixes with an underscore and lowercases the first letter", function()
|
|
107
|
+
expect(String.toPrivateCase("MyThing")).toEqual("_myThing")
|
|
108
|
+
end)
|
|
109
|
+
|
|
110
|
+
it("preserves the remainder of the string", function()
|
|
111
|
+
expect(String.toPrivateCase("SomeValue")).toEqual("_someValue")
|
|
112
|
+
end)
|
|
113
|
+
end)
|
|
114
|
+
|
|
115
|
+
describe("String.checkNumOfCharacterInString", function()
|
|
116
|
+
it("counts the occurrences of a character", function()
|
|
117
|
+
expect(String.checkNumOfCharacterInString("hello", "l")).toEqual(2)
|
|
118
|
+
end)
|
|
119
|
+
|
|
120
|
+
it("returns 0 when the character is absent", function()
|
|
121
|
+
expect(String.checkNumOfCharacterInString("hello", "z")).toEqual(0)
|
|
122
|
+
end)
|
|
123
|
+
|
|
124
|
+
it("counts every character in the string", function()
|
|
125
|
+
expect(String.checkNumOfCharacterInString("aaaa", "a")).toEqual(4)
|
|
126
|
+
end)
|
|
127
|
+
end)
|
|
128
|
+
|
|
129
|
+
describe("String.isWhitespace", function()
|
|
130
|
+
it("returns true for a string of only whitespace", function()
|
|
131
|
+
expect(String.isWhitespace(" ")).toEqual(true)
|
|
132
|
+
end)
|
|
133
|
+
|
|
134
|
+
it("returns false for a string with non-whitespace", function()
|
|
135
|
+
expect(String.isWhitespace("a b")).toEqual(false)
|
|
136
|
+
end)
|
|
137
|
+
|
|
138
|
+
it("returns false for an empty string", function()
|
|
139
|
+
expect(String.isWhitespace("")).toEqual(false)
|
|
140
|
+
end)
|
|
141
|
+
end)
|
|
142
|
+
|
|
143
|
+
describe("String.isEmptyOrWhitespaceOrNil", function()
|
|
144
|
+
it("returns true for nil", function()
|
|
145
|
+
expect(String.isEmptyOrWhitespaceOrNil(nil)).toEqual(true)
|
|
146
|
+
end)
|
|
147
|
+
|
|
148
|
+
it("returns true for an empty string", function()
|
|
149
|
+
expect(String.isEmptyOrWhitespaceOrNil("")).toEqual(true)
|
|
150
|
+
end)
|
|
151
|
+
|
|
152
|
+
it("returns true for a whitespace-only string", function()
|
|
153
|
+
expect(String.isEmptyOrWhitespaceOrNil(" \t")).toEqual(true)
|
|
154
|
+
end)
|
|
155
|
+
|
|
156
|
+
it("returns false for a string with content", function()
|
|
157
|
+
expect(String.isEmptyOrWhitespaceOrNil("hello")).toEqual(false)
|
|
158
|
+
end)
|
|
159
|
+
end)
|
|
160
|
+
|
|
161
|
+
describe("String.elipseLimit", function()
|
|
162
|
+
it("truncates and appends an ellipsis when over the limit", function()
|
|
163
|
+
expect(String.elipseLimit("hello world", 8)).toEqual("hello...")
|
|
164
|
+
end)
|
|
165
|
+
|
|
166
|
+
it("leaves a string at or under the limit untouched", function()
|
|
167
|
+
expect(String.elipseLimit("hello", 8)).toEqual("hello")
|
|
168
|
+
end)
|
|
169
|
+
|
|
170
|
+
it("produces a result of exactly the limit length", function()
|
|
171
|
+
expect(#String.elipseLimit("abcdefghij", 8)).toEqual(8)
|
|
172
|
+
end)
|
|
173
|
+
end)
|
|
174
|
+
|
|
175
|
+
describe("String.removePrefix", function()
|
|
176
|
+
it("removes a matching prefix", function()
|
|
177
|
+
expect(String.removePrefix("foobar", "foo")).toEqual("bar")
|
|
178
|
+
end)
|
|
179
|
+
|
|
180
|
+
it("returns the string unchanged when the prefix does not match", function()
|
|
181
|
+
expect(String.removePrefix("foobar", "xyz")).toEqual("foobar")
|
|
182
|
+
end)
|
|
183
|
+
end)
|
|
184
|
+
|
|
185
|
+
describe("String.removePostfix", function()
|
|
186
|
+
it("removes a matching postfix", function()
|
|
187
|
+
expect(String.removePostfix("foobar", "bar")).toEqual("foo")
|
|
188
|
+
end)
|
|
189
|
+
|
|
190
|
+
it("returns the string unchanged when the postfix does not match", function()
|
|
191
|
+
expect(String.removePostfix("foobar", "xyz")).toEqual("foobar")
|
|
192
|
+
end)
|
|
193
|
+
end)
|
|
194
|
+
|
|
195
|
+
describe("String.startsWith", function()
|
|
196
|
+
it("returns true when the string starts with the prefix", function()
|
|
197
|
+
expect(String.startsWith("foobar", "foo")).toEqual(true)
|
|
198
|
+
end)
|
|
199
|
+
|
|
200
|
+
it("returns false when the string does not start with the prefix", function()
|
|
201
|
+
expect(String.startsWith("foobar", "bar")).toEqual(false)
|
|
202
|
+
end)
|
|
203
|
+
end)
|
|
204
|
+
|
|
205
|
+
describe("String.endsWith", function()
|
|
206
|
+
it("returns true when the string ends with the postfix", function()
|
|
207
|
+
expect(String.endsWith("foobar", "bar")).toEqual(true)
|
|
208
|
+
end)
|
|
209
|
+
|
|
210
|
+
it("returns false when the string does not end with the postfix", function()
|
|
211
|
+
expect(String.endsWith("foobar", "foo")).toEqual(false)
|
|
212
|
+
end)
|
|
213
|
+
end)
|
|
214
|
+
|
|
215
|
+
describe("String.addCommas", function()
|
|
216
|
+
it("adds commas to a large number", function()
|
|
217
|
+
expect(String.addCommas(1000000)).toEqual("1,000,000")
|
|
218
|
+
end)
|
|
219
|
+
|
|
220
|
+
it("leaves numbers under a thousand unchanged", function()
|
|
221
|
+
expect(String.addCommas(123)).toEqual("123")
|
|
222
|
+
end)
|
|
223
|
+
|
|
224
|
+
it("handles negative numbers", function()
|
|
225
|
+
expect(String.addCommas(-1234567)).toEqual("-1,234,567")
|
|
226
|
+
end)
|
|
227
|
+
|
|
228
|
+
it("accepts a string number", function()
|
|
229
|
+
expect(String.addCommas("1234567")).toEqual("1,234,567")
|
|
230
|
+
end)
|
|
231
|
+
|
|
232
|
+
it("uses a custom separator", function()
|
|
233
|
+
expect(String.addCommas(1234, ".")).toEqual("1.234")
|
|
234
|
+
end)
|
|
235
|
+
end)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "StringTest",
|
|
3
|
+
"globIgnorePaths": [
|
|
4
|
+
"**/.package-lock.json",
|
|
5
|
+
"**/.pnpm",
|
|
6
|
+
"**/.pnpm-workspace-state-v1.json",
|
|
7
|
+
"**/.modules.yaml",
|
|
8
|
+
"**/.ignored",
|
|
9
|
+
"**/.ignored_*"
|
|
10
|
+
],
|
|
11
|
+
"tree": {
|
|
12
|
+
"$className": "DataModel",
|
|
13
|
+
"ServerScriptService": {
|
|
14
|
+
"$properties": {
|
|
15
|
+
"LoadStringEnabled": true
|
|
16
|
+
},
|
|
17
|
+
"string": {
|
|
18
|
+
"$path": ".."
|
|
19
|
+
},
|
|
20
|
+
"Script": {
|
|
21
|
+
"$path": "scripts/Server"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
--!nonstrict
|
|
2
|
+
--[[
|
|
3
|
+
@class ServerMain
|
|
4
|
+
]]
|
|
5
|
+
|
|
6
|
+
local ServerScriptService = game:GetService("ServerScriptService")
|
|
7
|
+
|
|
8
|
+
local root = ServerScriptService.string
|
|
9
|
+
local loader = root:FindFirstChild("LoaderUtils", true).Parent
|
|
10
|
+
local require = require(loader).bootstrapGame(root)
|
|
11
|
+
|
|
12
|
+
local NevermoreTestRunnerUtils = require("NevermoreTestRunnerUtils")
|
|
13
|
+
|
|
14
|
+
NevermoreTestRunnerUtils.runTestsIfNeededAsync(root)
|