Skip to content

Commit 282d13c

Browse files
committed
Include additional information in yaml
1 parent 1d6c658 commit 282d13c

16 files changed

Lines changed: 1503 additions & 186 deletions

apps/api-documenter/src/documenters/YamlDocumenter.ts

Lines changed: 124 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ import {
3636
ApiTypeParameterListMixin,
3737
Excerpt,
3838
ExcerptToken,
39-
ExcerptTokenKind
39+
ExcerptTokenKind,
40+
HeritageType,
41+
ApiVariable,
42+
ApiTypeAlias
4043
} from '@microsoft/api-extractor-model';
4144
import {
4245
DeclarationReference,
@@ -49,7 +52,8 @@ import {
4952
IYamlSyntax,
5053
IYamlParameter,
5154
IYamlReference,
52-
IYamlReferenceSpec
55+
IYamlReferenceSpec,
56+
IYamlInheritanceTree
5357
} from '../yaml/IYamlApiFile';
5458
import {
5559
IYamlTocFile,
@@ -72,6 +76,11 @@ const enum FlattenMode {
7276
NoNamespaces
7377
}
7478

79+
interface INameOptions {
80+
includeSignature?: boolean;
81+
includeNamespace?: boolean;
82+
}
83+
7584
/**
7685
* Writes documentation in the Universal Reference YAML file format, as defined by typescript.schema.json.
7786
*/
@@ -172,10 +181,13 @@ export class YamlDocumenter {
172181
this._writeYamlFile(newYamlFile, yamlFilePath, 'UniversalReference', yamlApiSchema);
173182

174183
if (parentYamlFile) {
184+
// References should be recorded in the parent YAML file with the local name of the embedded item.
185+
// This avoids unnecessary repetition when listing items inside of a namespace.
175186
this._recordYamlReference(
176187
this._ensureYamlReferences(),
177188
this._getUid(apiItem),
178-
this._getYamlItemName(apiItem, /*includeSignature*/ true));
189+
this._getYamlItemName(apiItem, { includeSignature: true }),
190+
this._getYamlItemName(apiItem, { includeNamespace: true, includeSignature: true }));
179191
}
180192
}
181193

@@ -202,17 +214,19 @@ export class YamlDocumenter {
202214
private _flattenNamespaces(items: ReadonlyArray<ApiItem>, childrenOut: ApiItem[], mode: FlattenMode): boolean {
203215
let hasNonNamespaceChildren: boolean = false;
204216
for (const item of items) {
205-
if (item.kind === ApiItemKind.Namespace && mode !== FlattenMode.NoNamespaces) {
206-
// At any level, always include a nested namespace if it has non-namespace children, but do not include its
207-
// non-namespace children in the result.
217+
if (item.kind === ApiItemKind.Namespace) {
218+
if (mode !== FlattenMode.NoNamespaces) {
219+
// At any level, always include a nested namespace if it has non-namespace children, but do not include its
220+
// non-namespace children in the result.
208221

209-
// Record the offset at which the namespace is added in case we need to remove it later.
210-
const index: number = childrenOut.length;
211-
childrenOut.push(item);
222+
// Record the offset at which the namespace is added in case we need to remove it later.
223+
const index: number = childrenOut.length;
224+
childrenOut.push(item);
212225

213-
if (!this._flattenNamespaces(item.members, childrenOut, FlattenMode.NestedNamespacesOnly)) {
214-
// This namespace had no non-namespace children, remove it.
215-
childrenOut.splice(index, 1);
226+
if (!this._flattenNamespaces(item.members, childrenOut, FlattenMode.NestedNamespacesOnly)) {
227+
// This namespace had no non-namespace children, remove it.
228+
childrenOut.splice(index, 1);
229+
}
216230
}
217231
} else if (this._shouldInclude(item.kind)) {
218232
if (mode !== FlattenMode.NestedNamespacesOnly) {
@@ -278,10 +292,10 @@ export class YamlDocumenter {
278292
if (apiItem.kind === ApiItemKind.Package) {
279293
name = PackageName.getUnscopedName(apiItem.displayName);
280294
} else {
281-
name = this._getYamlItemName(apiItem, /*includeSignature*/ false);
295+
name = this._getYamlItemName(apiItem);
282296
}
283297

284-
if (apiItem.getMergedSiblings().length > 1) {
298+
if (name === apiItem.displayName && apiItem.getMergedSiblings().length > 1) {
285299
name += ` (${apiItem.kind})`;
286300
}
287301

@@ -306,8 +320,6 @@ export class YamlDocumenter {
306320
case ApiItemKind.CallSignature:
307321
case ApiItemKind.ConstructSignature:
308322
case ApiItemKind.IndexSignature:
309-
case ApiItemKind.TypeAlias:
310-
case ApiItemKind.Variable:
311323
return false;
312324
}
313325
return true;
@@ -354,11 +366,16 @@ export class YamlDocumenter {
354366
}
355367
}
356368

357-
yamlItem.name = this._getYamlItemName(apiItem, /*includeSignature*/ true);
358-
359-
yamlItem.fullName = yamlItem.name;
369+
yamlItem.name = this._getYamlItemName(apiItem, { includeSignature: true });
370+
yamlItem.fullName = this._getYamlItemName(apiItem, { includeSignature: true, includeNamespace: true });
360371
yamlItem.langs = [ 'typeScript' ];
361372

373+
// Add the namespace of the item if it is contained in one.
374+
// Do not add the namespace parent of a namespace as they are flattened in the documentation.
375+
if (apiItem.kind !== ApiItemKind.Namespace && apiItem.parent && apiItem.parent.kind === ApiItemKind.Namespace) {
376+
yamlItem.namespace = apiItem.parent.canonicalReference.toString();
377+
}
378+
362379
switch (apiItem.kind) {
363380
case ApiItemKind.Enum:
364381
yamlItem.type = 'enum';
@@ -413,6 +430,16 @@ export class YamlDocumenter {
413430
this._populateYamlFunctionLike(uid, yamlItem, apiItem as ApiFunction);
414431
break;
415432

433+
case ApiItemKind.Variable:
434+
yamlItem.type = 'variable';
435+
this._populateYamlVariable(uid, yamlItem, apiItem as ApiVariable);
436+
break;
437+
438+
case ApiItemKind.TypeAlias:
439+
yamlItem.type = 'typealias';
440+
this._populateYamlTypeAlias(uid, yamlItem, apiItem as ApiTypeAlias);
441+
break;
442+
416443
default:
417444
throw new Error('Unimplemented item kind: ' + apiItem.kind);
418445
}
@@ -456,6 +483,7 @@ export class YamlDocumenter {
456483
if (apiItem instanceof ApiClass) {
457484
if (apiItem.extendsType) {
458485
yamlItem.extends = [ this._renderType(uid, apiItem.extendsType.excerpt) ];
486+
yamlItem.inheritance = this._renderInheritance(uid, [apiItem.extendsType]);
459487
}
460488
if (apiItem.implementsTypes.length > 0) {
461489
yamlItem.implements = [];
@@ -469,6 +497,7 @@ export class YamlDocumenter {
469497
for (const extendsType of apiItem.extendsTypes) {
470498
yamlItem.extends.push(this._renderType(uid, extendsType.excerpt));
471499
}
500+
yamlItem.inheritance = this._renderInheritance(uid, apiItem.extendsTypes);
472501
}
473502

474503
const typeParameters: IYamlParameter[] = this._populateYamlTypeParameters(uid, apiItem);
@@ -565,6 +594,41 @@ export class YamlDocumenter {
565594
}
566595
}
567596

597+
private _populateYamlVariable(uid: DeclarationReference, yamlItem: Partial<IYamlItem>, apiItem: ApiVariable):
598+
void {
599+
600+
const syntax: IYamlSyntax = {
601+
content: apiItem.getExcerptWithModifiers()
602+
};
603+
yamlItem.syntax = syntax;
604+
605+
if (apiItem.variableTypeExcerpt.text) {
606+
syntax.return = {
607+
type: [ this._renderType(uid, apiItem.variableTypeExcerpt) ]
608+
};
609+
}
610+
}
611+
612+
private _populateYamlTypeAlias(uid: DeclarationReference, yamlItem: Partial<IYamlItem>, apiItem: ApiTypeAlias):
613+
void {
614+
615+
const syntax: IYamlSyntax = {
616+
content: apiItem.getExcerptWithModifiers()
617+
};
618+
yamlItem.syntax = syntax;
619+
620+
const typeParameters: IYamlParameter[] = this._populateYamlTypeParameters(uid, apiItem);
621+
if (typeParameters.length) {
622+
syntax.typeParameters = typeParameters;
623+
}
624+
625+
if (apiItem.typeExcerpt.text) {
626+
syntax.return = {
627+
type: [ this._renderType(uid, apiItem.typeExcerpt) ]
628+
};
629+
}
630+
}
631+
568632
private _renderMarkdown(docSection: DocSection, contextApiItem: ApiItem): string {
569633
const stringBuilder: StringBuilder = new StringBuilder();
570634

@@ -649,6 +713,30 @@ export class YamlDocumenter {
649713
return this._yamlReferences;
650714
}
651715

716+
private _renderInheritance(contextUid: DeclarationReference, heritageTypes: ReadonlyArray<HeritageType>):
717+
IYamlInheritanceTree[] {
718+
719+
const result: IYamlInheritanceTree[] = [];
720+
for (const heritageType of heritageTypes) {
721+
const type: string = this._renderType(contextUid, heritageType.excerpt);
722+
const yamlInheritance: IYamlInheritanceTree = { type };
723+
const apiItem: ApiItem | undefined = this._apiItemsByCanonicalReference.get(type);
724+
if (apiItem) {
725+
if (apiItem instanceof ApiClass) {
726+
if (apiItem.extendsType) {
727+
yamlInheritance.inheritance = this._renderInheritance(this._getUidObject(apiItem), [apiItem.extendsType]);
728+
}
729+
} else if (apiItem instanceof ApiInterface) {
730+
if (apiItem.extendsTypes.length > 0) {
731+
yamlInheritance.inheritance = this._renderInheritance(this._getUidObject(apiItem), apiItem.extendsTypes);
732+
}
733+
}
734+
}
735+
result.push(yamlInheritance);
736+
}
737+
return result;
738+
}
739+
652740
private _renderType(contextUid: DeclarationReference, typeExcerpt: Excerpt): string {
653741
const excerptTokens: ExcerptToken[] = typeExcerpt.tokens.slice(
654742
typeExcerpt.tokenRange.startIndex,
@@ -686,10 +774,13 @@ export class YamlDocumenter {
686774
if (excerptTokens.length === 1 &&
687775
excerptTokens[0].kind === ExcerptTokenKind.Reference &&
688776
excerptTokens[0].canonicalReference) {
777+
const excerptRef: string = excerptTokens[0].canonicalReference.toString();
778+
const apiItem: ApiItem | undefined = this._apiItemsByCanonicalReference.get(excerptRef);
689779
return this._recordYamlReference(
690780
yamlReferences,
691781
excerptTokens[0].canonicalReference.toString(),
692-
typeName
782+
apiItem ? this._getYamlItemName(apiItem) : typeName,
783+
apiItem ? this._getYamlItemName(apiItem, { includeNamespace: true }) : typeName
693784
);
694785
}
695786

@@ -711,10 +802,10 @@ export class YamlDocumenter {
711802
.withOverloadIndex(undefined)
712803
.toString();
713804

714-
return this._recordYamlReference(yamlReferences, uid, typeName, excerptTokens);
805+
return this._recordYamlReference(yamlReferences, uid, typeName, typeName, excerptTokens);
715806
}
716807

717-
private _recordYamlReference(yamlReferences: IYamlReferences, uid: string, typeName: string,
808+
private _recordYamlReference(yamlReferences: IYamlReferences, uid: string, name: string, fullName: string,
718809
excerptTokens?: ExcerptToken[]): string {
719810

720811
if (yamlReferences.references.some(ref => ref.uid === uid)) {
@@ -758,17 +849,24 @@ export class YamlDocumenter {
758849
yamlReference.name = specs.map(s => s.name).join('').trim();
759850
yamlReference.fullName = specs.map(s => s.fullName || s.name).join('').trim();
760851
yamlReference['spec.typeScript'] = specs;
761-
} else if (typeName !== uid) {
762-
yamlReference.name = typeName;
852+
} else {
853+
if (name !== uid) {
854+
yamlReference.name = name;
855+
}
856+
if (fullName !== uid && fullName !== name) {
857+
yamlReference.fullName = fullName;
858+
}
763859
}
764860

765861
yamlReferences.references.push(yamlReference);
766862
return uid;
767863
}
768864

769-
private _getYamlItemName(apiItem: ApiItem, includeSignature: boolean): string {
865+
private _getYamlItemName(apiItem: ApiItem, options: INameOptions = {}): string {
866+
const { includeSignature, includeNamespace } = options;
770867
const baseName: string = includeSignature ? Utilities.getConciseSignature(apiItem) : apiItem.displayName;
771-
if (apiItem.parent && apiItem.parent.kind === ApiItemKind.Namespace) {
868+
if ((includeNamespace || apiItem.kind === ApiItemKind.Namespace) && apiItem.parent &&
869+
apiItem.parent.kind === ApiItemKind.Namespace) {
772870
// If the immediate parent is a namespace, then add the namespaces to the name. For example:
773871
//
774872
// // Name: "N1"

0 commit comments

Comments
 (0)