Skip to content

Commit 8163bac

Browse files
authored
Fix broken camelCase normalisation in src/codegen (#884)
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent 90c9d98 commit 8163bac

11 files changed

Lines changed: 249 additions & 43 deletions

File tree

src/codegen/codegen_mangle.cc

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,26 @@ auto symbol_to_identifier(const std::string_view prefix,
2828
continue;
2929
}
3030

31-
bool first_in_segment{true};
31+
bool at_word_start{true};
32+
bool at_segment_start{true};
3233
for (const auto character : segment) {
3334
if (is_alpha(character)) {
34-
if (first_in_segment) {
35-
result += to_upper(character);
36-
first_in_segment = false;
37-
} else {
38-
result += character;
39-
}
35+
result += at_word_start ? to_upper(character) : character;
36+
at_word_start = false;
37+
at_segment_start = false;
4038
} else if (is_digit(character)) {
41-
if (first_in_segment) {
39+
if (at_segment_start) {
4240
result += '_';
4341
}
4442
result += character;
45-
first_in_segment = false;
43+
at_word_start = false;
44+
at_segment_start = false;
4645
} else if (character == '_' || character == '$') {
4746
result += character;
48-
first_in_segment = false;
47+
at_word_start = false;
48+
at_segment_start = false;
49+
} else {
50+
at_word_start = true;
4951
}
5052
}
5153
}

test/codegen/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
sourcemeta_googletest(NAMESPACE sourcemeta PROJECT blaze NAME codegen
22
FOLDER "Blaze/Codegen"
33
SOURCES codegen_test.cc codegen_2020_12_test.cc
4-
codegen_symbol_test.cc codegen_test_utils.h)
4+
codegen_symbol_test.cc codegen_mangle_test.cc codegen_test_utils.h)
55

