fix(docs-infra): correctly generate CLI commands docs when the overview page moves (#38365)
Previously, the [processCliCommands][1] dgeni processor, which is used
to generate the docs pages for the CLI commands, expected the CLI
commands overview page (with a URL of `cli`) to exist as a child of a
top-level navigation section (`CLI Commands`). If one tried to move the
`CLI Commands` section inside another section, `processCliCommnads`
would fail to find it and thus fail to generate the CLI commands docs.
This problem came up in #38353.
This commit updates the `processCliCommands` processor to be able to
find it regardless of the position of the `CLI Commands` section inside
the navigation doc.
[1]:
dca4443a8e/aio/tools/transforms/cli-docs-package/processors/processCliCommands.js (L7-L9)
PR Close #38365
This commit is contained in:
parent
dca4443a8e
commit
0551fbdf88
|
@ -4,11 +4,9 @@ module.exports = function processCliCommands(createDocMessage) {
|
||||||
$runBefore: ['rendering-docs'],
|
$runBefore: ['rendering-docs'],
|
||||||
$process(docs) {
|
$process(docs) {
|
||||||
const navigationDoc = docs.find(doc => doc.docType === 'navigation-json');
|
const navigationDoc = docs.find(doc => doc.docType === 'navigation-json');
|
||||||
const navigationNode = navigationDoc &&
|
const cliCommandsNode = navigationDoc && findCliCommandsNode(navigationDoc.data['SideNav']);
|
||||||
navigationDoc.data['SideNav'].find(
|
|
||||||
node => node.children && node.children.length && node.children[0].url === 'cli');
|
|
||||||
|
|
||||||
if (!navigationNode) {
|
if (!cliCommandsNode) {
|
||||||
throw new Error(createDocMessage(
|
throw new Error(createDocMessage(
|
||||||
'Missing `cli` url - CLI Commands must include a first child node with url set at `cli`',
|
'Missing `cli` url - CLI Commands must include a first child node with url set at `cli`',
|
||||||
navigationDoc));
|
navigationDoc));
|
||||||
|
@ -24,13 +22,41 @@ module.exports = function processCliCommands(createDocMessage) {
|
||||||
doc.optionKeywords = Array.from(optionKeywords).join(' ');
|
doc.optionKeywords = Array.from(optionKeywords).join(' ');
|
||||||
|
|
||||||
// Add to navigation doc
|
// Add to navigation doc
|
||||||
navigationNode.children.push({url: doc.path, title: `ng ${doc.name}`});
|
cliCommandsNode.children.push({url: doc.path, title: `ng ${doc.name}`});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Look for the `CLI Commands` navigation node. It is the node whose first child has `url: 'cli'`.
|
||||||
|
// (NOTE: Using the URL instead of the title, because it is more robust.)
|
||||||
|
function findCliCommandsNode(nodes) {
|
||||||
|
// We will "recursively" check all navigation nodes and their children (in breadth-first order),
|
||||||
|
// until we find the `CLI Commands` node. Keep a list of nodes lists to check.
|
||||||
|
// (NOTE: Each item in the list is a LIST of nodes.)
|
||||||
|
const nodesList = [nodes];
|
||||||
|
|
||||||
|
while (nodesList.length > 0) {
|
||||||
|
// Get the first item from the list of nodes lists.
|
||||||
|
const currentNodes = nodesList.shift();
|
||||||
|
const cliCommandsNode = currentNodes.find(isCliCommandsNode);
|
||||||
|
|
||||||
|
// One of the nodes in `currentNodes` was the `CLI Commands` node. Return it.
|
||||||
|
if (cliCommandsNode) return cliCommandsNode;
|
||||||
|
|
||||||
|
// The `CLI Commands` node is not in `currentNodes`. Check each node's children (if any).
|
||||||
|
currentNodes.forEach(node => node.children && nodesList.push(node.children));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We checked all navigation nodes and their children and did not find the `CLI Commands` node.
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCliCommandsNode(node) {
|
||||||
|
return node.children && node.children.length && node.children[0].url === 'cli';
|
||||||
|
}
|
||||||
|
|
||||||
function processOptions(container, options, optionKeywords) {
|
function processOptions(container, options, optionKeywords) {
|
||||||
container.positionalOptions = [];
|
container.positionalOptions = [];
|
||||||
container.namedOptions = [];
|
container.namedOptions = [];
|
||||||
|
|
|
@ -258,14 +258,15 @@ describe('processCliCommands processor', () => {
|
||||||
docType: 'navigation-json',
|
docType: 'navigation-json',
|
||||||
data: {
|
data: {
|
||||||
SideNav: [
|
SideNav: [
|
||||||
{url: 'some/page', title: 'Some Page'}, {
|
{url: 'some/page', title: 'Some Page'},
|
||||||
|
{
|
||||||
title: 'CLI Commands',
|
title: 'CLI Commands',
|
||||||
tooltip: 'Angular CLI command reference',
|
tooltip: 'Angular CLI command reference',
|
||||||
children: [{'title': 'Overview', 'url': 'cli'}]
|
children: [{'title': 'Overview', 'url': 'cli'}],
|
||||||
|
},
|
||||||
|
{url: 'other/page', title: 'Other Page'},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{url: 'other/page', title: 'Other Page'}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
processor.$process([command, navigation]);
|
processor.$process([command, navigation]);
|
||||||
expect(navigation.data.SideNav[1].title).toEqual('CLI Commands');
|
expect(navigation.data.SideNav[1].title).toEqual('CLI Commands');
|
||||||
|
@ -275,6 +276,54 @@ describe('processCliCommands processor', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should detect the CLI node if it is nested in another node (as long as there is a first child node with a `cli` url',
|
||||||
|
() => {
|
||||||
|
const command = {
|
||||||
|
docType: 'cli-command',
|
||||||
|
name: 'command1',
|
||||||
|
commandAliases: ['alias1', 'alias2'],
|
||||||
|
options: [],
|
||||||
|
path: 'cli/command1',
|
||||||
|
};
|
||||||
|
const navigation = {
|
||||||
|
docType: 'navigation-json',
|
||||||
|
data: {
|
||||||
|
SideNav: [
|
||||||
|
{url: 'some/page', title: 'Some Page'},
|
||||||
|
{
|
||||||
|
title: 'CLI Commands Grandparent',
|
||||||
|
children: [
|
||||||
|
{url: 'some/nested/page', title: 'Some Nested Page'},
|
||||||
|
{
|
||||||
|
title: 'CLI Commands Parent',
|
||||||
|
children: [
|
||||||
|
{url: 'some/more/nested/page', title: 'Some More Nested Page'},
|
||||||
|
{
|
||||||
|
title: 'CLI Commands',
|
||||||
|
tooltip: 'Angular CLI command reference',
|
||||||
|
children: [{'title': 'Overview', 'url': 'cli'}],
|
||||||
|
},
|
||||||
|
{url: 'other/more/nested/page', title: 'Other More Nested Page'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{url: 'other/nested/page', title: 'Other Nested Page'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{url: 'other/page', title: 'Other Page'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
processor.$process([command, navigation]);
|
||||||
|
|
||||||
|
const cliCommandsNode = navigation.data.SideNav[1].children[1].children[1];
|
||||||
|
expect(cliCommandsNode.title).toEqual('CLI Commands');
|
||||||
|
expect(cliCommandsNode.children).toEqual([
|
||||||
|
{url: 'cli', title: 'Overview'},
|
||||||
|
{url: 'cli/command1', title: 'ng command1'},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('should complain if there is no child with `cli` url', () => {
|
it('should complain if there is no child with `cli` url', () => {
|
||||||
const command = {
|
const command = {
|
||||||
docType: 'cli-command',
|
docType: 'cli-command',
|
||||||
|
|
Loading…
Reference in New Issue