Skip to content

feat(core): add tagsSplitDeduplication option for barrel + shared type extraction#3558

Merged
melloware merged 2 commits into
orval-labs:masterfrom
aqeelat:feat/3553/tags-split-barrel-index
Jun 23, 2026
Merged

feat(core): add tagsSplitDeduplication option for barrel + shared type extraction#3558
melloware merged 2 commits into
orval-labs:masterfrom
aqeelat:feat/3553/tags-split-barrel-index

Conversation

@aqeelat

@aqeelat aqeelat commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Problem

Fix #3553, #3108

When using mode: "tags-split", orval generates per-tag subdirectories but creates no barrel index.ts at the target root. A naive barrel (export * from each tag) fails because fetch-based clients emit HTTPStatusCode* types into every tag file, causing TS2308 duplicate export errors.

Solution

New tagsSplitDeduplication option (default: false) that:

  1. Extracts shared types emitted by client header builders into <commonTypesFileName>.ts (default: common-types.ts)
  2. Generates barrel index.ts with named re-exports for public shared types + export * for per-tag files
  3. Adds imports to per-tag files so they reference the common types

Configuration

output: {
  mode: 'tags-split',
  indexFiles: true,                // required for barrel
  tagsSplitDeduplication: true,    // enables extraction + barrel
  commonTypesFileName: 'shared',   // optional, default: 'common-types'
}

Resulting structure

<target>/
  common-types.ts        # extracted shared types (when duplicates exist)
  index.ts               # barrel with named re-exports + wildcard exports
  pets/
    pets.ts              # import type { HTTPStatusCode2xx } from '../common-types'
  health/
    health.ts            # import type { HTTPStatusCode2xx } from '../common-types'

Behavior matrix

tagsSplitDeduplication indexFiles Shared types? Result
false (default) any any Current behavior — no barrel, no extraction
true true yes common-types.ts + barrel with named re-exports
true true no Barrel with export * only (no common-types)
true false yes common-types.ts extracted, no barrel
true false no Nothing (identical to current behavior)

Suppressed when output.workspace is set (workspace barrel handles it).

Implementation

  • ClientHeaderBuilder return type widened from string to string | HeaderResult (backward compatible)
  • generateFetchHeader now returns sharedTypes for HTTPStatusCode* instead of inlining them
  • generateClientHeader normalizes both return forms into GeneratorClientExtra
  • generateTargetForTags inlines shared types back when dedup is off, passes them through when on
  • writeSplitTagsMode collects, deduplicates, writes common-types.ts, generates barrel

Currently only generateFetchHeader emits sharedTypes. The mechanism is generic — other header builders (angular HttpClientOptions, etc.) can adopt it incrementally in follow-up PRs.

Design discussion

See issue comment for the full design discussion including:

  • Why export * barrels fail (HTTPStatusCode collision in 13 fetch-based configs)
  • Why a new option instead of reusing indexFiles
  • Why non-exported types (HttpClientOptions) are deferred to a follow-up

Closes #3553

Summary by CodeRabbit

  • New Features
    • Added tagsSplitDeduplication (default false) for tags-split mode to extract shared infrastructure types into a common-types.ts file.
    • Added commonTypesFileName (default 'common-types') to control the shared-types filename.
    • When enabled with indexFiles: true (and not in workspace mode), generates a root index.ts barrel with named + re-export entries.
  • Tests
    • Added regression coverage for shared-types and barrel generation/omission behavior.
  • Documentation
    • Updated output configuration docs (including Chinese reference) for the new options.

Copilot AI review requested due to automatic review settings June 6, 2026 19:32
@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bd8efd5c-ad52-4df7-a390-85dfa2a78861

📥 Commits

Reviewing files that changed from the base of the PR and between ca3d6c5 and 4e8a1bf.

