mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(docs-infra): make absolute angular.dev hrefs relative in CLI option descriptions
CLI option descriptions are sourced from `@angular/cli` schema JSON files, several of which contain absolute `https://angular.dev/...` URLs in their `description` text. Those URLs render with the external-link icon and push preview users out to production when viewed on `next.angular.dev` or other dev previews. The path bypasses the existing `link.mts` ban on absolute angular.dev links because option descriptions go through `marked.parse` directly, without `AdevDocsRenderer`. Rewrite the rendered hrefs whose values begin with `https://angular.dev/` (or the `http:` variant) to root-relative paths so the resulting anchors route through Angular's Router and resolve against the active deployment. Subdomains such as `next.angular.dev/...` are intentionally not rewritten because they refer to genuinely different deployments. Closes #68795
This commit is contained in:
@@ -43,4 +43,17 @@ describe('CLI docs to html', () => {
|
||||
expect(cliTocs[0].textContent).toContain('ng component [name] [options]');
|
||||
expect(cliTocs[1].textContent).toContain('ng c [name] [options]');
|
||||
});
|
||||
|
||||
it('should rewrite absolute angular.dev hrefs in option descriptions to root-relative', async () => {
|
||||
const renderableJson = await getRenderable(entryJson, '', 'angular/cli');
|
||||
const localFragment = JSDOM.fragment(renderEntry(renderableJson));
|
||||
const hrefs = Array.from(localFragment.querySelectorAll('a')).map((a) =>
|
||||
a.getAttribute('href'),
|
||||
);
|
||||
// Absolute angular.dev URLs are rewritten to root-relative.
|
||||
expect(hrefs).toContain('/cli-test-rewrite');
|
||||
expect(hrefs).not.toContain('https://angular.dev/cli-test-rewrite');
|
||||
// Subdomains are intentionally left as external.
|
||||
expect(hrefs).toContain('https://next.angular.dev/cli-test-preview');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
"name": "generate",
|
||||
"command": "ng generate <schematic>",
|
||||
"shortDescription": "Generates and/or modifies files based on a schematic.",
|
||||
"aliases": [
|
||||
"g"
|
||||
],
|
||||
"aliases": ["g"],
|
||||
"deprecated": false,
|
||||
"options": [
|
||||
{
|
||||
@@ -16,9 +14,7 @@
|
||||
{
|
||||
"name": "dry-run",
|
||||
"type": "boolean",
|
||||
"aliases": [
|
||||
"d"
|
||||
],
|
||||
"aliases": ["d"],
|
||||
"default": false,
|
||||
"description": "Run through and reports activity without writing out results."
|
||||
},
|
||||
@@ -44,6 +40,12 @@
|
||||
"type": "string",
|
||||
"description": "The [collection:schematic] to run.",
|
||||
"positional": 0
|
||||
},
|
||||
{
|
||||
"name": "test-angular-dev-href-rewrite",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "See [angular.dev test](https://angular.dev/cli-test-rewrite) and [preview test](https://next.angular.dev/cli-test-preview)."
|
||||
}
|
||||
],
|
||||
"subcommands": [
|
||||
@@ -75,17 +77,13 @@
|
||||
{
|
||||
"name": "inline-style",
|
||||
"type": "boolean",
|
||||
"aliases": [
|
||||
"s"
|
||||
],
|
||||
"aliases": ["s"],
|
||||
"description": "Include styles inline in the root component.ts file. Only CSS styles can be included inline. Default is false, meaning that an external styles file is created and referenced in the root component.ts file."
|
||||
},
|
||||
{
|
||||
"name": "inline-template",
|
||||
"type": "boolean",
|
||||
"aliases": [
|
||||
"t"
|
||||
],
|
||||
"aliases": ["t"],
|
||||
"description": "Include template inline in the root component.ts file. Default is false, meaning that an external template file is created and referenced in the root component.ts file. "
|
||||
},
|
||||
{
|
||||
@@ -103,9 +101,7 @@
|
||||
{
|
||||
"name": "prefix",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"p"
|
||||
],
|
||||
"aliases": ["p"],
|
||||
"default": "app",
|
||||
"description": "A prefix to apply to generated selectors."
|
||||
},
|
||||
@@ -135,9 +131,7 @@
|
||||
{
|
||||
"name": "skip-tests",
|
||||
"type": "boolean",
|
||||
"aliases": [
|
||||
"S"
|
||||
],
|
||||
"aliases": ["S"],
|
||||
"default": false,
|
||||
"description": "Do not create \"spec.ts\" test files for the application."
|
||||
},
|
||||
@@ -163,29 +157,17 @@
|
||||
"name": "style",
|
||||
"type": "string",
|
||||
"default": "css",
|
||||
"enum": [
|
||||
"css",
|
||||
"scss",
|
||||
"sass",
|
||||
"less"
|
||||
],
|
||||
"enum": ["css", "scss", "sass", "less"],
|
||||
"description": "The file extension or preprocessor to use for style files."
|
||||
},
|
||||
{
|
||||
"name": "view-encapsulation",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Emulated",
|
||||
"None",
|
||||
"ShadowDom",
|
||||
"ExperimentalIsolatedShadowDom"
|
||||
],
|
||||
"enum": ["Emulated", "None", "ShadowDom", "ExperimentalIsolatedShadowDom"],
|
||||
"description": "The view encapsulation strategy to use in the new application."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"app"
|
||||
],
|
||||
"aliases": ["app"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -216,9 +198,7 @@
|
||||
"description": "Adds a developer-defined type to the filename, in the format \"name.type.ts\"."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"cl"
|
||||
],
|
||||
"aliases": ["cl"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -229,22 +209,15 @@
|
||||
{
|
||||
"name": "change-detection",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"c"
|
||||
],
|
||||
"aliases": ["c"],
|
||||
"default": "Default",
|
||||
"enum": [
|
||||
"Default",
|
||||
"OnPush"
|
||||
],
|
||||
"enum": ["Default", "OnPush"],
|
||||
"description": "The change detection strategy to use in the new component."
|
||||
},
|
||||
{
|
||||
"name": "display-block",
|
||||
"type": "boolean",
|
||||
"aliases": [
|
||||
"b"
|
||||
],
|
||||
"aliases": ["b"],
|
||||
"default": false,
|
||||
"description": "Specifies if the style will contain `:host { display: block; }`."
|
||||
},
|
||||
@@ -269,27 +242,21 @@
|
||||
{
|
||||
"name": "inline-style",
|
||||
"type": "boolean",
|
||||
"aliases": [
|
||||
"s"
|
||||
],
|
||||
"aliases": ["s"],
|
||||
"default": false,
|
||||
"description": "Include styles inline in the component.ts file. Only CSS styles can be included inline. By default, an external styles file is created and referenced in the component.ts file."
|
||||
},
|
||||
{
|
||||
"name": "inline-template",
|
||||
"type": "boolean",
|
||||
"aliases": [
|
||||
"t"
|
||||
],
|
||||
"aliases": ["t"],
|
||||
"default": false,
|
||||
"description": "Include template inline in the component.ts file. By default, an external template file is created and referenced in the component.ts file."
|
||||
},
|
||||
{
|
||||
"name": "module",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"m"
|
||||
],
|
||||
"aliases": ["m"],
|
||||
"description": "The declaring NgModule."
|
||||
},
|
||||
{
|
||||
@@ -301,9 +268,7 @@
|
||||
{
|
||||
"name": "prefix",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"p"
|
||||
],
|
||||
"aliases": ["p"],
|
||||
"description": "The prefix to apply to the generated component selector."
|
||||
},
|
||||
{
|
||||
@@ -344,13 +309,7 @@
|
||||
"name": "style",
|
||||
"type": "string",
|
||||
"default": "css",
|
||||
"enum": [
|
||||
"css",
|
||||
"scss",
|
||||
"sass",
|
||||
"less",
|
||||
"none"
|
||||
],
|
||||
"enum": ["css", "scss", "sass", "less", "none"],
|
||||
"description": "The file extension or preprocessor to use for style files, or 'none' to skip generating the style file."
|
||||
},
|
||||
{
|
||||
@@ -362,21 +321,12 @@
|
||||
{
|
||||
"name": "view-encapsulation",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"v"
|
||||
],
|
||||
"enum": [
|
||||
"Emulated",
|
||||
"None",
|
||||
"ShadowDom",
|
||||
"ExperimentalIsolatedShadowDom"
|
||||
],
|
||||
"aliases": ["v"],
|
||||
"enum": ["Emulated", "None", "ShadowDom", "ExperimentalIsolatedShadowDom"],
|
||||
"description": "The view encapsulation strategy to use in the new component."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"c"
|
||||
],
|
||||
"aliases": ["c"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -392,10 +342,7 @@
|
||||
{
|
||||
"name": "type",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"karma",
|
||||
"browserslist"
|
||||
],
|
||||
"enum": ["karma", "browserslist"],
|
||||
"description": "Specifies which type of configuration file to create.",
|
||||
"positional": 0
|
||||
}
|
||||
@@ -423,9 +370,7 @@
|
||||
{
|
||||
"name": "module",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"m"
|
||||
],
|
||||
"aliases": ["m"],
|
||||
"description": "The declaring NgModule."
|
||||
},
|
||||
{
|
||||
@@ -437,9 +382,7 @@
|
||||
{
|
||||
"name": "prefix",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"p"
|
||||
],
|
||||
"aliases": ["p"],
|
||||
"description": "A prefix to apply to generated selectors."
|
||||
},
|
||||
{
|
||||
@@ -471,9 +414,7 @@
|
||||
"description": "Whether the generated directive is standalone."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"d"
|
||||
],
|
||||
"aliases": ["d"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -498,9 +439,7 @@
|
||||
"description": "Adds a developer-defined type to the filename, in the format \"name.type.ts\"."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"e"
|
||||
],
|
||||
"aliases": ["e"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -537,9 +476,7 @@
|
||||
{
|
||||
"name": "implements",
|
||||
"type": "array",
|
||||
"aliases": [
|
||||
"guardType"
|
||||
],
|
||||
"aliases": ["guardType"],
|
||||
"description": "Specifies which type of guard to create."
|
||||
},
|
||||
{
|
||||
@@ -560,9 +497,7 @@
|
||||
"description": "Do not create \"spec.ts\" test files for the new guard."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"g"
|
||||
],
|
||||
"aliases": ["g"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -631,9 +566,7 @@
|
||||
"positional": 1
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"i"
|
||||
],
|
||||
"aliases": ["i"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -656,9 +589,7 @@
|
||||
{
|
||||
"name": "prefix",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"p"
|
||||
],
|
||||
"aliases": ["p"],
|
||||
"default": "lib",
|
||||
"description": "A prefix to apply to generated selectors."
|
||||
},
|
||||
@@ -692,9 +623,7 @@
|
||||
"description": "Creates a library based upon the standalone API, without NgModules."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"lib"
|
||||
],
|
||||
"aliases": ["lib"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -711,9 +640,7 @@
|
||||
{
|
||||
"name": "module",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"m"
|
||||
],
|
||||
"aliases": ["m"],
|
||||
"description": "The declaring NgModule."
|
||||
},
|
||||
{
|
||||
@@ -742,16 +669,11 @@
|
||||
"name": "routing-scope",
|
||||
"type": "string",
|
||||
"default": "Child",
|
||||
"enum": [
|
||||
"Child",
|
||||
"Root"
|
||||
],
|
||||
"enum": ["Child", "Root"],
|
||||
"description": "The scope for the new routing module."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"m"
|
||||
],
|
||||
"aliases": ["m"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -774,9 +696,7 @@
|
||||
{
|
||||
"name": "module",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"m"
|
||||
],
|
||||
"aliases": ["m"],
|
||||
"description": "The declaring NgModule."
|
||||
},
|
||||
{
|
||||
@@ -809,9 +729,7 @@
|
||||
"description": "Whether the generated pipe is standalone."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"p"
|
||||
],
|
||||
"aliases": ["p"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -849,9 +767,7 @@
|
||||
"description": "Do not create \"spec.ts\" test files for the new resolver."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"r"
|
||||
],
|
||||
"aliases": ["r"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -883,9 +799,7 @@
|
||||
"description": "Do not create \"spec.ts\" test files for the new service."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"s"
|
||||
],
|
||||
"aliases": ["s"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
|
||||
@@ -53,11 +53,14 @@ export function getCliCardsRenderable(command: CliCommand): CliCardRenderable[]
|
||||
return cards;
|
||||
}
|
||||
|
||||
// Rewrite absolute angular.dev hrefs to root-relative so links stay in-site.
|
||||
const angularDevHrefRegex = /(href=["'])https?:\/\/angular\.dev\//g;
|
||||
|
||||
function getRenderableOptions(items: CliOption[]): CliOptionRenderable[] {
|
||||
return items.map((option) => ({
|
||||
...option,
|
||||
deprecated: option.deprecated ? {version: undefined} : undefined,
|
||||
description: marked.parse(option.description) as string,
|
||||
description: (marked.parse(option.description) as string).replace(angularDevHrefRegex, '$1/'),
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user