-
Notifications
You must be signed in to change notification settings - Fork 374
chore(repo): typedoc - Render accessors to markdown in the same fashion as properties #6532
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?
Conversation
🦋 Changeset detectedLatest commit: 95ac629 The changes in this PR will be included in the next version bump. This PR includes changesets to release 0 packagesWhen changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types 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 |
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
@clerk/agent-toolkit
@clerk/astro
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/dev-cli
@clerk/elements
@clerk/clerk-expo
@clerk/expo-passkeys
@clerk/express
@clerk/fastify
@clerk/localizations
@clerk/nextjs
@clerk/nuxt
@clerk/clerk-react
@clerk/react-router
@clerk/remix
@clerk/shared
@clerk/tanstack-react-start
@clerk/testing
@clerk/themes
@clerk/types
@clerk/upgrade
@clerk/vue
commit: |
📝 WalkthroughWalkthroughThe PR updates the custom TypeDoc Markdown theme to render Accessor members in a dedicated "Accessors" section: adds a new accessor partial, suppresses default per-accessor rendering in member, and changes memberWithGroups and signature to build and append an Accessors table with anchors, computed types, and prioritized descriptions. It also splits the TypeDoc generation script in package.json into two steps by adding typedoc:generate:skip-build and making typedoc:generate delegate to it after building declarations. A new empty changeset file (.changeset/old-dolls-smell.md) is added. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
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.
Actionable comments posted: 2
🧹 Nitpick comments (2)
package.json (1)
57-57
: Guard against wiping docs when Typedoc failsIf typedoc fails to produce .typedoc/temp-docs, the current script will remove .typedoc/docs and then fail on mv, leaving you without docs. Add a guard to only replace docs when the temp folder exists.
Apply this diff:
- "typedoc:generate:skip-build": "typedoc --tsconfig tsconfig.typedoc.json && rm -rf .typedoc/docs && mv .typedoc/temp-docs .typedoc/docs", + "typedoc:generate:skip-build": "typedoc --tsconfig tsconfig.typedoc.json && if [ -d .typedoc/temp-docs ]; then rm -rf .typedoc/docs && mv .typedoc/temp-docs .typedoc/docs; else echo 'Error: missing .typedoc/temp-docs (Typedoc may have failed)'; exit 1; fi",Also consider switching test:typedoc to use typedoc:generate:skip-build when declarations are already built in CI/local to speed the loop.
.typedoc/custom-theme.mjs (1)
221-273
: Add tests for Accessors table renderingNo tests are shown in this PR for the new Accessors table. Please add tests that assert:
- The “## Accessors” section is emitted when accessor members exist.
- Rows include correct Property, Type (getter-only, setter-only, getter+setter), and Description (preferring getter comment).
- Proper escaping of names and rendering of comment parts (inline code, links).
- Stable anchor generation for property rows.
I can help scaffold a small fixture class (e.g., User) and assertions against the generated Markdown.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
.typedoc/custom-theme.mjs
(2 hunks)package.json
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}
📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)
Use Prettier for consistent code formatting
Files:
package.json
**/*
⚙️ CodeRabbit Configuration File
If there are no tests added or modified as part of the PR, please suggest that tests be added to cover the changes.
Files:
package.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Build Packages
- GitHub Check: Formatting | Dedupe | Changeset
- GitHub Check: semgrep/ci
- GitHub Check: semgrep-cloud-platform/scan
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (2)
package.json (1)
56-57
: Decoupling build and docs generation looks goodSplitting Typedoc generation into build and skip-build steps makes the flow more flexible and cache-friendly. No issues spotted with the scripts as written.
.typedoc/custom-theme.mjs (1)
274-284
: Suppressing default Accessor rendering is correctReturning an empty string for ReflectionKind.Accessor prevents duplicate rendering now that accessors are handled in memberWithGroups. Looks good.
// Extract the Accessors group (if any) and prevent default rendering for it | ||
const originalGroups = customizedModel.groups; | ||
const accessorsGroup = originalGroups?.find(g => g.title === 'Accessors'); | ||
const groupsWithoutAccessors = originalGroups?.filter(g => g.title !== 'Accessors'); | ||
|
||
customizedModel.groups = groupsWithoutAccessors; | ||
const nonAccessorOutput = superPartials.memberWithGroups(customizedModel, options); | ||
customizedModel.groups = originalGroups; | ||
|
||
/** @type {string[]} */ | ||
const md = [nonAccessorOutput]; | ||
|
||
if (accessorsGroup && accessorsGroup.children && accessorsGroup.children.length > 0) { | ||
md.push('\n\n## Accessors\n'); | ||
// Table header | ||
// This needs to be 'Property' instead of 'Accessor' so that clerk.com renders it correctly | ||
md.push('| Property | Type | Description |'); | ||
md.push('| --- | --- | --- |'); | ||
|
||
for (const child of accessorsGroup.children) { | ||
/** @type {import('typedoc').DeclarationReflection} */ | ||
// @ts-ignore - child is a DeclarationReflection for accessor members | ||
const decl = child; | ||
// Name and anchor id | ||
const name = decl.name; | ||
const id = name.toLowerCase().replace(/[^a-z0-9]/g, ''); | ||
|
||
// Resolve the accessor type from the getter signature | ||
/** @type {any} */ | ||
const getterSig = /** @type {any} */ (decl).getSignature; | ||
/** @type {any} */ | ||
const setterSig = /** @type {any} */ (decl).setSignature; | ||
let typeStr = ''; | ||
if (getterSig?.type) { | ||
typeStr = this.partials.someType(getterSig.type); | ||
} else if (setterSig?.parameters?.[0]?.type) { | ||
typeStr = this.partials.someType(setterSig.parameters[0].type); | ||
} else if (decl.type) { | ||
typeStr = this.partials.someType(decl.type); | ||
} | ||
|
||
return output; | ||
// Prefer comment on the getter signature; fallback to declaration comment | ||
const summary = getterSig?.comment?.summary ?? decl.comment?.summary ?? setterSig?.comment?.summary; | ||
const description = Array.isArray(summary) | ||
? summary.reduce((acc, curr) => acc + (curr.text || ''), '') | ||
: ''; | ||
|
||
md.push(`| <a id="${id}"></a> \`${escapeChars(name)}\` | ${typeStr} | ${description} |`); | ||
} | ||
} | ||
|
||
return md.join('\n'); | ||
}, |
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.
🛠️ Refactor suggestion
Use getCommentParts for descriptions and add a safe fallback for empty types
Two improvements:
- Description: prefer the theme helper this.helpers.getCommentParts over manually reducing CommentDisplayPart[] so tags/formatting render correctly.
- Type: if neither getter, setter nor decl.type yields a type, use a visible placeholder (e.g., —) to avoid an empty table cell.
Apply this diff:
- let typeStr = '';
- if (getterSig?.type) {
- typeStr = this.partials.someType(getterSig.type);
- } else if (setterSig?.parameters?.[0]?.type) {
- typeStr = this.partials.someType(setterSig.parameters[0].type);
- } else if (decl.type) {
- typeStr = this.partials.someType(decl.type);
- }
+ let typeStr = '';
+ if (getterSig?.type) {
+ typeStr = this.partials.someType(getterSig.type);
+ } else if (setterSig?.parameters?.[0]?.type) {
+ typeStr = this.partials.someType(setterSig.parameters[0].type);
+ } else if (decl.type) {
+ typeStr = this.partials.someType(decl.type);
+ }
+ if (!typeStr) {
+ typeStr = '—';
+ }
@@
- // Prefer comment on the getter signature; fallback to declaration comment
- const summary = getterSig?.comment?.summary ?? decl.comment?.summary ?? setterSig?.comment?.summary;
- const description = Array.isArray(summary)
- ? summary.reduce((acc, curr) => acc + (curr.text || ''), '')
- : '';
+ // Prefer comment on the getter signature; fallback to declaration, then setter
+ const summaryParts =
+ getterSig?.comment?.summary ?? decl.comment?.summary ?? setterSig?.comment?.summary;
+ const description = summaryParts ? this.helpers.getCommentParts(summaryParts) : '';
Optional: to minimize potential ID collisions, consider prefixing the anchor with the parent name (e.g., ${decl.parent?.name}-${name}
) before sanitizing.
📝 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.
// Extract the Accessors group (if any) and prevent default rendering for it | |
const originalGroups = customizedModel.groups; | |
const accessorsGroup = originalGroups?.find(g => g.title === 'Accessors'); | |
const groupsWithoutAccessors = originalGroups?.filter(g => g.title !== 'Accessors'); | |
customizedModel.groups = groupsWithoutAccessors; | |
const nonAccessorOutput = superPartials.memberWithGroups(customizedModel, options); | |
customizedModel.groups = originalGroups; | |
/** @type {string[]} */ | |
const md = [nonAccessorOutput]; | |
if (accessorsGroup && accessorsGroup.children && accessorsGroup.children.length > 0) { | |
md.push('\n\n## Accessors\n'); | |
// Table header | |
// This needs to be 'Property' instead of 'Accessor' so that clerk.com renders it correctly | |
md.push('| Property | Type | Description |'); | |
md.push('| --- | --- | --- |'); | |
for (const child of accessorsGroup.children) { | |
/** @type {import('typedoc').DeclarationReflection} */ | |
// @ts-ignore - child is a DeclarationReflection for accessor members | |
const decl = child; | |
// Name and anchor id | |
const name = decl.name; | |
const id = name.toLowerCase().replace(/[^a-z0-9]/g, ''); | |
// Resolve the accessor type from the getter signature | |
/** @type {any} */ | |
const getterSig = /** @type {any} */ (decl).getSignature; | |
/** @type {any} */ | |
const setterSig = /** @type {any} */ (decl).setSignature; | |
let typeStr = ''; | |
if (getterSig?.type) { | |
typeStr = this.partials.someType(getterSig.type); | |
} else if (setterSig?.parameters?.[0]?.type) { | |
typeStr = this.partials.someType(setterSig.parameters[0].type); | |
} else if (decl.type) { | |
typeStr = this.partials.someType(decl.type); | |
} | |
return output; | |
// Prefer comment on the getter signature; fallback to declaration comment | |
const summary = getterSig?.comment?.summary ?? decl.comment?.summary ?? setterSig?.comment?.summary; | |
const description = Array.isArray(summary) | |
? summary.reduce((acc, curr) => acc + (curr.text || ''), '') | |
: ''; | |
md.push(`| <a id="${id}"></a> \`${escapeChars(name)}\` | ${typeStr} | ${description} |`); | |
} | |
} | |
return md.join('\n'); | |
}, | |
for (const child of accessorsGroup.children) { | |
/** @type {import('typedoc').DeclarationReflection} */ | |
// @ts-ignore - child is a DeclarationReflection for accessor members | |
const decl = child; | |
// Name and anchor id | |
const name = decl.name; | |
const id = name.toLowerCase().replace(/[^a-z0-9]/g, ''); | |
// Resolve the accessor type from the getter signature | |
/** @type {any} */ | |
const getterSig = /** @type {any} */ (decl).getSignature; | |
/** @type {any} */ | |
const setterSig = /** @type {any} */ (decl).setSignature; | |
let typeStr = ''; | |
if (getterSig?.type) { | |
typeStr = this.partials.someType(getterSig.type); | |
} else if (setterSig?.parameters?.[0]?.type) { | |
typeStr = this.partials.someType(setterSig.parameters?.[0].type); | |
} else if (decl.type) { | |
typeStr = this.partials.someType(decl.type); | |
} | |
if (!typeStr) { | |
typeStr = '—'; | |
} | |
// Prefer comment on the getter signature; fallback to declaration, then setter | |
const summaryParts = | |
getterSig?.comment?.summary ?? decl.comment?.summary ?? setterSig?.comment?.summary; | |
const description = summaryParts ? this.helpers.getCommentParts(summaryParts) : ''; | |
md.push(`| <a id="${id}"></a> \`${escapeChars(name)}\` | ${typeStr} | ${description} |`); | |
} |
🤖 Prompt for AI Agents
In .typedoc/custom-theme.mjs around lines 221 to 273, the accessor table
currently builds descriptions by manually reducing CommentDisplayPart[] and
leaves the Type cell empty when no type is resolved; change the description
extraction to use this.helpers.getCommentParts (or
this.helpers.getCommentParts(summary) equivalent) so tags/formatting render
correctly, and ensure typeStr defaults to a visible placeholder (e.g., '—') when
getter/setter/decl.type are all absent; also, to reduce anchor collisions,
prefix the id with the parent name when present (e.g.,
`${decl.parent?.name}-${name}`) before sanitizing and lowercasing.
/** | ||
* @param {import('typedoc').DeclarationReflection} model | ||
*/ | ||
accessor: model => { | ||
// Fallback single-row rendering if used directly elsewhere | ||
const name = model.name; | ||
const typeStr = model.getSignature?.type ? this.partials.someType(model.getSignature.type) : ''; | ||
const summary = model.getSignature?.comment?.summary ?? model.comment?.summary; | ||
const description = Array.isArray(summary) ? summary.reduce((acc, curr) => acc + (curr.text || ''), '') : ''; | ||
return '| ' + '`' + escapeChars(name) + '`' + ' | ' + typeStr + ' | ' + description + ' |'; | ||
}, | ||
}; |
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.
🛠️ Refactor suggestion
Align fallback accessor partial with main table logic
For consistency, compute type from getter or setter (with fallback placeholder) and use getCommentParts for the description. This keeps standalone accessor rendering consistent with the table.
Apply this diff:
- accessor: model => {
- // Fallback single-row rendering if used directly elsewhere
- const name = model.name;
- const typeStr = model.getSignature?.type ? this.partials.someType(model.getSignature.type) : '';
- const summary = model.getSignature?.comment?.summary ?? model.comment?.summary;
- const description = Array.isArray(summary) ? summary.reduce((acc, curr) => acc + (curr.text || ''), '') : '';
- return '| ' + '`' + escapeChars(name) + '`' + ' | ' + typeStr + ' | ' + description + ' |';
- },
+ accessor: model => {
+ // Fallback single-row rendering if used directly elsewhere
+ const name = model.name;
+ let typeStr = '';
+ if (model.getSignature?.type) {
+ typeStr = this.partials.someType(model.getSignature.type);
+ } else if (model.setSignature?.parameters?.[0]?.type) {
+ typeStr = this.partials.someType(model.setSignature.parameters[0].type);
+ } else if (model.type) {
+ typeStr = this.partials.someType(model.type);
+ }
+ if (!typeStr) {
+ typeStr = '—';
+ }
+ const summaryParts =
+ model.getSignature?.comment?.summary ?? model.comment?.summary ?? model.setSignature?.comment?.summary;
+ const description = summaryParts ? this.helpers.getCommentParts(summaryParts) : '';
+ return '| ' + '`' + escapeChars(name) + '`' + ' | ' + typeStr + ' | ' + description + ' |';
+ },
📝 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.
/** | |
* @param {import('typedoc').DeclarationReflection} model | |
*/ | |
accessor: model => { | |
// Fallback single-row rendering if used directly elsewhere | |
const name = model.name; | |
const typeStr = model.getSignature?.type ? this.partials.someType(model.getSignature.type) : ''; | |
const summary = model.getSignature?.comment?.summary ?? model.comment?.summary; | |
const description = Array.isArray(summary) ? summary.reduce((acc, curr) => acc + (curr.text || ''), '') : ''; | |
return '| ' + '`' + escapeChars(name) + '`' + ' | ' + typeStr + ' | ' + description + ' |'; | |
}, | |
}; | |
accessor: model => { | |
// Fallback single-row rendering if used directly elsewhere | |
const name = model.name; | |
let typeStr = ''; | |
if (model.getSignature?.type) { | |
typeStr = this.partials.someType(model.getSignature.type); | |
} else if (model.setSignature?.parameters?.[0]?.type) { | |
typeStr = this.partials.someType(model.setSignature.parameters[0].type); | |
} else if (model.type) { | |
typeStr = this.partials.someType(model.type); | |
} | |
if (!typeStr) { | |
typeStr = '—'; | |
} | |
const summaryParts = | |
model.getSignature?.comment?.summary ?? model.comment?.summary ?? model.setSignature?.comment?.summary; | |
const description = summaryParts ? this.helpers.getCommentParts(summaryParts) : ''; | |
return '| ' + '`' + escapeChars(name) + '`' + ' | ' + typeStr + ' | ' + description + ' |'; | |
}, |
🤖 Prompt for AI Agents
In .typedoc/custom-theme.mjs around lines 475 to 486, the fallback accessor
partial currently only reads type from getSignature and builds description
manually; update it to compute type from either getSignature or setSignature
(falling back to the same placeholder used by the main table) and replace the
manual summary/description assembly with a call to getCommentParts for the
appropriate signature so the standalone accessor rendering matches the main
table logic.
Description
the
User
class has accessors on itLargely speaking for a consumer of Clerk, these work no differently than standard properties, so we should document them the same. This pr renders them out as a properties table:
Getting us a very nice table in clerk.com
Checklist
pnpm test
runs as expected.pnpm build
runs as expected.Type of change
Summary by CodeRabbit