build(docs-infra): do not require abstract directives to declare a @ngModule (#36921)
Abstract directives cannot be part of a `@NgModule`, but the AIO dgeni setup currently enforces this. This commit updates the logic so that abstract directives are skipped. PR Close #36921
This commit is contained in:
parent
e17fe90aaa
commit
854bd7d0c8
|
@ -18,7 +18,10 @@ module.exports = function extractDecoratedClassesProcessor(EXPORT_DOC_TYPES) {
|
||||||
|
|
||||||
if (decoratorTypes.indexOf(decorator.name) !== -1) {
|
if (decoratorTypes.indexOf(decorator.name) !== -1) {
|
||||||
doc.docType = decorator.name.toLowerCase();
|
doc.docType = decorator.name.toLowerCase();
|
||||||
doc[doc.docType + 'Options'] = decorator.argumentInfo[0];
|
// Directives do not always have an argument (i.e. abstract directives).
|
||||||
|
// We still create options for those, as an empty object literal is equal
|
||||||
|
// to just having an empty object literal as decorator argument.
|
||||||
|
doc[doc.docType + 'Options'] = decorator.argumentInfo[0] || {};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,11 +3,20 @@ module.exports = function processNgModuleDocs(getDocFromAlias, createDocMessage,
|
||||||
$runAfter: ['extractDecoratedClassesProcessor', 'computeIdsProcessor'],
|
$runAfter: ['extractDecoratedClassesProcessor', 'computeIdsProcessor'],
|
||||||
$runBefore: ['createSitemap'],
|
$runBefore: ['createSitemap'],
|
||||||
exportDocTypes: ['directive', 'pipe'],
|
exportDocTypes: ['directive', 'pipe'],
|
||||||
|
skipAbstractDirectives: true,
|
||||||
$process(docs) {
|
$process(docs) {
|
||||||
// Match all the directives/pipes to their module
|
// Match all the directives/pipes to their module
|
||||||
const errors = [];
|
const errors = [];
|
||||||
docs.forEach(doc => {
|
docs.forEach(doc => {
|
||||||
if (this.exportDocTypes.indexOf(doc.docType) !== -1) {
|
if (this.exportDocTypes.indexOf(doc.docType) !== -1) {
|
||||||
|
const options = doc[`${doc.docType}Options`];
|
||||||
|
|
||||||
|
// Directives without a selector are considered abstract and do
|
||||||
|
// not need to be part of any `@NgModule`.
|
||||||
|
if (this.skipAbstractDirectives && doc.docType === 'directive' && !options.selector) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!doc.ngModules || doc.ngModules.length === 0) {
|
if (!doc.ngModules || doc.ngModules.length === 0) {
|
||||||
errors.push(createDocMessage(`"${doc.id}" has no @ngModule tag. Docs of type "${doc.docType}" must have this tag.`, doc));
|
errors.push(createDocMessage(`"${doc.id}" has no @ngModule tag. Docs of type "${doc.docType}" must have this tag.`, doc));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -39,11 +39,12 @@ describe('processNgModuleDocs processor', () => {
|
||||||
|
|
||||||
it('should link directive/pipe docs with their NgModule docs (sorted by id)', () => {
|
it('should link directive/pipe docs with their NgModule docs (sorted by id)', () => {
|
||||||
const aliasMap = injector.get('aliasMap');
|
const aliasMap = injector.get('aliasMap');
|
||||||
|
const directiveOptions = {selector: 'some-selector'};
|
||||||
const ngModule1 = { docType: 'ngmodule', id: 'NgModule1', aliases: ['NgModule1'], ngmoduleOptions: {}};
|
const ngModule1 = { docType: 'ngmodule', id: 'NgModule1', aliases: ['NgModule1'], ngmoduleOptions: {}};
|
||||||
const ngModule2 = { docType: 'ngmodule', id: 'NgModule2', aliases: ['NgModule2'], ngmoduleOptions: {}};
|
const ngModule2 = { docType: 'ngmodule', id: 'NgModule2', aliases: ['NgModule2'], ngmoduleOptions: {}};
|
||||||
const directive1 = { docType: 'directive', id: 'Directive1', ngModules: ['NgModule1']};
|
const directive1 = { docType: 'directive', id: 'Directive1', ngModules: ['NgModule1'], directiveOptions};
|
||||||
const directive2 = { docType: 'directive', id: 'Directive2', ngModules: ['NgModule2']};
|
const directive2 = { docType: 'directive', id: 'Directive2', ngModules: ['NgModule2'], directiveOptions};
|
||||||
const directive3 = { docType: 'directive', id: 'Directive3', ngModules: ['NgModule1', 'NgModule2']};
|
const directive3 = { docType: 'directive', id: 'Directive3', ngModules: ['NgModule1', 'NgModule2'], directiveOptions};
|
||||||
const pipe1 = { docType: 'pipe', id: 'Pipe1', ngModules: ['NgModule1']};
|
const pipe1 = { docType: 'pipe', id: 'Pipe1', ngModules: ['NgModule1']};
|
||||||
const pipe2 = { docType: 'pipe', id: 'Pipe2', ngModules: ['NgModule2']};
|
const pipe2 = { docType: 'pipe', id: 'Pipe2', ngModules: ['NgModule2']};
|
||||||
const pipe3 = { docType: 'pipe', id: 'Pipe3', ngModules: ['NgModule1', 'NgModule2']};
|
const pipe3 = { docType: 'pipe', id: 'Pipe3', ngModules: ['NgModule1', 'NgModule2']};
|
||||||
|
@ -66,10 +67,22 @@ describe('processNgModuleDocs processor', () => {
|
||||||
expect(pipe3.ngModules).toEqual([ngModule1, ngModule2]);
|
expect(pipe3.ngModules).toEqual([ngModule1, ngModule2]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not error if an abstract directove does not have a `@ngModule` tag', () => {
|
||||||
|
expect(() => {
|
||||||
|
processor.$process([{ docType: 'directive', id: 'AbstractDir', directiveOptions: {} }]);
|
||||||
|
}).not.toThrow();
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
processor.$process([{ docType: 'directive', id: 'AbstractDir',
|
||||||
|
directiveOptions: {selector: undefined} }]);
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
it('should error if a pipe/directive does not have a `@ngModule` tag', () => {
|
it('should error if a pipe/directive does not have a `@ngModule` tag', () => {
|
||||||
const log = injector.get('log');
|
const log = injector.get('log');
|
||||||
expect(() => {
|
expect(() => {
|
||||||
processor.$process([{ docType: 'directive', id: 'Directive1' }]);
|
processor.$process([{ docType: 'directive', id: 'Directive1',
|
||||||
|
directiveOptions: {selector: 'dir1'} }]);
|
||||||
}).toThrowError('Failed to process NgModule relationships.');
|
}).toThrowError('Failed to process NgModule relationships.');
|
||||||
expect(log.error).toHaveBeenCalledWith(
|
expect(log.error).toHaveBeenCalledWith(
|
||||||
'"Directive1" has no @ngModule tag. Docs of type "directive" must have this tag. - doc "Directive1" (directive) ');
|
'"Directive1" has no @ngModule tag. Docs of type "directive" must have this tag. - doc "Directive1" (directive) ');
|
||||||
|
@ -84,7 +97,8 @@ describe('processNgModuleDocs processor', () => {
|
||||||
it('should error if a pipe/directive has an @ngModule tag that does not match an NgModule doc', () => {
|
it('should error if a pipe/directive has an @ngModule tag that does not match an NgModule doc', () => {
|
||||||
const log = injector.get('log');
|
const log = injector.get('log');
|
||||||
expect(() => {
|
expect(() => {
|
||||||
processor.$process([{ docType: 'directive', id: 'Directive1', ngModules: ['MissingNgModule'] }]);
|
processor.$process([{ docType: 'directive', id: 'Directive1', ngModules: ['MissingNgModule'],
|
||||||
|
directiveOptions: {selector: 'dir1'} }]);
|
||||||
}).toThrowError('Failed to process NgModule relationships.');
|
}).toThrowError('Failed to process NgModule relationships.');
|
||||||
expect(log.error).toHaveBeenCalledWith(
|
expect(log.error).toHaveBeenCalledWith(
|
||||||
'"@ngModule MissingNgModule" does not match a public NgModule - doc "Directive1" (directive) ');
|
'"@ngModule MissingNgModule" does not match a public NgModule - doc "Directive1" (directive) ');
|
||||||
|
@ -105,7 +119,9 @@ describe('processNgModuleDocs processor', () => {
|
||||||
aliasMap.addDoc(ngModule2);
|
aliasMap.addDoc(ngModule2);
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
processor.$process([{ docType: 'directive', id: 'Directive1', ngModules: ['NgModuleAlias'] }]);
|
processor.$process([{
|
||||||
|
docType: 'directive', id: 'Directive1', ngModules: ['NgModuleAlias'],
|
||||||
|
directiveOptions: {selector: 'dir1'} }]);
|
||||||
}).toThrowError('Failed to process NgModule relationships.');
|
}).toThrowError('Failed to process NgModule relationships.');
|
||||||
expect(log.error).toHaveBeenCalledWith(
|
expect(log.error).toHaveBeenCalledWith(
|
||||||
'"@ngModule NgModuleAlias" is ambiguous. Matches: NgModule1, NgModule2 - doc "Directive1" (directive) ');
|
'"@ngModule NgModuleAlias" is ambiguous. Matches: NgModule1, NgModule2 - doc "Directive1" (directive) ');
|
||||||
|
|
Loading…
Reference in New Issue