66
target_link_libraries(sourcemeta_blaze_codegen_unit
77
PRIVATE sourcemeta::blaze::codegen)
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
#include <gtest/gtest.h>
2+
3+
#include <sourcemeta/blaze/codegen.h>
4+
5+
#include <map> // std::map
6+
#include <string> // std::string
7+
#include <vector> // std::vector
8+
9+
TEST(Codegen_mangle, prefix_only_no_symbol) {
10+
std::map<std::string, sourcemeta::core::Pointer> cache;
11+
const sourcemeta::core::Pointer pointer{};
12+
EXPECT_EQ(sourcemeta::blaze::mangle("Schema", pointer,
13+
std::vector<std::string>{}, cache),
14+
"Schema");
15+
}
16+
17+
TEST(Codegen_mangle, single_lowercase_word) {
18+
std::map<std::string, sourcemeta::core::Pointer> cache;
19+
const sourcemeta::core::Pointer pointer{};
20+
EXPECT_EQ(sourcemeta::blaze::mangle(
21+
"Schema", pointer, std::vector<std::string>{"address"}, cache),
22+
"SchemaAddress");
23+
}
24+
25+
TEST(Codegen_mangle, single_already_capitalized_word) {
26+
std::map<std::string, sourcemeta::core::Pointer> cache;
27+
const sourcemeta::core::Pointer pointer{};
28+
EXPECT_EQ(sourcemeta::blaze::mangle(
29+
"Schema", pointer, std::vector<std::string>{"Address"}, cache),
30+
"SchemaAddress");
31+
}
32+
33+
TEST(Codegen_mangle, hyphenated_two_words) {
34+
std::map<std::string, sourcemeta::core::Pointer> cache;
35+
const sourcemeta::core::Pointer pointer{};
36+
EXPECT_EQ(sourcemeta::blaze::mangle(
37+
"Schema", pointer,
38+
std::vector<std::string>{"structured-address"}, cache),
39+
"SchemaStructuredAddress");
40+
}
41+
42+
TEST(Codegen_mangle, hyphenated_three_words) {
43+
std::map<std::string, sourcemeta::core::Pointer> cache;
44+
const sourcemeta::core::Pointer pointer{};
45+
EXPECT_EQ(
46+
sourcemeta::blaze::mangle(
47+
"Schema", pointer, std::vector<std::string>{"very-long-name"}, cache),
48+
"SchemaVeryLongName");
49+
}
50+
51+
TEST(Codegen_mangle, dot_separator) {
52+
std::map<std::string, sourcemeta::core::Pointer> cache;
53+
const sourcemeta::core::Pointer pointer{};
54+
EXPECT_EQ(sourcemeta::blaze::mangle("Schema", pointer,
55+
std::vector<std::string>{"user.profile"},
56+
cache),
57+
"SchemaUserProfile");
58+
}
59+
60+
TEST(Codegen_mangle, whitespace_separator) {
61+
std::map<std::string, sourcemeta::core::Pointer> cache;
62+
const sourcemeta::core::Pointer pointer{};
63+
EXPECT_EQ(sourcemeta::blaze::mangle(
64+
"Schema", pointer,
65+
std::vector<std::string>{"structured address"}, cache),
66+
"SchemaStructuredAddress");
67+
}
68+
69+
TEST(Codegen_mangle, mixed_separators) {
70+
std::map<std::string, sourcemeta::core::Pointer> cache;
71+
const sourcemeta::core::Pointer pointer{};
72+
EXPECT_EQ(sourcemeta::blaze::mangle(
73+
"Schema", pointer, std::vector<std::string>{"a-b.c d"}, cache),
74+
"SchemaABCD");
75+
}
76+
77+
TEST(Codegen_mangle, consecutive_separators) {
78+
std::map<std::string, sourcemeta::core::Pointer> cache;
79+
const sourcemeta::core::Pointer pointer{};
80+
EXPECT_EQ(sourcemeta::blaze::mangle("Schema", pointer,
81+
std::vector<std::string>{"a--b"}, cache),
82+
"SchemaAB");
83+
}
84+
85+
TEST(Codegen_mangle, leading_separator) {
86+
std::map<std::string, sourcemeta::core::Pointer> cache;
87+
const sourcemeta::core::Pointer pointer{};
88+
EXPECT_EQ(sourcemeta::blaze::mangle("Schema", pointer,
89+
std::vector<std::string>{"-abc"}, cache),
90+
"SchemaAbc");
91+
}
92+
93+
TEST(Codegen_mangle, trailing_separator) {
94+
std::map<std::string, sourcemeta::core::Pointer> cache;
95+
const sourcemeta::core::Pointer pointer{};
96+
EXPECT_EQ(sourcemeta::blaze::mangle("Schema", pointer,
97+
std::vector<std::string>{"abc-"}, cache),
98+
"SchemaAbc");
99+
}
100+
101+
TEST(Codegen_mangle, multiple_segments_with_hyphen) {
102+
std::map<std::string, sourcemeta::core::Pointer> cache;
103+
const sourcemeta::core::Pointer pointer{};
104+
EXPECT_EQ(sourcemeta::blaze::mangle(
105+
"Schema", pointer,
106+
std::vector<std::string>{"user", "structured-address"}, cache),
107+
"SchemaUserStructuredAddress");
108+
}
109+
110+
TEST(Codegen_mangle, digit_inside_word) {
111+
std::map<std::string, sourcemeta::core::Pointer> cache;
112+
const sourcemeta::core::Pointer pointer{};
113+
EXPECT_EQ(sourcemeta::blaze::mangle("Schema", pointer,
114+
std::vector<std::string>{"line1"}, cache),
115+
"SchemaLine1");
116+
}
117+
118+
TEST(Codegen_mangle, segment_starting_with_digit) {
119+
std::map<std::string, sourcemeta::core::Pointer> cache;
120+
const sourcemeta::core::Pointer pointer{};
121+
EXPECT_EQ(sourcemeta::blaze::mangle("Schema", pointer,
122+
std::vector<std::string>{"2fa"}, cache),
123+
"Schema_2fa");
124+
}
125+
126+
TEST(Codegen_mangle, digit_after_separator) {
127+
std::map<std::string, sourcemeta::core::Pointer> cache;
128+
const sourcemeta::core::Pointer pointer{};
129+
EXPECT_EQ(sourcemeta::blaze::mangle("Schema", pointer,
130+
std::vector<std::string>{"a-2b"}, cache),
131+
"SchemaA2b");
132+
}
133+
134+
TEST(Codegen_mangle, underscore_preserved) {
135+
std::map<std::string, sourcemeta::core::Pointer> cache;
136+
const sourcemeta::core::Pointer pointer{};
137+
EXPECT_EQ(sourcemeta::blaze::mangle(
138+
"Schema", pointer, std::vector<std::string>{"foo_bar"}, cache),
139+
"SchemaFoo_bar");
140+
}
141+
142+
TEST(Codegen_mangle, dollar_preserved) {
143+
std::map<std::string, sourcemeta::core::Pointer> cache;
144+
const sourcemeta::core::Pointer pointer{};
145+
EXPECT_EQ(sourcemeta::blaze::mangle("Schema", pointer,
146+
std::vector<std::string>{"$ref"}, cache),
147+
"Schema$ref");
148+
}
149+
150+
TEST(Codegen_mangle, empty_segment_skipped) {
151+
std::map<std::string, sourcemeta::core::Pointer> cache;
152+
const sourcemeta::core::Pointer pointer{};
153+
EXPECT_EQ(sourcemeta::blaze::mangle(
154+
"Schema", pointer, std::vector<std::string>{"", "name"}, cache),
155+
"SchemaName");
156+
}
157+
158+
TEST(Codegen_mangle, segment_of_only_separators) {
159+
std::map<std::string, sourcemeta::core::Pointer> cache;
160+
const sourcemeta::core::Pointer pointer{};
161+
EXPECT_EQ(sourcemeta::blaze::mangle("Schema", pointer,
162+
std::vector<std::string>{"---"}, cache),
163+
"Schema");
164+
}
165+
166+
TEST(Codegen_mangle, acronym_preserved) {
167+
std::map<std::string, sourcemeta::core::Pointer> cache;
168+
const sourcemeta::core::Pointer pointer{};
169+
EXPECT_EQ(sourcemeta::blaze::mangle("Schema", pointer,
170+
std::vector<std::string>{"HTTPServer"},
171+
cache),
172+
"SchemaHTTPServer");
173+
}
174+
175+
TEST(Codegen_mangle, other_characters_dropped_as_boundary) {
176+
std::map<std::string, sourcemeta::core::Pointer> cache;
177+
const sourcemeta::core::Pointer pointer{};
178+
EXPECT_EQ(sourcemeta::blaze::mangle(
179+
"Schema", pointer, std::vector<std::string>{"foo@bar"}, cache),
180+
"SchemaFooBar");
181+
}
182+
183+
TEST(Codegen_mangle, collision_same_pointer_returns_same_name) {
184+
std::map<std::string, sourcemeta::core::Pointer> cache;
185+
const sourcemeta::core::Pointer pointer{"a"};
186+
EXPECT_EQ(sourcemeta::blaze::mangle(
187+
"Schema", pointer, std::vector<std::string>{"address"}, cache),
188+
"SchemaAddress");
189+
EXPECT_EQ(sourcemeta::blaze::mangle(
190+
"Schema", pointer, std::vector<std::string>{"address"}, cache),
191+
"SchemaAddress");
192+
}
193+
194+
TEST(Codegen_mangle, collision_different_pointer_gets_prefixed) {
195+
std::map<std::string, sourcemeta::core::Pointer> cache;
196+
const sourcemeta::core::Pointer first{"a"};
197+
const sourcemeta::core::Pointer second{"b"};
198+
EXPECT_EQ(sourcemeta::blaze::mangle(
199+
"Schema", first, std::vector<std::string>{"address"}, cache),
200+
"SchemaAddress");
201+
EXPECT_EQ(sourcemeta::blaze::mangle(
202+
"Schema", second, std::vector<std::string>{"address"}, cache),
203+
"_SchemaAddress");
204+
}
Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
export type TestWithus = string;
1+
export type TestWithUs = string;
22

