import { Contracts , ExtractDto } from "ts-extractor" ; import { MarkdownGenerator , MarkdownBuilder , Contracts as MarkdownContracts } from "@simplrjs/markdown" ; import { LogLevel } from "simplr-logger" ; import * as path from "path" ; import { Helpers } from "./utils/helpers" ; import { PluginResult , PluginHeading } from "./contracts/plugin" ; import { FileResult } from "./contracts/file-result" ; import { GeneratorHelpers } from "./generator-helpers" ; import { ApiContainer , ContainerMembersKindsGroup } from "./abstractions/container-plugin" ; import { ApiClassPlugin } from "./plugins/api-class-plugin" ; import { ApiSourceFilePlugin } from "./plugins/api-source-file-plugin" ; import { ApiNamespacePlugin } from "./plugins/api-namespace-plugin" ; export class FileManager { constructor ( private extractedData ) { } /**
     * <FileLocation, RenderedItems>
     */ private filesList : Map < string , PluginResult < ApiContainer > > = new Map ( ) ; /**
     * <ReferenceId, FileLocation>
     */ private referenceToFile : Map < string , string > = new Map ( ) ; private resolveMemberKindsList ( apiItemKind ) { switch ( apiItemKind ) { case Contracts . ApiDefinitionKind . Class : { return ApiClassPlugin . MemberKindsList ; } case Contracts . ApiDefinitionKind . Namespace : { return ApiNamespacePlugin . MemberKindsList ; } case Contracts . ApiDefinitionKind . SourceFile : { return ApiSourceFilePlugin . MemberKindsList ; } } } private renderTableOfContents ( containerResult ) { const memberKindsList = this . resolveMemberKindsList ( containerResult . ApiItem . ApiKind ) ; if ( memberKindsList == null ) { return [ ] ; } const tableList = [ ] ; containerResult . Headings . forEach ( heading => { const headingMembers = heading . Members ; if ( headingMembers == null || headingMembers . length === 0 ) { return ; } const headingLink = MarkdownGenerator . Link ( heading . Heading , heading . ApiItemId , true ) ; tableList . push ( headingLink ) ; memberKindsList . forEach ( memberKindGroup => { const membersOfKind = headingMembers . filter ( x => memberKindGroup . Kinds . indexOf ( this . extractedData . Registry [ x . ApiItemId ] . ApiKind ) !== - 1 ) ; if ( membersOfKind . length === 0 ) { return [ ] ; } const membersReferences = membersOfKind . map ( x => MarkdownGenerator . Link ( x . Heading , x . ApiItemId , true ) ) ; tableList . push ( [ memberKindGroup . Heading , membersReferences ] ) ; } ) ; } ) ; if ( tableList . length === 0 ) { return [ ] ; } return new MarkdownBuilder ( ) . Header ( "Table of contents" , 1 ) . EmptyLine ( ) . UnorderedList ( tableList ) . EmptyLine ( ) . GetOutput ( ) ; } public AddEntryFile ( itemResult ) { const filePath = path . basename ( itemResult . ApiItem . Location . FileName , path . extname ( itemResult . ApiItem . Location . FileName ) ) + GeneratorHelpers . MARKDOWN_EXT ; this . AddItem ( itemResult , filePath ) ; } private addItemHeadings ( headings , filePath ) { for ( const heading of headings ) { this . referenceToFile . set ( heading . ApiItemId , `${ filePath }#${ Helpers . HeadingToAnchor ( heading . Heading ) }` ) ; if ( heading . Members != null ) { this . addItemHeadings ( heading . Members , filePath ) ; } } } private resolveReferenceFile ( referenceId ) { const apiItem = this . extractedData . Registry [ referenceId ] ; const serializedApiItem = GeneratorHelpers . SerializeApiDefinition ( this . extractedData , apiItem , { Alias : apiItem . Name , Id : referenceId } ) ; if ( ! this . referenceToFile . has ( referenceId ) && serializedApiItem . ParentItem != null ) { return this . resolveReferenceFile ( serializedApiItem . ParentItem . Reference . Id ) ; } return this . referenceToFile . get ( referenceId ) ; } private removeBrokenLinks ( result , referenceId ) { const linkDefinition = new RegExp ( `\\[(.+)\\]\\[${ referenceId }\\]` , "g" ) ; return result . map ( x => x . replace ( linkDefinition , "$1" ) ) ; } public AddItem ( itemResult , filePath ) { if ( this . filesList . get ( filePath ) == null ) { this . filesList . set ( filePath , itemResult ) ; } this . filesList . set ( filePath , itemResult ) ; this . addItemHeadings ( itemResult . Headings , filePath ) ; if ( itemResult . Members != null ) { for ( const member of itemResult . Members ) { const baseName = path . basename ( filePath , path . extname ( filePath ) ) ; const targetFilePath = path . join ( path . dirname ( filePath ) , baseName , member . PluginResult . ApiItem . Name + GeneratorHelpers . MARKDOWN_EXT ) . toLowerCase ( ) ; this . AddItem ( member . PluginResult , targetFilePath ) ; } } } public ToFilesOutput ( ) { const files = [ ] ; for ( const [ fileLocation , item ] of this . filesList ) { const linkDefinitions = [ ] ; let pluginResult = item . Result ; item . UsedReferences . forEach ( referenceId => { const filePath = path . dirname ( fileLocation ) ; const referenceString = this . resolveReferenceFile ( referenceId ) ; if ( referenceString ) { const resolvePath = GeneratorHelpers . StandardizePath ( path . relative ( filePath , referenceString ) ) ; linkDefinitions . push ( MarkdownGenerator . LinkDefinition ( referenceId , resolvePath ) ) ; } else { pluginResult = this . removeBrokenLinks ( pluginResult , referenceId ) ; const apiItem = this . extractedData . Registry [ referenceId ] ; GeneratorHelpers . LogWithApiItemPosition ( LogLevel . Warning , apiItem , "Declaration is used as type and not exported in entry files." ) ; } } ) ; files . push ( { FileLocation : GeneratorHelpers . StandardizePath ( fileLocation ) , Result : [ ... this . renderTableOfContents ( item ) , ... pluginResult , ... linkDefinitions ] } ) ; } return files ; } }