Skip to content

feat(core): add schemas.importPath for package import specifiers - #3548

Merged
melloware merged 3 commits into
orval-labs:masterfrom
aqeelat:feat/3535-schemas-import-path
Jun 5, 2026
Merged

feat(core): add schemas.importPath for package import specifiers#3548
melloware merged 3 commits into
orval-labs:masterfrom
aqeelat:feat/3535-schemas-import-path

Conversation

@aqeelat

@aqeelat aqeelat commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Closes #3535
Fix #353

Problem

When output.schemas points to a folder outside the generated client target, Orval emits imports based on filesystem paths. This works when schemas and clients are part of the same TypeScript compilation root, but can fail for package secondary entrypoints, where imports like import type { Pet } from '/libs/client/models' are emitted instead of a proper package specifier.

Solution

Allow output.schemas to specify an import specifier independent from the filesystem output path:

output: {
  target: './libs/client/angular/src/lib/endpoints',
  schemas: {
    path: './libs/client/models/src/lib',
    type: 'typescript',
    importPath: '@acme/client/models',
  },
}

When importPath is set, generated client files import schema types from that package specifier. The filesystem path is still used for the on-disk schema output.

Changes

  • core: add importPath to SchemaOptions / NormalizedSchemaOptions
  • core: extract getSchemasImportPath helper into its own module
  • core: update all writers (single/split/tags/split-tags) to use the helper
  • core: update factory generators to resolve factory and type imports from importPath
  • core: skip per-file .js/ .ts extension in generateImportsForBuilder for package imports (no extension on package specifiers)
  • orval: tighten normalizeSchemasOption validation for importPath — rejects empty strings, relative paths, absolute paths, and whitespace-only values
  • docs: document schemas object form, the importPath option, and the zod .zod subpath requirement
  • tests: cover all four write modes, zod suffix, faker subpath, and the factoryMethods.outputDirectory bypass

Notes

  • Validations fail fast at config-load time with a clear error message.
  • When importPath is set, factoryMethods.outputDirectory is bypassed (factories resolve imports against the package specifier rather than the on-disk factory output directory) — documented.
  • For zod schemas (type: 'zod') the per-file suffix is .zod, so the package must expose ./pet.zod (e.g., @acme/models/pet.zod).

Summary by CodeRabbit

  • New Features
    • Support for package-style schema imports via a new schemas.importPath; generated schema and factory imports use this package specifier when provided.
  • Documentation
    • output.schemas docs expanded to accept String | Object | false; added object form (path, type, importPath), examples, and import/index-file/extension rules.
  • Tests
    • Added/expanded tests validating schemas.importPath across modes, import-resolution, and factory import behavior.
  • Validation
    • schemas.importPath now rejects empty, whitespace-only, relative, and absolute specifiers.

Copilot AI review requested due to automatic review settings June 5, 2026 12:44
@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds support for schemas.importPath (package import specifier): validation and types, a helper to read it, writer/generator logic to prefer package imports (omitting extensions), tests across units and integration, and updated documentation.

Changes

Schema importPath Configuration Support

