Skip to content

Reduce code duplication - #60

Merged
christianhelle merged 15 commits into
mainfrom
reduce-code-duplication
Jul 4, 2026
Merged

Reduce code duplication#60
christianhelle merged 15 commits into
mainfrom
reduce-code-duplication

Conversation

@christianhelle

@christianhelle christianhelle commented Jul 4, 2026

Copy link
Copy Markdown
Owner
  • Extract shared ident utilities to ident_utils.zig
  • Use shared ident_utils in api_generator.zig
  • Use shared ident_utils in model_generator.zig
  • Create generic parseArray helper
  • Use parseArray helper in v3.0/openapi.zig
  • Use parseArray helper in v3.1/openapi.zig
  • Use parseArray helper in v3.2/openapi.zig
  • Shim v3.1 externaldocs/tag/server to v3.0 (leaf nodes only)
  • Shim v3.2 externaldocs/tag/server to v3.0 (leaf nodes only)
  • Consolidate 4 generateCodeFrom wrappers into generic fn*
  • Consolidate lib.zig parseYaml and convertDocument wrappers

Summary by CodeRabbit

  • Refactor

    • Simplified document handling across supported OpenAPI versions by routing generation and parsing through shared paths.
    • Consolidated identifier validation and sanitization for more consistent generated names.
    • Reused common model definitions and parsing helpers across versions to reduce duplication.
  • Bug Fixes

    • Improved handling of arrays and identifiers during parsing and code generation, which should make generated output more consistent and reliable.

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@christianhelle, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 8 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dc88dbf6-7f9c-46b5-a9ab-fa7df7ec2fc1

📥 Commits

Reviewing files that changed from the base of the PR and between ff74aac and 5c0a387.

📒 Files selected for processing (5)
  • src/generators/unified/api_generator.zig
  • src/generators/unified/ident_utils.zig
  • src/generators/unified/model_generator.zig
  • src/lib.zig
  • src/models/common/parse_helpers.zig
📝 Walkthrough

Walkthrough

This PR refactors OpenAPI/Swagger code generation and parsing in Zig. generator.zig and lib.zig consolidate version-specific wrapper functions into generic helpers. A new ident_utils.zig centralizes identifier validation. A new parse_helpers.zig provides shared array parsing, and v3.1/v3.2 model files re-export v3.0 type definitions instead of duplicating them.

Changes

Generator and Library Dispatch Consolidation

Layer / File(s) Summary
Generic document generation
src/generator.zig
Replaces four version-specific generation wrappers with a single generic generateCodeFromDocument function parameterized by converter type.
Generic YAML parsing/conversion helpers
src/lib.zig
Introduces private parseYaml and convertDocument generics; exported YAML parse and unified-conversion functions now delegate to them.

Shared Identifier Utilities

Layer / File(s) Summary
New identifier validation module
src/generators/unified/ident_utils.zig
Adds isIdentStart, isIdentContinue, isReservedIdent, and isBareIdentifier functions.
API generator migration
src/generators/unified/api_generator.zig
Removes local identifier helpers and delegates appendIdentifier/sanitizeIdentifierAlloc to ident_utils.
Model generator migration
src/generators/unified/model_generator.zig
Removes local identifier helpers and delegates appendIdentifier, sanitizeIdentifierAlloc, and fieldTypeNameAlloc to ident_utils.

Model De-duplication Across OpenAPI Versions

Layer / File(s) Summary
Shared array parsing helper
src/models/common/parse_helpers.zig, src/models/v3.0/openapi.zig, src/models/v3.1/openapi.zig, src/models/v3.2/openapi.zig
Adds parseArray and updates servers/security/tags parsing in v3.0/v3.1/v3.2 to use it instead of manual loops.
v3.1/v3.2 model re-exports
src/models/v3.1/externaldocs.zig, src/models/v3.1/server.zig, src/models/v3.1/tag.zig, src/models/v3.2/externaldocs.zig, src/models/v3.2/server.zig, src/models/v3.2/tag.zig
Replaces local ExternalDocumentation, ServerVariable/Server, and Tag definitions with re-exports of the v3.0 types.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the refactor-focused changes that centralize repeated code into shared helpers and generic wrappers.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch reduce-code-duplication

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@christianhelle christianhelle self-assigned this Jul 4, 2026
@christianhelle christianhelle added the enhancement New feature or request label Jul 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/generators/unified/ident_utils.zig (2)

28-34: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider extracting the shared appendIdentifier writer too.

isBareIdentifier is consumed by two near-identical appendIdentifier implementations in api_generator.zig and model_generator.zig (escaping/quoting logic is byte-for-byte the same). Since this module already centralizes identifier classification, it could also host a generic appendIdentifier(buffer: *std.ArrayList(u8), allocator: std.mem.Allocator, name: []const u8) !void helper, letting both generators call a one-line wrapper instead of duplicating the ~20-line escape loop.

♻️ Proposed shared helper
 pub fn isBareIdentifier(name: []const u8) bool {
     if (name.len == 0 or !isIdentStart(name[0]) or isReservedIdent(name)) return false;
     for (name[1..]) |c| {
         if (!isIdentContinue(c)) return false;
     }
     return true;
 }