3-
export type TestWithformfeed = string;
3+
export type TestWithFormfeed = string;
44

5-
export type TestWithbackspace = string;
5+
export type TestWithBackspace = string;
66

7-
export type TestWithsoh = string;
7+
export type TestWithSoh = string;
88

9-
export type TestWithnull = string;
9+
export type TestWithNull = string;
1010

1111
export type TestNormal = string;
1212

1313
export type TestAdditionalProperties = never;
1414

1515
export interface Test {
1616
"normal"?: TestNormal;
17-
"with\bbackspace"?: TestWithbackspace;
18-
"with\fformfeed"?: TestWithformfeed;
19-
"with\u0000null"?: TestWithnull;
20-
"with\u0001soh"?: TestWithsoh;
21-
"with\u001fus"?: TestWithus;
17+
"with\bbackspace"?: TestWithBackspace;
18+
"with\fformfeed"?: TestWithFormfeed;
19+
"with\u0000null"?: TestWithNull;
20+
"with\u0001soh"?: TestWithSoh;
21+
"with\u001fus"?: TestWithUs;
2222
}

test/codegen/e2e/typescript/2020-12/pattern_properties_non_prefix_additional_false/expected.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export type StrictFallbackName = string;
22

3-
export type StrictFallbackAz_id = number;
3+
export type StrictFallbackAZ_id = number;
44

