From 1d6c658a804c9543725084589b14f86749c39a4d Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Sat, 21 Sep 2019 18:33:04 -0700 Subject: [PATCH 1/4] Include namespaces in .yml output --- .../documenters/ExperimentalYamlDocumenter.ts | 38 ++--- .../src/documenters/YamlDocumenter.ts | 136 ++++++++++-------- apps/api-documenter/src/yaml/IYamlApiFile.ts | 2 +- .../src/yaml/typescript.schema.json | 2 +- .../etc/yaml/api-documenter-test.yml | 22 +-- .../outernamespace.innernamespace.yml | 30 ++++ .../api-documenter-test/etc/yaml/toc.yml | 2 + .../flattenNamespaces2_2019-09-22-01-34.json | 11 ++ 8 files changed, 139 insertions(+), 104 deletions(-) create mode 100644 build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.innernamespace.yml create mode 100644 common/changes/@microsoft/api-documenter/flattenNamespaces2_2019-09-22-01-34.json diff --git a/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts b/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts index 4412ca1e8c3..87a06066777 100644 --- a/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts @@ -36,39 +36,23 @@ export class ExperimentalYamlDocumenter extends YamlDocumenter { private _buildTocItems2(apiItems: ReadonlyArray): IYamlTocItem[] { const tocItems: IYamlTocItem[] = []; for (const apiItem of apiItems) { - let tocItem: IYamlTocItem; - - if (apiItem.kind === ApiItemKind.Namespace) { - // Namespaces don't have nodes yet - tocItem = { - name: this._getTocItemName(apiItem) - }; - } else { - if (this._shouldEmbed(apiItem.kind)) { - // Don't generate table of contents items for embedded definitions - continue; - } + if (this._shouldEmbed(apiItem.kind)) { + // Don't generate table of contents items for embedded definitions + continue; + } - tocItem = { - name: this._getTocItemName(apiItem), - uid: this._getUid(apiItem) - }; + const tocItem: IYamlTocItem = { + name: this._getTocItemName(apiItem), + uid: this._getUid(apiItem) + }; - if (apiItem.kind !== ApiItemKind.Package) { - this._filterItem(apiItem, tocItem); - } + if (apiItem.kind !== ApiItemKind.Package) { + this._filterItem(apiItem, tocItem); } tocItems.push(tocItem); - let children: ReadonlyArray; - if (apiItem.kind === ApiItemKind.Package) { - // Skip over the entry point, since it's not part of the documentation hierarchy - children = apiItem.members[0].members; - } else { - children = apiItem.members; - } - + const children: ApiItem[] = this._getLogicalChildren(apiItem); const childItems: IYamlTocItem[] = this._buildTocItems2(children); if (childItems.length > 0) { tocItem.items = childItems; diff --git a/apps/api-documenter/src/documenters/YamlDocumenter.ts b/apps/api-documenter/src/documenters/YamlDocumenter.ts index b91f829a2b2..d59f2c105da 100644 --- a/apps/api-documenter/src/documenters/YamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/YamlDocumenter.ts @@ -66,6 +66,12 @@ interface IYamlReferences { uidTypeReferenceCounters: Map; } +const enum FlattenMode { + NestedNamespacesAndChildren, + NestedNamespacesOnly, + NoNamespaces +} + /** * Writes documentation in the Universal Reference YAML file format, as defined by typescript.schema.json. */ @@ -139,17 +145,8 @@ export class YamlDocumenter { }; newYamlFile.items.push(yamlItem); - let children: ReadonlyArray; - if (apiItem.kind === ApiItemKind.Package) { - // Skip over the entry point, since it's not part of the documentation hierarchy - children = apiItem.members[0].members; - } else { - children = apiItem.members; - } - - const flattenedChildren: ApiItem[] = this._flattenNamespaces(children); - - for (const child of flattenedChildren) { + const children: ApiItem[] = this._getLogicalChildren(apiItem); + for (const child of children) { if (child instanceof ApiDocumentedItem) { if (this._visitApiItems(child, newYamlFile)) { if (!yamlItem.children) { @@ -178,25 +175,54 @@ export class YamlDocumenter { this._recordYamlReference( this._ensureYamlReferences(), this._getUid(apiItem), - this._getYamlItemName(apiItem)); + this._getYamlItemName(apiItem, /*includeSignature*/ true)); } } return true; } - // Since the YAML schema does not yet support nested namespaces, we simply omit them from - // the tree. However, _getYamlItemName() will show the namespace. - private _flattenNamespaces(items: ReadonlyArray): ApiItem[] { - const flattened: ApiItem[] = []; + protected _getLogicalChildren(apiItem: ApiItem): ApiItem[] { + const children: ApiItem[] = []; + if (apiItem.kind === ApiItemKind.Package) { + // Skip over the entry point, since it's not part of the documentation hierarchy + this._flattenNamespaces(apiItem.members[0].members, children, FlattenMode.NestedNamespacesAndChildren); + } else { + this._flattenNamespaces(apiItem.members, children, FlattenMode.NoNamespaces); + } + return children; + } + + // Flattens nested namespaces into top level entries so that the following: + // namespace X { export namespace Y { export namespace Z { } } + // Is represented as: + // - X + // - X.Y + // - X.Y.Z + private _flattenNamespaces(items: ReadonlyArray, childrenOut: ApiItem[], mode: FlattenMode): boolean { + let hasNonNamespaceChildren: boolean = false; for (const item of items) { - if (item.kind === ApiItemKind.Namespace) { - flattened.push(... this._flattenNamespaces(item.members)); - } else { - flattened.push(item); + if (item.kind === ApiItemKind.Namespace && mode !== FlattenMode.NoNamespaces) { + // At any level, always include a nested namespace if it has non-namespace children, but do not include its + // non-namespace children in the result. + + // Record the offset at which the namespace is added in case we need to remove it later. + const index: number = childrenOut.length; + childrenOut.push(item); + + if (!this._flattenNamespaces(item.members, childrenOut, FlattenMode.NestedNamespacesOnly)) { + // This namespace had no non-namespace children, remove it. + childrenOut.splice(index, 1); + } + } else if (this._shouldInclude(item.kind)) { + if (mode !== FlattenMode.NestedNamespacesOnly) { + // At the top level, include non-namespace children as well. + childrenOut.push(item); + } + hasNonNamespaceChildren = true; } } - return flattened; + return hasNonNamespaceChildren; } /** @@ -226,35 +252,18 @@ export class YamlDocumenter { private _buildTocItems(apiItems: ReadonlyArray): IYamlTocItem[] { const tocItems: IYamlTocItem[] = []; for (const apiItem of apiItems) { - let tocItem: IYamlTocItem; - - if (apiItem.kind === ApiItemKind.Namespace) { - // Namespaces don't have nodes yet - tocItem = { - name: this._getTocItemName(apiItem) - }; - } else { - if (this._shouldEmbed(apiItem.kind)) { - // Don't generate table of contents items for embedded definitions - continue; - } - - tocItem = { - name: this._getTocItemName(apiItem), - uid: this._getUid(apiItem) - }; + if (this._shouldEmbed(apiItem.kind)) { + // Don't generate table of contents items for embedded definitions + continue; } + const tocItem: IYamlTocItem = { + name: this._getTocItemName(apiItem), + uid: this._getUid(apiItem) + }; tocItems.push(tocItem); - let children: ReadonlyArray; - if (apiItem.kind === ApiItemKind.Package) { - // Skip over the entry point, since it's not part of the documentation hierarchy - children = apiItem.members[0].members; - } else { - children = apiItem.members; - } - + const children: ApiItem[] = this._getLogicalChildren(apiItem); const childItems: IYamlTocItem[] = this._buildTocItems(children); if (childItems.length > 0) { tocItem.items = childItems; @@ -265,9 +274,11 @@ export class YamlDocumenter { /** @virtual */ protected _getTocItemName(apiItem: ApiItem): string { - let name: string = apiItem.displayName; + let name: string; if (apiItem.kind === ApiItemKind.Package) { - name = PackageName.getUnscopedName(name); + name = PackageName.getUnscopedName(apiItem.displayName); + } else { + name = this._getYamlItemName(apiItem, /*includeSignature*/ false); } if (apiItem.getMergedSiblings().length > 1) { @@ -283,20 +294,29 @@ export class YamlDocumenter { case ApiItemKind.Package: case ApiItemKind.Interface: case ApiItemKind.Enum: - return false; + case ApiItemKind.Namespace: + return false; } return true; } - private _generateYamlItem(apiItem: ApiDocumentedItem): IYamlItem | undefined { + protected _shouldInclude(apiItemKind: ApiItemKind): boolean { // Filter out known items that are not yet supported - switch (apiItem.kind) { + switch (apiItemKind) { case ApiItemKind.CallSignature: case ApiItemKind.ConstructSignature: case ApiItemKind.IndexSignature: case ApiItemKind.TypeAlias: case ApiItemKind.Variable: - return undefined; + return false; + } + return true; + } + + private _generateYamlItem(apiItem: ApiDocumentedItem): IYamlItem | undefined { + // Filter out known items that are not yet supported + if (!this._shouldInclude(apiItem.kind)) { + return undefined; } const uid: DeclarationReference = this._getUidObject(apiItem); @@ -334,7 +354,7 @@ export class YamlDocumenter { } } - yamlItem.name = this._getYamlItemName(apiItem); + yamlItem.name = this._getYamlItemName(apiItem, /*includeSignature*/ true); yamlItem.fullName = yamlItem.name; yamlItem.langs = [ 'typeScript' ]; @@ -374,6 +394,9 @@ export class YamlDocumenter { case ApiItemKind.Package: yamlItem.type = 'package'; break; + case ApiItemKind.Namespace: + yamlItem.type = 'namespace'; + break; case ApiItemKind.Property: case ApiItemKind.PropertySignature: const apiProperty: ApiPropertyItem = apiItem as ApiPropertyItem; @@ -743,7 +766,8 @@ export class YamlDocumenter { return uid; } - private _getYamlItemName(apiItem: ApiItem): string { + private _getYamlItemName(apiItem: ApiItem, includeSignature: boolean): string { + const baseName: string = includeSignature ? Utilities.getConciseSignature(apiItem) : apiItem.displayName; if (apiItem.parent && apiItem.parent.kind === ApiItemKind.Namespace) { // If the immediate parent is a namespace, then add the namespaces to the name. For example: // @@ -771,7 +795,7 @@ export class YamlDocumenter { // embeds this entry in the web page for "N1.N2.C", so the container is obvious. Whereas "N1.N2.f(x,y)" // needs to be qualified because the DocFX template doesn't make pages for namespaces. Instead, they get // flattened into the package's page. - const nameParts: string[] = [ Utilities.getConciseSignature(apiItem) ]; + const nameParts: string[] = [ baseName ]; for (let current: ApiItem | undefined = apiItem.parent; current; current = current.parent) { if (current.kind !== ApiItemKind.Namespace) { @@ -783,7 +807,7 @@ export class YamlDocumenter { return nameParts.join('.'); } else { - return Utilities.getConciseSignature(apiItem); + return baseName; } } diff --git a/apps/api-documenter/src/yaml/IYamlApiFile.ts b/apps/api-documenter/src/yaml/IYamlApiFile.ts index 3eb0d7cf5ee..bb50702e7bf 100644 --- a/apps/api-documenter/src/yaml/IYamlApiFile.ts +++ b/apps/api-documenter/src/yaml/IYamlApiFile.ts @@ -27,7 +27,7 @@ export interface IYamlException { * Part of the IYamlApiFile structure. Represents the type of an IYamlItem. */ export type YamlTypeId = 'class' | 'constructor' | 'enum' | 'field' | 'function' | 'interface' - | 'method' | 'package' | 'property' | 'event' | 'typealias' | 'variable'; + | 'method' | 'package' | 'property' | 'event' | 'typealias' | 'variable' | 'namespace'; /** * Part of the IYamlApiFile structure. Represents basic API elements such as diff --git a/apps/api-documenter/src/yaml/typescript.schema.json b/apps/api-documenter/src/yaml/typescript.schema.json index b10570c3a70..016cbdf1ad4 100644 --- a/apps/api-documenter/src/yaml/typescript.schema.json +++ b/apps/api-documenter/src/yaml/typescript.schema.json @@ -129,7 +129,7 @@ "$ref": "#/definitions/syntax" }, "type": { - "enum": [ "class", "constructor", "enum", "field", "function", "interface", "method", "package", "property", "event", "typealias", "variable" ] + "enum": [ "class", "constructor", "enum", "field", "function", "interface", "method", "package", "property", "event", "typealias", "variable", "namespace" ] }, "uid": { "type": "string", diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test.yml index 12fdd60f6f3..779b47ae822 100644 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test.yml +++ b/build-tests/api-documenter-test/etc/yaml/api-documenter-test.yml @@ -24,7 +24,7 @@ items: - 'api-documenter-test!IDocInterface4:interface' - 'api-documenter-test!IDocInterface5:interface' - 'api-documenter-test!IDocInterface6:interface' - - 'api-documenter-test!OuterNamespace.InnerNamespace.nestedFunction:function(1)' + - 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' - 'api-documenter-test!SystemEvent:class' - 'api-documenter-test!yamlReferenceUniquenessTest:function(1)' - uid: 'api-documenter-test!globalFunction:function(1)' @@ -45,24 +45,6 @@ items: description: '' type: - number - - uid: 'api-documenter-test!OuterNamespace.InnerNamespace.nestedFunction:function(1)' - summary: A function inside a namespace - name: OuterNamespace.InnerNamespace.nestedFunction(x) - fullName: OuterNamespace.InnerNamespace.nestedFunction(x) - langs: - - typeScript - type: function - syntax: - content: 'function nestedFunction(x: number): number;' - return: - type: - - number - description: '' - parameters: - - id: x - description: '' - type: - - number - uid: 'api-documenter-test!yamlReferenceUniquenessTest:function(1)' name: yamlReferenceUniquenessTest() fullName: yamlReferenceUniquenessTest() @@ -100,5 +82,7 @@ references: name: IDocInterface5 - uid: 'api-documenter-test!IDocInterface6:interface' name: IDocInterface6 + - uid: 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' + name: OuterNamespace.InnerNamespace - uid: 'api-documenter-test!SystemEvent:class' name: SystemEvent diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.innernamespace.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.innernamespace.yml new file mode 100644 index 00000000000..7b5dc60fd84 --- /dev/null +++ b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.innernamespace.yml @@ -0,0 +1,30 @@ +### YamlMime:UniversalReference +items: + - uid: 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' + summary: A nested namespace + name: OuterNamespace.InnerNamespace + fullName: OuterNamespace.InnerNamespace + langs: + - typeScript + type: namespace + package: api-documenter-test! + children: + - 'api-documenter-test!OuterNamespace.InnerNamespace.nestedFunction:function(1)' + - uid: 'api-documenter-test!OuterNamespace.InnerNamespace.nestedFunction:function(1)' + summary: A function inside a namespace + name: OuterNamespace.InnerNamespace.nestedFunction(x) + fullName: OuterNamespace.InnerNamespace.nestedFunction(x) + langs: + - typeScript + type: function + syntax: + content: 'function nestedFunction(x: number): number;' + return: + type: + - number + description: '' + parameters: + - id: x + description: '' + type: + - number diff --git a/build-tests/api-documenter-test/etc/yaml/toc.yml b/build-tests/api-documenter-test/etc/yaml/toc.yml index 376c3df8b77..2f75c7fc38f 100644 --- a/build-tests/api-documenter-test/etc/yaml/toc.yml +++ b/build-tests/api-documenter-test/etc/yaml/toc.yml @@ -47,5 +47,7 @@ items: uid: 'api-documenter-test!DocEnum:enum' - name: Generic uid: 'api-documenter-test!Generic:class' + - name: OuterNamespace.InnerNamespace + uid: 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' - name: SystemEvent uid: 'api-documenter-test!SystemEvent:class' diff --git a/common/changes/@microsoft/api-documenter/flattenNamespaces2_2019-09-22-01-34.json b/common/changes/@microsoft/api-documenter/flattenNamespaces2_2019-09-22-01-34.json new file mode 100644 index 00000000000..03cfd51ca8e --- /dev/null +++ b/common/changes/@microsoft/api-documenter/flattenNamespaces2_2019-09-22-01-34.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@microsoft/api-documenter", + "comment": "Include namespaces in YAML output", + "type": "minor" + } + ], + "packageName": "@microsoft/api-documenter", + "email": "ron.buckton@microsoft.com" +} \ No newline at end of file From 282d13cd1a93e5027912247b683884f3fe57d866 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 23 Sep 2019 01:12:08 -0700 Subject: [PATCH 2/4] Include additional information in yaml --- .../src/documenters/YamlDocumenter.ts | 150 +++- apps/api-documenter/src/yaml/IYamlApiFile.ts | 753 ++++++++++++++++-- .../src/yaml/typescript.schema.json | 551 ++++++++++--- .../etc/api-documenter-test.api.json | 63 ++ .../etc/api-documenter-test.api.md | 6 + .../api-documenter-test.generictypealias.md | 12 + .../etc/markdown/api-documenter-test.md | 2 + .../markdown/api-documenter-test.typealias.md | 12 + .../etc/yaml/api-documenter-test.yml | 67 ++ .../yaml/api-documenter-test/docclass1.yml | 2 + .../yaml/api-documenter-test/ecmasmbols.yml | 25 + .../api-documenter-test/idocinterface2.yml | 2 + .../outernamespace.innernamespace.yml | 3 +- .../api-documenter-test/outernamespace.yml | 25 + .../api-documenter-test/etc/yaml/toc.yml | 4 + build-tests/api-documenter-test/src/index.ts | 12 +- 16 files changed, 1503 insertions(+), 186 deletions(-) create mode 100644 build-tests/api-documenter-test/etc/markdown/api-documenter-test.generictypealias.md create mode 100644 build-tests/api-documenter-test/etc/markdown/api-documenter-test.typealias.md create mode 100644 build-tests/api-documenter-test/etc/yaml/api-documenter-test/ecmasmbols.yml create mode 100644 build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.yml diff --git a/apps/api-documenter/src/documenters/YamlDocumenter.ts b/apps/api-documenter/src/documenters/YamlDocumenter.ts index d59f2c105da..1a841544c16 100644 --- a/apps/api-documenter/src/documenters/YamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/YamlDocumenter.ts @@ -36,7 +36,10 @@ import { ApiTypeParameterListMixin, Excerpt, ExcerptToken, - ExcerptTokenKind + ExcerptTokenKind, + HeritageType, + ApiVariable, + ApiTypeAlias } from '@microsoft/api-extractor-model'; import { DeclarationReference, @@ -49,7 +52,8 @@ import { IYamlSyntax, IYamlParameter, IYamlReference, - IYamlReferenceSpec + IYamlReferenceSpec, + IYamlInheritanceTree } from '../yaml/IYamlApiFile'; import { IYamlTocFile, @@ -72,6 +76,11 @@ const enum FlattenMode { NoNamespaces } +interface INameOptions { + includeSignature?: boolean; + includeNamespace?: boolean; +} + /** * Writes documentation in the Universal Reference YAML file format, as defined by typescript.schema.json. */ @@ -172,10 +181,13 @@ export class YamlDocumenter { this._writeYamlFile(newYamlFile, yamlFilePath, 'UniversalReference', yamlApiSchema); if (parentYamlFile) { + // References should be recorded in the parent YAML file with the local name of the embedded item. + // This avoids unnecessary repetition when listing items inside of a namespace. this._recordYamlReference( this._ensureYamlReferences(), this._getUid(apiItem), - this._getYamlItemName(apiItem, /*includeSignature*/ true)); + this._getYamlItemName(apiItem, { includeSignature: true }), + this._getYamlItemName(apiItem, { includeNamespace: true, includeSignature: true })); } } @@ -202,17 +214,19 @@ export class YamlDocumenter { private _flattenNamespaces(items: ReadonlyArray, childrenOut: ApiItem[], mode: FlattenMode): boolean { let hasNonNamespaceChildren: boolean = false; for (const item of items) { - if (item.kind === ApiItemKind.Namespace && mode !== FlattenMode.NoNamespaces) { - // At any level, always include a nested namespace if it has non-namespace children, but do not include its - // non-namespace children in the result. + if (item.kind === ApiItemKind.Namespace) { + if (mode !== FlattenMode.NoNamespaces) { + // At any level, always include a nested namespace if it has non-namespace children, but do not include its + // non-namespace children in the result. - // Record the offset at which the namespace is added in case we need to remove it later. - const index: number = childrenOut.length; - childrenOut.push(item); + // Record the offset at which the namespace is added in case we need to remove it later. + const index: number = childrenOut.length; + childrenOut.push(item); - if (!this._flattenNamespaces(item.members, childrenOut, FlattenMode.NestedNamespacesOnly)) { - // This namespace had no non-namespace children, remove it. - childrenOut.splice(index, 1); + if (!this._flattenNamespaces(item.members, childrenOut, FlattenMode.NestedNamespacesOnly)) { + // This namespace had no non-namespace children, remove it. + childrenOut.splice(index, 1); + } } } else if (this._shouldInclude(item.kind)) { if (mode !== FlattenMode.NestedNamespacesOnly) { @@ -278,10 +292,10 @@ export class YamlDocumenter { if (apiItem.kind === ApiItemKind.Package) { name = PackageName.getUnscopedName(apiItem.displayName); } else { - name = this._getYamlItemName(apiItem, /*includeSignature*/ false); + name = this._getYamlItemName(apiItem); } - if (apiItem.getMergedSiblings().length > 1) { + if (name === apiItem.displayName && apiItem.getMergedSiblings().length > 1) { name += ` (${apiItem.kind})`; } @@ -306,8 +320,6 @@ export class YamlDocumenter { case ApiItemKind.CallSignature: case ApiItemKind.ConstructSignature: case ApiItemKind.IndexSignature: - case ApiItemKind.TypeAlias: - case ApiItemKind.Variable: return false; } return true; @@ -354,11 +366,16 @@ export class YamlDocumenter { } } - yamlItem.name = this._getYamlItemName(apiItem, /*includeSignature*/ true); - - yamlItem.fullName = yamlItem.name; + yamlItem.name = this._getYamlItemName(apiItem, { includeSignature: true }); + yamlItem.fullName = this._getYamlItemName(apiItem, { includeSignature: true, includeNamespace: true }); yamlItem.langs = [ 'typeScript' ]; + // Add the namespace of the item if it is contained in one. + // Do not add the namespace parent of a namespace as they are flattened in the documentation. + if (apiItem.kind !== ApiItemKind.Namespace && apiItem.parent && apiItem.parent.kind === ApiItemKind.Namespace) { + yamlItem.namespace = apiItem.parent.canonicalReference.toString(); + } + switch (apiItem.kind) { case ApiItemKind.Enum: yamlItem.type = 'enum'; @@ -413,6 +430,16 @@ export class YamlDocumenter { this._populateYamlFunctionLike(uid, yamlItem, apiItem as ApiFunction); break; + case ApiItemKind.Variable: + yamlItem.type = 'variable'; + this._populateYamlVariable(uid, yamlItem, apiItem as ApiVariable); + break; + + case ApiItemKind.TypeAlias: + yamlItem.type = 'typealias'; + this._populateYamlTypeAlias(uid, yamlItem, apiItem as ApiTypeAlias); + break; + default: throw new Error('Unimplemented item kind: ' + apiItem.kind); } @@ -456,6 +483,7 @@ export class YamlDocumenter { if (apiItem instanceof ApiClass) { if (apiItem.extendsType) { yamlItem.extends = [ this._renderType(uid, apiItem.extendsType.excerpt) ]; + yamlItem.inheritance = this._renderInheritance(uid, [apiItem.extendsType]); } if (apiItem.implementsTypes.length > 0) { yamlItem.implements = []; @@ -469,6 +497,7 @@ export class YamlDocumenter { for (const extendsType of apiItem.extendsTypes) { yamlItem.extends.push(this._renderType(uid, extendsType.excerpt)); } + yamlItem.inheritance = this._renderInheritance(uid, apiItem.extendsTypes); } const typeParameters: IYamlParameter[] = this._populateYamlTypeParameters(uid, apiItem); @@ -565,6 +594,41 @@ export class YamlDocumenter { } } + private _populateYamlVariable(uid: DeclarationReference, yamlItem: Partial, apiItem: ApiVariable): + void { + + const syntax: IYamlSyntax = { + content: apiItem.getExcerptWithModifiers() + }; + yamlItem.syntax = syntax; + + if (apiItem.variableTypeExcerpt.text) { + syntax.return = { + type: [ this._renderType(uid, apiItem.variableTypeExcerpt) ] + }; + } + } + + private _populateYamlTypeAlias(uid: DeclarationReference, yamlItem: Partial, apiItem: ApiTypeAlias): + void { + + const syntax: IYamlSyntax = { + content: apiItem.getExcerptWithModifiers() + }; + yamlItem.syntax = syntax; + + const typeParameters: IYamlParameter[] = this._populateYamlTypeParameters(uid, apiItem); + if (typeParameters.length) { + syntax.typeParameters = typeParameters; + } + + if (apiItem.typeExcerpt.text) { + syntax.return = { + type: [ this._renderType(uid, apiItem.typeExcerpt) ] + }; + } + } + private _renderMarkdown(docSection: DocSection, contextApiItem: ApiItem): string { const stringBuilder: StringBuilder = new StringBuilder(); @@ -649,6 +713,30 @@ export class YamlDocumenter { return this._yamlReferences; } + private _renderInheritance(contextUid: DeclarationReference, heritageTypes: ReadonlyArray): + IYamlInheritanceTree[] { + + const result: IYamlInheritanceTree[] = []; + for (const heritageType of heritageTypes) { + const type: string = this._renderType(contextUid, heritageType.excerpt); + const yamlInheritance: IYamlInheritanceTree = { type }; + const apiItem: ApiItem | undefined = this._apiItemsByCanonicalReference.get(type); + if (apiItem) { + if (apiItem instanceof ApiClass) { + if (apiItem.extendsType) { + yamlInheritance.inheritance = this._renderInheritance(this._getUidObject(apiItem), [apiItem.extendsType]); + } + } else if (apiItem instanceof ApiInterface) { + if (apiItem.extendsTypes.length > 0) { + yamlInheritance.inheritance = this._renderInheritance(this._getUidObject(apiItem), apiItem.extendsTypes); + } + } + } + result.push(yamlInheritance); + } + return result; + } + private _renderType(contextUid: DeclarationReference, typeExcerpt: Excerpt): string { const excerptTokens: ExcerptToken[] = typeExcerpt.tokens.slice( typeExcerpt.tokenRange.startIndex, @@ -686,10 +774,13 @@ export class YamlDocumenter { if (excerptTokens.length === 1 && excerptTokens[0].kind === ExcerptTokenKind.Reference && excerptTokens[0].canonicalReference) { + const excerptRef: string = excerptTokens[0].canonicalReference.toString(); + const apiItem: ApiItem | undefined = this._apiItemsByCanonicalReference.get(excerptRef); return this._recordYamlReference( yamlReferences, excerptTokens[0].canonicalReference.toString(), - typeName + apiItem ? this._getYamlItemName(apiItem) : typeName, + apiItem ? this._getYamlItemName(apiItem, { includeNamespace: true }) : typeName ); } @@ -711,10 +802,10 @@ export class YamlDocumenter { .withOverloadIndex(undefined) .toString(); - return this._recordYamlReference(yamlReferences, uid, typeName, excerptTokens); + return this._recordYamlReference(yamlReferences, uid, typeName, typeName, excerptTokens); } - private _recordYamlReference(yamlReferences: IYamlReferences, uid: string, typeName: string, + private _recordYamlReference(yamlReferences: IYamlReferences, uid: string, name: string, fullName: string, excerptTokens?: ExcerptToken[]): string { if (yamlReferences.references.some(ref => ref.uid === uid)) { @@ -758,17 +849,24 @@ export class YamlDocumenter { yamlReference.name = specs.map(s => s.name).join('').trim(); yamlReference.fullName = specs.map(s => s.fullName || s.name).join('').trim(); yamlReference['spec.typeScript'] = specs; - } else if (typeName !== uid) { - yamlReference.name = typeName; + } else { + if (name !== uid) { + yamlReference.name = name; + } + if (fullName !== uid && fullName !== name) { + yamlReference.fullName = fullName; + } } yamlReferences.references.push(yamlReference); return uid; } - private _getYamlItemName(apiItem: ApiItem, includeSignature: boolean): string { + private _getYamlItemName(apiItem: ApiItem, options: INameOptions = {}): string { + const { includeSignature, includeNamespace } = options; const baseName: string = includeSignature ? Utilities.getConciseSignature(apiItem) : apiItem.displayName; - if (apiItem.parent && apiItem.parent.kind === ApiItemKind.Namespace) { + if ((includeNamespace || apiItem.kind === ApiItemKind.Namespace) && apiItem.parent && + apiItem.parent.kind === ApiItemKind.Namespace) { // If the immediate parent is a namespace, then add the namespaces to the name. For example: // // // Name: "N1" diff --git a/apps/api-documenter/src/yaml/IYamlApiFile.ts b/apps/api-documenter/src/yaml/IYamlApiFile.ts index bb50702e7bf..66fcb5d8129 100644 --- a/apps/api-documenter/src/yaml/IYamlApiFile.ts +++ b/apps/api-documenter/src/yaml/IYamlApiFile.ts @@ -4,125 +4,750 @@ /** * TypeScript interface describing a Universal Reference YAML documentation file, * as defined by typescript.schema.json. + * + * NOTE: Corresponds to `Microsoft.DocAsCode.DataContracts.UniversalReference.PageViewModel` in DocFX. */ export interface IYamlApiFile { + /** + * The items contained in this file. + * + * NOTE: Corresponds to `ExceptionInfo.Items` in DocFX. + */ items: IYamlItem[]; - references?: IYamlReference[]; -} -export interface IYamlDeprecatedNotice { - content: string; -} + /** + * References to other items. + * + * NOTE: Corresponds to `ExceptionInfo.References` in DocFX. + */ + references?: IYamlReference[]; -/** - * Part of the IYamlApiFile structure. Used to document exceptions that can be thrown - * by a method, property, function, or constructor. - */ -export interface IYamlException { - description?: string; - tupe?: string; + /** + * NOTE: Corresponds to `ExceptionInfo.ShouldSkipMarkup` in DocFX. + */ + shouldSkipMarkup?: boolean; } /** - * Part of the IYamlApiFile structure. Represents the type of an IYamlItem. - */ -export type YamlTypeId = 'class' | 'constructor' | 'enum' | 'field' | 'function' | 'interface' - | 'method' | 'package' | 'property' | 'event' | 'typealias' | 'variable' | 'namespace'; - -/** - * Part of the IYamlApiFile structure. Represents basic API elements such as + * Part of the IYamlApiFile structure. Represents basic API elements such as * classes, interfaces, members, etc. + * + * NOTE: Corresponds to `Microsoft.DocAsCode.DataContracts.UniversalReference.ItemViewModel` in DocFX. */ export interface IYamlItem { - type: YamlTypeId; + /** + * The Unique Identifier (UID) for this item. + * + * NOTE: Corresponds to `ItemViewModel.Uid` in DocFX. + */ + uid: string; + + /** + * A Roslyn comment ID (unused). + * + * NOTE: Corresponds to `ItemViewModel.CommentId` in DocFX. + */ + commentId?: string; + + /** + * The ID for this item. + * + * NOTE: Corresponds to `ItemViewModel.Id` in DocFX. + */ + id?: string; + + /** + * The Unique Identifier (UID) of the parent item. This value can vary by development language + * by setting the relevant `parent.${lang}` property. + * + * NOTE: Corresponds to `ItemViewModel.Parent` in DocFX. + * NOTE: Corresponds to `ItemViewModel.ParentInDevLangs` in DocFX when `parent.${lang}` is used. + */ + parent?: string; + 'parent.typeScript'?: string; + /** + * The Unique Identifiers (UID) of the children of this item. This value can vary by development language + * by setting the relevant `children.${lang}` property. + * + * NOTE: Corresponds to `ItemViewModel.Children` in DocFX. + * NOTE: Corresponds to `ItemViewModel.ChildrenInDevLangs` in DocFX when `children.${lang}` is used. + */ children?: string[]; - deprecated?: IYamlDeprecatedNotice; - exceptions?: IYamlException[]; - extends?: string[]; + 'children.typeScript'?: string[]; + + /** + * Item's link URL. An item can only have a single link in cross references, so varying `href` by development + * languages is not supported. + * + * NOTE: Corresponds to `ItemViewModel.Href` in DocFX. + */ + href?: string; + + /** + * The development languages supported by this item. + * + * NOTE: Corresponds to `ItemViewModel.SupportedLanguages` in DocFX. + */ + langs?: YamlDevLangs[]; + + /** + * The local name of this item. This name should generally not be namespace qualified or include + * parent type information. This value can vary by development language by setting the relevant + * `name.${lang}` property. + * + * NOTE: Corresponds to `ItemViewModel.Name` in DocFX. + * NOTE: Corresponds to `ItemViewModel.Names` in DocFX when `name.${lang}` is used. + */ + name?: string; + 'name.typeScript'?: string; + + /** + * The name of this item including its parent type, if it has one. This name should generally not be namespace + * qualified. This value can vary by development language by setting the relevant `nameWithType.${lang}` property. + * + * NOTE: Corresponds to `ItemViewModel.NameWithType` in DocFX. + * NOTE: Corresponds to `ItemViewModel.NamesWithType` in DocFX when `nameWithType.${lang}` is used. + */ + nameWithType?: string; + 'nameWithType.typeScript'?: string; + + /** + * The namespace-qualified name of this item including its parent type. This value can vary by development language + * by setting the relevant `fullName.${lang}` property. + * + * NOTE: Corresponds to `ItemViewModel.FullName` in DocFX. + * NOTE: Corresponds to `ItemViewModel.FullNames` in DocFX when `fullName.${lang}` is used. + */ fullName?: string; + 'fullName.typeScript'?: string; + + /** + * The type of source element this item represents. This value cannot vary by development language. + * + * NOTE: Corresponds to `ItemViewModel.Type` in DocFX. + */ + type: YamlTypeId; + + /** + * The location of the item's source. This value can vary by development language by setting the relevant + * `source.${lang}` property. + * + * NOTE: Corresponds to `ItemViewModel.Source` in DocFX. + * NOTE: Corresponds to `ItemViewModel.SourceInDevLangs` in DocFX when `source.${lang}` is used. + */ + source?: IYamlSource; + 'source.typeScript'?: IYamlSource; + + /** + * The location of the item's documentation overrides. This value cannot vary by development language. + * + * NOTE: Corresponds to `ItemViewModel.Documentation` in DocFX. + */ + documentation?: IYamlSource; + + /** + * The names of managed assemblies that contain this item. This value can vary by development language by setting + * the relevant `assemblies.${lang}` property. + * + * NOTE: Corresponds to `ItemViewModel.AssemblyNameList` in DocFX. + * NOTE: Corresponds to `ItemViewModel.AssemblyNameListInDevLangs` in DocFX when `assemblies.${lang}` is used. + */ + assemblies?: string[]; + 'assemblies.typeScript'?: string[]; + + /** + * The Unique Identifier (UID) of the namespace that contains this item. This value can vary by development language + * by setting the relevant `namespace.${lang}` property. + * + * NOTE: Corresponds to `ItemViewModel.NamespaceName` in DocFX. + * NOTE: Corresponds to `ItemViewModel.NamespaceNameInDevLangs` in DocFX. + */ + namespace?: string; + 'namespace.typeScript'?: string; + + /** + * The summary for the item. This value cannot vary by development language. + * Markdown is permitted. + * + * NOTE: Corresponds to `ItemViewModel.Summary` in DocFX. + */ + summary?: string; + + /** + * The remarks for the item. This value cannot vary by development language. + * Markdown is permitted. + * + * NOTE: Corresponds to `ItemViewModel.Remarks` in DocFX. + */ + remarks?: string; + + /** + * The examples for the item. This value cannot vary by development language. + * Markdown is permitted. + * + * NOTE: Corresponds to `ItemViewModel.Examples` in DocFX. + */ + examples?: string[]; + + /** + * The syntax for this item. This value itself cannot vary by development language, but + * instead contains properties that may vary by development language. + * + * NOTE: Corresponds to `ItemViewModel.Syntax` in DocFX. + */ + syntax?: IYamlSyntax; + + /** + * The Unique Identifier (UID) of the member this item overrides. This value can vary by development language + * by setting the relevant `overridden.${lang}` property. + * + * NOTE: Corresponds to `ItemViewModel.Overridden` in DocFX. + * NOTE: Corresponds to `ItemViewModel.OverriddenInDevLangs` in DocFX when `overriden.${lang}` is used. + */ + overridden?: string; + 'overridden.typeScript'?: string; + + /** + * The Unique Identifier (UID) of the member this item overloads. This value can vary by development language + * by setting the relevant `overload.${lang}` property. + * + * NOTE: Corresponds to `ItemViewModel.Overload` in DocFX. + * NOTE: Corresponds to `ItemViewModel.OverloadInDevLangs` in DocFX when `overload.${lang}` is used. + */ + overload?: string; + 'overload.typeScript'?: string; + + /** + * The exceptions thrown by this item. This value can vary by development language by setting the relevant + * `exceptions.${lang}` property. + * + * NOTE: Corresponds to `ItemViewModel.Exceptions` in DocFX. + * NOTE: Corresponds to `ItemViewModel.ExceptionsInDevLangs` in DocFX when `exceptions.${lang}` is used. + */ + exceptions?: IYamlException[]; + 'exceptions.typeScript'?: IYamlException[]; + + /** + * Links to additional content related to this item. + * + * NOTE: Corresponds to `ItemViewModel.SeeAlsos` in DocFX. + */ + seealso?: IYamlLink[]; + + /** + * Additional information about other content related to this item. + * Markdown is permitted. + * + * NOTE: Corresponds to `ItemViewModel.SeeAlsoContent` in DocFX. + */ + seealsoContent?: string; + + /** + * Links to additional content related to this item. + * + * NOTE: Corresponds to `ItemViewModel.Sees` in DocFX. + */ + see?: IYamlLink[]; + + /** + * The inheritance tree for this item. Multiple inheritance is permitted for languages like Python. + * + * NOTE: Corresponds to `ItemViewModel.Inheritance` in DocFX. + * NOTE: Corresponds to `ItemViewModel.InheritanceInDevLangs` in DocFX when `inheritance.${lang}` is used. + */ + inheritance?: IYamlInheritanceTree[]; + 'inheritance.typeScript'?: IYamlInheritanceTree[]; + + /** + * NOTE: Corresponds to `ItemViewModel.DerivedClassses` in DocFX. + * NOTE: Corresponds to `ItemViewModel.DerivedClasssesInDevLangs` in DocFX when `derivedClasses.${lang}` is used. + */ + derivedClasses?: string[]; + 'derivedClasses.typeScript'?: string[]; + + /** + * NOTE: Corresponds to `ItemViewModel.Implements` in DocFX. + * NOTE: Corresponds to `ItemViewModel.ImplementsInDevLangs` in DocFX when `implements.${lang}` is used. + */ implements?: string[]; + 'implements.typeScript'?: string[]; + + /** + * NOTE: Corresponds to `ItemViewModel.InheritedMembers` in DocFX. + * NOTE: Corresponds to `ItemViewModel.InheritedMembersInDevLangs` in DocFX when `inheritedMembers.${lang}` is used. + */ + inheritedMembers?: string[]; + 'inheritedMembers.typeScript'?: string[]; + + /** + * NOTE: Corresponds to `ItemViewModel.ExtensionMethods` in DocFX. + * NOTE: Corresponds to `ItemViewModel.ExtensionMethodsInDevLangs` in DocFX when `extensionMethods.${lang}` is used. + */ + extensionMethods?: string[]; + 'extensionMethods.typeScript'?: string[]; + + /** + * NOTE: Corresponds to `ItemViewModel.Conceptual` in DocFX. + */ + conceptual?: string; + + /** + * NOTE: Corresponds to `ItemViewModel.Platform` in DocFX. + * NOTE: Corresponds to `ItemViewModel.PlatformInDevLangs` in DocFX when `platform.${lang}` is used. + */ + platform?: string[]; + 'platform.typeScript'?: string[]; + + /** + * NOTE: This is an extension and corresponds to `ItemViewModel.Metadata` in DocFX. + */ + deprecated?: IYamlDeprecatedNotice; + + /** + * NOTE: This is an extension and corresponds to `ItemViewModel.Metadata` in DocFX. + */ + extends?: string[]; + + /** + * NOTE: This is an extension and corresponds to `ItemViewModel.Metadata` in DocFX. + */ isPreview?: boolean; - langs?: string[]; - name?: string; + /** * NOTE: In TypeScript, enum members can be strings or integers. * If it is an integer, then enumMember.value will be a string representation of the integer. * If it is a string, then enumMember.value will include the quotation marks. + * + * NOTE: This is an extension and corresponds to `ItemViewModel.Metadata` in DocFX. */ numericValue?: string; + + /** + * NOTE: This is an extension and corresponds to `ItemViewModel.Metadata` in DocFX. + */ package?: string; - source?: IYamlSource; - summary?: string; - remarks?: string; - syntax?: IYamlSyntax; - uid: string; } /** - * Part of the IYamlApiFile structure. Represents a method or function parameter. + * Part of the IYamlApiFile structure. Represents the type of an IYamlItem. */ -export interface IYamlParameter { - description?: string; - id?: string; - type?: string[]; -} +export type YamlTypeId = + | 'class' + | 'constructor' + | 'enum' + | 'field' + | 'function' + | 'interface' + | 'method' + | 'package' + | 'property' + | 'event' + | 'typealias' + | 'variable' + | 'namespace' + ; /** - * Part of the IYamlApiFile structure. Represents a reference to an item that is - * declared in a separate YAML file. + * Development languages supported by the Universal Reference file format, as defined by typescript.schema.json. */ -export interface IYamlReference { - uid?: string; - name?: string; - fullName?: string; - 'spec.typeScript'?: IYamlReferenceSpec[]; -} +export type YamlDevLangs = + | 'typeScript' + ; /** - * Part of the IYamlApiFile structure. Represents a text specification for a reference. + * Part of the IYamlApiFile structure. Documents the source file where an IYamlItem is defined. + * + * NOTE: Corresponds to `Microsoft.DocAsCode.DataContracts.Common.SourceDetail` in DocFX. */ -export interface IYamlReferenceSpec { - uid?: string; - name?: string; - fullName?: string; +export interface IYamlSource { + /** + * Information about the Git repository where this source can be found. + * + * NOTE: Corresponds to `SourceDetail.Remote` in DocFX. + */ + remote?: IYamlRemote; + + /** + * The base path for the source for this item. + * + * NOTE: Corresponds to `SourceDetail.BasePath` in DocFX. + */ + basePath?: string; + + /** + * The name of the item. + * + * NOTE: Corresponds to `SourceDetail.Name` in DocFX. + */ + id?: string; + + /** + * A link to the source for this item. + * + * NOTE: Corresponds to `SourceDetail.Href` in DocFX. + */ + href?: string; + + /** + * The path to the source for this item. This path will be made relative to `basePath` in the documentation. + * + * NOTE: Corresponds to `SourceDetail.Path` in DocFX. + */ + path?: string; + + /** + * The starting line of the source for this item. + * + * NOTE: Corresponds to `SourceDetail.StartLine` in DocFX. + */ + startLine?: number; + + /** + * The ending line of the source for this item. + * + * NOTE: Corresponds to `SourceDetail.EndLine` in DocFX. + */ + endLine?: number; + + /** + * The content of the source for this item. + * + * NOTE: Corresponds to `SourceDetail.Content` in DocFX. + */ + content?: string; + + /** + * Indicates whether the path to the source is not locally available. + * + * NOTE: Corresponds to `SourceDetail.IsExternal` in DocFX. + */ + isExternal?: boolean; } /** * Part of the IYamlApiFile structure. Indicates the open source Git repository * where an IYamlItem is defined. + * + * NOTE: Corresponds to `Microsoft.DocAsCode.DataContracts.Common.GitDetail` in DocFX. */ export interface IYamlRemote { - branch?: string; + /** + * The relative path of the current item to the Git repository root directory. + * + * NOTE: Corresponds to `GitDetail.RelativePath` in DocFX. + */ path?: string; + + /** + * The Git branch in which this item can be found. + * + * NOTE: Corresponds to `GitDetail.RemoteBranch` in DocFX. + */ + branch?: string; + + /** + * The Git repository in which this item can be found. + * + * NOTE: Corresponds to `GitDetail.RemoteRepositoryUrl` in DocFX. + */ repo?: string; } /** - * Part of the IYamlApiFile structure. Documents the return value of a function + * Part of the IYamlApiFile structure. Documents the type signature for an IYamlItem. + * + * NOTE: Corresponds to `Microsoft.DocAsCode.DataContracts.UniversalReference.SyntaxDetailViewModel` in DocFX. + */ +export interface IYamlSyntax { + /** + * The content for the syntax of this item. + * + * NOTE: Corresponds to `SyntaxDetailViewModel.Content` in DocFX. + * NOTE: Corresponds to `SyntaxDetailViewModel.Contents` in DocFX when `content.${lang}` is used. + */ + content?: string; + 'content.typeScript'?: string; + + /** + * The parameters for this item. + * + * NOTE: Corresponds to `SyntaxDetailViewModel.Parameters` in DocFX. + */ + parameters?: IYamlParameter[]; + + /** + * The type parameters for this item. + * + * NOTE: Corresponds to `SyntaxDetailViewModel.TypeParameters` in DocFX. + */ + typeParameters?: IYamlParameter[]; + + /** + * The return type for this item. + * + * NOTE: Corresponds to `SyntaxDetailViewModel.Return` in DocFX. + * NOTE: Corresponds to `SyntaxDetailViewModel.ReturnInDevLangs` in DocFX when `return.${lang}` is used. + */ + return?: IYamlReturn; + 'return.typeScript'?: IYamlReturn; +} + +/** + * Part of the IYamlApiFile structure. Represents a method or function parameter. + * + * NOTE: Corresponds to `Microsoft.DocAsCode.DataContracts.UniversalReference.ApiParameter` in DocFX. + */ +export interface IYamlParameter { + /** + * The name of the parameter. + * + * NOTE: Corresponds to `ApiParameter.Name` in DocFX. + */ + id?: string; + + /** + * The Unique Identifiers (UIDs) of the types for this parameter. + * + * NOTE: Corresponds to `ApiParameter.Type` in DocFX. + */ + type?: string[]; + + /** + * The description for this parameter. + * Markdown is permitted. + * + * NOTE: Corresponds to `ApiParameter.Description` in DocFX. + */ + description?: string; + + /** + * Indicates whether the parameter is optional. + * + * NOTE: Corresponds to `ApiParameter.Optional` in DocFX. + */ + optional?: boolean; + + /** + * The default value for the parameter. + * + * NOTE: Corresponds to `ApiParameter.DefaultValue` in DocFX. + */ + defaultValue?: string; +} + +/** + * Part of the IYamlApiFile structure. Documents the return value of a function * or method. + * + * NOTE: Corresponds to `Microsoft.DocAsCode.DataContracts.UniversalReference.ApiParameter` in DocFX. */ export interface IYamlReturn { - description?: string; + /** + * The Unique Identifiers (UIDs) of the types for this parameter. + * + * NOTE: Corresponds to `ApiParameter.Type` in DocFX. + */ type?: string[]; + + /** + * The description for this parameter. + * Markdown is permitted. + * + * NOTE: Corresponds to `ApiParameter.Description` in DocFX. + */ + description?: string; } /** - * Part of the IYamlApiFile structure. Documents the source file where an IYamlItem is defined. + * Part of the IYamlApiFile structure. Used to document exceptions that can be thrown + * by a method, property, function, or constructor. + * + * NOTE: Corresponds to `Microsoft.DocAsCode.DataContracts.UniversalReference.ExceptionInfo` in DocFX. */ -export interface IYamlSource { - id?: string; - path?: string; - remote?: IYamlRemote; - startLine?: number; +export interface IYamlException { + /** + * The Unique Identifier (UID) of the type for this exception. + * + * NOTE: Corresponds to `ExceptionInfo.Type` in DocFX. + */ + type?: string; + + /** + * The description for this exception. + * + * NOTE: Corresponds to `ExceptionInfo.Description` in DocFX. + */ + description?: string; } /** - * Part of the IYamlApiFile structure. Documents the type signature for an IYamlItem. + * Part of the IYamlApiFile structure. Used to indicate links to external content or other documentation. + * + * NOTE: Corresponds to `Microsoft.DocAsCode.DataContracts.UniversalReference.LinkInfo` in DocFX. */ -export interface IYamlSyntax { - content?: string; - parameters?: IYamlParameter[]; - typeParameters?: IYamlParameter[]; - return?: IYamlReturn; +export interface IYamlLink { + /** + * The type of link. + * + * The value `"CRef"` indicates that `linkId` is a Unique Identifier (UID) reference to + * another documentation entry. + * + * The value `"HRef"` indicates that `linkId` is a link to external documentation. + * NOTE: Corresponds to `LinkInfo.LinkType` in DocFX. + */ + linkType: 'CRef' | 'HRef'; + + /** + * When `linkType` is `"CRef"`, this is a Unique Identifier (UID) reference to another documentation entry. + * + * When `linkType` is `"HRef"`, this is a link to external documentation. + * + * NOTE: Corresponds to `LinkInfo.LinkId` in DocFX. + */ + linkId: string; + + /** + * A Roslyn comment ID for this link. + * + * NOTE: Corresponds to `LinkInfo.CommentId` in DocFX. + */ + commentId?: string; + + /** + * Alternate text to display for thie link. + * + * NOTE: Corresponds to `LinkInfo.AltText` in DocFX. + */ + altText?: string; +} + +/** + * Part of the IYamlApiFile structure. Represents the inheritance hierarchy of an item. + * + * NOTE: Corresponds to `Microsoft.DocAsCode.DataContracts.UniversalReference.InheritanceTree` in DocFX. + */ +export interface IYamlInheritanceTree { + /** + * The Unique Identifier (UID) of the type from which an item or type inherits. + * + * NOTE: Corresponds to `InheritanceTree.Type` in DocFX. + */ + type: string; + + /** + * The inheritance tree for the specified type. Multiple inheritance is permitted for languages like Python. + * + * NOTE: Corresponds to `InheritanceTree.Inheritance` in DocFX. + */ + inheritance?: IYamlInheritanceTree[]; +} + +/** + * Part of the IYamlApiFile structure. Represents a reference to an item that is + * declared in a separate YAML file. + * + * NOTE: Corresponds to `Microsoft.DocAsCode.DataContracts.Common.ReferenceViewModel` in DocFX. + */ +export interface IYamlReference { + /** + * NOTE: Corresponds to `ReferenceViewModel.Uid` in DocFX. + */ + uid?: string; + + /** + * NOTE: Corresponds to `ReferenceViewModel.CommentId` in DocFX. + */ + commentId?: string; + + /** + * NOTE: Corresponds to `ReferenceViewModel.Parent` in DocFX. + */ + parent?: string; + + /** + * NOTE: Corresponds to `ReferenceViewModel.Definition` in DocFX. + */ + definition?: string; + + /** + * NOTE: Corresponds to `ReferenceViewModel.IsExternal` in DocFX. + */ + isExternal?: boolean; + + /** + * NOTE: Corresponds to `ReferenceViewModel.Href` in DocFX. + */ + href?: string; + + /** + * NOTE: Corresponds to `ReferenceViewModel.Name` in DocFX. + * NOTE: Corresponds to `ReferenceViewModel.NameInDevLangs` in DocFX when `name.${lang}` is used. + */ + name?: string; + 'name.typeScript'?: string; + + /** + * NOTE: Corresponds to `ReferenceViewModel.NameWithType` in DocFX. + * NOTE: Corresponds to `ReferenceViewModel.NameWithTypeInDevLangs` in DocFX when `nameWithType.${lang}` is used. + */ + nameWithType?: string; + 'nameWithType.typeScript'?: string; + + /** + * NOTE: Corresponds to `ReferenceViewModel.FullName` in DocFX. + * NOTE: Corresponds to `ReferenceViewModel.FullNameInDevLangs` in DocFX when `fullName.${lang}` is used. + */ + fullName?: string; + 'fullName.typeScript'?: string; + + /** + * NOTE: Corresponds to `ReferenceViewModel.Spec` in DocFX. + */ + 'spec.typeScript'?: IYamlReferenceSpec[]; +} + +/** + * Part of the IYamlApiFile structure. Represents a text specification for a reference. + * + * NOTE: Corresponds to `Microsoft.DocAsCode.DataContracts.Common.SpecViewModel` in DocFX. + */ +export interface IYamlReferenceSpec { + /** + * NOTE: Corresponds to `SpecViewModel.Uid` in DocFX. + */ + uid?: string; + + /** + * NOTE: Corresponds to `SpecViewModel.Name` in DocFX. + */ + name?: string; + + /** + * NOTE: Corresponds to `SpecViewModel.NameWithType` in DocFX. + */ + nameWithType?: string; + + /** + * NOTE: Corresponds to `SpecViewModel.FullName` in DocFX. + */ + fullName?: string; + + /** + * NOTE: Corresponds to `SpecViewModel.IsExternal` in DocFX. + */ + isExternal?: boolean; + + /** + * NOTE: Corresponds to `SpecViewModel.Href` in DocFX. + */ + href?: string; +} + +/** + * NOTE: This is an extension to the Universal Reference format and does not correspond to + * a known type in DocFX. + */ +export interface IYamlDeprecatedNotice { + content: string; } diff --git a/apps/api-documenter/src/yaml/typescript.schema.json b/apps/api-documenter/src/yaml/typescript.schema.json index 016cbdf1ad4..83e55daf678 100644 --- a/apps/api-documenter/src/yaml/typescript.schema.json +++ b/apps/api-documenter/src/yaml/typescript.schema.json @@ -1,5 +1,5 @@ { - "title": "Universal Reference YAML Schema for TypeScript", + "title": "Universal Reference YAML Schema for DocFX", "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "additionalProperties": false, @@ -17,45 +17,45 @@ "uniqueItems": true }, "references": { + "description": "References to other items.", "type": "array", "items": { "$ref": "#/definitions/reference" }, "minItems": 1, "uniqueItems": true + }, + "shouldSkipMarkup": { + "type": "boolean" } }, "definitions":{ - "deprecated": { - "type": "object", - "additionalProperties": false, - "properties": { - "content": { - "description": "The string following the default obsolete message. Supports markdown.", - "type": "string" - } - } - }, - "exception": { - "type": "object", - "additionalProperties": false, - "properties": { - "description": { - "type": "string" - }, - "type": { - "type": "string" - } - } - }, "item": { + "description": "Represents basic API elements such as classes, interfaces, members, etc.", "type": "object", "additionalProperties": false, "required": [ "uid" ], "properties": { + "uid": { + "description": "A value that uniquely identifies this item among all other documentation elements. (ex: Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject`2)", + "type": "string" + }, + "commentId": { + "description": "A Roslyn comment ID.", + "type": "string" + }, + "id": { + "description": "An ID for the item.", + "type": "string" + }, + "parent": { + "description": "A UID reference to the parent of this item.", + "type": "string" + }, "children": { + "description": "A list of UID references to the children of this item.", "type": "array", "items": { "type": "string" @@ -63,10 +63,87 @@ "minItems": 1, "uniqueItems": true }, - "deprecated": { - "$ref": "#/definitions/deprecated" + "href": { + "description": "A link URL for the item.", + "type": "string" + }, + "langs": { + "description": "The development languages supported by this item", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "name": { + "description": "The local name of the item (ex: AnonymousObject). This name should generally not be namespace qualified and should not include parent type information.", + "type": "string" + }, + "nameWithType": { + "description": "The name of the item including its parent type (ex: Colors.Red). This name should generally not be namespace qualified.", + "type": "string" + }, + "fullName": { + "description": "The full-qualified name of the item (ex: Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject).", + "type": "string" + }, + "type": { + "description": "The type of source element this item represents", + "enum": [ "class", "constructor", "enum", "field", "function", "interface", "method", "package", "property", "event", "typealias", "variable", "namespace" ] + }, + "source": { + "description": "The source details for the item", + "$ref": "#/definitions/source" + }, + "documentation": { + "description": "Overrides the source details for the item.", + "$ref": "#/definitions/source" + }, + "assemblies": { + "description": "The names of managed assemblies that contain this item.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "namespace": { + "description": "The UID of the namespace that contains this item.", + "type": "string" + }, + "summary": { + "description": "The summary for the item. Markdown is permitted", + "type": "string" + }, + "remarks": { + "description": "The remarks for the item. Markdown is permitted", + "type": "string" + }, + "examples": { + "description": "The examples for the item. Markdown is permitted", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "syntax": { + "description": "The syntax for this item.", + "$ref": "#/definitions/syntax" + }, + "overridden": { + "description": "The UID of the member this item overrides.", + "type": "string" + }, + "overload": { + "description": "The UID of the member this item overloads.", + "type": "string" }, "exceptions": { + "description": "The exceptions thrown by this item.", "type": "array", "items": { "$ref": "#/definitions/exception" @@ -74,19 +151,48 @@ "minItems": 1, "uniqueItems": true }, - "extends": { + "seealso": { + "description": "Links to additional content related to this item.", "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/link" }, "minItems": 1, "uniqueItems": true }, - "fullName": { - "type": "string", - "description": "The full friendly name of the object. (ex: Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject)" + "seealsoContent": { + "description": "Additional information about other content related to this item. Markdown is permitted.", + "type": "string" + }, + "see": { + "description": "Links to additional content related to this item.", + "type": "array", + "items": { + "$ref": "#/definitions/link" + }, + "minItems": 1, + "uniqueItems": true + }, + "inheritance": { + "description": "The inheritance tree for this item. Multiple inherited is permitted if the underlying language supports it.", + "type": "array", + "items": { + "$ref": "#/definitions/inheritance" + }, + "minItems": 1, + "uniqueItems": true + }, + "derivedClasses": { + "description": "A list of UIDs for items derived from this item.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true }, "implements": { + "description": "A list of UIDs for the items this item implements.", "type": "array", "items": { "type": "string" @@ -94,10 +200,17 @@ "minItems": 1, "uniqueItems": true }, - "isPreview": { - "type": "boolean" + "inheritedMembers": { + "description": "A list of UIDs for the members this item inherits.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true }, - "langs": { + "extensionMethods": { + "description": "A list of UIDs for extension methods for this item.", "type": "array", "items": { "type": "string" @@ -105,9 +218,33 @@ "minItems": 1, "uniqueItems": true }, - "name": { - "type": "string", - "description": "The name of the object. (ex: AnonymousObject)" + "conceptual": { + "description": "The conceptual text for this item.", + "type": "string" + }, + "platform": { + "description": "The platforms supported by this item.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + + "deprecated": { + "$ref": "#/definitions/deprecated" + }, + "extends": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "isPreview": { + "type": "boolean" }, "numericValue": { "type": "string", @@ -115,93 +252,227 @@ }, "package": { "type": "string" + } + }, + "patternProperties": { + "^parent\\.": { + "description": "A UID reference to the parent of this item for a specific development language.", + "type": "string" }, - "source": { + "^children\\.": { + "description": "A list of UID references to the children of this item for a specific development language.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "^name\\.": { + "description": "The local name of the item (ex: AnonymousObject) for a specific development language. This name should generally not be namespace qualified and should not include parent type information.", + "type": "string" + }, + "^nameWithType\\.": { + "description": "The name of the item including its parent type (ex: Colors.Red) for a specific development language. This name should generally not be namespace qualified.", + "type": "string" + }, + "^fullName\\.": { + "description": "The full-qualified name of the item (ex: Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject) for a specific development language.", + "type": "string" + }, + "^source\\.": { + "description": "The source details for the item for a specific development language.", "$ref": "#/definitions/source" }, - "summary": { + "^assemblies\\.": { + "description": "The names of managed assemblies that contain this item for a specific development language.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "^namespace\\.": { + "description": "The UID of the namespace that contains this item for a specific development language.", "type": "string" }, - "remarks": { + "^overridden\\.": { + "description": "The UID of the member this item overrides for a specific development language.", "type": "string" }, - "syntax": { - "$ref": "#/definitions/syntax" + "^overload\\.": { + "description": "The UID of the member this item overloads for a specific development language.", + "type": "string" }, - "type": { - "enum": [ "class", "constructor", "enum", "field", "function", "interface", "method", "package", "property", "event", "typealias", "variable", "namespace" ] + "^exceptions\\.": { + "description": "The exceptions thrown by this item for a specific development language.", + "type": "array", + "items": { + "$ref": "#/definitions/exception" + }, + "minItems": 1, + "uniqueItems": true }, - "uid": { - "type": "string", - "description": "The fully qualified name of the object. (ex: Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject`2)" + "^inheritance\\.": { + "description": "The inheritance tree for this item for a specific development language. Multiple inherited is permitted if the underlying language supports it.", + "type": "array", + "items": { + "$ref": "#/definitions/inheritance" + }, + "minItems": 1, + "uniqueItems": true + }, + "^derivedClasses\\.": { + "description": "A list of UIDs for items derived from this item for a specific development language.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "^implements\\.": { + "description": "A list of UIDs for the items this item implements for a specific development language.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "^inheritedMembers\\.": { + "description": "A list of UIDs for the members this item inherits for a specific development language.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "^extensionMethods\\.": { + "description": "A list of UIDs for extension methods for this item for a specific development language.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "^platform\\.": { + "description": "The platforms supported by this item for a specific development language.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true } } }, - "parameter": { + "source": { "type": "object", - "additionalProperties": false, "properties": { - "description": { + "remote": { + "$ref": "#/definitions/remote" + }, + "basePath": { "type": "string" }, "id": { "type": "string" }, - "type": { - "type": "array", - "items": { - "type": "string" - } + "href": { + "type": "string" + }, + "path": { + "type": "string" + }, + "startLine": { + "type": "integer" + }, + "endLine": { + "type": "integer" + }, + "content": { + "type": "string" + }, + "isExternal": { + "type": "boolean" } } }, - "reference": { + "remote": { "type": "object", "additionalProperties": false, "properties": { - "uid": { + "path": { "type": "string" }, - "name": { + "branch": { "type": "string" }, - "fullName": { + "repo": { "type": "string" - }, - "spec.typeScript": { - "type": "array", - "items": { - "$ref": "#/definitions/spec" - } } } }, - "spec": { + "syntax": { "type": "object", "additionalProperties": false, "properties": { - "uid": { + "content": { "type": "string" }, - "name": { - "type": "string" + "parameters": { + "type": "array", + "items": { + "$ref": "#/definitions/parameter" + }, + "minItems": 1, + "uniqueItems": true }, - "fullName": { + "typeParameters": { + "type": "array", + "items": { + "$ref": "#/definitions/parameter" + }, + "minItems": 1, + "uniqueItems": true + }, + "return": { + "$ref": "#/definitions/return" + } + }, + "patternProperties": { + "^content\\.": { "type": "string" + }, + "^return\\.": { + "$ref": "#/definitions/return" } } }, - "remote": { + "parameter": { "type": "object", "additionalProperties": false, "properties": { - "branch": { + "id": { "type": "string" }, - "path": { + "type": { + "type": "array", + "items": { + "type": "string" + } + }, + "description": { "type": "string" }, - "repo": { + "optional": { + "type": "boolean" + }, + "defaultValue": { "type": "string" } } @@ -210,59 +481,151 @@ "type": "object", "additionalProperties": false, "properties": { - "description": { - "type": "string" - }, "type": { "type": "array", "items": { "type": "string" } + }, + "description": { + "type": "string" } } }, - "source": { + "exception": { "type": "object", + "additionalProperties": false, "properties": { - "id": { + "type": { "type": "string" }, - "path": { + "description": { + "type": "string" + } + } + }, + "link": { + "type": "object", + "additionalProperties": false, + "required": [ "linkType", "linkId" ], + "properties": { + "linkType": { + "enum": [ "CRef", "HRef" ] + }, + "linkId": { "type": "string" }, - "remote": { - "$ref": "#/definitions/remote" + "commentId": { + "type": "string" }, - "startLine": { - "type": "integer" + "altText": { + "type": "string" } } }, - "syntax": { + "inheritance": { "type": "object", "additionalProperties": false, + "required": [ "type" ], "properties": { - "content": { + "type": { "type": "string" }, - "typeParameters": { + "inheritance": { "type": "array", "items": { - "$ref": "#/definitions/parameter" + "$ref": "#/definitions/inheritance" }, "minItems": 1, "uniqueItems": true }, - "parameters": { + "level": { + "type": "number" + } + } + }, + "reference": { + "type": "object", + "additionalProperties": false, + "properties": { + "uid": { + "type": "string" + }, + "commentId": { + "type": "string" + }, + "parent": { + "type": "string" + }, + "definition": { + "type": "string" + }, + "isExternal": { + "type": "boolean" + }, + "href": { + "type": "string" + }, + "name": { + "type": "string" + }, + "nameWithType": { + "type": "string" + }, + "fullName": { + "type": "string" + } + }, + "patternProperties": { + "^name\\.": { + "type": "string" + }, + "^nameWithType\\.": { + "type": "string" + }, + "^fullName\\.": { + "type": "string" + }, + "^spec\\.": { "type": "array", "items": { - "$ref": "#/definitions/parameter" - }, - "minItems": 1, - "uniqueItems": true + "$ref": "#/definitions/spec" + } + } + } + }, + "spec": { + "type": "object", + "additionalProperties": false, + "properties": { + "uid": { + "type": "string" }, - "return": { - "$ref": "#/definitions/return" + "name": { + "type": "string" + }, + "nameWithType": { + "type": "string" + }, + "fullName": { + "type": "string" + }, + "isExternal": { + "type": "boolean" + }, + "href": { + "type": "string" + } + } + }, + + "deprecated": { + "type": "object", + "additionalProperties": false, + "properties": { + "content": { + "description": "The string following the default obsolete message. Supports markdown.", + "type": "string" } } } diff --git a/build-tests/api-documenter-test/etc/api-documenter-test.api.json b/build-tests/api-documenter-test/etc/api-documenter-test.api.json index 3590068c968..d135ad3bb36 100644 --- a/build-tests/api-documenter-test/etc/api-documenter-test.api.json +++ b/build-tests/api-documenter-test/etc/api-documenter-test.api.json @@ -685,6 +685,44 @@ "members": [], "implementsTokenRanges": [] }, + { + "kind": "TypeAlias", + "canonicalReference": "api-documenter-test!GenericTypeAlias:type", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type GenericTypeAlias = " + }, + { + "kind": "Content", + "text": "T[]" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "GenericTypeAlias", + "typeParameters": [ + { + "typeParameterName": "T", + "constraintTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "defaultTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ], + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, { "kind": "Function", "canonicalReference": "api-documenter-test!globalFunction:function(1)", @@ -1633,6 +1671,31 @@ ], "implementsTokenRanges": [] }, + { + "kind": "TypeAlias", + "canonicalReference": "api-documenter-test!TypeAlias:type", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type TypeAlias = " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "TypeAlias", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, { "kind": "Function", "canonicalReference": "api-documenter-test!yamlReferenceUniquenessTest:function(1)", diff --git a/build-tests/api-documenter-test/etc/api-documenter-test.api.md b/build-tests/api-documenter-test/etc/api-documenter-test.api.md index fa8f9f82dc7..d189d5a7c81 100644 --- a/build-tests/api-documenter-test/etc/api-documenter-test.api.md +++ b/build-tests/api-documenter-test/etc/api-documenter-test.api.md @@ -58,6 +58,9 @@ export type ExampleTypeAlias = Promise; export class Generic { } +// @public (undocumented) +export type GenericTypeAlias = T[]; + // @public export function globalFunction(x: number): number; @@ -131,6 +134,9 @@ export class SystemEvent { addHandler(handler: () => void): void; } +// @public (undocumented) +export type TypeAlias = number; + // @public (undocumented) export function yamlReferenceUniquenessTest(): IDocInterface1; diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.generictypealias.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.generictypealias.md new file mode 100644 index 00000000000..d0ce5a0e31e --- /dev/null +++ b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.generictypealias.md @@ -0,0 +1,12 @@ + + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [GenericTypeAlias](./api-documenter-test.generictypealias.md) + +## GenericTypeAlias type + + +Signature: + +```typescript +export declare type GenericTypeAlias = T[]; +``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.md index d59a347ee9a..82b38593d2c 100644 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.md +++ b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.md @@ -61,4 +61,6 @@ This project tests various documentation generation scenarios and doc comment sy | Type Alias | Description | | --- | --- | | [ExampleTypeAlias](./api-documenter-test.exampletypealias.md) | A type alias | +| [GenericTypeAlias](./api-documenter-test.generictypealias.md) | | +| [TypeAlias](./api-documenter-test.typealias.md) | | diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.typealias.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.typealias.md new file mode 100644 index 00000000000..5d36ebd5e69 --- /dev/null +++ b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.typealias.md @@ -0,0 +1,12 @@ + + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [TypeAlias](./api-documenter-test.typealias.md) + +## TypeAlias type + + +Signature: + +```typescript +export declare type TypeAlias = number; +``` diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test.yml index 779b47ae822..f4fff664512 100644 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test.yml +++ b/build-tests/api-documenter-test/etc/yaml/api-documenter-test.yml @@ -11,12 +11,16 @@ items: - typeScript type: package children: + - 'api-documenter-test!constVariable:var' - 'api-documenter-test!DocBaseClass:class' - 'api-documenter-test!DocClass1:class' - 'api-documenter-test!DocClassInterfaceMerge:class' - 'api-documenter-test!DocClassInterfaceMerge:interface' - 'api-documenter-test!DocEnum:enum' + - 'api-documenter-test!EcmaSmbols:namespace' + - 'api-documenter-test!ExampleTypeAlias:type' - 'api-documenter-test!Generic:class' + - 'api-documenter-test!GenericTypeAlias:type' - 'api-documenter-test!globalFunction:function(1)' - 'api-documenter-test!IDocInterface1:interface' - 'api-documenter-test!IDocInterface2:interface' @@ -24,9 +28,48 @@ items: - 'api-documenter-test!IDocInterface4:interface' - 'api-documenter-test!IDocInterface5:interface' - 'api-documenter-test!IDocInterface6:interface' + - 'api-documenter-test!OuterNamespace:namespace' - 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' - 'api-documenter-test!SystemEvent:class' + - 'api-documenter-test!TypeAlias:type' - 'api-documenter-test!yamlReferenceUniquenessTest:function(1)' + - uid: 'api-documenter-test!constVariable:var' + summary: An exported variable declaration. + name: constVariable + fullName: constVariable + langs: + - typeScript + type: variable + syntax: + content: 'constVariable: number' + return: + type: + - number + - uid: 'api-documenter-test!ExampleTypeAlias:type' + summary: A type alias + name: ExampleTypeAlias + fullName: ExampleTypeAlias + langs: + - typeScript + type: typealias + syntax: + content: export declare type ExampleTypeAlias = Promise; + return: + type: + - 'api-documenter-test!ExampleTypeAlias~0:complex' + - uid: 'api-documenter-test!GenericTypeAlias:type' + name: GenericTypeAlias + fullName: GenericTypeAlias + langs: + - typeScript + type: typealias + syntax: + content: 'export declare type GenericTypeAlias = T[];' + typeParameters: + - id: T + return: + type: + - 'T[]' - uid: 'api-documenter-test!globalFunction:function(1)' summary: An exported function name: globalFunction(x) @@ -45,6 +88,17 @@ items: description: '' type: - number + - uid: 'api-documenter-test!TypeAlias:type' + name: TypeAlias + fullName: TypeAlias + langs: + - typeScript + type: typealias + syntax: + content: export declare type TypeAlias = number; + return: + type: + - number - uid: 'api-documenter-test!yamlReferenceUniquenessTest:function(1)' name: yamlReferenceUniquenessTest() fullName: yamlReferenceUniquenessTest() @@ -68,6 +122,17 @@ references: name: DocClassInterfaceMerge - uid: 'api-documenter-test!DocEnum:enum' name: DocEnum + - uid: 'api-documenter-test!EcmaSmbols:namespace' + name: EcmaSmbols + - uid: 'api-documenter-test!ExampleTypeAlias~0:complex' + name: Promise + fullName: Promise + spec.typeScript: + - uid: '!Promise:interface' + name: Promise + fullName: Promise + - name: + fullName: - uid: 'api-documenter-test!Generic:class' name: Generic - uid: 'api-documenter-test!IDocInterface1:interface' @@ -82,6 +147,8 @@ references: name: IDocInterface5 - uid: 'api-documenter-test!IDocInterface6:interface' name: IDocInterface6 + - uid: 'api-documenter-test!OuterNamespace:namespace' + name: OuterNamespace - uid: 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' name: OuterNamespace.InnerNamespace - uid: 'api-documenter-test!SystemEvent:class' diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclass1.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclass1.yml index 330d469d40a..adb7d8ff275 100644 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclass1.yml +++ b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclass1.yml @@ -15,6 +15,8 @@ items: type: class extends: - 'api-documenter-test!DocBaseClass:class' + inheritance: + - type: 'api-documenter-test!DocBaseClass:class' implements: - 'api-documenter-test!IDocInterface1:interface' - 'api-documenter-test!IDocInterface2:interface' diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/ecmasmbols.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/ecmasmbols.yml new file mode 100644 index 00000000000..1cef2ce3d4c --- /dev/null +++ b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/ecmasmbols.yml @@ -0,0 +1,25 @@ +### YamlMime:UniversalReference +items: + - uid: 'api-documenter-test!EcmaSmbols:namespace' + summary: A namespace containing an ECMAScript symbol + name: EcmaSmbols + fullName: EcmaSmbols + langs: + - typeScript + type: namespace + package: api-documenter-test! + children: + - 'api-documenter-test!EcmaSmbols.example:var' + - uid: 'api-documenter-test!EcmaSmbols.example:var' + summary: An ECMAScript symbol + name: example + fullName: EcmaSmbols.example + langs: + - typeScript + namespace: 'api-documenter-test!EcmaSmbols:namespace' + type: variable + syntax: + content: 'example: unique symbol' + return: + type: + - unique symbol diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface2.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface2.yml index 66afe8a14d3..654a3556910 100644 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface2.yml +++ b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface2.yml @@ -8,6 +8,8 @@ items: type: interface extends: - 'api-documenter-test!IDocInterface1:interface' + inheritance: + - type: 'api-documenter-test!IDocInterface1:interface' package: api-documenter-test! children: - 'api-documenter-test!IDocInterface2#deprecatedExample:member(1)' diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.innernamespace.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.innernamespace.yml index 7b5dc60fd84..ccfa0c9e5f6 100644 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.innernamespace.yml +++ b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.innernamespace.yml @@ -12,10 +12,11 @@ items: - 'api-documenter-test!OuterNamespace.InnerNamespace.nestedFunction:function(1)' - uid: 'api-documenter-test!OuterNamespace.InnerNamespace.nestedFunction:function(1)' summary: A function inside a namespace - name: OuterNamespace.InnerNamespace.nestedFunction(x) + name: nestedFunction(x) fullName: OuterNamespace.InnerNamespace.nestedFunction(x) langs: - typeScript + namespace: 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' type: function syntax: content: 'function nestedFunction(x: number): number;' diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.yml new file mode 100644 index 00000000000..44145cff45b --- /dev/null +++ b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.yml @@ -0,0 +1,25 @@ +### YamlMime:UniversalReference +items: + - uid: 'api-documenter-test!OuterNamespace:namespace' + summary: A top-level namespace + name: OuterNamespace + fullName: OuterNamespace + langs: + - typeScript + type: namespace + package: api-documenter-test! + children: + - 'api-documenter-test!OuterNamespace.nestedVariable:var' + - uid: 'api-documenter-test!OuterNamespace.nestedVariable:var' + summary: A variable exported from within a namespace. + name: nestedVariable + fullName: OuterNamespace.nestedVariable + langs: + - typeScript + namespace: 'api-documenter-test!OuterNamespace:namespace' + type: variable + syntax: + content: 'nestedVariable: boolean' + return: + type: + - boolean diff --git a/build-tests/api-documenter-test/etc/yaml/toc.yml b/build-tests/api-documenter-test/etc/yaml/toc.yml index 2f75c7fc38f..2c391ee5940 100644 --- a/build-tests/api-documenter-test/etc/yaml/toc.yml +++ b/build-tests/api-documenter-test/etc/yaml/toc.yml @@ -45,8 +45,12 @@ items: uid: 'api-documenter-test!DocClassInterfaceMerge:interface' - name: DocEnum uid: 'api-documenter-test!DocEnum:enum' + - name: EcmaSmbols + uid: 'api-documenter-test!EcmaSmbols:namespace' - name: Generic uid: 'api-documenter-test!Generic:class' + - name: OuterNamespace + uid: 'api-documenter-test!OuterNamespace:namespace' - name: OuterNamespace.InnerNamespace uid: 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' - name: SystemEvent diff --git a/build-tests/api-documenter-test/src/index.ts b/build-tests/api-documenter-test/src/index.ts index 090978947fa..eb77c9fec79 100644 --- a/build-tests/api-documenter-test/src/index.ts +++ b/build-tests/api-documenter-test/src/index.ts @@ -60,4 +60,14 @@ export namespace OuterNamespace { /** * @public */ -export declare function yamlReferenceUniquenessTest(): IDocInterface1; \ No newline at end of file +export declare function yamlReferenceUniquenessTest(): IDocInterface1; + +/** + * @public + */ +export type TypeAlias = number; + +/** + * @public + */ +export type GenericTypeAlias = T[]; \ No newline at end of file From dc9ea2d5d2722c36b9a56e6b81b7ce72eff76d84 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Fri, 15 Nov 2019 14:48:47 -0800 Subject: [PATCH 3/4] Add --namespaces parameter to opt-in to new namespace flattening behavior --- apps/api-documenter/src/cli/YamlAction.ts | 11 ++- .../documenters/ExperimentalYamlDocumenter.ts | 29 +++--- .../src/documenters/IConfigFile.ts | 9 ++ .../src/documenters/OfficeYamlDocumenter.ts | 4 +- .../src/documenters/YamlDocumenter.ts | 91 +++++++++++++------ .../src/schemas/api-documenter.schema.json | 7 +- .../config/api-documenter.json | 2 +- 7 files changed, 106 insertions(+), 47 deletions(-) diff --git a/apps/api-documenter/src/cli/YamlAction.ts b/apps/api-documenter/src/cli/YamlAction.ts index 9ab34dce64d..a0185c3ff25 100644 --- a/apps/api-documenter/src/cli/YamlAction.ts +++ b/apps/api-documenter/src/cli/YamlAction.ts @@ -14,6 +14,7 @@ import { ApiModel } from '@microsoft/api-extractor-model'; export class YamlAction extends BaseAction { private _officeParameter: CommandLineFlagParameter; + private _namespacesParameter: CommandLineFlagParameter; constructor(parser: ApiDocumenterCommandLine) { super({ @@ -32,14 +33,20 @@ export class YamlAction extends BaseAction { parameterLongName: '--office', description: `Enables some additional features specific to Office Add-ins` }); + this._namespacesParameter = this.defineFlagParameter({ + parameterLongName: '--namespaces', + description: `Include documentation for namespaces and add them to the TOC.` + + ` This will also affect file layout as namespaced items will be nested` + + ` under a directory for the namespace instead of just within the package.` + }); } protected onExecute(): Promise { // override const apiModel: ApiModel = this.buildApiModel(); const yamlDocumenter: YamlDocumenter = this._officeParameter.value - ? new OfficeYamlDocumenter(apiModel, this.inputFolder) - : new YamlDocumenter(apiModel); + ? new OfficeYamlDocumenter(apiModel, this.inputFolder, this._namespacesParameter.value) + : new YamlDocumenter(apiModel, this._namespacesParameter.value); yamlDocumenter.generateFiles(this.outputFolder); return Promise.resolve(); diff --git a/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts b/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts index 87a06066777..e680962f313 100644 --- a/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts @@ -19,7 +19,7 @@ export class ExperimentalYamlDocumenter extends YamlDocumenter { private _catchAllPointer: IYamlTocItem; public constructor(apiModel: ApiModel, documenterConfig: DocumenterConfig) { - super(apiModel); + super(apiModel, documenterConfig.configFile.documentNamespaces); this._config = documenterConfig.configFile.tableOfContents!; this._tocPointerMap = {}; @@ -36,18 +36,25 @@ export class ExperimentalYamlDocumenter extends YamlDocumenter { private _buildTocItems2(apiItems: ReadonlyArray): IYamlTocItem[] { const tocItems: IYamlTocItem[] = []; for (const apiItem of apiItems) { - if (this._shouldEmbed(apiItem.kind)) { - // Don't generate table of contents items for embedded definitions - continue; - } + let tocItem: IYamlTocItem; + if (apiItem.kind === ApiItemKind.Namespace && !this.documentNamespaces) { + tocItem = { + name: this._getTocItemName(apiItem) + }; + } else { + if (this._shouldEmbed(apiItem.kind)) { + // Don't generate table of contents items for embedded definitions + continue; + } - const tocItem: IYamlTocItem = { - name: this._getTocItemName(apiItem), - uid: this._getUid(apiItem) - }; + tocItem = { + name: this._getTocItemName(apiItem), + uid: this._getUid(apiItem) + }; - if (apiItem.kind !== ApiItemKind.Package) { - this._filterItem(apiItem, tocItem); + if (apiItem.kind !== ApiItemKind.Package) { + this._filterItem(apiItem, tocItem); + } } tocItems.push(tocItem); diff --git a/apps/api-documenter/src/documenters/IConfigFile.ts b/apps/api-documenter/src/documenters/IConfigFile.ts index 6ef18ee7760..631057837bd 100644 --- a/apps/api-documenter/src/documenters/IConfigFile.ts +++ b/apps/api-documenter/src/documenters/IConfigFile.ts @@ -77,6 +77,15 @@ export interface IConfigFile { */ outputTarget: 'docfx' | 'markdown'; + /** + * Include documentation for namespaces and add them to the TOC. + * This will also affect file layout as namespaced items will be nested + * under a directory for the namespace instead of just within the package. + * + * This setting currently only affects the 'docfx' output target. + */ + documentNamespaces?: boolean; + /** {@inheritDoc IConfigPlugin} */ plugins?: IConfigPlugin[]; diff --git a/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts b/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts index f0067d30fcd..f015ba19651 100644 --- a/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts @@ -39,8 +39,8 @@ export class OfficeYamlDocumenter extends YamlDocumenter { 'Word': '/office/dev/add-ins/reference/requirement-sets/word-api-requirement-sets' }; - public constructor(apiModel: ApiModel, inputFolder: string) { - super(apiModel); + public constructor(apiModel: ApiModel, inputFolder: string, documentNamespaces?: boolean) { + super(apiModel, documentNamespaces); const snippetsFilePath: string = path.join(inputFolder, 'snippets.yaml'); diff --git a/apps/api-documenter/src/documenters/YamlDocumenter.ts b/apps/api-documenter/src/documenters/YamlDocumenter.ts index 1a841544c16..8d225d38abf 100644 --- a/apps/api-documenter/src/documenters/YamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/YamlDocumenter.ts @@ -71,9 +71,14 @@ interface IYamlReferences { } const enum FlattenMode { + /** Include entries for nested namespaces and non-namespace children. */ NestedNamespacesAndChildren, + /** Include entries for nested namespaces only. */ NestedNamespacesOnly, - NoNamespaces + /** Include entries for non-namespace immediate children. */ + ImmediateChildren, + /** Include entries for nested non-namespace children. */ + NestedChildren } interface INameOptions { @@ -85,6 +90,7 @@ interface INameOptions { * Writes documentation in the Universal Reference YAML file format, as defined by typescript.schema.json. */ export class YamlDocumenter { + protected readonly documentNamespaces: boolean; private readonly _apiModel: ApiModel; private readonly _markdownEmitter: CustomMarkdownEmitter; @@ -92,8 +98,9 @@ export class YamlDocumenter { private _yamlReferences: IYamlReferences | undefined; private _outputFolder: string; - public constructor(apiModel: ApiModel) { + public constructor(apiModel: ApiModel, documentNamespaces: boolean = false) { this._apiModel = apiModel; + this.documentNamespaces = documentNamespaces; this._markdownEmitter = new CustomMarkdownEmitter(this._apiModel); this._apiItemsByCanonicalReference = new Map(); @@ -186,7 +193,7 @@ export class YamlDocumenter { this._recordYamlReference( this._ensureYamlReferences(), this._getUid(apiItem), - this._getYamlItemName(apiItem, { includeSignature: true }), + this._getYamlItemName(apiItem, { includeNamespace: !this.documentNamespaces, includeSignature: true }), this._getYamlItemName(apiItem, { includeNamespace: true, includeSignature: true })); } } @@ -198,9 +205,11 @@ export class YamlDocumenter { const children: ApiItem[] = []; if (apiItem.kind === ApiItemKind.Package) { // Skip over the entry point, since it's not part of the documentation hierarchy - this._flattenNamespaces(apiItem.members[0].members, children, FlattenMode.NestedNamespacesAndChildren); + this._flattenNamespaces(apiItem.members[0].members, children, + this.documentNamespaces ? FlattenMode.NestedNamespacesAndChildren : FlattenMode.NestedChildren); } else { - this._flattenNamespaces(apiItem.members, children, FlattenMode.NoNamespaces); + this._flattenNamespaces(apiItem.members, children, + this.documentNamespaces ? FlattenMode.ImmediateChildren : FlattenMode.NestedChildren); } return children; } @@ -215,23 +224,34 @@ export class YamlDocumenter { let hasNonNamespaceChildren: boolean = false; for (const item of items) { if (item.kind === ApiItemKind.Namespace) { - if (mode !== FlattenMode.NoNamespaces) { - // At any level, always include a nested namespace if it has non-namespace children, but do not include its - // non-namespace children in the result. - - // Record the offset at which the namespace is added in case we need to remove it later. - const index: number = childrenOut.length; - childrenOut.push(item); - - if (!this._flattenNamespaces(item.members, childrenOut, FlattenMode.NestedNamespacesOnly)) { - // This namespace had no non-namespace children, remove it. - childrenOut.splice(index, 1); - } + switch (mode) { + case FlattenMode.NestedChildren: + // Include children of namespaces, but not the namespaces themselves. This matches existing legacy behavior. + this._flattenNamespaces(item.members, childrenOut, FlattenMode.NestedChildren); + break; + case FlattenMode.NestedNamespacesOnly: + case FlattenMode.NestedNamespacesAndChildren: + // At any level, always include a nested namespace if it has non-namespace children, but do not include its + // non-namespace children in the result. + + // Record the offset at which the namespace is added in case we need to remove it later. + const index: number = childrenOut.length; + childrenOut.push(item); + + if (!this._flattenNamespaces(item.members, childrenOut, FlattenMode.NestedNamespacesOnly)) { + // This namespace had no non-namespace children, remove it. + childrenOut.splice(index, 1); + } + break; } } else if (this._shouldInclude(item.kind)) { - if (mode !== FlattenMode.NestedNamespacesOnly) { - // At the top level, include non-namespace children as well. - childrenOut.push(item); + switch (mode) { + case FlattenMode.NestedChildren: + case FlattenMode.NestedNamespacesAndChildren: + case FlattenMode.ImmediateChildren: + // At the top level, include non-namespace children as well. + childrenOut.push(item); + break; } hasNonNamespaceChildren = true; } @@ -266,15 +286,23 @@ export class YamlDocumenter { private _buildTocItems(apiItems: ReadonlyArray): IYamlTocItem[] { const tocItems: IYamlTocItem[] = []; for (const apiItem of apiItems) { - if (this._shouldEmbed(apiItem.kind)) { - // Don't generate table of contents items for embedded definitions - continue; + let tocItem: IYamlTocItem; + if (apiItem.kind === ApiItemKind.Namespace && !this.documentNamespaces) { + tocItem = { + name: this._getTocItemName(apiItem) + }; + } else { + if (this._shouldEmbed(apiItem.kind)) { + // Don't generate table of contents items for embedded definitions + continue; + } + + tocItem = { + name: this._getTocItemName(apiItem), + uid: this._getUid(apiItem) + }; } - const tocItem: IYamlTocItem = { - name: this._getTocItemName(apiItem), - uid: this._getUid(apiItem) - }; tocItems.push(tocItem); const children: ApiItem[] = this._getLogicalChildren(apiItem); @@ -308,8 +336,9 @@ export class YamlDocumenter { case ApiItemKind.Package: case ApiItemKind.Interface: case ApiItemKind.Enum: - case ApiItemKind.Namespace: return false; + case ApiItemKind.Namespace: + return !this.documentNamespaces; } return true; } @@ -366,13 +395,15 @@ export class YamlDocumenter { } } - yamlItem.name = this._getYamlItemName(apiItem, { includeSignature: true }); + yamlItem.name = this._getYamlItemName(apiItem, { includeSignature: true, + includeNamespace: !this.documentNamespaces }); yamlItem.fullName = this._getYamlItemName(apiItem, { includeSignature: true, includeNamespace: true }); yamlItem.langs = [ 'typeScript' ]; // Add the namespace of the item if it is contained in one. // Do not add the namespace parent of a namespace as they are flattened in the documentation. - if (apiItem.kind !== ApiItemKind.Namespace && apiItem.parent && apiItem.parent.kind === ApiItemKind.Namespace) { + if (apiItem.kind !== ApiItemKind.Namespace && apiItem.parent && apiItem.parent.kind === ApiItemKind.Namespace && + this.documentNamespaces) { yamlItem.namespace = apiItem.parent.canonicalReference.toString(); } diff --git a/apps/api-documenter/src/schemas/api-documenter.schema.json b/apps/api-documenter/src/schemas/api-documenter.schema.json index 244dc64d68b..6d4aea7a332 100644 --- a/apps/api-documenter/src/schemas/api-documenter.schema.json +++ b/apps/api-documenter/src/schemas/api-documenter.schema.json @@ -17,6 +17,11 @@ ] }, + "documentNamespaces": { + "description": "Include documentation for namespaces and add them to the TOC. This will also affect file layout as namespaced items will be nested under a directory for the namespace instead of just within the package. This setting currently only affects the 'docfx' output target.", + "type": "boolean" + }, + "plugins": { "description": "Specifies plugin packages to be loaded", "type": "array" @@ -26,7 +31,7 @@ "description": "Configures how the table of contents is generated.", "type": "object", "additionalProperties": true - }, + } }, "additionalProperties": false diff --git a/build-tests/api-documenter-test/config/api-documenter.json b/build-tests/api-documenter-test/config/api-documenter.json index 2c38e04fd33..aa72175a133 100644 --- a/build-tests/api-documenter-test/config/api-documenter.json +++ b/build-tests/api-documenter-test/config/api-documenter.json @@ -1,6 +1,6 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-documenter.schema.json", - + "documentNamespaces": true, "tableOfContents": { "tocConfig": { "items": [ From 5f49ef78303ac445163f8f7a815015abb343da2f Mon Sep 17 00:00:00 2001 From: Pete Gonzalez <4673363+octogonz@users.noreply.github.com> Date: Sun, 24 Nov 2019 09:16:06 +0900 Subject: [PATCH 4/4] Rename "documentNamespaces" to "newDocfxNamespaces" to make it more clear that this is an opt-in for an experimental DocFX-specific feature --- apps/api-documenter/src/cli/YamlAction.ts | 15 +++++++------- .../documenters/ExperimentalYamlDocumenter.ts | 4 ++-- .../src/documenters/IConfigFile.ts | 10 ++++++---- .../src/documenters/OfficeYamlDocumenter.ts | 4 ++-- .../src/documenters/YamlDocumenter.ts | 20 +++++++++---------- .../src/schemas/api-documenter-template.json | 11 ++++++++++ .../src/schemas/api-documenter.schema.json | 4 ++-- .../config/api-documenter.json | 2 +- .../flattenNamespaces2_2019-09-22-01-34.json | 4 ++-- 9 files changed, 44 insertions(+), 30 deletions(-) diff --git a/apps/api-documenter/src/cli/YamlAction.ts b/apps/api-documenter/src/cli/YamlAction.ts index c5521170e4f..68f75cd43db 100644 --- a/apps/api-documenter/src/cli/YamlAction.ts +++ b/apps/api-documenter/src/cli/YamlAction.ts @@ -14,7 +14,7 @@ import { ApiModel } from '@microsoft/api-extractor-model'; export class YamlAction extends BaseAction { private _officeParameter: CommandLineFlagParameter; - private _namespacesParameter: CommandLineFlagParameter; + private _newDocfxNamespacesParameter: CommandLineFlagParameter; public constructor(parser: ApiDocumenterCommandLine) { super({ @@ -33,10 +33,11 @@ export class YamlAction extends BaseAction { parameterLongName: '--office', description: `Enables some additional features specific to Office Add-ins` }); - this._namespacesParameter = this.defineFlagParameter({ - parameterLongName: '--namespaces', - description: `Include documentation for namespaces and add them to the TOC.` - + ` This will also affect file layout as namespaced items will be nested` + this._newDocfxNamespacesParameter = this.defineFlagParameter({ + parameterLongName: '--new-docfx-namespaces', + description: `This enables an experimental feature that will be officially released with the next major version` + + ` of API Documenter. It requires DocFX 2.46 or newer. It enables documentation for namespaces and` + + ` adds them to the table of contents. This will also affect file layout as namespaced items will be nested` + ` under a directory for the namespace instead of just within the package.` }); } @@ -45,8 +46,8 @@ export class YamlAction extends BaseAction { const apiModel: ApiModel = this.buildApiModel(); const yamlDocumenter: YamlDocumenter = this._officeParameter.value - ? new OfficeYamlDocumenter(apiModel, this.inputFolder, this._namespacesParameter.value) - : new YamlDocumenter(apiModel, this._namespacesParameter.value); + ? new OfficeYamlDocumenter(apiModel, this.inputFolder, this._newDocfxNamespacesParameter.value) + : new YamlDocumenter(apiModel, this._newDocfxNamespacesParameter.value); yamlDocumenter.generateFiles(this.outputFolder); return Promise.resolve(); diff --git a/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts b/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts index e680962f313..0fea06fa1b6 100644 --- a/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts @@ -19,7 +19,7 @@ export class ExperimentalYamlDocumenter extends YamlDocumenter { private _catchAllPointer: IYamlTocItem; public constructor(apiModel: ApiModel, documenterConfig: DocumenterConfig) { - super(apiModel, documenterConfig.configFile.documentNamespaces); + super(apiModel, documenterConfig.configFile.newDocfxNamespaces); this._config = documenterConfig.configFile.tableOfContents!; this._tocPointerMap = {}; @@ -37,7 +37,7 @@ export class ExperimentalYamlDocumenter extends YamlDocumenter { const tocItems: IYamlTocItem[] = []; for (const apiItem of apiItems) { let tocItem: IYamlTocItem; - if (apiItem.kind === ApiItemKind.Namespace && !this.documentNamespaces) { + if (apiItem.kind === ApiItemKind.Namespace && !this.newDocfxNamespaces) { tocItem = { name: this._getTocItemName(apiItem) }; diff --git a/apps/api-documenter/src/documenters/IConfigFile.ts b/apps/api-documenter/src/documenters/IConfigFile.ts index 99371dd0e4c..c3116b6f119 100644 --- a/apps/api-documenter/src/documenters/IConfigFile.ts +++ b/apps/api-documenter/src/documenters/IConfigFile.ts @@ -88,13 +88,15 @@ export interface IConfigFile { newlineKind?: 'crlf' | 'lf' | 'os'; /** - * Include documentation for namespaces and add them to the TOC. - * This will also affect file layout as namespaced items will be nested + * This enables an experimental feature that will be officially released with the next major version + * of API Documenter. It requires DocFX 2.46 or newer. It enables documentation for namespaces and + * adds them to the table of contents. This will also affect file layout as namespaced items will be nested * under a directory for the namespace instead of just within the package. * - * This setting currently only affects the 'docfx' output target. + * This setting currently only affects the 'docfx' output target. It is equivalent to the `--new-docfx-namespaces` + * command-line parameter. */ - documentNamespaces?: boolean; + newDocfxNamespaces?: boolean; /** {@inheritDoc IConfigPlugin} */ plugins?: IConfigPlugin[]; diff --git a/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts b/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts index d149e83779f..42f31d4a5d2 100644 --- a/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts @@ -39,8 +39,8 @@ export class OfficeYamlDocumenter extends YamlDocumenter { 'Word': '/office/dev/add-ins/reference/requirement-sets/word-api-requirement-sets' }; - public constructor(apiModel: ApiModel, inputFolder: string, documentNamespaces?: boolean) { - super(apiModel, documentNamespaces); + public constructor(apiModel: ApiModel, inputFolder: string, newDocfxNamespaces?: boolean) { + super(apiModel, newDocfxNamespaces); const snippetsFilePath: string = path.join(inputFolder, 'snippets.yaml'); diff --git a/apps/api-documenter/src/documenters/YamlDocumenter.ts b/apps/api-documenter/src/documenters/YamlDocumenter.ts index 7276a7b3685..ea680a292fb 100644 --- a/apps/api-documenter/src/documenters/YamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/YamlDocumenter.ts @@ -88,7 +88,7 @@ interface INameOptions { * Writes documentation in the Universal Reference YAML file format, as defined by typescript.schema.json. */ export class YamlDocumenter { - protected readonly documentNamespaces: boolean; + protected readonly newDocfxNamespaces: boolean; private readonly _apiModel: ApiModel; private readonly _markdownEmitter: CustomMarkdownEmitter; @@ -96,9 +96,9 @@ export class YamlDocumenter { private _yamlReferences: IYamlReferences | undefined; private _outputFolder: string; - public constructor(apiModel: ApiModel, documentNamespaces: boolean = false) { + public constructor(apiModel: ApiModel, newDocfxNamespaces: boolean = false) { this._apiModel = apiModel; - this.documentNamespaces = documentNamespaces; + this.newDocfxNamespaces = newDocfxNamespaces; this._markdownEmitter = new CustomMarkdownEmitter(this._apiModel); this._apiItemsByCanonicalReference = new Map(); @@ -191,7 +191,7 @@ export class YamlDocumenter { this._recordYamlReference( this._ensureYamlReferences(), this._getUid(apiItem), - this._getYamlItemName(apiItem, { includeNamespace: !this.documentNamespaces, includeSignature: true }), + this._getYamlItemName(apiItem, { includeNamespace: !this.newDocfxNamespaces, includeSignature: true }), this._getYamlItemName(apiItem, { includeNamespace: true, includeSignature: true })); } } @@ -204,10 +204,10 @@ export class YamlDocumenter { if (apiItem.kind === ApiItemKind.Package) { // Skip over the entry point, since it's not part of the documentation hierarchy this._flattenNamespaces(apiItem.members[0].members, children, - this.documentNamespaces ? FlattenMode.NestedNamespacesAndChildren : FlattenMode.NestedChildren); + this.newDocfxNamespaces ? FlattenMode.NestedNamespacesAndChildren : FlattenMode.NestedChildren); } else { this._flattenNamespaces(apiItem.members, children, - this.documentNamespaces ? FlattenMode.ImmediateChildren : FlattenMode.NestedChildren); + this.newDocfxNamespaces ? FlattenMode.ImmediateChildren : FlattenMode.NestedChildren); } return children; } @@ -285,7 +285,7 @@ export class YamlDocumenter { const tocItems: IYamlTocItem[] = []; for (const apiItem of apiItems) { let tocItem: IYamlTocItem; - if (apiItem.kind === ApiItemKind.Namespace && !this.documentNamespaces) { + if (apiItem.kind === ApiItemKind.Namespace && !this.newDocfxNamespaces) { tocItem = { name: this._getTocItemName(apiItem) }; @@ -336,7 +336,7 @@ export class YamlDocumenter { case ApiItemKind.Enum: return false; case ApiItemKind.Namespace: - return !this.documentNamespaces; + return !this.newDocfxNamespaces; } return true; } @@ -394,14 +394,14 @@ export class YamlDocumenter { } yamlItem.name = this._getYamlItemName(apiItem, { includeSignature: true, - includeNamespace: !this.documentNamespaces }); + includeNamespace: !this.newDocfxNamespaces }); yamlItem.fullName = this._getYamlItemName(apiItem, { includeSignature: true, includeNamespace: true }); yamlItem.langs = [ 'typeScript' ]; // Add the namespace of the item if it is contained in one. // Do not add the namespace parent of a namespace as they are flattened in the documentation. if (apiItem.kind !== ApiItemKind.Namespace && apiItem.parent && apiItem.parent.kind === ApiItemKind.Namespace && - this.documentNamespaces) { + this.newDocfxNamespaces) { yamlItem.namespace = apiItem.parent.canonicalReference.toString(); } diff --git a/apps/api-documenter/src/schemas/api-documenter-template.json b/apps/api-documenter/src/schemas/api-documenter-template.json index 7fa4ce88683..ec893c904c6 100644 --- a/apps/api-documenter/src/schemas/api-documenter-template.json +++ b/apps/api-documenter/src/schemas/api-documenter-template.json @@ -19,6 +19,17 @@ */ // "newlineKind": "crlf", + /** + * This enables an experimental feature that will be officially released with the next major version + * of API Documenter. It requires DocFX 2.46 or newer. It enables documentation for namespaces and + * adds them to the table of contents. This will also affect file layout as namespaced items will be nested + * under a directory for the namespace instead of just within the package. + * + * This setting currently only affects the 'docfx' output target. It is equivalent to the `--new-docfx-namespaces` + * command-line parameter. + */ + // "newDocfxNamespaces": false, + /** * Describes plugin packages to be loaded, and which features to enable. */ diff --git a/apps/api-documenter/src/schemas/api-documenter.schema.json b/apps/api-documenter/src/schemas/api-documenter.schema.json index bb92a6c393a..e8ccd2d477d 100644 --- a/apps/api-documenter/src/schemas/api-documenter.schema.json +++ b/apps/api-documenter/src/schemas/api-documenter.schema.json @@ -24,8 +24,8 @@ "default": "crlf" }, - "documentNamespaces": { - "description": "Include documentation for namespaces and add them to the TOC. This will also affect file layout as namespaced items will be nested under a directory for the namespace instead of just within the package. This setting currently only affects the 'docfx' output target.", + "newDocfxNamespaces": { + "description": "This enables an experimental feature that will be officially released with the next major version of API Documenter. It requires DocFX 2.46 or newer. It enables documentation for namespaces and adds them to the table of contents. This will also affect file layout as namespaced items will be nested under a directory for the namespace instead of just within the package.", "type": "boolean" }, diff --git a/build-tests/api-documenter-test/config/api-documenter.json b/build-tests/api-documenter-test/config/api-documenter.json index 239905c2776..59dddf06166 100644 --- a/build-tests/api-documenter-test/config/api-documenter.json +++ b/build-tests/api-documenter-test/config/api-documenter.json @@ -1,6 +1,6 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-documenter.schema.json", - "documentNamespaces": true, + "newDocfxNamespaces": true, "newlineKind": "crlf", "tableOfContents": { diff --git a/common/changes/@microsoft/api-documenter/flattenNamespaces2_2019-09-22-01-34.json b/common/changes/@microsoft/api-documenter/flattenNamespaces2_2019-09-22-01-34.json index 03cfd51ca8e..f92273ed006 100644 --- a/common/changes/@microsoft/api-documenter/flattenNamespaces2_2019-09-22-01-34.json +++ b/common/changes/@microsoft/api-documenter/flattenNamespaces2_2019-09-22-01-34.json @@ -2,10 +2,10 @@ "changes": [ { "packageName": "@microsoft/api-documenter", - "comment": "Include namespaces in YAML output", + "comment": "Add a new command-line option --new-docfx-namespaces to improve how namespaces are represented when generating YAML for DocFX", "type": "minor" } ], "packageName": "@microsoft/api-documenter", - "email": "ron.buckton@microsoft.com" + "email": "rbuckton@users.noreply.github.com" } \ No newline at end of file