diff --git a/adev/shared-docs/pipeline/api-gen/rendering/entities/traits.mts b/adev/shared-docs/pipeline/api-gen/rendering/entities/traits.mts
index 190a5697a1b..6efc2724607 100644
--- a/adev/shared-docs/pipeline/api-gen/rendering/entities/traits.mts
+++ b/adev/shared-docs/pipeline/api-gen/rendering/entities/traits.mts
@@ -22,6 +22,10 @@ export interface HasJsDocTags {
jsdocTags: JsDocTagEntry[];
}
+export interface MaybeJsDocTags {
+ jsdocTags?: JsDocTagEntry[];
+}
+
export interface HasAdditionalLinks {
additionalLinks: LinkEntryRenderable[];
}
diff --git a/adev/shared-docs/pipeline/api-gen/rendering/templates/function-reference.tsx b/adev/shared-docs/pipeline/api-gen/rendering/templates/function-reference.tsx
index e1aa46b849b..408f9baa769 100644
--- a/adev/shared-docs/pipeline/api-gen/rendering/templates/function-reference.tsx
+++ b/adev/shared-docs/pipeline/api-gen/rendering/templates/function-reference.tsx
@@ -73,13 +73,14 @@ export function FunctionReference(entry: FunctionEntryRenderable) {
- {entry.signatures.map((s, i) =>
- signatureCard(s.name, getFunctionMetadataRenderable(s, entry.moduleName, entry.repo), {
- id: `${s.name}_${i}`,
- printSignaturesAsHeader,
- hideUsageNotes: true,
- }),
- )}
+ {entry.signatures.length > 1 &&
+ entry.signatures.map((s, i) =>
+ signatureCard(s.name, getFunctionMetadataRenderable(s, entry.moduleName, entry.repo), {
+ id: `${s.name}_${i}`,
+ printSignaturesAsHeader,
+ hideUsageNotes: true,
+ }),
+ )}
diff --git a/adev/shared-docs/pipeline/api-gen/rendering/test/marked.spec.mts b/adev/shared-docs/pipeline/api-gen/rendering/test/marked.spec.mts
index 2c2a0cf9c2a..a3ecd04d120 100644
--- a/adev/shared-docs/pipeline/api-gen/rendering/test/marked.spec.mts
+++ b/adev/shared-docs/pipeline/api-gen/rendering/test/marked.spec.mts
@@ -8,12 +8,12 @@
import {readFile} from 'fs/promises';
import {JSDOM} from 'jsdom';
-import {getRenderable} from '../processing.mjs';
-import {renderEntry} from '../rendering.mjs';
-import {setSymbols} from '../symbol-context.mjs';
import {resolve} from 'path';
import {initHighlighter} from '../../../shared/shiki.mjs';
+import {getRenderable} from '../processing.mjs';
+import {renderEntry} from '../rendering.mjs';
import {setHighlighterInstance} from '../shiki/shiki.mjs';
+import {setSymbols} from '../symbol-context.mjs';
// 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.
@@ -69,7 +69,7 @@ describe('markdown to html', () => {
it('should render multiple {@link} blocks', () => {
const provideClientHydrationEntry = entries.get('provideClientHydration')!;
expect(provideClientHydrationEntry).toBeDefined();
- const cardItem = provideClientHydrationEntry.querySelector('.docs-reference-card-item')!;
+ const cardItem = provideClientHydrationEntry.querySelector('.docs-api')!;
expect(cardItem.innerHTML).not.toContain('@link');
});
diff --git a/adev/shared-docs/pipeline/api-gen/rendering/test/transforms/jsdoc-transforms.spec.mts b/adev/shared-docs/pipeline/api-gen/rendering/test/transforms/jsdoc-transforms.spec.mts
index bcf7f022703..285345badc6 100644
--- a/adev/shared-docs/pipeline/api-gen/rendering/test/transforms/jsdoc-transforms.spec.mts
+++ b/adev/shared-docs/pipeline/api-gen/rendering/test/transforms/jsdoc-transforms.spec.mts
@@ -17,204 +17,207 @@ import {
// @ts-ignore This compiles fine, but Webstorm doesn't like the ESM import in a CJS context.
describe('jsdoc transforms', () => {
- it('should transform links', () => {
- setCurrentSymbol('Router');
- setSymbols(
- Object.fromEntries([
- ['Route', 'test'],
- ['Router', 'test'],
- ['Router.someMethod', 'test'],
- ['Router.someMethodWithParenthesis', 'test'],
- ['FormGroup', 'test'],
- ['FormGroup.someMethod', 'test'],
- ]),
- );
+ describe('addHtmlAdditionalLinks', () => {
+ it('should transform links', () => {
+ setCurrentSymbol('Router');
+ setSymbols(
+ Object.fromEntries([
+ ['Route', 'test'],
+ ['Router', 'test'],
+ ['Router.someMethod', 'test'],
+ ['Router.someMethodWithParenthesis', 'test'],
+ ['FormGroup', 'test'],
+ ['FormGroup.someMethod', 'test'],
+ ]),
+ );
- const entry = addHtmlAdditionalLinks({
- jsdocTags: [
- {
- name: 'see',
- comment: '[Angular](https://angular.io)',
- },
- {
- name: 'see',
- comment: '[Angular](https://angular.io "Angular")',
- },
- {
- name: 'see',
- comment: '{@link Route}',
- },
- {
- name: 'see',
- comment: '{@link Route Something else}',
- },
- {
- name: 'see',
- comment: '{@link #someMethod}',
- },
- {
- name: 'see',
- comment: '{@link #someMethodWithParenthesis()}',
- },
- {
- name: 'see',
- comment: '{@link someMethod()}',
- },
- {
- name: 'see',
- comment: '{@link FormGroup.someMethod()}',
- },
- {
- name: 'see',
- comment: '{@link https://angular.dev/api/core/ApplicationRef}',
- },
- {
- name: 'see',
- comment: '{@link https://angular.dev}',
- },
- {
- name: 'see',
- comment: '{@link /cli/build ng build}',
- },
- {
- name: 'see',
- comment: '{@link /ecosystem/rxjs-interop/output-interop Output Interop}',
- },
- ],
- moduleName: 'test',
- });
-
- expect(entry.additionalLinks[0]).toEqual({
- label: 'Angular',
- url: 'https://angular.io',
- title: undefined,
- });
-
- expect(entry.additionalLinks[1]).toEqual({
- label: 'Angular',
- url: 'https://angular.io',
- title: 'Angular',
- });
-
- expect(entry.additionalLinks[2]).toEqual({
- label: 'Route',
- url: '/api/test/Route',
- });
-
- expect(entry.additionalLinks[3]).toEqual({
- label: 'Something else',
- url: '/api/test/Route',
- });
-
- expect(entry.additionalLinks[4]).toEqual({
- label: 'someMethod',
- url: '/api/test/Router#someMethod',
- });
- expect(entry.additionalLinks[5]).toEqual({
- label: 'someMethodWithParenthesis()',
- url: '/api/test/Router#someMethodWithParenthesis',
- });
- expect(entry.additionalLinks[6]).toEqual({
- label: 'someMethod()',
- url: '/api/test/Router#someMethod',
- });
- expect(entry.additionalLinks[7]).toEqual({
- label: 'FormGroup.someMethod()',
- url: '/api/test/FormGroup#someMethod',
- });
-
- expect(entry.additionalLinks[8]).toEqual({
- label: 'ApplicationRef',
- url: 'https://angular.dev/api/core/ApplicationRef',
- });
- expect(entry.additionalLinks[9]).toEqual({
- label: 'angular.dev',
- url: 'https://angular.dev',
- });
-
- expect(entry.additionalLinks[10]).toEqual({
- label: 'ng build',
- url: '/cli/build',
- });
-
- expect(entry.additionalLinks[11]).toEqual({
- label: 'Output Interop',
- url: '/ecosystem/rxjs-interop/output-interop',
- });
- });
-
- it('should convert backticks to code tags in markdown links', () => {
- const entry = addHtmlAdditionalLinks({
- jsdocTags: [
- {
- name: 'see',
- comment:
- '[Host view using `ViewContainerRef.createComponent`](guide/components/programmatic-rendering#host-view-using-viewcontainerrefcreatecomponent)',
- },
- {
- name: 'see',
- comment:
- '[Popup attached to `document.body` with `createComponent` + `hostElement`](guide/components/programmatic-rendering#popup-attached-to-documentbody-with-createcomponent--hostelement)',
- },
- {
- name: 'see',
- comment: '[Method with `backticks` in title](https://example.com "Title with `code`")',
- },
- ],
- moduleName: 'test',
- });
-
- expect(entry.additionalLinks[0]).toEqual({
- label: 'Host view using ViewContainerRef.createComponent',
- url: 'guide/components/programmatic-rendering#host-view-using-viewcontainerrefcreatecomponent',
- title: undefined,
- });
-
- expect(entry.additionalLinks[1]).toEqual({
- label:
- 'Popup attached to document.body with createComponent + hostElement',
- url: 'guide/components/programmatic-rendering#popup-attached-to-documentbody-with-createcomponent--hostelement',
- title: undefined,
- });
-
- expect(entry.additionalLinks[2]).toEqual({
- label: 'Method with backticks in title',
- url: 'https://example.com',
- title: 'Title with `code`',
- });
- });
-
- it('should throw on invalid relatie @link', () => {
- const entryFn = () =>
- addHtmlAdditionalLinks({
+ const entry = addHtmlAdditionalLinks({
jsdocTags: [
{
name: 'see',
- comment: '{@link cli/build ng build}',
+ comment: '[Angular](https://angular.io)',
+ },
+ {
+ name: 'see',
+ comment: '[Angular](https://angular.io "Angular")',
+ },
+ {
+ name: 'see',
+ comment: '{@link Route}',
+ },
+ {
+ name: 'see',
+ comment: '{@link Route Something else}',
+ },
+ {
+ name: 'see',
+ comment: '{@link #someMethod}',
+ },
+ {
+ name: 'see',
+ comment: '{@link #someMethodWithParenthesis()}',
+ },
+ {
+ name: 'see',
+ comment: '{@link someMethod()}',
+ },
+ {
+ name: 'see',
+ comment: '{@link FormGroup.someMethod()}',
+ },
+ {
+ name: 'see',
+ comment: '{@link https://angular.dev/api/core/ApplicationRef}',
+ },
+ {
+ name: 'see',
+ comment: '{@link https://angular.dev}',
+ },
+ {
+ name: 'see',
+ comment: '{@link /cli/build ng build}',
+ },
+ {
+ name: 'see',
+ comment: '{@link /ecosystem/rxjs-interop/output-interop Output Interop}',
},
],
moduleName: 'test',
});
- expect(entryFn).toThrowError(/Forbidden relative link: cli\/build ng build/);
+ expect(entry.additionalLinks[0]).toEqual({
+ label: 'Angular',
+ url: 'https://angular.io',
+ title: undefined,
+ });
+
+ expect(entry.additionalLinks[1]).toEqual({
+ label: 'Angular',
+ url: 'https://angular.io',
+ title: 'Angular',
+ });
+
+ expect(entry.additionalLinks[2]).toEqual({
+ label: 'Route',
+ url: '/api/test/Route',
+ });
+
+ expect(entry.additionalLinks[3]).toEqual({
+ label: 'Something else',
+ url: '/api/test/Route',
+ });
+
+ expect(entry.additionalLinks[4]).toEqual({
+ label: 'someMethod',
+ url: '/api/test/Router#someMethod',
+ });
+ expect(entry.additionalLinks[5]).toEqual({
+ label: 'someMethodWithParenthesis()',
+ url: '/api/test/Router#someMethodWithParenthesis',
+ });
+ expect(entry.additionalLinks[6]).toEqual({
+ label: 'someMethod()',
+ url: '/api/test/Router#someMethod',
+ });
+ expect(entry.additionalLinks[7]).toEqual({
+ label: 'FormGroup.someMethod()',
+ url: '/api/test/FormGroup#someMethod',
+ });
+
+ expect(entry.additionalLinks[8]).toEqual({
+ label: 'ApplicationRef',
+ url: 'https://angular.dev/api/core/ApplicationRef',
+ });
+ expect(entry.additionalLinks[9]).toEqual({
+ label: 'angular.dev',
+ url: 'https://angular.dev',
+ });
+
+ expect(entry.additionalLinks[10]).toEqual({
+ label: 'ng build',
+ url: '/cli/build',
+ });
+
+ expect(entry.additionalLinks[11]).toEqual({
+ label: 'Output Interop',
+ url: '/ecosystem/rxjs-interop/output-interop',
+ });
+ });
+
+ it('should convert backticks to code tags in markdown links', () => {
+ const entry = addHtmlAdditionalLinks({
+ jsdocTags: [
+ {
+ name: 'see',
+ comment:
+ '[Host view using `ViewContainerRef.createComponent`](guide/components/programmatic-rendering#host-view-using-viewcontainerrefcreatecomponent)',
+ },
+ {
+ name: 'see',
+ comment:
+ '[Popup attached to `document.body` with `createComponent` + `hostElement`](guide/components/programmatic-rendering#popup-attached-to-documentbody-with-createcomponent--hostelement)',
+ },
+ {
+ name: 'see',
+ comment: '[Method with `backticks` in title](https://example.com "Title with `code`")',
+ },
+ ],
+ moduleName: 'test',
+ });
+
+ expect(entry.additionalLinks[0]).toEqual({
+ label: 'Host view using ViewContainerRef.createComponent',
+ url: 'guide/components/programmatic-rendering#host-view-using-viewcontainerrefcreatecomponent',
+ title: undefined,
+ });
+
+ expect(entry.additionalLinks[1]).toEqual({
+ label:
+ 'Popup attached to document.body with createComponent + hostElement',
+ url: 'guide/components/programmatic-rendering#popup-attached-to-documentbody-with-createcomponent--hostelement',
+ title: undefined,
+ });
+
+ expect(entry.additionalLinks[2]).toEqual({
+ label: 'Method with backticks in title',
+ url: 'https://example.com',
+ title: 'Title with `code`',
+ });
+ });
+
+ 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/);
+ });
});
- it('should parse markdown in descriptions', async () => {
- setHighlighterInstance(await initHighlighter());
+ describe('addHtmlDescription', () => {
+ it('should parse markdown in descriptions', async () => {
+ setHighlighterInstance(await initHighlighter());
- setSymbols(
- Object.fromEntries([
- ['Route', 'test'],
- ['Router', 'angular/router'],
- ['Router.someMethod', 'test'],
- ['Router.someMethodWithParenthesis', 'test'],
- ['FormGroup', 'test'],
- ['FormGroup.someMethod', 'test'],
- ]),
- );
+ setSymbols(
+ Object.fromEntries([
+ ['Route', 'test'],
+ ['Router', 'angular/router'],
+ ['Router.someMethod', 'test'],
+ ['Router.someMethodWithParenthesis', 'test'],
+ ['FormGroup', 'test'],
+ ['FormGroup.someMethod', 'test'],
+ ]),
+ );
- const entry = addHtmlDescription({
- description: `
+ const entry = addHtmlDescription({
+ description: `
\`\`\`angular-ts
import { Router } from '@angular/router';
@@ -223,16 +226,36 @@ function setupRouter() {
}
\`\`\`
`,
- moduleName: 'test',
+ moduleName: 'test',
+ });
+
+ // Should have some shiki variables (meaning the description was highlighted).
+ expect(entry.htmlDescription).toContain('--shiki');
+
+ // Having docs-code means that the description was parsed and formatted correctly (by the shared marked renderer)
+ expect(entry.htmlDescription).toContain('class="docs-code"');
+
+ expect(entry.htmlDescription).toContain('/api/angular/router/Router');
});
- // Should have some shiki variables (meaning the description was highlighted).
- expect(entry.htmlDescription).toContain('--shiki');
+ it('should transform entry with different description & description tag', () => {
+ const entry = addHtmlDescription({
+ 'description':
+ "Enables interop with the browser's `Navigation` API for router navigations.",
+ 'jsdocTags': [
+ {
+ 'name': 'description',
+ 'comment': 'This feature is _highly_ experimental ...',
+ },
+ ],
+ 'moduleName': 'platform-browser',
+ });
- // Having docs-code means that the description was parsed and formatted correctly (by the shared marked renderer)
- expect(entry.htmlDescription).toContain('class="docs-code"');
-
- expect(entry.htmlDescription).toContain('/api/angular/router/Router');
+ expect(entry.htmlDescription).toBe(`This feature is highly experimental ...
`);
+ expect(entry.shortHtmlDescription).toBe(
+ `Enables interop with the browser's Navigation API for router navigations.
`,
+ );
+ });
});
it('should only mark as deprecated if all overloads are deprecated', () => {
diff --git a/adev/shared-docs/pipeline/api-gen/rendering/transforms/function-transforms.mts b/adev/shared-docs/pipeline/api-gen/rendering/transforms/function-transforms.mts
index 46befb4cdbb..7b2468a0c45 100644
--- a/adev/shared-docs/pipeline/api-gen/rendering/transforms/function-transforms.mts
+++ b/adev/shared-docs/pipeline/api-gen/rendering/transforms/function-transforms.mts
@@ -29,7 +29,7 @@ export async function getFunctionRenderable(
moduleName: string,
repo: string,
): Promise {
- return setEntryFlags(
+ const a = setEntryFlags(
await addRenderableCodeToc(
addHtmlAdditionalLinks(
addHtmlUsageNotes(
@@ -42,6 +42,11 @@ export async function getFunctionRenderable(
),
),
);
+ if (entry.name === 'withExperimentalPlatformNavigation') {
+ console.warn('**************', a);
+ }
+
+ return a;
}
export function getFunctionMetadataRenderable(
diff --git a/adev/shared-docs/pipeline/api-gen/rendering/transforms/jsdoc-transforms.mts b/adev/shared-docs/pipeline/api-gen/rendering/transforms/jsdoc-transforms.mts
index 4a49c2459f7..98f7822a2d1 100644
--- a/adev/shared-docs/pipeline/api-gen/rendering/transforms/jsdoc-transforms.mts
+++ b/adev/shared-docs/pipeline/api-gen/rendering/transforms/jsdoc-transforms.mts
@@ -22,6 +22,7 @@ import {
HasModuleName,
HasRenderableJsDocTags,
HasStableFlag,
+ MaybeJsDocTags,
} from '../entities/traits.mjs';
import {parseMarkdown} from '../../../shared/marked/parse.mjs';
@@ -43,7 +44,7 @@ const jsDoclinkRegex = /\{\s*@link\s+([^}]+)\s*\}/;
const jsDoclinkRegexGlobal = new RegExp(jsDoclinkRegex.source, 'g');
/** Given an entity with a description, gets the entity augmented with an `htmlDescription`. */
-export function addHtmlDescription(
+export function addHtmlDescription(
entry: T,
): T & HasHtmlDescription {
const firstParagraphRule = /(.*?)(?:\n\n|$)/s;
@@ -56,10 +57,17 @@ export function addHtmlDescription(
?.comment ?? '';
}
- const description = !!entry.description ? entry.description : jsDocDescription;
- const shortTextMatch = description.match(firstParagraphRule);
+ let description = entry.description || jsDocDescription;
+ let shortDescription = description.match(firstParagraphRule)?.[0] ?? '';
+
+ // For the cases where the @description tag is after a short description
+ if (jsDocDescription && description !== jsDocDescription) {
+ shortDescription = entry.description;
+ description = jsDocDescription;
+ }
+
const htmlDescription = getHtmlForJsDocText(description).trim();
- const shortHtmlDescription = getHtmlForJsDocText(shortTextMatch ? shortTextMatch[0] : '').trim();
+ const shortHtmlDescription = getHtmlForJsDocText(shortDescription).trim();
return {...entry, htmlDescription, shortHtmlDescription};
}
@@ -137,6 +145,9 @@ function getHtmlAdditionalLinks(entry: T): LinkEntryRend
.filter((tag) => tag.name === JS_DOC_SEE_TAG)
.map((tag) => tag.comment)
.map((comment) => {
+ // TODO: Throw when the comment is an absolute link.
+ // With TS 5.9 this is not possible as the ts api that extracts comments from tags strips the "http" part of links.
+
const markdownLinkMatch = comment.match(markdownLinkRule);
if (markdownLinkMatch) {
diff --git a/packages/compiler-cli/src/ngtsc/docs/src/jsdoc_extractor.ts b/packages/compiler-cli/src/ngtsc/docs/src/jsdoc_extractor.ts
index 41fe4720539..96f39e1d1c7 100644
--- a/packages/compiler-cli/src/ngtsc/docs/src/jsdoc_extractor.ts
+++ b/packages/compiler-cli/src/ngtsc/docs/src/jsdoc_extractor.ts
@@ -24,6 +24,8 @@ export function extractJsDocTags(node: ts.HasJSDoc): JsDocTagEntry[] {
return ts.getJSDocTags(escapedNode).map((t) => {
return {
name: t.tagName.getText(),
+ // In TS 5.9, ts.getTextOfJSDocComment still strips "http" from comments breaking any absolute links in @see blocks.
+ // eg: @see https://angular.dev
comment: unescapeAngularDecorators(ts.getTextOfJSDocComment(t.comment) ?? ''),
};
});
diff --git a/packages/router/src/provide_router.ts b/packages/router/src/provide_router.ts
index 82e00d87bb6..4d265cf886b 100644
--- a/packages/router/src/provide_router.ts
+++ b/packages/router/src/provide_router.ts
@@ -8,10 +8,10 @@
import {
HashLocationStrategy,
+ Location,
LOCATION_INITIALIZED,
LocationStrategy,
ViewportScroller,
- Location,
ɵNavigationAdapterForLocation,
} from '@angular/common';
import {
@@ -23,15 +23,15 @@ import {
inject,
InjectionToken,
Injector,
+ ɵIS_ENABLED_BLOCKING_INITIAL_NAVIGATION as IS_ENABLED_BLOCKING_INITIAL_NAVIGATION,
makeEnvironmentProviders,
+ ɵperformanceMarkFeature as performanceMarkFeature,
provideAppInitializer,
+ provideEnvironmentInitializer,
Provider,
runInInjectionContext,
- ɵperformanceMarkFeature as performanceMarkFeature,
- ɵIS_ENABLED_BLOCKING_INITIAL_NAVIGATION as IS_ENABLED_BLOCKING_INITIAL_NAVIGATION,
- ɵpublishExternalGlobalUtil,
- provideEnvironmentInitializer,
Type,
+ ɵpublishExternalGlobalUtil,
} from '@angular/core';
import {of, Subject} from 'rxjs';
@@ -39,15 +39,18 @@ import {INPUT_BINDER, RoutedComponentInputBinder} from './directives/router_outl
import {Event, NavigationError, stringifyEvent} from './events';
import {RedirectCommand, Routes} from './models';
import {NAVIGATION_ERROR_HANDLER, NavigationTransitions} from './navigation_transition';
+import {ROUTE_INJECTOR_CLEANUP, routeInjectorCleanup} from './route_injector_cleanup';
import {Router} from './router';
import {InMemoryScrollingOptions, ROUTER_CONFIGURATION, RouterConfigOptions} from './router_config';
import {ROUTES} from './router_config_loader';
import {PreloadingStrategy, RouterPreloader} from './router_preloader';
-import {routeInjectorCleanup, ROUTE_INJECTOR_CLEANUP} from './route_injector_cleanup';
import {ROUTER_SCROLLER, RouterScroller} from './router_scroller';
+import {getLoadedRoutes, getRouterInstance, navigateByUrl} from './router_devtools';
import {ActivatedRoute} from './router_state';
+import {NavigationStateManager} from './statemanager/navigation_state_manager';
+import {StateManager} from './statemanager/state_manager';
import {afterNextNavigation} from './utils/navigations';
import {
CREATE_VIEW_TRANSITION,
@@ -55,9 +58,6 @@ import {
VIEW_TRANSITION_OPTIONS,
ViewTransitionsFeatureOptions,
} from './utils/view_transition';
-import {getLoadedRoutes, getRouterInstance, navigateByUrl} from './router_devtools';
-import {StateManager} from './statemanager/state_manager';
-import {NavigationStateManager} from './statemanager/navigation_state_manager';
/**
* Sets up providers necessary to enable `Router` functionality for the application.
@@ -282,9 +282,9 @@ export type ExperimentalPlatformNavigationFeature =
* });
* ```
*
- * @see https://github.com/WICG/navigation-api?tab=readme-ov-file#problem-statement
- * @see https://developer.chrome.com/docs/web-platform/navigation-api/
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Navigation_API
+ * @see [Navigation API on WICG](https://github.com/WICG/navigation-api?tab=readme-ov-file#problem-statement)
+ * @see [Navigation API on Chrome from developers](https://developer.chrome.com/docs/web-platform/navigation-api/)
+ * @see [Navigation API on MDN](https://developer.mozilla.org/en-US/docs/Web/API/Navigation_API)
*
* @experimental 21.1
* @returns A `RouterFeature` that enables the platform navigation.
@@ -899,8 +899,8 @@ export function withComponentInputBinding(): ComponentInputBindingFeature {
* ```
*
* @returns A set of providers for use with `provideRouter`.
- * @see https://developer.chrome.com/docs/web-platform/view-transitions/
- * @see https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API
+ * @see [View Transitions on MDN](https://developer.chrome.com/docs/web-platform/view-transitions/)
+ * @see [View Transitions API on MDN](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API)
* @see [Route transition animations](guide/routing/route-transition-animations)
* @developerPreview 19.0
*/