Skip to content

Commit

Permalink
fix: handle snake case of ABcD which should become a_bc_d (#7883)
Browse files Browse the repository at this point in the history
this also simplifies the regular expressions
  • Loading branch information
imnotjames committed Jul 10, 2021
1 parent a1c6bb0 commit eb680f9
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 2 deletions.
9 changes: 7 additions & 2 deletions src/util/StringUtils.ts
Expand Up @@ -18,8 +18,13 @@ export function camelCase(str: string, firstCapital: boolean = false): string {
*
* @see https://regex101.com/r/QeSm2I/1
*/
export function snakeCase(str: string) {
return str.replace(/(?:([a-z])([A-Z]))|(?:((?!^)[A-Z])([a-z]))/g, "$1_$3$2$4").toLowerCase();
export function snakeCase(str: string): string{
return str
// ABc -> ab_c
.replace(/([A-Z])([A-Z])([a-z])/g, "$1_$2$3")
// aC -> a_c
.replace(/([a-z])([A-Z])/g, "$1_$2")
.toLowerCase();
}

/**
Expand Down
69 changes: 69 additions & 0 deletions test/functional/util/StringUtils.ts
@@ -0,0 +1,69 @@
import { expect } from "chai";
import { snakeCase } from "../../../src/util/StringUtils";

describe("StringUtils", () => {
describe("snakeCase", () => {
it("should convert camelcase to snakecase", () => {
const input = "camelCaseStringHere";
const expected = "camel_case_string_here";
const actual = snakeCase(input);

expect(actual).to.be.equal(expected, `Failed for Input: ${input}`);
});

it("should correctly convert an initial capital", () => {
const input = "CamelCaseStringHere";
const expected = "camel_case_string_here";
const actual = snakeCase(input);

expect(actual).to.be.equal(expected, `Failed for Input: ${input}`);
});

it("should correctly convert strings of capitals", () => {
const input = "testABCItem";
const expected = "test_abc_item";
const actual = snakeCase(input)

expect(actual).to.be.equal(expected, `Failed for Input: ${input}`);
});

it("should correctly convert repeating camelcase groups", () => {
const input = "optionAOrB";
const expected = "option_a_or_b";
const actual = snakeCase(input);

expect(actual).to.be.equal(expected, `Failed for Input: ${input}`);
});

it("should do nothing with strings that are already snakecase", () => {
const expected = "snake_case_string_here";
expect(snakeCase(expected)).to.be.equal(expected, expected);
});

it("should correctly convert mixed strings into snakecase", () => {
const input = "optionAOr_BOr_C";
const expected = "option_a_or_b_or_c";
const actual = snakeCase(input);

expect(actual).to.be.equal(expected, `Failed for Input: ${input}`);
});

it("should match the examples given in the older implementation", () => {
// Pulled from https://regex101.com/r/QeSm2I/1
const examples = {
"AbcItem": "abc_item",
"ABCItem": "abc_item",
"TestAbcItem": "test_abc_item",
"testABCItem": "test_abc_item",
"TestItemAbc": "test_item_abc",
"TestItemABC": "test_item_abc",
"abcItem": "abc_item",
};

for (const [ input, expected] of Object.entries(examples)) {
const actual = snakeCase(input);
expect(actual).to.be.equal(expected, `Failed for Input: ${input}`);
}
})
});
});

1 comment on commit eb680f9

@meganoob1337
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is Actually a Breaking change for our Repository
our Entity is named "Fail2Ban"
old implementation => fail2_ban
new Implementation => fail2ban

Please sign in to comment.