1*082815dcSEvan Baconexport interface CodeBlock { 2*082815dcSEvan Bacon start: number; 3*082815dcSEvan Bacon end: number; 4*082815dcSEvan Bacon code: string; 5*082815dcSEvan Bacon} 6*082815dcSEvan Bacon 7*082815dcSEvan Bacon/** 8*082815dcSEvan Bacon * Insert contents at given offset 9*082815dcSEvan Bacon * @param srcContents source contents 10*082815dcSEvan Bacon * @param insertion content to insert 11*082815dcSEvan Bacon * @param offset `srcContents` offset to insert `insertion` 12*082815dcSEvan Bacon * @returns updated contents 13*082815dcSEvan Bacon */ 14*082815dcSEvan Baconexport function insertContentsAtOffset( 15*082815dcSEvan Bacon srcContents: string, 16*082815dcSEvan Bacon insertion: string, 17*082815dcSEvan Bacon offset: number 18*082815dcSEvan Bacon): string { 19*082815dcSEvan Bacon const srcContentsLength = srcContents.length; 20*082815dcSEvan Bacon if (offset < 0 || offset > srcContentsLength) { 21*082815dcSEvan Bacon throw new Error('Invalid parameters.'); 22*082815dcSEvan Bacon } 23*082815dcSEvan Bacon if (offset === 0) { 24*082815dcSEvan Bacon return `${insertion}${srcContents}`; 25*082815dcSEvan Bacon } else if (offset === srcContentsLength) { 26*082815dcSEvan Bacon return `${srcContents}${insertion}`; 27*082815dcSEvan Bacon } 28*082815dcSEvan Bacon 29*082815dcSEvan Bacon const prefix = srcContents.substring(0, offset); 30*082815dcSEvan Bacon const suffix = srcContents.substring(offset); 31*082815dcSEvan Bacon return `${prefix}${insertion}${suffix}`; 32*082815dcSEvan Bacon} 33*082815dcSEvan Bacon 34*082815dcSEvan Bacon/** 35*082815dcSEvan Bacon * Replace contents at given start and end offset 36*082815dcSEvan Bacon * 37*082815dcSEvan Bacon * @param contents source contents 38*082815dcSEvan Bacon * @param replacement new contents to place in [startOffset:endOffset] 39*082815dcSEvan Bacon * @param startOffset `contents` start offset for replacement 40*082815dcSEvan Bacon * @param endOffset `contents` end offset for replacement 41*082815dcSEvan Bacon * @returns updated contents 42*082815dcSEvan Bacon */ 43*082815dcSEvan Baconexport function replaceContentsWithOffset( 44*082815dcSEvan Bacon contents: string, 45*082815dcSEvan Bacon replacement: string, 46*082815dcSEvan Bacon startOffset: number, 47*082815dcSEvan Bacon endOffset: number 48*082815dcSEvan Bacon): string { 49*082815dcSEvan Bacon const contentsLength = contents.length; 50*082815dcSEvan Bacon if ( 51*082815dcSEvan Bacon startOffset < 0 || 52*082815dcSEvan Bacon endOffset < 0 || 53*082815dcSEvan Bacon startOffset >= contentsLength || 54*082815dcSEvan Bacon endOffset >= contentsLength || 55*082815dcSEvan Bacon startOffset > endOffset 56*082815dcSEvan Bacon ) { 57*082815dcSEvan Bacon throw new Error('Invalid parameters.'); 58*082815dcSEvan Bacon } 59*082815dcSEvan Bacon const prefix = contents.substring(0, startOffset); 60*082815dcSEvan Bacon const suffix = contents.substring(endOffset + 1); 61*082815dcSEvan Bacon return `${prefix}${replacement}${suffix}`; 62*082815dcSEvan Bacon} 63*082815dcSEvan Bacon 64*082815dcSEvan Bacon/** 65*082815dcSEvan Bacon * String.prototype.search() with offset support 66*082815dcSEvan Bacon * 67*082815dcSEvan Bacon * @param source source string to search 68*082815dcSEvan Bacon * @param regexp RegExp pattern to search 69*082815dcSEvan Bacon * @param offset start offset of `source` to search `regexp` pattern 70*082815dcSEvan Bacon * @returns The index of the first match between the regular expression and the given string, or -1 if no match was found. 71*082815dcSEvan Bacon */ 72*082815dcSEvan Baconexport function searchFromOffset(source: string, regexp: RegExp, offset: number): number { 73*082815dcSEvan Bacon const target = source.substring(offset); 74*082815dcSEvan Bacon const matchedIndex = target.search(regexp); 75*082815dcSEvan Bacon return matchedIndex < 0 ? matchedIndex : matchedIndex + offset; 76*082815dcSEvan Bacon} 77