import { DocCollection , Document , Processor } from 'dgeni' ; import { ApiDoc } from 'dgeni-packages/typescript/api-doc-types/ApiDoc' ; import { ConstExportDoc } from 'dgeni-packages/typescript/api-doc-types/ConstExportDoc' ; import { FunctionExportDoc } from 'dgeni-packages/typescript/api-doc-types/FunctionExportDoc' ; import { InterfaceExportDoc } from 'dgeni-packages/typescript/api-doc-types/InterfaceExportDoc' ; import { TypeAliasExportDoc } from 'dgeni-packages/typescript/api-doc-types/TypeAliasExportDoc' ; import * as path from 'path' ; import { computeApiDocumentUrl } from '../common/compute-api-url' ; import { isDeprecatedDoc , isPrimaryExportDoc } from '../common/decorators' ; import { CategorizedClassDoc } from '../common/dgeni-definitions' ; export interface ModuleInfo { /** Name of the module (e.g. toolbar, drag-drop, ripple, slider-testing) */ name : string ; /** Name of the package that contains this entry point. */ packageName : string ; /** Name of the entry-point that contains this module. */ entryPointName : string ; } /** Document type for an entry-point. */ export class EntryPointDoc { /** Unique document type for Dgeni. */ docType = 'entry-point' ; /** Name of the component group. */ name : string ; /** Display name of the entry-point. */ displayName : string ; /** Module import path for the entry-point. */ moduleImportPath : string ; /** Name of the package, either material or cdk */ packageName : string ; /** Display name of the package. */ packageDisplayName : string ; /** Unique id for the entry-point. */ id : string ; /** Known aliases for the entry-point. This is only needed for the `computeIdsProcessor`. */ aliases : string [ ] = [ ] ; /** List of categorized class docs that are defining a directive. */ directives : CategorizedClassDoc [ ] = [ ] ; /** List of categorized class docs that are defining a service. */ services : CategorizedClassDoc [ ] = [ ] ; /** Classes that belong to the entry-point. */ classes : CategorizedClassDoc [ ] = [ ] ; /** Interfaces that belong to the entry-point. */ interfaces : InterfaceExportDoc [ ] = [ ] ; /** Type aliases that belong to the entry-point. */ typeAliases : TypeAliasExportDoc [ ] = [ ] ; /** Functions that belong to the entry-point. */ functions : FunctionExportDoc [ ] = [ ] ; /** Constants that belong to the entry-point. */ constants : ConstExportDoc [ ] = [ ] ; /** List of NgModules which are exported in the current entry-point. */ exportedNgModules : CategorizedClassDoc [ ] = [ ] ; /** List of test harnesses which are exported in the entry-point. */ testHarnesses : CategorizedClassDoc [ ] = [ ] ; /**
     * Name of the primary export of the entry-point. This export will be showed
     * in the API docs as export when show-casing the import to the entry-point.
     */ primaryExportName : string | null = null ; constructor ( name ) { this . name = name ; this . id = `entry-point-${ name }` ; } } /**
 * Processor to group docs into entry-points that consist of directives, component, classes,
 * interfaces, functions or type aliases.
 */ export class EntryPointGrouper implements Processor { name = 'entryPointGrouper' ; $runBefore = [ 'docs-processed' ] ; entryPoints : string [ ] = [ ] ; $process ( docs ) { const entryPoints = new Map < string , EntryPointDoc > ( ) ; docs . forEach ( ( doc ) => { const moduleInfo = this . _getModulePackageInfo ( doc ) ; const packageName = moduleInfo . packageName ; const packageDisplayName = packageName . replace ( 'angular-' , '' ) . replace ( /^\w/ , ( m ) => m . toUpperCase ( ) ) ; const moduleImportPath = `@sbb-esta/${ packageName }/${ moduleInfo . entryPointName }` ; const entryPointName = packageName + '-' + moduleInfo . name ; doc . publicUrl = computeApiDocumentUrl ( doc , moduleInfo ) ; let entryPoint ; if ( entryPoints . has ( entryPointName ) ) { entryPoint = entryPoints . get ( entryPointName ) ! ; } else { entryPoint = new EntryPointDoc ( entryPointName ) ; entryPoints . set ( entryPointName , entryPoint ) ; } entryPoint . displayName = moduleInfo . name ; entryPoint . moduleImportPath = moduleImportPath ; entryPoint . packageName = packageName ; entryPoint . packageDisplayName = packageDisplayName ; if ( doc . isDirective ) { entryPoint . directives . push ( doc ) ; } else if ( doc . isService ) { entryPoint . services . push ( doc ) ; } else if ( doc . isNgModule ) { entryPoint . exportedNgModules . push ( doc ) ; } else if ( doc . docType === 'class' ) { entryPoint . classes . push ( doc ) ; if ( doc . isTestHarness ) { entryPoint . testHarnesses . push ( doc ) ; } } else if ( doc . docType === 'interface' ) { entryPoint . interfaces . push ( doc ) ; } else if ( doc . docType === 'type-alias' ) { entryPoint . typeAliases . push ( doc ) ; } else if ( doc . docType === 'function' ) { entryPoint . functions . push ( doc ) ; } else if ( doc . docType === 'const' ) { entryPoint . constants . push ( doc ) ; } if ( isPrimaryExportDoc ( doc ) ) { entryPoint . primaryExportName = doc . name ; } } ) ; entryPoints . forEach ( ( entryPoint ) => { if ( entryPoint . primaryExportName !== null ) { return ; } const ngModuleExport = this . _findBestPrimaryExport ( entryPoint . exportedNgModules ) ; if ( ngModuleExport !== null ) { entryPoint . primaryExportName = ngModuleExport . name ; return ; } const testHarnessExport = this . _findBestPrimaryExport ( entryPoint . testHarnesses ) ; if ( testHarnessExport !== null ) { entryPoint . primaryExportName = testHarnessExport . name ; } } ) ; return Array . from ( entryPoints . values ( ) ) ; } /**
     * Walks through the specified API documents and looks for the best
     * API document that could serve as primary export of an entry-point.
     */ private _findBestPrimaryExport ( docs ) { for ( const doc of docs ) { if ( ! isDeprecatedDoc ( doc ) ) { return doc ; } } return null ; } /** Resolves module package information of the given Dgeni document. */ private _getModulePackageInfo ( doc ) { const basePath = doc . fileInfo . basePath ; const filePath = doc . fileInfo . filePath ; const relativeFilePath = path . relative ( basePath , filePath ) . replace ( /\\/g , '/' ) ; const foundEntryPoint = this . _findMatchingEntryPoint ( relativeFilePath ) ; if ( ! foundEntryPoint ) { throw Error ( `Could not determine entry-point for: ${ doc . name } in ${ relativeFilePath }` ) ; } const pathSegments = foundEntryPoint . split ( '/' ) ; const entryPointName = pathSegments . slice ( 1 ) ; let moduleName = entryPointName . join ( '-' ) ; if ( relativeFilePath . startsWith ( 'material/core/ripple' ) ) { moduleName = 'ripple' ; } return { name : moduleName , packageName : pathSegments [ 0 ] , entryPointName : entryPointName . join ( '/' ) , } ; } /** Finds the matching entry-point of the given file path. */ private _findMatchingEntryPoint ( relativeFilePath ) { let foundEntryPoint = null ; if ( relativeFilePath . startsWith ( '../external/npm/node_modules/@angular' ) ) { return path . dirname ( relativeFilePath . substr ( 29 ) ) ; } for ( const entryPoint of this . entryPoints ) { if ( ! relativeFilePath . startsWith ( entryPoint ) ) { continue ; } if ( foundEntryPoint === null || entryPoint . length > foundEntryPoint . length ) { foundEntryPoint = entryPoint ; } } return foundEntryPoint ; } }