Skip to content

fix(lint): treat category folders as slug-bearing in duplicate detection#37

Open
rossrdme wants to merge 1 commit into
mainfrom
fix/lint-duplicate-slug-folder-aware
Open

fix(lint): treat category folders as slug-bearing in duplicate detection#37
rossrdme wants to merge 1 commit into
mainfrom
fix/lint-duplicate-slug-folder-aware

Conversation

@rossrdme

Copy link
Copy Markdown
Contributor

Problem

The duplicates linter validator enforces unique slugs within docs/ and reference/ (separately — identical slugs across the two are fine). But it skipped index.md/index.mdx entirely, so a category page — a folder containing index.md, whose slug is the folder name — was invisible to duplicate detection.

That means these two, in the same section, share the slug guides but were not flagged:

  • reference/API/Other/guides.md (slug guides)
  • reference/API/Other/guides/index.md (a category, also slug guides)

Fix

Count a folder's index.md as the folder-name slug, competing in the same namespace as <slug>.md files. A section-root index (docs/index.md, reference/index.md) is still skipped — it has no competing leaf slug. Docs and reference remain separate namespaces (keyed by top-level dir), so an identical slug across them is still allowed.

Verification

Tests added (all passing, 93/93 total):

  • page slug vs. category-folder slug in the same folder → flagged
  • same collision across different subdirs of one section → flagged (section-wide, not per-folder)
  • section-root index page → not treated as a competing slug
  • category-folder slug in reference vs. same slug in docs → allowed (separate namespaces)

This mirrors the folder-aware slug rule used by oas:sync (separate PR), so the linter now detects the folder-vs-file slug collision that oas:sync avoids.

🤖 Generated with Claude Code

…n duplicate detection

The duplicates validator skipped index.md/index.mdx entirely, so a category
page (a folder containing index.md, whose slug is the folder name) was invisible
to duplicate detection. A `<slug>.md` page and a `<slug>/index.md` category in
the same section share a slug but were never flagged.

Count a folder's index.md as the folder-name slug (skipping only a section-root
index like reference/index.md). Docs and reference remain separate namespaces.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Updated duplicate-slug validation to treat non-root index.md and index.mdx files as category slugs based on their parent folders. Section-root indexes remain excluded, and docs and reference retain separate namespaces. Added tests covering page/category collisions, section-wide category collisions, section-root exclusions, and cross-section behavior.


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@src/validators/duplicates.js`:
- Around line 26-28: Update the section-root check in the duplicate validation
logic to compare the full parentDir path with topDir rather than comparing
path.basename(parentDir). Preserve slug assignment for nested folders, including
cases such as docs/a/docs/index.md, and add a regression test covering the
recommended nested-path inputs.
🪄 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 Plus

Run ID: 4395d26d-9a78-4e74-a3f8-573c64838e39

📥 Commits

Reviewing files that changed from the base of the PR and between 2415f0c and 28f2eab.

📒 Files selected for processing (2)
  • src/validators/duplicates.js
  • test/duplicates.test.js
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • readmeio/ai (manual)
  • readmeio/gitto (manual)
  • readmeio/markdown (manual)
  • readmeio/readme (manual)

Comment on lines +26 to +28
const parent = path.basename(path.dirname(relPath));
if (parent === topDir) continue;
slug = parent;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Fix false negative for nested folders matching the section name.

The section-root check only compares the parent folder's name (path.basename) to topDir. This incorrect conditional will erroneously skip valid category index pages if they reside in a nested folder that happens to share the same name as the top directory (e.g., docs/api/docs/index.md).

Compare the entire parentDir path to topDir instead to accurately isolate section-root files. I also recommend adding a test case like ['docs/a/docs/index.md', 'docs/a/docs.md'] to the test suite to prevent future regressions.

🐛 Proposed fix
-      const parent = path.basename(path.dirname(relPath));
-      if (parent === topDir) continue;
-      slug = parent;
+      const parentDir = path.dirname(relPath);
+      if (parentDir === topDir) continue;
+      slug = path.basename(parentDir);
📝 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 parent = path.basename(path.dirname(relPath));
if (parent === topDir) continue;
slug = parent;
const parentDir = path.dirname(relPath);
if (parentDir === topDir) continue;
slug = path.basename(parentDir);
🤖 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 `@src/validators/duplicates.js` around lines 26 - 28, Update the section-root
check in the duplicate validation logic to compare the full parentDir path with
topDir rather than comparing path.basename(parentDir). Preserve slug assignment
for nested folders, including cases such as docs/a/docs/index.md, and add a
regression test covering the recommended nested-path inputs.

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.

1 participant