Skip to content

Commit 59c1528

Browse files
JeanMecheAndrewKushnir
authored andcommitted
docs: add check for non-existing anchor (angular#64309)
This is only for the anchors on the same document for now. Commit also includes some reformating. fixes angular#64303 PR Close angular#64309
1 parent a397ca3 commit 59c1528

13 files changed

Lines changed: 659 additions & 686 deletions

File tree

adev/shared-docs/pipeline/guides/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ ts_project(
6060
"//adev/shared-docs:__subpackages__",
6161
],
6262
deps = [
63+
"//adev:node_modules/jsdom",
6364
"//adev/shared-docs/pipeline/shared:shiki",
6465
"//adev/shared-docs/pipeline/shared/marked",
6566
],

adev/shared-docs/pipeline/guides/helpers.mts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9+
import {JSDOM} from 'jsdom';
10+
911
/** Whether the link provided is external to the application. */
1012
export function isExternalLink(href: string | undefined | null) {
1113
return href?.startsWith('http') ?? false;
@@ -15,3 +17,24 @@ export function isExternalLink(href: string | undefined | null) {
1517
export function anchorTarget(href: string | undefined | null) {
1618
return isExternalLink(href) ? ` target="_blank"` : '';
1719
}
20+
21+
/**
22+
*
23+
* @param htmlString
24+
* @returns the first unknown anchor found or undefined if all anchors are valid
25+
*/
26+
export function hasUnknownAnchors(htmlString: string) {
27+
const fragment = JSDOM.fragment(htmlString);
28+
const anchors = fragment.querySelectorAll('a');
29+
return Array.from(anchors).find((anchor) => {
30+
const href = anchor.getAttribute('href');
31+
if (href?.startsWith('#')) {
32+
const id = href.slice(1);
33+
const target = fragment.getElementById(id);
34+
if (!target) {
35+
return href;
36+
}
37+
}
38+
return undefined;
39+
});
40+
}

adev/shared-docs/pipeline/guides/index.mts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {readFileSync, writeFileSync} from 'fs';
1010
import path from 'path';
1111
import {initHighlighter} from '../shared/shiki.mjs';
1212
import {parseMarkdownAsync} from '../shared/marked/parse.mjs';
13+
import {hasUnknownAnchors} from './helpers.mjs';
1314

1415
type ApiManifest = ApiManifestPackage[];
1516
interface ApiManifestPackage {
@@ -52,6 +53,13 @@ async function main() {
5253
const htmlFileName = filePath + '.html';
5354
const htmlOutputPath = path.join(outputFilenameExecRootRelativePath, htmlFileName);
5455

56+
const unknownAnchor = hasUnknownAnchors(htmlOutputContent);
57+
if (unknownAnchor) {
58+
throw new Error(
59+
`The file "${filePath}" contains an anchor link to "${unknownAnchor}" which does not exist in the document.`,
60+
);
61+
}
62+
5563
writeFileSync(htmlOutputPath, htmlOutputContent, {encoding: 'utf8'});
5664
}
5765
}

adev/src/content/ecosystem/service-workers/config.md

Lines changed: 53 additions & 62 deletions
Large diffs are not rendered by default.

adev/src/content/guide/routing/router-reference.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ The in-application URLs can be indistinguishable from server URLs.
5656
Modern HTML5 browsers were the first to support `pushState` which is why many people refer to these URLs as "HTML5 style" URLs.
5757

5858
HELPFUL: HTML5 style navigation is the router default.
59-
In the [LocationStrategy and browser URL styles](#locationstrategy-and-browser-url-styles) section, learn why HTML5 style is preferable, how to adjust its behavior, and how to switch to the older hash \(`#`\) style, if necessary.
59+
In the [LocationStrategy and browser URL styles](common-router-tasks#locationstrategy-and-browser-url-styles) section, learn why HTML5 style is preferable, how to adjust its behavior, and how to switch to the older hash \(`#`\) style, if necessary.
6060

6161
You must add a [`<base href>` element](https://developer.mozilla.org/docs/Web/HTML/Element/base 'base href') to the application's `index.html` for `pushState` routing to work.
6262
The browser uses the `<base href>` value to prefix relative URLs when referencing CSS files, scripts, and images.
@@ -94,7 +94,6 @@ Those developers can still use HTML5 URLs by taking the following two steps:
9494

9595
1. Provide the router with an appropriate `APP_BASE_HREF` value.
9696
1. Use root URLs \(URLs with an `authority`\) for all web resources: CSS, images, scripts, and template HTML files.
97-
9897
- The `<base href>` `path` should end with a "/", as browsers ignore characters in the `path` that follow the right-most "`/`"
9998
- If the `<base href>` includes a `query` part, the `query` is only used if the `path` of a link in the page is empty and has no `query`.
10099
This means that a `query` in the `<base href>` is only included when using `HashLocationStrategy`.

adev/src/content/guide/testing/components-scenarios.md

Lines changed: 66 additions & 68 deletions
Large diffs are not rendered by default.

adev/src/content/guide/testing/utility-apis.md

Lines changed: 64 additions & 63 deletions
Large diffs are not rendered by default.

adev/src/content/kitchen-sink.md

Lines changed: 70 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ This is a visual list of all custom components and styles for Angular.dev.
44

55
As a design system, this page contains visual and Markdown authoring guidance for:
66

7-
* Custom Angular docs elements: [`docs-card`](#cards), [`docs-callout`](#callouts), [`docs-pill`](#pills), and [`docs-steps`](#workflow)
8-
* Custom text elements: [alerts](#alerts)
9-
* Code examples: [`docs-code`](#code)
10-
* Built-in Markdown styled elements: links, lists, [headers](#headers), [horizontal lines](#horizontal-line-divider), [tables](#tables)
11-
* and more!
7+
- Custom Angular docs elements: [`docs-card`](#cards), [`docs-callout`](#callouts), [`docs-pill`](#pills), and [`docs-steps`](#workflow)
8+
- Custom text elements: [alerts](#alerts)
9+
- Code examples: [`docs-code`](#code)
10+
- Built-in Markdown styled elements: links, lists, [headers](#headers-h2), [horizontal lines](#horizontal-line-divider)
11+
- and more!
1212

1313
Get ready to:
1414

@@ -42,13 +42,13 @@ Get ready to:
4242

4343
### `<docs-card>` Attributes
4444

45-
| Attributes | Details |
46-
|:--- |:--- |
47-
| `<docs-card-container>` | All cards must be nested inside a container |
48-
| `title` | Card title |
49-
| card body contents | Anything between `<docs-card>` and `</docs-card>` |
50-
| `link` | (Optional) Call to Action link text |
51-
| `href` | (Optional) Call to Action link href |
45+
| Attributes | Details |
46+
| :---------------------- | :------------------------------------------------ |
47+
| `<docs-card-container>` | All cards must be nested inside a container |
48+
| `title` | Card title |
49+
| card body contents | Anything between `<docs-card>` and `</docs-card>` |
50+
| `link` | (Optional) Call to Action link text |
51+
| `href` | (Optional) Call to Action link href |
5252

5353
## Callouts
5454

@@ -67,7 +67,7 @@ Get ready to:
6767
### `<docs-callout>` Attributes
6868

6969
| Attributes | Details |
70-
|:--- |:--- |
70+
| :----------------------------------------------- | :-------------------------------------------------------- |
7171
| `title` | Callout title |
7272
| card body contents | Anything between `<docs-callout>` and `</docs-callout>` |
7373
| `helpful` (default) \| `critical` \| `important` | (Optional) Adds styling and icons based on severity level |
@@ -76,7 +76,7 @@ Get ready to:
7676

7777
Pill rows are helpful as a sort of navigation with links to helpful resources.
7878

79-
<docs-pill-row>
79+
<docs-pill-row id=pill-row>
8080
<docs-pill href="#pill-row" title="Link"/>
8181
<docs-pill href="#pill-row" title="Link"/>
8282
<docs-pill href="#pill-row" title="Link"/>
@@ -87,11 +87,11 @@ Pill rows are helpful as a sort of navigation with links to helpful resources.
8787

8888
### `<docs-pill>` Attributes
8989

90-
| Attributes | Details |
91-
|:--- |:--- |
92-
| `<docs-pill-row` | All pills must be nested inside a pill row |
93-
| `title` | Pill text |
94-
| `href` | Pill href |
90+
| Attributes | Details |
91+
| :--------------- | :----------------------------------------- |
92+
| `<docs-pill-row` | All pills must be nested inside a pill row |
93+
| `title` | Pill text |
94+
| `href` | Pill href |
9595

9696
Pills may also be used inline by themselves, but we haven't built that out yet.
9797

@@ -135,8 +135,8 @@ Or using the `<docs-code>` element.
135135
import { Component } from '@angular/core';
136136

137137
@Component({
138-
selector: 'example-code',
139-
template: '<h1>Hello World!</h1>',
138+
selector: 'example-code',
139+
template: '<h1>Hello World!</h1>',
140140
})
141141
export class ComponentOverviewComponent {}
142142
</docs-code>
@@ -163,19 +163,19 @@ We also have styling for the terminal, just set the language as `shell`:
163163

164164
#### `<docs-code>` Attributes
165165

166-
| Attributes | Type | Details |
167-
|:--- |:--- |:--- |
168-
| code | `string` | Anything between tags is treated as code |
169-
| `path` | `string` | Path to code example (root: `content/examples/`) |
170-
| `header` | `string` | Title of the example (default: `file-name`) |
171-
| `language` | `string` | code language |
172-
| `linenums` | `boolean` | (False) displays line numbers |
173-
| `highlight` | `string of number[]` | lines highlighted |
174-
| `diff` | `string` | path to changed code |
175-
| `visibleLines` | `string of number[]` | range of lines for collapse mode |
176-
| `visibleRegion` | `string` | **DEPRECATED** FOR `visibleLines` |
177-
| `preview` | `boolean` | (False) display preview |
178-
| `hideCode` | `boolean` | (False) Whether to collapse code example by default. |
166+
| Attributes | Type | Details |
167+
| :-------------- | :------------------- | :--------------------------------------------------- |
168+
| code | `string` | Anything between tags is treated as code |
169+
| `path` | `string` | Path to code example (root: `content/examples/`) |
170+
| `header` | `string` | Title of the example (default: `file-name`) |
171+
| `language` | `string` | code language |
172+
| `linenums` | `boolean` | (False) displays line numbers |
173+
| `highlight` | `string of number[]` | lines highlighted |
174+
| `diff` | `string` | path to changed code |
175+
| `visibleLines` | `string of number[]` | range of lines for collapse mode |
176+
| `visibleRegion` | `string` | **DEPRECATED** FOR `visibleLines` |
177+
| `preview` | `boolean` | (False) display preview |
178+
| `hideCode` | `boolean` | (False) Whether to collapse code example by default. |
179179

180180
### Multifile examples
181181

@@ -184,43 +184,43 @@ You can create multifile examples by wrapping the examples inside a `<docs-code-
184184
<docs-code-multifile
185185
path="adev/src/content/examples/hello-world/src/app/app.component.ts"
186186
preview>
187-
<docs-code
187+
<docs-code
188188
path="adev/src/content/examples/hello-world/src/app/app.component.ts"
189189
diff="adev/src/content/examples/hello-world/src/app/app.component-old.ts"
190190
linenums
191191
visibleLines="[3, 11]"/>
192-
<docs-code
192+
<docs-code
193193
path="adev/src/content/examples/hello-world/src/app/app.component.html"
194194
highlight="[1]"
195195
linenums/>
196-
<docs-code
196+
<docs-code
197197
path="adev/src/content/examples/hello-world/src/app/app.component.css" />
198198
</docs-code-multifile>
199199

200200
#### `<docs-code-multifile>` Attributes
201201

202-
| Attributes | Type | Details |
203-
|:--- |:--- |:--- |
204-
| body contents | `string` | nested tabs of `docs-code` examples |
205-
| `path` | `string` | Path to code example for preview and external link |
206-
| `preview` | `boolean` | (False) display preview |
207-
| `hideCode` | `boolean` | (False) Whether to collapse code example by default. |
202+
| Attributes | Type | Details |
203+
| :------------ | :-------- | :--------------------------------------------------- |
204+
| body contents | `string` | nested tabs of `docs-code` examples |
205+
| `path` | `string` | Path to code example for preview and external link |
206+
| `preview` | `boolean` | (False) display preview |
207+
| `hideCode` | `boolean` | (False) Whether to collapse code example by default. |
208208

209209
### Adding `preview` to your code example
210210

211211
Adding the `preview` flag builds a running example of the code below the code snippet. This also automatically adds a button to open the running example in Stackblitz.
212212

213213
NOTE: `preview` only works with standalone.
214214

215-
### Styling example previews with Tailwind CSS
215+
### Styling example previews with Tailwind CSS
216216

217217
Tailwind utility classes can be used within code examples.
218218

219219
<docs-code-multifile
220220
path="adev/src/content/examples/hello-world/src/app/tailwind-app.component.ts"
221221
preview>
222-
<docs-code path="adev/src/content/examples/hello-world/src/app/tailwind-app.component.html" />
223-
<docs-code path="adev/src/content/examples/hello-world/src/app/tailwind-app.component.ts" />
222+
<docs-code path="adev/src/content/examples/hello-world/src/app/tailwind-app.component.html" />
223+
<docs-code path="adev/src/content/examples/hello-world/src/app/tailwind-app.component.ts" />
224224
</docs-code-multifile>
225225

226226
## Workflow
@@ -229,11 +229,11 @@ Style numbered steps using `<docs-step>`. Numbering is created using CSS (handy!
229229

230230
### `<docs-workflow>` and `<docs-step>` Attributes
231231

232-
| Attributes | Details |
233-
|:--- |:--- |
234-
| `<docs-workflow>` | All steps must be nested inside a workflow |
235-
| `title` | Step title |
236-
| step body contents | Anything between `<docs-step>` and `</docs-step>` |
232+
| Attributes | Details |
233+
| :----------------- | :------------------------------------------------ |
234+
| `<docs-workflow>` | All steps must be nested inside a workflow |
235+
| `title` | Step title |
236+
| step body contents | Anything between `<docs-step>` and `</docs-step>` |
237237

238238
Steps must start on a new line, and can contain `docs-code`s and other nested elements and styles.
239239

@@ -242,7 +242,7 @@ Steps must start on a new line, and can contain `docs-code`s and other nested el
242242
<docs-step title="Install the Angular CLI">
243243
You use the Angular CLI to create projects, generate application and library code, and perform a variety of ongoing development tasks such as testing, bundling, and deployment.
244244

245-
To install the Angular CLI, open a terminal window and run the following command:
245+
To install the Angular CLI, open a terminal window and run the following command:
246246

247247
<docs-code language="shell">
248248
npm install -g @angular/cli
@@ -252,34 +252,34 @@ Steps must start on a new line, and can contain `docs-code`s and other nested el
252252
<docs-step title="Create a workspace and initial application">
253253
You develop apps in the context of an Angular workspace.
254254

255-
To create a new workspace and initial starter app:
255+
To create a new workspace and initial starter app:
256256

257-
* Run the CLI command `ng new` and provide the name `my-app`, as shown here:
258-
<docs-code language="shell">
259-
ng new my-app
260-
</docs-code>
257+
- Run the CLI command `ng new` and provide the name `my-app`, as shown here:
258+
<docs-code language="shell">
259+
ng new my-app
260+
</docs-code>
261261

262-
* The ng new command prompts you for information about features to include in the initial app. Accept the defaults by pressing the Enter or Return key.
262+
- The ng new command prompts you for information about features to include in the initial app. Accept the defaults by pressing the Enter or Return key.
263263

264264
The Angular CLI installs the necessary Angular npm packages and other dependencies. This can take a few minutes.
265265

266266
The CLI creates a new workspace and a simple Welcome app, ready to run.
267-
</docs-step>
267+
</docs-step>
268268

269269
<docs-step title="Run the application">
270270
The Angular CLI includes a server, for you to build and serve your app locally.
271271

272-
1. Navigate to the workspace folder, such as `my-app`.
273-
2. Run the following command:
274-
<docs-code language="shell">
275-
cd my-app
276-
ng serve --open
277-
</docs-code>
272+
1. Navigate to the workspace folder, such as `my-app`.
273+
2. Run the following command:
274+
<docs-code language="shell">
275+
cd my-app
276+
ng serve --open
277+
</docs-code>
278278

279-
The `ng serve` command launches the server, watches your files, and rebuilds the app as you make changes to those files.
279+
The `ng serve` command launches the server, watches your files, and rebuilds the app as you make changes to those files.
280280

281-
The `--open` (or just `-o`) option automatically opens your browser to <http://localhost:4200/>.
282-
If your installation and setup was successful, you should see a page similar to the following.
281+
The `--open` (or just `-o`) option automatically opens your browser to <http://localhost:4200/>.
282+
If your installation and setup was successful, you should see a page similar to the following.
283283
</docs-step>
284284

285285
<docs-step title="Final step">
@@ -299,7 +299,7 @@ Steps must start on a new line, and can contain `docs-code`s and other nested el
299299

300300
You can add images using the semantic Markdown image:
301301

302-
![Rhubarb the cat](assets/images/kitchen-sink/rhubarb.jpg "Optional title")
302+
![Rhubarb the cat](assets/images/kitchen-sink/rhubarb.jpg 'Optional title')
303303

304304
### Add `#small` and `#medium` to change the image size
305305

@@ -339,7 +339,7 @@ Write diagrams and charts using [Mermaid](http://mermaid.js.org/) by setting the
339339

340340
## Horizontal Line Divider
341341

342-
This can be used to separate page sections, like we're about to do below. These styles will be added by default, nothing custom needed.
342+
This can be used to separate page sections, like we're about to do below. These styles will be added by default, nothing custom needed.
343343

344344
<hr/>
345345

0 commit comments

Comments
 (0)