import { DocComment , DocInlineTag } from '@microsoft/tsdoc' ; import { ApiModel , ApiItem , ApiItemKind , ApiDocumentedItem } from '@microsoft/api-extractor-model' ; import { IConfigTableOfContents } from './IConfigFile' ; import { IYamlTocItem , IYamlTocFile } from '../yaml/IYamlTocFile' ; import { YamlDocumenter } from './YamlDocumenter' ; import { DocumenterConfig } from './DocumenterConfig' ; /**
 * EXPERIMENTAL - This documenter is a prototype of a new config file driven mode of operation for
 * API Documenter.  It is not ready for general usage yet.  Its design may change in the future.
 */ export class ExperimentalYamlDocumenter extends YamlDocumenter { private _config : IConfigTableOfContents ; private _tocPointerMap : { [ key ] : IYamlTocItem ; } ; private _catchAllPointer : IYamlTocItem | undefined ; public constructor ( apiModel , documenterConfig ) { super ( apiModel , documenterConfig . configFile . newDocfxNamespaces ) ; this . _config = documenterConfig . configFile . tableOfContents ! ; this . _tocPointerMap = { } ; this . _generateTocPointersMap ( this . _config . tocConfig ) ; } @override  protected buildYamlTocFile ( apiItems ) { this . _buildTocItems2 ( apiItems ) ; return this . _config . tocConfig ; } private _buildTocItems2 ( apiItems ) { const tocItems = [ ] ; for ( const apiItem of apiItems ) { let tocItem ; if ( apiItem . kind === ApiItemKind . Namespace && ! this . newDocfxNamespaces ) { tocItem = { name : this . _getTocItemName ( apiItem ) } ; } else { if ( this . _shouldEmbed ( apiItem . kind ) ) { continue ; } tocItem = { name : this . _getTocItemName ( apiItem ) , uid : this . _getUid ( apiItem ) } ; if ( apiItem . kind !== ApiItemKind . Package ) { this . _filterItem ( apiItem , tocItem ) ; } } tocItems . push ( tocItem ) ; const children = this . _getLogicalChildren ( apiItem ) ; const childItems = this . _buildTocItems2 ( children ) ; if ( childItems . length > 0 ) { tocItem . items = childItems ; } } return tocItems ; } private _generateTocPointersMap ( tocConfig ) { const { catchAllCategory } = this . _config ; if ( tocConfig . items ) { for ( const tocItem of tocConfig . items ) { if ( tocItem . items && tocItem . items . length > 0 && this . _shouldNotIncludeInPointersMap ( tocItem ) ) { this . _generateTocPointersMap ( tocItem ) ; } else { if ( catchAllCategory && tocItem . name === catchAllCategory ) { this . _catchAllPointer = tocItem ; } else { this . _tocPointerMap [ tocItem . name ] = tocItem ; } } } } } /**
     * Filtering out the api-item by inlineTags or category name presence in the item name.
     */ private _filterItem ( apiItem , tocItem ) { const { categoryInlineTag , categorizeByName } = this . _config ; const { name : itemName } = tocItem ; let filtered = false ; if ( apiItem instanceof ApiDocumentedItem ) { const docInlineTag = categoryInlineTag ? this . _findInlineTagByName ( categoryInlineTag , apiItem . tsdocComment ) : undefined ; const tagContent = docInlineTag && docInlineTag . tagContent && docInlineTag . tagContent . trim ( ) ; if ( tagContent && this . _tocPointerMap [ tagContent ] ) { this . _tocPointerMap [ tagContent ] . items ! . push ( tocItem ) ; filtered = true ; } } if ( ! filtered && categorizeByName ) { const pointers = Object . keys ( this . _tocPointerMap ) ; for ( let i = 0 , length = pointers . length ; i < length ; i ++ ) { if ( itemName . indexOf ( pointers [ i ] ) !== - 1 ) { this . _tocPointerMap [ pointers [ i ] ] . items ! . push ( tocItem ) ; filtered = true ; break ; } } } if ( ! filtered && this . _catchAllPointer && this . _catchAllPointer . items ) { this . _catchAllPointer . items . push ( tocItem ) ; } } private _findInlineTagByName ( tagName , docComment ) { const tagNameToCheck = `@${ tagName }` ; if ( docComment instanceof DocInlineTag ) { if ( docComment . tagName === tagNameToCheck ) { return docComment ; } } if ( docComment ) { for ( const childNode of docComment . getChildNodes ( ) ) { const result = this . _findInlineTagByName ( tagName , childNode as DocComment ) ; if ( result !== undefined ) { return result ; } } } return undefined ; } private _shouldNotIncludeInPointersMap ( item ) { const { nonEmptyCategoryNodeNames } = this . _config ; if ( nonEmptyCategoryNodeNames && nonEmptyCategoryNodeNames . length ) { return nonEmptyCategoryNodeNames . indexOf ( item . name ) === - 1 ; } return true ; } }