1// Copyright (c) Jupyter Development Team. 2// Distributed under the terms of the Modified BSD License. 3'use strict'; 4 5import { 6 sortByKey, shallowCopy, accumulateLengths, splitLines 7} from '../common/util'; 8 9import { 10 IDiffEntry, IDiffArrayEntry, IDiffPatch, 11 opAddRange, opRemoveRange, validateSequenceOp 12} from './diffentries'; 13 14/** 15 * The indentation to use for JSON stringify. 16 */ 17export const JSON_INDENT = ' '; 18 19 20/** 21 * Search the list of diffs for an entry with the given key. 22 * 23 * Returns the first found entry, or null if not entry was found. 24 */ 25export 26function getSubDiffByKey(diff: IDiffEntry[] | null, key: string | number) : IDiffEntry[] | null { 27 if (!diff) { 28 return null; 29 } 30 for (let i=0; i < diff.length; ++i) { 31 if (diff[i].key === key) { 32 return (diff[i] as IDiffPatch).diff || null; 33 } 34 } 35 return null; 36} 37 38/** 39 * Search the list of diffs for an entry with the given key. 40 * 41 * Returns the first found entry, or null if not entry was found. 42 */ 43export 44function getDiffEntryByKey(diff: IDiffEntry[] | null, key: string | number) : IDiffEntry | null { 45 if (!diff) { 46 return null; 47 } 48 for (let i=0; i < diff.length; ++i) { 49 if (diff[i].key === key) { 50 return diff[i]; 51 } 52 } 53 return null; 54} 55 56 57function validateStringDiff(base: string[], entry: IDiffArrayEntry, lineToChar: number[]): void { 58 // First valdiate line ops: 59 validateSequenceOp(base, entry); 60 61 if (entry.op === 'patch') { 62 let line = base[entry.key]; 63 let diff = entry.diff; 64 if (diff !== null) { 65 for (let d of diff) { 66 validateSequenceOp(line, d); 67 } 68 } 69 } 70} 71 72/** 73 * Remove the merge source indicator from a diff (returns a copy). 74 */ 75export 76function stripSource(diff: IDiffEntry[] | null): IDiffEntry[] | null { 77 if (!diff) { 78 return null; 79 } 80 let ret: IDiffEntry[] = []; 81 for (let e of diff) { 82 if (e.op === 'patch') { 83 ret.push({ 84 key: e.key, 85 op: e.op, 86 diff: stripSource(e.diff) 87 }); 88 } else { 89 let d = shallowCopy(e); 90 delete d.source; 91 ret.push(d); 92 } 93 } 94 return ret; 95} 96 97 98/** 99 * Translates a diff of strings split by str.splitlines() to a diff of the 100 * joined multiline string 101 */ 102export 103function flattenStringDiff(val: string[] | string, diff: IDiffArrayEntry[]): IDiffArrayEntry[] { 104 105 if (typeof val === 'string') { 106 val = splitLines(val); 107 } 108 let lineToChar = [0].concat(accumulateLengths(val)); 109 let flattened: IDiffArrayEntry[] = []; 110 for (let e of diff) { 111 // Frist validate op: 112 validateStringDiff(val, e, lineToChar); 113 let lineOffset = lineToChar[e.key]; 114 if (e.op === 'patch') { 115 let pdiff = e.diff as IDiffArrayEntry[]; 116 if (pdiff !== null) { 117 for (let p of pdiff) { 118 let d = shallowCopy(p); 119 d.key += lineOffset; 120 flattened.push(d); 121 } 122 } 123 } else { 124 // Other ops simply have keys which refer to lines 125 let d: IDiffEntry | null = null; 126 if (e.op === 'addrange') { 127 d = opAddRange(lineOffset, 128 (e.valuelist as any[]).join('')); 129 } else { // e.op === 'removerange' 130 let idx = e.key + e.length; 131 d = opRemoveRange(lineOffset, 132 lineToChar[idx] - lineOffset); 133 } 134 d.source = e.source; 135 flattened.push(d); 136 } 137 } 138 // Finally, sort on key (leaving equal items in original order) 139 // This is done since the original diffs are sorted deeper first! 140 return sortByKey(flattened, 'key'); 141} 142