-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch-worker.js
More file actions
129 lines (116 loc) · 3.06 KB
/
search-worker.js
File metadata and controls
129 lines (116 loc) · 3.06 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
const { parentPort, workerData } = require('worker_threads');
const YAML = require('yaml');
function parseSource(source) {
const text = String(source || '').trim();
if (!text) {
return {
ok: false,
error: 'Paste JSON or YAML to begin.'
};
}
try {
return {
ok: true,
data: JSON.parse(text)
};
} catch (jsonError) {
try {
return {
ok: true,
data: YAML.parse(text)
};
} catch (yamlError) {
const yamlMessage = yamlError instanceof Error ? yamlError.message : String(yamlError);
return {
ok: false,
error: `Unable to parse input as JSON or YAML. JSON error: ${jsonError.message}. YAML error: ${yamlMessage}`
};
}
}
}
function isObject(value) {
return value !== null && typeof value === 'object' && !Array.isArray(value);
}
function primitiveText(value) {
if (value === null) {
return 'null';
}
if (typeof value === 'string') {
return value;
}
return String(value);
}
function searchPaths(root, query, limit) {
const normalized = String(query || '').trim().toLowerCase();
if (!normalized) {
return [];
}
const results = [];
const seen = new Set();
const stack = [{ value: root, path: [] }];
while (stack.length > 0 && results.length < limit) {
const current = stack.pop();
const value = current.value;
const path = current.path;
if (Array.isArray(value)) {
for (let i = value.length - 1; i >= 0; i -= 1) {
stack.push({
value: value[i],
path: [...path, i]
});
}
continue;
}
if (isObject(value)) {
const entries = Object.entries(value);
for (let i = entries.length - 1; i >= 0; i -= 1) {
const [key, child] = entries[i];
const childPath = [...path, key];
if (String(key).toLowerCase().includes(normalized)) {
const token = JSON.stringify(childPath);
if (!seen.has(token)) {
seen.add(token);
results.push({
path: childPath,
target: 'key'
});
if (results.length >= limit) {
break;
}
}
}
stack.push({
value: child,
path: childPath
});
}
continue;
}
if (primitiveText(value).toLowerCase().includes(normalized)) {
const token = JSON.stringify(path);
if (!seen.has(token)) {
seen.add(token);
results.push({
path,
target: 'value'
});
}
}
}
return results;
}
const source = workerData && typeof workerData.source === 'string' ? workerData.source : '';
const query = workerData && typeof workerData.query === 'string' ? workerData.query : '';
const limit = workerData && typeof workerData.limit === 'number' ? workerData.limit : 2000;
const parsed = parseSource(source);
if (!parsed.ok) {
parentPort.postMessage(parsed);
} else {
const results = searchPaths(parsed.data, query, limit);
parentPort.postMessage({
ok: true,
query,
count: results.length,
results
});
}