/**
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License.
 */ import { NodeTypes } from "./APEModels" ; export interface IOptions { fallbackToOriginal : boolean ; preserveOptionalNodeWrappingCharacters : boolean ; } const defaultOptions = { fallbackToOriginal : false , preserveOptionalNodeWrappingCharacters : false } ; function serialize ( value , entityValuesMap , userOptions = { } ) { const options = { ... defaultOptions , ... userOptions } ; const valueAsJson = typeof value . toJSON === 'function' ? value . toJSON ( ) : value ; const valueAsJsonClone = JSON . parse ( JSON . stringify ( valueAsJson ) ) ; const processedDocument = removeOptionalNodesWithoutEntityValues ( valueAsJsonClone . document , Array . from ( entityValuesMap . keys ( ) ) ) ; return serializeNode ( processedDocument , entityValuesMap , options ) ; } param node param entityValues function removeOptionalNodesWithoutEntityValues ( node , entityIds ) { if ( node . kind === 'inline' && node . type === NodeTypes . Optional ) { const entityIdsWithinOptionalNode = getEntityIds ( node ) ; const hasValues = entityIdsWithinOptionalNode . every ( x => entityIds . includes ( x ) ) ; return hasValues ? node : undefined ; } if ( Array . isArray ( node . nodes ) ) { node . nodes = node . nodes . map ( ( n ) => removeOptionalNodesWithoutEntityValues ( n , entityIds ) ) . filter ( ( n ) => n ) ; } return node ; } function getEntityIds ( node ) { const entityIds = [ ] ; if ( node . kind === 'inline' && node . type === NodeTypes . Mention ) { const data = typeof node . data . toJS === 'function' ? node . data . toJS ( ) : node . data ; const option = data . option ; if ( option ) { const entityId = option . id ; entityIds . push ( entityId ) ; } else { console . warn ( `Attempting to serialize inline node but it did not have option` ) ; } } if ( Array . isArray ( node . nodes ) ) { const childrenEntityIds = node . nodes . map ( ( n ) => getEntityIds ( n ) ) . reduce ( ( totalIds , nodeIds ) => [ ... totalIds , ... nodeIds ] , [ ] ) ; entityIds . push ( ... childrenEntityIds ) ; } return entityIds ; } function serializeNode ( node , entityValues , options ) { if ( node . kind === 'text' ) { return node . leaves . map ( ( n ) => n . text ) . join ( '' ) ; } const serializedChildNodes = node . nodes . map ( ( n ) => serializeNode ( n , entityValues , options ) ) ; if ( node . kind === 'inline' && node . type === NodeTypes . Mention ) { const data = typeof node . data . toJS === 'function' ? node . data . toJS ( ) : node . data ; if ( ! data . completed ) { return serializedChildNodes . join ( '' ) ; } const option = data . option ; if ( ! option ) { throw new Error ( `Attempting to serialize inline node but it did not have option` ) ; } const entityId = option . id ; const mapContainsEntity = entityValues . has ( entityId ) ; if ( ! mapContainsEntity ) { if ( options . fallbackToOriginal ) { return serializedChildNodes . join ( '' ) ; } const entityValuesString = Array . from ( entityValues . entries ( ) ) . map ( ( [ id , value ] ) => `${ id }: ${ value }` ) . join ( ', ' ) ; throw new Error ( `Inline node representing entity ${ entityId } was NOT provided a value in the given entityValue map: [${ entityValuesString }]` ) ; } return entityValues . get ( entityId ) ! ; } if ( node . kind === 'document' ) { return serializedChildNodes . join ( '\n' ) ; } const serializedChildren = serializedChildNodes . join ( '' ) ; return ( node . kind === 'inline' && node . type === NodeTypes . Optional ) ? options . preserveOptionalNodeWrappingCharacters ? serializedChildren : serializedChildren . slice ( 1 , - 1 ) : serializedChildren ; } export default { serialize , getEntityIds , } ;