Skip to content

Commit 84366a9

Browse files
committed
signame -> sigid function done with tests
1 parent c256f43 commit 84366a9

File tree

4 files changed

+654
-7
lines changed

4 files changed

+654
-7
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777
"typescript": "^5.5.4",
7878
"typescript-eslint": "^8.0.1",
7979
"vite-tsconfig-paths": "^5.0.1",
80-
"vitest": "^2.0.5",
80+
"vitest": "^3.1.2",
8181
"yarn-upgrade-all": "^0.7.4"
8282
},
8383
"resolutions": {

src/common/utils.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,48 @@ export function transformCommaSeperatedName(name: string) {
1212
}
1313
return name;
1414
}
15+
16+
const notUnreservedCharsRegex = /[^a-zA-Z0-9\-._~]/g;
17+
const reservedCharsRegex = /[:\/?#\[\]@!$&'()*+,;=]/g;
18+
/**
19+
* Transforms an organization name (sig lead) into a URI-friendly format.
20+
* The function performs the following transformations:
21+
* - Removes characters that are reserved or not unreserved.
22+
* - Adds spaces between camel case words.
23+
* - Converts reserved characters to spaces.
24+
* - Converts all characters to lowercase and replaces all types of whitespace with hyphens.
25+
* - Replaces any sequence of repeated hyphens with a single hyphen.
26+
* - Refer to RFC 3986 https://datatracker.ietf.org/doc/html/rfc3986#section-2.3
27+
*
28+
* @param {string} org - The organization (sig lead) name to be transformed.
29+
* @returns {string} - The transformed organization name, ready for use as a URL.
30+
*/
31+
export function transformSigLeadToURI(org: string) {
32+
console.log(`org\t${org}`)
33+
org = org
34+
// change not reserved chars to spaces
35+
.trim()
36+
.replace(notUnreservedCharsRegex, " ")
37+
.trim()
38+
.replace(/\s/g, "-")
39+
40+
// remove all that is reserved or not unreserved
41+
.replace(reservedCharsRegex, "")
42+
43+
// convert SIG -> sig for camel case
44+
.replace(/SIG/g, "sig")
45+
46+
// add hyphen for camel case
47+
.replace(/([a-z])([A-Z])/g, "$1-$2")
48+
49+
// lower
50+
.toLowerCase()
51+
52+
// add spaces between chars and numbers (seq2seq -> seq-2-seq)
53+
.replace(/(?<=[a-z])([0-9]+)(?=[a-z])/g, "-$1-")
54+
55+
// remove duplicate hyphens
56+
.replace(/-{2,}/g, "-");
57+
58+
return org === "-" ? "" : org;
59+
}

tests/unit/common/utils.test.ts

Lines changed: 144 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect, test, describe } from "vitest";
2-
import { transformCommaSeperatedName } from "../../../src/common/utils.js";
2+
import { transformCommaSeperatedName, transformSigLeadToURI } from "../../../src/common/utils.js";
33

44
describe("Comma-seperated name transformer tests", () => {
55
test("Already-transformed names are returned as-is", () => {
@@ -27,3 +27,146 @@ describe("Comma-seperated name transformer tests", () => {
2727
expect(output).toEqual(", Test");
2828
});
2929
});
30+
31+
describe("transformSigLeadToURI tests", () => {
32+
33+
// Basic Functionality Tests
34+
test("should convert simple names with spaces to lowercase hyphenated", () => {
35+
const output = transformSigLeadToURI("SIG Network");
36+
expect(output).toEqual("sig-network");
37+
});
38+
39+
test("should convert simple names to lowercase", () => {
40+
const output = transformSigLeadToURI("Testing");
41+
expect(output).toEqual("testing");
42+
});
43+
44+
test("should handle names already in the desired format", () => {
45+
const output = transformSigLeadToURI("already-transformed-name");
46+
expect(output).toEqual("already-transformed-name");
47+
});
48+
49+
// Camel Case Tests
50+
test("should add hyphens between camelCase words", () => {
51+
const output = transformSigLeadToURI("SIGAuth");
52+
expect(output).toEqual("sig-auth");
53+
});
54+
55+
test("should handle multiple camelCase words", () => {
56+
const output = transformSigLeadToURI("SuperCamelCaseProject");
57+
expect(output).toEqual("super-camel-case-project");
58+
});
59+
60+
test("should handle mixed camelCase and spaces", () => {
61+
const output = transformSigLeadToURI("SIG ContribEx"); // SIG Contributor Experience
62+
expect(output).toEqual("sig-contrib-ex");
63+
});
64+
65+
test("should handle camelCase starting with lowercase", () => {
66+
const output = transformSigLeadToURI("myCamelCaseName");
67+
expect(output).toEqual("my-camel-case-name");
68+
});
69+
70+
// Reserved Character Tests (RFC 3986 gen-delims and sub-delims)
71+
test("should convert reserved characters like & to hyphens", () => {
72+
const output = transformSigLeadToURI("SIG Storage & Backup");
73+
expect(output).toEqual("sig-storage-backup"); // & -> space -> hyphen
74+
});
75+
76+
test("should convert reserved characters like / and : to hyphens", () => {
77+
const output = transformSigLeadToURI("Project:Alpha/Beta");
78+
expect(output).toEqual("project-alpha-beta"); // : -> space, / -> space, space+space -> hyphen
79+
});
80+
81+
test("should convert reserved characters like () and + to hyphens", () => {
82+
const output = transformSigLeadToURI("My Project (Test+Alpha)");
83+
expect(output).toEqual("my-project-test-alpha");
84+
});
85+
86+
test("should convert various reserved characters #[]@?$, to hyphens", () => {
87+
const output = transformSigLeadToURI("Special#Chars[Test]?@Value,$");
88+
expect(output).toEqual("special-chars-test-value");
89+
});
90+
91+
// Non-Allowed Character Removal Tests
92+
test("should remove characters not unreserved or reserved (e.g., ™, ©)", () => {
93+
const output = transformSigLeadToURI("MyOrg™ With © Symbols");
94+
expect(output).toEqual("my-org-with-symbols");
95+
});
96+
97+
test("should remove emoji", () => {
98+
const output = transformSigLeadToURI("Project ✨ Fun");
99+
expect(output).toEqual("project-fun");
100+
});
101+
102+
103+
// Whitespace and Hyphen Collapsing Tests
104+
test("should handle multiple spaces between words", () => {
105+
const output = transformSigLeadToURI("SIG UI Project");
106+
expect(output).toEqual("sig-ui-project");
107+
});
108+
109+
test("should handle leading/trailing whitespace", () => {
110+
const output = transformSigLeadToURI(" Leading and Trailing ");
111+
expect(output).toEqual("leading-and-trailing");
112+
});
113+
114+
test("should handle mixed whitespace (tabs, newlines)", () => {
115+
const output = transformSigLeadToURI("Mix\tOf\nWhite Space");
116+
expect(output).toEqual("mix-of-white-space");
117+
});
118+
119+
test("should collapse multiple hyphens resulting from transformations", () => {
120+
const output = transformSigLeadToURI("Test--Multiple / Spaces");
121+
expect(output).toEqual("test-multiple-spaces");
122+
});
123+
124+
test("should collapse hyphens from start/end after transformations", () => {
125+
const output = transformSigLeadToURI("&Another Test!");
126+
expect(output).toEqual("another-test");
127+
});
128+
129+
// Unreserved Character Tests (RFC 3986)
130+
test("should keep unreserved characters: hyphen, period, underscore, tilde", () => {
131+
const output = transformSigLeadToURI("Keep.These-Chars_Okay~123");
132+
expect(output).toEqual("keep.these-chars_okay~123");
133+
});
134+
135+
test("should handle unreserved chars next to reserved chars", () => {
136+
const output = transformSigLeadToURI("Test._~&Stuff");
137+
expect(output).toEqual("test._~-stuff");
138+
});
139+
140+
141+
// Edge Case Tests
142+
test("should return an empty string for an empty input", () => {
143+
const output = transformSigLeadToURI("");
144+
expect(output).toEqual("");
145+
});
146+
147+
test("should return an empty string for input with only spaces", () => {
148+
const output = transformSigLeadToURI(" ");
149+
expect(output).toEqual("");
150+
});
151+
152+
test("should return an empty string for input with only reserved/non-allowed chars and spaces", () => {
153+
const output = transformSigLeadToURI(" & / # ™ © ");
154+
expect(output).toEqual("");
155+
});
156+
157+
test("should handle numbers correctly", () => {
158+
const output = transformSigLeadToURI("ProjectApollo11");
159+
expect(output).toEqual("project-apollo11"); // Number doesn't trigger camel case break after letter
160+
});
161+
162+
test("should handle numbers triggering camel case break", () => {
163+
const output = transformSigLeadToURI("Project11Apollo");
164+
expect(output).toEqual("project-11-apollo"); // Letter after number triggers camel case break
165+
});
166+
167+
test("should handle names starting with lowercase", () => {
168+
const output = transformSigLeadToURI("myOrg");
169+
expect(output).toEqual("my-org");
170+
});
171+
172+
});

0 commit comments

Comments
 (0)