Skip to content

Commit b5205c7

Browse files
JeanMecheAndrewKushnir
authored andcommitted
docs(docs-infra): throw when rendering absolute links to adev in our guides
This is to prevent any further regressions in the future
1 parent 8243bb3 commit b5205c7

15 files changed

Lines changed: 48 additions & 17 deletions

File tree

adev/shared-docs/pipeline/shared/marked/renderer.mts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ export class AdevDocsRenderer extends Renderer {
4242

4343
defaultRenderer = new Renderer();
4444

45+
isGuideFile(): boolean {
46+
return this.context.markdownFilePath?.includes('/content/guide') ?? false;
47+
}
48+
4549
override link = linkRender;
4650
override table = tableRender;
4751
override list = listRender;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[Angular Site](https://angular.dev)
1+
[Please click](https://www.youtube.com/watch?v=dQw4w9WgXcQ)
22
[same page](#test)
33
[same site](../other/page)
44
[npm packages](https://docs.npmjs.com/getting-started/what-is-npm 'What is npm?')

adev/shared-docs/pipeline/shared/marked/test/link/link.spec.mts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe('markdown to html', () => {
2020

2121
it('should render external links with _blank target', () => {
2222
expect(parsedMarkdown).toContain(
23-
'<a href="https://angular.dev" target="_blank">Angular Site</a>',
23+
'<a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ" target="_blank">Please click</a>',
2424
);
2525
});
2626

@@ -37,4 +37,17 @@ describe('markdown to html', () => {
3737
'<a href="https://docs.npmjs.com/getting-started/what-is-npm" title="What is npm?" target="_blank">npm packages</a>',
3838
);
3939
});
40+
41+
it('should throw if on absolute links to adev', async () => {
42+
try {
43+
parsedMarkdown = await parseMarkdown(
44+
'[Some absolute link](https://angular.dev/yeah-nope-should-be-relative)',
45+
{...rendererContext, markdownFilePath: '/content/guide/some-guide.md'},
46+
);
47+
} catch (e: any) {
48+
expect(e.message).toContain('Absolute links to angular.dev are not allowed');
49+
return;
50+
}
51+
fail('Did not throw for absolute link to angular.dev');
52+
});
4053
});

adev/shared-docs/pipeline/shared/marked/test/list/list.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010
- here
1111
- matter
1212
- doesn't
13-
- [some link](https://angular.dev)
13+
- [some link](https://www.youtube.com/watch?v=dQw4w9WgXcQ)
1414
- Code block `SomeClass`

adev/shared-docs/pipeline/shared/marked/test/list/list.spec.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ describe('markdown to html', () => {
3535
it('should render list items', () => {
3636
const unorderedList = markdownDocument.querySelector('ul');
3737
const linkItem = unorderedList!.children[4];
38-
expect(linkItem.outerHTML).toContain('href="https://angular.dev"');
38+
expect(linkItem.outerHTML).toContain('href="https://www.youtube.com/watch?v=dQw4w9WgXcQ"');
3939

4040
const codeItem = unorderedList!.children[5];
4141
expect(codeItem.outerHTML).toContain('<code>SomeClass</code>');

adev/shared-docs/pipeline/shared/marked/transformations/link.mts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import {anchorTarget} from '../helpers.mjs';
1010
import {Renderer, Tokens} from 'marked';
11+
import {AdevDocsRenderer} from '../renderer.mjs';
1112

1213
/**
1314
* Tracks whether the current renderer is inside a link.
@@ -19,7 +20,20 @@ export function setInsideLink(value: boolean) {
1920
insideLink = value;
2021
}
2122

22-
export function linkRender(this: Renderer, {href, title, tokens}: Tokens.Link) {
23+
export function linkRender(this: AdevDocsRenderer, {href, title, tokens}: Tokens.Link) {
24+
// We have render-time check that we don't create absolute links (which are rendered as external links)
25+
// in our guides
26+
if (
27+
(href.startsWith('https://angular.dev/') || href.startsWith('http://angular.dev/')) &&
28+
this.isGuideFile()
29+
) {
30+
Error.stackTraceLimit = Infinity;
31+
throw new Error(
32+
`Absolute links to angular.dev are not allowed: "${href}". Please use relative links instead.` +
33+
`\n ----------------------------- \n ${(this as any).__raw}`,
34+
);
35+
}
36+
2337
if (insideLink) {
2438
return this.parser.parseInline(tokens);
2539
}

adev/src/content/ai/mcp-server-setup.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Some tools are provided in experimental / preview status since they are new or n
2222
| Name | Description | `local-only` | `read-only` |
2323
| :------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------: | :---------: |
2424
| `build` | Perform a one-off, non-watched build using `ng build`. |||
25-
| `modernize` | Performs code migrations and provides further instructions on how to modernize Angular code to align with the latest best practices and syntax. [Learn more](https://angular.dev/reference/migrations) |||
25+
| `modernize` | Performs code migrations and provides further instructions on how to modernize Angular code to align with the latest best practices and syntax. [Learn more](/reference/migrations) |||
2626
| `start_devserver` | Asynchronously starts a development server that watches the workspace for changes, similar to running `ng serve`. Since this is asynchronous it returns immediately. To manage the resulting server, use the `stop_devserver` and `wait_for_devserver_build` tools. |||
2727
| `stop_devserver` | Stops a development server started by `start_devserver`. |||
2828
| `wait_for_devserver_build` | Returns the output logs of the most recent build in a running development server started by `start_devserver`. If a build is currently ongoing, it will first wait for that build to complete and then return the logs. |||

adev/src/content/guide/ngmodules/overview.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ IMPORTANT: The Angular team recommends using [bootstrapApplication](api/platform
173173

174174
The `@NgModule` decorator accepts an optional `bootstrap` array that may contain one or more components.
175175

176-
You can use the [`bootstrapModule`](https://angular.dev/api/core/PlatformRef#bootstrapModule) method from either [`platformBrowser`](api/platform-browser/platformBrowser) or [`platformServer`](api/platform-server/platformServer) to start an Angular application. When run, this function locates any elements on the page with a CSS selector that matches the listed componet(s) and renders those components on the page.
176+
You can use the [`bootstrapModule`](/api/core/PlatformRef#bootstrapModule) method from either [`platformBrowser`](api/platform-browser/platformBrowser) or [`platformServer`](api/platform-server/platformServer) to start an Angular application. When run, this function locates any elements on the page with a CSS selector that matches the listed componet(s) and renders those components on the page.
177177

178178
```typescript
179179
import {platformBrowser} from '@angular/platform-browser';

adev/src/content/guide/testing/using-component-harnesses.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ it('should get value of slider thumb', async () => {
177177

178178
## Interop with Angular change detection
179179

180-
By default, test harnesses runs Angular's [change detection](https://angular.dev/best-practices/runtime-performance) before reading the state of a DOM element and after interacting with a DOM element.
180+
By default, test harnesses runs Angular's [change detection](/best-practices/runtime-performance) before reading the state of a DOM element and after interacting with a DOM element.
181181

182182
There may be times that you need finer-grained control over change detection in your tests. such as checking the state of a component while an async operation is pending. In these cases use the `manualChangeDetection` function to disable automatic handling of change detection for a block of code.
183183

adev/src/content/reference/cli.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@
1717
| [`run`](cli/run) | | Runs an Architect target with an optional custom builder configuration defined in your project. |
1818
| [`serve`](cli/serve) | `s`, `dev` | Builds and serves your application, rebuilding on file changes. |
1919
| [`test`](cli/test) | `t` | Runs unit tests in a project. |
20-
| [`update`](cli/update) | | Updates your workspace and its dependencies. See https://angular.dev/update-guide/. |
20+
| [`update`](cli/update) | | Updates your workspace and its dependencies. See the [Update Guide](/update-guide). |
2121
| [`version`](cli/version) | `v` | Outputs Angular CLI version. |

0 commit comments

Comments
 (0)