fix(oas:sync): match the platform's OAS-upload output (tag index pages, root ordering, slug casing)#35
fix(oas:sync): match the platform's OAS-upload output (tag index pages, root ordering, slug casing)#35rossrdme wants to merge 1 commit into
Conversation
oas:sync generated a different tree than uploading the same spec to ReadMe, so a repo initialized by upload drifted after a local sync: - Tag category pages (<tag>/index.md) were never generated, silently dropping the tag's description from the spec's top-level tags array. - The root reference/_order.yaml was never written, losing top-level ordering. - Slugs kept the operationId casing (getUserById.md) where the platform lowercases (getuserbyid.md), diverging URLs. - Generated pages omitted hidden: false. Generate the tag index.md (title from tag name, excerpt from tag description, never overwriting an existing one), maintain the root _order.yaml, lowercase slugs, and include hidden: false. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
WalkthroughOpenAPI synchronization now generates visible operation pages and per-tag 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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/commands/oas-sync.js (1)
253-253: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider generating tag index pages even when operation pages already exist.
Because this
continueskips the rest of the loop for already-synced operations, missing tag category pages (index.md) and their corresponding_order.yamlupdates won't be backfilled for tags whose operation pages were generated in previous runs.If the goal is to fully align with the platform and ensure all tags have an
index.mdregardless of their operations' page status, consider moving the tag index generation logic (lines 268-277) and the relevant_order.yamlupdates above this check.🤖 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/commands/oas-sync.js` at line 253, Update the operation-processing loop so tag index generation and its corresponding _order.yaml updates execute before the pagesByOpId.has(opId) early continue. Preserve the continue for already-existing operation pages, while still backfilling missing tag index.md pages and ordering entries.
🤖 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/commands/oas-sync.js`:
- Line 257: Update the slug derivation in the operation-page generation flow
around safeSegment to reserve the "index" slug: when the normalized operation
slug equals "index", append a distinct suffix before constructing pagePath,
while preserving existing slugs for all other operations.
---
Nitpick comments:
In `@src/commands/oas-sync.js`:
- Line 253: Update the operation-processing loop so tag index generation and its
corresponding _order.yaml updates execute before the pagesByOpId.has(opId) early
continue. Preserve the continue for already-existing operation pages, while
still backfilling missing tag index.md pages and ordering entries.
🪄 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: dc454943-2f4a-4b94-9bcc-52610b01a54c
📒 Files selected for processing (2)
src/commands/oas-sync.jstest/oas-sync.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)
| const slug = safeSegment(opId, 'operation'); | ||
| const rawTag = op.tag || 'Other'; | ||
| const tag = safeSegment(rawTag, 'Other'); | ||
| const slug = safeSegment(opId, 'operation').toLowerCase(); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Prevent the index slug from colliding with the tag category page.
If an operation's ID results in the slug 'index' (e.g., operationId: "index"), pagePath will evaluate to index.md. This causes the operation page to silently overwrite the newly generated tag category page (index.md) at line 279, pushing the exact same path to changes.added twice and incorrectly adding 'index' to the tag's _order.yaml.
Consider appending a suffix to the slug if it resolves to 'index' to prevent this collision.
🐛 Proposed fix to prevent collision
- const slug = safeSegment(opId, 'operation').toLowerCase();
+ let slug = safeSegment(opId, 'operation').toLowerCase();
+ if (slug === 'index') {
+ slug = 'index-operation';
+ }📝 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.
| const slug = safeSegment(opId, 'operation').toLowerCase(); | |
| let slug = safeSegment(opId, 'operation').toLowerCase(); | |
| if (slug === 'index') { | |
| slug = 'index-operation'; | |
| } |
🤖 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/commands/oas-sync.js` at line 257, Update the slug derivation in the
operation-page generation flow around safeSegment to reserve the "index" slug:
when the normalized operation slug equals "index", append a distinct suffix
before constructing pagePath, while preserving existing slugs for all other
operations.
There was a problem hiding this comment.
Yeah this is a valid issue. We should deduplicate any index operation ID pages so they don't collide with the parent page index.md files we expect.
And I don't think that the bot's suggestion to do index-operation is going to work because you could have an operation called index-operation. We'll need to do some unique slug generation work here to add -<num> suffixes to this instead.
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
ast-grep outline test/oas-sync.test.js --items all --type function
rg -n -C 5 -P '(operation-name collision|index\.md|operationId:\s*[\"\x27]index|destination already exists|lowercase)' test/oas-sync.test.js
rg -n -C 4 -P '\bpagePath\b|\bindexPath\b|\bslug\b|fs\.existsSync' src/commands/oas-sync.jsLength of output: 7583
@erunion, confirmed. The current test suite covers tag-index creation/preservation and normal operation-path collisions, but not the reserved index operation case.
The change should reserve index.md exclusively for the category page and, only when the normalized operation slug is index, probe index-1.md, index-2.md, etc. until it finds an available destination. Non-index slug collisions should retain the current skip behavior.
✏️ Learnings added
Learnt from: erunion
Repo: readmeio/cli PR: 35
File: src/commands/oas-sync.js:257-257
Timestamp: 2026-07-17T16:16:41.243Z
Learning: In `src/commands/oas-sync.js`, each OpenAPI tag directory reserves `index.md` for its tag category landing page. An operation whose normalized lowercased `operationId` is `index` must instead receive the first available numeric slug (`index-1`, `index-2`, and so on), rather than a fixed suffix, to avoid collisions with both the landing page and other operation pages.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
| file: oasFilename, | ||
| operationId, | ||
| }, | ||
| hidden: false, |
There was a problem hiding this comment.
Why do we need to add this in here? Can we rely on the defaults in our backend?
| const slug = safeSegment(opId, 'operation'); | ||
| const rawTag = op.tag || 'Other'; | ||
| const tag = safeSegment(rawTag, 'Other'); | ||
| const slug = safeSegment(opId, 'operation').toLowerCase(); |
There was a problem hiding this comment.
Yeah this is a valid issue. We should deduplicate any index operation ID pages so they don't collide with the parent page index.md files we expect.
And I don't think that the bot's suggestion to do index-operation is going to work because you could have an operation called index-operation. We'll need to do some unique slug generation work here to add -<num> suffixes to this instead.
Problem
oas:syncproduced a different tree than uploading the same OAS spec to ReadMe, so a repo initialized by upload drifted after a local sync:<tag>/index.md) were never generated — the tag'sdescriptionfrom the spec's top-leveltagsarray was silently dropped.reference/_order.yamlwas never written, losing top-level ordering.getUserById.md) where the platform lowercases (getuserbyid.md), diverging page URLs.hidden: false.Fix
In
syncOneOas:<tag>/index.md(title = tag name, excerpt = tag description) when creating a tag's first page — never overwriting an existing index, mirroring the existing never-clobber rule for op pages.reference/_order.yamlalongside the existing tag/op order files.hidden: falsein op-page frontmatter.Verification
reference/down to the spec, ran the patched sync, and diffed against the platform's actual upload output (committed state): identical file trees, byte-identical_order.yamlfiles, frontmatter matching on every page. Only remaining delta is a trailing newline (we emit POSIX-standard final newline; the upload does not).index.mdand the tag's entry in the parent_order.yamlare left behind — deliberately out of scope here (deleting an index risks eating hand-authored category pages; needs a provenance guard)._order.yamlmaintained; existingindex.mdnever overwritten; lowercased slugs +hidden: false), existing tests updated for the lowercase-slug behavior change. 89/89 passing.Independent of #33 and #34.
🤖 Generated with Claude Code