feat(mock): add schemasImportPath to faker generator - #3618
Conversation
Adds a `schemasImportPath` option to the faker mock generator so consumers can point schema-level faker factories at a dedicated barrel separate from the production type barrel (`schemas.importPath`). When `schemas.importPath` resolves to a single barrel file via tsconfig path mappings, appending `/index.faker` produces an unresolvable sub-path. `schemasImportPath` is used verbatim as the schema factory import path, sidestepping that limitation (orval-labs#3612). - Add `schemasImportPath` to `FakerMockOptions` in core types - Use it verbatim in `generateImportsForBuilder` when the faker generator has `schemas: true` - Validate: reject empty/whitespace/relative/absolute specifiers; require both `schemas: true` and `schemas.importPath` - Extract shared `validatePackageSpecifier` (reused by `schemas.importPath`) - Document the option in the faker generator section
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughAdds a Changesfaker schemasImportPath option
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
When schemas are split by tag and there is no root barrel, operation
files (pets/pets.ts) and the consolidated <schemas>/index.faker.ts file
both previously emitted schema imports that didn't resolve. Operation
files imported '../model/pet' when the file lived at
'../model/pets/pet.ts'; the faker factory file imported types from '.'
when no root index.ts existed.
The root cause was that generateImportsForBuilder (used by every mode
writer) and writeFakerSchemaMocks both assumed a flat schemas directory
or a root barrel. Neither consulted the schema-to-tag map computed by
writeSchemasTagsSplit.
Compute the schema-to-tag map once in writeSpecs and thread it through:
- WriteModeProps: new optional schemaTagMap field
- generateImportsForBuilder: optional schemaTagMap param; the
indexFiles:false branch routes each import into its tag subdir
(or keeps shared schemas at the schemas root)
- single-mode / split-mode / tags-mode / split-tags-mode: forward
schemaTagMap at all 13 generateImportsForBuilder call sites
- writeFakerSchemaMocks: same per-schema routing for the consolidated
index.faker.ts file under indexFiles:false
Removes the validation guard that previously rejected the combination,
since the underlying import resolution now handles it correctly.
- packages/core/src/types.ts: add schemaTagMap? to WriteModeProps
- packages/core/src/writers/generate-imports-for-builder.ts: optional
schemaTagMap param + tag-aware routing in indexFiles:false branch
- packages/core/src/writers/{single,split,tags,split-tags}-mode.ts:
destructure schemaTagMap from WriteModeProps, forward to call sites
- packages/orval/src/write-specs.ts: hoist schemaTagMap computation to
writeSpecs scope; thread to writeFakerSchemaMocks and writeMode;
per-schema routing in writeFakerSchemaMocks under indexFiles:false
- packages/orval/src/utils/options.ts: remove the guard
- packages/orval/src/utils/options.test.ts: remove guard tests
- packages/core/src/writers/generate-imports-for-builder.test.ts: add
splitByTags: false to two orval-labs#3618 schemasImportPath test cases that
now require it (those test cases predate splitByTags becoming
required in NormalizedSchemaOptions)
- docs/content/docs/reference/configuration/output.mdx: drop the
indexFiles:true requirement note under splitByTags
- tests/configs/axios.config.ts: new splitByTagsFakerSchemasNoIndex
config exercising the previously-broken combination
- tests/__snapshots__/axios/split-by-tags-faker-schemas-no-index/:
snapshots for the new config
- tests/api-generation.spec.ts: 3 regression tests pinning per-tag
import paths for operation files, faker factory file, and tag
isolation
When schemas are split by tag and there is no root barrel, operation
files (pets/pets.ts) and the consolidated <schemas>/index.faker.ts file
both previously emitted schema imports that didn't resolve. Operation
files imported '../model/pet' when the file lived at
'../model/pets/pet.ts'; the faker factory file imported types from '.'
when no root index.ts existed.
The root cause was that generateImportsForBuilder (used by every mode
writer) and writeFakerSchemaMocks both assumed a flat schemas directory
or a root barrel. Neither consulted the schema-to-tag map computed by
writeSchemasTagsSplit.
Compute the schema-to-tag map once in writeSpecs and thread it through:
- WriteModeProps: new optional schemaTagMap field
- generateImportsForBuilder: optional schemaTagMap param; the
indexFiles:false branch routes each import into its tag subdir
(or keeps shared schemas at the schemas root)
- single-mode / split-mode / tags-mode / split-tags-mode: forward
schemaTagMap at all 13 generateImportsForBuilder call sites
- writeFakerSchemaMocks: same per-schema routing for the consolidated
index.faker.ts file under indexFiles:false
Removes the validation guard that previously rejected the combination,
since the underlying import resolution now handles it correctly.
- packages/core/src/types.ts: add schemaTagMap? to WriteModeProps
- packages/core/src/writers/generate-imports-for-builder.ts: optional
schemaTagMap param + tag-aware routing in indexFiles:false branch
- packages/core/src/writers/{single,split,tags,split-tags}-mode.ts:
destructure schemaTagMap from WriteModeProps, forward to call sites
- packages/orval/src/write-specs.ts: hoist schemaTagMap computation to
writeSpecs scope; thread to writeFakerSchemaMocks and writeMode;
per-schema routing in writeFakerSchemaMocks under indexFiles:false
- packages/orval/src/utils/options.ts: remove the guard
- packages/orval/src/utils/options.test.ts: remove guard tests
- packages/core/src/writers/generate-imports-for-builder.test.ts: add
splitByTags: false to two orval-labs#3618 schemasImportPath test cases that
now require it (those test cases predate splitByTags becoming
required in NormalizedSchemaOptions)
- docs/content/docs/reference/configuration/output.mdx: drop the
indexFiles:true requirement note under splitByTags
- tests/configs/axios.config.ts: new splitByTagsFakerSchemasNoIndex
config exercising the previously-broken combination
- tests/__snapshots__/axios/split-by-tags-faker-schemas-no-index/:
snapshots for the new config
- tests/api-generation.spec.ts: 3 regression tests pinning per-tag
import paths for operation files, faker factory file, and tag
isolation
When schemas are split by tag and there is no root barrel, operation
files (pets/pets.ts) and the consolidated <schemas>/index.faker.ts file
both previously emitted schema imports that didn't resolve. Operation
files imported '../model/pet' when the file lived at
'../model/pets/pet.ts'; the faker factory file imported types from '.'
when no root index.ts existed.
The root cause was that generateImportsForBuilder (used by every mode
writer) and writeFakerSchemaMocks both assumed a flat schemas directory
or a root barrel. Neither consulted the schema-to-tag map computed by
writeSchemasTagsSplit.
Compute the schema-to-tag map once in writeSpecs and thread it through:
- WriteModeProps: new optional schemaTagMap field
- generateImportsForBuilder: optional schemaTagMap param; the
indexFiles:false branch routes each import into its tag subdir
(or keeps shared schemas at the schemas root)
- single-mode / split-mode / tags-mode / split-tags-mode: forward
schemaTagMap at all 13 generateImportsForBuilder call sites
- writeFakerSchemaMocks: same per-schema routing for the consolidated
index.faker.ts file under indexFiles:false
Removes the validation guard that previously rejected the combination,
since the underlying import resolution now handles it correctly.
- packages/core/src/types.ts: add schemaTagMap? to WriteModeProps
- packages/core/src/writers/generate-imports-for-builder.ts: optional
schemaTagMap param + tag-aware routing in indexFiles:false branch
- packages/core/src/writers/{single,split,tags,split-tags}-mode.ts:
destructure schemaTagMap from WriteModeProps, forward to call sites
- packages/orval/src/write-specs.ts: hoist schemaTagMap computation to
writeSpecs scope; thread to writeFakerSchemaMocks and writeMode;
per-schema routing in writeFakerSchemaMocks under indexFiles:false
- packages/orval/src/utils/options.ts: remove the guard
- packages/orval/src/utils/options.test.ts: remove guard tests
- packages/core/src/writers/generate-imports-for-builder.test.ts: add
splitByTags: false to two orval-labs#3618 schemasImportPath test cases that
now require it (those test cases predate splitByTags becoming
required in NormalizedSchemaOptions)
- docs/content/docs/reference/configuration/output.mdx: drop the
indexFiles:true requirement note under splitByTags
- tests/configs/axios.config.ts: new splitByTagsFakerSchemasNoIndex
config exercising the previously-broken combination
- tests/__snapshots__/axios/split-by-tags-faker-schemas-no-index/:
snapshots for the new config
- tests/api-generation.spec.ts: 3 regression tests pinning per-tag
import paths for operation files, faker factory file, and tag
isolation
* feat(schemas): add splitByTags option to organize schemas by tag Adds schemas.splitByTags and schemas.sharedDirName options that organize generated schema files into per-tag subdirectories when using output.mode: 'tags-split'. Schemas referenced by multiple tags are placed in a shared directory (default '_shared'). Closes #3592 * fix(schemas): allow splitByTags with schemas.importPath The importPath guard was unnecessary — when indexFiles is true (the default), operation and factory files import schemas through the barrel index, which re-exports tag subdirectories. The importPath option just replaces the barrel specifier (e.g. @acme/models instead of ../model). * refactor(types): make splitByTags required in NormalizedSchemaOptions normalizeSchemasOption always materializes splitByTags as a boolean, so the optional designation weakened type safety for downstream consumers. * feat(schemas): support splitByTags with zod schemas Thread schemaTagMap through writeZodSchemas, writeZodSchemasReusable, and writeZodSchemasFromVerbs so zod schemas are organized into per-tag subdirectories the same way TypeScript schemas are. - buildSiblingImports computes cross-directory paths when schemaTagMap is set - Verb schemas are routed to their operation's tag directory - writeZodSchemaTagsSplitBarrel writes per-tag + root barrel indexes - Remove zod rejection guard from write-specs.ts * fix(zod): use getImportExtension for NodeNext in write-zod-specs Replace fileExtension.replace(/\.ts$/, '') with getImportExtension at all 4 remaining sites in write-zod-specs.ts: - writeZodSchemaIndex: add tsconfig param, use getImportExtension - writeZodSchemaTagsSplitBarrel: fix importExt (was using old pattern alongside getImportExtension for indexImportExt in the same function) - writeZodSchemasReusable: use output.tsconfig - writeZodSchemasFromVerbs: use output.tsconfig Add tsconfig?: Tsconfig to WriteZodOutputOptions interface and pass output.tsconfig from all writeZodSchemaIndex call sites. Aligns with #3603 which applies the same fix to the non-zod writers. * refactor(hono): pass full handler file path to generateModuleSpecifier Construct the complete handler file path (including tag name and extension) upfront and pass it to generateModuleSpecifier, instead of passing only the directory and manually appending the filename and extension afterward. Matches the pattern already used by the per-operation handler block above. * fix(hono): construct composite route handler imports per output mode Handler files are written flat (tag.handlers.ts) in tags mode but in a subdirectory (tag/tag.handlers.ts) in tags-split mode. The composite route import construction assumed tags-split layout unconditionally, producing wrong import paths for tags mode. * fix(zod): handle ../ mutator paths + cleanup test fixtures + import SHARED_DIR - adjustMutatorPathForDir: prepend ../ to ../-prefixed mutator paths to account for tag subdirectory depth (previously only handled ./-prefixed) - schemas-tags-split: import SHARED_DIR from schema-tag-mapper instead of redefining as local ROOT constant (single source of truth) - schemas-tags-split.test: centralize temp dir cleanup in afterEach hook so cleanup runs even when assertions throw - schema-tag-mapper.test: add regression test verifying imports are matched by GeneratorImport.name (TS identifier) not schemaName * test(schemas): add #3592 splitByTags regression tests Pin the end-to-end behaviors of schemas.splitByTags that the snapshot suite alone cannot express intent for: - tags-split + splitByTags places per-tag schemas under <tag>/ subdirs with their own barrels, while cross-tag-shared schemas stay at the model root. Pagination is the interesting case: shared indirectly via PetList and StoreList, both tag-scoped. - Endpoint and faker files import via the '../model' barrel rather than reaching into a specific tag subdir, keeping tag files agnostic to where a schema physically lives. - mode: 'split' + splitByTags produces the same per-tag layout; the combined endpoints.ts imports every cross-tag schema from the single './model' barrel. Mirrors the style of the #3596 regression tests added in 76de240. * fix(schemas): reject splitByTags + indexFiles:false When schemas are split by tag and there is no root barrel, operation files (pets/pets.ts) and the consolidated <schemas>/index.faker.ts file both emit schema imports that don't resolve. Operation files import '../model/pet' when the file lives at '../model/pets/pet.ts'; the faker factory file imports types from '.' when no root index.ts exists. The root cause is that generateImportsForBuilder (used by every mode writer) and writeFakerSchemaMocks both assume a flat schemas directory or a root barrel. Neither consults the schema-to-tag map computed by writeSchemasTagsSplit. Reject the combination at config normalization time until the import resolvers are taught to honor splitByTags directly. Tracked as a follow-up. - packages/orval/src/utils/options.ts: throw when schemas.splitByTags + !indexFiles. - packages/orval/src/utils/options.test.ts: rejection test plus two positive cases (splitByTags + indexFiles:true accepted; indexFiles:false alone accepted). - docs/content/docs/reference/configuration/output.mdx: note the indexFiles requirement under splitByTags. * fix(schemas): support splitByTags with indexFiles:false When schemas are split by tag and there is no root barrel, operation files (pets/pets.ts) and the consolidated <schemas>/index.faker.ts file both previously emitted schema imports that didn't resolve. Operation files imported '../model/pet' when the file lived at '../model/pets/pet.ts'; the faker factory file imported types from '.' when no root index.ts existed. The root cause was that generateImportsForBuilder (used by every mode writer) and writeFakerSchemaMocks both assumed a flat schemas directory or a root barrel. Neither consulted the schema-to-tag map computed by writeSchemasTagsSplit. Compute the schema-to-tag map once in writeSpecs and thread it through: - WriteModeProps: new optional schemaTagMap field - generateImportsForBuilder: optional schemaTagMap param; the indexFiles:false branch routes each import into its tag subdir (or keeps shared schemas at the schemas root) - single-mode / split-mode / tags-mode / split-tags-mode: forward schemaTagMap at all 13 generateImportsForBuilder call sites - writeFakerSchemaMocks: same per-schema routing for the consolidated index.faker.ts file under indexFiles:false Removes the validation guard that previously rejected the combination, since the underlying import resolution now handles it correctly. - packages/core/src/types.ts: add schemaTagMap? to WriteModeProps - packages/core/src/writers/generate-imports-for-builder.ts: optional schemaTagMap param + tag-aware routing in indexFiles:false branch - packages/core/src/writers/{single,split,tags,split-tags}-mode.ts: destructure schemaTagMap from WriteModeProps, forward to call sites - packages/orval/src/write-specs.ts: hoist schemaTagMap computation to writeSpecs scope; thread to writeFakerSchemaMocks and writeMode; per-schema routing in writeFakerSchemaMocks under indexFiles:false - packages/orval/src/utils/options.ts: remove the guard - packages/orval/src/utils/options.test.ts: remove guard tests - packages/core/src/writers/generate-imports-for-builder.test.ts: add splitByTags: false to two #3618 schemasImportPath test cases that now require it (those test cases predate splitByTags becoming required in NormalizedSchemaOptions) - docs/content/docs/reference/configuration/output.mdx: drop the indexFiles:true requirement note under splitByTags - tests/configs/axios.config.ts: new splitByTagsFakerSchemasNoIndex config exercising the previously-broken combination - tests/__snapshots__/axios/split-by-tags-faker-schemas-no-index/: snapshots for the new config - tests/api-generation.spec.ts: 3 regression tests pinning per-tag import paths for operation files, faker factory file, and tag isolation * fix(schemas): route splitByTags imports by TS identifier, not schemaName generateImportsForBuilder's splitByTags tag lookup was using `baseName` (which prefers `schemaImport.schemaName` over `.name`) to key into the schema-to-tag map. The map is built by `buildSchemaTagMap`, which keys exclusively on `schema.name` — the pascal-cased TS identifier produced by `getRefInfo`. When an import's `schemaName` differs from its TS `name` (e.g. `PetSchema` vs `Pet`), the lookup silently missed and the import was placed at the schemas root instead of its tag subdirectory. Use `schemaImport.name` directly for the tag lookup. The filename computation still uses `baseName` (preferring `schemaName`), which is unchanged from the existing flat-layout behavior — `conventionName` is idempotent on already-pascal-cased input in the common case. - packages/core/src/writers/generate-imports-for-builder.ts: lookup by `schemaImport.name`; clarify the comment. - packages/core/src/writers/generate-imports-for-builder.test.ts: two new tests pinning tag routing — one with `name`/`schemaName` differing to exercise the lookup, one with a missing entry to exercise the root fallback. * fix(schemas): address review findings on cleanup hook and dirSchemas skip Two issues found in review: 1. `schemas-tags-split.test.ts`: the outer-scope `dir` was shadowed by per-test `const dir` declarations, so the `afterEach` cleanup hook never removed temp directories. Replaced `const dir = await tmpDir()` with `dir = await tmpDir()` so the outer variable is populated. 2. `write-zod-specs.ts`: the dirSchemas loop in `writeZodSchemasFromVerbs` iterated `uniqueVerbsSchemas` directly, but the writing loop above skips pure-$ref wrappers via `continue` when `useReusableSchemas` is on. Skipped entries still landed in dirSchemas, so the tag barrel re-exported files that were never written. Replicated the skip condition in the dirSchemas loop with a comment explaining why. * test(schemas): prune redundant splitByTags config and fold symmetry test `petstoreTagsSplitSchemas` generated 27 snapshot files but no test in `api-generation.spec.ts` actually inspected any of them — the cross- tag split logic was already covered by `tagsSplitSharedModels` with explicit assertions. Removed the config block and its snapshots. Also folded the standalone 'stores files do not import peer tag subdirectories' test into the operation-imports test as additional assertions — same coverage, one less test. Updated existing snapshots for the v8.18.0 version bump brought in by the master rebase. * test(schemas): complete unresolved .resolves assertions in splitByTags test Three `await expect(readFile(...)).resolves;` chains had no trailing matcher, so the promise was awaited but no assertion ran. The file- exists intent only surfaced via promise rejection. Added `.toBeDefined()` to make the assertion explicit. The broader readFile-vs-pathExists inconsistency is tracked in #3623.
…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)
Summary
Adds a
schemasImportPathoption to the faker mock generator so consumers can point schema-level faker factories at a dedicated barrel separate from the production type barrel (schemas.importPath).When
schemas.importPathresolves to a single barrel file (e.g. via tsconfig path mappings like"@acme/models": ["libs/models/public-api.ts"]), appending/index.fakerproduces an unresolvable sub-path — a barrel specifier isn't a directory prefix.schemasImportPathis used verbatim as the schema factory import path, sidestepping that limitation.Resolves #3612.
Changes
packages/core/src/types.ts— AddschemasImportPath?: stringtoFakerMockOptions.packages/core/src/writers/generate-imports-for-builder.ts— When the faker generator hasschemas: trueandschemasImportPathset, use it verbatim as the schema factory dependency instead of joiningimportPathwithindex.faker.packages/orval/src/utils/options.ts— Extract a sharedvalidatePackageSpecifierhelper (reused byschemas.importPath) and validateschemasImportPath: reject empty/whitespace/relative/absolute specifiers; require bothschemas: trueandschemas.importPath.generate-imports-for-builder.test.ts(+2),options.test.ts(+6 incl. adescribeblock for the new validation).schemas,schemasImportPath,operationResponses,arrayItemsrows) plus aschemasImportPathexample section.Checklist
generate-imports-for-builder.test.ts,options.test.ts)Summary by CodeRabbit
Release Notes
New Features
schemasImportPathconfiguration option for faker generators, enabling users to specify a custom import path for schema-level faker factories instead of using the default/index.fakerpattern.Documentation
schemasImportPathoverride option for faker mock generators.