-
Notifications
You must be signed in to change notification settings - Fork 227
feat: add support for the strategy parameter in component-name-unique rule #3011
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
026b58d
f40a1e4
e970517
ec68603
f38370c
1f25bc8
8cbffec
12f8387
b3888b9
cd72939
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| '@redocly/cli': minor | ||
| '@redocly/openapi-core': minor | ||
| --- | ||
|
|
||
| Added a `strategy` option to the `component-name-unique` rule, matching the `--component-names-strategy` option of the `bundle` command. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,9 @@ import type { | |
| Oas3_1Schema, | ||
| OasRef, | ||
| } from '../../typings/openapi.js'; | ||
| import { componentNameFromTitle } from '../../utils/component-name-from-title.js'; | ||
| import { isPlainObject } from '../../utils/is-plain-object.js'; | ||
| import { isString } from '../../utils/is-string.js'; | ||
| import { isSupportedExtension } from '../../utils/is-supported-extension.js'; | ||
| import type { Oas2Rule, Oas3Rule, Oas3Visitor } from '../../visitors.js'; | ||
| import type { Problem, UserContext } from '../../walk.js'; | ||
|
|
@@ -32,6 +35,8 @@ type ComponentsMapValue = { absolutePointers: Set<string>; locations: Location[] | |
|
|
||
| export const ComponentNameUnique: Oas3Rule | Oas2Rule = (options) => { | ||
| const components = new Map<string, ComponentsMapValue>(); | ||
| const useTitleStrategy = options.strategy === 'title'; | ||
| let rootSourceRef: string; | ||
|
|
||
| const typeNames: string[] = []; | ||
| if (options.schemas !== 'off') { | ||
|
|
@@ -55,11 +60,19 @@ export const ComponentNameUnique: Oas3Rule | Oas2Rule = (options) => { | |
| const resolvedRef = resolve(ref); | ||
| if (!resolvedRef.location) return; | ||
|
|
||
| addComponentFromAbsoluteLocation(typeName, resolvedRef.location); | ||
| const titleName = getTitleComponentName(typeName, resolvedRef); | ||
| if (titleName) { | ||
| addFoundComponent(typeName, titleName, resolvedRef.location); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reports point at file rootMedium Severity When the title strategy records a component, it stores Reviewed by Cursor Bugbot for commit cd72939. Configure here. |
||
| } else { | ||
| addComponentFromAbsoluteLocation(typeName, resolvedRef.location); | ||
| } | ||
| } | ||
| }, | ||
| }, | ||
| Root: { | ||
| enter(_: AnyOas3Definition, { location }: UserContext) { | ||
| rootSourceRef = location.source.absoluteRef; | ||
| }, | ||
|
harshit078 marked this conversation as resolved.
|
||
| leave(root: AnyOas3Definition, ctx: UserContext) { | ||
| components.forEach((value, key, _) => { | ||
| if (value.absolutePointers.size > 1) { | ||
|
|
@@ -147,6 +160,23 @@ export const ComponentNameUnique: Oas3Rule | Oas2Rule = (options) => { | |
| const componentName = getComponentNameFromAbsoluteLocation(location.absolutePointer.toString()); | ||
| addFoundComponent(typeName, componentName, location); | ||
| } | ||
|
|
||
| function getTitleComponentName( | ||
| typeName: string, | ||
| resolved: { node: unknown; location: Location } | ||
| ): string | null { | ||
| if ( | ||
| !useTitleStrategy || | ||
| typeName !== TYPE_NAME_SCHEMA || | ||
| resolved.location.source.absoluteRef === rootSourceRef | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The rule skips the title strategy for every schema in the root file. The The bundle is still written, but |
||
| ) { | ||
| return null; | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Root schemas skip title strategyHigh Severity
Additional Locations (1)Reviewed by Cursor Bugbot for commit cd72939. Configure here. |
||
|
|
||
| const { node } = resolved; | ||
| const title = isPlainObject(node) && isString(node.title) ? node.title.trim() : ''; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This duplicates code that already exists; you should consider reusing the existing logic |
||
| return title === '' ? null : componentNameFromTitle(title); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If a schema has no Lint says the description is fine, and then there is no bundle at all. The two commands disagree again, and this is the most common way the title strategy breaks, so the rule should report it: |
||
| } | ||
| }; | ||
|
|
||
| function getOptionComponentNameForTypeName(typeName: string): string | null { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| import { COMPONENT_NAME_CHARS } from '../oas-types.js'; | ||
| import { toPascalCase } from './to-pascal-case.js'; | ||
|
|
||
| export function componentNameFromTitle(title: string): string { | ||
| return toPascalCase(title).replace(new RegExp(`[^${COMPONENT_NAME_CHARS}]`, 'g'), '-'); | ||
| } |


Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The report points at the start of the file, but the line to change is the title. Pass
resolvedRef.location.child('title')here, in the same place the bundler reports atbundle-visitor.ts.