json-term 1.0.0
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/LICENSE +21 -0
- package/README.md +176 -0
- package/dist/cli.d.mts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +718 -0
- package/dist/cli.js.map +1 -0
- package/dist/cli.mjs +695 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/index.d.mts +111 -0
- package/dist/index.d.ts +111 -0
- package/dist/index.js +638 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +592 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +69 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,638 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
InteractiveViewer: () => InteractiveViewer,
|
|
34
|
+
buildTree: () => buildTree,
|
|
35
|
+
calculateDiffStats: () => calculateDiffStats,
|
|
36
|
+
copyToClipboard: () => copyToClipboard,
|
|
37
|
+
diffJSON: () => diffJSON,
|
|
38
|
+
formatKey: () => formatKey,
|
|
39
|
+
formatValue: () => formatValue,
|
|
40
|
+
getValueType: () => getValueType,
|
|
41
|
+
prettyPrintDiff: () => prettyPrintDiff,
|
|
42
|
+
prettyPrintTree: () => prettyPrintTree
|
|
43
|
+
});
|
|
44
|
+
module.exports = __toCommonJS(src_exports);
|
|
45
|
+
|
|
46
|
+
// src/formatter.ts
|
|
47
|
+
var import_picocolors = __toESM(require("picocolors"));
|
|
48
|
+
function getValueType(value) {
|
|
49
|
+
if (value === null || value === void 0) return "null";
|
|
50
|
+
if (Array.isArray(value)) return "array";
|
|
51
|
+
const t = typeof value;
|
|
52
|
+
if (t === "object") return "object";
|
|
53
|
+
if (t === "string") return "string";
|
|
54
|
+
if (t === "number") return "number";
|
|
55
|
+
if (t === "boolean") return "boolean";
|
|
56
|
+
return "string";
|
|
57
|
+
}
|
|
58
|
+
function formatValue(value, truncateLen = 80) {
|
|
59
|
+
const type = getValueType(value);
|
|
60
|
+
switch (type) {
|
|
61
|
+
case "string": {
|
|
62
|
+
const str = JSON.stringify(value);
|
|
63
|
+
const truncated = str.length > truncateLen ? str.slice(0, truncateLen - 3) + '..."' : str;
|
|
64
|
+
return import_picocolors.default.green(truncated);
|
|
65
|
+
}
|
|
66
|
+
case "number":
|
|
67
|
+
return import_picocolors.default.yellow(String(value));
|
|
68
|
+
case "boolean":
|
|
69
|
+
return import_picocolors.default.magenta(String(value));
|
|
70
|
+
case "null":
|
|
71
|
+
return import_picocolors.default.dim("null");
|
|
72
|
+
case "array":
|
|
73
|
+
return import_picocolors.default.dim(`[${value.length} items]`);
|
|
74
|
+
case "object":
|
|
75
|
+
return import_picocolors.default.dim(`{${Object.keys(value).length} keys}`);
|
|
76
|
+
default:
|
|
77
|
+
return String(value);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function formatKey(key) {
|
|
81
|
+
return import_picocolors.default.bold(import_picocolors.default.cyan(key));
|
|
82
|
+
}
|
|
83
|
+
function buildTree(data, key, path = "$", depth = 0, maxInitialDepth = 2, parentId) {
|
|
84
|
+
const type = getValueType(data);
|
|
85
|
+
const id = `${path}-${key || "root"}-${depth}`;
|
|
86
|
+
const collapsed = depth >= maxInitialDepth;
|
|
87
|
+
const node = {
|
|
88
|
+
id,
|
|
89
|
+
key,
|
|
90
|
+
value: data,
|
|
91
|
+
type,
|
|
92
|
+
depth,
|
|
93
|
+
path,
|
|
94
|
+
collapsed,
|
|
95
|
+
parentId
|
|
96
|
+
};
|
|
97
|
+
if (type === "object" && data !== null) {
|
|
98
|
+
const keys = Object.keys(data);
|
|
99
|
+
node.itemCount = keys.length;
|
|
100
|
+
node.children = keys.map(
|
|
101
|
+
(k) => buildTree(
|
|
102
|
+
data[k],
|
|
103
|
+
k,
|
|
104
|
+
path === "$" ? k : `${path}.${k}`,
|
|
105
|
+
depth + 1,
|
|
106
|
+
maxInitialDepth,
|
|
107
|
+
id
|
|
108
|
+
)
|
|
109
|
+
);
|
|
110
|
+
} else if (type === "array") {
|
|
111
|
+
node.itemCount = data.length;
|
|
112
|
+
node.children = data.map(
|
|
113
|
+
(item, idx) => buildTree(
|
|
114
|
+
item,
|
|
115
|
+
`[${idx}]`,
|
|
116
|
+
`${path}[${idx}]`,
|
|
117
|
+
depth + 1,
|
|
118
|
+
maxInitialDepth,
|
|
119
|
+
id
|
|
120
|
+
)
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
return node;
|
|
124
|
+
}
|
|
125
|
+
function prettyPrintTree(node, indent = "", isLast = true) {
|
|
126
|
+
const isRoot = node.depth === 0;
|
|
127
|
+
const marker = node.type === "object" || node.type === "array" ? node.collapsed ? import_picocolors.default.cyan("\u25B6 ") : import_picocolors.default.cyan("\u25BC ") : import_picocolors.default.dim("\u2022 ");
|
|
128
|
+
let line = "";
|
|
129
|
+
if (!isRoot) {
|
|
130
|
+
const branch = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
131
|
+
line += import_picocolors.default.dim(indent + branch) + marker;
|
|
132
|
+
if (node.key) {
|
|
133
|
+
line += formatKey(node.key) + import_picocolors.default.dim(": ");
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
line += marker + (node.key ? formatKey(node.key) + import_picocolors.default.dim(": ") : import_picocolors.default.bold(import_picocolors.default.white("root: ")));
|
|
137
|
+
}
|
|
138
|
+
if (node.type === "object") {
|
|
139
|
+
line += import_picocolors.default.dim(`{ ${node.itemCount} keys }`);
|
|
140
|
+
} else if (node.type === "array") {
|
|
141
|
+
line += import_picocolors.default.dim(`[ ${node.itemCount} items ]`);
|
|
142
|
+
} else {
|
|
143
|
+
line += formatValue(node.value);
|
|
144
|
+
}
|
|
145
|
+
const lines = [line];
|
|
146
|
+
if (!node.collapsed && node.children && node.children.length > 0) {
|
|
147
|
+
const nextIndent = isRoot ? "" : indent + (isLast ? " " : "\u2502 ");
|
|
148
|
+
node.children.forEach((child, index) => {
|
|
149
|
+
const childIsLast = index === node.children.length - 1;
|
|
150
|
+
lines.push(prettyPrintTree(child, nextIndent, childIsLast));
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return lines.join("\n");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// src/differ.ts
|
|
157
|
+
var import_picocolors2 = __toESM(require("picocolors"));
|
|
158
|
+
function diffJSON(a, b, key, path = "$", depth = 0, maxInitialDepth = 3) {
|
|
159
|
+
const typeA = getValueType(a);
|
|
160
|
+
const typeB = getValueType(b);
|
|
161
|
+
const id = `${path}-${key || "diff"}-${depth}`;
|
|
162
|
+
const collapsed = depth >= maxInitialDepth;
|
|
163
|
+
if (a === void 0 && b !== void 0) {
|
|
164
|
+
const node = {
|
|
165
|
+
id,
|
|
166
|
+
key,
|
|
167
|
+
path,
|
|
168
|
+
depth,
|
|
169
|
+
status: "added",
|
|
170
|
+
newValue: b,
|
|
171
|
+
type: typeB,
|
|
172
|
+
collapsed: false
|
|
173
|
+
};
|
|
174
|
+
if (typeB === "object" && b !== null) {
|
|
175
|
+
node.itemCount = Object.keys(b).length;
|
|
176
|
+
node.children = Object.keys(b).map(
|
|
177
|
+
(k) => diffJSON(void 0, b[k], k, path === "$" ? k : `${path}.${k}`, depth + 1, maxInitialDepth)
|
|
178
|
+
);
|
|
179
|
+
} else if (typeB === "array") {
|
|
180
|
+
node.itemCount = b.length;
|
|
181
|
+
node.children = b.map(
|
|
182
|
+
(item, idx) => diffJSON(void 0, item, `[${idx}]`, `${path}[${idx}]`, depth + 1, maxInitialDepth)
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
return node;
|
|
186
|
+
}
|
|
187
|
+
if (a !== void 0 && b === void 0) {
|
|
188
|
+
const node = {
|
|
189
|
+
id,
|
|
190
|
+
key,
|
|
191
|
+
path,
|
|
192
|
+
depth,
|
|
193
|
+
status: "removed",
|
|
194
|
+
oldValue: a,
|
|
195
|
+
type: typeA,
|
|
196
|
+
collapsed: false
|
|
197
|
+
};
|
|
198
|
+
if (typeA === "object" && a !== null) {
|
|
199
|
+
node.itemCount = Object.keys(a).length;
|
|
200
|
+
node.children = Object.keys(a).map(
|
|
201
|
+
(k) => diffJSON(a[k], void 0, k, path === "$" ? k : `${path}.${k}`, depth + 1, maxInitialDepth)
|
|
202
|
+
);
|
|
203
|
+
} else if (typeA === "array") {
|
|
204
|
+
node.itemCount = a.length;
|
|
205
|
+
node.children = a.map(
|
|
206
|
+
(item, idx) => diffJSON(item, void 0, `[${idx}]`, `${path}[${idx}]`, depth + 1, maxInitialDepth)
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
return node;
|
|
210
|
+
}
|
|
211
|
+
if (typeA !== typeB) {
|
|
212
|
+
return {
|
|
213
|
+
id,
|
|
214
|
+
key,
|
|
215
|
+
path,
|
|
216
|
+
depth,
|
|
217
|
+
status: "modified",
|
|
218
|
+
oldValue: a,
|
|
219
|
+
newValue: b,
|
|
220
|
+
type: typeB,
|
|
221
|
+
collapsed: false
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
if (typeA === "object" && a !== null && b !== null) {
|
|
225
|
+
const allKeys = Array.from(/* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]));
|
|
226
|
+
const children = [];
|
|
227
|
+
let hasModifications = false;
|
|
228
|
+
for (const k of allKeys) {
|
|
229
|
+
const child = diffJSON(
|
|
230
|
+
a[k],
|
|
231
|
+
b[k],
|
|
232
|
+
k,
|
|
233
|
+
path === "$" ? k : `${path}.${k}`,
|
|
234
|
+
depth + 1,
|
|
235
|
+
maxInitialDepth
|
|
236
|
+
);
|
|
237
|
+
if (child.status !== "unchanged") hasModifications = true;
|
|
238
|
+
children.push(child);
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
id,
|
|
242
|
+
key,
|
|
243
|
+
path,
|
|
244
|
+
depth,
|
|
245
|
+
status: hasModifications ? "modified" : "unchanged",
|
|
246
|
+
oldValue: a,
|
|
247
|
+
newValue: b,
|
|
248
|
+
type: "object",
|
|
249
|
+
itemCount: allKeys.length,
|
|
250
|
+
collapsed,
|
|
251
|
+
children
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
if (typeA === "array") {
|
|
255
|
+
const maxLen = Math.max(a.length, b.length);
|
|
256
|
+
const children = [];
|
|
257
|
+
let hasModifications = false;
|
|
258
|
+
for (let i = 0; i < maxLen; i++) {
|
|
259
|
+
const child = diffJSON(
|
|
260
|
+
a[i],
|
|
261
|
+
b[i],
|
|
262
|
+
`[${i}]`,
|
|
263
|
+
`${path}[${i}]`,
|
|
264
|
+
depth + 1,
|
|
265
|
+
maxInitialDepth
|
|
266
|
+
);
|
|
267
|
+
if (child.status !== "unchanged") hasModifications = true;
|
|
268
|
+
children.push(child);
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
id,
|
|
272
|
+
key,
|
|
273
|
+
path,
|
|
274
|
+
depth,
|
|
275
|
+
status: hasModifications ? "modified" : "unchanged",
|
|
276
|
+
oldValue: a,
|
|
277
|
+
newValue: b,
|
|
278
|
+
type: "array",
|
|
279
|
+
itemCount: maxLen,
|
|
280
|
+
collapsed,
|
|
281
|
+
children
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
if (a !== b) {
|
|
285
|
+
return {
|
|
286
|
+
id,
|
|
287
|
+
key,
|
|
288
|
+
path,
|
|
289
|
+
depth,
|
|
290
|
+
status: "modified",
|
|
291
|
+
oldValue: a,
|
|
292
|
+
newValue: b,
|
|
293
|
+
type: typeB,
|
|
294
|
+
collapsed: false
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
id,
|
|
299
|
+
key,
|
|
300
|
+
path,
|
|
301
|
+
depth,
|
|
302
|
+
status: "unchanged",
|
|
303
|
+
oldValue: a,
|
|
304
|
+
newValue: b,
|
|
305
|
+
type: typeA,
|
|
306
|
+
collapsed
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
function calculateDiffStats(node) {
|
|
310
|
+
const stats = { added: 0, removed: 0, modified: 0, unchanged: 0 };
|
|
311
|
+
function traverse(n) {
|
|
312
|
+
if (n.children && n.children.length > 0) {
|
|
313
|
+
n.children.forEach(traverse);
|
|
314
|
+
} else {
|
|
315
|
+
stats[n.status]++;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
traverse(node);
|
|
319
|
+
return stats;
|
|
320
|
+
}
|
|
321
|
+
function prettyPrintDiff(node, options = {}, indent = "", isLast = true) {
|
|
322
|
+
const showUnchanged = options.showUnchanged ?? true;
|
|
323
|
+
if (!showUnchanged && node.status === "unchanged" && (!node.children || node.children.length === 0)) {
|
|
324
|
+
return "";
|
|
325
|
+
}
|
|
326
|
+
const isRoot = node.depth === 0;
|
|
327
|
+
let prefix = " ";
|
|
328
|
+
let statusColor = import_picocolors2.default.dim;
|
|
329
|
+
if (node.status === "added") {
|
|
330
|
+
prefix = import_picocolors2.default.green("+ ");
|
|
331
|
+
statusColor = import_picocolors2.default.green;
|
|
332
|
+
} else if (node.status === "removed") {
|
|
333
|
+
prefix = import_picocolors2.default.red("- ");
|
|
334
|
+
statusColor = import_picocolors2.default.red;
|
|
335
|
+
} else if (node.status === "modified") {
|
|
336
|
+
prefix = import_picocolors2.default.yellow("~ ");
|
|
337
|
+
statusColor = import_picocolors2.default.yellow;
|
|
338
|
+
}
|
|
339
|
+
let line = prefix;
|
|
340
|
+
if (!isRoot) {
|
|
341
|
+
const branch = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
342
|
+
line += import_picocolors2.default.dim(indent + branch);
|
|
343
|
+
if (node.key) {
|
|
344
|
+
line += formatKey(node.key) + import_picocolors2.default.dim(": ");
|
|
345
|
+
}
|
|
346
|
+
} else {
|
|
347
|
+
line += node.key ? formatKey(node.key) + import_picocolors2.default.dim(": ") : import_picocolors2.default.bold("diff: ");
|
|
348
|
+
}
|
|
349
|
+
if (node.status === "added") {
|
|
350
|
+
line += statusColor(formatValue(node.newValue));
|
|
351
|
+
} else if (node.status === "removed") {
|
|
352
|
+
line += statusColor(formatValue(node.oldValue));
|
|
353
|
+
} else if (node.status === "modified") {
|
|
354
|
+
if (node.type === "object" || node.type === "array") {
|
|
355
|
+
line += statusColor(`{ ${node.itemCount} items modified }`);
|
|
356
|
+
} else {
|
|
357
|
+
line += `${import_picocolors2.default.red(formatValue(node.oldValue))} ${import_picocolors2.default.dim("->")} ${import_picocolors2.default.green(formatValue(node.newValue))}`;
|
|
358
|
+
}
|
|
359
|
+
} else {
|
|
360
|
+
line += import_picocolors2.default.dim(formatValue(node.newValue));
|
|
361
|
+
}
|
|
362
|
+
const lines = [line];
|
|
363
|
+
if (!node.collapsed && node.children && node.children.length > 0) {
|
|
364
|
+
const nextIndent = isRoot ? "" : indent + (isLast ? " " : "\u2502 ");
|
|
365
|
+
node.children.forEach((child, index) => {
|
|
366
|
+
const childIsLast = index === node.children.length - 1;
|
|
367
|
+
const childStr = prettyPrintDiff(child, options, nextIndent, childIsLast);
|
|
368
|
+
if (childStr) lines.push(childStr);
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
return lines.join("\n");
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// src/interactive.ts
|
|
375
|
+
var import_readline = __toESM(require("readline"));
|
|
376
|
+
var import_picocolors3 = __toESM(require("picocolors"));
|
|
377
|
+
|
|
378
|
+
// src/utils/clipboard.ts
|
|
379
|
+
var import_child_process = require("child_process");
|
|
380
|
+
var import_os = __toESM(require("os"));
|
|
381
|
+
async function copyToClipboard(text) {
|
|
382
|
+
const platform = import_os.default.platform();
|
|
383
|
+
return new Promise((resolve) => {
|
|
384
|
+
let proc;
|
|
385
|
+
if (platform === "darwin") {
|
|
386
|
+
proc = (0, import_child_process.exec)("pbcopy", (err) => resolve(!err));
|
|
387
|
+
} else if (platform === "win32") {
|
|
388
|
+
proc = (0, import_child_process.exec)("clip", (err) => resolve(!err));
|
|
389
|
+
} else {
|
|
390
|
+
proc = (0, import_child_process.exec)("wl-copy 2>/dev/null || xclip -selection clipboard 2>/dev/null || xsel --clipboard --input", (err) => {
|
|
391
|
+
resolve(!err);
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
if (proc.stdin) {
|
|
395
|
+
proc.stdin.write(text);
|
|
396
|
+
proc.stdin.end();
|
|
397
|
+
} else {
|
|
398
|
+
resolve(false);
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// src/interactive.ts
|
|
404
|
+
var InteractiveViewer = class {
|
|
405
|
+
root;
|
|
406
|
+
flatList = [];
|
|
407
|
+
selectedIndex = 0;
|
|
408
|
+
searchQuery = "";
|
|
409
|
+
isSearching = false;
|
|
410
|
+
searchInput = "";
|
|
411
|
+
notification = "";
|
|
412
|
+
notificationTimer = null;
|
|
413
|
+
isDiff;
|
|
414
|
+
constructor(root, isDiff = false) {
|
|
415
|
+
this.root = root;
|
|
416
|
+
this.isDiff = isDiff;
|
|
417
|
+
this.rebuildFlatList();
|
|
418
|
+
}
|
|
419
|
+
isDiffNode(node) {
|
|
420
|
+
return this.isDiff && "status" in node;
|
|
421
|
+
}
|
|
422
|
+
rebuildFlatList() {
|
|
423
|
+
const list = [];
|
|
424
|
+
const traverse = (node, currentDepth) => {
|
|
425
|
+
if (this.searchQuery) {
|
|
426
|
+
const query = this.searchQuery.toLowerCase();
|
|
427
|
+
const keyMatch = node.key && node.key.toLowerCase().includes(query);
|
|
428
|
+
const pathMatch = node.path && node.path.toLowerCase().includes(query);
|
|
429
|
+
const valMatch = "value" in node ? JSON.stringify(node.value).toLowerCase().includes(query) : "newValue" in node ? JSON.stringify(node.newValue).toLowerCase().includes(query) : false;
|
|
430
|
+
if (!keyMatch && !pathMatch && !valMatch && (!node.children || node.children.length === 0)) {
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
list.push({ node, depth: currentDepth, isDiff: this.isDiff });
|
|
435
|
+
if (!node.collapsed && node.children && node.children.length > 0) {
|
|
436
|
+
for (const child of node.children) {
|
|
437
|
+
traverse(child, currentDepth + 1);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
traverse(this.root, 0);
|
|
442
|
+
this.flatList = list;
|
|
443
|
+
if (this.selectedIndex >= this.flatList.length) {
|
|
444
|
+
this.selectedIndex = Math.max(0, this.flatList.length - 1);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
setNotification(msg) {
|
|
448
|
+
this.notification = msg;
|
|
449
|
+
if (this.notificationTimer) clearTimeout(this.notificationTimer);
|
|
450
|
+
this.notificationTimer = setTimeout(() => {
|
|
451
|
+
this.notification = "";
|
|
452
|
+
this.render();
|
|
453
|
+
}, 2500);
|
|
454
|
+
}
|
|
455
|
+
render() {
|
|
456
|
+
const rows = process.stdout.rows || 24;
|
|
457
|
+
const maxVisibleRows = Math.max(5, rows - 5);
|
|
458
|
+
let startIdx = 0;
|
|
459
|
+
if (this.selectedIndex >= maxVisibleRows) {
|
|
460
|
+
startIdx = this.selectedIndex - maxVisibleRows + 1;
|
|
461
|
+
}
|
|
462
|
+
const endIdx = Math.min(this.flatList.length, startIdx + maxVisibleRows);
|
|
463
|
+
process.stdout.write("\x1B[2J\x1B[3J\x1B[H\x1B[?25l");
|
|
464
|
+
const title = this.isDiff ? " JSON Structural Diff Explorer " : " Interactive JSON Tree Explorer ";
|
|
465
|
+
console.log(import_picocolors3.default.bgCyan(import_picocolors3.default.black(import_picocolors3.default.bold(` ${title} `)) + import_picocolors3.default.dim(` [Total items: ${this.flatList.length}]`)));
|
|
466
|
+
for (let i = startIdx; i < endIdx; i++) {
|
|
467
|
+
const { node, depth } = this.flatList[i];
|
|
468
|
+
const isSelected = i === this.selectedIndex;
|
|
469
|
+
const indent = " ".repeat(depth);
|
|
470
|
+
let marker = "\u2022 ";
|
|
471
|
+
if (node.children && node.children.length > 0) {
|
|
472
|
+
marker = node.collapsed ? "\u25B6 " : "\u25BC ";
|
|
473
|
+
}
|
|
474
|
+
let lineContent = "";
|
|
475
|
+
if (this.isDiffNode(node)) {
|
|
476
|
+
let diffPrefix = " ";
|
|
477
|
+
if (node.status === "added") diffPrefix = import_picocolors3.default.green("+ ");
|
|
478
|
+
else if (node.status === "removed") diffPrefix = import_picocolors3.default.red("- ");
|
|
479
|
+
else if (node.status === "modified") diffPrefix = import_picocolors3.default.yellow("~ ");
|
|
480
|
+
lineContent = diffPrefix + indent + marker;
|
|
481
|
+
if (node.key) lineContent += formatKey(node.key) + import_picocolors3.default.dim(": ");
|
|
482
|
+
if (node.status === "added") {
|
|
483
|
+
lineContent += import_picocolors3.default.green(formatValue(node.newValue, 50));
|
|
484
|
+
} else if (node.status === "removed") {
|
|
485
|
+
lineContent += import_picocolors3.default.red(formatValue(node.oldValue, 50));
|
|
486
|
+
} else if (node.status === "modified") {
|
|
487
|
+
if (node.type === "object" || node.type === "array") {
|
|
488
|
+
lineContent += import_picocolors3.default.yellow(`{ ${node.itemCount} modified }`);
|
|
489
|
+
} else {
|
|
490
|
+
lineContent += `${import_picocolors3.default.red(formatValue(node.oldValue, 25))} -> ${import_picocolors3.default.green(formatValue(node.newValue, 25))}`;
|
|
491
|
+
}
|
|
492
|
+
} else {
|
|
493
|
+
lineContent += import_picocolors3.default.dim(formatValue(node.newValue, 50));
|
|
494
|
+
}
|
|
495
|
+
} else {
|
|
496
|
+
const treeNode = node;
|
|
497
|
+
lineContent = indent + marker;
|
|
498
|
+
if (treeNode.key) lineContent += formatKey(treeNode.key) + import_picocolors3.default.dim(": ");
|
|
499
|
+
if (treeNode.type === "object") {
|
|
500
|
+
lineContent += import_picocolors3.default.dim(`{ ${treeNode.itemCount} keys }`);
|
|
501
|
+
} else if (treeNode.type === "array") {
|
|
502
|
+
lineContent += import_picocolors3.default.dim(`[ ${treeNode.itemCount} items ]`);
|
|
503
|
+
} else {
|
|
504
|
+
lineContent += formatValue(treeNode.value, 60);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (isSelected) {
|
|
508
|
+
console.log(import_picocolors3.default.bgBlue(import_picocolors3.default.white(import_picocolors3.default.bold(`> ${lineContent}`))));
|
|
509
|
+
} else {
|
|
510
|
+
console.log(` ${lineContent}`);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
const selectedItem = this.flatList[this.selectedIndex];
|
|
514
|
+
const currentPath = selectedItem ? selectedItem.node.path : "$";
|
|
515
|
+
console.log("\n" + import_picocolors3.default.dim("\u2500".repeat(Math.min(process.stdout.columns || 80, 80))));
|
|
516
|
+
if (this.notification) {
|
|
517
|
+
console.log(import_picocolors3.default.green(import_picocolors3.default.bold(` ${this.notification}`)));
|
|
518
|
+
} else if (this.isSearching) {
|
|
519
|
+
console.log(import_picocolors3.default.yellow(import_picocolors3.default.bold(` Search: /${this.searchInput}\u2588`)));
|
|
520
|
+
} else {
|
|
521
|
+
console.log(import_picocolors3.default.bold(import_picocolors3.default.cyan(` Path: ${currentPath}`)));
|
|
522
|
+
console.log(
|
|
523
|
+
import_picocolors3.default.dim(" [\u2191/\u2193] Move [Enter/Space] Toggle [e] Expand All [c] Collapse All [p] Copy Path [y] Copy Val [/] Search [q] Exit")
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
expandAll(node) {
|
|
528
|
+
node.collapsed = false;
|
|
529
|
+
if (node.children) node.children.forEach((c) => this.expandAll(c));
|
|
530
|
+
}
|
|
531
|
+
collapseAll(node) {
|
|
532
|
+
if (node.depth > 0) node.collapsed = true;
|
|
533
|
+
if (node.children) node.children.forEach((c) => this.collapseAll(c));
|
|
534
|
+
}
|
|
535
|
+
async start() {
|
|
536
|
+
if (!process.stdin.isTTY) {
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
import_readline.default.emitKeypressEvents(process.stdin);
|
|
540
|
+
process.stdin.setRawMode(true);
|
|
541
|
+
process.stdin.resume();
|
|
542
|
+
this.render();
|
|
543
|
+
return new Promise((resolve) => {
|
|
544
|
+
const onKeypress = async (str, key) => {
|
|
545
|
+
if (this.isSearching) {
|
|
546
|
+
if (key.name === "return") {
|
|
547
|
+
this.searchQuery = this.searchInput;
|
|
548
|
+
this.isSearching = false;
|
|
549
|
+
this.rebuildFlatList();
|
|
550
|
+
this.render();
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
if (key.name === "escape") {
|
|
554
|
+
this.isSearching = false;
|
|
555
|
+
this.searchInput = "";
|
|
556
|
+
this.render();
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
if (key.name === "backspace") {
|
|
560
|
+
this.searchInput = this.searchInput.slice(0, -1);
|
|
561
|
+
this.render();
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
if (str && str.length === 1) {
|
|
565
|
+
this.searchInput += str;
|
|
566
|
+
this.render();
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
if (key.name === "up" || key.name === "k") {
|
|
571
|
+
if (this.selectedIndex > 0) {
|
|
572
|
+
this.selectedIndex--;
|
|
573
|
+
this.render();
|
|
574
|
+
}
|
|
575
|
+
} else if (key.name === "down" || key.name === "j") {
|
|
576
|
+
if (this.selectedIndex < this.flatList.length - 1) {
|
|
577
|
+
this.selectedIndex++;
|
|
578
|
+
this.render();
|
|
579
|
+
}
|
|
580
|
+
} else if (key.name === "return" || key.name === "space" || key.name === "right" || key.name === "left") {
|
|
581
|
+
const item = this.flatList[this.selectedIndex];
|
|
582
|
+
if (item && item.node.children && item.node.children.length > 0) {
|
|
583
|
+
item.node.collapsed = !item.node.collapsed;
|
|
584
|
+
this.rebuildFlatList();
|
|
585
|
+
this.render();
|
|
586
|
+
}
|
|
587
|
+
} else if (str === "e" || str === "E") {
|
|
588
|
+
this.expandAll(this.root);
|
|
589
|
+
this.rebuildFlatList();
|
|
590
|
+
this.render();
|
|
591
|
+
} else if (str === "c" || str === "C") {
|
|
592
|
+
this.collapseAll(this.root);
|
|
593
|
+
this.rebuildFlatList();
|
|
594
|
+
this.render();
|
|
595
|
+
} else if (str === "p" || str === "P") {
|
|
596
|
+
const item = this.flatList[this.selectedIndex];
|
|
597
|
+
if (item) {
|
|
598
|
+
await copyToClipboard(item.node.path);
|
|
599
|
+
this.setNotification(`\u2714 Copied JSONPath: ${item.node.path}`);
|
|
600
|
+
}
|
|
601
|
+
} else if (str === "y" || str === "Y") {
|
|
602
|
+
const item = this.flatList[this.selectedIndex];
|
|
603
|
+
if (item) {
|
|
604
|
+
const val = "value" in item.node ? item.node.value : item.node.newValue;
|
|
605
|
+
const textToCopy = typeof val === "object" ? JSON.stringify(val, null, 2) : String(val);
|
|
606
|
+
await copyToClipboard(textToCopy);
|
|
607
|
+
this.setNotification(`\u2714 Copied value to clipboard!`);
|
|
608
|
+
}
|
|
609
|
+
} else if (str === "/") {
|
|
610
|
+
this.isSearching = true;
|
|
611
|
+
this.searchInput = "";
|
|
612
|
+
this.render();
|
|
613
|
+
} else if (key.ctrl && key.name === "c" || key.name === "escape" || str === "q" || str === "Q") {
|
|
614
|
+
process.stdin.removeListener("keypress", onKeypress);
|
|
615
|
+
process.stdin.setRawMode(false);
|
|
616
|
+
process.stdin.pause();
|
|
617
|
+
process.stdout.write("\x1B[?25h\n");
|
|
618
|
+
resolve();
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
process.stdin.on("keypress", onKeypress);
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
626
|
+
0 && (module.exports = {
|
|
627
|
+
InteractiveViewer,
|
|
628
|
+
buildTree,
|
|
629
|
+
calculateDiffStats,
|
|
630
|
+
copyToClipboard,
|
|
631
|
+
diffJSON,
|
|
632
|
+
formatKey,
|
|
633
|
+
formatValue,
|
|
634
|
+
getValueType,
|
|
635
|
+
prettyPrintDiff,
|
|
636
|
+
prettyPrintTree
|
|
637
|
+
});
|
|
638
|
+
//# sourceMappingURL=index.js.map
|