From e2b76bb3860e5cdb4ad3e8595520f7edc3b137a3 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Mon, 20 Nov 2017 14:46:14 +0000 Subject: [PATCH] build(aio): filter out ambiguous directives from auto code linking (#20512) Closes #20466 PR Close #20512 --- .../transforms/angular-base-package/index.js | 5 +- .../filterAmbiguousDirectiveAliases.js | 26 ++++++++++ .../filterAmbiguousDirectiveAliases.spec.js | 50 +++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 aio/tools/transforms/angular-base-package/services/filterAmbiguousDirectiveAliases.js create mode 100644 aio/tools/transforms/angular-base-package/services/filterAmbiguousDirectiveAliases.spec.js diff --git a/aio/tools/transforms/angular-base-package/index.js b/aio/tools/transforms/angular-base-package/index.js index 1b72f54640..b94b79d100 100644 --- a/aio/tools/transforms/angular-base-package/index.js +++ b/aio/tools/transforms/angular-base-package/index.js @@ -36,6 +36,7 @@ module.exports = new Package('angular-base', [ .factory(require('./readers/json')) .factory(require('./services/copyFolder')) .factory(require('./services/filterPipes')) + .factory(require('./services/filterAmbiguousDirectiveAliases')) .factory(require('./services/getImageDimensions')) .factory(require('./post-processors/add-image-dimensions')) @@ -127,9 +128,9 @@ module.exports = new Package('angular-base', [ }) - .config(function(postProcessHtml, addImageDimensions, autoLinkCode, filterPipes) { + .config(function(postProcessHtml, addImageDimensions, autoLinkCode, filterPipes, filterAmbiguousDirectiveAliases) { addImageDimensions.basePath = path.resolve(AIO_PATH, 'src'); - autoLinkCode.customFilters = [filterPipes]; + autoLinkCode.customFilters = [filterPipes, filterAmbiguousDirectiveAliases]; postProcessHtml.plugins = [ require('./post-processors/autolink-headings'), addImageDimensions, diff --git a/aio/tools/transforms/angular-base-package/services/filterAmbiguousDirectiveAliases.js b/aio/tools/transforms/angular-base-package/services/filterAmbiguousDirectiveAliases.js new file mode 100644 index 0000000000..c599230c53 --- /dev/null +++ b/aio/tools/transforms/angular-base-package/services/filterAmbiguousDirectiveAliases.js @@ -0,0 +1,26 @@ + +/** + * This service is used by the autoLinkCode post-processor to filter out ambiguous directive + * docs where the matching word is a directive selector. + * E.g. `ngModel`, which is a selector for a number of directives, where we are only really + * interested in the `NgModel` class. + */ +module.exports = function filterAmbiguousDirectiveAliases() { + return (docs, words, index) => { + const word = words[index]; + + // we are only interested if there are multiple matching docs + if (docs.length > 1) { + if (docs.every(doc => + // We are only interested if they are all either directives or components + (doc.docType === 'directive' || doc.docType === 'component') && + // and the matching word is in the selector for all of them + doc[doc.docType + 'Options'].selector.indexOf(word) != -1 + )) { + // find the directive whose class name matches the word (case-insensitive) + return docs.filter(doc => doc.name.toLowerCase() === word.toLowerCase()); + } + } + return docs; + }; +}; diff --git a/aio/tools/transforms/angular-base-package/services/filterAmbiguousDirectiveAliases.spec.js b/aio/tools/transforms/angular-base-package/services/filterAmbiguousDirectiveAliases.spec.js new file mode 100644 index 0000000000..14564898bb --- /dev/null +++ b/aio/tools/transforms/angular-base-package/services/filterAmbiguousDirectiveAliases.spec.js @@ -0,0 +1,50 @@ +const filterAmbiguousDirectiveAliases = require('./filterAmbiguousDirectiveAliases')(); + +const words = ['Http', 'ngModel', 'NgModel', 'NgControlStatus']; + +describe('filterAmbiguousDirectiveAliases(docs, words, index)', () => { + it('should not try to filter the docs, if the docs are not all directives or components', () => { + const docs = [ + { docType: 'class', name: 'Http' }, + { docType: 'directive', name: 'NgModel', directiveOptions: { selector: '[ngModel]' } }, + { docType: 'component', name: 'NgModel', componentOptions: { selector: '[ngModel]' } } + ]; + // take a copy to prove `docs` was not modified + const filteredDocs = docs.slice(0); + expect(filterAmbiguousDirectiveAliases(docs, words, 1)).toEqual(filteredDocs); + expect(filterAmbiguousDirectiveAliases(docs, words, 2)).toEqual(filteredDocs); + }); + + describe('(where all the docs are components or directives', () => { + describe('and do not all contain the matching word in their selector)', () => { + it('should not try to filter the docs', () => { + const docs = [ + { docType: 'directive', name: 'NgModel', ['directiveOptions']: { selector: '[ngModel]' } }, + { docType: 'component', name: 'NgControlStatus', ['componentOptions']: { selector: '[ngControlStatus]' } } + ]; + // take a copy to prove `docs` was not modified + const filteredDocs = docs.slice(0); + expect(filterAmbiguousDirectiveAliases(docs, words, 1)).toEqual(filteredDocs); + expect(filterAmbiguousDirectiveAliases(docs, words, 2)).toEqual(filteredDocs); + + // Also test that the check is case-sensitive + docs[1].componentOptions.selector = '[ngModel]'; + filteredDocs[1].componentOptions.selector = '[ngModel]'; + expect(filterAmbiguousDirectiveAliases(docs, words, 2)).toEqual(filteredDocs); + }); + }); + + describe('and do all contain the matching word in there selector)', () => { + it('should filter out docs whose class name is not (case-insensitively) equal to the matching word', () => { + const docs = [ + { docType: 'directive', name: 'NgModel', ['directiveOptions']: { selector: '[ngModel],[ngControlStatus]' } }, + { docType: 'component', name: 'NgControlStatus', ['componentOptions']: { selector: '[ngModel],[ngControlStatus]' } } + ]; + const filteredDocs = [ + { docType: 'directive', name: 'NgModel', ['directiveOptions']: { selector: '[ngModel],[ngControlStatus]' } } + ]; + expect(filterAmbiguousDirectiveAliases(docs, words, 1)).toEqual(filteredDocs); + }); + }); + }); +});