|
132 | 132 | }); |
133 | 133 | } |
134 | 134 |
|
135 | | - reply({ action: 'cmd_ok' }); |
| 135 | + if (action !== undefined) { |
| 136 | + reply({ action: 'cmd_ok' }); |
| 137 | + } |
136 | 138 | } catch ({ message, stack }) { |
137 | 139 | reply({ action: 'cmd_error', message, stack }); |
138 | 140 | } |
|
146 | 148 | send({ action: 'unhandledrejection', value: event.reason }); |
147 | 149 | }); |
148 | 150 |
|
149 | | - // Intercept console methods |
150 | | - const timers = new Map(); |
151 | | - const counters = new Map(); |
152 | | - |
153 | | - function log(command, opts) { |
154 | | - try { |
155 | | - send({ action: 'console', command, ...opts }); |
156 | | - } catch { |
157 | | - send({ action: 'console', command: 'unclonable' }); |
158 | | - } |
159 | | - } |
160 | | - |
161 | | - function stringify(args) { |
162 | | - try { |
163 | | - return JSON.stringify(args, (key, value) => { |
164 | | - // if we don't do this, our Set/Map from svelte/reactivity would show up wrong in the console |
165 | | - if (value instanceof Map) { |
166 | | - return { type: 'Map', value }; |
167 | | - } |
168 | | - |
169 | | - if (value instanceof Set) { |
170 | | - return { type: 'Set', value }; |
171 | | - } |
172 | 151 |
|
173 | | - // if we don't handle bigints separately, they will cause JSON.stringify to blow up |
174 | | - if (typeof value === 'bigint') { |
175 | | - return { type: 'BigInt', value: value + '' }; |
176 | | - } |
177 | | - |
178 | | - return value; |
179 | | - }); |
180 | | - } catch (error) { |
181 | | - return null; |
182 | | - } |
183 | | - } |
184 | | - |
185 | | - /** @param {string} method */ |
186 | | - function stack(method) { |
187 | | - return new Error().stack |
188 | | - .split('\n') |
189 | | - .filter((line) => { |
190 | | - if (/[(@]about:srcdoc/.test(line)) return false; |
191 | | - return true; |
192 | | - }) |
193 | | - .slice(1) |
194 | | - .map((line) => { |
195 | | - line = line |
196 | | - .replace('console[method]', `console.${method}`) |
197 | | - .replace(/console\.<computed> \[as \w+\]/, `console.${method}`); |
198 | | - |
199 | | - let match = |
200 | | - /^\s+at (.+) \((.+:\d+:\d+)\)/.exec(line) || /^(.+)@(.+:\d+:\d+)?/.exec(line); |
201 | | - |
202 | | - if (match) { |
203 | | - return { |
204 | | - label: match[1], |
205 | | - location: match[2] |
206 | | - }; |
207 | | - } |
208 | | - |
209 | | - return null; |
210 | | - }) |
211 | | - .filter((x) => x); |
212 | | - } |
213 | | - |
214 | | - const can_dedupe = ['log', 'info', 'dir', 'warn', 'error', 'assert', 'trace']; |
215 | | - |
216 | | - const methods = { |
217 | | - clear: () => log('clear'), |
218 | | - // TODO make the command 'push' and the level/type 'info' |
219 | | - log: (...args) => log('info', { args }), |
220 | | - info: (...args) => log('info', { args }), |
221 | | - dir: (...args) => log('info', { args: [args[0]], expanded: true }), |
222 | | - warn: (...args) => log('warn', { args, stack: stack('warn'), collapsed: true }), |
223 | | - error: (...args) => log('error', { args, stack: stack('error'), collapsed: true }), |
224 | | - assert: (condition, ...args) => { |
225 | | - if (condition) return; |
226 | | - log('error', { |
227 | | - args: ['Assertion failed:', ...args], |
228 | | - stack: stack('assert'), |
229 | | - collapsed: true |
230 | | - }); |
231 | | - }, |
232 | | - group: (...args) => log('group', { args, collapsed: false }), |
233 | | - groupCollapsed: (...args) => log('group', { args, collapsed: true }), |
234 | | - groupEnd: () => log('groupEnd'), |
235 | | - table: (...args) => { |
236 | | - const data = args[0]; |
237 | | - if (data && typeof data === 'object') { |
238 | | - log('table', { data, columns: args[1] }); |
239 | | - } else { |
240 | | - log('info', { args }); |
241 | | - } |
242 | | - }, |
243 | | - time: (label = 'default') => timers.set(label, performance.now()), |
244 | | - timeLog: (label = 'default') => { |
245 | | - const now = performance.now(); |
246 | | - if (timers.has(label)) { |
247 | | - log('info', { args: [`${label}: ${now - timers.get(label)}ms`] }); |
248 | | - } else { |
249 | | - log('warn', { args: [`Timer '${label}' does not exist`] }); |
250 | | - } |
251 | | - }, |
252 | | - timeEnd: (label = 'default') => { |
253 | | - const now = performance.now(); |
254 | | - if (timers.has(label)) { |
255 | | - log('info', { args: [`${label}: ${now - timers.get(label)}ms`] }); |
256 | | - } else { |
257 | | - log('warn', { args: [`Timer '${label}' does not exist`] }); |
258 | | - } |
259 | | - timers.delete(label); |
260 | | - }, |
261 | | - count: (label = 'default') => { |
262 | | - counters.set(label, (counters.get(label) || 0) + 1); |
263 | | - log('info', { args: [`${label}: ${counters.get(label)}`] }); |
264 | | - }, |
265 | | - countReset: (label = 'default') => { |
266 | | - if (counters.has(label)) { |
267 | | - counters.set(label, 0); |
268 | | - } else { |
269 | | - log('warn', { args: [`Count for '${label}' does not exist`] }); |
270 | | - } |
271 | | - }, |
272 | | - trace: (...args) => { |
273 | | - log('info', { |
274 | | - args: args.length === 0 ? ['console.trace'] : args, |
275 | | - stack: stack('trace'), |
276 | | - collapsed: false |
277 | | - }); |
278 | | - } |
279 | | - }; |
280 | | - |
281 | | - let previous = ''; |
282 | | - |
283 | | - for (const method in methods) { |
284 | | - const original = console[method]; |
285 | | - |
286 | | - console[method] = (...args) => { |
287 | | - const stack = new Error().stack; |
288 | | - |
289 | | - if ( |
290 | | - previous === (previous = stringify({ method, args, stack })) && |
291 | | - can_dedupe.includes(method) && |
292 | | - args.every((arg) => !arg || typeof arg !== 'object') |
293 | | - ) { |
294 | | - send({ action: 'console', command: 'duplicate' }); |
295 | | - } else { |
296 | | - methods[method](...args); |
297 | | - } |
298 | | - |
299 | | - original(...args); |
300 | | - }; |
301 | | - } |
302 | 152 | })(); |
303 | 153 | </script> |
304 | 154 | </head> |
|
0 commit comments