import { assert , stringToBuffer , Uint8ArrayToString , unreachableCase } from "@fluidframework/common-utils" ; import { getGitType } from "@fluidframework/protocol-base" ; import { ISnapshotTree , SummaryType } from "@fluidframework/protocol-definitions" ; import { ISummaryTree , IWholeSummaryTree , WholeSummaryTreeValue , IWholeSummaryTreeBaseEntry , WholeSummaryTreeEntry , IEmbeddedSummaryHandle , IWholeFlatSummaryTree , IWholeFlatSummary , INormalizedWholeSummary , } from "./storageContracts" ; param nodeNames export const buildTreePath = ( ... nodeNames ) : string => nodeNames . map ( ( nodeName ) => nodeName . replace ( /^\// , "" ) . replace ( /\/$/ , "" ) ) . filter ( ( nodeName ) => ! ! nodeName ) . join ( "/" ) ; param parentHandle param tree param path export function convertSummaryTreeToWholeSummaryTree ( parentHandle , tree , path = "" , rootNodeName = "" ) { const wholeSummaryTree = { type : "tree" , entries : [ ] as WholeSummaryTreeEntry [ ] } ; const keys = Object . keys ( tree . tree ) ; for ( const key of keys ) { const summaryObject = tree . tree [ key ] ; let id ; let value ; let unreferenced ; const currentPath = path === "" ? buildTreePath ( rootNodeName , key ) : buildTreePath ( path , key ) ; switch ( summaryObject . type ) { case SummaryType . Tree : { const result = convertSummaryTreeToWholeSummaryTree ( parentHandle , summaryObject , currentPath , rootNodeName ) ; value = result ; unreferenced = summaryObject . unreferenced || undefined ; break ; } case SummaryType . Blob : { if ( typeof summaryObject . content === "string" ) { value = { type : "blob" , content : summaryObject . content , encoding : "utf-8" } ; } else { value = { type : "blob" , content : Uint8ArrayToString ( summaryObject . content , "base64" ) , encoding : "base64" } ; } break ; } case SummaryType . Handle : { const handleValue = summaryObject as IEmbeddedSummaryHandle ; if ( handleValue . embedded ) { id = summaryObject . handle ; } else { if ( ! parentHandle ) { throw Error ( "Parent summary does not exist to reference by handle." ) ; } id = buildTreePath ( parentHandle , rootNodeName , summaryObject . handle ) ; } break ; } case SummaryType . Attachment : { id = summaryObject . id ; break ; } default : { unreachableCase ( summaryObject , `Unknown type: ${ ( summaryObject as any ) . type }` ) ; } } const baseEntry = { path : encodeURIComponent ( key ) , type : getGitType ( summaryObject ) } ; let entry ; if ( value ) { assert ( id === undefined , 0x0ad ) ; entry = { value , unreferenced , ... baseEntry } ; } else if ( id ) { entry = { ... baseEntry , id } ; } else { throw new Error ( `Invalid tree entry for ${ summaryObject . type }` ) ; } wholeSummaryTree . entries . push ( entry ) ; } return wholeSummaryTree ; } param flatTree returns function buildHeirarchy ( flatTree ) { const lookup = { } ; const root = { id : flatTree . id , blobs : { } , trees : { } , commits : { } } ; lookup [ "" ] = root ; for ( const entry of flatTree . entries ) { const entryPath = entry . path . replace ( /^\.app\// , "" ) ; const lastIndex = entryPath . lastIndexOf ( "/" ) ; const entryPathDir = entryPath . slice ( 0 , Math . max ( 0 , lastIndex ) ) ; const entryPathBase = entryPath . slice ( lastIndex + 1 ) ; const node = lookup [ entryPathDir ] ; if ( entry . type === "tree" ) { const newTree = { blobs : { } , commits : { } , trees : { } , unreferenced : entry . unreferenced } ; node . trees [ decodeURIComponent ( entryPathBase ) ] = newTree ; lookup [ entryPath ] = newTree ; } else if ( entry . type === "blob" ) { node . blobs [ decodeURIComponent ( entryPathBase ) ] = entry . id ; } else { throw new Error ( `Unknown entry type!!` ) ; } } return root ; } param flatSummary export function convertWholeFlatSummaryToSnapshotTreeAndBlobs ( flatSummary ) { const blobs = new Map < string , ArrayBuffer > ( ) ; if ( flatSummary . blobs ) { flatSummary . blobs . forEach ( ( blob ) => { blobs . set ( blob . id , stringToBuffer ( blob . content , blob . encoding ?? "utf-8" ) ) ; } ) ; } const flatSummaryTree = flatSummary . trees && flatSummary . trees [ 0 ] ; const sequenceNumber = flatSummaryTree ?. sequenceNumber ; const snapshotTree = buildHeirarchy ( flatSummaryTree ) ; return { blobs , snapshotTree , sequenceNumber } ; }