build(aio): fix matchUpDirectiveDecorators processor
This commit is contained in:
parent
633ec30291
commit
99b38f52cb
|
@ -1,61 +1,85 @@
|
|||
var _ = require('lodash');
|
||||
|
||||
/**
|
||||
* @dgProcessor
|
||||
* @description
|
||||
* Directives in Angular are specified by various decorators. In particular the `@Directive()`
|
||||
* decorator on the class and various other property decorators, such as `@Input`.
|
||||
*
|
||||
* This processor will extract this decorator information and attach it as properties to the
|
||||
* directive document.
|
||||
*
|
||||
* Notably, the `input` and `output` binding information can be specified
|
||||
* either via property decorators (`@Input()`/`@Output()`) or by properties on the metadata
|
||||
* passed to the `@Directive` decorator. This processor will collect up info from both and
|
||||
* merge them.
|
||||
*/
|
||||
module.exports = function matchUpDirectiveDecoratorsProcessor() {
|
||||
|
||||
module.exports = function matchUpDirectiveDecorators() {
|
||||
return {
|
||||
$runAfter: ['ids-computed', 'paths-computed'],
|
||||
$runBefore: ['rendering-docs'],
|
||||
decoratorMappings: {'Inputs': 'inputs', 'Outputs': 'outputs'},
|
||||
$process: function(docs) {
|
||||
var decoratorMappings = this.decoratorMappings;
|
||||
_.forEach(docs, function(doc) {
|
||||
docs.forEach(function(doc) {
|
||||
if (doc.docType === 'directive') {
|
||||
doc.selector = doc.directiveOptions.selector;
|
||||
|
||||
for (let decoratorName in decoratorMappings) {
|
||||
var propertyName = decoratorMappings[decoratorName];
|
||||
doc[propertyName] =
|
||||
getDecoratorValues(doc.directiveOptions[propertyName], decoratorName, doc.members);
|
||||
}
|
||||
doc.selector = stripQuotes(doc.directiveOptions.selector);
|
||||
doc.exportAs = stripQuotes(doc.directiveOptions.exportAs);
|
||||
|
||||
doc.inputs = getBindingInfo(doc.directiveOptions.inputs, doc.members, 'Input');
|
||||
doc.outputs = getBindingInfo(doc.directiveOptions.outputs, doc.members, 'Output');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function getDecoratorValues(classDecoratorValues, memberDecoratorName, members) {
|
||||
var decoratorValues = {};
|
||||
function getBindingInfo(directiveBindings, members, bindingType) {
|
||||
const bindings = {};
|
||||
|
||||
// Parse the class decorator
|
||||
_.forEach(classDecoratorValues, function(option) {
|
||||
// Options are of the form: "propName : bindingName" (bindingName is optional)
|
||||
var optionPair = option.split(':');
|
||||
var propertyName = optionPair.shift().trim();
|
||||
var bindingName = (optionPair.shift() || '').trim() || propertyName;
|
||||
|
||||
decoratorValues[propertyName] = {propertyName: propertyName, bindingName: bindingName};
|
||||
// Parse the bindings from the directive decorator
|
||||
if (directiveBindings) {
|
||||
directiveBindings.forEach(function(binding) {
|
||||
const bindingInfo = parseBinding(binding);
|
||||
bindings[bindingInfo.propertyName] = bindingInfo;
|
||||
});
|
||||
}
|
||||
|
||||
_.forEach(members, function(member) {
|
||||
_.forEach(member.decorators, function(decorator) {
|
||||
if (decorator.name === memberDecoratorName) {
|
||||
decoratorValues[member.name] = {
|
||||
propertyName: member.name,
|
||||
bindingName: decorator.arguments[0] || member.name
|
||||
};
|
||||
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);
|
||||
}
|
||||
});
|
||||
if (decoratorValues[member.name]) {
|
||||
decoratorValues[member.name].memberDoc = member;
|
||||
}
|
||||
|
||||
// Now ensure that any bindings have the associated member attached
|
||||
// Note that this binding could have come from the directive decorator
|
||||
if (bindings[member.name]) {
|
||||
bindings[member.name].memberDoc = member;
|
||||
}
|
||||
});
|
||||
|
||||
if (Object.keys(decoratorValues).length) {
|
||||
return decoratorValues;
|
||||
}
|
||||
|
||||
// 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.replace(/^(['"])(.*)\1/, '$2') : value;
|
||||
}
|
||||
|
||||
function parseBinding(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);
|
||||
}
|
||||
|
||||
function createBindingInfo(propertyName, bindingName) {
|
||||
return {
|
||||
propertyName: stripQuotes(propertyName),
|
||||
bindingName: stripQuotes(bindingName)
|
||||
};
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
const testPackage = require('../../helpers/test-package');
|
||||
const processorFactory = require('./matchUpDirectiveDecorators');
|
||||
const Dgeni = require('dgeni');
|
||||
|
||||
describe('matchUpDirectiveDecorators processor', () => {
|
||||
|
||||
it('should be available on the injector', () => {
|
||||
const dgeni = new Dgeni([testPackage('angular-api-package')]);
|
||||
const injector = dgeni.configureInjector();
|
||||
const processor = injector.get('matchUpDirectiveDecorators');
|
||||
expect(processor.$process).toBeDefined();
|
||||
expect(processor.$runAfter).toContain('ids-computed');
|
||||
expect(processor.$runAfter).toContain('paths-computed');
|
||||
expect(processor.$runBefore).toContain('rendering-docs');
|
||||
});
|
||||
|
||||
it('should extract selector and exportAs from the directive decorator on directive docs', () => {
|
||||
const docs = [{
|
||||
docType: 'directive',
|
||||
directiveOptions: { selector: 'a,b,c', exportAs: 'someExport' }
|
||||
}];
|
||||
processorFactory().$process(docs);
|
||||
expect(docs[0].selector).toEqual('a,b,c');
|
||||
expect(docs[0].exportAs).toEqual('someExport');
|
||||
});
|
||||
|
||||
it('should ignore properties from the directive decorator on non-directive docs', () => {
|
||||
const docs = [{
|
||||
docType: 'class',
|
||||
directiveOptions: { selector: 'a,b,c', exportAs: 'someExport' }
|
||||
}];
|
||||
processorFactory().$process(docs);
|
||||
expect(docs[0].selector).toBeUndefined();
|
||||
expect(docs[0].exportAs).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should strip quotes off directive properties', () => {
|
||||
const docs = [{
|
||||
docType: 'directive',
|
||||
directiveOptions: { selector: '"a,b,c"', exportAs: '\'someExport\'' }
|
||||
}];
|
||||
processorFactory().$process(docs);
|
||||
expect(docs[0].selector).toEqual('a,b,c');
|
||||
expect(docs[0].exportAs).toEqual('someExport');
|
||||
});
|
||||
|
||||
it('should extract inputs and outputs from the directive decorator', () => {
|
||||
const docs = [{
|
||||
docType: 'directive',
|
||||
directiveOptions: {
|
||||
inputs: ['a:b', 'x'],
|
||||
outputs: ['foo:foo']
|
||||
},
|
||||
members: [
|
||||
{ name: 'a' },
|
||||
{ name: 'x' },
|
||||
{ name: 'foo' }
|
||||
]
|
||||
}];
|
||||
processorFactory().$process(docs);
|
||||
expect(docs[0].inputs).toEqual([
|
||||
{ propertyName: 'a', bindingName: 'b', memberDoc: docs[0].members[0] },
|
||||
{ propertyName: 'x', bindingName: 'x', memberDoc: docs[0].members[1] }
|
||||
]);
|
||||
|
||||
expect(docs[0].outputs).toEqual([
|
||||
{ propertyName: 'foo', bindingName: 'foo', memberDoc: docs[0].members[2] }
|
||||
]);
|
||||
});
|
||||
|
||||
it('should extract inputs and outputs from decorated properties', () => {
|
||||
const docs = [{
|
||||
docType: 'directive',
|
||||
directiveOptions: {},
|
||||
members: [
|
||||
{ name: 'a1', decorators: [{ name: 'Input', arguments: ['a2'] }] },
|
||||
{ name: 'b1', decorators: [{ name: 'Output', arguments: ['b2'] }] },
|
||||
{ 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] }
|
||||
]);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue