|
| 1 | +import JSZip from 'jszip'; |
| 2 | +import uid from './uid'; |
| 3 | + |
1 | 4 | /**
|
2 | 5 | * String.prototype.indexOf, but it returns NaN not -1 on failure
|
3 | 6 | * @param {string} str The string to check in
|
@@ -56,7 +59,7 @@ const push = (type, message, trace) => {
|
56 | 59 | trace
|
57 | 60 | });
|
58 | 61 | };
|
59 |
| -const _parseFirefoxStack = stack => stack.split('\n') |
| 62 | +const _parseFirefoxStack = stack => stack.split('\n').slice(1) |
60 | 63 | .map(line => {
|
61 | 64 | const at = line.indexOf('@');
|
62 | 65 | const secondCol = line.lastIndexOf(':');
|
@@ -87,7 +90,7 @@ const _parseFirefoxStack = stack => stack.split('\n')
|
87 | 90 | origin
|
88 | 91 | };
|
89 | 92 | });
|
90 |
| -const _parseChromeStack = stack => stack.split('\n').slice(1) |
| 93 | +const _parseChromeStack = stack => stack.split('\n').slice(2) |
91 | 94 | .map(line => {
|
92 | 95 | // we have no use for the human readable fluff
|
93 | 96 | line = line.slice(7);
|
@@ -142,18 +145,83 @@ const parseStack = (stack, url, line, column) => {
|
142 | 145 | if (stack.split('\n', 2)[0].includes('@')) return _parseFirefoxStack(stack);
|
143 | 146 | return _parseChromeStack(stack);
|
144 | 147 | };
|
| 148 | +const downloadLogs = async () => { |
| 149 | + const files = new JSZip(); |
| 150 | + files.file('logs.json', JSON.stringify(consoleLogs)); |
| 151 | + const index = {}; |
| 152 | + // get files |
| 153 | + // sadly, this may just dead ass fail to get files due to blob lifecycle |
| 154 | + // and i dont want to make these files get stored at runtime, cause poopy doo doo ram |
| 155 | + for (const log of consoleLogs) { |
| 156 | + for (const trace of log.trace) { |
| 157 | + if (index[trace.url]) continue; |
| 158 | + const id = uid(); |
| 159 | + const content = await fetch(trace.url) |
| 160 | + .then(res => res.ok ? res.text() : null) |
| 161 | + .catch(() => {}); |
| 162 | + if (!content) continue; |
| 163 | + files.file(id, content); |
| 164 | + index[trace.url] = id; |
| 165 | + } |
| 166 | + } |
| 167 | + files.file('index.json', JSON.stringify(index)); |
| 168 | + let blob = await files.generateAsync({ type: 'blob', compression: 'DEFLATE' }); |
| 169 | + let filename = 'pm-error-download.pml'; |
| 170 | + /* actually, this is a bad idea |
| 171 | + // if we can, include the project |
| 172 | + if (vm) { |
| 173 | + filename = 'pm-error-download.pmp'; |
| 174 | + const archive = vm._saveProjectZip(); |
| 175 | + archive.file('logs.json', blob); |
| 176 | + blob = await archive.generateAsync({ |
| 177 | + type: 'blob', |
| 178 | + mimeType: 'application/x.scratch.sb3', |
| 179 | + compression: 'DEFLATE' |
| 180 | + }); |
| 181 | + } |
| 182 | + */ |
| 183 | + const a = document.createElement('a'); |
| 184 | + a.style.display = 'none'; |
| 185 | + document.body.append(a); |
| 186 | + const url = window.URL.createObjectURL(blob); |
| 187 | + a.href = url; |
| 188 | + a.download = filename; |
| 189 | + a.click(); |
| 190 | + window.URL.revokeObjectURL(url); |
| 191 | + a.remove(); |
| 192 | +}; |
| 193 | +window.downloadLogs = downloadLogs; |
145 | 194 |
|
146 | 195 | window.addEventListener('error', e =>
|
147 | 196 | push('error', e.message, parseStack(e.error.stack, e.filename, e.lineno, e.colno)));
|
148 | 197 | window.addEventListener('unhandledrejection', e => push('promiseError', e.reason, []));
|
149 |
| -for (const name of ['log', 'warn', 'error', 'debug', 'info']) { |
150 |
| - const item = window.console[name]; |
151 |
| - window.console[name] = (...args) => { |
152 |
| - let stack = []; |
153 |
| - if (browserHasStack) stack = parseStack(new Error().stack); |
154 |
| - push(name, args, stack); |
155 |
| - item(...args); |
156 |
| - }; |
| 198 | +class StackTrace extends Error { |
| 199 | + constructor() { |
| 200 | + super(''); |
| 201 | + if (this.stack.split('\n', 2)[0].includes('@')) |
| 202 | + this.stack = this.stack |
| 203 | + .split('\n') |
| 204 | + .slice(2, 3) |
| 205 | + .join('\n'); |
| 206 | + else { |
| 207 | + // chrome is weird ngl |
| 208 | + const lines = this.stack |
| 209 | + .split('\n') |
| 210 | + .slice(0, 3); |
| 211 | + lines.splice(1, 2); |
| 212 | + this.stack = lines.join('\n'); |
| 213 | + } |
| 214 | + } |
157 | 215 | }
|
158 |
| - |
159 |
| -export { consoleLogs, parseStack, push }; |
| 216 | +if (!String(window.location.href).startsWith(`http://localhost:`)) { |
| 217 | + for (const name of ['log', 'warn', 'error', 'debug', 'info']) { |
| 218 | + const item = window.console[name]; |
| 219 | + window.console[name] = (...args) => { |
| 220 | + let stack = []; |
| 221 | + if (browserHasStack) stack = parseStack(new Error().stack); |
| 222 | + push(name, args, stack); |
| 223 | + item.call(console, ...args, new StackTrace()); |
| 224 | + }; |
| 225 | + } |
| 226 | +} |
| 227 | +export { consoleLogs, parseStack, push, downloadLogs }; |
0 commit comments