diff --git a/aio/content/guide/api-page-class.md b/aio/content/guide/api-page-class.md new file mode 100644 index 0000000000..989bd0f327 --- /dev/null +++ b/aio/content/guide/api-page-class.md @@ -0,0 +1,175 @@ + +
+

Class Name

+
+
+ + +
+

Class description goes here. This is a short and to the point one or two sentence description that easily introduces the reader to the class.

+
+
+

Overview

+
+        class Compiler {
+    compileModuleSync<T>(moduleType: Type<T>): NgModuleFactory<T>
+    compileModuleAsync<T>(moduleType: Type<T>): Promise<NgModuleFactory<T>>
+    compileModuleAndAllComponentsSync<T>(moduleType: Type<T>): ModuleWithComponentFactories<T>
+    compileModuleAndAllComponentsAsync<T>(moduleType: Type<T>): Promise<ModuleWithComponentFactories<T>>
+    clearCache(): void
+    clearCacheFor(type: Type<any>)
+    }
+        
+
+
+

Description

+

The longer class description goes here which can include multiple paragraphs.

+

Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham.

+

Subclasses

+ +

See Also

+ +
+
+

Constructor

+ +
   
+        constructor(element: any, keyframes: {
+        [key: string]: string | number;
+    }[], duration: number, delay: number, easing: string, previousPlayers: any[])
+        
+
+
+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
+ Property1 + Description goes here
+ Property2 + TypeDescription goes here
+ Property3 + TypeDescription goes here
+
+
+

Methods

+ + + + + + + + + + + +
Method1Name( )
+

Description goes here

+
+

Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham.

+
+ + + + + + + + + + + +
Method2Name( )
+

Description goes here

+
+
Declaration
+ +
+                    class AnimationBuilder {build(animation: AnimationMetadata | AnimationMetadata[]): AnimationFactory}
+
+
+
Parameters
+
Returns
+

Returns information and results goes here.

+
Errors
+

Error information goes here

+
+

Further details provided as needed. Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball.


+
Overloads
+ + + + + + + + + + + +
+ +
   
+        constructor(element: any, keyframes: {
+        [key: string]: string | number;
+    }[], duration: number, delay: number, easing: string, previousPlayers: any[])
+        
+
Description goes here
+ +
   
+        constructor(element: any, keyframes: {
+        [key: string]: string | number;
+    }[], duration: number, delay: number, easing: string, previousPlayers: any[])
+        
+
Description goes here
+
+
Example: Descriptive Title of Method Example
+

Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham.

+
+
+
+

Example: Descriptive Title of Combined Example Goes Here

+

Intro description text about what the example is and how it can be used.

+ +
   
+        constructor(element: any, keyframes: {
+        [key: string]: string | number;
+    }[], duration: number, delay: number, easing: string, previousPlayers: any[])
+        
+

Further explanation provided as needed. Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball.