+
+pub fn appendIdentifier(buffer: *std.ArrayList(u8), allocator: std.mem.Allocator, name: []const u8) !void {
+    if (isBareIdentifier(name)) {
+        try buffer.appendSlice(allocator, name);
+        return;
+    }
+    try buffer.appendSlice(allocator, "@\"");
+    for (name) |c| {
+        switch (c) {
+            '\\', '"' => {
+                try buffer.append(allocator, '\\');
+                try buffer.append(allocator, c);
+            },
+            '\n' => try buffer.appendSlice(allocator, "\\n"),
+            '\r' => try buffer.appendSlice(allocator, "\\r"),
+            '\t' => try buffer.appendSlice(allocator, "\\t"),
+            else => try buffer.append(allocator, c),
+        }
+    }
+    try buffer.appendSlice(allocator, "\"");
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/generators/unified/ident_utils.zig` around lines 28 - 34, The identifier
handling is duplicated in the two `appendIdentifier` implementations, so
centralize that shared escaping/quoting logic alongside `isBareIdentifier` in
`ident_utils.zig`. Add a generic `appendIdentifier(buffer, allocator, name)`
helper there, then update the `api_generator.zig` and `model_generator.zig`
wrappers to delegate to it instead of keeping their own near-identical loops.
Keep the existing `isBareIdentifier` behavior unchanged and use the new shared
helper as the single source of truth for identifier output formatting.

1-34: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

No unit tests for the newly-shared identifier logic.

isIdentStart/isIdentContinue/isReservedIdent/isBareIdentifier now back identifier sanitization across both generators; a compact test block here would guard against regressions in generated Zig code's syntactic validity (e.g. reserved words, leading digits, non-ASCII bytes).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/generators/unified/ident_utils.zig` around lines 1 - 34, Add a small test
block for the shared identifier helpers in ident_utils.zig so the new logic is
covered. Create focused unit tests for isIdentStart, isIdentContinue,
isReservedIdent, and isBareIdentifier that verify reserved words, leading
digits, underscores, and non-ASCII bytes behave as expected. Keep the tests
close to the helper functions so future changes to identifier sanitization in
the generators are caught early.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib.zig`:
- Around line 258-261: `parseToUnified` still repeats the same converter
initialization and `convert` call pattern that `convertDocument` was added to
remove. Update `parseToUnified` to reuse `convertDocument` for each parser
branch instead of manually creating `PARSER.init(allocator)` and calling
`.convert(doc)` four times, referencing the existing `convertDocument` helper
and the parser-specific types used in `parseToUnified`.

In `@src/models/common/parse_helpers.zig`:
- Around line 4-11: The parseArray helper in parse_helpers.zig only frees the
ArrayList backing storage on failure, so partially parsed items are leaked if
T.parseFromJson errors mid-loop. Update parseArray to clean up each successfully
parsed element on error by iterating the accumulated items and calling their
deinit logic before deinitializing the list, using the item type T’s deinit
behavior if available. Keep the fix localized to parseArray so callers like the
OpenAPI parsers automatically get safe rollback for Server, Tag, and
SecurityRequirement parsing.

---

Nitpick comments:
In `@src/generators/unified/ident_utils.zig`:
- Around line 28-34: The identifier handling is duplicated in the two
`appendIdentifier` implementations, so centralize that shared escaping/quoting
logic alongside `isBareIdentifier` in `ident_utils.zig`. Add a generic
`appendIdentifier(buffer, allocator, name)` helper there, then update the
`api_generator.zig` and `model_generator.zig` wrappers to delegate to it instead
of keeping their own near-identical loops. Keep the existing `isBareIdentifier`
behavior unchanged and use the new shared helper as the single source of truth
for identifier output formatting.
- Around line 1-34: Add a small test block for the shared identifier helpers in
ident_utils.zig so the new logic is covered. Create focused unit tests for
isIdentStart, isIdentContinue, isReservedIdent, and isBareIdentifier that verify
reserved words, leading digits, underscores, and non-ASCII bytes behave as
expected. Keep the tests close to the helper functions so future changes to
identifier sanitization in the generators are caught early.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e86f1139-359b-4dd5-bdc4-26e3bd0bfe4c

📥 Commits

Reviewing files that changed from the base of the PR and between d2e7b67 and ff74aac.

📒 Files selected for processing (15)
  • src/generator.zig
  • src/generators/unified/api_generator.zig
  • src/generators/unified/ident_utils.zig
  • src/generators/unified/model_generator.zig
  • src/lib.zig
  • src/models/common/parse_helpers.zig
  • src/models/v3.0/openapi.zig
  • src/models/v3.1/externaldocs.zig
  • src/models/v3.1/openapi.zig
  • src/models/v3.1/server.zig
  • src/models/v3.1/tag.zig
  • src/models/v3.2/externaldocs.zig
  • src/models/v3.2/openapi.zig
  • src/models/v3.2/server.zig
  • src/models/v3.2/tag.zig

Comment thread src/lib.zig
Comment thread src/models/common/parse_helpers.zig
@christianhelle
christianhelle merged commit 99f3e54 into main Jul 4, 2026
17 checks passed
@christianhelle
christianhelle deleted the reduce-code-duplication branch July 4, 2026 22:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant