Skip to content

feat: deduplicate shared refs with a single component#292

Open
JounQin wants to merge 1 commit intomainfrom
feat/duplicate_refs
Open

feat: deduplicate shared refs with a single component#292
JounQin wants to merge 1 commit intomainfrom
feat/duplicate_refs

Conversation

@JounQin
Copy link
Member

@JounQin JounQin commented Mar 24, 2026

close IDP-1446

Summary by CodeRabbit

  • New Features

    • OpenAPI documentation components now accept multiple endpoint paths in a single declaration.
    • Added a documentation lint rule to enforce single OpenAPIPath usage per file.
  • Bug Fixes

    • Deduplicated shared references for cleaner API docs and reduced duplication.
  • Refactor

    • Consolidated API path declarations across docs.
    • Simplified anchor/id generation and reference linking (no per-instance UID fragments).
  • Chores

    • Bumped package minor version.

Copilot AI review requested due to automatic review settings March 24, 2026 10:42
@changeset-bot
Copy link

changeset-bot bot commented Mar 24, 2026

🦋 Changeset detected

Latest commit: f1b7818

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@alauda/doom Minor

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

@coderabbitai
Copy link

coderabbitai bot commented Mar 24, 2026

Walkthrough

This PR consolidates multiple OpenAPIPath usages in docs into array-based paths, adds a remark-lint rule to forbid multiple OpenAPIPath components per file, refactors OpenAPIPath to accept multiple paths and render per-path bases, and removes UID context/uid-based anchor logic from several runtime components.

Changes

Cohort / File(s) Summary
Documentation (English)
docs/en/apis/advanced_apis/event/search.mdx, docs/en/apis/advanced_apis/gitops/applicationsets.mdx, docs/en/apis/advanced_apis/log/aggregation.mdx, docs/en/apis/advanced_apis/log/search.mdx
Replaced multiple <OpenAPIPath path="..."/> instances with single <OpenAPIPath path={[ ... ]}/> using arrays; updated frontmatter sourceSHA.
Documentation (Chinese)
docs/zh/apis/advanced_apis/event/search.mdx, docs/zh/apis/advanced_apis/gitops/applicationsets.mdx, docs/zh/apis/advanced_apis/log/aggregation.mdx, docs/zh/apis/advanced_apis/log/search.mdx
Consolidated multiple OpenAPIPath declarations into single components with array-based path props; no endpoint changes.
Remark linting
packages/doom/src/remark-lint/no-multi-open-api-paths.ts, packages/doom/src/remark-lint/index.ts, packages/doom/src/remarkrc.ts
Added noMultiOpenAPIPaths lint rule that reports when >1 OpenAPIPath appears in a file; re-exported rule and registered it in remarkrc.
OpenAPIPath runtime refactor
packages/doom/src/runtime/components/OpenAPIPath.tsx
Changed OpenAPIPathProps.path to `string
Reference & heading UID removal
packages/doom/src/runtime/components/_context.ts, packages/doom/src/runtime/components/OpenAPIRef.tsx, packages/doom/src/runtime/components/_HeadingTitle.tsx, packages/doom/src/runtime/components/_RefLink.tsx
Removed UidContext, useUid, and UidProvider; removed isCommonRef prop and uid-prefixed anchor logic; simplified heading slug/id generation to exclude uid.
Changeset
.changeset/forty-brooms-pull.md
Added changeset marking @alauda/doom for a minor version bump with a feature note about deduplicating shared refs.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

feature, enhancement

Poem

🐇 I nibbled through docs and code tonight,
One OpenAPIPath to make things right,
UIDs tucked away, refs now tidy and shared,
Lint watches closely — no duplicates spared,
Hoppity-hop, a cleaner tree declared ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main objective: deduplicating shared refs with a single component, which is the core architectural change reflected across multiple files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/duplicate_refs

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.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 24, 2026

Open in StackBlitz

yarn add https://pkg.pr.new/@alauda/doom@292.tgz
yarn add https://pkg.pr.new/@alauda/doom-export@292.tgz

commit: f1b7818

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the OpenAPI MDX runtime rendering to deduplicate shared schema references when documenting multiple API paths, and enforces the “single OpenAPIPath per file” authoring pattern (IDP-1446).

Changes:

  • Remove the UidContext-based unique ID scheme and switch refs/headings to use stable schema-based anchors.
  • Extend OpenAPIPath to accept path: string | string[] and collect/deduplicate referenced schemas across the provided paths.
  • Add a remark-lint rule to prevent multiple OpenAPIPath components in one MDX file, and update impacted docs to the new array form.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/doom/src/runtime/components/_context.ts Removes UID context/provider used for unique anchor generation.
packages/doom/src/runtime/components/_RefLink.tsx Simplifies ref links to target stable schema anchors (or COMMON_REFS).
packages/doom/src/runtime/components/_HeadingTitle.tsx Adjusts slug extraction/id creation for headings (no UID prefix).
packages/doom/src/runtime/components/OpenAPIRef.tsx Removes UID provider usage and the isCommonRef behavior.
packages/doom/src/runtime/components/OpenAPIPath.tsx Adds multi-path support and ref collection/dedup across paths.
packages/doom/src/remarkrc.ts Enables the new noMultiOpenAPIPaths lint rule.
packages/doom/src/remark-lint/site.ts Renames the rule id to match the doom-lint:* naming scheme.
packages/doom/src/remark-lint/no-multi-open-api-paths.ts Adds lint rule to enforce single OpenAPIPath usage per file.
packages/doom/src/remark-lint/index.ts Exports the new lint rule.
docs/zh/apis/advanced_apis/log/search.mdx Combines multiple OpenAPIPath usages into one with path={[...]}.
docs/zh/apis/advanced_apis/log/aggregation.mdx Same as above.
docs/zh/apis/advanced_apis/gitops/applicationsets.mdx Same as above (larger path list).
docs/zh/apis/advanced_apis/event/search.mdx Same as above.
docs/en/apis/advanced_apis/log/search.mdx Same as above (+ sourceSHA update).
docs/en/apis/advanced_apis/log/aggregation.mdx Same as above (+ sourceSHA update).
docs/en/apis/advanced_apis/gitops/applicationsets.mdx Same as above (+ sourceSHA update).
docs/en/apis/advanced_apis/event/search.mdx Same as above (+ sourceSHA update).
Comments suppressed due to low confidence (1)

packages/doom/src/runtime/components/_HeadingTitle.tsx:42

  • HeadingTitle can compute id as undefined (e.g., when slug is absent and slugger.slug(...) returns an empty string). In that case the anchor still renders with href="#undefined", producing a broken/self-invented anchor. Consider only rendering the anchor when id is truthy (or providing a fallback id).
    <HeadingComponent id={id}>
      <X.a className="rp-header-anchor" href={`#${id}`} aria-hidden>
        #
      </X.a>

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/doom/src/runtime/components/_HeadingTitle.tsx (1)

32-36: Simplified id construction aligns with single-component deduplication strategy.

With multiple paths now consolidated into a single OpenAPIPath component (which creates one BananaSlug instance), the slugger's internal deduplication handles collisions by appending -1, -2, etc. for duplicate headings within the same component instance.

The single-element array pattern could be simplified to a direct expression, but this is a minor style preference:

♻️ Optional: Simplify the id computation
  const id = useMemo(
     () =>
-      [slug || slugger?.slug(slugFromChildren)].filter(Boolean).join('-') ||
-      undefined,
+      slug || slugger?.slug(slugFromChildren) || undefined,
     [slug, slugger, slugFromChildren],
   )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/doom/src/runtime/components/_HeadingTitle.tsx` around lines 32 - 36,
The id useMemo currently builds an array and filters to join which is
unnecessary given the single-component deduplication; simplify the expression in
the useMemo that computes id (referencing useMemo, id, slug, slugger,
slugFromChildren) to directly choose slug || slugger?.slug(slugFromChildren) and
return undefined when falsy, removing the intermediate array/filter/join pattern
so the logic remains identical but clearer and relies on BananaSlug/OpenAPIPath
slugger deduplication.
packages/doom/src/runtime/components/OpenAPIPath.tsx (2)

174-182: Consider keeping OpenAPIPathBaseProps internal.

The OpenAPIPathBase component is not exported, so its props interface doesn't need to be exported either. This reduces the public API surface.

♻️ Suggested change
-export interface OpenAPIPathBaseProps extends Omit<
+interface OpenAPIPathBaseProps extends Omit<
   OpenAPIPathProps,
   'openapiPath'
 > {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/doom/src/runtime/components/OpenAPIPath.tsx` around lines 174 - 182,
