-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathworker.js
More file actions
137 lines (123 loc) · 4.39 KB
/
worker.js
File metadata and controls
137 lines (123 loc) · 4.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/**
* JSON Viewer Web Worker
* Parses JSON off the main thread and serves lazy children for the tree.
*/
let data = null;
function getAtPath(root, path) {
let cur = root;
for (const p of path) {
if (cur == null) return undefined;
cur = cur[p];
}
return cur;
}
function infoOf(v) {
if (Array.isArray(v)) return { kind: "array", length: v.length };
if (v && typeof v === "object") return { kind: "object", length: Object.keys(v).length };
return { kind: "primitive", type: v === null ? "null" : typeof v, value: v };
}
function preview(v) {
if (Array.isArray(v)) return `[${v.length}]`;
if (v && typeof v === "object") return `{${Object.keys(v).length}}`;
if (typeof v === "string") return v.length > 80 ? JSON.stringify(v.slice(0, 80) + "…") : JSON.stringify(v);
return String(v);
}
function childrenSlice(v, offset = 0, limit = 200) {
if (Array.isArray(v)) {
const end = Math.min(v.length, offset + limit);
const items = [];
for (let i = offset; i < end; i++) {
const child = v[i];
items.push({ key: i, ...infoOf(child), preview: preview(child) });
}
return { items, total: v.length, offset, limit, hasMore: end < v.length };
}
if (v && typeof v === "object") {
const keys = Object.keys(v);
const end = Math.min(keys.length, offset + limit);
const items = [];
for (let i = offset; i < end; i++) {
const k = keys[i];
const child = v[k];
items.push({ key: k, ...infoOf(child), preview: preview(child) });
}
return { items, total: keys.length, offset, limit, hasMore: end < keys.length };
}
return { items: [], total: 0, offset: 0, limit: 0, hasMore: false };
}
function flattenObject(obj, prefix = "") {
if (obj === null || obj === undefined || typeof obj !== "object") {
return { [prefix || "value"]: obj };
}
const result = {};
for (const [key, value] of Object.entries(obj)) {
const newKey = prefix ? `${prefix}.${key}` : key;
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
Object.assign(result, flattenObject(value, newKey));
} else if (Array.isArray(value)) {
if (value.every((v) => typeof v !== "object" || v === null)) {
result[newKey] = value.join("; ");
} else {
result[newKey] = `[${value.length} items]`;
}
} else {
result[newKey] = value;
}
}
return result;
}
const EXPORT_ROW_LIMIT = 50000; // Cap to avoid Excel slowdown; 32k–50k rows usually fine
self.onmessage = (e) => {
const msg = e.data;
try {
if (msg.type === "LOAD") {
data = JSON.parse(msg.text);
self.postMessage({ type: "READY", root: { ...infoOf(data), preview: preview(data) } });
return;
}
if (msg.type === "FORMAT") {
if (msg.text) data = JSON.parse(msg.text);
const formatted = data ? JSON.stringify(data, null, 2) : "";
self.postMessage({ type: "READY", root: data ? { ...infoOf(data), preview: preview(data) } : null });
self.postMessage({ type: "FORMATTED", text: formatted });
return;
}
if (msg.type === "CHILDREN") {
const v = getAtPath(data, msg.path || []);
const res = childrenSlice(v, msg.offset || 0, msg.limit || 200);
self.postMessage({ type: "CHILDREN_RESULT", path: msg.path || [], ...res });
return;
}
if (msg.type === "GET_FULL") {
const text = data != null ? JSON.stringify(data) : "";
self.postMessage({ type: "FULL", text });
return;
}
if (msg.type === "EXPORT_PREP") {
let arr = data;
let sheetName = "Data";
if (!Array.isArray(arr) && typeof arr === "object" && arr !== null) {
const keys = Object.keys(arr);
const arrayKey = keys.find((k) => Array.isArray(arr[k]) && arr[k].length > 0);
if (arrayKey) {
arr = arr[arrayKey];
sheetName = arrayKey;
} else {
arr = [arr];
}
}
if (!Array.isArray(arr)) arr = [arr];
const flatData = arr.slice(0, EXPORT_ROW_LIMIT).map((item) => flattenObject(item));
const headers = [...new Set(flatData.flatMap((obj) => Object.keys(obj)))];
self.postMessage({ type: "EXPORT_DATA", sheetName, headers, rows: flatData, totalRows: arr.length });
return;
}
if (msg.type === "RESET") {
data = null;
self.postMessage({ type: "RESET_DONE" });
return;
}
} catch (err) {
self.postMessage({ type: "ERROR", message: err.message });
}
};