Skip to content

Commit 9039e83

Browse files
mridangclaude
andcommitted
fix: align serializers, header selectors, and auth classes across all 12 languages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ff5cb88 commit 9039e83

96 files changed

Lines changed: 1283 additions & 219 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/settings.local.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,14 @@
674674
"Bash(gh run view 24818838545 --log-failed 2>&1 | tail -80)",
675675
"Bash(gh run view 24818838545 --log-failed 2>&1 | grep -E \"^\\\\S+\\\\s+\\\\S+\\\\s+.*error:\" | head -10)",
676676
"Bash(git add pom.xml src/main/java/io/github/mridang/codegen/generators/AbstractBetterCodegen.java && git commit --amend --no-edit && git push --force)",
677-
"Bash(git add -A && git commit --amend --no-edit && git push --force)"
677+
"Bash(git add -A && git commit --amend --no-edit && git push --force)",
678+
"Bash(if grep -q '{{>api_info}}' \"src/main/resources/templates/csharp/test/tests_csproj.mustache\" 2>/dev/null; then echo \"BAD: tests_csproj has api_info\"; else echo \"OK: tests_csproj excluded\"; fi)",
679+
"Bash(git stash && devbox run -- mvn test -Dtest=\"GenerateClientsTest#generateRustClient\" -pl . -q 2>&1 | tail -5)",
680+
"Bash(git commit -m \"$\\(cat <<'EOF'\nchore: remove redundant codegen smoke tests\n\nThese tests duplicated what GenerateClientsTest already covers by\nrunning the generator into a temp directory and discarding the output.\nGenerateClientsTest exercises the same code path for all 12 languages.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>\nEOF\n\\)\" && git push)"
678681
]
682+
},
683+
"sandbox": {
684+
"enabled": true,
685+
"autoAllowBashIfSandboxed": true
679686
}
680687
}

src/main/java/io/github/mridang/codegen/generators/node/BetterNodeCodegen.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -662,28 +662,28 @@ protected void registerAuthSupportingFiles() {
662662
"base-authenticator.ts"));
663663
supportingFiles.add(
664664
new SupportingFile(
665-
"auth/http_aware_authenticator.mustache",
665+
"auth/http-aware-authenticator.mustache",
666666
authFolder,
667667
"http-aware-authenticator.ts"));
668668

