From d8c828c9b1b671a2e9a90145d53f5a230afc6a08 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Fri, 22 Jun 2018 16:58:29 +0100 Subject: [PATCH] build(docs-infra): implement the 'package' API template (#24631) PR Close #24631 --- .../api/api-list.component.html | 2 +- .../api/api-list.component.spec.ts | 2 + .../custom-elements/api/api.service.spec.ts | 8 +- .../app/custom-elements/api/api.service.ts | 1 + aio/src/styles/0-base/_typography.scss | 8 +- aio/src/styles/1-layouts/_api-pages.scss | 1 + aio/src/styles/2-modules/_api-pages.scss | 2 +- aio/src/styles/_constants.scss | 2 +- .../transforms/angular-api-package/index.js | 18 +- .../processors/addMetadataAliases.spec.js | 2 +- .../processors/computeApiBreadCrumbs.spec.js | 4 +- .../processors/computeSearchTitle.js | 2 +- .../processors/computeSearchTitle.spec.js | 4 +- .../processors/generateApiListDoc.js | 15 +- .../processors/generateApiListDoc.spec.js | 26 +-- .../processors/processPackages.js | 63 ++++++ .../processors/processPackages.spec.js | 180 ++++++++++++++++++ .../readers/package-content.js | 25 +++ .../processors/createOverviewDump.js | 2 +- .../templates/api/lib/githubLinks.html | 6 +- .../templates/api/module.template.html | 16 -- .../templates/api/package.template.html | 40 ++++ packages/animations/PACKAGE.md | 29 +++ 23 files changed, 399 insertions(+), 59 deletions(-) create mode 100644 aio/tools/transforms/angular-api-package/processors/processPackages.js create mode 100644 aio/tools/transforms/angular-api-package/processors/processPackages.spec.js create mode 100644 aio/tools/transforms/angular-api-package/readers/package-content.js delete mode 100644 aio/tools/transforms/templates/api/module.template.html create mode 100644 aio/tools/transforms/templates/api/package.template.html create mode 100644 packages/animations/PACKAGE.md diff --git a/aio/src/app/custom-elements/api/api-list.component.html b/aio/src/app/custom-elements/api/api-list.component.html index 893947fcaf..aa65d70291 100644 --- a/aio/src/app/custom-elements/api/api-list.component.html +++ b/aio/src/app/custom-elements/api/api-list.component.html @@ -21,7 +21,7 @@
-

{{section.title}}

+

{{section.title}}

  • diff --git a/aio/src/app/custom-elements/api/api-list.component.spec.ts b/aio/src/app/custom-elements/api/api-list.component.spec.ts index 9c4c3d2ad4..035a07f134 100644 --- a/aio/src/app/custom-elements/api/api-list.component.spec.ts +++ b/aio/src/app/custom-elements/api/api-list.component.spec.ts @@ -218,6 +218,7 @@ const apiSections: ApiSection[] = [ { "name": "common", "title": "common", + "path": "api/common", "items": [ { "name": "class_1", @@ -256,6 +257,7 @@ const apiSections: ApiSection[] = [ { "name": "core", "title": "core", + "path": "api/core", "items": [ { "name": "class_3", diff --git a/aio/src/app/custom-elements/api/api.service.spec.ts b/aio/src/app/custom-elements/api/api.service.spec.ts index c5ae75c6a8..253acd57de 100644 --- a/aio/src/app/custom-elements/api/api.service.spec.ts +++ b/aio/src/app/custom-elements/api/api.service.spec.ts @@ -50,7 +50,7 @@ describe('ApiService', () => { describe('#sections', () => { it('first subscriber should fetch sections', done => { - const data = [{name: 'a', title: 'A', items: []}, {name: 'b', title: 'B', items: []}]; + const data = [{name: 'a', title: 'A', path: '', items: []}, {name: 'b', title: 'B', path: '', items: []}]; service.sections.subscribe(sections => { expect(sections).toEqual(data); @@ -61,7 +61,7 @@ describe('ApiService', () => { }); it('second subscriber should get previous sections and NOT trigger refetch', done => { - const data = [{name: 'a', title: 'A', items: []}, {name: 'b', title: 'B', items: []}]; + const data = [{name: 'a', title: 'A', path: '', items: []}, {name: 'b', title: 'B', path: '', items: []}]; let subscriptions = 0; service.sections.subscribe(sections => { @@ -91,7 +91,7 @@ describe('ApiService', () => { let call = 0; - let data = [{name: 'a', title: 'A', items: []}, {name: 'b', title: 'B', items: []}]; + let data = [{name: 'a', title: 'A', path: '', items: []}, {name: 'b', title: 'B', path: '', items: []}]; service.sections.subscribe(sections => { // called twice during this test @@ -103,7 +103,7 @@ describe('ApiService', () => { httpMock.expectOne({}).flush(data); // refresh/refetch - data = [{name: 'c', title: 'C', items: []}]; + data = [{name: 'c', title: 'C', path: '', items: []}]; service.fetchSections(); httpMock.expectOne({}).flush(data); diff --git a/aio/src/app/custom-elements/api/api.service.ts b/aio/src/app/custom-elements/api/api.service.ts index 9d42350b2e..c2398e7d91 100644 --- a/aio/src/app/custom-elements/api/api.service.ts +++ b/aio/src/app/custom-elements/api/api.service.ts @@ -19,6 +19,7 @@ export interface ApiItem { } export interface ApiSection { + path: string; name: string; title: string; items: ApiItem[]; diff --git a/aio/src/styles/0-base/_typography.scss b/aio/src/styles/0-base/_typography.scss index 8d0f38f361..b83a0604b0 100755 --- a/aio/src/styles/0-base/_typography.scss +++ b/aio/src/styles/0-base/_typography.scss @@ -28,7 +28,7 @@ h2 { h3 { font-size: 20px; font-weight: 400; - margin: 24px 0px; + margin: 24px 0px 12px; clear: both; } @@ -55,6 +55,10 @@ h6 { } h2, h3, h4, h5, h6 { + a { + font-size: inherit; + } + @media screen and (max-width: 600px) { margin: 8px 0; } @@ -105,7 +109,7 @@ table { border-collapse: collapse; border-radius: 2px; border-spacing: 0; - margin: 0 0 32px 0; + margin: 12px 0 32px; } table tbody th { diff --git a/aio/src/styles/1-layouts/_api-pages.scss b/aio/src/styles/1-layouts/_api-pages.scss index 81e2f548a0..a819b1192f 100644 --- a/aio/src/styles/1-layouts/_api-pages.scss +++ b/aio/src/styles/1-layouts/_api-pages.scss @@ -3,6 +3,7 @@ max-width: 1200px; table { + margin: 12px 0 24px; th { text-transform: none; diff --git a/aio/src/styles/2-modules/_api-pages.scss b/aio/src/styles/2-modules/_api-pages.scss index dcd25bab04..41768a0bd9 100644 --- a/aio/src/styles/2-modules/_api-pages.scss +++ b/aio/src/styles/2-modules/_api-pages.scss @@ -30,7 +30,7 @@ } } - .method-table, .option-table { + .method-table, .option-table, .list-table { th { display: flex; align-items: center; diff --git a/aio/src/styles/_constants.scss b/aio/src/styles/_constants.scss index b46e0815b8..c719602f65 100755 --- a/aio/src/styles/_constants.scss +++ b/aio/src/styles/_constants.scss @@ -105,7 +105,7 @@ $api-symbols: ( content: 'T', background: $light-green-600 ), - module: ( + package: ( content: 'Pk', background: $purple-600 ) diff --git a/aio/tools/transforms/angular-api-package/index.js b/aio/tools/transforms/angular-api-package/index.js index d6838c892f..a40e3f7ed1 100644 --- a/aio/tools/transforms/angular-api-package/index.js +++ b/aio/tools/transforms/angular-api-package/index.js @@ -33,6 +33,7 @@ module.exports = new Package('angular-api', [basePackage, typeScriptPackage]) .processor(require('./processors/simplifyMemberAnchors')) .processor(require('./processors/computeStability')) .processor(require('./processors/removeInjectableConstructors')) + .processor(require('./processors/processPackages')) /** * These are the API doc types that will be rendered to actual files. @@ -40,7 +41,7 @@ module.exports = new Package('angular-api', [basePackage, typeScriptPackage]) * more Angular specific API types, such as decorators and directives. */ .factory(function API_DOC_TYPES_TO_RENDER(EXPORT_DOC_TYPES) { - return EXPORT_DOC_TYPES.concat(['decorator', 'directive', 'pipe', 'module']); + return EXPORT_DOC_TYPES.concat(['decorator', 'directive', 'pipe', 'package']); }) /** @@ -58,8 +59,10 @@ module.exports = new Package('angular-api', [basePackage, typeScriptPackage]) return API_DOC_TYPES_TO_RENDER.concat(API_CONTAINED_DOC_TYPES); }) + .factory(require('./readers/package-content')) + // Where do we get the source files? - .config(function(readTypeScriptModules, readFilesProcessor, collectExamples, tsParser) { + .config(function(readTypeScriptModules, readFilesProcessor, collectExamples, tsParser, packageContentFileReader) { // Tell TypeScript how to load modules that start with with `@angular` tsParser.options.paths = { '@angular/*': [API_SOURCE_PATH + '/*'] }; @@ -102,12 +105,19 @@ module.exports = new Package('angular-api', [basePackage, typeScriptPackage]) 'upgrade/static/index.ts', ]; + readFilesProcessor.fileReaders.push(packageContentFileReader); + // API Examples readFilesProcessor.sourceFiles = [ { basePath: API_SOURCE_PATH, include: API_SOURCE_PATH + '/examples/**/*', fileReader: 'exampleFileReader' + }, + { + basePath: API_SOURCE_PATH, + include: API_SOURCE_PATH + '/**/PACKAGE.md', + fileReader: 'packageContentFileReader' } ]; collectExamples.exampleFolders.push('examples'); @@ -123,7 +133,7 @@ module.exports = new Package('angular-api', [basePackage, typeScriptPackage]) .config(function(computeStability, splitDescription, addNotYetDocumentedProperty, API_DOC_TYPES_TO_RENDER, API_DOC_TYPES) { computeStability.docTypes = API_DOC_TYPES_TO_RENDER; // Only split the description on the API docs - splitDescription.docTypes = API_DOC_TYPES; + splitDescription.docTypes = API_DOC_TYPES.concat(['package-content']); addNotYetDocumentedProperty.docTypes = API_DOC_TYPES; }) @@ -180,7 +190,7 @@ module.exports = new Package('angular-api', [basePackage, typeScriptPackage]) generateApiListDoc.outputFolder = API_SEGMENT; computePathsProcessor.pathTemplates.push({ - docTypes: ['module'], + docTypes: ['package'], getPath: function computeModulePath(doc) { doc.moduleFolder = `${API_SEGMENT}/${doc.id.replace(/\/index$/, '')}`; return doc.moduleFolder; diff --git a/aio/tools/transforms/angular-api-package/processors/addMetadataAliases.spec.js b/aio/tools/transforms/angular-api-package/processors/addMetadataAliases.spec.js index 154f935fe7..33faa8ae73 100644 --- a/aio/tools/transforms/angular-api-package/processors/addMetadataAliases.spec.js +++ b/aio/tools/transforms/angular-api-package/processors/addMetadataAliases.spec.js @@ -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'] }, diff --git a/aio/tools/transforms/angular-api-package/processors/computeApiBreadCrumbs.spec.js b/aio/tools/transforms/angular-api-package/processors/computeApiBreadCrumbs.spec.js index 03bc24e426..256d7c44d2 100644 --- a/aio/tools/transforms/angular-api-package/processors/computeApiBreadCrumbs.spec.js +++ b/aio/tools/transforms/angular-api-package/processors/computeApiBreadCrumbs.spec.js @@ -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); diff --git a/aio/tools/transforms/angular-api-package/processors/computeSearchTitle.js b/aio/tools/transforms/angular-api-package/processors/computeSearchTitle.js index 6ea06a0229..295a2839fa 100644 --- a/aio/tools/transforms/angular-api-package/processors/computeSearchTitle.js +++ b/aio/tools/transforms/angular-api-package/processors/computeSearchTitle.js @@ -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; } diff --git a/aio/tools/transforms/angular-api-package/processors/computeSearchTitle.spec.js b/aio/tools/transforms/angular-api-package/processors/computeSearchTitle.spec.js index d90b707b50..61b205d956 100644 --- a/aio/tools/transforms/angular-api-package/processors/computeSearchTitle.spec.js +++ b/aio/tools/transforms/angular-api-package/processors/computeSearchTitle.spec.js @@ -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(); diff --git a/aio/tools/transforms/angular-api-package/processors/generateApiListDoc.js b/aio/tools/transforms/angular-api-package/processors/generateApiListDoc.js index b36b446904..4a8fd31a11 100644 --- a/aio/tools/transforms/angular-api-package/processors/generateApiListDoc.js +++ b/aio/tools/transforms/angular-api-package/processors/generateApiListDoc.js @@ -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) diff --git a/aio/tools/transforms/angular-api-package/processors/generateApiListDoc.spec.js b/aio/tools/transforms/angular-api-package/processors/generateApiListDoc.spec.js index 35d9ad000c..14eda0482f 100644 --- a/aio/tools/transforms/angular-api-package/processors/generateApiListDoc.spec.js +++ b/aio/tools/transforms/angular-api-package/processors/generateApiListDoc.spec.js @@ -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' }, diff --git a/aio/tools/transforms/angular-api-package/processors/processPackages.js b/aio/tools/transforms/angular-api-package/processors/processPackages.js new file mode 100644 index 0000000000..3d9fc3f202 --- /dev/null +++ b/aio/tools/transforms/angular-api-package/processors/processPackages.js @@ -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; + } + }; +}; diff --git a/aio/tools/transforms/angular-api-package/processors/processPackages.spec.js b/aio/tools/transforms/angular-api-package/processors/processPackages.spec.js new file mode 100644 index 0000000000..3692ab1b4c --- /dev/null +++ b/aio/tools/transforms/angular-api-package/processors/processPackages.spec.js @@ -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' }, + ]); + }); +}); diff --git a/aio/tools/transforms/angular-api-package/readers/package-content.js b/aio/tools/transforms/angular-api-package/readers/package-content.js new file mode 100644 index 0000000000..941b9c74e7 --- /dev/null +++ b/aio/tools/transforms/angular-api-package/readers/package-content.js @@ -0,0 +1,25 @@ +/** + * @dgService + * @description + * This file reader will pull the contents from a text file that will be used + * as the description of a package. + * + * The doc will initially have the form: + * ``` + * { + * content: 'the content of the file', + * startingLine: 1 + * } + * ``` + */ +module.exports = function packageContentFileReader() { + return { + name: 'packageContentFileReader', + defaultPattern: /PACKAGE\.md$/, + getDocs: function(fileInfo) { + + // We return a single element array because content files only contain one document + return [{docType: 'package-content', content: fileInfo.content, startingLine: 1}]; + } + }; +}; \ No newline at end of file diff --git a/aio/tools/transforms/angular.io-package/processors/createOverviewDump.js b/aio/tools/transforms/angular.io-package/processors/createOverviewDump.js index 6032e94f64..ab590315b0 100644 --- a/aio/tools/transforms/angular.io-package/processors/createOverviewDump.js +++ b/aio/tools/transforms/angular.io-package/processors/createOverviewDump.js @@ -14,7 +14,7 @@ module.exports = function createOverviewDump() { modules: [] }; _.forEach(docs, function(doc) { - if (doc.docType === 'module') { + if (doc.docType === 'package') { overviewDoc.modules.push(doc); } }); diff --git a/aio/tools/transforms/templates/api/lib/githubLinks.html b/aio/tools/transforms/templates/api/lib/githubLinks.html index 349e135b45..f99b37543b 100644 --- a/aio/tools/transforms/templates/api/lib/githubLinks.html +++ b/aio/tools/transforms/templates/api/lib/githubLinks.html @@ -1,12 +1,12 @@ {% macro githubViewHref(doc, versionInfo) -%} -https://github.com/{$ versionInfo.gitRepoInfo.owner $}/{$ versionInfo.gitRepoInfo.repo $}/tree/{$ versionInfo.currentVersion.isSnapshot and versionInfo.currentVersion.SHA or versionInfo.currentVersion.raw $}/packages/{$ doc.fileInfo.realProjectRelativePath $}#L{$ doc.startingLine + 1 $}-L{$ doc.endingLine + 1 $} +https://github.com/{$ versionInfo.gitRepoInfo.owner $}/{$ versionInfo.gitRepoInfo.repo $}/tree/{$ versionInfo.currentVersion.isSnapshot and versionInfo.currentVersion.SHA or versionInfo.currentVersion.raw $}/packages/{$ doc.fileInfo.realProjectRelativePath or doc.fileInfo.relativePath $}#L{$ doc.startingLine + 1 $}-L{$ doc.endingLine + 1 $} {%- endmacro -%} {% macro githubEditHref(doc, versionInfo) -%} -https://github.com/{$ versionInfo.gitRepoInfo.owner $}/{$ versionInfo.gitRepoInfo.repo $}/edit/master/packages/{$ doc.fileInfo.realProjectRelativePath $}?message=docs( +https://github.com/{$ versionInfo.gitRepoInfo.owner $}/{$ versionInfo.gitRepoInfo.repo $}/edit/master/packages/{$ doc.fileInfo.realProjectRelativePath or doc.fileInfo.relativePath $}?message=docs( {%- if doc.moduleDoc %}{$ doc.moduleDoc.id.split('/')[0] $} - {%- elseif doc.docType === 'module' %}{$ doc.id.split('/')[0] $} + {%- elseif doc.docType === 'package' %}{$ doc.id.split('/')[0] $} {%- else %}...{%- endif -%} )%3A%20describe%20your%20change...#L{$ doc.startingLine + 1 $}-L{$ doc.endingLine + 1 $} {%- endmacro -%} diff --git a/aio/tools/transforms/templates/api/module.template.html b/aio/tools/transforms/templates/api/module.template.html deleted file mode 100644 index 0704998b13..0000000000 --- a/aio/tools/transforms/templates/api/module.template.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends 'base.template.html' -%} - -{% block body -%} - -{% include "includes/deprecation.html" %} -{% include "includes/description.html" %} - -
    - -
    - -{%- endblock %} diff --git a/aio/tools/transforms/templates/api/package.template.html b/aio/tools/transforms/templates/api/package.template.html new file mode 100644 index 0000000000..3583ee6a0b --- /dev/null +++ b/aio/tools/transforms/templates/api/package.template.html @@ -0,0 +1,40 @@ +{% extends 'base.template.html' -%} + +{% macro listItems(items, title) %} + {% if items.length %} +
    +

    {$ title $}

    + + {% for item in items %} + + + + + {% endfor %} +
    + {$ item.name $}{% if item.shortDescription %}{$ item.shortDescription | marked $}{% endif %}
    +
    + {% endif %} +{% endmacro %} + +{% block body -%} + {% include "includes/deprecation.html" %} + {$ doc.shortDescription | marked $} + {% if doc.description %}{$ doc.description | marked $}{% endif %} + + {% include "includes/see-also.html" %} + +

    Entry points

    + {$ listItems([doc.packageInfo.primary], 'Primary') $} + {$ listItems(doc.packageInfo.secondary, 'Secondary') $} + + +

    Exports

    + {$ listItems(doc.classes, 'Classes') $} + {$ listItems(doc.decorators, 'Decorators') $} + {$ listItems(doc.functions, 'Functions') $} + {$ listItems(doc.structures, 'Structures') $} + {$ listItems(doc.directives, 'Directives') $} + {$ listItems(doc.pipes, 'Pipes') $} + {$ listItems(doc.types, 'Types') $} +{%- endblock %} diff --git a/packages/animations/PACKAGE.md b/packages/animations/PACKAGE.md new file mode 100644 index 0000000000..412b03243b --- /dev/null +++ b/packages/animations/PACKAGE.md @@ -0,0 +1,29 @@ +Implements a domain-specific language (DSL) for defining web animation sequences for HTML elements as +multiple transformations over time. + +Use this API to define how an HTML element can move, change color, grow or shrink, fade, or slide off +the page. These changes can occur simultaneously or sequentially. You can control the timing of each +of these transformations. The function calls generate the data structures and metadata that enable Angular +to integrate animations into templates and run them based on application states. + +Animation definitions are linked to components through the `{@link Component.animations animations}` +property in the `@Component` metadata, typically in the component file of the HTML element to be animated. +The `trigger()` function encapsulates a named animation, with all other function calls nested within. Use +the trigger name to bind the named animation to a specific triggering element in the HTML template. + +Angular animations are based on CSS web transition functionality, so anything that can be styled or +transformed in CSS can be animated the same way in Angular. Angular animations allow you to: + +* Set animation timings, styles, keyframes, and transitions. +* Animate HTML elements in complex sequences and choreographies. +* Animate HTML elements as they are inserted and removed from the DOM, including responsive real-time + filtering. +* Create reusable animations. +* Animate parent and child elements. + +Additional animation functionality is provided in other Angular modules for animation testing, for +route-based animations, and for programmatic animation controls that allow an end user to fast forward +and reverse an animation sequence. + +@see Find out more in the [animations guide](guide/animations). +@see See what polyfills you might need in the [browser support guide](guide/browser-support).