/** * Internal dependencies */ import { normaliseFormats } from './normalise-formats'; import { RichTextFormatList, RichTextValue } from './types'; /** * Search a Rich Text value and replace the match(es) with `replacement`. This * is similar to `String.prototype.replace`. * * @param {RichTextValue} value The value to modify. * @param {RegExp|string} pattern A RegExp object or literal. Can also be * a string. It is treated as a verbatim * string and is not interpreted as a * regular expression. Only the first * occurrence will be replaced. * @param {Function|string} replacement The match or matches are replaced with * the specified or the value returned by * the specified function. * * @return {RichTextValue} A new value with replacements applied. */ export function replace( { formats, replacements, text, start, end }: RichTextValue, pattern: RegExp|string, replacement: (s: string, ...rest: any[]) => (string|RichTextValue)|string, ): RichTextValue { text = text.replace( pattern, ( match, ...rest ) => { const offset = rest[ rest.length - 2 ]; let newFormats: Array; let newReplacements: Array; let newText = (typeof replacement === 'function') ? replacement( match, ...rest ) : replacement; if ( typeof newText === 'object' ) { newFormats = newText.formats; newReplacements = newText.replacements; newText = newText.text; } else { newFormats = Array( newText.length ); newReplacements = Array( newText.length ); if ( formats[ offset ] ) { newFormats = newFormats.fill( formats[ offset ] ); } } formats = formats .slice( 0, offset ) .concat( newFormats, formats.slice( offset + match.length ) ); replacements = replacements .slice( 0, offset ) .concat( newReplacements, replacements.slice( offset + match.length ) ); if ( start ) { start = end = offset + newText.length; } return newText; } ); return normaliseFormats( { formats, replacements, text, start, end } ); }