You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
3.3 KiB
101 lines
3.3 KiB
// In src/parser.worker.js
|
|
|
|
// Import the lightweight and worker-safe Clarinet library
|
|
importScripts('../vendor/clarinet.min.js'); //importing the clarinet.min.js (ver. 0.12.5) from the vendor folder.
|
|
|
|
self.onmessage = async function(event) {
|
|
const file = event.data.file;
|
|
if (!file) {
|
|
self.postMessage({ type: 'error', message: 'No file received in worker.' });
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const fileSize = file.size;
|
|
let bytesRead = 0;
|
|
let lastReportedProgress = -1;
|
|
|
|
const parser = clarinet.parser();
|
|
|
|
// --- START: New Robust Parsing Logic ---
|
|
// This logic correctly builds a complete object tree from the stream.
|
|
let result; // This will hold the final, fully parsed object.
|
|
const stack = []; // A stack to keep track of current object/array.
|
|
let key = null; // The current object key.
|
|
|
|
const getParent = () => stack.length > 0 ? stack[stack.length - 1] : null;
|
|
|
|
const assign = (value) => {
|
|
const parent = getParent();
|
|
if (parent) {
|
|
if (Array.isArray(parent)) {
|
|
parent.push(value);
|
|
} else {
|
|
parent[key] = value;
|
|
}
|
|
} else {
|
|
result = value;
|
|
}
|
|
};
|
|
|
|
parser.onopenobject = (k) => {
|
|
key = k;
|
|
const newObject = {};
|
|
assign(newObject);
|
|
stack.push(newObject);
|
|
};
|
|
|
|
parser.onkey = (k) => {
|
|
key = k;
|
|
};
|
|
|
|
parser.onopenarray = () => {
|
|
const newArray = [];
|
|
assign(newArray);
|
|
stack.push(newArray);
|
|
};
|
|
|
|
parser.onvalue = (value) => {
|
|
assign(value);
|
|
};
|
|
|
|
parser.oncloseobject = () => stack.pop();
|
|
parser.onclosearray = () => stack.pop();
|
|
// --- END: New Robust Parsing Logic ---
|
|
|
|
parser.onend = () => {
|
|
self.postMessage({ type: 'progress', percent: 100 });
|
|
// Send the fully constructed 'result' object back to the main thread.
|
|
self.postMessage({ type: 'complete', data: result });
|
|
};
|
|
|
|
parser.onerror = (err) => {
|
|
console.error("Worker: Clarinet parsing error:", err);
|
|
self.postMessage({ type: 'error', message: 'Failed to parse JSON structure.' });
|
|
};
|
|
|
|
// --- Stream Reading Logic (this part remains the same) ---
|
|
const stream = file.stream();
|
|
const reader = stream.getReader();
|
|
const decoder = new TextDecoder();
|
|
|
|
while (true) {
|
|
const { done, value } = await reader.read();
|
|
if (done) {
|
|
parser.close();
|
|
break;
|
|
}
|
|
bytesRead += value.length;
|
|
const percent = Math.round((bytesRead / fileSize) * 100);
|
|
if (percent > lastReportedProgress) {
|
|
self.postMessage({ type: 'progress', percent: percent });
|
|
lastReportedProgress = percent;
|
|
}
|
|
parser.write(decoder.decode(value, { stream: true }));
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error("Worker: An error occurred during streaming:", error);
|
|
self.postMessage({ type: 'error', message: 'Failed to read file in worker.' });
|
|
}
|
|
};
|