build(docs-infra): directive inputs and outputs (#25768)
PR Close #25768
This commit is contained in:
parent
d0f7eadc09
commit
9889276b15
|
@ -33,6 +33,7 @@
|
|||
.method-table, .option-table, .list-table {
|
||||
td > code {
|
||||
background-color: inherit;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.with-github-links {
|
||||
|
@ -74,19 +75,6 @@
|
|||
margin: 6px 0 0 10px;
|
||||
}
|
||||
|
||||
.properties-table {
|
||||
font-size: 14px;
|
||||
|
||||
thead th {
|
||||
&:nth-child(1) {
|
||||
width: 20%;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
width: 20%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.parameters-table {
|
||||
margin-top: 0;
|
||||
font-size: 14px;
|
||||
|
@ -126,6 +114,10 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.property-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.deprecated-api-item {
|
||||
|
|
|
@ -25,62 +25,59 @@ module.exports = function matchUpDirectiveDecorators() {
|
|||
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');
|
||||
attachBindingInfo(doc.directiveOptions.inputs, doc.members, 'Input');
|
||||
attachBindingInfo(doc.directiveOptions.outputs, doc.members, 'Output');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function getBindingInfo(directiveBindings, members, bindingType) {
|
||||
function attachBindingInfo(directiveBindings, members, bindingType) {
|
||||
const bindings = {};
|
||||
|
||||
if (members) {
|
||||
// Parse the bindings from the directive decorator
|
||||
if (directiveBindings) {
|
||||
directiveBindings.forEach(function(binding) {
|
||||
const bindingInfo = parseBinding(binding);
|
||||
const bindingInfo = parseBinding(bindingType, binding);
|
||||
bindings[bindingInfo.propertyName] = bindingInfo;
|
||||
});
|
||||
}
|
||||
|
||||
if (members) {
|
||||
members.forEach(function(member) {
|
||||
if (member.decorators) {
|
||||
// Search for members with binding decorators
|
||||
member.decorators.forEach(function(decorator) {
|
||||
if (decorator.name === bindingType) {
|
||||
bindings[member.name] = createBindingInfo(member.name, decorator.arguments[0] || member.name);
|
||||
bindings[member.name] = createBindingInfo(bindingType, member.name, decorator.arguments[0] || member.name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Now ensure that any bindings have the associated member attached
|
||||
// Note that this binding could have come from the directive decorator
|
||||
// Attach binding info to the member
|
||||
// Note: this may have come from the `@Directive` decorator or from a property decorator such as `@Input`.
|
||||
if (bindings[member.name]) {
|
||||
bindings[member.name].memberDoc = member;
|
||||
member.boundTo = bindings[member.name];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Convert the map back to an array
|
||||
return Object.keys(bindings).map(function(key) { return bindings[key]; });
|
||||
}
|
||||
|
||||
function stripQuotes(value) {
|
||||
return (typeof(value) === 'string') ? value.trim().replace(/^(['"])(.*)\1$/, '$2') : value;
|
||||
}
|
||||
|
||||
function parseBinding(option) {
|
||||
function parseBinding(bindingType, option) {
|
||||
// Directive decorator bindings are of the form: "propName : bindingName" (bindingName is optional)
|
||||
const optionPair = option.split(':');
|
||||
const propertyName = optionPair[0].trim();
|
||||
const bindingName = (optionPair[1] || '').trim() || propertyName;
|
||||
return createBindingInfo(propertyName, bindingName);
|
||||
return createBindingInfo(bindingType, propertyName, bindingName);
|
||||
}
|
||||
|
||||
function createBindingInfo(propertyName, bindingName) {
|
||||
function createBindingInfo(bindingType, propertyName, bindingName) {
|
||||
return {
|
||||
type: bindingType,
|
||||
propertyName: stripQuotes(propertyName),
|
||||
bindingName: stripQuotes(bindingName)
|
||||
};
|
||||
|
|
|
@ -59,7 +59,7 @@ describe('matchUpDirectiveDecorators processor', () => {
|
|||
});
|
||||
|
||||
it('should extract inputs and outputs from the directive decorator', () => {
|
||||
const docs = [{
|
||||
const doc = {
|
||||
docType: 'directive',
|
||||
directiveOptions: {
|
||||
inputs: ['in1:in2', 'in3', ' in4:in5 ', ' in6 '],
|
||||
|
@ -70,28 +70,30 @@ describe('matchUpDirectiveDecorators processor', () => {
|
|||
{ name: 'in3' },
|
||||
{ name: 'in4' },
|
||||
{ name: 'in6' },
|
||||
{ name: 'prop1' },
|
||||
{ name: 'out1' },
|
||||
{ name: 'out2' },
|
||||
{ name: 'out4' }
|
||||
{ name: 'out4' },
|
||||
{ name: 'prop2' },
|
||||
]
|
||||
}];
|
||||
processorFactory().$process(docs);
|
||||
expect(docs[0].inputs).toEqual([
|
||||
{ propertyName: 'in1', bindingName: 'in2', memberDoc: docs[0].members[0] },
|
||||
{ propertyName: 'in3', bindingName: 'in3', memberDoc: docs[0].members[1] },
|
||||
{ propertyName: 'in4', bindingName: 'in5', memberDoc: docs[0].members[2] },
|
||||
{ propertyName: 'in6', bindingName: 'in6', memberDoc: docs[0].members[3] }
|
||||
]);
|
||||
};
|
||||
|
||||
expect(docs[0].outputs).toEqual([
|
||||
{ propertyName: 'out1', bindingName: 'out1', memberDoc: docs[0].members[4] },
|
||||
{ propertyName: 'out2', bindingName: 'out3', memberDoc: docs[0].members[5] },
|
||||
{ propertyName: 'out4', bindingName: 'out4', memberDoc: docs[0].members[6] }
|
||||
processorFactory().$process([doc]);
|
||||
expect(doc.members).toEqual([
|
||||
{ name: 'in1', boundTo: { type: 'Input', propertyName: 'in1', bindingName: 'in2' } },
|
||||
{ name: 'in3', boundTo: { type: 'Input', propertyName: 'in3', bindingName: 'in3' } },
|
||||
{ name: 'in4', boundTo: { type: 'Input', propertyName: 'in4', bindingName: 'in5' } },
|
||||
{ name: 'in6', boundTo: { type: 'Input', propertyName: 'in6', bindingName: 'in6' }},
|
||||
{ name: 'prop1' },
|
||||
{ name: 'out1', boundTo: { type: 'Output', propertyName: 'out1', bindingName: 'out1' } },
|
||||
{ name: 'out2', boundTo: { type: 'Output', propertyName: 'out2', bindingName: 'out3' } },
|
||||
{ name: 'out4', boundTo: { type: 'Output', propertyName: 'out4', bindingName: 'out4' }},
|
||||
{ name: 'prop2' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should extract inputs and outputs from decorated properties', () => {
|
||||
const docs = [{
|
||||
const doc = {
|
||||
docType: 'directive',
|
||||
directiveOptions: {},
|
||||
members: [
|
||||
|
@ -100,21 +102,18 @@ describe('matchUpDirectiveDecorators processor', () => {
|
|||
{ name: 'c1', decorators: [{ name: 'Input', arguments: [] }] },
|
||||
{ name: 'd1', decorators: [{ name: 'Output', arguments: [] }] },
|
||||
]
|
||||
}];
|
||||
processorFactory().$process(docs);
|
||||
expect(docs[0].inputs).toEqual([
|
||||
{ propertyName: 'a1', bindingName: 'a2', memberDoc: docs[0].members[0] },
|
||||
{ propertyName: 'c1', bindingName: 'c1', memberDoc: docs[0].members[2] }
|
||||
]);
|
||||
|
||||
expect(docs[0].outputs).toEqual([
|
||||
{ propertyName: 'b1', bindingName: 'b2', memberDoc: docs[0].members[1] },
|
||||
{ propertyName: 'd1', bindingName: 'd1', memberDoc: docs[0].members[3] }
|
||||
};
|
||||
processorFactory().$process([doc]);
|
||||
expect(doc.members).toEqual([
|
||||
{ name: 'a1', decorators: [{ name: 'Input', arguments: ['a2'] }], boundTo: { type: 'Input', propertyName: 'a1', bindingName: 'a2' } },
|
||||
{ name: 'b1', decorators: [{ name: 'Output', arguments: ['b2'] }], boundTo: { type: 'Output', propertyName: 'b1', bindingName: 'b2' } },
|
||||
{ name: 'c1', decorators: [{ name: 'Input', arguments: [] }], boundTo: { type: 'Input', propertyName: 'c1', bindingName: 'c1' } },
|
||||
{ name: 'd1', decorators: [{ name: 'Output', arguments: [] }], boundTo: { type: 'Output', propertyName: 'd1', bindingName: 'd1' } },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should merge directive inputs/outputs with decorator property inputs/outputs', () => {
|
||||
const docs = [{
|
||||
const doc = {
|
||||
docType: 'directive',
|
||||
directiveOptions: {
|
||||
inputs: ['a1:a2'],
|
||||
|
@ -126,16 +125,13 @@ describe('matchUpDirectiveDecorators processor', () => {
|
|||
{ name: 'b1' },
|
||||
{ name: 'b3', decorators: [{ name: 'Output', arguments: ['b4'] }] },
|
||||
]
|
||||
}];
|
||||
processorFactory().$process(docs);
|
||||
expect(docs[0].inputs).toEqual([
|
||||
{ propertyName: 'a1', bindingName: 'a2', memberDoc: docs[0].members[0] },
|
||||
{ propertyName: 'a3', bindingName: 'a4', memberDoc: docs[0].members[1] }
|
||||
]);
|
||||
|
||||
expect(docs[0].outputs).toEqual([
|
||||
{ propertyName: 'b1', bindingName: 'b2', memberDoc: docs[0].members[2] },
|
||||
{ propertyName: 'b3', bindingName: 'b4', memberDoc: docs[0].members[3] }
|
||||
};
|
||||
processorFactory().$process([doc]);
|
||||
expect(doc.members).toEqual([
|
||||
{ name: 'a1', boundTo: { type: 'Input', propertyName: 'a1', bindingName: 'a2' } },
|
||||
{ name: 'a3', boundTo: { type: 'Input', propertyName: 'a3', bindingName: 'a4' }, decorators: [{ name: 'Input', arguments: ['a4'] }] },
|
||||
{ name: 'b1', boundTo: { type: 'Output', propertyName: 'b1', bindingName: 'b2' } },
|
||||
{ name: 'b3', boundTo: { type: 'Output', propertyName: 'b3', bindingName: 'b4' }, decorators: [{ name: 'Output', arguments: ['b4'] }] },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% import "lib/directiveHelpers.html" as directiveHelper -%}
|
||||
{% import "lib/memberHelpers.html" as memberHelpers -%}
|
||||
{% extends 'class.template.html' -%}
|
||||
|
||||
{% block overview %}{% endblock %}
|
||||
|
@ -7,9 +7,7 @@
|
|||
{% include "includes/ngmodule.html" %}
|
||||
{% include "includes/selectors.html" %}
|
||||
|
||||
{$ directiveHelper.renderBindings(doc.inputs, 'inputs', 'input', 'Inputs') $}
|
||||
|
||||
{$ directiveHelper.renderBindings(doc.outputs, 'outputs', 'output', 'Outputs') $}
|
||||
{$ memberHelpers.renderProperties(doc.properties, 'instance-properties', 'instance-property', 'Properties') $}
|
||||
|
||||
{% include "includes/export-as.html" %}
|
||||
|
||||
|
@ -21,8 +19,9 @@
|
|||
</section>
|
||||
{% endif %}
|
||||
|
||||
<h2>Class</h2>
|
||||
{% include "includes/class-members.html" %}
|
||||
{% endblock %}
|
||||
{$ memberHelpers.renderProperties(doc.staticProperties, 'static-properties', 'static-property', 'Static properties') $}
|
||||
{$ memberHelpers.renderMethodDetails(versionInfo, doc.staticMethods, 'static-methods', 'static-method', 'Static methods') $}
|
||||
{$ memberHelpers.renderMethodDetails(versionInfo, doc.methods, 'instance-methods', 'instance-method', 'Methods') $}
|
||||
{% endblock %}
|
||||
|
||||
{% block endNotes %}{% endblock %}
|
|
@ -1,40 +0,0 @@
|
|||
{% 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>
|
||||
<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 %}
|
||||
|
||||
|
|
@ -170,7 +170,6 @@
|
|||
|
||||
{%- macro renderProperties(properties, containerClass, propertyClass, headingText, headings) -%}
|
||||
{% set nonInternalProperties = properties | filterByPropertyValue('internal', undefined) %}
|
||||
{% set hasTypes = properties | hasValues('type') %}
|
||||
{% if nonInternalProperties.length -%}
|
||||
<section class="{$ containerClass $}">
|
||||
<h2>{$ headingText $}</h2>
|
||||
|
@ -178,15 +177,17 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th>{$ headings[0] or 'Property' $}</th>
|
||||
{% if hasTypes %}<th>{$ headings[1] or 'Type' $}</th>{% endif %}
|
||||
<th>{$ headings[2] or 'Description' $}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for property in nonInternalProperties %}
|
||||
<tr class="{$ propertyClass $}">
|
||||
<td><a id="{$ property.anchor $}"></a>{$ property.name $}</td>
|
||||
{% if hasTypes %}<td><label class="property-type-label"><code>{$ property.type | escape $}</code></label></td>{% endif %}
|
||||
<td>
|
||||
<code>{%- if property.boundTo %}<span class="property-binding">@{$ property.boundTo.type $}({$ property.boundTo.bindingName $})</span>
|
||||
{% endif -%}<a id="{$ property.anchor $}" class="property-name">{$ property.name $}</a>{% if property.type %}: <span class="property-type">{$ property.type | escape $}</span>{% endif -%}
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
{%- if (property.isGetAccessor or property.isReadonly) and not property.isSetAccessor %}<span class='read-only-property'>Read-only.</span>{% endif %}
|
||||
{% if property.shortDescription %}{$ property.shortDescription | marked $}{% endif %}
|
||||
|
|
Loading…
Reference in New Issue