-
Notifications
You must be signed in to change notification settings - Fork 0
/
worker.js
63 lines (56 loc) · 2.02 KB
/
worker.js
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
let sheet, errs, vals;
self.onmessage = ({ data }) => {
[sheet, errs, vals] = [data, {}, {}];
for (const coord in sheet) {
// Four variable names pointing to the same coordinate: A1, a1, $A1, $a1
["", "$"].map(p =>
[coord, coord.toLowerCase()].map(c => {
const name = p + c;
// Worker is reused across computations, so only define each variable once
if ((Object.getOwnPropertyDescriptor(self, name) || {}).get) {
return;
}
// Define self['A1'], w`hich is the same thing as the global variable A1
Object.defineProperty(self, name, {
get() {
if (coord in vals) {
return vals[coord];
}
vals[coord] = NaN;
// Turn numeric strings into numbers, so =A1+C1 works when both are numbers
let x = +sheet[coord];
if (sheet[coord] !== x.toString()) {
x = sheet[coord];
}
// Evaluate formula cells that begin with =
try {
vals[coord] = "=" === x[0] ? eval.call(null, x.slice(1)) : x;
} catch (e) {
const match = /\$?[A-Za-z]+[1-9][0-9]*\b/.exec(e);
if (match && !(match[0] in self)) {
// The formula refers to a uninitialized cell; set it to 0 and retry
self[match[0]] = 0;
delete vals[coord];
return self[coord];
}
// Otherwise, stringify the caught exception in the errs object
errs[coord] = e.toString();
}
// Turn vals[coord] into a string if it's not a number or boolean
switch (typeof vals[coord]) {
case "function":
case "object":
vals[coord] += "";
}
return vals[coord];
}
});
})
);
}
// For each coordinate in the sheet, call the property getter defined above
for (const coord in sheet) {
self[coord];
}
postMessage([errs, vals]);
};