mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
docs(docs-infra): Throw error at build time for invalid links (#59162)
PR Close #59162
This commit is contained in:
parent
6dd8cce155
commit
286e4da52b
5 changed files with 47 additions and 20 deletions
|
|
@ -38,8 +38,6 @@ export function getCurrentSymbol(): string | undefined {
|
|||
return currentSymbol;
|
||||
}
|
||||
|
||||
export function logUnknownSymbol(link: string, symbol: string): void {
|
||||
console.warn(
|
||||
`WARNING: {@link ${link}} is invalid, ${symbol} or ${currentSymbol}.${symbol} is unknown in this context`,
|
||||
);
|
||||
export function unknownSymbolMessage(link: string, symbol: string): string {
|
||||
return `WARNING: {@link ${link}} is invalid, ${symbol} or ${currentSymbol}.${symbol} is unknown in this context`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,13 @@ describe('markdown to html', () => {
|
|||
const symbols = new Map<string, string>([
|
||||
['AfterRenderPhase', 'core'],
|
||||
['afterRender', 'core'],
|
||||
['EmbeddedViewRef', 'core'],
|
||||
['ChangeDetectionStrategy', 'core'],
|
||||
['ChangeDetectorRef', 'core'],
|
||||
['withNoHttpTransferCache', 'platform-browser'],
|
||||
['withHttpTransferCacheOptions', 'platform-browser'],
|
||||
['withI18nSupport', 'platform-browser'],
|
||||
['withEventReplay', 'platform-browser'],
|
||||
]);
|
||||
setSymbols(symbols);
|
||||
for (const entry of entryJson.entries) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {getRenderable} from '../processing';
|
|||
import {DocEntryRenderable} from '../entities/renderables';
|
||||
import {initHighlighter} from '../shiki/shiki';
|
||||
import {configureMarkedGlobally} from '../marked/configuration';
|
||||
import {setSymbols} from '../symbol-context';
|
||||
|
||||
// Note: The tests will probably break if the schema of the api extraction changes.
|
||||
// All entries in the fake-entries are extracted from Angular's api.
|
||||
|
|
@ -28,6 +29,19 @@ describe('renderable', () => {
|
|||
encoding: 'utf-8',
|
||||
});
|
||||
const entryJson = JSON.parse(entryContent) as any;
|
||||
const symbols = new Map<string, string>([
|
||||
['AfterRenderPhase', 'core'],
|
||||
['afterRender', 'core'],
|
||||
['EmbeddedViewRef', 'core'],
|
||||
['ChangeDetectionStrategy', 'core'],
|
||||
['ChangeDetectorRef', 'core'],
|
||||
['withNoHttpTransferCache', 'platform-browser'],
|
||||
['withHttpTransferCacheOptions', 'platform-browser'],
|
||||
['withI18nSupport', 'platform-browser'],
|
||||
['withEventReplay', 'platform-browser'],
|
||||
]);
|
||||
setSymbols(symbols);
|
||||
|
||||
for (const entry of entryJson.entries) {
|
||||
const renderableJson = getRenderable(entry, '@angular/fakeentry') as DocEntryRenderable;
|
||||
entries.set(entry['name'], renderableJson);
|
||||
|
|
|
|||
|
|
@ -70,10 +70,6 @@ describe('jsdoc transforms', () => {
|
|||
name: 'see',
|
||||
comment: '{@link /cli/build ng build}',
|
||||
},
|
||||
{
|
||||
name: 'see',
|
||||
comment: '{@link cli/build ng build}',
|
||||
},
|
||||
{
|
||||
name: 'see',
|
||||
comment: '{@link /ecosystem/rxjs-interop/output-interop Output Interop}',
|
||||
|
|
@ -135,16 +131,24 @@ describe('jsdoc transforms', () => {
|
|||
url: '/cli/build',
|
||||
});
|
||||
|
||||
// TODO: in the future when all links are valid we would throw an error instead when not starting with a slash
|
||||
// Links should be absolute within adev (to support both next & stable site)
|
||||
expect(entry.additionalLinks[11]).toEqual({
|
||||
label: 'ng build',
|
||||
url: 'cli/build',
|
||||
});
|
||||
|
||||
expect(entry.additionalLinks[12]).toEqual({
|
||||
label: 'Output Interop',
|
||||
url: '/ecosystem/rxjs-interop/output-interop',
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw on invalid relatie @link', () => {
|
||||
const entryFn = () =>
|
||||
addHtmlAdditionalLinks({
|
||||
jsdocTags: [
|
||||
{
|
||||
name: 'see',
|
||||
comment: '{@link cli/build ng build}',
|
||||
},
|
||||
],
|
||||
moduleName: 'test',
|
||||
});
|
||||
|
||||
expect(entryFn).toThrowError(/Forbidden relative link: cli\/build ng build/);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import {
|
|||
|
||||
import {getLinkToModule} from './url-transforms';
|
||||
import {addApiLinksToHtml} from './code-transforms';
|
||||
import {getCurrentSymbol, getModuleName, logUnknownSymbol} from '../symbol-context';
|
||||
import {getCurrentSymbol, getModuleName, unknownSymbolMessage} from '../symbol-context';
|
||||
|
||||
export const JS_DOC_REMARKS_TAG = 'remarks';
|
||||
export const JS_DOC_USAGE_NOTES_TAG = 'usageNotes';
|
||||
|
|
@ -186,6 +186,12 @@ function parseAtLink(link: string): {label: string; url: string} {
|
|||
if (rawSymbol.startsWith('#')) {
|
||||
rawSymbol = rawSymbol.substring(1);
|
||||
} else if (rawSymbol.includes('/')) {
|
||||
if (!rawSymbol.startsWith('/') && !rawSymbol.startsWith('http')) {
|
||||
throw Error(
|
||||
`Forbidden relative link: ${link}. Links should be absolute and start with a slash`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
url: rawSymbol,
|
||||
label: description ?? rawSymbol.split('/').pop()!,
|
||||
|
|
@ -204,11 +210,9 @@ function parseAtLink(link: string): {label: string; url: string} {
|
|||
moduleName = getModuleName(`${currentSymbol}.${symbol}`);
|
||||
|
||||
if (!moduleName || !currentSymbol) {
|
||||
// TODO: remove the links that generate this error
|
||||
// TODO: throw an error when there are no more warning generated
|
||||
logUnknownSymbol(link, symbol);
|
||||
return {label, url: '#'};
|
||||
throw unknownSymbolMessage(link, symbol);
|
||||
}
|
||||
|
||||
subSymbol = symbol;
|
||||
symbol = currentSymbol;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue