docs(docs-infra): Validate case-sensitive API symbol links in @link

Adds build-time validation for case-sensitive API symbols in `@link`. Avoid broken links

(cherry picked from commit d2c7b4e111)
This commit is contained in:
SkyZeroZx 2026-04-26 13:06:46 -05:00 committed by Alon Mishne
parent 27da56ee9d
commit fa4eff36cb
3 changed files with 39 additions and 1 deletions

View file

@ -199,6 +199,23 @@ describe('jsdoc transforms', () => {
expect(entryFn).toThrowError(/Forbidden relative link: cli\/build ng build/);
});
it('should throw on a miscased absolute @link to a known API symbol', () => {
setSymbols({RouterModule: 'router'});
const entryFn = () =>
addHtmlAdditionalLinks({
jsdocTags: [
{
name: 'see',
comment: '{@link /api/router/routerModule#forRoot forRoot}',
},
],
moduleName: 'test',
});
expect(entryFn).toThrowError(/Broken @link.*Did you mean \/api\/router\/RouterModule/);
});
});
describe('addHtmlDescription', () => {

View file

@ -223,6 +223,27 @@ function parseAtLink(link: string): {label: string; url: string} | undefined {
);
}
// Validate absolute `/api/...` links against the known symbol registry. This catches
// miscased symbol names (e.g. `/api/router/routerModule` instead of
// `/api/router/RouterModule`) at build time.
if (rawSymbol.startsWith('/api/')) {
const [pathPart] = rawSymbol.split('#');
const segments = pathPart.split('/').filter((s) => s.length > 0);
const symbolName = segments[segments.length - 1];
// Case-insensitive lookup: find the canonical symbol name in the registry.
const knownSymbols = Object.keys(getSymbolsAsApiEntries());
const canonicalSymbol = knownSymbols.find(
(s) => s.toLowerCase() === symbolName.toLowerCase(),
);
if (canonicalSymbol && canonicalSymbol !== symbolName) {
const expectedUrl = getSymbolUrl(canonicalSymbol);
throw Error(
`Broken @link: ${link}. Did you mean ${expectedUrl}? ` +
`Symbol names in API URLs are case-sensitive.`,
);
}
}
return {
url: rawSymbol,
label: description ?? rawSymbol.split('/').pop()!,

View file

@ -197,7 +197,7 @@ export interface InMemoryScrollingOptions {
* A set of configuration options for a router module, provided in the
* `forRoot()` method.
*
* @see {@link /api/router/routerModule#forRoot forRoot}
* @see {@link /api/router/RouterModule#forRoot forRoot}
*
*
* @publicApi