Layer / File(s) Summary
Type definitions and configuration validation
packages/core/src/types.ts, packages/orval/src/utils/options.ts, packages/orval/src/utils/options.test.ts
SchemaOptions/NormalizedSchemaOptions add importPath?: string; normalizeSchemasOption validates schemas.importPath (rejects relative, absolute, empty, whitespace) and preserves valid package specifiers.
Documentation updates
docs/content/docs/reference/configuration/output.mdx
Documents schemas as `String
Schema import path helper & exports
packages/core/src/utils/schemas-options.ts, packages/core/src/utils/schemas-options.test.ts, packages/core/src/utils/index.ts
Adds getSchemasImportPath and SchemaOptionLike, tests for extraction behavior, and re-exports the helper from the utils barrel.
Writer modes import path computation
packages/core/src/writers/single-mode.ts, packages/core/src/writers/split-mode.ts, packages/core/src/writers/tags-mode.ts, packages/core/src/writers/split-tags-mode.ts
All writer modes now prefer getSchemasImportPath(output.schemas) for schema import bases and fall back to previous relative-path computation when absent.
Import builder: package import extension handling
packages/core/src/writers/generate-imports-for-builder.ts, packages/core/src/writers/generate-imports-for-builder.test.ts
generateImportsForBuilder detects package-style schemas.importPath (isPackageImport) and omits file extensions for package imports while preserving .zod suffixes; tests cover indexFiles variants, NodeNext compatibility, and schemaFactory imports.
Factory generator import resolution
packages/core/src/generators/factory.ts, packages/core/src/generators/factory.test.ts
generateFactory uses getSchemasImportPath to resolve schema/factory and referenced-type imports to the configured package import base across split/single/single-split modes; tests validate import composition and factory consolidation behavior.
Assertion test adjustments
packages/core/src/utils/assertion.test.ts
isReference test clarified to explicitly reject objects containing only $dynamicRef (no $ref).
End-to-end integration tests
packages/orval/src/generate-spec.test.ts
Integration tests assert generated endpoint files import schemas from the configured package specifier across modes, with indexFiles coverage.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • orval-labs/orval#3361: Touches import-extension logic in generate-imports-for-builder.ts, overlapping extension-handling behavior.
  • orval-labs/orval#3123: Modifies writeSplitTagsMode; related to writer-mode file/path handling.

Suggested reviewers

  • melloware
  • wadakatu
  • soartec-lab

"🐰 I hopped through options, tidy and spry,
I found an import path up in the sky,
No more ../ tangles or file-extension fray,
Package imports now lead the way—hip, hop, hooray! 🥕"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% 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
Title check ✅ Passed The pull request title 'feat(core): add schemas.importPath for package import specifiers' accurately describes the main feature addition—adding an importPath option to schemas for using package specifiers instead of filesystem-relative paths.
Linked Issues check ✅ Passed The PR fully implements all objectives from issue #3535: extends SchemaOptions/NormalizedSchemaOptions with importPath [#3535], adds getSchemasImportPath helper and updates writers to use it [#3535], implements validation rejecting empty/relative/absolute/whitespace paths [#3535], documents the option with zod/faker requirements [#3535], and adds comprehensive test coverage [#3535].
Out of Scope Changes check ✅ Passed All changes are scoped to implementing schemas.importPath: type additions, validation logic, helper utilities, writer updates, factory generator refinements, and comprehensive test coverage align with the stated objective. Documentation updates and test removals (assertion.test.ts) are supporting maintenance changes within scope.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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 and usage tips.

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 configuring output.schemas.importPath so generated clients (and related helpers) can import schemas via a package specifier instead of computed relative filesystem paths.

Changes:

  • Validates and preserves schemas.importPath during options normalization.
  • Updates core writers/import generation to prefer the configured package specifier and to omit NodeNext/Node16 file extensions for package imports.
  • Adds documentation and broad test coverage for schemas.importPath across generation modes.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/orval/src/utils/options.ts Validates schemas.importPath and passes it through normalization.
packages/orval/src/utils/options.test.ts Adds normalization tests for schemas.importPath and invalid values.
packages/orval/src/generate-spec.test.ts Adds generation tests asserting schema imports use the package specifier across modes.
packages/core/src/writers/tags-mode.ts Prefers package schemas.importPath over relative path computation.
packages/core/src/writers/split-tags-mode.ts Prefers package schemas.importPath over relative path computation in tags-split.
packages/core/src/writers/split-mode.ts Prefers package schemas.importPath over relative path computation in split mode.
packages/core/src/writers/single-mode.ts Prefers package schemas.importPath over relative path computation in single mode.
packages/core/src/writers/generate-imports-for-builder.ts Omits local-file import extensions when importing from a package specifier.
packages/core/src/writers/generate-imports-for-builder.test.ts Adds tests for package import behavior (indexFiles, NodeNext, zod suffix, schemaFactory).
packages/core/src/utils/schemas-options.ts Introduces getSchemasImportPath helper to extract importPath from schemas config.
packages/core/src/utils/schemas-options.test.ts Adds unit tests for getSchemasImportPath.
packages/core/src/utils/index.ts Re-exports the new schemas options helper.
packages/core/src/utils/assertion.test.ts Moves/duplicates a $dynamicRef assertion into the general isReference test.
packages/core/src/types.ts Extends schema option types with optional importPath.
packages/core/src/generators/factory.ts Changes factory/schema import path resolution to use schemas.importPath.
packages/core/src/generators/factory.test.ts Adds tests for factory imports when schemas.importPath is provided.
docs/content/docs/reference/configuration/output.mdx Documents object-form schemas and the new importPath option with requirements.

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

Comment thread packages/orval/src/utils/options.ts
Comment thread packages/core/src/generators/factory.ts
Comment thread docs/content/docs/reference/configuration/output.mdx
Comment thread packages/orval/src/generate-spec.test.ts
…al-labs#3535)

Allow generated client files to import schema types from a package
specifier (e.g. '@acme/models') instead of computing a relative
filesystem path. This unblocks use cases where the schemas and client
outputs sit in separate TypeScript compilation roots or in
secondary entrypoint packages.

When `schemas.importPath` is set, all four write modes and the
factory generators emit imports from the configured package
specifier. The filesystem `path` is still used for the on-disk
schema output, and validation rejects empty strings, relative paths,
absolute paths, and whitespace-only values.

- core: add `importPath` to `SchemaOptions` / `NormalizedSchemaOptions`
- core: extract `getSchemasImportPath` helper into its own module
- core: update all writers (single/split/tags/split-tags) to use the helper
- core: update factory.ts to resolve factory and type imports from `importPath`
- core: skip per-file extension in `generateImportsForBuilder` for package imports
- orval: tighten `normalizeSchemasOption` validation for `importPath`
- docs: document `schemas` object form and `importPath` requirements
- tests: cover all four modes, zod suffix, faker subpath, and
  `outputDirectory` bypass

Closes orval-labs#3535
@aqeelat
aqeelat force-pushed the feat/3535-schemas-import-path branch from 78af92c to 7eff340 Compare June 5, 2026 12:51

@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 (1)
packages/orval/src/generate-spec.test.ts (1)

882-883: ⚡ Quick win

Make import assertion regex consistent and more precise.

The regex pattern /from\s+'@acme\/models/ lacks the closing quote, which could match false positives like from '@acme/models/subpath'. The test at line 1021 correctly includes the closing quote: /from\s+'@acme\/models'/. For consistency and precision, standardize all four assertions to include the closing quote.

♻️ Proposed fix to add closing quotes
     const content = await fs.readFile(targetFile, 'utf8');
-    expect(content).toMatch(/from\s+'`@acme`\/models/);
+    expect(content).toMatch(/from\s+'`@acme`\/models'/);
     expect(content).not.toMatch(/from\s+'\.\./);

Apply the same pattern at lines 920, 956, and 989.

Also applies to: 920-921, 956-957, 989-990

🤖 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/orval/src/generate-spec.test.ts` around lines 882 - 883, Update the
four import-match assertions that currently use the incomplete regex
/from\s+'`@acme`\/models/ so they require the closing quote; change each to
/from\s+'`@acme`\/models'/ to avoid matching subpaths (same pattern already used
at the assertion around line 1021). Specifically update the occurrences that
pair with expect(content).toMatch(...) at the positions shown in the diff so all
four tests use the precise regex and keep the companion
expect(content).not.toMatch(/from\s+'\.\./) assertions unchanged.
🤖 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/reference/configuration/output.mdx`:
- Around line 151-169: Update the requirements list for importPath to explicitly
enumerate the validation rules applied during config normalization: state that
importPath is rejected if empty or only whitespace (including
whitespace-padded), if it is a relative specifier (starts with ./ or ../), or if
it is an absolute path (starts with /), and mention that these checks occur
during config normalization that rejects invalid importPath values; ensure this
text is added near the existing "Requirements when using `importPath`" bullets
and references the `importPath` setting so users see the exact constraints.

In `@packages/orval/src/utils/options.ts`:
- Around line 139-143: The current validation in the if block that checks
schemas.importPath using startsWith('/') misses Windows absolute paths; update
the check for schemas.importPath in packages/orval/src/utils/options.ts (the
conditional that throws the Error for absolute paths) to also detect
Windows-style absolute paths (drive-letter like "C:\..." and UNC paths starting
with "\\" )—best done by using Node's path.isAbsolute(schemas.importPath) or
additional regex checks for /^[A-Za-z]:\\/ and /^\\"\\/" to ensure any absolute
path (POSIX or Windows) triggers the same Error message that currently runs for
POSIX absolute paths.

---

Nitpick comments:
In `@packages/orval/src/generate-spec.test.ts`:
- Around line 882-883: Update the four import-match assertions that currently
use the incomplete regex /from\s+'`@acme`\/models/ so they require the closing
quote; change each to /from\s+'`@acme`\/models'/ to avoid matching subpaths (same
pattern already used at the assertion around line 1021). Specifically update the
occurrences that pair with expect(content).toMatch(...) at the positions shown
in the diff so all four tests use the precise regex and keep the companion
expect(content).not.toMatch(/from\s+'\.\./) assertions unchanged.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fda4abaa-c573-4a89-b78d-f774048951a3

📥 Commits

Reviewing files that changed from the base of the PR and between 7e48991 and 78af92c.

📒 Files selected for processing (17)
  • docs/content/docs/reference/configuration/output.mdx
  • packages/core/src/generators/factory.test.ts
  • packages/core/src/generators/factory.ts
  • packages/core/src/types.ts
  • packages/core/src/utils/assertion.test.ts
  • packages/core/src/utils/index.ts
  • packages/core/src/utils/schemas-options.test.ts
  • packages/core/src/utils/schemas-options.ts
  • packages/core/src/writers/generate-imports-for-builder.test.ts
  • packages/core/src/writers/generate-imports-for-builder.ts
  • packages/core/src/writers/single-mode.ts
  • packages/core/src/writers/split-mode.ts
  • packages/core/src/writers/split-tags-mode.ts
  • packages/core/src/writers/tags-mode.ts
  • packages/orval/src/generate-spec.test.ts
  • packages/orval/src/utils/options.test.ts
  • packages/orval/src/utils/options.ts

Comment thread docs/content/docs/reference/configuration/output.mdx
Comment thread packages/orval/src/utils/options.ts Outdated
@melloware melloware added the enhancement New feature or request label Jun 5, 2026
@melloware

Copy link
Copy Markdown
Collaborator

@aqeelat did you review all AI comments. Feel free to comment and resolve them?

@aqeelat

aqeelat commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

@aqeelat did you review all AI comments. Feel free to comment and resolve them?

not yet. I'll go over them now.

aqeelat and others added 2 commits June 5, 2026 16:17
…sion

Address review feedback on orval-labs#3548:

- docs: enumerate the validation rules applied to schemas.importPath
  during config normalization (empty, whitespace, relative, POSIX and
  Windows absolute paths).
- core: reject Windows-style absolute paths in addition to POSIX ones
  (drive-letter like 'C:\...', UNC like '\\server\share').
- core: tighten import-match regexes in generate-spec.test.ts to
  require the closing quote so subpath imports don't satisfy the
  assertion.

Tests cover the new Windows path rejections.
- Split whitespace validation into two distinct checks (whitespace-only
  vs. padded) with accurate error messages for each
- Add test for padded whitespace rejection
- In split mode, append .factory suffix when pkgBase is set so factory
  function and type imports resolve to distinct subpaths
- Update factory tests to match corrected behavior
- Add cross-reference from requirements list to validation section in docs
@aqeelat

aqeelat commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

@melloware all done

@melloware

Copy link
Copy Markdown
Collaborator

@aqeelat i think this also fixes this long old request right? #353

@melloware
melloware merged commit 03086ca into orval-labs:master Jun 5, 2026
5 checks passed
melloware pushed a commit that referenced this pull request Jun 28, 2026
…on (#3658)

* docs(output): restructure importPath validation and sync zh translation

Nest the "Validation of importPath" section under ### importPath as an
H4 subsection instead of a sibling H3 placed after splitByTags. The
anchor #validation-of-importpath is preserved.

Sync the Chinese translation (zh/reference/configuration/output.mdx)
with content from #3548, #3595, #3613, and #3618 that was only added to
the English docs:

- Expand ## schemas with String/Object forms, property table, importPath
  subsection (incl. requirements + validation), and splitByTags subsection
- Add schemasImportPath row to the Faker generator table and a dedicated
  #### schemasImportPath subsection
- Add missing MSW and Faker generator table rows for full zh/en parity
  (delay, useExamples, generateEachHttpStatus, locale, etc.)

* docs(zh): translate String/Object form and Validation headings to Chinese

Translate descriptive headings introduced in the previous commit from
English to Chinese, keeping config property name headings (importPath,
splitByTags) in English per existing convention:

- "String form" → "字符串形式"
- "Object form" → "对象形式"
- "Validation of importPath" → "importPath 校验" (link + heading updated)
@aqeelat
aqeelat deleted the feat/3535-schemas-import-path branch July 15, 2026 09:29
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.

feat: allow schema imports to use package import specifiers Allow to specify a ts path for importing schemas in generated clients

3 participants