build(aio): render class/interface "descendants" in API docs (#19343)
For classes, the tree of subclasses is rendered, recursively. For interfaces, the descendants are separated into child interfaces, which extend the interface, and classes, which implement the interface. Closes #19306
This commit is contained in:
parent
4ae546be1f
commit
97e02c2fa0
|
@ -0,0 +1,24 @@
|
||||||
|
import { ApiPage } from './api.po';
|
||||||
|
|
||||||
|
describe('Api pages', function() {
|
||||||
|
it('should show direct subclasses of a class', () => {
|
||||||
|
const page = new ApiPage('api/forms/AbstractControlDirective');
|
||||||
|
// We must use `as any` (here and below) because of broken typings for jasmine
|
||||||
|
expect(page.getDescendants('class', true)).toEqual(['ControlContainer', 'NgControl'] as any);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show direct and indirect subclasses of a class', () => {
|
||||||
|
const page = new ApiPage('api/forms/AbstractControlDirective');
|
||||||
|
expect(page.getDescendants('class')).toEqual(['ControlContainer', 'AbstractFormGroupDirective', 'NgControl'] as any);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show child interfaces that extend an interface', () => {
|
||||||
|
const page = new ApiPage('api/forms/Validator');
|
||||||
|
expect(page.getDescendants('interface')).toEqual(['AsyncValidator'] as any);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show classes that implement an interface', () => {
|
||||||
|
const page = new ApiPage('api/animations/AnimationPlayer');
|
||||||
|
expect(page.getDescendants('class')).toEqual(['NoopAnimationPlayer', 'MockAnimationPlayer'] as any);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { element, by } from 'protractor';
|
||||||
|
import { SitePage } from './app.po';
|
||||||
|
|
||||||
|
export class ApiPage extends SitePage {
|
||||||
|
constructor(url: string) {
|
||||||
|
super();
|
||||||
|
this.navigateTo(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDescendants(docType: string, onlyDirect = false) {
|
||||||
|
// This selector is horrible because we have potentially recursive HTML lists
|
||||||
|
//
|
||||||
|
// ul
|
||||||
|
// li
|
||||||
|
// code
|
||||||
|
// ul
|
||||||
|
// li
|
||||||
|
// code
|
||||||
|
// ul
|
||||||
|
// li
|
||||||
|
// code
|
||||||
|
// li
|
||||||
|
// code
|
||||||
|
//
|
||||||
|
// and we want to be able to pull out the code elements from only the first level
|
||||||
|
// if `onlyDirect` is set to `true`.
|
||||||
|
const selector = `.descendants.${docType} ${onlyDirect ? '>' : ''} li > :not(ul) code`;
|
||||||
|
return element.all(by.css(selector)).map<string>(item => item.getText());
|
||||||
|
}
|
||||||
|
}
|
|
@ -82,7 +82,7 @@
|
||||||
"concurrently": "^3.4.0",
|
"concurrently": "^3.4.0",
|
||||||
"cross-spawn": "^5.1.0",
|
"cross-spawn": "^5.1.0",
|
||||||
"dgeni": "^0.4.7",
|
"dgeni": "^0.4.7",
|
||||||
"dgeni-packages": "^0.21.2",
|
"dgeni-packages": "^0.21.3",
|
||||||
"entities": "^1.1.1",
|
"entities": "^1.1.1",
|
||||||
"eslint": "^3.19.0",
|
"eslint": "^3.19.0",
|
||||||
"eslint-plugin-jasmine": "^2.2.0",
|
"eslint-plugin-jasmine": "^2.2.0",
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
module.exports = function filterBy() {
|
||||||
|
return {
|
||||||
|
name: 'filterByPropertyValue',
|
||||||
|
process: function(list, property, value) {
|
||||||
|
if (!list) return list;
|
||||||
|
return list.filter(item => item[property] === value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,14 @@
|
||||||
|
const factory = require('./filterByPropertyValue');
|
||||||
|
|
||||||
|
describe('filterByPropertyValue filter', () => {
|
||||||
|
let filter;
|
||||||
|
|
||||||
|
beforeEach(function() { filter = factory(); });
|
||||||
|
|
||||||
|
it('should be called "filterByPropertyValue"', function() { expect(filter.name).toEqual('filterByPropertyValue'); });
|
||||||
|
|
||||||
|
it('should filter out items that do not match the given property value', function() {
|
||||||
|
expect(filter.process([{ a: 1 }, { a: 2 }, { b: 1 }, { a: 1, b: 2 }, { a: null }, { a: undefined }], 'a', 1))
|
||||||
|
.toEqual([{ a: 1 }, { a: 1, b: 2 }]);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,4 +1,5 @@
|
||||||
{% import "lib/memberHelpers.html" as memberHelpers -%}
|
{% import "lib/memberHelpers.html" as memberHelpers -%}
|
||||||
|
{% import "lib/descendants.html" as descendants -%}
|
||||||
{% import "lib/paramList.html" as params -%}
|
{% import "lib/paramList.html" as params -%}
|
||||||
{% extends 'export-base.template.html' -%}
|
{% extends 'export-base.template.html' -%}
|
||||||
|
|
||||||
|
@ -6,6 +7,7 @@
|
||||||
{% block details %}
|
{% block details %}
|
||||||
{% block additional %}{% endblock %}
|
{% block additional %}{% endblock %}
|
||||||
{% include "includes/description.html" %}
|
{% include "includes/description.html" %}
|
||||||
|
{$ descendants.renderDescendants(doc, 'class', 'Subclasses') $}
|
||||||
{$ memberHelpers.renderMemberDetails(doc.statics, 'static-members', 'static-member', 'Static Members') $}
|
{$ memberHelpers.renderMemberDetails(doc.statics, 'static-members', 'static-member', 'Static Members') $}
|
||||||
{% if doc.constructorDoc %}{$ memberHelpers.renderMemberDetails([doc.constructorDoc], 'constructors', 'constructor', 'Constructor') $}{% endif %}
|
{% if doc.constructorDoc %}{$ memberHelpers.renderMemberDetails([doc.constructorDoc], 'constructors', 'constructor', 'Constructor') $}{% endif %}
|
||||||
{$ memberHelpers.renderMemberDetails(doc.members, 'instance-members', 'instance-member', 'Members') $}
|
{$ memberHelpers.renderMemberDetails(doc.members, 'instance-members', 'instance-member', 'Members') $}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
{% import "lib/paramList.html" as params -%}
|
{% import "lib/paramList.html" as params -%}
|
||||||
{% import "lib/memberHelpers.html" as memberHelper -%}
|
{% import "lib/memberHelpers.html" as memberHelper -%}
|
||||||
|
{% import "lib/descendants.html" as descendants -%}
|
||||||
{% extends 'export-base.template.html' -%}
|
{% extends 'export-base.template.html' -%}
|
||||||
|
|
||||||
{% block overview %}{% include "includes/interface-overview.html" %}{% endblock %}
|
{% block overview %}{% include "includes/interface-overview.html" %}{% endblock %}
|
||||||
{% block details %}
|
{% block details %}
|
||||||
{% include "includes/description.html" %}
|
{% include "includes/description.html" %}
|
||||||
|
{$ descendants.renderDescendants(doc, 'interface', 'Child Interfaces') $}
|
||||||
|
{$ descendants.renderDescendants(doc, 'class', 'Class Implementations') $}
|
||||||
{$ memberHelper.renderMemberDetails(doc.members, 'instance-members', 'instance-member', 'Members') $}
|
{$ memberHelper.renderMemberDetails(doc.members, 'instance-members', 'instance-member', 'Members') $}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
{% macro renderDescendants(doc, docType, title='', recursed=false) %}
|
||||||
|
{% set descendants = doc.descendants | filterByPropertyValue('docType', docType) %}
|
||||||
|
{% if descendants.length %}
|
||||||
|
{% if title %}<h2>{$ title $}</h2>{% endif %}
|
||||||
|
<ul {% if not recursed %}class="descendants {$ docType $}"{% endif %}>
|
||||||
|
{% for descendant in descendants %}
|
||||||
|
<li>
|
||||||
|
<pre class="prettyprint lang-ts"><code>{$ descendant.name $}</code></pre>
|
||||||
|
{$ renderDescendants(descendant, docType, '', true) $}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
|
@ -2002,9 +2002,9 @@ devtools-timeline-model@1.1.6:
|
||||||
chrome-devtools-frontend "1.0.401423"
|
chrome-devtools-frontend "1.0.401423"
|
||||||
resolve "1.1.7"
|
resolve "1.1.7"
|
||||||
|
|
||||||
dgeni-packages@^0.21.2:
|
dgeni-packages@^0.21.3:
|
||||||
version "0.21.2"
|
version "0.21.3"
|
||||||
resolved "https://registry.yarnpkg.com/dgeni-packages/-/dgeni-packages-0.21.2.tgz#b031194176507b7c7d1c9735ea14664970763866"
|
resolved "https://registry.yarnpkg.com/dgeni-packages/-/dgeni-packages-0.21.3.tgz#49d5264400cdd8c8a2f66040267e38c099d540f4"
|
||||||
dependencies:
|
dependencies:
|
||||||
canonical-path "0.0.2"
|
canonical-path "0.0.2"
|
||||||
catharsis "^0.8.1"
|
catharsis "^0.8.1"
|
||||||
|
|
Loading…
Reference in New Issue