+
+
\ No newline at end of file diff --git a/aio/package.json b/aio/package.json index e7f1a02e78..855821ef5a 100644 --- a/aio/package.json +++ b/aio/package.json @@ -107,7 +107,7 @@ "cross-spawn": "^5.1.0", "css-selector-parser": "^1.3.0", "dgeni": "^0.4.7", - "dgeni-packages": "^0.24.0", + "dgeni-packages": "0.24.1", "entities": "^1.1.1", "eslint": "^3.19.0", "eslint-plugin-jasmine": "^2.2.0", diff --git a/aio/src/styles/0-base/_typography.scss b/aio/src/styles/0-base/_typography.scss index fdc110c0a0..764b67e154 100755 --- a/aio/src/styles/0-base/_typography.scss +++ b/aio/src/styles/0-base/_typography.scss @@ -143,13 +143,13 @@ th { text-align: left; } -p > code, li > code, table code { +p > code, li > code, td > code, th > code { font-family: $code-font; font-size: 85%; color: $darkgray; letter-spacing: 0; line-height: 1; - padding: 2px 6px; + padding: 2px 0; background-color: $backgroundgray; border-radius: 4px; } diff --git a/aio/src/styles/1-layouts/_api-page.scss b/aio/src/styles/1-layouts/_api-page.scss index 26cc1585ee..aa5e714c69 100644 --- a/aio/src/styles/1-layouts/_api-page.scss +++ b/aio/src/styles/1-layouts/_api-page.scss @@ -16,7 +16,7 @@ text-transform: none; padding: 8px 24px; } - + tbody { pre { white-space: normal; @@ -36,34 +36,44 @@ } } +.api-body { -.api-header label { - border-radius: 4px; - padding: 4px 16px; - display: inline; - font-size: 14px; - color: white; - margin: 0 8px 0 16px; - font-weight: 500; - text-transform: uppercase; - - @media screen and (max-width: 600px) { - display: block; - margin: 8px 0; - } + max-width: 1200px; - &.api-status-label { - background-color: $mediumgray; - } + table { - &.api-type-label { - background-color: $accentblue; + th { + text-transform: none; + font-size: 16px; + font-weight: bold; + } - @each $name, $symbol in $api-symbols { - &.#{$name} { - background: map-get($symbol, background); + tr { + border-bottom: 1px solid $lightgray; + } + + td { + vertical-align: middle; + } + + hr { + margin: 16px 0; + } + + tr:last-child { + border-bottom: none; + } + + &.item-table { + td { + padding: 32px; } } + &.list-table { + td { + padding: 16px 24px; + } + } } } \ No newline at end of file diff --git a/aio/src/styles/1-layouts/_content-layout.scss b/aio/src/styles/1-layouts/_content-layout.scss index c6034396da..6933ca7ba8 100644 --- a/aio/src/styles/1-layouts/_content-layout.scss +++ b/aio/src/styles/1-layouts/_content-layout.scss @@ -37,3 +37,11 @@ aio-shell.page-docs { margin: 24px 0px; background: $lightgray; } + +.page-actions { + display: flex; + flex-direction: column; + position: absolute; + top: 80px; + right: 24px; +} \ No newline at end of file diff --git a/aio/src/styles/2-modules/_api-pages.scss b/aio/src/styles/2-modules/_api-pages.scss index b8e4dacfab..460aa4cda1 100644 --- a/aio/src/styles/2-modules/_api-pages.scss +++ b/aio/src/styles/2-modules/_api-pages.scss @@ -1,23 +1,102 @@ -.api-info-bar { - max-width: 800px; - text-align: left; +.api-body { - span { - margin: 0 16px 0 0; + .class-overview { + position: relative; - @media screen and (max-width: 600px) { - display: block; + code-example { + clear: left; + } + } + + .sidebar { + box-shadow: 0 2px 2px rgba(10, 16, 20, 0.24), 0 0 2px rgba(10, 16, 20, 0.12); + border-radius: 2px; + background: #FAFAFA; + float: right; + margin: 20px; + padding: 0 24px 14px; + + h2 { + margin: 18px 0 4px; + } + + ul { + margin: 0; + padding-left: 14px; + } + } + .inline-sidebar { + display: none; + } + + @media (max-width: 1200px) { + .sidebar { + display: none; + } + .inline-sidebar { + display: block; + } + } + + + .method-table { + h3 { + margin: 6px 0; + font-weight: bold; } + h4 { + font-size: 14px; + font-weight: bold; + margin-top: 12px; + } + } + + .api-heading { + padding: 5px 0; + font-size: 16px; + } + + .properties-table { + font-size: 14px; + + thead th { + &:nth-child(1) { + width: 20%; + } + &:nth-child(2) { + width: 20%; + } + } + } + + .parameters-table { + margin-top: 0; + font-size: 14px; + td:nth-child(1) { + width: 20%; + } + } + + details.overloads { + margin-left: -8px; + + summary { + height: inherit; + padding: 8px 12px; + h4 { + margin: 0; + clear: left; + } + } +} + + .api-section aio-code { + background-color: rgba(241, 241, 241, 0.2); + } + + .from-constructor { + font-style: italic; + color: $blue; } } - -.api-heading { - margin-top: 24px; - margin-bottom: 18px; - font-size: 16px; -} - -.overloads .detail-contents { - padding-top: 0; -} diff --git a/aio/src/styles/2-modules/_code.scss b/aio/src/styles/2-modules/_code.scss index f98e53df6f..ef3ac8d95d 100644 --- a/aio/src/styles/2-modules/_code.scss +++ b/aio/src/styles/2-modules/_code.scss @@ -69,7 +69,7 @@ code-tabs mat-tab-body-content .fadeIn { aio-code pre { display: flex; min-height: 32px; - margin: 16px 32px; + margin: 16px 24px; white-space: pre-wrap; align-items: center; diff --git a/aio/src/styles/2-modules/_details.scss b/aio/src/styles/2-modules/_details.scss index 36a1b95714..32728d8026 100644 --- a/aio/src/styles/2-modules/_details.scss +++ b/aio/src/styles/2-modules/_details.scss @@ -25,16 +25,13 @@ summary { display: none; // Remove the built in details marker in webkit } - &::after { + &::before { content: '\E5CE'; // See https://material.io/icons/#ic_expand_less font-family: 'Material Icons'; font-size: 24px; -webkit-font-smoothing: antialiased; @include rotate(0deg); // We will rotate 180 degrees when details is open - - position: absolute; - top: 12px; - right: 22px; + float: right; } } @@ -45,7 +42,7 @@ details { padding: 16px 24px; } - &[open] > summary::after { + &[open] > summary::before { @include rotate(180deg); // Rotate the icon } } diff --git a/aio/src/styles/2-modules/_label.scss b/aio/src/styles/2-modules/_label.scss new file mode 100644 index 0000000000..6efd06cb64 --- /dev/null +++ b/aio/src/styles/2-modules/_label.scss @@ -0,0 +1,55 @@ +label.raised, .api-header label { + border-radius: 4px; + padding: 4px 16px; + display: inline; + font-size: 14px; + color: white; + margin-right: 8px; + font-weight: 500; + text-transform: uppercase; + + @media screen and (max-width: 600px) { + display: block; + margin: 8px 0; + } + + &.page-label { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + background-color: $mist; + color: $mediumgray; + margin-bottom: 8px; + width: 140px; + + .material-icons { + margin-right: 8px; + } + } + + &.property-type-label { + font-size: 12px; + background-color: $darkgray; + color: $white; + text-transform: none; + } +} + +.api-header label { + + &.api-status-label { + background-color: $mediumgray; + } + + &.api-type-label { + background-color: $accentblue; + + @each $name, $symbol in $api-symbols { + &.#{$name} { + background: map-get($symbol, background); + } + } + + } +} \ No newline at end of file diff --git a/aio/src/styles/2-modules/_modules-dir.scss b/aio/src/styles/2-modules/_modules-dir.scss index 066d020812..a397b70782 100644 --- a/aio/src/styles/2-modules/_modules-dir.scss +++ b/aio/src/styles/2-modules/_modules-dir.scss @@ -30,3 +30,4 @@ @import 'select-menu'; @import 'deploy-theme'; @import 'notification'; + @import 'label'; diff --git a/aio/src/styles/2-modules/_table.scss b/aio/src/styles/2-modules/_table.scss index b515033ecb..0d5436d632 100644 --- a/aio/src/styles/2-modules/_table.scss +++ b/aio/src/styles/2-modules/_table.scss @@ -12,7 +12,7 @@ table { table-layout: fixed; } - thead { + thead > { vertical-align: middle; border-color: inherit; @@ -21,20 +21,20 @@ table { border-color: inherit; } - th { + tr > th { background: rgba($lightgray, 0.2); border-bottom: 1px solid $lightgray; color: $darkgray; font-size: 12px; font-weight: 500; - padding: 8px 32px; + padding: 8px 24px; text-align: left; text-transform: uppercase; line-height: 28px; } } - tbody { + tbody > tr > { th, td { border-bottom: 1px solid $lightgray; @@ -70,7 +70,7 @@ table { max-width: 100px; } - tr:last-child td { + &:last-child td { border: none; @media (max-width: 480px) { diff --git a/aio/src/styles/_typography-theme.scss b/aio/src/styles/_typography-theme.scss index c1a468740b..d94535b713 100755 --- a/aio/src/styles/_typography-theme.scss +++ b/aio/src/styles/_typography-theme.scss @@ -30,7 +30,7 @@ box-shadow: 0 2px 2px rgba(0,0,0,0.24), 0 0 2px rgba(0,0,0,0.12); } - table tbody th{ + table > tbody > tr > th { border: 1px solid rgba(mat-color($foreground, secondary-text), .03); } diff --git a/aio/tests/e2e/api.po.ts b/aio/tests/e2e/api.po.ts index 1b632f698d..50406a2a5b 100644 --- a/aio/tests/e2e/api.po.ts +++ b/aio/tests/e2e/api.po.ts @@ -24,7 +24,7 @@ export class ApiPage extends SitePage { // // and we want to be able to pull out the code elements from only the first level // if `onlyDirect` is set to `true`. - const selector = `.descendants.${docType} ${onlyDirect ? '>' : ''} li > :not(ul) code`; + const selector = `.inline-sidebar .descendants.${docType} ${onlyDirect ? '>' : ''} ul > li > code`; return element.all(by.css(selector)).map(item => item && item.getText()); } diff --git a/aio/tools/transforms/angular-api-package/index.js b/aio/tools/transforms/angular-api-package/index.js index 26a6e6e220..7302a9b9a6 100644 --- a/aio/tools/transforms/angular-api-package/index.js +++ b/aio/tools/transforms/angular-api-package/index.js @@ -21,7 +21,9 @@ module.exports = new Package('angular-api', [basePackage, typeScriptPackage]) .processor(require('./processors/extractDecoratedClasses')) .processor(require('./processors/matchUpDirectiveDecorators')) .processor(require('./processors/addMetadataAliases')) + .processor(require('./processors/computeApiBreadCrumbs')) .processor(require('./processors/filterContainedDocs')) + .processor(require('./processors/processClassLikeMembers')) .processor(require('./processors/markBarredODocsAsPrivate')) .processor(require('./processors/filterPrivateDocs')) .processor(require('./processors/computeSearchTitle')) @@ -86,15 +88,6 @@ module.exports = new Package('angular-api', [basePackage, typeScriptPackage]) // Load up all the tag definitions in the tag-defs folder parseTagsProcessor.tagDefinitions = parseTagsProcessor.tagDefinitions.concat(getInjectables(requireFolder(__dirname, './tag-defs'))); - - // We actually don't want to parse param docs in this package as we are getting the data out using TS - // TODO: rewire the param docs to the params extracted from TS - parseTagsProcessor.tagDefinitions.forEach(function(tagDef) { - if (tagDef.name === 'param') { - tagDef.docProperty = 'paramData'; - tagDef.transforms = []; - } - }); }) diff --git a/aio/tools/transforms/angular-api-package/processors/computeApiBreadCrumbs.js b/aio/tools/transforms/angular-api-package/processors/computeApiBreadCrumbs.js new file mode 100644 index 0000000000..c813b11c9c --- /dev/null +++ b/aio/tools/transforms/angular-api-package/processors/computeApiBreadCrumbs.js @@ -0,0 +1,19 @@ +module.exports = function computeApiBreadCrumbs(EXPORT_DOC_TYPES) { + return { + $runAfter: ['paths-computed'], + $runBefore: ['rendering-docs'], + $process(docs) { + // Compute the breadcrumb for each doc by processing its containers + docs.forEach(doc => { + if (EXPORT_DOC_TYPES.indexOf(doc.docType) !== -1) { + doc.breadCrumbs = [ + { text: 'API', path: '/api' }, + { text: '@angular/' + doc.moduleDoc.id, path: doc.moduleDoc.path }, + { text: doc.name, path: doc.path } + ]; + } + }); + } + }; +}; + diff --git a/aio/tools/transforms/angular-api-package/processors/computeApiBreadCrumbs.spec.js b/aio/tools/transforms/angular-api-package/processors/computeApiBreadCrumbs.spec.js new file mode 100644 index 0000000000..7e3aba0c96 --- /dev/null +++ b/aio/tools/transforms/angular-api-package/processors/computeApiBreadCrumbs.spec.js @@ -0,0 +1,39 @@ +const testPackage = require('../../helpers/test-package'); +const processorFactory = require('./computeApiBreadCrumbs'); +const Dgeni = require('dgeni'); + +describe('angular-api-package: computeApiBreadCrumbs processor', () => { + + it('should be available on the injector', () => { + const dgeni = new Dgeni([testPackage('angular-api-package')]); + const injector = dgeni.configureInjector(); + const processor = injector.get('computeApiBreadCrumbs'); + expect(processor.$process).toBeDefined(); + expect(processor.$runAfter).toEqual(['paths-computed']); + expect(processor.$runBefore).toEqual(['rendering-docs']); + }); + + it('should attach a breadCrumbs property to each of the EXPORT_DOC_TYPES docs', () => { + const EXPORT_DOC_TYPES = ['class', 'interface']; + const processor = processorFactory(EXPORT_DOC_TYPES); + + 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' }, + ]; + processor.$process(docs); + + expect(docs[0].breadCrumbs).toEqual([ + { text: 'API', path: '/api' }, + { text: '@angular/moduleOne', path: 'module-1' }, + { text: 'ClassA', path: 'module-1/class-a' }, + ]); + expect(docs[1].breadCrumbs).toEqual([ + { text: 'API', path: '/api' }, + { text: '@angular/moduleTwo', path: 'module-2' }, + { text: 'InterfaceB', path: 'module-2/interface-b' }, + ]); + expect(docs[2].breadCrumbs).toBeUndefined(); + }); +}); diff --git a/aio/tools/transforms/angular-api-package/processors/processClassLikeMembers.js b/aio/tools/transforms/angular-api-package/processors/processClassLikeMembers.js new file mode 100644 index 0000000000..b9cf73e5b1 --- /dev/null +++ b/aio/tools/transforms/angular-api-package/processors/processClassLikeMembers.js @@ -0,0 +1,59 @@ +/** + * A class like API doc contains members, but these can be either properties or method. + * Separate the members into two new collections: `doc.properties` and `doc.methods`. + */ +module.exports = function processClassLikeMembers() { + return { + $runAfter: ['filterContainedDocs'], + $runBefore: ['rendering-docs'], + $process(docs) { + docs.forEach(doc => { + if (doc.members) { + doc.properties = []; + doc.methods = []; + doc.members.forEach(member => { + if (isMethod(member)) { + doc.methods.push(member); + computeMemberDescription(member); + } else { + doc.properties.push(member); + + if (!member.description) { + // Is this property defined as a constructor parameter e.g. `constructor(public property: string) { ... }`? + const constructorDoc = member.containerDoc.constructorDoc; + if (constructorDoc) { + const matchingParameterDoc = constructorDoc.parameterDocs.filter(doc => doc.declaration === member.declaration)[0]; + member.constructorParamDoc = matchingParameterDoc; + } + } + } + }); + } + if (doc.statics) { + doc.staticProperties = []; + doc.staticMethods = []; + doc.statics.forEach(member => { + if (isMethod(member)) { + doc.staticMethods.push(member); + computeMemberDescription(member); + } else { + doc.staticProperties.push(member); + } + }); + } + + }); + } + }; +}; + +function isMethod(doc) { + return doc.hasOwnProperty('parameters') && !doc.isGetAccessor && !doc.isSetAccessor; +} + +function computeMemberDescription(member) { + if (!member.description && member.overloads) { + // Perhaps the description is on one of the overloads - take the first non-empty one + member.description = member.overloads.map(overload => overload.description).filter(description => !!description)[0]; + } +} \ No newline at end of file diff --git a/aio/tools/transforms/angular-api-package/processors/processClassLikeMembers.spec.js b/aio/tools/transforms/angular-api-package/processors/processClassLikeMembers.spec.js new file mode 100644 index 0000000000..8a7bdc72d2 --- /dev/null +++ b/aio/tools/transforms/angular-api-package/processors/processClassLikeMembers.spec.js @@ -0,0 +1,81 @@ +const testPackage = require('../../helpers/test-package'); +const processorFactory = require('./processClassLikeMembers'); +const Dgeni = require('dgeni'); + +const property1 = { description: 'property 1' }; +const property2 = { description: 'property 2' }; +const getter1 = { parameters: [], isGetAccessor: true, description: 'getter 1' }; +const setter1 = { parameters: [], isSetAccessor: true, description: 'setter 1' }; +const method1 = { parameters: [] }; +const method2 = { parameters: [] }; +const method3 = { parameters: [] }; + +describe('angular-api-packge: processClassLikeMembers processor', () => { + + it('should be available on the injector', () => { + const dgeni = new Dgeni([testPackage('angular-api-package')]); + const injector = dgeni.configureInjector(); + const processor = injector.get('processClassLikeMembers'); + expect(processor.$process).toBeDefined(); + expect(processor.$runAfter).toEqual(['filterContainedDocs']); + expect(processor.$runBefore).toEqual(['rendering-docs']); + }); + + it('should copy instance members into properties and methods', () => { + const processor = processorFactory(); + const docs = [ + { members: [ property1, method1, getter1] }, + { members: [ method2, property2, method3, setter1] }, + { } + ]; + processor.$process(docs); + + expect(docs[0].properties).toEqual([property1, getter1]); + expect(docs[0].methods).toEqual([method1]); + + expect(docs[1].properties).toEqual([property2, setter1]); + expect(docs[1].methods).toEqual([method2, method3]); + + expect(docs[2].properties).toBeUndefined(); + expect(docs[2].methods).toBeUndefined(); + }); + + it('should copy static members into properties and methods', () => { + const processor = processorFactory(); + const docs = [ + { statics: [ property1, method1, getter1] }, + { statics: [ method2, property2, method3, setter1] }, + { } + ]; + processor.$process(docs); + + expect(docs[0].staticProperties).toEqual([property1, getter1]); + expect(docs[0].staticMethods).toEqual([method1]); + + expect(docs[1].staticProperties).toEqual([property2, setter1]); + expect(docs[1].staticMethods).toEqual([method2, method3]); + + expect(docs[2].staticProperties).toBeUndefined(); + expect(docs[2].staticMethods).toBeUndefined(); + }); + + it('should wire up properties that are declared as parameters on the constructor to its associated parameter doc', () => { + const processor = processorFactory(); + const propertyDeclaration = {}; + const parameterDoc1 = { declaration: {} }; + const parameterDoc2 = { declaration: propertyDeclaration }; + const parameterDoc3 = { declaration: {} }; + const property = { + declaration: propertyDeclaration, + containerDoc: { + constructorDoc: { + parameterDocs: [ parameterDoc1, parameterDoc2, parameterDoc3 ] + } + } + }; + const docs = [{ members: [ property] }]; + processor.$process(docs); + + expect(property.constructorParamDoc).toEqual(parameterDoc2); + }); +}); diff --git a/aio/tools/transforms/angular-api-package/tag-defs/throws.js b/aio/tools/transforms/angular-api-package/tag-defs/throws.js new file mode 100644 index 0000000000..4e1ac58be7 --- /dev/null +++ b/aio/tools/transforms/angular-api-package/tag-defs/throws.js @@ -0,0 +1,8 @@ +module.exports = function(extractTypeTransform, wholeTagTransform) { + return { + name: 'throws', + aliases: ['exception'], + multi: true, + transforms: [ extractTypeTransform, wholeTagTransform ] + }; +}; \ No newline at end of file diff --git a/aio/tools/transforms/templates/api/base.template.html b/aio/tools/transforms/templates/api/base.template.html index f1da284144..f1ffd6b2e1 100644 --- a/aio/tools/transforms/templates/api/base.template.html +++ b/aio/tools/transforms/templates/api/base.template.html @@ -1,13 +1,46 @@ +{% import "lib/githubLinks.html" as github -%} +{% set comma = joiner(',') %} +{% set slash = joiner('/') %}
+
-

{$ doc.name $}

+ {% if doc.deprecated !== undefined %}{% endif %} + {% if doc.experimental !== undefined %}{% endif %} + {% if doc.stable !== undefined %}{% endif %} - {% if doc.deprecated %}{% endif %} - {% if doc.experimental %}{% endif %} - {% if doc.stable %}{% endif %} +

+ {$ doc.name $} +

{$ version $}
+
- {% block body %}{% endblock %} - +
+ {% block body %}{% endblock %} +
\ No newline at end of file diff --git a/aio/tools/transforms/templates/api/class.template.html b/aio/tools/transforms/templates/api/class.template.html index 8394fb683f..04e7a8f7ea 100644 --- a/aio/tools/transforms/templates/api/class.template.html +++ b/aio/tools/transforms/templates/api/class.template.html @@ -1,16 +1,27 @@ {% import "lib/memberHelpers.html" as memberHelpers -%} {% import "lib/descendants.html" as descendants -%} {% import "lib/paramList.html" as params -%} -{% extends 'export-base.template.html' -%} +{% extends 'base.template.html' -%} -{% block overview %}{% include "includes/class-overview.html" %}{% endblock %} -{% block details %} -{% block additional %}{% endblock %} -{% include "includes/description.html" %} -{$ descendants.renderDescendants(doc, 'class', 'Subclasses') $} -{$ memberHelpers.renderMemberDetails(doc.statics, 'static-members', 'static-member', 'Static Members') $} -{% if doc.constructorDoc %}{$ memberHelpers.renderMemberDetails([doc.constructorDoc], 'constructors', 'constructor', 'Constructor') $}{% endif %} -{$ memberHelpers.renderMemberDetails(doc.members, 'instance-members', 'instance-member', 'Members') $} -{% block annotations %}{% include "includes/annotations.html" %}{% endblock %} +{% block body %} +

{$ doc.whatItDoes | marked $}

+ {% include "includes/security-notes.html" %} + {% include "includes/deprecation.html" %} + {% block overview %} + {% include "includes/class-overview.html" %} + {% endblock %} + {% block details %} + {% block additional %}{% endblock %} + {% include "includes/description.html" %} + {$ memberHelpers.renderProperties(doc.staticProperties, 'static-properties', 'static-property', 'Static Properties') $} + {$ memberHelpers.renderMethodDetails(doc.staticMethods, 'static-methods', 'static-method', 'Static Methods') $} + {% if doc.constructorDoc %}{$ memberHelpers.renderMethodDetail(doc.constructorDoc, 'constructor') $}{% endif %} + {$ memberHelpers.renderProperties(doc.properties, 'instance-properties', 'instance-property', 'Properties') $} + + {$ memberHelpers.renderMethodDetails(doc.methods, 'instance-methods', 'instance-method', 'Methods') $} + + {% block annotations %}{% include "includes/annotations.html" %}{% endblock %} + {% endblock %} + {% include "includes/how-to-use.html" %} {% endblock %} diff --git a/aio/tools/transforms/templates/api/decorator.template.html b/aio/tools/transforms/templates/api/decorator.template.html index 232b99b40d..c4d3f77e1a 100644 --- a/aio/tools/transforms/templates/api/decorator.template.html +++ b/aio/tools/transforms/templates/api/decorator.template.html @@ -5,5 +5,5 @@ {% block overview %}{% include "includes/decorator-overview.html" %}{% endblock %} {% block details %} {% include "includes/description.html" %} - {$ memberHelper.renderMemberDetails(doc.members, 'metadata-members', 'metadata-member', 'Metadata Properties') $} + {$ memberHelper.renderProperties(doc.members, 'metadata-members', 'metadata-member', 'Metadata Properties') $} {% endblock %} diff --git a/aio/tools/transforms/templates/api/export-base.template.html b/aio/tools/transforms/templates/api/export-base.template.html index 6b23a7e9db..f1d3c5be92 100644 --- a/aio/tools/transforms/templates/api/export-base.template.html +++ b/aio/tools/transforms/templates/api/export-base.template.html @@ -1,7 +1,6 @@ {% extends 'base.template.html' -%} {% block body %} - {% include "includes/info-bar.html" %} {% include "includes/what-it-does.html" %} {% include "includes/security-notes.html" %} {% include "includes/deprecation.html" %} diff --git a/aio/tools/transforms/templates/api/includes/class-overview.html b/aio/tools/transforms/templates/api/includes/class-overview.html index e7ddf7862f..dd5ad7ccdc 100644 --- a/aio/tools/transforms/templates/api/includes/class-overview.html +++ b/aio/tools/transforms/templates/api/includes/class-overview.html @@ -2,13 +2,23 @@

Overview

+{% if (doc.descendants | filterByPropertyValue('docType', 'class')).length or doc.see.length %} + +{% endif %} {$ doc.docType $} {$ doc.name $}{$ doc.typeParams | escape $}{$ memberHelper.renderHeritage(doc) $} { {%- if doc.constructorDoc %}{% if not doc.constructorDoc.internal %} - {$ memberHelper.renderMember(doc.constructorDoc, 1) $}{% endif %}{% endif -%} + {$ memberHelper.renderMemberSyntax(doc.constructorDoc, 1) $}{% endif %}{% endif -%} {%- if doc.statics.length %}{% for member in doc.statics %}{% if not member.internal %} - {$ memberHelper.renderMember(member, 1) $}{% endif %}{% endfor %}{% endif -%} + {$ memberHelper.renderMemberSyntax(member, 1) $}{% endif %}{% endfor %}{% endif -%} {$ memberHelper.renderMembers(doc) $} } +
+ {$ descendants.renderDescendants(doc, 'class', 'Subclasses') $} + {% include "includes/see-also.html" %} +
diff --git a/aio/tools/transforms/templates/api/includes/directive-overview.html b/aio/tools/transforms/templates/api/includes/directive-overview.html index 078f82c5ac..9518f47d67 100644 --- a/aio/tools/transforms/templates/api/includes/directive-overview.html +++ b/aio/tools/transforms/templates/api/includes/directive-overview.html @@ -6,7 +6,7 @@ @{$ decorator.name $}({$ decorator.arguments $}){% endfor %} class {$ doc.name $}{$ doc.typeParams | escape $}{$ memberHelper.renderHeritage(doc) $} { {%- if doc.statics.length %}{% for member in doc.statics %}{% if not member.internal %} - {$ memberHelper.renderMember(member, 1) $}{% endif %}{% endfor %}{% endif -%} + {$ memberHelper.renderMemberSyntax(member, 1) $}{% endif %}{% endfor %}{% endif -%} {$ memberHelper.renderMembers(doc) $} } diff --git a/aio/tools/transforms/templates/api/includes/interface-overview.html b/aio/tools/transforms/templates/api/includes/interface-overview.html index 490a344cbf..0c0ead536f 100644 --- a/aio/tools/transforms/templates/api/includes/interface-overview.html +++ b/aio/tools/transforms/templates/api/includes/interface-overview.html @@ -2,9 +2,14 @@

Interface Overview

+ interface {$ doc.name $}{$ doc.typeParams | escape $}{$ memberHelper.renderHeritage(doc) $} { {% if doc.members.length %}{% for member in doc.members %}{% if not member.internal %} - {$ memberHelper.renderMember(member, 1) $}{% endif %}{% endfor %}{% endif %} + {$ memberHelper.renderMemberSyntax(member, 1) $}{% endif %}{% endfor %}{% endif %} }
\ No newline at end of file diff --git a/aio/tools/transforms/templates/api/includes/see-also.html b/aio/tools/transforms/templates/api/includes/see-also.html new file mode 100644 index 0000000000..0b97cc87e8 --- /dev/null +++ b/aio/tools/transforms/templates/api/includes/see-also.html @@ -0,0 +1,9 @@ +{%- if doc.see.length %} +
+

See Also

+ +
+{% endif %} diff --git a/aio/tools/transforms/templates/api/interface.template.html b/aio/tools/transforms/templates/api/interface.template.html index 52327006e4..551d17adde 100644 --- a/aio/tools/transforms/templates/api/interface.template.html +++ b/aio/tools/transforms/templates/api/interface.template.html @@ -6,7 +6,11 @@ {% block overview %}{% include "includes/interface-overview.html" %}{% endblock %} {% block details %} {% include "includes/description.html" %} - {$ descendants.renderDescendants(doc, 'interface', 'Child Interfaces') $} - {$ descendants.renderDescendants(doc, 'class', 'Class Implementations') $} - {$ memberHelper.renderMemberDetails(doc.members, 'instance-members', 'instance-member', 'Members') $} +
+ {$ descendants.renderDescendants(doc, 'interface', 'Child Interfaces') $} + {$ descendants.renderDescendants(doc, 'class', 'Class Implementations') $} + {% include "includes/see-also.html" %} +
+ {$ memberHelper.renderProperties(doc.properties, 'instance-properties', 'instance-property', 'Properties') $} + {$ memberHelper.renderMethodDetails(doc.methods, 'instance-methods', 'instance-method', 'Methods') $} {% endblock %} diff --git a/aio/tools/transforms/templates/api/lib/descendants.html b/aio/tools/transforms/templates/api/lib/descendants.html index cdf15d0be8..73b097a1a9 100644 --- a/aio/tools/transforms/templates/api/lib/descendants.html +++ b/aio/tools/transforms/templates/api/lib/descendants.html @@ -1,14 +1,22 @@ -{% macro renderDescendants(doc, docType, title='', recursed=false) %} - {% set descendants = doc.descendants | filterByPropertyValue('docType', docType) %} - {% if descendants.length %} - {% if title %}

{$ title $}

{% endif %} - +{% endif %} +{% endmacro -%} + +{%- macro renderDescendants(doc, docType, title='', recursed=true) %} + {% set descendants = doc.descendants | filterByPropertyValue('docType', docType) %} + {% if descendants.length %} +
+ {% if title %}

{$ title $}

{% endif %} + {$ renderDescendantList(descendants, docType, recursed) $} +
{% endif %} {% endmacro %} \ No newline at end of file diff --git a/aio/tools/transforms/templates/api/lib/memberHelpers.html b/aio/tools/transforms/templates/api/lib/memberHelpers.html index 7589fb1781..0235484eba 100644 --- a/aio/tools/transforms/templates/api/lib/memberHelpers.html +++ b/aio/tools/transforms/templates/api/lib/memberHelpers.html @@ -11,12 +11,12 @@ {%- macro renderMembers(doc) -%} {%- if doc.members.length %}{% for member in doc.members %}{% if not member.internal %} - {$ renderMember(member, 1) $}{% endif %}{% endfor %}{% endif %} + {$ renderMemberSyntax(member, 1) $}{% endif %}{% endfor %}{% endif %} {%- for ancestor in doc.extendsClauses %}{% if ancestor.doc %} // inherited from {$ ancestor.doc.id $}{$ renderMembers(ancestor.doc) $}{% endif %}{% endfor %} {%- endmacro -%} -{%- macro renderMember(member, truncateLines) -%} +{%- macro renderMemberSyntax(member, truncateLines) -%} {%- if member.accessibility !== 'public' %}{$ member.accessibility $} {% endif -%} {%- if (member.isGetAccessor or member.isReadonly) and not member.isSetAccessor %}get {% endif -%} {%- if member.isSetAccessor and not member.isGetAccessor %}set {% endif -%} @@ -26,35 +26,101 @@ {$ params.returnType(member.type) | trim | truncateCode(truncateLines) $} {%- endmacro -%} -{%- macro renderMemberDetail(member, cssClass) -%} -
- - {$ renderMember(member) $} - {%- if not member.notYetDocumented %} - {$ member.description | marked $} - {% endif -%} -
+{%- macro renderOverloadInfo(overload, cssClass, method) -%} + {% if overload.description and (overload.description != method.description) %}{$ overload.description | marked $}{% endif %} + + {$ renderMemberSyntax(overload) $} + +

Parameters

+ {$ params.renderParameters(overload.parameterDocs, cssClass + '-parameters', cssClass + '-parameter') $} + + {% if overload.type or overload.returns.type %} +

Returns

+ {% marked %}`{$ (overload.type or overload.returns.type) $}`{% if overload.returns %}: {$ overload.returns.description $}{% endif %}{% endmarked %} + {% endif %} + + {% if overload.throws.length %} +

Throws

+ {% for error in overload.throws %} + {% marked %}`{$ (error.typeList or 'Error') $}` {$ error.description $}{% endmarked %} + {% endfor %} + {% endif %} +{%- endmacro -%} + +{%- macro renderMethodDetail(method, cssClass) -%} + + + + + + + + {% if method.overloads.length == 0 %} + + + + {% elseif method.overloads.length < 3 -%} + {% for overload in method.overloads -%} + + + + {% endfor -%} + {% else -%} + + + + {% endif %} + +

{$ method.name $}()

+ {% if method.description %}{$ method.description | marked $}{% endif %} +
+ {$ renderOverloadInfo(method, cssClass + '-overload', method) $} +
+ {$ renderOverloadInfo(overload, cssClass + '-overload', method) $} +
+
+

{$ method.overloads.length $} overloads...

+
+ {% for overload in method.overloads %} + {$ renderOverloadInfo(overload, cssClass + '-overload', method) $} + {% if not loop.last %}
{% endif %} + {% endfor %} +
+
+
{% endmacro -%} -{% macro renderMemberDetails(members, containerClass, itemClass, titleText) %} -{% if members.length %} +{%- macro renderMethodDetails(methods, containerClass, itemClass, headingText) -%} +{% if methods.length %}
-

{$ titleText $}

- {% for member in members %}{% if not member.internal %} - {$ renderMemberDetail(member, itemClass) $} - {% if member.overloads.length %} -
- Overloads -
- {% for overload in member.overloads %} - {$ renderMemberDetail(overload, itemClass + '-overload') $} - {% if not loop.last %}
{% endif %} - {% endfor %} -
-
- {% endif %} - {% if not loop.last %}
{% endif %} +

{$ headingText $}

+ {% for member in methods %}{% if not member.internal %} + {$ renderMethodDetail(member, itemClass) $} {% endif %}{% endfor %}
{% endif %} -{% endmacro %} +{%- endmacro -%} + + +{%- macro renderProperties(properties, containerClass, propertyClass, headingText) -%} +{%- if properties.length -%} +

{$ headingText $}

+ + + + + + {% for property in properties %}{% if not property.internal %} + + + + + + {% endif %}{% endfor %} + +
PropertyTypeDescription
{$ property.name $} + {$ (property.description or property.constructorParamDoc.description) | marked $} + {% if property.constructorParamDoc %} Declared in constructor.{% endif %} +
+{%- endif -%} +{%- endmacro -%} diff --git a/aio/tools/transforms/templates/api/lib/paramList.html b/aio/tools/transforms/templates/api/lib/paramList.html index 3e6b721cf4..b13e851ce6 100644 --- a/aio/tools/transforms/templates/api/lib/paramList.html +++ b/aio/tools/transforms/templates/api/lib/paramList.html @@ -10,3 +10,23 @@ {% macro returnType(returnType) -%} {%- if returnType %}: {$ returnType | escape $}{% endif -%} {%- endmacro -%} + +{%- macro renderParameters(parameters, containerClass, parameterClass) -%} +{%- if parameters.length -%} + + + {% for parameter in parameters %} + + + + {% endfor %} + +
{$ parameter.name $} + {% if parameter.description | trim %}{$ parameter.description | marked $} + {% elseif parameter.type %}{$ parameter.type $} + {% endif %} +
+{%- else -%} +

There are no parameters.

+{%- endif -%} +{%- endmacro -%} \ No newline at end of file diff --git a/aio/yarn.lock b/aio/yarn.lock index 4acead46b1..409398dfce 100644 --- a/aio/yarn.lock +++ b/aio/yarn.lock @@ -2312,9 +2312,9 @@ devtools-timeline-model@1.1.6: chrome-devtools-frontend "1.0.401423" resolve "1.1.7" -dgeni-packages@^0.24.0: - version "0.24.0" - resolved "https://registry.yarnpkg.com/dgeni-packages/-/dgeni-packages-0.24.0.tgz#2f995f78fecd6a9ded72d7bdccbbc4c46360c1ea" +dgeni-packages@0.24.1: + version "0.24.1" + resolved "https://registry.yarnpkg.com/dgeni-packages/-/dgeni-packages-0.24.1.tgz#e3e99eb82615b30a9e43fe1a9bb9911ff6bbf913" dependencies: canonical-path "0.0.2" catharsis "^0.8.1" diff --git a/packages/forms/src/model.ts b/packages/forms/src/model.ts index 4342cffad0..d9f28b534a 100644 --- a/packages/forms/src/model.ts +++ b/packages/forms/src/model.ts @@ -117,6 +117,9 @@ function isOptionsObj( * that are shared between all sub-classes, like `value`, `valid`, and `dirty`. It shouldn't be * instantiated directly. * + * @see [Forms Guide](/guide/forms) + * @see [Reactive Forms Guide](/guide/reactive-forms) + * @see [Dynamic Forms Guide](/guide/dynamic-form) * @stable */ export abstract class AbstractControl { @@ -136,6 +139,12 @@ export abstract class AbstractControl { private _asyncValidationSubscription: any; public readonly value: any; + /** + * Initialize the AbstractControl instance. + * @param validator The function that will determine the synchronous validity of this control. + * @param asyncValidator The function that will determine the asynchronous validity of this + * control. + */ constructor(public validator: ValidatorFn|null, public asyncValidator: AsyncValidatorFn|null) {} /** @@ -1033,10 +1042,6 @@ export class FormGroup extends AbstractControl { * Sets the value of the {@link FormGroup}. It accepts an object that matches * the structure of the group, with control names as keys. * - * This method performs strict checks, so it will throw an error if you try - * to set the value of a control that doesn't exist or if you exclude the - * value of a control. - * * ### Example * * ``` @@ -1050,6 +1055,9 @@ export class FormGroup extends AbstractControl { * console.log(form.value); // {first: 'Nancy', last: 'Drew'} * * ``` + * @throws This method performs strict checks, so it will throw an error if you try + * to set the value of a control that doesn't exist or if you exclude the + * value of a control. */ setValue(value: {[key: string]: any}, options: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {