feat: add bundle --use-titles-for-component-names flag#2851
feat: add bundle --use-titles-for-component-names flag#2851kanoru3101 wants to merge 33 commits into
--use-titles-for-component-names flag#2851Conversation
…ent-names-via-title-flag
🦋 Changeset detectedLatest commit: 17f3012 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Coverage Report
File Coverage
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Performance Benchmark (Lower is Faster)
|
--use-titles-for-component-names flag
|
📦 A new experimental 🧪 version v0.0.0-snapshot.1780513428 of Redocly CLI has been published for testing. Install with NPM: npm install @redocly/cli@0.0.0-snapshot.1780513428 |
|
📦 A new experimental 🧪 version v0.0.0-snapshot.1780518450 of Redocly CLI has been published for testing. Install with NPM: npm install @redocly/cli@0.0.0-snapshot.1780518450 |
|
📦 A new experimental 🧪 version v0.0.0-snapshot.1780520360 of Redocly CLI has been published for testing. Install with NPM: npm install @redocly/cli@0.0.0-snapshot.1780520360 |
…ent-names-via-title-flag
|
📦 A new experimental 🧪 version v0.0.0-snapshot.1780909948 of Redocly CLI has been published for testing. Install with NPM: npm install @redocly/cli@0.0.0-snapshot.1780909948 |
|
📦 A new experimental 🧪 version v0.0.0-snapshot.1781077827 of Redocly CLI has been published for testing. Install with NPM: npm install @redocly/cli@0.0.0-snapshot.1781077827 |
| ['API v2 User', 'APIV2User'], | ||
| [' padded ', 'Padded'], | ||
| ['', ''], | ||
| ])('converts %j to %j', (input, expected) => { |
There was a problem hiding this comment.
The names $input and $expected have been changed for clarity
| return { name, prevName }; | ||
| } | ||
|
|
||
| function componentNameFromTitle( |
There was a problem hiding this comment.
Let's check if we can reuse the existing logic.
There was a problem hiding this comment.
I tried collapsing it into a single if inside getComponentName without the extracted helper, but it comes out worse: the title path has failure modes the basename path doesn't (missing title / unusable chars / collision) and on failure it falls back to the basename, so you either duplicate the -N loop or scatter useTitle && checks through one big function. Keeping componentNameFromBasename as the shared primitive avoids both while leaving the default logic untouched.
| 'bundle', | ||
| '--use-titles-for-component-names', | ||
| '--component-renaming-conflicts-severity', | ||
| 'error', |
There was a problem hiding this comment.
Added test with off
|
📦 A new experimental 🧪 version v0.0.0-snapshot.1781166677 of Redocly CLI has been published for testing. Install with NPM: npm install @redocly/cli@0.0.0-snapshot.1781166677 |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0df08e9. Configure here.
…b.com:Redocly/redocly-cli into feat/duplicate-component-names-via-title-flag
| let components: Record<string, ComponentsGroup>; | ||
| let rootLocation: Location; | ||
|
|
||
| const firstSchemaLocationByName = new Map<string, Location>(); |
There was a problem hiding this comment.
firstSchemaLocationByName exists only to populate the collision's from — the "referenced from …" link that points at the first schema which already took the name. It can't be derived the way the basename path handles a conflict, because the two collisions behave differently:
- Basename collision auto-resolves: it appends -N and reports a rename warning at the current location. It never references the other schema, so it needs no location tracking.
- Title collision is a user-fixable error — the fix is to rename one of the two conflicting titles, so the message points from at the other (first) schema to help the user find both.
|
Question — Should lint also evaluate the effective derived component name? My understanding is that bundled inlined schemas already receive derived component names today, traditionally based on the referenced file basename or $ref pointer segment. This option adds another derivation strategy for schemas: when --use-titles-for-component-names is enabled, the component name can instead come from the schema’s title, with fallback to the existing basename/pointer logic when the title is missing or invalid. Given that the bundle process already has to resolve an effective component name either way, would it make sense for the lint/rule phase to expose or reuse that same derived-name calculation? Linting can certainly validate the presence or shape of title fields directly. However, that only covers one input to the naming strategy. What seems more useful is linting against the final effective name that bundle would produce, regardless of whether that name came from title or from the traditional basename / $ref pointer fallback. That would allow rules such as component-name-unique to detect collisions before bundling, including collisions introduced by title-derived names as well as collisions that still occur through fallback naming. It would also let validity and naming/casing rules apply to the actual component key that will be emitted, with diagnostics reported against the original schema files and source locations. This seems preferable to requiring a second lint pass against the generated bundled file, where diagnostics are tied to generated output and are less directly traceable to the originating schema. I understand the lifecycle split: bundle runs preprocessors, rules, and decorators, while lint runs preprocessors and rules but not decorators. Is keeping effective component-name resolution bundle-only an intentional boundary, or would sharing the derived-name helper with lint be reasonable so these checks can happen before bundling? |
| | --remove-unused-components | boolean | Remove unused components from the `bundle` output. | | ||
| | --skip-decorator | [string] | Ignore certain decorators. See the [Skip preprocessor, rule, or decorator section](#skip-preprocessor-rule-or-decorator). | | ||
| | --skip-preprocessor | [string] | Ignore certain preprocessors. See the [Skip preprocessor, rule, or decorator section](#skip-preprocessor-rule-or-decorator). | | ||
| | --use-titles-for-component-names | boolean | Build Schema component names from each schema's `title` field. See [Use titles for component names](#use-titles-for-component-names). | |
There was a problem hiding this comment.
Let's change it to --component-names-strategy with options like "basename" (default) or "title"?
@tatomyr what do you think?
There was a problem hiding this comment.
Sounds even better to me. What about "filename" instead of "basename"?
| return { | ||
| key, | ||
| problem: { | ||
| message: 'Schema must define a `title` to build a component name.', |
There was a problem hiding this comment.
Need to clarify it is required only when using this option or someone may get confused:
| message: 'Schema must define a `title` to build a component name.', | |
| message: 'Schema must define a `title` when using --use-titles-for-component-names.', |
| }, | ||
| }; | ||
| } | ||
| if (!new RegExp(COMPONENT_NAME_PATTERN).test(key)) { |
There was a problem hiding this comment.
do we need it? should we just replace any unsupported symbol ourselves with dashes?
There was a problem hiding this comment.
I'll change it to replace and add to docs about it

What/Why/How?
Added an opt-in
--use-titles-for-component-namesflag tobundle: inlined Schema components are named from each schema'stitle(PascalCased format) instead of the file basename.Reference
#2797
Testing
With flag
Error
missing titleError
invalid charactersWarn
title collisionWarn
two title collisionScreenshots (optional)
Check yourself
Security
Note
Low Risk
Opt-in bundle flag with default off; changes only schema component naming and bundler diagnostics, with broad test coverage and no auth or data-path impact.
Overview
Adds an opt-in
--use-titles-for-component-namesflag toredocly bundle(CLI, core API, docs, changeset). When enabled, inlined Schema components are named from each schema’stitle(trimmed, then PascalCased on spaces) instead of$refbasename / pointer, so names likeAuthorityModelvsAuthorityRequestavoid brittleAuthority/Authority-2collisions.The bundler reports errors for missing
titleor titles that can’t produce a valid component key (validated via sharedCOMPONENT_NAME_PATTERNinoas-types, also reused byspec-components-invalid-map-name). Title collisions reuse--component-renaming-conflicts-severity(warn/error/off) and include afrompointer to the first schema; on title problems it falls back to basename naming. Parameters and other non-schema components keep the existing basename logic.New
toPascalCaseutility, unit/e2e tests and fixtures, and help snapshot updates cover the behavior.Reviewed by Cursor Bugbot for commit 17f3012. Bugbot is set up for automated code reviews on this repo. Configure here.