build(docs-infra): implement the 'package' API template (#24631)
PR Close #24631
This commit is contained in:

committed by
Matias Niemelä

parent
97277bc9fb
commit
d8c828c9b1
@ -33,7 +33,7 @@ describe('addSelectorsAsAliases processor', () => {
|
||||
{ docType: 'directive', name: 'NgModel', aliases: ['NgModel'], directiveOptions: { selector: '\'[ngModel]:not([formControlName]):not([formControl])\'' } },
|
||||
{ docType: 'component', name: 'MyComponent', aliases: ['MyComponent'], componentOptions: { selector: '\'my-component\'' } },
|
||||
{ docType: 'decorator', name: 'MyDecorator', aliases: ['MyDecorator'] },
|
||||
{ docType: 'module', name: 'myModule', aliases: ['myModule'], id: 'some/myModule' },
|
||||
{ docType: 'package', name: 'myPackage', aliases: ['myPackage'], id: 'some/myPackage' },
|
||||
{ docType: 'var', name: 'myVar', aliases: ['myVar'] },
|
||||
{ docType: 'let', name: 'myLet', aliases: ['myLet'] },
|
||||
{ docType: 'const', name: 'myConst', aliases: ['myConst'] },
|
||||
|
@ -14,14 +14,14 @@ describe('angular-api-package: computeApiBreadCrumbs processor', () => {
|
||||
});
|
||||
|
||||
it('should attach a breadCrumbs property to each of the API_DOC_TYPES_TO_RENDER docs', () => {
|
||||
const API_DOC_TYPES_TO_RENDER = ['class', 'interface', 'module'];
|
||||
const API_DOC_TYPES_TO_RENDER = ['class', 'interface', 'package'];
|
||||
const processor = processorFactory(API_DOC_TYPES_TO_RENDER);
|
||||
|
||||
const docs = [
|
||||
{ docType: 'class', name: 'ClassA', path: 'module-1/class-a', moduleDoc: { id: 'moduleOne', path: 'module-1' } },
|
||||
{ docType: 'interface', name: 'InterfaceB', path: 'module-2/interface-b', moduleDoc: { id: 'moduleTwo', path: 'module-2' } },
|
||||
{ docType: 'guide', name: 'Guide One', path: 'guide/guide-1' },
|
||||
{ docType: 'module', name: 'testing', id: 'http/testing', path: 'http/testing' },
|
||||
{ docType: 'package', name: 'testing', id: 'http/testing', path: 'http/testing' },
|
||||
];
|
||||
processor.$process(docs);
|
||||
|
||||
|
@ -8,7 +8,7 @@ module.exports = function computeSearchTitleProcessor() {
|
||||
case 'function':
|
||||
doc.searchTitle = `${doc.name}()`;
|
||||
break;
|
||||
case 'module':
|
||||
case 'package':
|
||||
doc.searchTitle = `${doc.id} package`;
|
||||
break;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ describe('computeSearchTitle processor', () => {
|
||||
{ docType: 'pipe', name: 'MyPipe', pipeOptions: { name: 'myPipe' } },
|
||||
{ docType: 'directive', name: 'MyDirective', directiveOptions: {} },
|
||||
{ docType: 'decorator', name: 'MyDecorator' },
|
||||
{ docType: 'module', name: 'myModule', id: 'some/myModule' },
|
||||
{ docType: 'package', name: 'myPackage', id: 'some/myPackage' },
|
||||
{ docType: 'var', name: 'myVar' },
|
||||
{ docType: 'let', name: 'myLet' },
|
||||
{ docType: 'const', name: 'myConst' },
|
||||
@ -45,7 +45,7 @@ describe('computeSearchTitle processor', () => {
|
||||
expect(docs[4].searchTitle).toBeUndefined();
|
||||
expect(docs[5].searchTitle).toBeUndefined();
|
||||
expect(docs[6].searchTitle).toBeUndefined();
|
||||
expect(docs[7].searchTitle).toEqual('some/myModule package');
|
||||
expect(docs[7].searchTitle).toEqual('some/myPackage package');
|
||||
expect(docs[8].searchTitle).toBeUndefined();
|
||||
expect(docs[9].searchTitle).toBeUndefined();
|
||||
expect(docs[10].searchTitle).toBeUndefined();
|
||||
|
@ -12,19 +12,20 @@ module.exports = function generateApiListDoc() {
|
||||
path: this.outputFolder + '/api-list.json',
|
||||
outputPath: this.outputFolder + '/api-list.json',
|
||||
data: docs
|
||||
.filter(doc => doc.docType === 'module')
|
||||
.map(getModuleInfo)
|
||||
.filter(doc => doc.docType === 'package')
|
||||
.map(getPackageInfo)
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function getModuleInfo(moduleDoc) {
|
||||
const moduleName = moduleDoc.id.replace(/\/index$/, '');
|
||||
function getPackageInfo(packageDoc) {
|
||||
const packageName = packageDoc.id.replace(/\/index$/, '');
|
||||
return {
|
||||
name: moduleName.toLowerCase(),
|
||||
title: moduleName,
|
||||
items: moduleDoc.exports
|
||||
name: packageName.toLowerCase(),
|
||||
title: packageName,
|
||||
path: packageDoc.path,
|
||||
items: packageDoc.exports
|
||||
// Ignore internals and private exports (indicated by the ɵ prefix)
|
||||
.filter(doc => !doc.internal && !doc.privateExport)
|
||||
.map(getExportInfo)
|
||||
|
@ -38,28 +38,28 @@ describe('generateApiListDoc processor', () => {
|
||||
it('should add an info object to the doc for each module doc', () => {
|
||||
const processor = processorFactory();
|
||||
const docs = [
|
||||
{ docType: 'module', id: '@angular/common/index', exports: [] },
|
||||
{ docType: 'module', id: '@angular/core/index', exports: [] },
|
||||
{ docType: 'module', id: '@angular/http/index', exports: [] },
|
||||
{ docType: 'package', id: '@angular/common/index', exports: [], path: 'common' },
|
||||
{ docType: 'package', id: '@angular/core/index', exports: [], path: 'core' },
|
||||
{ docType: 'package', id: '@angular/http/index', exports: [], path: 'http' },
|
||||
];
|
||||
processor.$process(docs);
|
||||
expect(docs[3].data).toEqual([
|
||||
{ name: '@angular/common', title: '@angular/common', items: [] },
|
||||
{ name: '@angular/core', title: '@angular/core', items: [] },
|
||||
{ name: '@angular/http', title: '@angular/http', items: [] },
|
||||
{ name: '@angular/common', title: '@angular/common', items: [], path: 'common' },
|
||||
{ name: '@angular/core', title: '@angular/core', items: [], path: 'core' },
|
||||
{ name: '@angular/http', title: '@angular/http', items: [], path: 'http' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should add info about each export on each module', () => {
|
||||
const processor = processorFactory();
|
||||
const docs = [
|
||||
{ docType: 'module', id: '@angular/common/index', exports: [
|
||||
{ docType: 'package', id: '@angular/common/index', exports: [
|
||||
{ docType: 'directive', name: 'AaaAaa', path: 'aaa' },
|
||||
{ docType: 'pipe', name: 'BbbBbb', path: 'bbb' },
|
||||
{ docType: 'decorator', name: 'CccCcc', path: 'ccc' },
|
||||
{ docType: 'class', name: 'DddDdd', path: 'ddd' }
|
||||
] },
|
||||
{ docType: 'module', id: '@angular/core/index', exports: [
|
||||
{ docType: 'package', id: '@angular/core/index', exports: [
|
||||
{ docType: 'interface', name: 'EeeEee', path: 'eee' },
|
||||
{ docType: 'function', name: 'FffFff', path: 'fff' },
|
||||
{ docType: 'enum', name: 'GggGgg', path: 'ggg' },
|
||||
@ -86,7 +86,7 @@ describe('generateApiListDoc processor', () => {
|
||||
it('should ignore internal and private exports', () => {
|
||||
const processor = processorFactory();
|
||||
const docs = [
|
||||
{ docType: 'module', id: '@angular/common/index', exports: [
|
||||
{ docType: 'package', id: '@angular/common/index', exports: [
|
||||
{ docType: 'directive', name: 'AaaAaa', path: 'aaa', internal: true },
|
||||
{ docType: 'class', name: 'XxxXxx', path: 'xxx', privateExport: true },
|
||||
{ docType: 'pipe', name: 'BbbBbb', path: 'bbb' }
|
||||
@ -101,7 +101,7 @@ describe('generateApiListDoc processor', () => {
|
||||
it('should convert `let` and `var` docTypes to `const`', () => {
|
||||
const processor = processorFactory();
|
||||
const docs = [
|
||||
{ docType: 'module', id: '@angular/common/index', exports: [
|
||||
{ docType: 'package', id: '@angular/common/index', exports: [
|
||||
{ docType: 'var', name: 'AaaAaa', path: 'aaa' },
|
||||
{ docType: 'let', name: 'BbbBbb', path: 'bbb' },
|
||||
]}
|
||||
@ -116,7 +116,7 @@ describe('generateApiListDoc processor', () => {
|
||||
it('should convert security to a boolean securityRisk', () => {
|
||||
const processor = processorFactory();
|
||||
const docs = [
|
||||
{ docType: 'module', id: '@angular/common/index', exports: [
|
||||
{ docType: 'package', id: '@angular/common/index', exports: [
|
||||
{ docType: 'class', name: 'AaaAaa', path: 'aaa', security: 'This is a security risk' },
|
||||
{ docType: 'class', name: 'BbbBbb', path: 'bbb', security: '' },
|
||||
]}
|
||||
@ -131,7 +131,7 @@ describe('generateApiListDoc processor', () => {
|
||||
it('should convert stability tags to the stable string property', () => {
|
||||
const processor = processorFactory();
|
||||
const docs = [
|
||||
{ docType: 'module', id: '@angular/common/index', exports: [
|
||||
{ docType: 'package', id: '@angular/common/index', exports: [
|
||||
{ docType: 'class', name: 'AaaAaa', path: 'aaa', stable: undefined },
|
||||
{ docType: 'class', name: 'BbbBbb', path: 'bbb', experimental: 'Some message' },
|
||||
{ docType: 'class', name: 'CccCcc', path: 'ccc', deprecated: null },
|
||||
@ -150,7 +150,7 @@ describe('generateApiListDoc processor', () => {
|
||||
it('should sort items in each group alphabetically', () => {
|
||||
const processor = processorFactory();
|
||||
const docs = [
|
||||
{ docType: 'module', id: '@angular/common/index', exports: [
|
||||
{ docType: 'package', id: '@angular/common/index', exports: [
|
||||
{ docType: 'class', name: 'DddDdd', path: 'uuu' },
|
||||
{ docType: 'class', name: 'BbbBbb', path: 'vvv' },
|
||||
{ docType: 'class', name: 'AaaAaa', path: 'xxx' },
|
||||
|
63
aio/tools/transforms/angular-api-package/processors/processPackages.js
vendored
Normal file
63
aio/tools/transforms/angular-api-package/processors/processPackages.js
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
const { dirname } = require('canonical-path');
|
||||
|
||||
module.exports = function processPackages() {
|
||||
return {
|
||||
$runAfter: ['extractDecoratedClassesProcessor'],
|
||||
$runBefore: ['computing-ids'],
|
||||
$process(docs) {
|
||||
const packageContentFiles = {};
|
||||
const packageMap = {};
|
||||
|
||||
docs = docs.filter(doc => {
|
||||
if (doc.docType === 'package-content') {
|
||||
packageContentFiles[dirname(doc.fileInfo.filePath)] = doc;
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
docs.forEach(doc => {
|
||||
if (doc.docType === 'module') {
|
||||
// Convert the doc type from "module" to "package"
|
||||
doc.docType = 'package';
|
||||
// The name is actually the full id
|
||||
doc.name = `@angular/${doc.id}`;
|
||||
|
||||
// Partition the exports into groups by type
|
||||
if (doc.exports) {
|
||||
doc.classes = doc.exports.filter(doc => doc.docType === 'class');
|
||||
doc.decorators = doc.exports.filter(doc => doc.docType === 'decorator');
|
||||
doc.functions = doc.exports.filter(doc => doc.docType === 'function');
|
||||
doc.structures = doc.exports.filter(doc => doc.docType === 'enum' || doc.docType === 'interface');
|
||||
doc.directives = doc.exports.filter(doc => doc.docType === 'directive');
|
||||
doc.pipes = doc.exports.filter(doc => doc.docType === 'pipe');
|
||||
doc.types = doc.exports.filter(doc => doc.docType === 'type-alias' || doc.docType === 'const');
|
||||
}
|
||||
|
||||
// Copy over docs from the PACKAGE.md file that is used to document packages
|
||||
const readmeDoc = packageContentFiles[dirname(doc.fileInfo.filePath)];
|
||||
if (readmeDoc) {
|
||||
doc.shortDescription = readmeDoc.shortDescription;
|
||||
doc.description = readmeDoc.description;
|
||||
doc.see = readmeDoc.see;
|
||||
doc.fileInfo = readmeDoc.fileInfo;
|
||||
}
|
||||
|
||||
// Compute the primary/secondary entry point relationships
|
||||
const packageParts = doc.id.split('/');
|
||||
const primaryPackageName = packageParts[0];
|
||||
doc.isPrimaryPackage = packageParts.length === 1;
|
||||
doc.packageInfo = packageMap[primaryPackageName] = packageMap[primaryPackageName] || { primary: undefined, secondary: [] };
|
||||
if (doc.isPrimaryPackage) {
|
||||
doc.packageInfo.primary = doc;
|
||||
} else {
|
||||
doc.packageInfo.secondary.push(doc);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return docs;
|
||||
}
|
||||
};
|
||||
};
|
@ -0,0 +1,180 @@
|
||||
const testPackage = require('../../helpers/test-package');
|
||||
const processorFactory = require('./processPackages');
|
||||
const Dgeni = require('dgeni');
|
||||
|
||||
describe('processPackages processor', () => {
|
||||
|
||||
it('should be available on the injector', () => {
|
||||
const dgeni = new Dgeni([testPackage('angular-api-package')]);
|
||||
const injector = dgeni.configureInjector();
|
||||
const processor = injector.get('processPackages');
|
||||
expect(processor.$process).toBeDefined();
|
||||
expect(processor.$runAfter).toEqual(['extractDecoratedClassesProcessor']);
|
||||
expect(processor.$runBefore).toEqual(['computing-ids']);
|
||||
});
|
||||
|
||||
it('should filter out any `package-content` docs from the collection', () => {
|
||||
const docs = [
|
||||
{ fileInfo: { filePath: 'some/a' }, docType: 'a', id: 'a' },
|
||||
{ fileInfo: { filePath: 'some/x' }, docType: 'package-content', id: 'x' },
|
||||
{ fileInfo: { filePath: 'some/b' }, docType: 'b', id: 'b' },
|
||||
{ fileInfo: { filePath: 'some/y' }, docType: 'package-content', id: 'y' },
|
||||
{ fileInfo: { filePath: 'some/z' }, docType: 'package-content', id: 'z' },
|
||||
];
|
||||
const processor = processorFactory();
|
||||
const newDocs = processor.$process(docs);
|
||||
expect(newDocs).toEqual([
|
||||
{ fileInfo: { filePath: 'some/a' }, docType: 'a', id: 'a' },
|
||||
{ fileInfo: { filePath: 'some/b' }, docType: 'b', id: 'b' },
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
it('should change `module` docs to `package` docs', () => {
|
||||
const processor = processorFactory();
|
||||
const docs = [
|
||||
{ fileInfo: { filePath: 'some/a' }, docType: 'module', id: 'a' },
|
||||
{ fileInfo: { filePath: 'some/b' }, docType: 'module', id: 'b' },
|
||||
{ docType: 'other', id: 'c' },
|
||||
];
|
||||
const newDocs = processor.$process(docs);
|
||||
expect(newDocs).toEqual([
|
||||
jasmine.objectContaining({ docType: 'package', id: 'a' }),
|
||||
jasmine.objectContaining({ docType: 'package', id: 'b' }),
|
||||
jasmine.objectContaining({ docType: 'other', id: 'c' }),
|
||||
]);
|
||||
});
|
||||
|
||||
it('should attach the relevant package contents to the package doc', () => {
|
||||
const docs = [
|
||||
{
|
||||
fileInfo: { filePath: 'some/package-1/index' },
|
||||
docType: 'module',
|
||||
id: 'package-1',
|
||||
someProp: 'foo',
|
||||
},
|
||||
{
|
||||
fileInfo: { filePath: 'some/package-1/PACKAGE.md' },
|
||||
docType: 'package-content',
|
||||
id: 'package-1/PACKAGE.md',
|
||||
shortDescription: 'some short description',
|
||||
description: 'some description',
|
||||
see: [ 'a', 'b' ],
|
||||
},
|
||||
{
|
||||
fileInfo: { filePath: 'some/package-2/index' },
|
||||
docType: 'module',
|
||||
id: 'package-2',
|
||||
},
|
||||
];
|
||||
const processor = processorFactory();
|
||||
const newDocs = processor.$process(docs);
|
||||
|
||||
const package1 = jasmine.objectContaining({
|
||||
fileInfo: { filePath: 'some/package-1/PACKAGE.md' },
|
||||
docType: 'package',
|
||||
name: '@angular/package-1',
|
||||
id: 'package-1',
|
||||
someProp: 'foo',
|
||||
shortDescription: 'some short description',
|
||||
description: 'some description',
|
||||
see: [ 'a', 'b' ],
|
||||
isPrimaryPackage: true,
|
||||
});
|
||||
|
||||
const package2 = jasmine.objectContaining({
|
||||
fileInfo: { filePath: 'some/package-2/index' },
|
||||
docType: 'package',
|
||||
name: '@angular/package-2',
|
||||
id: 'package-2',
|
||||
isPrimaryPackage: true,
|
||||
});
|
||||
|
||||
expect(newDocs).toEqual([package1, package2]);
|
||||
});
|
||||
|
||||
it('should compute primary and second package info', () => {
|
||||
const docs = [
|
||||
{
|
||||
fileInfo: { filePath: 'some/package-1/index' },
|
||||
docType: 'module',
|
||||
id: 'package-1',
|
||||
},
|
||||
{
|
||||
fileInfo: { filePath: 'some/package-1/sub-1index' },
|
||||
docType: 'module',
|
||||
id: 'package-1/sub-1',
|
||||
},
|
||||
{
|
||||
fileInfo: { filePath: 'some/package-1/sub-2index' },
|
||||
docType: 'module',
|
||||
id: 'package-1/sub-2',
|
||||
},
|
||||
];
|
||||
const processor = processorFactory();
|
||||
const newDocs = processor.$process(docs);
|
||||
|
||||
expect(newDocs[0].isPrimaryPackage).toBe(true);
|
||||
expect(newDocs[1].isPrimaryPackage).toBe(false);
|
||||
expect(newDocs[2].isPrimaryPackage).toBe(false);
|
||||
|
||||
expect(newDocs[0].packageInfo.primary).toBe(newDocs[0]);
|
||||
expect(newDocs[1].packageInfo.primary).toBe(newDocs[0]);
|
||||
expect(newDocs[2].packageInfo.primary).toBe(newDocs[0]);
|
||||
|
||||
expect(newDocs[0].packageInfo.secondary).toEqual([newDocs[1], newDocs[2]]);
|
||||
expect(newDocs[1].packageInfo.secondary).toEqual([newDocs[1], newDocs[2]]);
|
||||
expect(newDocs[2].packageInfo.secondary).toEqual([newDocs[1], newDocs[2]]);
|
||||
});
|
||||
|
||||
it('should partition the exports of packages into groups', () => {
|
||||
const docs = [
|
||||
{
|
||||
fileInfo: { filePath: 'some/x' },
|
||||
docType: 'module',
|
||||
id: 'x',
|
||||
exports: [
|
||||
{ docType: 'directive', id: 'directive-1' },
|
||||
{ docType: 'function', id: 'function-1' },
|
||||
{ docType: 'directive', id: 'directive-2' },
|
||||
{ docType: 'decorator', id: 'decorator-1' },
|
||||
{ docType: 'class', id: 'class-1' },
|
||||
{ docType: 'type-alias', id: 'type-alias-1' },
|
||||
{ docType: 'class', id: 'class-2' },
|
||||
{ docType: 'pipe', id: 'pipe-1' },
|
||||
{ docType: 'const', id: 'const-1' },
|
||||
{ docType: 'const', id: 'const-2' },
|
||||
{ docType: 'enum', id: 'enum-1' },
|
||||
{ docType: 'interface', id: 'interface-1' },
|
||||
{ docType: 'interface', id: 'interface-2' },
|
||||
]
|
||||
},
|
||||
];
|
||||
const processor = processorFactory();
|
||||
const newDocs = processor.$process(docs);
|
||||
|
||||
expect(newDocs[0].decorators).toEqual([
|
||||
{ docType: 'decorator', id: 'decorator-1' },
|
||||
]);
|
||||
expect(newDocs[0].functions).toEqual([
|
||||
{ docType: 'function', id: 'function-1' },
|
||||
]);
|
||||
expect(newDocs[0].structures).toEqual([
|
||||
{ docType: 'enum', id: 'enum-1' },
|
||||
{ docType: 'interface', id: 'interface-1' },
|
||||
{ docType: 'interface', id: 'interface-2' },
|
||||
]);
|
||||
expect(newDocs[0].directives).toEqual([
|
||||
{ docType: 'directive', id: 'directive-1' },
|
||||
{ docType: 'directive', id: 'directive-2' },
|
||||
]);
|
||||
expect(newDocs[0].pipes).toEqual([
|
||||
{ docType: 'pipe', id: 'pipe-1' },
|
||||
]);
|
||||
expect(newDocs[0].types).toEqual([
|
||||
{ docType: 'type-alias', id: 'type-alias-1' },
|
||||
{ docType: 'const', id: 'const-1' },
|
||||
{ docType: 'const', id: 'const-2' },
|
||||
]);
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user