669669
if (hasBasicAuth) {
670670
supportingFiles.add(
671671
new SupportingFile(
672-
"auth/basic_authenticator.mustache",
672+
"auth/basic-authenticator.mustache",
673673
authFolder,
674674
"basic-authenticator.ts"));
675675
}
676676
if (hasBearerAuth) {
677677
supportingFiles.add(
678678
new SupportingFile(
679-
"auth/bearer_authenticator.mustache",
679+
"auth/bearer-authenticator.mustache",
680680
authFolder,
681681
"bearer-authenticator.ts"));
682682
}
683683
if (hasApiKeyAuth) {
684684
supportingFiles.add(
685685
new SupportingFile(
686-
"auth/api_key_authenticator.mustache",
686+
"auth/api-key-authenticator.mustache",
687687
authFolder,
688688
"api-key-authenticator.ts"));
689689
supportingFiles.add(

src/main/resources/templates/csharp/api/api.mustache

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ public class {{classname}} : BaseApi
342342
{{#hasFormParams}}formBody{{/hasFormParams}}{{^hasFormParams}}{{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}{{/hasFormParams}},
343343
{{^produces}} [],{{/produces}}{{#produces}}{{#-first}} {{operationId}}Accepts,{{/-first}}{{/produces}}
344344
{{#consumes.0}}"{{{mediaType}}}"{{/consumes.0}}{{^consumes}}"application/json"{{/consumes}},
345+
{{#returnType}}typeof({{{returnType}}}){{/returnType}}{{^returnType}}null{{/returnType}},
345346
{{#hasAuthMethods}}auth{{/hasAuthMethods}}{{^hasAuthMethods}}null{{/hasAuthMethods}}
346347
)
347348
.ConfigureAwait(false);

src/main/resources/templates/csharp/base_api.mustache

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ public abstract class BaseApi
6565
object? body,
6666
string[] accepts,
6767
string contentType,
68+
Type? returnType,
6869
IAuthenticator? auth = null
6970
)
7071
{
@@ -187,7 +188,7 @@ public abstract class BaseApi
187188
}
188189

189190
T? data = default;
190-
if (!string.IsNullOrEmpty(response.Body))
191+
if (returnType != null && !string.IsNullOrEmpty(response.Body))
191192
{
192193
string? responseContentType = response
193194
.Headers.Where(h =>
@@ -231,6 +232,7 @@ public abstract class BaseApi
231232
object? body,
232233
string[] accepts,
233234
string contentType,
235+
Type? returnType,
234236
IAuthenticator? auth = null
235237
)
236238
{
@@ -242,6 +244,7 @@ public abstract class BaseApi
242244
body,
243245
accepts,
244246
contentType,
247+
returnType,
245248
auth
246249
)
247250
.ConfigureAwait(false);

src/main/resources/templates/csharp/test/BaseApiTest.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public class BaseApiTest
3636
{
3737
return await InvokeApiAsync<T>(
3838
method, path, queryParams, headerParams, body,
39-
accepts, contentType, auth);
39+
accepts, contentType, typeof(T), auth);
4040
}
4141
}
4242

src/main/resources/templates/csharp/test/ValueSerializerTest.mustache

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,19 @@ public class ValueSerializerTest
322322
Assert.Equal(new List<string> { "blue", "black" }, result);
323323
}
324324

325+
[Fact]
326+
public void FormStyleScalarExplodeTrueReturnsStringNotList()
327+
{
328+
Assert.Equal("blue", ValueSerializer.SerializeStyled("color", "blue", "query", "string", null, "form", true));
329+
}
330+
331+
[Fact]
332+
public void FormStyleSingleElementArrayExplodeTrueReturnsList()
333+
{
334+
var result = ValueSerializer.SerializeStyled("color", new List<object> { "blue" }, "query", "array", null, "form", true);
335+
Assert.Equal(new List<string> { "blue" }, result);
336+
}
337+
325338
// -- serializeStyled: simple style backward compatibility --
326339

327340
[Fact]
@@ -336,6 +349,12 @@ public class ValueSerializerTest
336349
Assert.Equal("3,4,5", ValueSerializer.SerializeStyled("id", new List<object> { "3", "4", "5" }, "path", "array", null, "simple", false));
337350
}
338351

352+
[Fact]
353+
public void SimpleStyleScalarDoesNotUrlEncodePath()
354+
{
355+
Assert.Equal("hello world", ValueSerializer.SerializeStyled("id", "hello world", "path", "string", null, "simple", false));
356+
}
357+
339358
// -- serializeStyled: null style falls back to location default --
340359

341360
[Fact]

src/main/resources/templates/csharp/value_serializer.mustache

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,7 @@ public static class ValueSerializer
142142
{
143143
return string.Join(",", items);
144144
}
145-
string str = ObjectSerializer.Stringify(value);
146-
return location == "path" ? Uri.EscapeDataString(str) : str;
145+
return ObjectSerializer.Stringify(value);
147146
}
148147
}
149148

src/main/resources/templates/dart/header_selector.mustache

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import 'dart:math';
44
/// HeaderSelector selects Accept and Content-Type headers for API requests
55
/// based on the MIME types declared in the OpenAPI specification.
66
class HeaderSelector {
7-
static final _jsonMIMEPattern = RegExp(r'^application/(json|[\w!#$&.+\-^_]+\+json)\s*(;|$)');
7+
static final _jsonMIMEPattern = RegExp(r'^application/(json|[\w!#$&.+\-^_]+\+json)\s*(;|$)', caseSensitive: false);
88
static final _weightPattern = RegExp(r'(.*)\s*;\s*q=(1(?:\.0+)?|0\.\d+)$');
99
1010
/// Selects the Accept and Content-Type headers for an API request.
@@ -40,7 +40,7 @@ class HeaderSelector {
4040
return _jsonMIMEPattern.hasMatch(searchString);
4141
}
4242

43-
int _getNextWeight(int currentWeight, bool hasMoreThan28Headers) {
43+
int getNextWeight(int currentWeight, bool hasMoreThan28Headers) {
4444
if (currentWeight <= 1) return 1;
4545
if (hasMoreThan28Headers) return currentWeight - 1;
4646
@@ -120,12 +120,12 @@ class HeaderSelector {
120120
final acceptHeaders = <String>[];
121121
for (var i = 0; i < headers.length; i++) {
122122
if (i > 0 && headers[i - 1].weight > headers[i].weight) {
123-
weight = _getNextWeight(weight, hasMoreThan28Headers);
123+
weight = getNextWeight(weight, hasMoreThan28Headers);
124124
}
125125
acceptHeaders.add(_buildAcceptHeader(headers[i].header, weight));
126126
}
127127

128-
weight = _getNextWeight(weight, hasMoreThan28Headers);
128+
weight = getNextWeight(weight, hasMoreThan28Headers);
129129
return _AdjustResult(acceptHeaders, weight);
130130
}
131131

src/main/resources/templates/dart/object_serializer.mustache

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,7 @@ String stringify(Object? value) {
8888
if (value is DateTime) return value.toIso8601String();
8989
if (value is String) return value;
9090
if (value is int) return value.toString();
91-
if (value is double) {
92-
if (value == value.truncateToDouble()) {
93-
return value.toInt().toString();
94-
}
95-
return value.toString();
96-
}
91+
if (value is double) return value.toString();
9792
9893
return value.toString();
9994
}

src/main/resources/templates/dart/test/header_selector_test.mustache

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,48 @@ void main() {
105105
106106
expect(headers['Accept'], contains('application/vnd.api+json'));
107107
});
108+
109+
test('isJsonMime case insensitive', () {
110+
final hs = HeaderSelector();
111+
112+
expect(hs.isJsonMime('APPLICATION/JSON'), isTrue);
113+
});
114+
115+
test('getNextWeight standard sequence', () {
116+
final hs = HeaderSelector();
117+
118+
expect(hs.getNextWeight(1000, false), equals(900));
119+
expect(hs.getNextWeight(900, false), equals(800));
120+
expect(hs.getNextWeight(200, false), equals(100));
121+
expect(hs.getNextWeight(100, false), equals(90));
122+
expect(hs.getNextWeight(90, false), equals(80));
123+
});
124+
125+
test('getNextWeight more than 28 headers', () {
126+
final hs = HeaderSelector();
127+
128+
expect(hs.getNextWeight(1000, true), equals(999));
129+
expect(hs.getNextWeight(999, true), equals(998));
130+
expect(hs.getNextWeight(998, true), equals(997));
131+
});
132+
133+
test('getNextWeight minimum', () {
134+
final hs = HeaderSelector();
135+
136+
expect(hs.getNextWeight(1, false), equals(1));
137+
expect(hs.getNextWeight(0, false), equals(1));
138+
expect(hs.getNextWeight(-1, false), equals(1));
139+
});
140+
141+
test('getNextWeight 27 steps from 1000 to 1', () {
142+
final hs = HeaderSelector();
143+
144+
var weight = 1000;
145+
for (var i = 0; i < 27; i++) {
146+
weight = hs.getNextWeight(weight, false);
147+
}
148+
expect(weight, equals(1));
149+
});
108150
});
109151
}
110152
{{/generateTests}}

0 commit comments

Comments
 (0)