@plugjs/plug 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/utils/diff.cjs +292 -0
- package/dist/utils/diff.cjs.map +6 -0
- package/dist/utils/diff.d.ts +18 -0
- package/dist/utils/diff.mjs +266 -0
- package/dist/utils/diff.mjs.map +6 -0
- package/dist/utils/types.cjs +37 -0
- package/dist/utils/types.cjs.map +6 -0
- package/dist/utils/types.d.ts +4 -0
- package/dist/utils/types.mjs +12 -0
- package/dist/utils/types.mjs.map +6 -0
- package/dist/utils.cjs +2 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.ts +2 -0
- package/dist/utils.mjs +2 -0
- package/dist/utils.mjs.map +1 -1
- package/package.json +1 -1
- package/src/utils/diff.ts +360 -0
- package/src/utils/types.ts +11 -0
- package/src/utils.ts +2 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// utils/diff.ts
|
|
21
|
+
var diff_exports = {};
|
|
22
|
+
__export(diff_exports, {
|
|
23
|
+
diff: () => diff,
|
|
24
|
+
textDiff: () => textDiff
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(diff_exports);
|
|
27
|
+
var import_node_assert = require("node:assert");
|
|
28
|
+
var import_node_util = require("node:util");
|
|
29
|
+
var import_asserts = require("../asserts.cjs");
|
|
30
|
+
var import_logging = require("../logging.cjs");
|
|
31
|
+
var import_types = require("./types.cjs");
|
|
32
|
+
function compareLongestCommonSubsequence(lhsCtx, rhsCtx) {
|
|
33
|
+
let lhsStart = 0;
|
|
34
|
+
let rhsStart = 0;
|
|
35
|
+
let lhsItem = 0;
|
|
36
|
+
let rhsItem = 0;
|
|
37
|
+
const changes = [];
|
|
38
|
+
while (lhsItem < lhsCtx.length || rhsItem < rhsCtx.length) {
|
|
39
|
+
if (lhsItem < lhsCtx.length && !lhsCtx.modified[lhsItem] && rhsItem < rhsCtx.length && !rhsCtx.modified[rhsItem]) {
|
|
40
|
+
lhsItem++;
|
|
41
|
+
rhsItem++;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
lhsStart = lhsItem;
|
|
45
|
+
rhsStart = rhsItem;
|
|
46
|
+
while (lhsItem < lhsCtx.length && (rhsItem >= rhsCtx.length || lhsCtx.modified[lhsItem])) {
|
|
47
|
+
lhsItem++;
|
|
48
|
+
}
|
|
49
|
+
while (rhsItem < rhsCtx.length && (lhsItem >= lhsCtx.length || rhsCtx.modified[rhsItem])) {
|
|
50
|
+
rhsItem++;
|
|
51
|
+
}
|
|
52
|
+
if (lhsStart < lhsItem || rhsStart < rhsItem) {
|
|
53
|
+
const lat = Math.min(lhsStart, lhsCtx.length ? lhsCtx.length - 1 : 0);
|
|
54
|
+
const rat = Math.min(rhsStart, rhsCtx.length ? rhsCtx.length - 1 : 0);
|
|
55
|
+
changes.push({
|
|
56
|
+
lhsPos: lat,
|
|
57
|
+
lhsDel: lhsItem - lhsStart,
|
|
58
|
+
rhsPos: rat,
|
|
59
|
+
rhsAdd: rhsItem - rhsStart
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return changes;
|
|
64
|
+
}
|
|
65
|
+
function getShortestMiddleSnake(lhsCtx, lhsLower, lhsUpper, rhsCtx, rhsLower, rhsUpper, vectorU, vectorD) {
|
|
66
|
+
const max = lhsCtx.length + rhsCtx.length + 1;
|
|
67
|
+
const kdown = lhsLower - rhsLower;
|
|
68
|
+
const kup = lhsUpper - rhsUpper;
|
|
69
|
+
const delta = lhsUpper - lhsLower - (rhsUpper - rhsLower);
|
|
70
|
+
const odd = (delta & 1) != 0;
|
|
71
|
+
const offsetDown = max - kdown;
|
|
72
|
+
const offsetUp = max - kup;
|
|
73
|
+
const maxd = (lhsUpper - lhsLower + rhsUpper - rhsLower) / 2 + 1;
|
|
74
|
+
const ret = { x: 0, y: 0 };
|
|
75
|
+
let d;
|
|
76
|
+
let k;
|
|
77
|
+
let x;
|
|
78
|
+
let y;
|
|
79
|
+
vectorD[offsetDown + kdown + 1] = lhsLower;
|
|
80
|
+
vectorU[offsetUp + kup - 1] = lhsUpper;
|
|
81
|
+
for (d = 0; d <= maxd; ++d) {
|
|
82
|
+
for (k = kdown - d; k <= kdown + d; k += 2) {
|
|
83
|
+
if (k === kdown - d) {
|
|
84
|
+
x = vectorD[offsetDown + k + 1];
|
|
85
|
+
} else {
|
|
86
|
+
x = vectorD[offsetDown + k - 1] + 1;
|
|
87
|
+
if (k < kdown + d && vectorD[offsetDown + k + 1] >= x) {
|
|
88
|
+
x = vectorD[offsetDown + k + 1];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
y = x - k;
|
|
92
|
+
while (x < lhsUpper && y < rhsUpper && lhsCtx.codes[x] === rhsCtx.codes[y]) {
|
|
93
|
+
x++;
|
|
94
|
+
y++;
|
|
95
|
+
}
|
|
96
|
+
vectorD[offsetDown + k] = x;
|
|
97
|
+
if (odd && kup - d < k && k < kup + d) {
|
|
98
|
+
if (vectorU[offsetUp + k] <= vectorD[offsetDown + k]) {
|
|
99
|
+
ret.x = vectorD[offsetDown + k];
|
|
100
|
+
ret.y = vectorD[offsetDown + k] - k;
|
|
101
|
+
return ret;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
for (k = kup - d; k <= kup + d; k += 2) {
|
|
106
|
+
if (k === kup + d) {
|
|
107
|
+
x = vectorU[offsetUp + k - 1];
|
|
108
|
+
} else {
|
|
109
|
+
x = vectorU[offsetUp + k + 1] - 1;
|
|
110
|
+
if (k > kup - d && vectorU[offsetUp + k - 1] < x) {
|
|
111
|
+
x = vectorU[offsetUp + k - 1];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
y = x - k;
|
|
115
|
+
while (x > lhsLower && y > rhsLower && lhsCtx.codes[x - 1] === rhsCtx.codes[y - 1]) {
|
|
116
|
+
x--;
|
|
117
|
+
y--;
|
|
118
|
+
}
|
|
119
|
+
vectorU[offsetUp + k] = x;
|
|
120
|
+
if (!odd && kdown - d <= k && k <= kdown + d) {
|
|
121
|
+
if (vectorU[offsetUp + k] <= vectorD[offsetDown + k]) {
|
|
122
|
+
ret.x = vectorD[offsetDown + k];
|
|
123
|
+
ret.y = vectorD[offsetDown + k] - k;
|
|
124
|
+
return ret;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
(0, import_node_assert.fail)("Unexpected state computing diff");
|
|
130
|
+
}
|
|
131
|
+
function getLongestCommonSubsequence(lhsCtx, lhsLower, lhsUpper, rhsCtx, rhsLower, rhsUpper, vectorU = [], vectorD = []) {
|
|
132
|
+
while (lhsLower < lhsUpper && rhsLower < rhsUpper && lhsCtx.codes[lhsLower] === rhsCtx.codes[rhsLower]) {
|
|
133
|
+
++lhsLower;
|
|
134
|
+
++rhsLower;
|
|
135
|
+
}
|
|
136
|
+
while (lhsLower < lhsUpper && rhsLower < rhsUpper && lhsCtx.codes[lhsUpper - 1] === rhsCtx.codes[rhsUpper - 1]) {
|
|
137
|
+
--lhsUpper;
|
|
138
|
+
--rhsUpper;
|
|
139
|
+
}
|
|
140
|
+
if (lhsLower === lhsUpper) {
|
|
141
|
+
while (rhsLower < rhsUpper) {
|
|
142
|
+
rhsCtx.modified[rhsLower++] = true;
|
|
143
|
+
}
|
|
144
|
+
} else if (rhsLower === rhsUpper) {
|
|
145
|
+
while (lhsLower < lhsUpper) {
|
|
146
|
+
lhsCtx.modified[lhsLower++] = true;
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
const { x, y } = getShortestMiddleSnake(
|
|
150
|
+
lhsCtx,
|
|
151
|
+
lhsLower,
|
|
152
|
+
lhsUpper,
|
|
153
|
+
rhsCtx,
|
|
154
|
+
rhsLower,
|
|
155
|
+
rhsUpper,
|
|
156
|
+
vectorU,
|
|
157
|
+
vectorD
|
|
158
|
+
);
|
|
159
|
+
getLongestCommonSubsequence(
|
|
160
|
+
lhsCtx,
|
|
161
|
+
lhsLower,
|
|
162
|
+
x,
|
|
163
|
+
rhsCtx,
|
|
164
|
+
rhsLower,
|
|
165
|
+
y,
|
|
166
|
+
vectorU,
|
|
167
|
+
vectorD
|
|
168
|
+
);
|
|
169
|
+
getLongestCommonSubsequence(
|
|
170
|
+
lhsCtx,
|
|
171
|
+
x,
|
|
172
|
+
lhsUpper,
|
|
173
|
+
rhsCtx,
|
|
174
|
+
y,
|
|
175
|
+
rhsUpper,
|
|
176
|
+
vectorU,
|
|
177
|
+
vectorD
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
var Context = class {
|
|
182
|
+
/** Keep a tab on modified items */
|
|
183
|
+
modified;
|
|
184
|
+
/** A _code table_ for all the items in this context */
|
|
185
|
+
codes;
|
|
186
|
+
/** The number of item held by this context */
|
|
187
|
+
length;
|
|
188
|
+
/** Construct with a _code table_ */
|
|
189
|
+
constructor(codes) {
|
|
190
|
+
const length = this.length = codes.length;
|
|
191
|
+
this.modified = new Array(length);
|
|
192
|
+
this.codes = codes;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
var Coder = class {
|
|
196
|
+
_primitives = /* @__PURE__ */ new Map();
|
|
197
|
+
_objects = [];
|
|
198
|
+
_index = 1;
|
|
199
|
+
_getObjectCode(item) {
|
|
200
|
+
for (const [object, code2] of this._objects) {
|
|
201
|
+
if ((0, import_node_util.isDeepStrictEqual)(item, object))
|
|
202
|
+
return code2;
|
|
203
|
+
}
|
|
204
|
+
const code = ++this._index;
|
|
205
|
+
this._objects.push([item, code]);
|
|
206
|
+
return code;
|
|
207
|
+
}
|
|
208
|
+
_getPrimitiveCode(item) {
|
|
209
|
+
let code = this._primitives.get(item);
|
|
210
|
+
if (code)
|
|
211
|
+
return code;
|
|
212
|
+
code = ++this._index;
|
|
213
|
+
this._primitives.set(item, code);
|
|
214
|
+
return code;
|
|
215
|
+
}
|
|
216
|
+
/** Get the code table for an {@link Iterable} */
|
|
217
|
+
getCodes(iterable) {
|
|
218
|
+
const codes = [];
|
|
219
|
+
for (const item of iterable) {
|
|
220
|
+
const type = item === null ? "null" : typeof item;
|
|
221
|
+
const code = type === "object" ? this._getObjectCode(item) : this._getPrimitiveCode(item);
|
|
222
|
+
codes.push(code);
|
|
223
|
+
}
|
|
224
|
+
return codes;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
var inspectOptions = {
|
|
228
|
+
showHidden: false,
|
|
229
|
+
depth: 10,
|
|
230
|
+
colors: false,
|
|
231
|
+
maxArrayLength: 100,
|
|
232
|
+
maxStringLength: 250,
|
|
233
|
+
breakLength: Infinity,
|
|
234
|
+
compact: false,
|
|
235
|
+
sorted: true,
|
|
236
|
+
getters: true
|
|
237
|
+
};
|
|
238
|
+
function diff(lhs, rhs) {
|
|
239
|
+
(0, import_asserts.assert)(lhs !== void 0, "Left-Hand side undefined");
|
|
240
|
+
(0, import_asserts.assert)(rhs !== void 0, "Right-Hand side undefined");
|
|
241
|
+
const codec = new Coder();
|
|
242
|
+
const lhsCtx = new Context(codec.getCodes(lhs));
|
|
243
|
+
const rhsCtx = new Context(codec.getCodes(rhs));
|
|
244
|
+
getLongestCommonSubsequence(
|
|
245
|
+
lhsCtx,
|
|
246
|
+
0,
|
|
247
|
+
lhsCtx.length,
|
|
248
|
+
rhsCtx,
|
|
249
|
+
0,
|
|
250
|
+
rhsCtx.length
|
|
251
|
+
);
|
|
252
|
+
return compareLongestCommonSubsequence(lhsCtx, rhsCtx);
|
|
253
|
+
}
|
|
254
|
+
function textDiff(lhs, rhs, add, del, not) {
|
|
255
|
+
const _add = add || (import_logging.logOptions.colors ? import_logging.$grn : (s) => `+ ${s}`);
|
|
256
|
+
const _del = del || (import_logging.logOptions.colors ? import_logging.$red : (s) => `- ${s}`);
|
|
257
|
+
const _not = not || (import_logging.logOptions.colors ? (s) => s : (s) => ` ${s}`);
|
|
258
|
+
let lhsLines;
|
|
259
|
+
let rhsLines;
|
|
260
|
+
const lhsType = (0, import_types.getTypeOf)(lhs);
|
|
261
|
+
const rhsType = (0, import_types.getTypeOf)(rhs);
|
|
262
|
+
if (lhsType === "string" && rhsType === "string") {
|
|
263
|
+
lhsLines = lhs.split("\n");
|
|
264
|
+
rhsLines = rhs.split("\n");
|
|
265
|
+
} else {
|
|
266
|
+
lhsLines = (0, import_node_util.inspect)(lhs, inspectOptions).split("\n");
|
|
267
|
+
rhsLines = (0, import_node_util.inspect)(rhs, inspectOptions).split("\n");
|
|
268
|
+
}
|
|
269
|
+
const changes = diff(lhsLines, rhsLines);
|
|
270
|
+
if (changes.length === 0)
|
|
271
|
+
return "";
|
|
272
|
+
let offset = 0;
|
|
273
|
+
const result = [];
|
|
274
|
+
changes.forEach(({ lhsPos, lhsDel, rhsPos, rhsAdd }) => {
|
|
275
|
+
if (offset != lhsPos)
|
|
276
|
+
result.push(...lhsLines.slice(offset, lhsPos).map(_not));
|
|
277
|
+
if (lhsDel)
|
|
278
|
+
result.push(...lhsLines.slice(lhsPos, lhsPos + lhsDel).map(_del));
|
|
279
|
+
if (rhsAdd)
|
|
280
|
+
result.push(...rhsLines.slice(rhsPos, rhsPos + rhsAdd).map(_add));
|
|
281
|
+
offset = lhsPos + lhsDel;
|
|
282
|
+
});
|
|
283
|
+
if (offset < lhsLines.length)
|
|
284
|
+
result.push(...lhsLines.slice(offset).map(_not));
|
|
285
|
+
return result.join("\n");
|
|
286
|
+
}
|
|
287
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
288
|
+
0 && (module.exports = {
|
|
289
|
+
diff,
|
|
290
|
+
textDiff
|
|
291
|
+
});
|
|
292
|
+
//# sourceMappingURL=diff.cjs.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/diff.ts"],
|
|
4
|
+
"mappings": "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",
|
|
5
|
+
"names": ["code"]
|
|
6
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Identifies a single change */
|
|
2
|
+
export interface Change {
|
|
3
|
+
/** The position in the Left-Hand side where items were deleted */
|
|
4
|
+
lhsPos: number;
|
|
5
|
+
/** The number of items deleted from the Left-Hand side */
|
|
6
|
+
lhsDel: number;
|
|
7
|
+
/** The position in the Right-Hand side where items were added */
|
|
8
|
+
rhsPos: number;
|
|
9
|
+
/** The number of items added to the Right-Hand side */
|
|
10
|
+
rhsAdd: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Compare the _Left-Hand side_ {@link Iterable} to _Right-Hand side_ one,
|
|
14
|
+
* producing an array of {@link Change | Changes} identifying the differences.
|
|
15
|
+
*/
|
|
16
|
+
export declare function diff<T, I extends Iterable<T> = Iterable<T>>(lhs: I, rhs: I): Change[];
|
|
17
|
+
/** Produce a textual diff between two values. */
|
|
18
|
+
export declare function textDiff(lhs: any, rhs: any, add?: (s: string) => string, del?: (s: string) => string, not?: (s: string) => string): string;
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
// utils/diff.ts
|
|
2
|
+
import { fail } from "node:assert";
|
|
3
|
+
import { inspect, isDeepStrictEqual } from "node:util";
|
|
4
|
+
import { assert } from "../asserts.mjs";
|
|
5
|
+
import { $grn, $red, logOptions } from "../logging.mjs";
|
|
6
|
+
import { getTypeOf } from "./types.mjs";
|
|
7
|
+
function compareLongestCommonSubsequence(lhsCtx, rhsCtx) {
|
|
8
|
+
let lhsStart = 0;
|
|
9
|
+
let rhsStart = 0;
|
|
10
|
+
let lhsItem = 0;
|
|
11
|
+
let rhsItem = 0;
|
|
12
|
+
const changes = [];
|
|
13
|
+
while (lhsItem < lhsCtx.length || rhsItem < rhsCtx.length) {
|
|
14
|
+
if (lhsItem < lhsCtx.length && !lhsCtx.modified[lhsItem] && rhsItem < rhsCtx.length && !rhsCtx.modified[rhsItem]) {
|
|
15
|
+
lhsItem++;
|
|
16
|
+
rhsItem++;
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
lhsStart = lhsItem;
|
|
20
|
+
rhsStart = rhsItem;
|
|
21
|
+
while (lhsItem < lhsCtx.length && (rhsItem >= rhsCtx.length || lhsCtx.modified[lhsItem])) {
|
|
22
|
+
lhsItem++;
|
|
23
|
+
}
|
|
24
|
+
while (rhsItem < rhsCtx.length && (lhsItem >= lhsCtx.length || rhsCtx.modified[rhsItem])) {
|
|
25
|
+
rhsItem++;
|
|
26
|
+
}
|
|
27
|
+
if (lhsStart < lhsItem || rhsStart < rhsItem) {
|
|
28
|
+
const lat = Math.min(lhsStart, lhsCtx.length ? lhsCtx.length - 1 : 0);
|
|
29
|
+
const rat = Math.min(rhsStart, rhsCtx.length ? rhsCtx.length - 1 : 0);
|
|
30
|
+
changes.push({
|
|
31
|
+
lhsPos: lat,
|
|
32
|
+
lhsDel: lhsItem - lhsStart,
|
|
33
|
+
rhsPos: rat,
|
|
34
|
+
rhsAdd: rhsItem - rhsStart
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return changes;
|
|
39
|
+
}
|
|
40
|
+
function getShortestMiddleSnake(lhsCtx, lhsLower, lhsUpper, rhsCtx, rhsLower, rhsUpper, vectorU, vectorD) {
|
|
41
|
+
const max = lhsCtx.length + rhsCtx.length + 1;
|
|
42
|
+
const kdown = lhsLower - rhsLower;
|
|
43
|
+
const kup = lhsUpper - rhsUpper;
|
|
44
|
+
const delta = lhsUpper - lhsLower - (rhsUpper - rhsLower);
|
|
45
|
+
const odd = (delta & 1) != 0;
|
|
46
|
+
const offsetDown = max - kdown;
|
|
47
|
+
const offsetUp = max - kup;
|
|
48
|
+
const maxd = (lhsUpper - lhsLower + rhsUpper - rhsLower) / 2 + 1;
|
|
49
|
+
const ret = { x: 0, y: 0 };
|
|
50
|
+
let d;
|
|
51
|
+
let k;
|
|
52
|
+
let x;
|
|
53
|
+
let y;
|
|
54
|
+
vectorD[offsetDown + kdown + 1] = lhsLower;
|
|
55
|
+
vectorU[offsetUp + kup - 1] = lhsUpper;
|
|
56
|
+
for (d = 0; d <= maxd; ++d) {
|
|
57
|
+
for (k = kdown - d; k <= kdown + d; k += 2) {
|
|
58
|
+
if (k === kdown - d) {
|
|
59
|
+
x = vectorD[offsetDown + k + 1];
|
|
60
|
+
} else {
|
|
61
|
+
x = vectorD[offsetDown + k - 1] + 1;
|
|
62
|
+
if (k < kdown + d && vectorD[offsetDown + k + 1] >= x) {
|
|
63
|
+
x = vectorD[offsetDown + k + 1];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
y = x - k;
|
|
67
|
+
while (x < lhsUpper && y < rhsUpper && lhsCtx.codes[x] === rhsCtx.codes[y]) {
|
|
68
|
+
x++;
|
|
69
|
+
y++;
|
|
70
|
+
}
|
|
71
|
+
vectorD[offsetDown + k] = x;
|
|
72
|
+
if (odd && kup - d < k && k < kup + d) {
|
|
73
|
+
if (vectorU[offsetUp + k] <= vectorD[offsetDown + k]) {
|
|
74
|
+
ret.x = vectorD[offsetDown + k];
|
|
75
|
+
ret.y = vectorD[offsetDown + k] - k;
|
|
76
|
+
return ret;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
for (k = kup - d; k <= kup + d; k += 2) {
|
|
81
|
+
if (k === kup + d) {
|
|
82
|
+
x = vectorU[offsetUp + k - 1];
|
|
83
|
+
} else {
|
|
84
|
+
x = vectorU[offsetUp + k + 1] - 1;
|
|
85
|
+
if (k > kup - d && vectorU[offsetUp + k - 1] < x) {
|
|
86
|
+
x = vectorU[offsetUp + k - 1];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
y = x - k;
|
|
90
|
+
while (x > lhsLower && y > rhsLower && lhsCtx.codes[x - 1] === rhsCtx.codes[y - 1]) {
|
|
91
|
+
x--;
|
|
92
|
+
y--;
|
|
93
|
+
}
|
|
94
|
+
vectorU[offsetUp + k] = x;
|
|
95
|
+
if (!odd && kdown - d <= k && k <= kdown + d) {
|
|
96
|
+
if (vectorU[offsetUp + k] <= vectorD[offsetDown + k]) {
|
|
97
|
+
ret.x = vectorD[offsetDown + k];
|
|
98
|
+
ret.y = vectorD[offsetDown + k] - k;
|
|
99
|
+
return ret;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
fail("Unexpected state computing diff");
|
|
105
|
+
}
|
|
106
|
+
function getLongestCommonSubsequence(lhsCtx, lhsLower, lhsUpper, rhsCtx, rhsLower, rhsUpper, vectorU = [], vectorD = []) {
|
|
107
|
+
while (lhsLower < lhsUpper && rhsLower < rhsUpper && lhsCtx.codes[lhsLower] === rhsCtx.codes[rhsLower]) {
|
|
108
|
+
++lhsLower;
|
|
109
|
+
++rhsLower;
|
|
110
|
+
}
|
|
111
|
+
while (lhsLower < lhsUpper && rhsLower < rhsUpper && lhsCtx.codes[lhsUpper - 1] === rhsCtx.codes[rhsUpper - 1]) {
|
|
112
|
+
--lhsUpper;
|
|
113
|
+
--rhsUpper;
|
|
114
|
+
}
|
|
115
|
+
if (lhsLower === lhsUpper) {
|
|
116
|
+
while (rhsLower < rhsUpper) {
|
|
117
|
+
rhsCtx.modified[rhsLower++] = true;
|
|
118
|
+
}
|
|
119
|
+
} else if (rhsLower === rhsUpper) {
|
|
120
|
+
while (lhsLower < lhsUpper) {
|
|
121
|
+
lhsCtx.modified[lhsLower++] = true;
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
const { x, y } = getShortestMiddleSnake(
|
|
125
|
+
lhsCtx,
|
|
126
|
+
lhsLower,
|
|
127
|
+
lhsUpper,
|
|
128
|
+
rhsCtx,
|
|
129
|
+
rhsLower,
|
|
130
|
+
rhsUpper,
|
|
131
|
+
vectorU,
|
|
132
|
+
vectorD
|
|
133
|
+
);
|
|
134
|
+
getLongestCommonSubsequence(
|
|
135
|
+
lhsCtx,
|
|
136
|
+
lhsLower,
|
|
137
|
+
x,
|
|
138
|
+
rhsCtx,
|
|
139
|
+
rhsLower,
|
|
140
|
+
y,
|
|
141
|
+
vectorU,
|
|
142
|
+
vectorD
|
|
143
|
+
);
|
|
144
|
+
getLongestCommonSubsequence(
|
|
145
|
+
lhsCtx,
|
|
146
|
+
x,
|
|
147
|
+
lhsUpper,
|
|
148
|
+
rhsCtx,
|
|
149
|
+
y,
|
|
150
|
+
rhsUpper,
|
|
151
|
+
vectorU,
|
|
152
|
+
vectorD
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
var Context = class {
|
|
157
|
+
/** Keep a tab on modified items */
|
|
158
|
+
modified;
|
|
159
|
+
/** A _code table_ for all the items in this context */
|
|
160
|
+
codes;
|
|
161
|
+
/** The number of item held by this context */
|
|
162
|
+
length;
|
|
163
|
+
/** Construct with a _code table_ */
|
|
164
|
+
constructor(codes) {
|
|
165
|
+
const length = this.length = codes.length;
|
|
166
|
+
this.modified = new Array(length);
|
|
167
|
+
this.codes = codes;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
var Coder = class {
|
|
171
|
+
_primitives = /* @__PURE__ */ new Map();
|
|
172
|
+
_objects = [];
|
|
173
|
+
_index = 1;
|
|
174
|
+
_getObjectCode(item) {
|
|
175
|
+
for (const [object, code2] of this._objects) {
|
|
176
|
+
if (isDeepStrictEqual(item, object))
|
|
177
|
+
return code2;
|
|
178
|
+
}
|
|
179
|
+
const code = ++this._index;
|
|
180
|
+
this._objects.push([item, code]);
|
|
181
|
+
return code;
|
|
182
|
+
}
|
|
183
|
+
_getPrimitiveCode(item) {
|
|
184
|
+
let code = this._primitives.get(item);
|
|
185
|
+
if (code)
|
|
186
|
+
return code;
|
|
187
|
+
code = ++this._index;
|
|
188
|
+
this._primitives.set(item, code);
|
|
189
|
+
return code;
|
|
190
|
+
}
|
|
191
|
+
/** Get the code table for an {@link Iterable} */
|
|
192
|
+
getCodes(iterable) {
|
|
193
|
+
const codes = [];
|
|
194
|
+
for (const item of iterable) {
|
|
195
|
+
const type = item === null ? "null" : typeof item;
|
|
196
|
+
const code = type === "object" ? this._getObjectCode(item) : this._getPrimitiveCode(item);
|
|
197
|
+
codes.push(code);
|
|
198
|
+
}
|
|
199
|
+
return codes;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
var inspectOptions = {
|
|
203
|
+
showHidden: false,
|
|
204
|
+
depth: 10,
|
|
205
|
+
colors: false,
|
|
206
|
+
maxArrayLength: 100,
|
|
207
|
+
maxStringLength: 250,
|
|
208
|
+
breakLength: Infinity,
|
|
209
|
+
compact: false,
|
|
210
|
+
sorted: true,
|
|
211
|
+
getters: true
|
|
212
|
+
};
|
|
213
|
+
function diff(lhs, rhs) {
|
|
214
|
+
assert(lhs !== void 0, "Left-Hand side undefined");
|
|
215
|
+
assert(rhs !== void 0, "Right-Hand side undefined");
|
|
216
|
+
const codec = new Coder();
|
|
217
|
+
const lhsCtx = new Context(codec.getCodes(lhs));
|
|
218
|
+
const rhsCtx = new Context(codec.getCodes(rhs));
|
|
219
|
+
getLongestCommonSubsequence(
|
|
220
|
+
lhsCtx,
|
|
221
|
+
0,
|
|
222
|
+
lhsCtx.length,
|
|
223
|
+
rhsCtx,
|
|
224
|
+
0,
|
|
225
|
+
rhsCtx.length
|
|
226
|
+
);
|
|
227
|
+
return compareLongestCommonSubsequence(lhsCtx, rhsCtx);
|
|
228
|
+
}
|
|
229
|
+
function textDiff(lhs, rhs, add, del, not) {
|
|
230
|
+
const _add = add || (logOptions.colors ? $grn : (s) => `+ ${s}`);
|
|
231
|
+
const _del = del || (logOptions.colors ? $red : (s) => `- ${s}`);
|
|
232
|
+
const _not = not || (logOptions.colors ? (s) => s : (s) => ` ${s}`);
|
|
233
|
+
let lhsLines;
|
|
234
|
+
let rhsLines;
|
|
235
|
+
const lhsType = getTypeOf(lhs);
|
|
236
|
+
const rhsType = getTypeOf(rhs);
|
|
237
|
+
if (lhsType === "string" && rhsType === "string") {
|
|
238
|
+
lhsLines = lhs.split("\n");
|
|
239
|
+
rhsLines = rhs.split("\n");
|
|
240
|
+
} else {
|
|
241
|
+
lhsLines = inspect(lhs, inspectOptions).split("\n");
|
|
242
|
+
rhsLines = inspect(rhs, inspectOptions).split("\n");
|
|
243
|
+
}
|
|
244
|
+
const changes = diff(lhsLines, rhsLines);
|
|
245
|
+
if (changes.length === 0)
|
|
246
|
+
return "";
|
|
247
|
+
let offset = 0;
|
|
248
|
+
const result = [];
|
|
249
|
+
changes.forEach(({ lhsPos, lhsDel, rhsPos, rhsAdd }) => {
|
|
250
|
+
if (offset != lhsPos)
|
|
251
|
+
result.push(...lhsLines.slice(offset, lhsPos).map(_not));
|
|
252
|
+
if (lhsDel)
|
|
253
|
+
result.push(...lhsLines.slice(lhsPos, lhsPos + lhsDel).map(_del));
|
|
254
|
+
if (rhsAdd)
|
|
255
|
+
result.push(...rhsLines.slice(rhsPos, rhsPos + rhsAdd).map(_add));
|
|
256
|
+
offset = lhsPos + lhsDel;
|
|
257
|
+
});
|
|
258
|
+
if (offset < lhsLines.length)
|
|
259
|
+
result.push(...lhsLines.slice(offset).map(_not));
|
|
260
|
+
return result.join("\n");
|
|
261
|
+
}
|
|
262
|
+
export {
|
|
263
|
+
diff,
|
|
264
|
+
textDiff
|
|
265
|
+
};
|
|
266
|
+
//# sourceMappingURL=diff.mjs.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/diff.ts"],
|
|
4
|
+
"mappings": "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",
|
|
5
|
+
"names": ["code"]
|
|
6
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// utils/types.ts
|
|
21
|
+
var types_exports = {};
|
|
22
|
+
__export(types_exports, {
|
|
23
|
+
getTypeOf: () => getTypeOf
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(types_exports);
|
|
26
|
+
function getTypeOf(what) {
|
|
27
|
+
if (Array.isArray(what))
|
|
28
|
+
return "array";
|
|
29
|
+
if (what === null)
|
|
30
|
+
return "null";
|
|
31
|
+
return typeof what;
|
|
32
|
+
}
|
|
33
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
34
|
+
0 && (module.exports = {
|
|
35
|
+
getTypeOf
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=types.cjs.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** A type adding the values `null` or `array` to the result of `typeof` */
|
|
2
|
+
export type BasicType = 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | 'null' | 'array';
|
|
3
|
+
/** Get the _real_ type of a value, including `null` or `array` */
|
|
4
|
+
export declare function getTypeOf(what: unknown): BasicType;
|
package/dist/utils.cjs
CHANGED
|
@@ -17,8 +17,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
17
17
|
// utils.ts
|
|
18
18
|
var utils_exports = {};
|
|
19
19
|
module.exports = __toCommonJS(utils_exports);
|
|
20
|
+
__reExport(utils_exports, require("./utils/diff.cjs"), module.exports);
|
|
20
21
|
__reExport(utils_exports, require("./utils/exec.cjs"), module.exports);
|
|
21
22
|
__reExport(utils_exports, require("./utils/match.cjs"), module.exports);
|
|
22
23
|
__reExport(utils_exports, require("./utils/options.cjs"), module.exports);
|
|
24
|
+
__reExport(utils_exports, require("./utils/types.cjs"), module.exports);
|
|
23
25
|
__reExport(utils_exports, require("./utils/walk.cjs"), module.exports);
|
|
24
26
|
//# sourceMappingURL=utils.cjs.map
|
package/dist/utils.cjs.map
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/utils.ts"],
|
|
4
|
-
"mappings": ";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,0BAAc,6BAAd;AACA,0BAAc,
|
|
4
|
+
"mappings": ";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,0BAAc,6BAAd;AACA,0BAAc,6BADd;AAEA,0BAAc,8BAFd;AAGA,0BAAc,gCAHd;AAIA,0BAAc,8BAJd;AAKA,0BAAc,6BALd;",
|
|
5
5
|
"names": []
|
|
6
6
|
}
|
package/dist/utils.d.ts
CHANGED
package/dist/utils.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// utils.ts
|
|
2
|
+
export * from "./utils/diff.mjs";
|
|
2
3
|
export * from "./utils/exec.mjs";
|
|
3
4
|
export * from "./utils/match.mjs";
|
|
4
5
|
export * from "./utils/options.mjs";
|
|
6
|
+
export * from "./utils/types.mjs";
|
|
5
7
|
export * from "./utils/walk.mjs";
|
|
6
8
|
//# sourceMappingURL=utils.mjs.map
|
package/dist/utils.mjs.map
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import { fail } from 'node:assert'
|
|
2
|
+
import { inspect, isDeepStrictEqual } from 'node:util'
|
|
3
|
+
|
|
4
|
+
import { assert } from '../asserts'
|
|
5
|
+
import { $grn, $red, logOptions } from '../logging'
|
|
6
|
+
import { getTypeOf } from './types'
|
|
7
|
+
|
|
8
|
+
import type { InspectOptions } from 'node:util'
|
|
9
|
+
|
|
10
|
+
/* ========================================================================== *
|
|
11
|
+
* EXPORTED INTERFACES *
|
|
12
|
+
* ========================================================================== */
|
|
13
|
+
|
|
14
|
+
/** Identifies a single change */
|
|
15
|
+
export interface Change {
|
|
16
|
+
/** The position in the Left-Hand side where items were deleted */
|
|
17
|
+
lhsPos: number;
|
|
18
|
+
/** The number of items deleted from the Left-Hand side */
|
|
19
|
+
lhsDel: number;
|
|
20
|
+
/** The position in the Right-Hand side where items were added */
|
|
21
|
+
rhsPos: number;
|
|
22
|
+
/** The number of items added to the Right-Hand side */
|
|
23
|
+
rhsAdd: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* ========================================================================== *
|
|
27
|
+
* MYERS IMPLEMENTATION *
|
|
28
|
+
* Lifted from https://github.com/wickedest/myers-diff/ (Apache 2.0) *
|
|
29
|
+
* ========================================================================== */
|
|
30
|
+
|
|
31
|
+
function compareLongestCommonSubsequence(lhsCtx: Context, rhsCtx: Context): Change[] {
|
|
32
|
+
let lhsStart = 0
|
|
33
|
+
let rhsStart = 0
|
|
34
|
+
let lhsItem = 0
|
|
35
|
+
let rhsItem = 0
|
|
36
|
+
|
|
37
|
+
const changes: Change[] = []
|
|
38
|
+
|
|
39
|
+
while (lhsItem < lhsCtx.length || rhsItem < rhsCtx.length) {
|
|
40
|
+
if (
|
|
41
|
+
(lhsItem < lhsCtx.length) && (!lhsCtx.modified[lhsItem]) &&
|
|
42
|
+
(rhsItem < rhsCtx.length) && (!rhsCtx.modified[rhsItem])
|
|
43
|
+
) {
|
|
44
|
+
// equal lines
|
|
45
|
+
lhsItem++
|
|
46
|
+
rhsItem++
|
|
47
|
+
continue
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// maybe deleted and/or inserted lines
|
|
51
|
+
lhsStart = lhsItem
|
|
52
|
+
rhsStart = rhsItem
|
|
53
|
+
|
|
54
|
+
while ((lhsItem < lhsCtx.length) &&
|
|
55
|
+
(rhsItem >= rhsCtx.length || lhsCtx.modified[lhsItem])) {
|
|
56
|
+
lhsItem++
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
while ((rhsItem < rhsCtx.length) &&
|
|
60
|
+
(lhsItem >= lhsCtx.length || rhsCtx.modified[rhsItem])) {
|
|
61
|
+
rhsItem++
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if ((lhsStart < lhsItem) || (rhsStart < rhsItem)) {
|
|
65
|
+
const lat = Math.min(lhsStart, (lhsCtx.length) ? lhsCtx.length - 1 : 0)
|
|
66
|
+
const rat = Math.min(rhsStart, (rhsCtx.length) ? rhsCtx.length - 1 : 0)
|
|
67
|
+
|
|
68
|
+
changes.push({
|
|
69
|
+
lhsPos: lat,
|
|
70
|
+
lhsDel: lhsItem - lhsStart,
|
|
71
|
+
rhsPos: rat,
|
|
72
|
+
rhsAdd: rhsItem - rhsStart,
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return changes
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function getShortestMiddleSnake(
|
|
81
|
+
lhsCtx: Context, lhsLower: number, lhsUpper: number,
|
|
82
|
+
rhsCtx: Context, rhsLower: number, rhsUpper: number,
|
|
83
|
+
vectorU: number[], vectorD: number[],
|
|
84
|
+
): { x: number, y: number } {
|
|
85
|
+
const max = lhsCtx.length + rhsCtx.length + 1
|
|
86
|
+
|
|
87
|
+
const kdown = lhsLower - rhsLower
|
|
88
|
+
const kup = lhsUpper - rhsUpper
|
|
89
|
+
const delta = (lhsUpper - lhsLower) - (rhsUpper - rhsLower)
|
|
90
|
+
const odd = (delta & 1) != 0
|
|
91
|
+
const offsetDown = max - kdown
|
|
92
|
+
const offsetUp = max - kup
|
|
93
|
+
const maxd = ((lhsUpper - lhsLower + rhsUpper - rhsLower) / 2) + 1
|
|
94
|
+
const ret = { x: 0, y: 0 }
|
|
95
|
+
let d: number
|
|
96
|
+
let k: number
|
|
97
|
+
let x: number
|
|
98
|
+
let y: number
|
|
99
|
+
|
|
100
|
+
vectorD[offsetDown + kdown + 1] = lhsLower
|
|
101
|
+
vectorU[offsetUp + kup - 1] = lhsUpper
|
|
102
|
+
for (d = 0; d <= maxd; ++d) {
|
|
103
|
+
for (k = kdown - d; k <= kdown + d; k += 2) {
|
|
104
|
+
if (k === kdown - d) {
|
|
105
|
+
x = vectorD[offsetDown + k + 1]! // down
|
|
106
|
+
} else {
|
|
107
|
+
x = vectorD[offsetDown + k - 1]! + 1 // right
|
|
108
|
+
if ((k < (kdown + d)) && (vectorD[offsetDown + k + 1]! >= x)) {
|
|
109
|
+
x = vectorD[offsetDown + k + 1]! // down
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
y = x - k
|
|
113
|
+
// find the end of the furthest reaching forward D-path in diagonal k.
|
|
114
|
+
while ((x < lhsUpper) &&
|
|
115
|
+
(y < rhsUpper) &&
|
|
116
|
+
(lhsCtx.codes[x] === rhsCtx.codes[y])
|
|
117
|
+
) {
|
|
118
|
+
x++; y++
|
|
119
|
+
}
|
|
120
|
+
vectorD[offsetDown + k]! = x
|
|
121
|
+
// overlap ?
|
|
122
|
+
if (odd && (kup - d < k) && (k < kup + d)) {
|
|
123
|
+
if (vectorU[offsetUp + k]! <= vectorD[offsetDown + k]!) {
|
|
124
|
+
ret.x = vectorD[offsetDown + k]!
|
|
125
|
+
ret.y = vectorD[offsetDown + k]! - k
|
|
126
|
+
return (ret)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Extend the reverse path.
|
|
131
|
+
for (k = kup - d; k <= kup + d; k += 2) {
|
|
132
|
+
// find the only or better starting point
|
|
133
|
+
if (k === kup + d) {
|
|
134
|
+
x = vectorU[offsetUp + k - 1]! // up
|
|
135
|
+
} else {
|
|
136
|
+
x = vectorU[offsetUp + k + 1]! - 1 // left
|
|
137
|
+
if ((k > kup - d) && (vectorU[offsetUp + k - 1]! < x)) {
|
|
138
|
+
x = vectorU[offsetUp + k - 1]!
|
|
139
|
+
} // up
|
|
140
|
+
}
|
|
141
|
+
y = x - k
|
|
142
|
+
while ((x > lhsLower) &&
|
|
143
|
+
(y > rhsLower) &&
|
|
144
|
+
(lhsCtx.codes[x - 1] === rhsCtx.codes[y - 1])
|
|
145
|
+
) {
|
|
146
|
+
// diagonal
|
|
147
|
+
x--
|
|
148
|
+
y--
|
|
149
|
+
}
|
|
150
|
+
vectorU[offsetUp + k] = x
|
|
151
|
+
// overlap ?
|
|
152
|
+
if (!odd && (kdown - d <= k) && (k <= kdown + d)) {
|
|
153
|
+
if (vectorU[offsetUp + k]! <= vectorD[offsetDown + k]!) {
|
|
154
|
+
ret.x = vectorD[offsetDown + k]!
|
|
155
|
+
ret.y = vectorD[offsetDown + k]! - k
|
|
156
|
+
return (ret)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// coverage ignore next // we should never get here
|
|
163
|
+
fail('Unexpected state computing diff')
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function getLongestCommonSubsequence(
|
|
167
|
+
lhsCtx: Context, lhsLower: number, lhsUpper: number,
|
|
168
|
+
rhsCtx: Context, rhsLower: number, rhsUpper: number,
|
|
169
|
+
vectorU = [], vectorD = [],
|
|
170
|
+
): void {
|
|
171
|
+
// trim off the matching items at the beginning
|
|
172
|
+
while ( (lhsLower < lhsUpper) &&
|
|
173
|
+
(rhsLower < rhsUpper) &&
|
|
174
|
+
(lhsCtx.codes[lhsLower] === rhsCtx.codes[rhsLower]) ) {
|
|
175
|
+
++lhsLower
|
|
176
|
+
++rhsLower
|
|
177
|
+
}
|
|
178
|
+
// trim off the matching items at the end
|
|
179
|
+
while ( (lhsLower < lhsUpper) &&
|
|
180
|
+
(rhsLower < rhsUpper) &&
|
|
181
|
+
(lhsCtx.codes[lhsUpper - 1] === rhsCtx.codes[rhsUpper - 1]) ) {
|
|
182
|
+
--lhsUpper
|
|
183
|
+
--rhsUpper
|
|
184
|
+
}
|
|
185
|
+
if (lhsLower === lhsUpper) {
|
|
186
|
+
while (rhsLower < rhsUpper) {
|
|
187
|
+
rhsCtx.modified[rhsLower++] = true
|
|
188
|
+
}
|
|
189
|
+
} else if (rhsLower === rhsUpper) {
|
|
190
|
+
while (lhsLower < lhsUpper) {
|
|
191
|
+
lhsCtx.modified[lhsLower++] = true
|
|
192
|
+
}
|
|
193
|
+
} else {
|
|
194
|
+
const { x, y } = getShortestMiddleSnake(
|
|
195
|
+
lhsCtx, lhsLower, lhsUpper,
|
|
196
|
+
rhsCtx, rhsLower, rhsUpper,
|
|
197
|
+
vectorU, vectorD)
|
|
198
|
+
getLongestCommonSubsequence(
|
|
199
|
+
lhsCtx, lhsLower, x,
|
|
200
|
+
rhsCtx, rhsLower, y,
|
|
201
|
+
vectorU, vectorD)
|
|
202
|
+
getLongestCommonSubsequence(
|
|
203
|
+
lhsCtx, x, lhsUpper,
|
|
204
|
+
rhsCtx, y, rhsUpper,
|
|
205
|
+
vectorU, vectorD)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/* ========================================================================== *
|
|
210
|
+
* INTERNAL CLASSES *
|
|
211
|
+
* ========================================================================== */
|
|
212
|
+
|
|
213
|
+
/** The context to use while executing the diff */
|
|
214
|
+
class Context {
|
|
215
|
+
/** Keep a tab on modified items */
|
|
216
|
+
readonly modified: (true | undefined)[]
|
|
217
|
+
/** A _code table_ for all the items in this context */
|
|
218
|
+
readonly codes: readonly number[]
|
|
219
|
+
/** The number of item held by this context */
|
|
220
|
+
readonly length: number
|
|
221
|
+
|
|
222
|
+
/** Construct with a _code table_ */
|
|
223
|
+
constructor(codes: number[]) {
|
|
224
|
+
const length = this.length = codes.length
|
|
225
|
+
this.modified = new Array(length)
|
|
226
|
+
this.codes = codes
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** A codec producing _code tables_ */
|
|
231
|
+
class Coder<T, I extends Iterable<T> = Iterable<T>> {
|
|
232
|
+
private _primitives = new Map<T, number>()
|
|
233
|
+
private _objects: [ T, number ][] = []
|
|
234
|
+
private _index = 1
|
|
235
|
+
|
|
236
|
+
private _getObjectCode(item: T): number {
|
|
237
|
+
for (const [ object, code ] of this._objects) {
|
|
238
|
+
if (isDeepStrictEqual(item, object)) return code
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const code = ++ this._index
|
|
242
|
+
this._objects.push([ item, code ])
|
|
243
|
+
return code
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
private _getPrimitiveCode(item: T): number {
|
|
247
|
+
let code = this._primitives.get(item)
|
|
248
|
+
if (code) return code
|
|
249
|
+
|
|
250
|
+
code = ++ this._index
|
|
251
|
+
this._primitives.set(item, code)
|
|
252
|
+
return code
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** Get the code table for an {@link Iterable} */
|
|
256
|
+
getCodes(iterable: I): number[] {
|
|
257
|
+
const codes: number[] = []
|
|
258
|
+
for (const item of iterable) {
|
|
259
|
+
const type = item === null ? 'null' : typeof item
|
|
260
|
+
|
|
261
|
+
const code = type === 'object' ?
|
|
262
|
+
this._getObjectCode(item) :
|
|
263
|
+
this._getPrimitiveCode(item)
|
|
264
|
+
|
|
265
|
+
codes.push(code)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return codes
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** Shared constant for inspect options */
|
|
273
|
+
const inspectOptions: InspectOptions = {
|
|
274
|
+
showHidden: false,
|
|
275
|
+
depth: 10,
|
|
276
|
+
colors: false,
|
|
277
|
+
maxArrayLength: 100,
|
|
278
|
+
maxStringLength: 250,
|
|
279
|
+
breakLength: Infinity,
|
|
280
|
+
compact: false,
|
|
281
|
+
sorted: true,
|
|
282
|
+
getters: true,
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/* ========================================================================== *
|
|
286
|
+
* EXPORTED FUNCTIONS *
|
|
287
|
+
* ========================================================================== */
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Compare the _Left-Hand side_ {@link Iterable} to _Right-Hand side_ one,
|
|
291
|
+
* producing an array of {@link Change | Changes} identifying the differences.
|
|
292
|
+
*/
|
|
293
|
+
export function diff<T, I extends Iterable<T> = Iterable<T>>(
|
|
294
|
+
lhs: I,
|
|
295
|
+
rhs: I,
|
|
296
|
+
): Change[] {
|
|
297
|
+
assert(lhs !== undefined, 'Left-Hand side undefined')
|
|
298
|
+
assert(rhs !== undefined, 'Right-Hand side undefined')
|
|
299
|
+
|
|
300
|
+
const codec = new Coder<T>()
|
|
301
|
+
const lhsCtx = new Context(codec.getCodes(lhs))
|
|
302
|
+
const rhsCtx = new Context(codec.getCodes(rhs))
|
|
303
|
+
|
|
304
|
+
getLongestCommonSubsequence(
|
|
305
|
+
lhsCtx, 0, lhsCtx.length,
|
|
306
|
+
rhsCtx, 0, rhsCtx.length,
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
return compareLongestCommonSubsequence(lhsCtx, rhsCtx)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** Produce a textual diff between two values. */
|
|
313
|
+
export function textDiff(
|
|
314
|
+
lhs: any,
|
|
315
|
+
rhs: any,
|
|
316
|
+
add?: (s: string) => string,
|
|
317
|
+
del?: (s: string) => string,
|
|
318
|
+
not?: (s: string) => string,
|
|
319
|
+
): string {
|
|
320
|
+
// Defaults for our "add" "del" and "not" functions (depending on colorization)
|
|
321
|
+
const _add = add || (logOptions.colors ? $grn : (s: string): string => `+ ${s}`)
|
|
322
|
+
const _del = del || (logOptions.colors ? $red : (s: string): string => `- ${s}`)
|
|
323
|
+
const _not = not || (logOptions.colors ? (s: string): string => s : (s: string): string => ` ${s}`)
|
|
324
|
+
|
|
325
|
+
// We'll need two array of string lines to compare...
|
|
326
|
+
let lhsLines: string[]
|
|
327
|
+
let rhsLines: string[]
|
|
328
|
+
|
|
329
|
+
// Get the _real_ types of both arguments
|
|
330
|
+
const lhsType = getTypeOf(lhs)
|
|
331
|
+
const rhsType = getTypeOf(rhs)
|
|
332
|
+
|
|
333
|
+
// If _both_ arguments are strings, then just split and compare, otherwise
|
|
334
|
+
// we nuse NodeJS' inspect to prep their string version
|
|
335
|
+
if ((lhsType === 'string') && (rhsType === 'string')) {
|
|
336
|
+
lhsLines = lhs.split('\n')
|
|
337
|
+
rhsLines = rhs.split('\n')
|
|
338
|
+
} else {
|
|
339
|
+
lhsLines = inspect(lhs, inspectOptions).split('\n')
|
|
340
|
+
rhsLines = inspect(rhs, inspectOptions).split('\n')
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Calculate the difference between the two arrays of strings
|
|
344
|
+
const changes = diff(lhsLines, rhsLines)
|
|
345
|
+
if (changes.length === 0) return ''
|
|
346
|
+
|
|
347
|
+
// Go through changes and highlight
|
|
348
|
+
let offset = 0
|
|
349
|
+
const result: string[] = []
|
|
350
|
+
changes.forEach(({ lhsPos, lhsDel, rhsPos, rhsAdd }) => {
|
|
351
|
+
if (offset != lhsPos) result.push(...lhsLines.slice(offset, lhsPos).map(_not))
|
|
352
|
+
if (lhsDel) result.push(...lhsLines.slice(lhsPos, lhsPos + lhsDel).map(_del))
|
|
353
|
+
if (rhsAdd) result.push(...rhsLines.slice(rhsPos, rhsPos + rhsAdd).map(_add))
|
|
354
|
+
offset = lhsPos + lhsDel
|
|
355
|
+
})
|
|
356
|
+
if (offset < lhsLines.length) result.push(...lhsLines.slice(offset).map(_not))
|
|
357
|
+
|
|
358
|
+
// Join our results and return
|
|
359
|
+
return result.join('\n')
|
|
360
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** A type adding the values `null` or `array` to the result of `typeof` */
|
|
2
|
+
export type BasicType =
|
|
3
|
+
| 'string' | 'number' | 'bigint' | 'boolean' | 'symbol'
|
|
4
|
+
| 'undefined' | 'object' | 'function' | 'null' | 'array'
|
|
5
|
+
|
|
6
|
+
/** Get the _real_ type of a value, including `null` or `array` */
|
|
7
|
+
export function getTypeOf(what: unknown): BasicType {
|
|
8
|
+
if (Array.isArray(what)) return 'array'
|
|
9
|
+
if (what === null) return 'null'
|
|
10
|
+
return typeof what
|
|
11
|
+
}
|