build(aio): move link disambiguation from `getLinkInfo` to `getDocFromAlias` (#22494)

The disambiguation needs to be done earlier so that the auto-link-code
post-processor can benefit from it.

PR Close #22494
This commit is contained in:
Pete Bacon Darwin 2018-02-28 14:52:29 +00:00 committed by Alex Eagle
parent 94707fe795
commit 997b30a093
10 changed files with 101 additions and 86 deletions

View File

@ -8,15 +8,16 @@ module.exports =
.factory(require('./services/getAliases')) .factory(require('./services/getAliases'))
.factory(require('./services/getDocFromAlias')) .factory(require('./services/getDocFromAlias'))
.factory(require('./services/getLinkInfo')) .factory(require('./services/getLinkInfo'))
.factory(require('./services/moduleScopeLinkDisambiguator')) .factory(require('./services/disambiguators/disambiguateByDeprecated'))
.factory(require('./services/deprecatedDocsLinkDisambiguator')) .factory(require('./services/disambiguators/disambiguateByModule'))
.config(function(inlineTagProcessor, linkInlineTagDef) { .config(function(inlineTagProcessor, linkInlineTagDef) {
inlineTagProcessor.inlineTagDefinitions.push(linkInlineTagDef); inlineTagProcessor.inlineTagDefinitions.push(linkInlineTagDef);
}) })
.config(function( .config(function(getDocFromAlias, disambiguateByDeprecated, disambiguateByModule) {
getLinkInfo, moduleScopeLinkDisambiguator, deprecatedDocsLinkDisambiguator) { getDocFromAlias.disambiguators = [
getLinkInfo.disambiguators.push(moduleScopeLinkDisambiguator); disambiguateByDeprecated,
getLinkInfo.disambiguators.push(deprecatedDocsLinkDisambiguator); disambiguateByModule
];
}); });

View File

@ -1,12 +0,0 @@
var _ = require('lodash');
module.exports = function deprecatedDocsLinkDisambiguator() {
return function(url, title, currentDoc, docs) {
if (docs.length != 2) return docs;
var filteredDocs = _.filter(
docs, function(doc) { return !doc.fileInfo.relativePath.match(/\/(\w+)-deprecated\//); });
return filteredDocs.length > 0 ? filteredDocs : docs;
};
};

View File

@ -0,0 +1,3 @@
module.exports = function disambiguateByDeprecated() {
return (alias, originatingDoc, docs) => docs.filter(doc => doc.deprecated === undefined);
};

View File

@ -0,0 +1,17 @@
const disambiguateByDeprecated = require('./disambiguateByDeprecated')();
const docs = [
{ id: 'doc1' },
{ id: 'doc2', deprecated: true },
{ id: 'doc3', deprecated: '' },
{ id: 'doc4' },
{ id: 'doc5', deprecated: 'Some text' },
];
describe('disambiguateByDeprecated', () => {
it('should filter out docs whose `deprecated` property is defined', () => {
expect(disambiguateByDeprecated('alias', {}, docs)).toEqual([
{ id: 'doc1' },
{ id: 'doc4' },
]);
});
});

View File

@ -0,0 +1,12 @@
module.exports = function disambiguateByModule() {
return (alias, originatingDoc, docs) => {
const originatingModule = originatingDoc && originatingDoc.moduleDoc;
if (originatingModule) {
const filteredDocs = docs.filter(doc => doc.moduleDoc === originatingModule);
if (filteredDocs.length > 0) {
return filteredDocs;
}
}
return docs;
};
};

View File

@ -0,0 +1,29 @@
const disambiguateByModule = require('./disambiguateByModule')();
const moduleA = { name: 'a' };
const moduleB = { name: 'b' };
const docs = [
{ id: 'doc1', moduleDoc: moduleA },
{ id: 'doc2', moduleDoc: moduleA },
{ id: 'doc3', moduleDoc: moduleB },
];
describe('disambiguateByModule', () => {
it('should return all docs if the originating doc has no moduleDoc', () => {
expect(disambiguateByModule('alias', { }, docs)).toEqual(docs);
});
it('should return all docs if no docs match the originating doc moduleDoc', () => {
expect(disambiguateByModule('alias', { moduleDoc: { name: 'c' } }, docs)).toEqual(docs);
});
it('should return only docs that match the moduleDoc of the originating doc', () => {
expect(disambiguateByModule('alias', { moduleDoc: moduleA }, docs)).toEqual([
{ id: 'doc1', moduleDoc: moduleA },
{ id: 'doc2', moduleDoc: moduleA },
]);
expect(disambiguateByModule('alias', { moduleDoc: moduleB }, docs)).toEqual([
{ id: 'doc3', moduleDoc: moduleB },
]);
});
});

View File

@ -1,31 +1,23 @@
var _ = require('lodash');
/** /**
* @dgService getDocFromAlias * @dgService getDocFromAlias
* @description Get an array of docs that match this alias, relative to the originating doc. * @description Get an array of docs that match this alias, relative to the originating doc.
*
* @property {Array<(alias: string, originatingDoc: Doc, ambiguousDocs: Doc[]) => Doc[]>} disambiguators
* a collection of functions that attempt to resolve ambiguous links. Each disambiguator returns
* a new collection of docs with unwanted ambiguous docs removed (see links-package/service/disambiguators
* for examples).
*/ */
module.exports = function getDocFromAlias(aliasMap) { module.exports = function getDocFromAlias(aliasMap) {
return function getDocFromAlias(alias, originatingDoc) { getDocFromAlias.disambiguators = [];
var docs = aliasMap.getDocs(alias); return getDocFromAlias;
// If there is more than one item with this name then try to filter them by the originatingDoc's function getDocFromAlias(alias, originatingDoc) {
// area return getDocFromAlias.disambiguators.reduce(
if (docs.length > 1 && originatingDoc && originatingDoc.area) { // Run the disambiguators while there is more than 1 doc found
docs = _.filter(docs, function(doc) { return doc.area === originatingDoc.area; }); (docs, disambiguater) => docs.length > 1 ? disambiguater(alias, originatingDoc, docs) : docs,
} // Start with the docs that match the alias
aliasMap.getDocs(alias)
// If filtering by area left us with none then let's start again );
if (docs.length === 0) { }
docs = aliasMap.getDocs(alias);
}
// If there is more than one item with this name then try to filter them by the originatingDoc's
// module
if (docs.length > 1 && originatingDoc && originatingDoc.module) {
docs = _.filter(docs, function(doc) { return doc.module === originatingDoc.module; });
}
return docs;
};
}; };

View File

@ -3,15 +3,15 @@ var Dgeni = require('dgeni');
var getDocFromAlias, aliasMap; var getDocFromAlias, aliasMap;
describe('getDocFromAlias', function() { describe('getDocFromAlias', () => {
beforeEach(function() { beforeEach(() => {
var dgeni = new Dgeni([testPackage('links-package', true)]); var dgeni = new Dgeni([testPackage('links-package', true)]);
var injector = dgeni.configureInjector(); var injector = dgeni.configureInjector();
aliasMap = injector.get('aliasMap'); aliasMap = injector.get('aliasMap');
getDocFromAlias = injector.get('getDocFromAlias'); getDocFromAlias = injector.get('getDocFromAlias');
}); });
it('should return an array of docs that match the alias', function() { it('should return an array of docs that match the alias', () => {
var doc1 = {aliases: ['a', 'b', 'c']}; var doc1 = {aliases: ['a', 'b', 'c']};
var doc2 = {aliases: ['a', 'b']}; var doc2 = {aliases: ['a', 'b']};
var doc3 = {aliases: ['a']}; var doc3 = {aliases: ['a']};
@ -24,25 +24,24 @@ describe('getDocFromAlias', function() {
expect(getDocFromAlias('c')).toEqual([doc1]); expect(getDocFromAlias('c')).toEqual([doc1]);
}); });
it('should return docs that match the alias and originating doc\'s area', function() { it('should filter ambiguous docs by calling each disambiguator', () => {
var doc1 = {aliases: ['a'], area: 'api'}; getDocFromAlias.disambiguators = [
var doc2 = {aliases: ['a'], area: 'api'}; (alias, originatingDoc, docs) => docs.filter(doc => doc.name.indexOf('X') !== -1), // only if X appears in name
var doc3 = {aliases: ['a'], area: 'other'}; (alias, originatingDoc, docs) => docs.filter(doc => doc.name.indexOf('Y') !== -1) // only if Y appears in name
];
var doc1 = {name: 'X', aliases: ['a', 'b', 'c']};
var doc2 = {name: 'Y', aliases: ['a', 'b']};
var doc3 = {name: 'XY', aliases: ['a', 'c']};
aliasMap.addDoc(doc1); aliasMap.addDoc(doc1);
aliasMap.addDoc(doc2); aliasMap.addDoc(doc2);
aliasMap.addDoc(doc3); aliasMap.addDoc(doc3);
expect(getDocFromAlias('a', {area: 'api'})).toEqual([doc1, doc2]); // doc1 and doc2 get removed as they don't both have X and Y in name
}); expect(getDocFromAlias('a')).toEqual([doc3]);
// doc2 gets removed as it has no X; then we have only one doc left so second disambiguator never runs
it('should return docs that match the alias and originating doc\'s area and module', function() { expect(getDocFromAlias('b')).toEqual([doc1]);
var doc1 = {aliases: ['a'], area: 'api', module: 'ng'}; // doc1 gets removed as it has no Y; then we have only one doc left (which would anyway pass 2nd disambiguator)
var doc2 = {aliases: ['a'], area: 'api', module: 'ngMock'}; expect(getDocFromAlias('c')).toEqual([doc3]);
var doc3 = {aliases: ['a'], area: 'other', module: 'ng'};
aliasMap.addDoc(doc1);
aliasMap.addDoc(doc2);
aliasMap.addDoc(doc3);
expect(getDocFromAlias('a', {area: 'api', module: 'ng'})).toEqual([doc1]);
}); });
}); });

View File

@ -10,14 +10,9 @@ var path = require('canonical-path');
* @return {Object} The link information * @return {Object} The link information
* *
* @property {boolean} relativeLinks Whether we expect the links to be relative to the originating doc * @property {boolean} relativeLinks Whether we expect the links to be relative to the originating doc
* @property {array<function(url, title, currentDoc, ambiguousDocs) : array} disambiguators a collection of functions
* that attempt to resolve ambiguous links. Each disambiguator returns a new collection of docs with
* unwanted ambiguous docs removed (see moduleScopeLinkDisambiguator service for an example).
*/ */
module.exports = function getLinkInfo(getDocFromAlias, encodeCodeBlock, log) { module.exports = function getLinkInfo(getDocFromAlias, encodeCodeBlock, log) {
getLinkInfoImpl.disambiguators = [];
return getLinkInfoImpl; return getLinkInfoImpl;
function getLinkInfoImpl(url, title, currentDoc) { function getLinkInfoImpl(url, title, currentDoc) {
@ -29,11 +24,6 @@ module.exports = function getLinkInfo(getDocFromAlias, encodeCodeBlock, log) {
var docs = getDocFromAlias(url, currentDoc); var docs = getDocFromAlias(url, currentDoc);
// Give each disambiguator a chance to reduce the number of ambiguous docs
docs = getLinkInfoImpl.disambiguators.reduce(function(docs, disambiguator) {
return disambiguator(url, title, currentDoc, docs);
}, docs);
if (!getLinkInfoImpl.useFirstAmbiguousLink && docs.length > 1) { if (!getLinkInfoImpl.useFirstAmbiguousLink && docs.length > 1) {
linkInfo.valid = false; linkInfo.valid = false;
linkInfo.errorType = 'ambiguous'; linkInfo.errorType = 'ambiguous';
@ -80,5 +70,4 @@ module.exports = function getLinkInfo(getDocFromAlias, encodeCodeBlock, log) {
return linkInfo; return linkInfo;
} }
}; };

View File

@ -1,15 +0,0 @@
var _ = require('lodash');
module.exports = function moduleScopeLinkDisambiguator() {
return function(url, title, currentDoc, docs) {
if (docs.length > 1) {
// filter out target docs that are not in the same module as the source doc
var filteredDocs =
_.filter(docs, function(doc) { return doc.moduleDoc === currentDoc.moduleDoc; });
// if all target docs are in a different module then just return the full collection of
// ambiguous docs
return filteredDocs.length > 0 ? filteredDocs : docs;
}
return docs;
};
};