@hobenakicoffee/libraries 1.0.0 → 1.2.0
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/package.json
CHANGED
|
@@ -4,13 +4,14 @@ import type { ServiceType } from "./services";
|
|
|
4
4
|
|
|
5
5
|
describe("ServiceTypes", () => {
|
|
6
6
|
test("should contain all expected service type keys", () => {
|
|
7
|
-
const expectedKeys = ["GIFT", "EXCLUSIVE_CONTENT"];
|
|
7
|
+
const expectedKeys = ["GIFT", "EXCLUSIVE_CONTENT", "WITHDRAWAL"];
|
|
8
8
|
expect(Object.keys(ServiceTypes)).toEqual(expectedKeys);
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
test("should have correct values for each service type", () => {
|
|
12
12
|
expect(ServiceTypes.GIFT).toBe("gift");
|
|
13
13
|
expect(ServiceTypes.EXCLUSIVE_CONTENT).toBe("exclusive_content");
|
|
14
|
+
expect(ServiceTypes.WITHDRAWAL).toBe("withdrawal");
|
|
14
15
|
});
|
|
15
16
|
|
|
16
17
|
test("should be read-only at compile time", () => {
|
|
@@ -26,7 +27,7 @@ describe("ServiceTypes", () => {
|
|
|
26
27
|
});
|
|
27
28
|
|
|
28
29
|
test("should have 2 service types", () => {
|
|
29
|
-
expect(Object.keys(ServiceTypes).length).toBe(
|
|
30
|
+
expect(Object.keys(ServiceTypes).length).toBe(3);
|
|
30
31
|
});
|
|
31
32
|
|
|
32
33
|
test("all values should be lowercase or snake_case strings", () => {
|
package/src/utils/index.ts
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { toHumanReadable } from "./to-human-readable";
|
|
3
|
+
|
|
4
|
+
describe("toHumanReadable", () => {
|
|
5
|
+
test("returns empty string for blank input", () => {
|
|
6
|
+
expect(toHumanReadable(" ")).toBe("");
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
test("normalizes separators and trims", () => {
|
|
10
|
+
expect(toHumanReadable(" hello-world__again ")).toBe("Hello World Again");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test("splits camelCase and title cases words", () => {
|
|
14
|
+
expect(toHumanReadable("supporterName")).toBe("Supporter Name");
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("preserves uppercase acronyms and numbers", () => {
|
|
18
|
+
expect(toHumanReadable("APIResponseV2")).toBe("API Response V2");
|
|
19
|
+
expect(toHumanReadable("USER_ID_2")).toBe("USER ID 2");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("handles mixed separators and spacing", () => {
|
|
23
|
+
expect(toHumanReadable("foo__BAR-baz QUX")).toBe("Foo BAR Baz QUX");
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const UPPERCASE_OR_NUMBER = /^[A-Z0-9]+$/;
|
|
2
|
+
|
|
3
|
+
export function toHumanReadable(input: string): string {
|
|
4
|
+
const normalized = input
|
|
5
|
+
.trim()
|
|
6
|
+
.replace(/[-_]+/g, " ")
|
|
7
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
8
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2")
|
|
9
|
+
.replace(/\s+/g, " ")
|
|
10
|
+
.trim();
|
|
11
|
+
|
|
12
|
+
if (!normalized) return "";
|
|
13
|
+
|
|
14
|
+
return normalized
|
|
15
|
+
.split(" ")
|
|
16
|
+
.map((word) => {
|
|
17
|
+
if (UPPERCASE_OR_NUMBER.test(word)) return word;
|
|
18
|
+
|
|
19
|
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
20
|
+
})
|
|
21
|
+
.join(" ");
|
|
22
|
+
}
|