55
export type StrictFallbackAdditionalProperties = never;
66

@@ -11,6 +11,6 @@ export interface StrictFallback {
1111
// to also include the types of all of its properties, so we must
1212
// match a superset of what JSON Schema allows
1313
StrictFallbackName |
14-
StrictFallbackAz_id |
14+
StrictFallbackAZ_id |
1515
undefined;
1616
}

test/codegen/e2e/typescript/2020-12/pattern_properties_non_prefix_fallback/expected.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export type FallbackName = string;
22

3-
export type FallbackAz_id = number;
3+
export type FallbackAZ_id = number;
44

55
export interface Fallback {
66
"name"?: FallbackName;

test/codegen/e2e/typescript/2020-12/pattern_properties_non_prefix_only/expected.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export type NonPrefixAz_id = number;
1+
export type NonPrefixAZ_id = number;
22

33
export interface NonPrefix {
44
[key: string]: unknown | undefined;
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
export type OverlapXdata = number;
1+
export type OverlapXData = number;
22

33
export type OverlapX = string;
44

55
export type OverlapAdditionalProperties = never;
66

77
export interface Overlap {
88
[key: `x-${string}`]: OverlapX;
9-
[key: `x-data-${string}`]: OverlapXdata & OverlapX;
9+
[key: `x-data-${string}`]: OverlapXData & OverlapX;
1010
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
export type SameTypeXdata = string;
1+
export type SameTypeXData = string;
22

33
export type SameTypeX = string;
44

55
export type SameTypeAdditionalProperties = never;
66

77
export interface SameType {
88
[key: `x-${string}`]: SameTypeX;
9-
[key: `x-data-${string}`]: SameTypeXdata & SameTypeX;
9+
[key: `x-data-${string}`]: SameTypeXData & SameTypeX;
1010
}

test/codegen/e2e/typescript/2020-12/pattern_properties_partial_overlap/expected.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export type PartialId = number;
22

33
export type PartialY = number;
44

5-
export type PartialXinternal = boolean;
5+
export type PartialXInternal = boolean;
66

77
export type PartialX = string;
88

@@ -11,6 +11,6 @@ export type PartialAdditionalProperties = never;
1111
export interface Partial {
1212
"id": PartialId;
1313
[key: `x-${string}`]: PartialX;
14-
[key: `x-internal-${string}`]: PartialXinternal & PartialX;
14+
[key: `x-internal-${string}`]: PartialXInternal & PartialX;
1515
[key: `y-${string}`]: PartialY;
1616
}

0 commit comments

Comments
 (0)