⛔ Files ignored due to path filters (66)
  • samples/react-app-with-swr/basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.ts is excluded by !**/__snapshots__/**
  • samples/react-query/custom-fetch/__snapshots__/pets/pets.ts is excluded by !**/__snapshots__/**
  • samples/react-query/custom-fetch/src/gen/pets/pets.ts is excluded by !**/gen/**
  • samples/react-query/form-data-mutator/__snapshots__/endpoints.ts is excluded by !**/__snapshots__/**
  • samples/react-query/hook-mutator-fetch/__snapshots__/endpoints.ts is excluded by !**/__snapshots__/**
  • samples/svelte-query/custom-fetch/__snapshots__/pets/pets.ts is excluded by !**/__snapshots__/**
  • samples/svelte-query/custom-fetch/src/gen/pets/pets.ts is excluded by !**/gen/**
  • samples/svelte-query/v6-custom-fetch/__snapshots__/pets/pets.ts is excluded by !**/__snapshots__/**
  • samples/svelte-query/v6-custom-fetch/src/gen/pets/pets.ts is excluded by !**/gen/**
  • samples/vue-query/custom-fetch/__snapshots__/pets/pets.ts is excluded by !**/__snapshots__/**
  • samples/vue-query/custom-fetch/src/gen/pets/pets.ts is excluded by !**/gen/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/common-types.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/health/health.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/index.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/cat.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/catType.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/createPetsBody.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/createPetsParams.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/createPetsSort.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/dachshund.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/dachshundBreed.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/dog.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/dogType.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/error.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/index.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/labradoodle.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/labradoodleBreed.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/listPetsParams.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/listPetsSort.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/pet.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/petCallingCode.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/petCountry.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/petWithTag.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/model/pets.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/fetch/petstore-tags-split-deduplication/pets/pets.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/mcp/custom-server/http-client.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/mcp/single/http-client.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/mcp/zod-schema-response/http-client.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/http-client-fetch-with-custom-fetch/endpoints.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/common-types.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/health/health.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/index.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/cat.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/catType.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/createPetsBody.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/createPetsParams.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/createPetsSort.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/dachshund.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/dachshundBreed.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/dog.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/dogType.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/error.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/index.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/labradoodle.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/labradoodleBreed.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/listPetsParams.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/listPetsSort.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/pet.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/petCallingCode.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/petCountry.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/petWithTag.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/model/pets.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/react-query/petstore-tags-split-deduplication/pets/pets.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/svelte-query/http-client-fetch-with-custom-fetch/endpoints.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/swr/http-client-fetch-with-custom-fetch/endpoints.ts is excluded by !**/__snapshots__/**
  • tests/__snapshots__/vue-query/http-client-fetch-with-custom-fetch/endpoints.ts is excluded by !**/__snapshots__/**
📒 Files selected for processing (27)
  • docs/content/docs/reference/configuration/output.mdx
  • docs/content/docs/zh/reference/configuration/output.mdx
  • packages/angular/src/http-client.test.ts
  • packages/angular/src/http-resource.test.ts
  • packages/core/src/test-utils/context.ts
  • packages/core/src/test-utils/split-modes.ts
  • packages/core/src/types.ts
  • packages/core/src/writers/split-tags-mode.test.ts
  • packages/core/src/writers/split-tags-mode.ts
  • packages/core/src/writers/target-tags.ts
  • packages/core/src/writers/target.ts
  • packages/fetch/src/index.ts
  • packages/mcp/src/index.ts
  • packages/mock/src/faker/getters/combine.test.ts
  • packages/orval/src/client.ts
  • packages/orval/src/utils/options.ts
  • packages/query/src/frameworks/react.test.ts
  • packages/query/src/index.ts
  • packages/solid-start/src/index.test.ts
  • packages/swr/src/index.ts
  • samples/mcp/custom-server/src/http-client.ts
  • samples/mcp/petstore/src/http-client.ts
  • samples/react-app-with-swr/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.ts
  • samples/react-query/form-data-mutator/endpoints.ts
  • samples/react-query/hook-mutator-fetch/endpoints.ts
  • tests/configs/fetch.config.ts
  • tests/configs/react-query.config.ts
💤 Files with no reviewable changes (2)
  • samples/mcp/petstore/src/http-client.ts
  • samples/mcp/custom-server/src/http-client.ts
✅ Files skipped from review due to trivial changes (9)
  • packages/core/src/test-utils/context.ts
  • tests/configs/fetch.config.ts
  • packages/orval/src/utils/options.ts
  • samples/react-query/hook-mutator-fetch/endpoints.ts
  • docs/content/docs/zh/reference/configuration/output.mdx
  • samples/react-app-with-swr/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.ts
  • packages/mock/src/faker/getters/combine.test.ts
  • docs/content/docs/reference/configuration/output.mdx
  • samples/react-query/form-data-mutator/endpoints.ts
🚧 Files skipped from review as they are similar to previous changes (14)
  • packages/solid-start/src/index.test.ts
  • packages/core/src/test-utils/split-modes.ts
  • packages/query/src/frameworks/react.test.ts
  • packages/angular/src/http-client.test.ts
  • packages/core/src/writers/target.ts
  • packages/query/src/index.ts
  • packages/core/src/writers/target-tags.ts
  • packages/mcp/src/index.ts
  • packages/angular/src/http-resource.test.ts
  • packages/core/src/writers/split-tags-mode.ts
  • packages/orval/src/client.ts
  • packages/core/src/types.ts
  • packages/fetch/src/index.ts
  • packages/swr/src/index.ts

📝 Walkthrough

Walkthrough

Adds tagsSplitDeduplication and commonTypesFileName output options for tags-split mode. HTTP status-code types are converted from raw strings to structured SharedTypeDeclaration objects in the fetch package, enabling header generators (query, swr, angular) to return string | HeaderResult. Writers inline or collect shared types based on the deduplication flag, and writeSplitTagsMode now generates a common-types file plus a root index.ts barrel when deduplication is enabled and indexFiles is true.

Changes

Shared-type deduplication and root barrel for tags-split mode

Layer / File(s) Summary
Core type contracts
packages/core/src/types.ts
Adds SharedTypeDeclaration, HeaderResult, widens ClientHeaderBuilder return to string | HeaderResult; extends NormalizedOutputOptions, OutputOptions, GeneratorTarget, GeneratorTargetFull, and GeneratorClientExtra with new fields.
Fetch: HTTP status codes as SharedTypeDeclarations
packages/fetch/src/index.ts
Replaces getHTTPStatusCodes() string generator with HTTP_STATUS_CODE_SHARED_TYPES array; generateFetchHeader returns '' or { implementation: '', sharedTypes }.
Client header normalization and options defaults
packages/orval/src/client.ts, packages/orval/src/utils/options.ts
generateClientHeader normalizes string-or-object rawHeader and propagates sharedTypes; normalizeOptions adds defaults for tagsSplitDeduplication and commonTypesFileName.
Query, SWR, and MCP header propagation
packages/query/src/index.ts, packages/swr/src/index.ts, packages/mcp/src/index.ts
generateQueryHeader and generateSwrHeader extract innerImpl/innerSharedTypes and conditionally return HeaderResult; MCP normalizes generateFetchHeader output inline.
Target writers: inline or pass through shared types
packages/core/src/writers/target.ts, packages/core/src/writers/target-tags.ts
target.ts inlines header.sharedTypes into final implementation; target-tags.ts computes deduplicationActive, inlines when off, passes sharedTypes through when on.
split-tags-mode: common-types file and root index barrel
packages/core/src/writers/split-tags-mode.ts
Collects unique shared types across tags, injects import type into each tag, writes common-types file and root index.ts barrel when indexFiles && !workspace.
Tests and test harness updates
packages/core/src/writers/split-tags-mode.test.ts, packages/query/src/frameworks/react.test.ts, packages/angular/src/http-resource.test.ts, packages/core/src/test-utils/..., packages/mock/src/faker/getters/combine.test.ts, packages/solid-start/src/index.test.ts, packages/angular/src/http-client.test.ts
New Vitest suite validates barrel creation/suppression; all test harnesses normalize string | HeaderResult returns and include the two new output config fields.
Documentation and test configs
docs/content/docs/reference/configuration/output.mdx, docs/content/docs/zh/reference/configuration/output.mdx, tests/configs/fetch.config.ts, tests/configs/react-query.config.ts
English and Chinese docs for tagsSplitDeduplication and commonTypesFileName; new test configs generate samples with deduplication enabled.
Sample file formatting and type relocation
samples/mcp/..., samples/react-app-with-swr/..., samples/react-query/...
Internal type helpers relocated within generated modules; whitespace adjustments around HTTP status code type declarations.

Sequence Diagram

sequenceDiagram
    participant User as orval config
    participant FetchPkg as generateFetchHeader
    participant ClientHeader as generateClientHeader
    participant TargetTags as generateTargetForTags
    participant SplitWriter as writeSplitTagsMode

    User->>FetchPkg: tagsSplitDeduplication: true
    FetchPkg-->>ClientHeader: { implementation: '', sharedTypes: HTTP_STATUS_CODE_SHARED_TYPES }
    ClientHeader-->>TargetTags: { implementation, sharedTypes }
    TargetTags->>TargetTags: deduplicationActive=true → set sharedTypes on tag output
    TargetTags-->>SplitWriter: tags with sharedTypes arrays
    SplitWriter->>SplitWriter: collect unique sharedTypes across all tags
    SplitWriter->>SplitWriter: inject import type { } from common-types into each tag
    SplitWriter-->>SplitWriter: write common-types.ts
    SplitWriter-->>SplitWriter: write index.ts barrel (if indexFiles && !workspace)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • orval-labs/orval#3123: Modifies writeSplitTagsMode path assembly and deduplication of returned file paths — directly overlaps with the same function modified here to add commonTypes and index outputs.

Suggested labels

fetch

Suggested reviewers

  • melloware
  • soartec-lab

Poem

🐇 Hippity-hop, the barrel is here!
No more importing each folder, my dear.
common-types.ts holds the shared bits with care,
index.ts re-exports them all, crisp and fair.
One import to rule them — the bunny is pleased! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main feature: introducing a new tagsSplitDeduplication option for barrel generation and shared type extraction in tags-split mode.
Linked Issues check ✅ Passed The PR directly addresses issue #3553 by implementing barrel index.ts generation in tags-split mode with shared type deduplication, meeting all stated requirements including indexFiles gating and workspace suppression.
Out of Scope Changes check ✅ Passed All changes are directly related to the feature: configuration options, type definitions, implementation logic for deduplication/barrel generation, test updates, and fixture configurations. No unrelated refactoring or scope creep detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Copilot AI 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.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds support for generating a root-level barrel index.ts for TAGS_SPLIT outputs when indexFiles is enabled, updating snapshots and tests accordingly.

Changes:

  • Generate a root index{ext} file exporting each per-tag module in tags-split mode (when enabled and not in workspace mode).
  • Add/refresh snapshot fixtures to include the new root index.ts across multiple clients/configurations.
  • Add unit tests validating creation/non-creation and returned-path inclusion for the new barrel file.

Reviewed changes

Copilot reviewed 42 out of 42 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/snapshots/zod/petstore-tags-split/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/vue-query/petstore-tags-split/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/vue-query/http-client-fetch/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/vue-query/http-client-fetch-with-include-http-response-return-type/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/swr/petstore-tags-split/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/swr/http-client-fetch/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/swr/http-client-fetch-with-include-http_status_return-type/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/svelte-query/petstore-tags-split/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/svelte-query/http-client-fetch/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/svelte-query/http-client-fetch-with-include-http-response-return-type/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/react-query/petstore-tags-split/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/react-query/issue-3301-include-unreferenced-schemas/index.ts Snapshot adds a root barrel export for this scenario.
tests/snapshots/react-query/issue-3269/index.ts Snapshot adds a root barrel export for this scenario.
tests/snapshots/react-query/issue-3066/index.ts Snapshot adds a root barrel export for this scenario.
tests/snapshots/react-query/invalidates-tags-split/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/react-query/http-client-fetch/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/react-query/http-client-fetch-with-include-http-response-return-type/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/mock/petstore-tags-split/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/mock/faker-array-items-tags-split/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/mock/enums-inline-tags-split-native/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/hono/petstore-tags-split/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/hono/petstore-tags-split-with-zod-mutator/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/hono/petstore-tags-split-with-handlers/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/fetch/zod-schema-response-tags-split/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/fetch/zod-schema-response-suffix-tags-split/index.ts Snapshot adds a root barrel export for this scenario.
tests/snapshots/fetch/zod-schema-response-suffix-tags-split-no-runtime-validation/index.ts Snapshot adds a root barrel export for this scenario.
tests/snapshots/fetch/reviver/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/fetch/petstore-tags-split/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/fetch/dateParams/index.ts Snapshot adds a root barrel export for this scenario.
tests/snapshots/default/regressions/index.ts Snapshot adds a root barrel export for this scenario.
tests/snapshots/default/multiple-tags-split/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/default/issue-2998/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/default/index-mock-file/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/default/file-extension-tags-split/index.generated.ts Snapshot adds barrel output matching the configured generated file extension.
tests/snapshots/axios/petstore-tags-split/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/axios/petstore-tags-split-mutator/index.ts Snapshot now includes root barrel exports for tags-split output.
tests/snapshots/angular/tags-split/index.ts Snapshot now includes root barrel exports for tags-split output (Angular service suffix).
tests/snapshots/angular/issue-3103/index.ts Snapshot adds a root barrel export for this scenario.
tests/snapshots/angular/http-resource-both-tags-split/index.ts Snapshot now includes root barrel exports for tags-split output (Angular service suffix).
tests/snapshots/angular-query/tags-split/index.ts Snapshot now includes root barrel exports for tags-split output.
packages/core/src/writers/split-tags-mode.ts Implements root barrel index{ext} generation in tags-split mode and returns it in the file list.
packages/core/src/writers/split-tags-mode.test.ts Adds unit tests for writing (or not writing) the root barrel index and returning its path.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/core/src/writers/split-tags-mode.ts Outdated
Comment thread packages/core/src/writers/split-tags-mode.ts Outdated
Comment thread packages/core/src/writers/split-tags-mode.test.ts Outdated

@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.

🧹 Nitpick comments (1)
packages/core/src/writers/split-tags-mode.test.ts (1)

60-123: ⚡ Quick win

Add explicit workspace-mode coverage for root barrel suppression.

Line 338 in the writer adds a !output.workspace gate, but this suite only varies indexFiles. Add a test with indexFiles: true and workspace set, then assert root index.ts is neither written nor returned.

Suggested test addition
+  it('does not write index.ts when workspace is set', async () => {
+    const target = path.join(tmpDir, 'petstore.ts');
+    const props = {
+      ...createSplitModeProps(target),
+      output: createSplitModeOutput(target, {
+        mode: OutputMode.TAGS_SPLIT,
+        indexFiles: true,
+        workspace: 'my-workspace',
+      }),
+    };
+
+    const paths = await writeSplitTagsMode({ ...props, needSchema: false });
+
+    const indexPath = path.join(tmpDir, 'index.ts');
+    expect(paths).not.toContain(indexPath);
+    expect(fs.existsSync(indexPath)).toBe(false);
+  });
🤖 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 `@packages/core/src/writers/split-tags-mode.test.ts` around lines 60 - 123, The
test suite for writeSplitTagsMode lacks coverage for when output.workspace is
true; add a new test case alongside the existing 'writes index.ts when
indexFiles is true' that sets output: createSplitModeOutput(..., { mode:
OutputMode.TAGS_SPLIT, indexFiles: true, workspace: true }) and then assert that
the root index.ts path is neither created on disk (fs.existsSync(indexPath) is
false) nor included in the returned paths array
(expect(paths).not.toContain(indexPath)); locate the test file
split-tags-mode.test.ts and the helper usage around
createSplitModeOutput/writeSplitTagsMode to insert this case so the
!output.workspace gate in writeSplitTagsMode is exercised.
🤖 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.

Nitpick comments:
In `@packages/core/src/writers/split-tags-mode.test.ts`:
- Around line 60-123: The test suite for writeSplitTagsMode lacks coverage for
when output.workspace is true; add a new test case alongside the existing
'writes index.ts when indexFiles is true' that sets output:
createSplitModeOutput(..., { mode: OutputMode.TAGS_SPLIT, indexFiles: true,
workspace: true }) and then assert that the root index.ts path is neither
created on disk (fs.existsSync(indexPath) is false) nor included in the returned
paths array (expect(paths).not.toContain(indexPath)); locate the test file
split-tags-mode.test.ts and the helper usage around
createSplitModeOutput/writeSplitTagsMode to insert this case so the
!output.workspace gate in writeSplitTagsMode is exercised.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d523ef79-31cc-44a2-9e0b-a82b7bd0ac3e

📥 Commits

Reviewing files that changed from the base of the PR and between 33ef474 and cdb6901.

📒 Files selected for processing (42)
  • packages/core/src/writers/split-tags-mode.test.ts
  • packages/core/src/writers/split-tags-mode.ts
  • tests/__snapshots__/angular-query/tags-split/index.ts
  • tests/__snapshots__/angular/http-resource-both-tags-split/index.ts
  • tests/__snapshots__/angular/issue-3103/index.ts
  • tests/__snapshots__/angular/tags-split/index.ts
  • tests/__snapshots__/axios/petstore-tags-split-mutator/index.ts
  • tests/__snapshots__/axios/petstore-tags-split/index.ts
  • tests/__snapshots__/default/file-extension-tags-split/index.generated.ts
  • tests/__snapshots__/default/index-mock-file/index.ts
  • tests/__snapshots__/default/issue-2998/index.ts
  • tests/__snapshots__/default/multiple-tags-split/index.ts
  • tests/__snapshots__/default/regressions/index.ts
  • tests/__snapshots__/fetch/dateParams/index.ts
  • tests/__snapshots__/fetch/petstore-tags-split/index.ts
  • tests/__snapshots__/fetch/reviver/index.ts
  • tests/__snapshots__/fetch/zod-schema-response-suffix-tags-split-no-runtime-validation/index.ts
  • tests/__snapshots__/fetch/zod-schema-response-suffix-tags-split/index.ts
  • tests/__snapshots__/fetch/zod-schema-response-tags-split/index.ts
  • tests/__snapshots__/hono/petstore-tags-split-with-handlers/index.ts
  • tests/__snapshots__/hono/petstore-tags-split-with-zod-mutator/index.ts
  • tests/__snapshots__/hono/petstore-tags-split/index.ts
  • tests/__snapshots__/mock/enums-inline-tags-split-native/index.ts
  • tests/__snapshots__/mock/faker-array-items-tags-split/index.ts
  • tests/__snapshots__/mock/petstore-tags-split/index.ts
  • tests/__snapshots__/react-query/http-client-fetch-with-include-http-response-return-type/index.ts
  • tests/__snapshots__/react-query/http-client-fetch/index.ts
  • tests/__snapshots__/react-query/invalidates-tags-split/index.ts
  • tests/__snapshots__/react-query/issue-3066/index.ts
  • tests/__snapshots__/react-query/issue-3269/index.ts
  • tests/__snapshots__/react-query/issue-3301-include-unreferenced-schemas/index.ts
  • tests/__snapshots__/react-query/petstore-tags-split/index.ts
  • tests/__snapshots__/svelte-query/http-client-fetch-with-include-http-response-return-type/index.ts
  • tests/__snapshots__/svelte-query/http-client-fetch/index.ts
  • tests/__snapshots__/svelte-query/petstore-tags-split/index.ts
  • tests/__snapshots__/swr/http-client-fetch-with-include-http_status_return-type/index.ts
  • tests/__snapshots__/swr/http-client-fetch/index.ts
  • tests/__snapshots__/swr/petstore-tags-split/index.ts
  • tests/__snapshots__/vue-query/http-client-fetch-with-include-http-response-return-type/index.ts
  • tests/__snapshots__/vue-query/http-client-fetch/index.ts
  • tests/__snapshots__/vue-query/petstore-tags-split/index.ts
  • tests/__snapshots__/zod/petstore-tags-split/index.ts

@aqeelat aqeelat force-pushed the feat/3553/tags-split-barrel-index branch from cdb6901 to 0e132ee Compare June 6, 2026 20:48
@aqeelat aqeelat marked this pull request as draft June 6, 2026 21:03
@melloware melloware added enhancement New feature or request zod Zod schema client related issue labels Jun 7, 2026
@melloware

Copy link
Copy Markdown
Collaborator

@aqeelat can you double check i think this PR will fix this issue too with Zod: #3108

@melloware

Copy link
Copy Markdown
Collaborator

where are we with this PR?

@aqeelat

aqeelat commented Jun 14, 2026

Copy link
Copy Markdown
Contributor Author

@melloware still waiting on a response to #3553 (comment)

@aqeelat

aqeelat commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

Blocked by #3595

@aqeelat aqeelat force-pushed the feat/3553/tags-split-barrel-index branch from 0e132ee to 73df503 Compare June 21, 2026 21:44
@aqeelat aqeelat changed the title feat(core): add barrel index.ts at target root in tags-split mode feat(core): add tagsSplitDeduplication option for barrel + shared type extraction Jun 21, 2026
Generate an index.ts barrel at the target root that re-exports all
per-tag implementation files when using mode: 'tags-split' with
indexFiles: true (the default). This is consistent with the existing
mock barrel behavior (mock.indexMockFiles).

The barrel is skipped when output.workspace is set, since the workspace
barrel in write-specs.ts already serves that purpose.

Closes orval-labs#3553
@aqeelat aqeelat force-pushed the feat/3553/tags-split-barrel-index branch 6 times, most recently from 3177fa9 to ca3d6c5 Compare June 22, 2026 15:44
@aqeelat aqeelat marked this pull request as ready for review June 22, 2026 21:12

@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)
packages/core/src/writers/split-tags-mode.test.ts (1)

416-432: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding a positive test case for common-types.ts emission.

The test verifies that common-types.ts is not written when no shared types exist, which is correct. However, the test suite lacks a complementary positive case that verifies the file is written and contains the expected content when shared types are present (e.g., when using a fetch client that emits HTTP status code types).

A positive test would:

  1. Configure output with client: 'fetch' to trigger shared-type emission
  2. Assert that common-types.ts is written and included in returned paths
  3. Optionally verify the file contains expected type declarations (e.g., HTTPStatusCode)

This would strengthen confidence that the deduplication mechanism correctly extracts and writes shared types.

🤖 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 `@packages/core/src/writers/split-tags-mode.test.ts` around lines 416 - 432,
Add a new test case (similar structure to the existing test starting at line
416) that verifies the positive scenario: when shared types are present,
common-types.ts is written and included in the output paths. In this new test,
configure the output props with client set to 'fetch' to trigger shared-type
emission, then assert that the commonTypesPath is included in the returned paths
array and that fs.existsSync confirms the file was created. Optionally, read the
file content and verify it contains expected type declarations like
HTTPStatusCode to strengthen validation that the deduplication mechanism
correctly extracts and writes shared types.
packages/core/src/writers/split-tags-mode.ts (1)

83-93: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Add a conflict check when deduplicating shared types by name.

Current dedup keeps the first declaration per name and silently drops later ones. If code/exported diverge for the same name, generated common-types can become inconsistent.

💡 Proposed fix
-  const collectedSharedTypes: SharedTypeDeclaration[] = [];
-  const seenSharedTypeNames = new Set<string>();
+  const collectedSharedTypes: SharedTypeDeclaration[] = [];
+  const sharedTypesByName = new Map<string, SharedTypeDeclaration>();
   for (const [, target] of tagEntries) {
     if (!target.sharedTypes) continue;
     for (const t of target.sharedTypes) {
-      if (!seenSharedTypeNames.has(t.name)) {
-        seenSharedTypeNames.add(t.name);
-        collectedSharedTypes.push(t);
-      }
+      const existing = sharedTypesByName.get(t.name);
+      if (!existing) {
+        sharedTypesByName.set(t.name, t);
+        collectedSharedTypes.push(t);
+        continue;
+      }
+      if (existing.code !== t.code || existing.exported !== t.exported) {
+        throw new Error(
+          `Conflicting shared type declaration for "${t.name}" in tags-split generation.`,
+        );
+      }
     }
   }
🤖 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 `@packages/core/src/writers/split-tags-mode.ts` around lines 83 - 93, The
deduplication logic in the loop that processes target.sharedTypes currently
silently discards subsequent declarations when a shared type name has already
been encountered. When deduplicating by name using the seenSharedTypeNames set
and collectedSharedTypes array, add a conflict check that compares the code and
exported properties of the new declaration against the previously collected one.
If these properties differ between declarations with the same name, the conflict
should be explicitly handled (such as logging a warning, throwing an error, or
applying a conflict resolution strategy) to prevent inconsistent common-types
generation. This check should occur when a duplicate name is detected and before
continuing to the next iteration.
🤖 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 `@docs/content/docs/zh/reference/configuration/output.mdx`:
- Around line 142-147: The documentation for `tagsSplitDeduplication`
configuration option is missing an important note about its interaction with
workspace mode. Update the documentation section for `tagsSplitDeduplication` to
clearly state that this option is automatically suppressed and has no effect
when `output.workspace` is enabled, since the implementation applies the logic
`deduplicationEnabled = output.tagsSplitDeduplication && !output.workspace`. Add
a warning or note that explicitly tells users that enabling
`tagsSplitDeduplication` while workspace mode is active will not produce the
expected behavior.

In `@packages/core/src/writers/split-tags-mode.ts`:
- Around line 125-133: The code imports all shared type names from
target.sharedTypes without filtering for those actually exported by
common-types. Since common-types conditionally omits the export keyword for some
declarations, this generates invalid imports for non-exported symbols. Filter
target.sharedTypes to only include types that meet the export conditions
(matching the logic at lines 409-412) before mapping their names and
constructing the import statement in the implementationData variable.

---

Nitpick comments:
In `@packages/core/src/writers/split-tags-mode.test.ts`:
- Around line 416-432: Add a new test case (similar structure to the existing
test starting at line 416) that verifies the positive scenario: when shared
types are present, common-types.ts is written and included in the output paths.
In this new test, configure the output props with client set to 'fetch' to
trigger shared-type emission, then assert that the commonTypesPath is included
in the returned paths array and that fs.existsSync confirms the file was
created. Optionally, read the file content and verify it contains expected type
declarations like HTTPStatusCode to strengthen validation that the deduplication
mechanism correctly extracts and writes shared types.

In `@packages/core/src/writers/split-tags-mode.ts`:
- Around line 83-93: The deduplication logic in the loop that processes
target.sharedTypes currently silently discards subsequent declarations when a
shared type name has already been encountered. When deduplicating by name using
the seenSharedTypeNames set and collectedSharedTypes array, add a conflict check
that compares the code and exported properties of the new declaration against
the previously collected one. If these properties differ between declarations
with the same name, the conflict should be explicitly handled (such as logging a
warning, throwing an error, or applying a conflict resolution strategy) to
prevent inconsistent common-types generation. This check should occur when a
duplicate name is detected and before continuing to the next iteration.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 821735d4-dfa4-42d4-874e-e068bddf5364

📥 Commits

Reviewing files that changed from the base of the PR and between 0e132ee and ca3d6c5.

📒 Files selected for processing (20)
  • docs/content/docs/reference/configuration/output.mdx
  • docs/content/docs/zh/reference/configuration/output.mdx
  • packages/angular/src/http-client.test.ts
  • packages/angular/src/http-resource.test.ts
  • packages/core/src/test-utils/context.ts
  • packages/core/src/test-utils/split-modes.ts
  • packages/core/src/types.ts
  • packages/core/src/writers/split-tags-mode.test.ts
  • packages/core/src/writers/split-tags-mode.ts
  • packages/core/src/writers/target-tags.ts
  • packages/core/src/writers/target.ts
  • packages/fetch/src/index.ts
  • packages/mcp/src/index.ts
  • packages/mock/src/faker/getters/combine.test.ts
  • packages/orval/src/client.ts
  • packages/orval/src/utils/options.ts
  • packages/query/src/frameworks/react.test.ts
  • packages/query/src/index.ts
  • packages/solid-start/src/index.test.ts
  • packages/swr/src/index.ts
✅ Files skipped from review due to trivial changes (3)
  • packages/mock/src/faker/getters/combine.test.ts
  • packages/core/src/test-utils/context.ts
  • docs/content/docs/reference/configuration/output.mdx

Comment thread docs/content/docs/zh/reference/configuration/output.mdx
Comment thread packages/core/src/writers/split-tags-mode.ts
…e extraction

Add a new `tagsSplitDeduplication` output option (default: false) that
extracts shared infrastructure types (e.g. HTTPStatusCode*) emitted by
client header builders into a `common-types.ts` file, then generates a
barrel `index.ts` with named re-exports for public types.

When enabled (with `indexFiles: true`):
- Shared types are collected across all per-tag files and deduplicated
- Extracted to `<commonTypesFileName>.ts` (default: 'common-types')
- Per-tag files import shared types from the common file
- Barrel uses named re-exports for exported types + `export *` for tags

When disabled (default): behavior is identical to before — shared types
are inlined per-tag, no barrel, no extraction.

The header builder API is backward compatible: `ClientHeaderBuilder`
return type widens from `string` to `string | HeaderResult`. Existing
builders returning `string` continue to work unchanged.

Currently only `generateFetchHeader` emits `sharedTypes` (HTTPStatusCode*
family). The extraction mechanism is generic — other header builders can
adopt it incrementally.

Remove stale barrel snapshots from the previous naive implementation
(gated on `indexFiles` alone). The barrel now requires both
`indexFiles` and `tagsSplitDeduplication` to be `true`.

Related design discussion: orval-labs#3553
Closes orval-labs#3553
@aqeelat aqeelat force-pushed the feat/3553/tags-split-barrel-index branch from ca3d6c5 to 4e8a1bf Compare June 23, 2026 00:06
@aqeelat

aqeelat commented Jun 23, 2026

Copy link
Copy Markdown
Contributor Author

@melloware the PR is ready.

@melloware melloware merged commit c7f84c1 into orval-labs:master Jun 23, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request zod Zod schema client related issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add barrel index.ts at target root in tags-split mode

3 participants