build(docs-infra): improve directive API doc templates (#25768)

Closes #22790
Closes #25530

PR Close #25768
This commit is contained in:
Pete Bacon Darwin 2018-08-31 15:57:53 +01:00 committed by Alex Rickabaugh
parent 57de9fc41a
commit f22deb2e2d
13 changed files with 155 additions and 41 deletions

View File

@ -31,6 +31,10 @@
}
.method-table, .option-table, .list-table {
td > code {
background-color: inherit;
}
.with-github-links {
align-items: center;
display: flex;

View File

@ -137,6 +137,7 @@ aio-code pre {
.sidenav-content code a {
color: inherit;
font-size: inherit;
font-weight: inherit;
}
/* PRETTY PRINTING STYLES for prettify.js. */

View File

@ -21,7 +21,9 @@ module.exports = function matchUpDirectiveDecorators() {
if (doc.docType === 'directive') {
doc.selector = stripQuotes(doc.directiveOptions.selector);
doc.selectorArray = doc.selector ? doc.selector.split(',') : [];
doc.exportAs = stripQuotes(doc.directiveOptions.exportAs);
doc.exportAsArray = doc.exportAs ? doc.exportAs.split(',') : [];
doc.inputs = getBindingInfo(doc.directiveOptions.inputs, doc.members, 'Input');
doc.outputs = getBindingInfo(doc.directiveOptions.outputs, doc.members, 'Output');

View File

@ -3,7 +3,21 @@ module.exports = function hasValues() {
name: 'hasValues',
process: function(list, property) {
if (!list || !Array.isArray(list)) return false;
return list.some(item => item[property]);
return list.some(item => readProperty(item, property.split('.'), 0));
}
};
};
};
/**
* Search deeply into an object via a collection of property segments, starting at the
* indexed segment.
*
* E.g. if `obj = { a: { b: { c: 10 }}}` then
* `readProperty(obj, ['a', 'b', 'c'], 0)` will return true;
* but
* `readProperty(obj, ['a', 'd'], 0)` will return false;
*/
function readProperty(obj, propertySegments, index) {
const value = obj[propertySegments[index]];
return !!value && (index === propertySegments.length - 1 || readProperty(value, propertySegments, index + 1));
}

View File

@ -7,13 +7,37 @@ describe('hasValues filter', () => {
it('should be called "hasValues"', function() { expect(filter.name).toEqual('hasValues'); });
it('should return true if the specified property is truthy on any item in the list', function() {
expect(filter.process([], 'a')).toEqual(false);
expect(filter.process(0, 'a')).toEqual(false);
expect(filter.process({}, 'a')).toEqual(false);
it('should return true if the specified property path is truthy on any item in the list', function() {
expect(filter.process([{a: 1}], 'a')).toEqual(true);
expect(filter.process([{b: 2}], 'a')).toEqual(false);
expect(filter.process([{a: 1, b: 2}], 'a')).toEqual(true);
expect(filter.process([{b: 2}, {a: 1}], 'a')).toEqual(true);
expect(filter.process([{a:{b:1}}], 'a.b')).toEqual(true);
expect(filter.process([{a:{b:1}, b: 2}], 'a.b')).toEqual(true);
expect(filter.process([{b: 2}, {a:{b:1}}], 'a.b')).toEqual(true);
});
it('should return false if the value is not an object', () => {
expect(filter.process([], 'a')).toEqual(false);
expect(filter.process(0, 'a')).toEqual(false);
expect(filter.process([], 'a.b')).toEqual(false);
expect(filter.process(0, 'a.b')).toEqual(false);
});
it('should return false if the property exists but is falsy', () => {
expect(filter.process([{a: false}], 'a')).toEqual(false);
expect(filter.process([{a: ''}], 'a')).toEqual(false);
expect(filter.process([{a: 0}], 'a')).toEqual(false);
expect(filter.process([{a: null}], 'a')).toEqual(false);
expect(filter.process([{a: undefined}], 'a')).toEqual(false);
});
it('should return false if any of the properties in the path do not exist', () => {
expect(filter.process({}, 'a')).toEqual(false);
expect(filter.process({}, 'a.b')).toEqual(false);
expect(filter.process([{b: 2}], 'a')).toEqual(false);
expect(filter.process([{a: 2}], 'a.b')).toEqual(false);
expect(filter.process([{a: {}}], 'a.b.c')).toEqual(false);
});
});

View File

@ -1,21 +1,9 @@
{% import "lib/memberHelpers.html" as memberHelpers -%}
{% import "lib/descendants.html" as descendants -%}
{% import "lib/paramList.html" as params -%}
{% extends 'export-base.template.html' -%}
{% block overview %}
{% include "includes/class-overview.html" %}
{% endblock %}
{% block details %}
{% block additional %}{% endblock %}
{% include "includes/description.html" %}
{$ memberHelpers.renderProperties(doc.staticProperties, 'static-properties', 'static-property', 'Static properties') $}
{$ memberHelpers.renderMethodDetails(versionInfo, doc.staticMethods, 'static-methods', 'static-method', 'Static methods') $}
{% if doc.constructorDoc %}
<h2>Constructor</h2>
{$ memberHelpers.renderMethodDetail(versionInfo, doc.constructorDoc, 'constructor') $}{% endif %}
{$ memberHelpers.renderProperties(doc.properties, 'instance-properties', 'instance-property', 'Properties') $}
{$ memberHelpers.renderMethodDetails(versionInfo, doc.methods, 'instance-methods', 'instance-method', 'Methods') $}
{% include "includes/class-members.html" %}
{% endblock %}

View File

@ -1,14 +1,30 @@
{% import "lib/directiveHelpers.html" as directiveHelper -%}
{% import "lib/paramList.html" as params -%}
{% extends 'class.template.html' -%}
{% block overview %}{% include "includes/directive-overview.html" %}{% endblock %}
{% block additional -%}
{% include "includes/ngmodule.html" %}
{% include "includes/selectors.html" %}
{% block overview %}{% endblock %}
{% block details -%}
{% include "includes/ngmodule.html" %}
{% include "includes/selectors.html" %}
{$ directiveHelper.renderBindings(doc.inputs, 'inputs', 'input', 'Inputs') $}
{$ directiveHelper.renderBindings(doc.outputs, 'outputs', 'output', 'Outputs') $}
{% include "includes/export-as.html" %}
{% if doc.description or doc.usageNotes %}
<section class="description">
<h2>Description</h2>
{$ (doc.description or '') | trimBlankLines | marked $}
{$ (doc.usageNotes or '') | trimBlankLines | marked $}
</section>
{% endif %}
<h2>Class</h2>
{% include "includes/directive-overview.html" %}
{% include "includes/class-members.html" %}
{% endblock %}
{% block annotations %}{% endblock %}
{% block endNotes %}{% endblock %}

View File

@ -7,5 +7,5 @@
{% block overview %}{% endblock %}
{% include "includes/see-also.html" %}
{% block details %}{% endblock %}
{% include "includes/usageNotes.html" %}
{% block endNotes %}{% include "includes/usageNotes.html" %}{% endblock %}
{% endblock %}

View File

@ -0,0 +1,14 @@
{% import "lib/memberHelpers.html" as memberHelpers -%}
{$ memberHelpers.renderProperties(doc.staticProperties, 'static-properties', 'static-property', 'Static properties') $}
{$ memberHelpers.renderMethodDetails(versionInfo, doc.staticMethods, 'static-methods', 'static-method', 'Static methods') $}
{% if doc.constructorDoc %}
<h2>Constructor</h2>
{$ memberHelpers.renderMethodDetail(versionInfo, doc.constructorDoc, 'constructor') $}
{% endif %}
{$ memberHelpers.renderProperties(doc.properties, 'instance-properties', 'instance-property', 'Properties') $}
{$ memberHelpers.renderMethodDetails(versionInfo, doc.methods, 'instance-methods', 'instance-method', 'Methods') $}

View File

@ -1,4 +1,5 @@
{% import "lib/memberHelpers.html" as memberHelper -%}
{% import "lib/descendants.html" as descendants -%}
<section class="{$ doc.docType $}-overview">
<code-example language="ts" hideCopy="true" linenums="false">

View File

@ -1,8 +1,21 @@
{%- if doc.exportAs %}
<section class="export-as">
<h2>Exported as</h2>
<div>
<code>{$ doc.exportAs $}</code>
</div>
<h2>Template variable references</h2>
<table class="is-full-width list-table export-as-table">
<thead>
<tr>
<th>Identifier</th>
<th>Usage</th>
</tr>
</thead>
<tbody>
{%- for exportAs in doc.exportAsArray %}
<tr class="export-as">
<td><code>{$ exportAs $}</code></td>
<td><code>#var="{$ exportAs $}"</code></td>
</tr>
{% endfor %}
</tbody>
</table>
</section>
{% endif %}

View File

@ -1,9 +1,19 @@
{%- if doc.selector %}
<section class="selectors">
<h2>Selectors</h2>
<code-example hideCopy="true" class="no-box api-heading selector">
{%- for selector in doc.selector.split(',') %}
{$ selector $}{% endfor %}
</code-example>
<table class="is-full-width list-table selector-table">
<thead>
<tr>
<th>Selector</th>
</tr>
</thead>
<tbody>
{%- for selector in doc.selectorArray %}
<tr class="selector">
<td><code>{$ selector $}</code></td>
</tr>
{% endfor %}
</tbody>
</table>
</section>
{% endif %}

View File

@ -1,13 +1,40 @@
{% macro renderBindings(bindings, cssContainerClass, cssItemClass, title) -%}
{% set hasDescription = bindings | hasValues('memberDoc.description') %}
{% set hasTypes = bindings | hasValues('memberDoc.type') %}
{% if bindings.length %}
<section class="{$ cssContainerClass $}">
<h2>{$ title $}</h2>
{% for binding in bindings %}
<div class="{$ cssItemClass $}">
<code>{$ binding.bindingName $}</code>&nbsp;bound to&nbsp;<code>{$ binding.memberDoc.containerDoc.name $}.{$ binding.propertyName $}</code>
{#{$ binding.memberDoc.description | trimBlankLines | marked $}#}
</div>
<table class="is-full-width list-table binding-table">
<thead>
<tr>
<th>Binding</th>
{% if hasTypes %}<th>Type</th>{% endif %}
{% if hasDescription %}<th>Description</th>{% endif %}
</tr>
</thead>
<tbody>
{% for binding in bindings %}
<tr class="{$ cssItemClass $}">
<td><a href="#{$ binding.memberDoc.anchor $}">
<code>{$ binding.bindingName $}
{%- if binding.bindingName != binding.propertyName %} ({$ binding.propertyName $}){% endif-%}
</code>
</a></td>
{% if hasTypes %}
<td><label class="property-type-label"><code>{$ binding.memberDoc.type | escape $}</code></label></td>
{% endif %}
{% if hasDescription %}
<td>
{$ binding.memberDoc.shortDescription | marked $}
{$ binding.memberDoc.description | marked $}
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</section>
{% endif %}
{%- endmacro %}
{%- endmacro %}