build(docs-infra): capture all decorators in doc-gen (#41091)
In 6cff877 we broke the decorator docs because the doc-gen no longer knew how to identify them. This commit updates the dgeni processor responsible for identifying the decorators in the code and ensures that the docs are now generated correctly. Fixes #40851 PR Close #41091
This commit is contained in:
parent
7854c4ddbe
commit
2893b925c3
@ -56,7 +56,6 @@ module.exports = function mergeDecoratorDocs(log) {
|
|||||||
{type: 'Param', description: 'parameter', functionName: 'makeParamDecorator'},
|
{type: 'Param', description: 'parameter', functionName: 'makeParamDecorator'},
|
||||||
],
|
],
|
||||||
$process(docs) {
|
$process(docs) {
|
||||||
|
|
||||||
const decoratorDocs = Object.create(null);
|
const decoratorDocs = Object.create(null);
|
||||||
|
|
||||||
// find all the decorators, signified by a call to `make...Decorator<Decorator>(metadata)`
|
// find all the decorators, signified by a call to `make...Decorator<Decorator>(metadata)`
|
||||||
@ -69,7 +68,8 @@ module.exports = function mergeDecoratorDocs(log) {
|
|||||||
// For example the `X` of `createDecorator<X>(...)`.
|
// For example the `X` of `createDecorator<X>(...)`.
|
||||||
const decoratorType = initializer.arguments[0].text;
|
const decoratorType = initializer.arguments[0].text;
|
||||||
|
|
||||||
log.debug('mergeDecoratorDocs: found decorator', doc.docType, doc.name, decoratorType);
|
log.debug(
|
||||||
|
'mergeDecoratorDocs: found decorator', doc.docType, doc.name, decoratorType);
|
||||||
|
|
||||||
doc.docType = 'decorator';
|
doc.docType = 'decorator';
|
||||||
doc.decoratorLocation = call.description;
|
doc.decoratorLocation = call.description;
|
||||||
@ -84,8 +84,8 @@ module.exports = function mergeDecoratorDocs(log) {
|
|||||||
// merge the info from the associated metadata interfaces into the decorator docs
|
// merge the info from the associated metadata interfaces into the decorator docs
|
||||||
docs = docs.filter(doc => {
|
docs = docs.filter(doc => {
|
||||||
if (decoratorDocs[doc.name]) {
|
if (decoratorDocs[doc.name]) {
|
||||||
|
// We have found an `XxxDecorator` document that will hold the call signature of the
|
||||||
// We have found an `XxxDecorator` document that will hold the call signature of the decorator
|
// decorator
|
||||||
var decoratorDoc = decoratorDocs[doc.name];
|
var decoratorDoc = decoratorDocs[doc.name];
|
||||||
var callMember = doc.members.find(member => member.isCallMember);
|
var callMember = doc.members.find(member => member.isCallMember);
|
||||||
|
|
||||||
@ -109,18 +109,44 @@ module.exports = function mergeDecoratorDocs(log) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function getInitializer(doc) {
|
function getInitializer(doc) {
|
||||||
var initializer = doc.symbol && doc.symbol.valueDeclaration && doc.symbol.valueDeclaration.initializer;
|
const declaration = doc.symbol && doc.symbol.valueDeclaration;
|
||||||
|
if (!declaration || !declaration.initializer || !declaration.initializer.expression) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let initializer = declaration.initializer;
|
||||||
|
|
||||||
// There appear to be two forms of initializer:
|
// There appear to be two forms of initializer:
|
||||||
// export var Injectable: InjectableFactory =
|
//
|
||||||
|
// ```
|
||||||
|
// export const Injectable: InjectableFactory =
|
||||||
// <InjectableFactory>makeDecorator(InjectableMetadata);
|
// <InjectableFactory>makeDecorator(InjectableMetadata);
|
||||||
|
// ```
|
||||||
|
//
|
||||||
// and
|
// and
|
||||||
// export var RouteConfig: (configs: RouteDefinition[]) => ClassDecorator =
|
//
|
||||||
|
// ```
|
||||||
|
// export const RouteConfig: (configs: RouteDefinition[]) => ClassDecorator =
|
||||||
// makeDecorator(RouteConfigAnnotation);
|
// makeDecorator(RouteConfigAnnotation);
|
||||||
// In the first case, the type assertion `<InjectableFactory>` causes the AST to contain an
|
// ```
|
||||||
// extra level of expression
|
//
|
||||||
// to hold the new type of the expression.
|
// In the first case, the type assertion `<InjectableFactory>` causes the AST to contain an extra
|
||||||
if (initializer && initializer.expression && initializer.expression.expression) {
|
// level of expression to hold the new type of the expression.
|
||||||
|
if (initializer.type && initializer.expression.expression) {
|
||||||
initializer = initializer.expression;
|
initializer = initializer.expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It is also possible that the decorator call is wrapped in a call to `attachInjectFlag()`:
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// const Optional: OptionalDecorator =
|
||||||
|
// attachInjectFlag(makeParamDecorator('Optional'), InternalInjectFlags.Optional);
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// If so, use the first argument of the call.
|
||||||
|
if (initializer.arguments && initializer.expression.text === 'attachInjectFlag') {
|
||||||
|
initializer = initializer.arguments[0];
|
||||||
|
}
|
||||||
|
|
||||||
return initializer;
|
return initializer;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
var testPackage = require('../../helpers/test-package');
|
const testPackage = require('../../helpers/test-package');
|
||||||
var Dgeni = require('dgeni');
|
const Dgeni = require('dgeni');
|
||||||
|
|
||||||
describe('mergeDecoratorDocs processor', () => {
|
describe('mergeDecoratorDocs processor', () => {
|
||||||
let processor, moduleDoc, decoratorDoc, metadataDoc, otherDoc;
|
let processor, moduleDoc, decoratorDoc, metadataDoc, otherDoc;
|
||||||
@ -20,11 +20,10 @@ describe('mergeDecoratorDocs processor', () => {
|
|||||||
shortDescription: 'decorator - short description',
|
shortDescription: 'decorator - short description',
|
||||||
description: 'decorator - description',
|
description: 'decorator - description',
|
||||||
symbol: {
|
symbol: {
|
||||||
valueDeclaration: { initializer: { expression: { text: 'makeDecorator' }, arguments: [{ text: 'X' }] } }
|
valueDeclaration:
|
||||||
|
{initializer: {expression: {text: 'makeDecorator'}, arguments: [{text: 'X'}]}}
|
||||||
},
|
},
|
||||||
members: [
|
members: [{name: 'templateUrl', description: 'templateUrl - description'}],
|
||||||
{ name: 'templateUrl', description: 'templateUrl - description' }
|
|
||||||
],
|
|
||||||
moduleDoc
|
moduleDoc
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,9 +37,7 @@ describe('mergeDecoratorDocs processor', () => {
|
|||||||
description: 'call interface - call member - description',
|
description: 'call interface - call member - description',
|
||||||
usageNotes: 'call interface - call member - usageNotes',
|
usageNotes: 'call interface - call member - usageNotes',
|
||||||
},
|
},
|
||||||
{
|
{description: 'call interface - non call member - description'}
|
||||||
description: 'call interface - non call member - description'
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
moduleDoc
|
moduleDoc
|
||||||
};
|
};
|
||||||
@ -49,7 +46,8 @@ describe('mergeDecoratorDocs processor', () => {
|
|||||||
name: 'Y',
|
name: 'Y',
|
||||||
docType: 'const',
|
docType: 'const',
|
||||||
symbol: {
|
symbol: {
|
||||||
valueDeclaration: { initializer: { expression: { text: 'otherCall' }, arguments: [{ text: 'param1' }] } }
|
valueDeclaration:
|
||||||
|
{initializer: {expression: {text: 'otherCall'}, arguments: [{text: 'param1'}]}}
|
||||||
},
|
},
|
||||||
moduleDoc
|
moduleDoc
|
||||||
};
|
};
|
||||||
@ -58,7 +56,8 @@ describe('mergeDecoratorDocs processor', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should change the docType of only the docs that are initialized by a call to makeDecorator', () => {
|
it('should change the docType of only the docs that are initialized by a call to makeDecorator',
|
||||||
|
() => {
|
||||||
processor.$process([decoratorDoc, metadataDoc, otherDoc]);
|
processor.$process([decoratorDoc, metadataDoc, otherDoc]);
|
||||||
expect(decoratorDoc.docType).toEqual('decorator');
|
expect(decoratorDoc.docType).toEqual('decorator');
|
||||||
expect(otherDoc.docType).toEqual('const');
|
expect(otherDoc.docType).toEqual('const');
|
||||||
@ -88,4 +87,23 @@ describe('mergeDecoratorDocs processor', () => {
|
|||||||
processor.$process([decoratorDoc, metadataDoc, otherDoc]);
|
processor.$process([decoratorDoc, metadataDoc, otherDoc]);
|
||||||
expect(decoratorDoc.docType).toEqual('decorator');
|
expect(decoratorDoc.docType).toEqual('decorator');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should handle a type cast before the "make decorator" call', () => {
|
||||||
|
decoratorDoc.symbol.valueDeclaration.initializer = {
|
||||||
|
expression: decoratorDoc.symbol.valueDeclaration.initializer,
|
||||||
|
type: {},
|
||||||
|
};
|
||||||
|
processor.$process([decoratorDoc, metadataDoc, otherDoc]);
|
||||||
|
expect(decoratorDoc.docType).toEqual('decorator');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle the "make decorator" call being wrapped in a call to `attachInjectFlag()`',
|
||||||
|
() => {
|
||||||
|
decoratorDoc.symbol.valueDeclaration.initializer = {
|
||||||
|
expression: {text: 'attachInjectFlag'},
|
||||||
|
arguments: [decoratorDoc.symbol.valueDeclaration.initializer]
|
||||||
|
};
|
||||||
|
processor.$process([decoratorDoc, metadataDoc, otherDoc]);
|
||||||
|
expect(decoratorDoc.docType).toEqual('decorator');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user