@plugjs/plug 0.2.4 → 0.2.5

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.
@@ -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,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/types.ts"],
4
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAMO,SAAS,UAAU,MAA0B;AAClD,MAAI,MAAM,QAAQ,IAAI;AAAG,WAAO;AAChC,MAAI,SAAS;AAAM,WAAO;AAC1B,SAAO,OAAO;AAChB;",
5
+ "names": []
6
+ }
@@ -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;
@@ -0,0 +1,12 @@
1
+ // utils/types.ts
2
+ function getTypeOf(what) {
3
+ if (Array.isArray(what))
4
+ return "array";
5
+ if (what === null)
6
+ return "null";
7
+ return typeof what;
8
+ }
9
+ export {
10
+ getTypeOf
11
+ };
12
+ //# sourceMappingURL=types.mjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/types.ts"],
4
+ "mappings": ";AAMO,SAAS,UAAU,MAA0B;AAClD,MAAI,MAAM,QAAQ,IAAI;AAAG,WAAO;AAChC,MAAI,SAAS;AAAM,WAAO;AAC1B,SAAO,OAAO;AAChB;",
5
+ "names": []
6
+ }
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
@@ -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,8BADd;AAEA,0BAAc,gCAFd;AAGA,0BAAc,6BAHd;",
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
@@ -1,4 +1,6 @@
1
+ export * from './utils/diff';
1
2
  export * from './utils/exec';
2
3
  export * from './utils/match';
3
4
  export * from './utils/options';
5
+ export * from './utils/types';
4
6
  export * from './utils/walk';
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/utils.ts"],
4
- "mappings": ";AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
4
+ "mappings": ";AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
5
5
  "names": []
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plugjs/plug",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "type": "commonjs",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -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
+ }
package/src/utils.ts CHANGED
@@ -1,4 +1,6 @@
1
+ export * from './utils/diff'
1
2
  export * from './utils/exec'
2
3
  export * from './utils/match'
3
4
  export * from './utils/options'
5
+ export * from './utils/types'
4
6
  export * from './utils/walk'