OpenAPIPathBaseProps is unnecessarily exported despite OpenAPIPathBase being
internal; change the declaration of OpenAPIPathBaseProps from "export interface
OpenAPIPathBaseProps" to a non-exported "interface OpenAPIPathBaseProps" and
update any internal references in the same file (e.g., usages in
OpenAPIPathBase, OpenAPIPath, or related helper types) to ensure they still
resolve, removing it from the module's public API surface.

307-307: Variable shadowing: inner path shadows the prop.

The loop variable path shadows the destructured prop path from the function parameters. While functionally correct, this can be confusing and error-prone during future maintenance.

♻️ Suggested change
-      for (const path of paths) {
-        const pathItem = openapi.paths?.[path]
+      for (const pathKey of paths) {
+        const pathItem = openapi.paths?.[pathKey]
         if (pathItem) {
-          pathMap.set(path, {
+          pathMap.set(pathKey, {
             pathItem,
             openapi,
           })
 
           if (!refMap.has(pathname)) {
             refMap.set(pathname, new Set())
           }
           const refs = refMap.get(pathname)!
-          setRefsForPath(openapi, path, omitRoutePathRefs(page.routePath), refs)
+          setRefsForPath(openapi, pathKey, omitRoutePathRefs(page.routePath), refs)
         }
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/doom/src/runtime/components/OpenAPIPath.tsx` at line 307, The loop
variable `path` inside the for-loop shadows the component prop `path` in
OpenAPIPath, which is confusing; rename the loop variable (for example to
`apiPath`, `pathItem`, or `p`) in the loop `for (const ... of paths)` and update
all references inside that loop body to the new name so the destructured prop
`path` remains unshadowed (check usages within the loop and any nested callbacks
in the OpenAPIPath component).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/doom/src/runtime/components/OpenAPIPath.tsx`:
- Line 326: The slugger instance is memoized with an empty dependency array so
BananaSlug (which tracks generated slugs) can retain state when the component's
path prop changes; update the useMemo call that creates slugger to include path
in its dependency array (i.e., recreate BananaSlug when path changes) so heading
IDs are regenerated without stale duplicate-count state—locate the useMemo
creating slugger and add path to its dependencies.

---

Nitpick comments:
In `@packages/doom/src/runtime/components/_HeadingTitle.tsx`:
- Around line 32-36: The id useMemo currently builds an array and filters to
join which is unnecessary given the single-component deduplication; simplify the
expression in the useMemo that computes id (referencing useMemo, id, slug,
slugger, slugFromChildren) to directly choose slug ||
slugger?.slug(slugFromChildren) and return undefined when falsy, removing the
intermediate array/filter/join pattern so the logic remains identical but
clearer and relies on BananaSlug/OpenAPIPath slugger deduplication.

In `@packages/doom/src/runtime/components/OpenAPIPath.tsx`:
- Around line 174-182: OpenAPIPathBaseProps is unnecessarily exported despite
OpenAPIPathBase being internal; change the declaration of OpenAPIPathBaseProps
from "export interface OpenAPIPathBaseProps" to a non-exported "interface
OpenAPIPathBaseProps" and update any internal references in the same file (e.g.,
usages in OpenAPIPathBase, OpenAPIPath, or related helper types) to ensure they
still resolve, removing it from the module's public API surface.
- Line 307: The loop variable `path` inside the for-loop shadows the component
prop `path` in OpenAPIPath, which is confusing; rename the loop variable (for
example to `apiPath`, `pathItem`, or `p`) in the loop `for (const ... of paths)`
and update all references inside that loop body to the new name so the
destructured prop `path` remains unshadowed (check usages within the loop and
any nested callbacks in the OpenAPIPath component).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1bee29cf-ecfb-47a9-be8f-3a5bc7ad1bb5

📥 Commits

Reviewing files that changed from the base of the PR and between 0495f3a and 972db41.

📒 Files selected for processing (18)
  • .changeset/forty-brooms-pull.md
  • docs/en/apis/advanced_apis/event/search.mdx
  • docs/en/apis/advanced_apis/gitops/applicationsets.mdx
  • docs/en/apis/advanced_apis/log/aggregation.mdx
  • docs/en/apis/advanced_apis/log/search.mdx
  • docs/zh/apis/advanced_apis/event/search.mdx
  • docs/zh/apis/advanced_apis/gitops/applicationsets.mdx
  • docs/zh/apis/advanced_apis/log/aggregation.mdx
  • docs/zh/apis/advanced_apis/log/search.mdx
  • packages/doom/src/remark-lint/index.ts
  • packages/doom/src/remark-lint/no-multi-open-api-paths.ts
  • packages/doom/src/remark-lint/site.ts
  • packages/doom/src/remarkrc.ts
  • packages/doom/src/runtime/components/OpenAPIPath.tsx
  • packages/doom/src/runtime/components/OpenAPIRef.tsx
  • packages/doom/src/runtime/components/_HeadingTitle.tsx
  • packages/doom/src/runtime/components/_RefLink.tsx
  • packages/doom/src/runtime/components/_context.ts
💤 Files with no reviewable changes (1)
  • packages/doom/src/runtime/components/_context.ts

return { paths, pathMap, refMap }
}, [openapiPath, page.routePath, path])

const slugger = useMemo(() => new BananaSlug(), [])
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Slugger may retain stale state when path changes.

The slugger is memoized with an empty dependency array, so it persists across prop changes. BananaSlug tracks previously generated slugs to avoid duplicates. If path changes, the slugger retains its history, which could cause heading IDs to have unexpected numeric suffixes (e.g., heading-2 instead of heading).

Consider including path in the dependency array to reset the slugger when paths change:

🐛 Suggested fix
-  const slugger = useMemo(() => new BananaSlug(), [])
+  const slugger = useMemo(() => new BananaSlug(), [path])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const slugger = useMemo(() => new BananaSlug(), [])
const slugger = useMemo(() => new BananaSlug(), [path])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/doom/src/runtime/components/OpenAPIPath.tsx` at line 326, The
slugger instance is memoized with an empty dependency array so BananaSlug (which
tracks generated slugs) can retain state when the component's path prop changes;
update the useMemo call that creates slugger to include path in its dependency
array (i.e., recreate BananaSlug when path changes) so heading IDs are
regenerated without stale duplicate-count state—locate the useMemo creating
slugger and add path to its dependencies.

@JounQin JounQin force-pushed the feat/duplicate_refs branch from 231e9ad to f1b7818 Compare March 24, 2026 10:50
@JounQin
Copy link
Member Author

JounQin commented Mar 24, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 24, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/doom/src/runtime/components/OpenAPIPath.tsx (1)

307-307: Consider renaming loop variables to avoid shadowing the path prop.

The loop variable path shadows the component's path prop in multiple places, which can reduce code clarity and cause confusion during maintenance.

♻️ Suggested refactor
-      for (const path of paths) {
-        const pathItem = openapi.paths?.[path]
+      for (const p of paths) {
+        const pathItem = openapi.paths?.[p]
         if (pathItem) {
-          pathMap.set(path, {
+          pathMap.set(p, {
             pathItem,
             openapi,
           })

           if (!refMap.has(pathname)) {
             refMap.set(pathname, new Set())
           }
           const refs = refMap.get(pathname)!
-          setRefsForPath(openapi, path, omitRoutePathRefs(page.routePath), refs)
+          setRefsForPath(openapi, p, omitRoutePathRefs(page.routePath), refs)
         }
       }

And similarly in the render section:

-      {paths.map((path) => {
-        const p = pathMap.get(path)
+      {paths.map((pathKey) => {
+        const resolved = pathMap.get(pathKey)
         return (
           <OpenAPIPathBase
-            key={path}
-            path={path}
-            pathItem={p?.pathItem}
-            openapi={p?.openapi}
+            key={pathKey}
+            path={pathKey}
+            pathItem={resolved?.pathItem}
+            openapi={resolved?.openapi}
             pathPrefix={pathPrefix}
             slugger={slugger}
           />
         )
       })}

Also applies to: 330-331

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/doom/src/runtime/components/OpenAPIPath.tsx` at line 307, The
component OpenAPIPath currently uses a loop variable named "path" which shadows
the component prop "path" (e.g., the loop beginning with "for (const path of
paths)" and the loops in the render section around the subsequent iteration),
causing ambiguity; rename the loop variable to a non-conflicting identifier such
as "pathKey", "pathItem", or "route" throughout the file (including all
references in the loop bodies and render JSX) to eliminate shadowing and
preserve the prop "path" name unmodified in OpenAPIPath.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/doom/src/runtime/components/OpenAPIPath.tsx`:
- Line 307: The component OpenAPIPath currently uses a loop variable named
"path" which shadows the component prop "path" (e.g., the loop beginning with
"for (const path of paths)" and the loops in the render section around the
subsequent iteration), causing ambiguity; rename the loop variable to a
non-conflicting identifier such as "pathKey", "pathItem", or "route" throughout
the file (including all references in the loop bodies and render JSX) to
eliminate shadowing and preserve the prop "path" name unmodified in OpenAPIPath.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 108b5272-c0c8-4046-83a8-e2618c5df595

📥 Commits

Reviewing files that changed from the base of the PR and between 972db41 and f1b7818.

📒 Files selected for processing (18)
  • .changeset/forty-brooms-pull.md
  • docs/en/apis/advanced_apis/event/search.mdx
  • docs/en/apis/advanced_apis/gitops/applicationsets.mdx
  • docs/en/apis/advanced_apis/log/aggregation.mdx
  • docs/en/apis/advanced_apis/log/search.mdx
  • docs/zh/apis/advanced_apis/event/search.mdx
  • docs/zh/apis/advanced_apis/gitops/applicationsets.mdx
  • docs/zh/apis/advanced_apis/log/aggregation.mdx
  • docs/zh/apis/advanced_apis/log/search.mdx
  • packages/doom/src/remark-lint/index.ts
  • packages/doom/src/remark-lint/no-multi-open-api-paths.ts
  • packages/doom/src/remark-lint/site.ts
  • packages/doom/src/remarkrc.ts
  • packages/doom/src/runtime/components/OpenAPIPath.tsx
  • packages/doom/src/runtime/components/OpenAPIRef.tsx
  • packages/doom/src/runtime/components/_HeadingTitle.tsx
  • packages/doom/src/runtime/components/_RefLink.tsx
  • packages/doom/src/runtime/components/_context.ts
💤 Files with no reviewable changes (1)
  • packages/doom/src/runtime/components/_context.ts
✅ Files skipped from review due to trivial changes (9)
  • .changeset/forty-brooms-pull.md
  • docs/zh/apis/advanced_apis/event/search.mdx
  • docs/zh/apis/advanced_apis/log/aggregation.mdx
  • packages/doom/src/remark-lint/index.ts
  • docs/zh/apis/advanced_apis/log/search.mdx
  • docs/en/apis/advanced_apis/log/search.mdx
  • packages/doom/src/remarkrc.ts
  • docs/en/apis/advanced_apis/log/aggregation.mdx
  • docs/en/apis/advanced_apis/event/search.mdx
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/doom/src/runtime/components/_HeadingTitle.tsx
  • docs/zh/apis/advanced_apis/gitops/applicationsets.mdx
  • packages/doom/src/remark-lint/site.ts
  • docs/en/apis/advanced_apis/gitops/applicationsets.mdx
  • packages/doom/src/runtime/components/OpenAPIRef.tsx
  • packages/doom/src/remark-lint/no-multi-open-api-paths.ts
  • packages/doom/src/runtime/components/_RefLink.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants