Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
base.js266 linesDownload Raw Back to diff
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3var Diff = /** @class */ (function () {
4    function Diff() {
5    }
6    Diff.prototype.diff = function (oldStr, newStr,
7    // Type below is not accurate/complete - see above for full possibilities - but it compiles
8    options) {
9        if (options === void 0) { options = {}; }
10        var callback;
11        if (typeof options === 'function') {
12            callback = options;
13            options = {};
14        }
15        else if ('callback' in options) {
16            callback = options.callback;
17        }
18        // Allow subclasses to massage the input prior to running
19        var oldString = this.castInput(oldStr, options);
20        var newString = this.castInput(newStr, options);
21        var oldTokens = this.removeEmpty(this.tokenize(oldString, options));
22        var newTokens = this.removeEmpty(this.tokenize(newString, options));
23        return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
24    };
25    Diff.prototype.diffWithOptionsObj = function (oldTokens, newTokens, options, callback) {
26        var _this = this;
27        var _a;
28        var done = function (value) {
29            value = _this.postProcess(value, options);
30            if (callback) {
31                setTimeout(function () { callback(value); }, 0);
32                return undefined;
33            }
34            else {
35                return value;
36            }
37        };
38        var newLen = newTokens.length, oldLen = oldTokens.length;
39        var editLength = 1;
40        var maxEditLength = newLen + oldLen;
41        if (options.maxEditLength != null) {
42            maxEditLength = Math.min(maxEditLength, options.maxEditLength);
43        }
44        var maxExecutionTime = (_a = options.timeout) !== null && _a !== void 0 ? _a : Infinity;
45        var abortAfterTimestamp = Date.now() + maxExecutionTime;
46        var bestPath = [{ oldPos: -1, lastComponent: undefined }];
47        // Seed editLength = 0, i.e. the content starts with the same values
48        var newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
49        if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
50            // Identity per the equality and tokenizer
51            return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
52        }
53        // Once we hit the right edge of the edit graph on some diagonal k, we can
54        // definitely reach the end of the edit graph in no more than k edits, so
55        // there's no point in considering any moves to diagonal k+1 any more (from
56        // which we're guaranteed to need at least k+1 more edits).
57        // Similarly, once we've reached the bottom of the edit graph, there's no
58        // point considering moves to lower diagonals.
59        // We record this fact by setting minDiagonalToConsider and
60        // maxDiagonalToConsider to some finite value once we've hit the edge of
61        // the edit graph.
62        // This optimization is not faithful to the original algorithm presented in
63        // Myers's paper, which instead pointlessly extends D-paths off the end of
64        // the edit graph - see page 7 of Myers's paper which notes this point
65        // explicitly and illustrates it with a diagram. This has major performance
66        // implications for some common scenarios. For instance, to compute a diff
67        // where the new text simply appends d characters on the end of the
68        // original text of length n, the true Myers algorithm will take O(n+d^2)
69        // time while this optimization needs only O(n+d) time.
70        var minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
71        // Main worker method. checks all permutations of a given edit length for acceptance.
72        var execEditLength = function () {
73            for (var diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
74                var basePath = void 0;
75                var removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
76                if (removePath) {
77                    // No one else is going to attempt to use this value, clear it
78                    // @ts-expect-error - perf optimisation. This type-violating value will never be read.
79                    bestPath[diagonalPath - 1] = undefined;
80                }
81                var canAdd = false;
82                if (addPath) {
83                    // what newPos will be after we do an insertion:
84                    var addPathNewPos = addPath.oldPos - diagonalPath;
85                    canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
86                }
87                var canRemove = removePath && removePath.oldPos + 1 < oldLen;
88                if (!canAdd && !canRemove) {
89                    // If this path is a terminal then prune
90                    // @ts-expect-error - perf optimisation. This type-violating value will never be read.
91                    bestPath[diagonalPath] = undefined;
92                    continue;
93                }
94                // Select the diagonal that we want to branch from. We select the prior
95                // path whose position in the old string is the farthest from the origin
96                // and does not pass the bounds of the diff graph
97                if (!canRemove || (canAdd && removePath.oldPos < addPath.oldPos)) {
98                    basePath = _this.addToPath(addPath, true, false, 0, options);
99                }
100                else {
101                    basePath = _this.addToPath(removePath, false, true, 1, options);
102                }
103                newPos = _this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options);
104                if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
105                    // If we have hit the end of both strings, then we are done
106                    return done(_this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
107                }
108                else {
109                    bestPath[diagonalPath] = basePath;
110                    if (basePath.oldPos + 1 >= oldLen) {
111                        maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
112                    }
113                    if (newPos + 1 >= newLen) {
114                        minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
115                    }
116                }
117            }
118            editLength++;
119        };
120        // Performs the length of edit iteration. Is a bit fugly as this has to support the
121        // sync and async mode which is never fun. Loops over execEditLength until a value
122        // is produced, or until the edit length exceeds options.maxEditLength (if given),
123        // in which case it will return undefined.
124        if (callback) {
125            (function exec() {
126                setTimeout(function () {
127                    if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
128                        return callback(undefined);
129                    }
130                    if (!execEditLength()) {
131                        exec();
132                    }
133                }, 0);
134            }());
135        }
136        else {
137            while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
138                var ret = execEditLength();
139                if (ret) {
140                    return ret;
141                }
142            }
143        }
144    };
145    Diff.prototype.addToPath = function (path, added, removed, oldPosInc, options) {
146        var last = path.lastComponent;
147        if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
148            return {
149                oldPos: path.oldPos + oldPosInc,
150                lastComponent: { count: last.count + 1, added: added, removed: removed, previousComponent: last.previousComponent }
151            };
152        }
153        else {
154            return {
155                oldPos: path.oldPos + oldPosInc,
156                lastComponent: { count: 1, added: added, removed: removed, previousComponent: last }
157            };
158        }
159    };
160    Diff.prototype.extractCommon = function (basePath, newTokens, oldTokens, diagonalPath, options) {
161        var newLen = newTokens.length, oldLen = oldTokens.length;
162        var oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
163        while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) {
164            newPos++;
165            oldPos++;
166            commonCount++;
167            if (options.oneChangePerToken) {
168                basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: false, removed: false };
169            }
170        }
171        if (commonCount && !options.oneChangePerToken) {
172            basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: false, removed: false };
173        }
174        basePath.oldPos = oldPos;
175        return newPos;
176    };
177    Diff.prototype.equals = function (left, right, options) {
178        if (options.comparator) {
179            return options.comparator(left, right);
180        }
181        else {
182            return left === right
183                || (!!options.ignoreCase && left.toLowerCase() === right.toLowerCase());
184        }
185    };
186    Diff.prototype.removeEmpty = function (array) {
187        var ret = [];
188        for (var i = 0; i < array.length; i++) {
189            if (array[i]) {
190                ret.push(array[i]);
191            }
192        }
193        return ret;
194    };
195    // eslint-disable-next-line @typescript-eslint/no-unused-vars
196    Diff.prototype.castInput = function (value, options) {
197        return value;
198    };
199    // eslint-disable-next-line @typescript-eslint/no-unused-vars
200    Diff.prototype.tokenize = function (value, options) {
201        return Array.from(value);
202    };
203    Diff.prototype.join = function (chars) {
204        // Assumes ValueT is string, which is the case for most subclasses.
205        // When it's false, e.g. in diffArrays, this method needs to be overridden (e.g. with a no-op)
206        // Yes, the casts are verbose and ugly, because this pattern - of having the base class SORT OF
207        // assume tokens and values are strings, but not completely - is weird and janky.
208        return chars.join('');
209    };
210    Diff.prototype.postProcess = function (changeObjects,
211    // eslint-disable-next-line @typescript-eslint/no-unused-vars
212    options) {
213        return changeObjects;
214    };
215    Object.defineProperty(Diff.prototype, "useLongestToken", {
216        get: function () {
217            return false;
218        },
219        enumerable: false,
220        configurable: true
221    });
222    Diff.prototype.buildValues = function (lastComponent, newTokens, oldTokens) {
223        // First we convert our linked list of components in reverse order to an
224        // array in the right order:
225        var components = [];
226        var nextComponent;
227        while (lastComponent) {
228            components.push(lastComponent);
229            nextComponent = lastComponent.previousComponent;
230            delete lastComponent.previousComponent;
231            lastComponent = nextComponent;
232        }
233        components.reverse();
234        var componentLen = components.length;
235        var componentPos = 0, newPos = 0, oldPos = 0;
236        for (; componentPos < componentLen; componentPos++) {
237            var component = components[componentPos];
238            if (!component.removed) {
239                if (!component.added && this.useLongestToken) {
240                    var value = newTokens.slice(newPos, newPos + component.count);
241                    value = value.map(function (value, i) {
242                        var oldValue = oldTokens[oldPos + i];
243                        return oldValue.length > value.length ? oldValue : value;
244                    });
245                    component.value = this.join(value);
246                }
247                else {
248                    component.value = this.join(newTokens.slice(newPos, newPos + component.count));
249                }
250                newPos += component.count;
251                // Common case
252                if (!component.added) {
253                    oldPos += component.count;
254                }
255            }
256            else {
257                component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
258                oldPos += component.count;
259            }
260        }
261        return components;
262    };
263    return Diff;
264}());
265exports.default = Diff;
266 
codekingpro/portable-devtools · Team Ai