playground: better console (#11719)

* remove unused code

* better console

* simplify

* simplify

* fix

* fix

* fix

* fix console.table

* more table tweaks

* improve table styles

* tweaks

* bump svelte-json-tree

* tweak group styles

* level -> command

* remove stack from assertions

* nicer style for duplicates

* styles

* tidy/simplify

* tweaks

* tweaks

* tweaks

* fixes

* better stack traces (albeit not sourcemapped yet)
pull/11735/head
Rich Harris 4 months ago committed by GitHub
parent 4f9096a5a8
commit d4718e0755
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -16,7 +16,7 @@ importers:
version: 2.27.1
'@sveltejs/eslint-config':
specifier: ^7.0.1
version: 7.0.1(@stylistic/eslint-plugin-js@1.8.0)(eslint-config-prettier@9.1.0)(eslint-plugin-svelte@2.38.0)(eslint-plugin-unicorn@52.0.0)(eslint@9.0.0)(typescript-eslint@7.6.0)(typescript@5.3.3)
version: 7.0.1(@stylistic/eslint-plugin-js@2.1.0)(eslint-config-prettier@9.1.0)(eslint-plugin-svelte@2.39.0)(eslint-plugin-unicorn@53.0.0)(eslint@9.0.0)(typescript-eslint@7.6.0)(typescript@5.3.3)
'@svitejs/changesets-changelog-github-compact':
specifier: ^1.1.0
version: 1.1.0
@ -131,7 +131,7 @@ importers:
version: 0.19.11
knip:
specifier: ^4.2.1
version: 4.2.1(@types/node@20.12.7)(typescript@5.4.5)
version: 4.2.1(@types/node@20.12.12)(typescript@5.4.5)
rollup:
specifier: ^4.9.5
version: 4.9.5
@ -221,7 +221,7 @@ importers:
version: 0.0.15(@codemirror/autocomplete@6.12.0)(@codemirror/commands@6.3.3)(@codemirror/language@6.10.1)(@codemirror/lint@6.5.0)(@codemirror/search@6.5.6)(@codemirror/state@6.4.0)(@codemirror/view@6.24.0)
'@replit/codemirror-lang-svelte':
specifier: ^6.0.0
version: 6.0.0(@codemirror/autocomplete@6.12.0)(@codemirror/lang-css@6.2.1)(@codemirror/lang-html@6.4.9)(@codemirror/lang-javascript@6.2.1)(@codemirror/language@6.10.1)(@codemirror/state@6.4.0)(@codemirror/view@6.24.0)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0)(@lezer/javascript@1.4.15)(@lezer/lr@1.4.0)
version: 6.0.0(@codemirror/autocomplete@6.12.0)(@codemirror/lang-css@6.2.1)(@codemirror/lang-html@6.4.9)(@codemirror/lang-javascript@6.2.1)(@codemirror/language@6.10.1)(@codemirror/state@6.4.0)(@codemirror/view@6.24.0)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0)(@lezer/javascript@1.4.16)(@lezer/lr@1.4.0)
'@rich_harris/svelte-split-pane':
specifier: ^1.1.3
version: 1.1.3(svelte@packages+svelte)
@ -244,7 +244,7 @@ importers:
specifier: ^2.0.2
version: 2.0.2
svelte-json-tree:
specifier: ^2.1.0
specifier: ^2.2.0
version: 2.2.0(svelte@packages+svelte)
zimmerframe:
specifier: ^1.1.1
@ -312,7 +312,7 @@ importers:
version: 2.39.3
'@sveltejs/repl':
specifier: 0.6.0
version: 0.6.0(@codemirror/lang-html@6.4.9)(@codemirror/search@6.5.6)(@lezer/common@1.2.1)(@lezer/javascript@1.4.15)(@lezer/lr@1.4.0)(@sveltejs/kit@2.4.3)(svelte@4.2.9)
version: 0.6.0(@codemirror/lang-html@6.4.9)(@codemirror/search@6.5.6)(@lezer/common@1.2.1)(@lezer/javascript@1.4.16)(@lezer/lr@1.4.0)(@sveltejs/kit@2.4.3)(svelte@4.2.9)
cookie:
specifier: ^0.6.0
version: 0.6.0
@ -807,11 +807,11 @@ packages:
dependencies:
'@codemirror/autocomplete': 6.16.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.2.1)
'@codemirror/language': 6.10.1
'@codemirror/lint': 6.7.0
'@codemirror/lint': 6.7.1
'@codemirror/state': 6.4.1
'@codemirror/view': 6.26.3
'@lezer/common': 1.2.1
'@lezer/javascript': 1.4.15
'@lezer/javascript': 1.4.16
dev: false
/@codemirror/lang-json@6.0.1:
@ -852,8 +852,8 @@ packages:
crelt: 1.0.6
dev: false
/@codemirror/lint@6.7.0:
resolution: {integrity: sha512-LTLOL2nT41ADNSCCCCw8Q/UmdAFzB23OUYSjsHTdsVaH0XEo+orhuqbDNWzrzodm14w6FOxqxpmy4LF8Lixqjw==}
/@codemirror/lint@6.7.1:
resolution: {integrity: sha512-rELba6QJD20/bNXWP/cKTGLrwVEcpa2ViwULCV03ONcY1Je85++7sczVRUlnE4TJMjatx3IJTz6HX4NXi+moXw==}
dependencies:
'@codemirror/state': 6.4.1
'@codemirror/view': 6.26.3
@ -1124,15 +1124,15 @@ packages:
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
dev: true
/@eslint/eslintrc@2.1.4:
resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
/@eslint/eslintrc@3.0.2:
resolution: {integrity: sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
dependencies:
ajv: 6.12.6
debug: 4.3.4(supports-color@5.5.0)
espree: 9.6.1
globals: 13.24.0
ignore: 5.3.1
espree: 10.0.1
globals: 14.0.0
ignore: 5.3.0
import-fresh: 3.3.0
js-yaml: 4.1.0
minimatch: 3.1.2
@ -1141,15 +1141,15 @@ packages:
- supports-color
dev: true
/@eslint/eslintrc@3.0.2:
resolution: {integrity: sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==}
/@eslint/eslintrc@3.1.0:
resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
dependencies:
ajv: 6.12.6
debug: 4.3.4(supports-color@5.5.0)
espree: 10.0.1
globals: 14.0.0
ignore: 5.3.0
ignore: 5.3.1
import-fresh: 3.3.0
js-yaml: 4.1.0
minimatch: 3.1.2
@ -1826,8 +1826,8 @@ packages:
'@lezer/lr': 1.4.0
dev: false
/@lezer/javascript@1.4.15:
resolution: {integrity: sha512-B082ZdjI0vo2AgLqD834GlRTE9gwRX8NzHzKq5uDwEnQ9Dq+A/CEhd3nf68tiNA2f9O+8jS1NeSTUYT9IAqcTw==}
/@lezer/javascript@1.4.16:
resolution: {integrity: sha512-84UXR3N7s11MPQHWgMnjb9571fr19MmXnr5zTv2XX0gHXXUvW3uPJ8GCjKrfTXmSdfktjRK0ayKklw+A13rk4g==}
dependencies:
'@lezer/common': 1.2.1
'@lezer/highlight': 1.2.0
@ -2150,7 +2150,7 @@ packages:
/@polka/url@1.0.0-next.24:
resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==}
/@replit/codemirror-lang-svelte@6.0.0(@codemirror/autocomplete@6.12.0)(@codemirror/lang-css@6.2.1)(@codemirror/lang-html@6.4.9)(@codemirror/lang-javascript@6.2.1)(@codemirror/language@6.10.1)(@codemirror/state@6.4.0)(@codemirror/view@6.24.0)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0)(@lezer/javascript@1.4.15)(@lezer/lr@1.4.0):
/@replit/codemirror-lang-svelte@6.0.0(@codemirror/autocomplete@6.12.0)(@codemirror/lang-css@6.2.1)(@codemirror/lang-html@6.4.9)(@codemirror/lang-javascript@6.2.1)(@codemirror/language@6.10.1)(@codemirror/state@6.4.0)(@codemirror/view@6.24.0)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0)(@lezer/javascript@1.4.16)(@lezer/lr@1.4.0):
resolution: {integrity: sha512-U2OqqgMM6jKelL0GNWbAmqlu1S078zZNoBqlJBW+retTc5M4Mha6/Y2cf4SVg6ddgloJvmcSpt4hHrVoM4ePRA==}
peerDependencies:
'@codemirror/autocomplete': ^6.0.0
@ -2174,7 +2174,7 @@ packages:
'@codemirror/view': 6.24.0
'@lezer/common': 1.2.1
'@lezer/highlight': 1.2.0
'@lezer/javascript': 1.4.15
'@lezer/javascript': 1.4.16
'@lezer/lr': 1.4.0
dev: false
@ -2540,18 +2540,17 @@ packages:
p-map: 4.0.0
dev: true
/@stylistic/eslint-plugin-js@1.8.0(eslint@9.0.0):
resolution: {integrity: sha512-jdvnzt+pZPg8TfclZlTZPiUbbima93ylvQ+wNgHLNmup3obY6heQvgewSu9i2CfS61BnRByv+F9fxQLPoNeHag==}
engines: {node: ^16.0.0 || >=18.0.0}
/@stylistic/eslint-plugin-js@2.1.0(eslint@9.0.0):
resolution: {integrity: sha512-gdXUjGNSsnY6nPyqxu6lmDTtVrwCOjun4x8PUn0x04d5ucLI74N3MT1Q0UhdcOR9No3bo5PGDyBgXK+KmD787A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: '>=8.40.0'
dependencies:
'@types/eslint': 8.56.10
acorn: 8.11.3
escape-string-regexp: 4.0.0
eslint: 9.0.0
eslint-visitor-keys: 3.4.3
espree: 9.6.1
eslint-visitor-keys: 4.0.0
espree: 10.0.1
dev: true
/@supabase/functions-js@2.1.5:
@ -2645,7 +2644,7 @@ packages:
- supports-color
dev: true
/@sveltejs/eslint-config@7.0.1(@stylistic/eslint-plugin-js@1.8.0)(eslint-config-prettier@9.1.0)(eslint-plugin-svelte@2.38.0)(eslint-plugin-unicorn@52.0.0)(eslint@9.0.0)(typescript-eslint@7.6.0)(typescript@5.3.3):
/@sveltejs/eslint-config@7.0.1(@stylistic/eslint-plugin-js@2.1.0)(eslint-config-prettier@9.1.0)(eslint-plugin-svelte@2.39.0)(eslint-plugin-unicorn@53.0.0)(eslint@9.0.0)(typescript-eslint@7.6.0)(typescript@5.3.3):
resolution: {integrity: sha512-0c65gMzIRkfSNxVtUmMB/0I0A+ypyIS7aJhXXU7dEdoOEmdN5K+GpGB4ybYBmqODJdZlNRmwNFaKxzzUGBkXQA==}
peerDependencies:
'@stylistic/eslint-plugin-js': '>= 1'
@ -2656,11 +2655,11 @@ packages:
typescript: '>= 5'
typescript-eslint: '>= 7.5'
dependencies:
'@stylistic/eslint-plugin-js': 1.8.0(eslint@9.0.0)
'@stylistic/eslint-plugin-js': 2.1.0(eslint@9.0.0)
eslint: 9.0.0
eslint-config-prettier: 9.1.0(eslint@9.0.0)
eslint-plugin-svelte: 2.38.0(eslint@9.0.0)(svelte@packages+svelte)
eslint-plugin-unicorn: 52.0.0(eslint@9.0.0)
eslint-plugin-svelte: 2.39.0(eslint@9.0.0)(svelte@packages+svelte)
eslint-plugin-unicorn: 53.0.0(eslint@9.0.0)
globals: 15.0.0
typescript: 5.3.3
typescript-eslint: 7.6.0(eslint@9.0.0)(typescript@5.3.3)
@ -2719,7 +2718,7 @@ packages:
vite: 5.0.13(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0)
dev: true
/@sveltejs/repl@0.6.0(@codemirror/lang-html@6.4.9)(@codemirror/search@6.5.6)(@lezer/common@1.2.1)(@lezer/javascript@1.4.15)(@lezer/lr@1.4.0)(@sveltejs/kit@2.4.3)(svelte@4.2.9):
/@sveltejs/repl@0.6.0(@codemirror/lang-html@6.4.9)(@codemirror/search@6.5.6)(@lezer/common@1.2.1)(@lezer/javascript@1.4.16)(@lezer/lr@1.4.0)(@sveltejs/kit@2.4.3)(svelte@4.2.9):
resolution: {integrity: sha512-NADKN0NZhLlSatTSh5CCsdzgf2KHJFRef/8krA/TVWAWos5kSwmZ5fF0UImuqs61Pu/SiMXksaWNTGTiOtr4fQ==}
peerDependencies:
svelte: ^3.54.0 || ^4.0.0-next.0 || ^4.0.0
@ -2737,7 +2736,7 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.15
'@lezer/highlight': 1.2.0
'@neocodemirror/svelte': 0.0.15(@codemirror/autocomplete@6.12.0)(@codemirror/commands@6.3.3)(@codemirror/language@6.10.1)(@codemirror/lint@6.5.0)(@codemirror/search@6.5.6)(@codemirror/state@6.4.0)(@codemirror/view@6.24.0)
'@replit/codemirror-lang-svelte': 6.0.0(@codemirror/autocomplete@6.12.0)(@codemirror/lang-css@6.2.1)(@codemirror/lang-html@6.4.9)(@codemirror/lang-javascript@6.2.1)(@codemirror/language@6.10.1)(@codemirror/state@6.4.0)(@codemirror/view@6.24.0)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0)(@lezer/javascript@1.4.15)(@lezer/lr@1.4.0)
'@replit/codemirror-lang-svelte': 6.0.0(@codemirror/autocomplete@6.12.0)(@codemirror/lang-css@6.2.1)(@codemirror/lang-html@6.4.9)(@codemirror/lang-javascript@6.2.1)(@codemirror/language@6.10.1)(@codemirror/state@6.4.0)(@codemirror/view@6.24.0)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0)(@lezer/javascript@1.4.16)(@lezer/lr@1.4.0)
'@replit/codemirror-vim': 6.1.0(@codemirror/commands@6.3.3)(@codemirror/language@6.10.1)(@codemirror/search@6.5.6)(@codemirror/state@6.4.0)(@codemirror/view@6.24.0)
'@rich_harris/svelte-split-pane': 1.1.2(svelte@4.2.9)
'@rollup/browser': 3.29.4
@ -2932,8 +2931,8 @@ packages:
dependencies:
undici-types: 5.26.5
/@types/node@20.12.7:
resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==}
/@types/node@20.12.12:
resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==}
dependencies:
undici-types: 5.26.5
dev: true
@ -3568,10 +3567,10 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
dependencies:
caniuse-lite: 1.0.30001614
electron-to-chromium: 1.4.751
caniuse-lite: 1.0.30001621
electron-to-chromium: 1.4.777
node-releases: 2.0.14
update-browserslist-db: 1.0.13(browserslist@4.23.0)
update-browserslist-db: 1.0.16(browserslist@4.23.0)
dev: true
/buffer-crc32@0.2.13:
@ -3657,8 +3656,8 @@ packages:
resolution: {integrity: sha512-HMFNotUmLXn71BQxg8cijvqxnIAofforZOwGsxyXJ0qugTdspUF4sPSJ2vhgprHCB996tIDzEq1ubumPDV8ULA==}
dev: true
/caniuse-lite@1.0.30001614:
resolution: {integrity: sha512-jmZQ1VpmlRwHgdP1/uiKzgiAuGOfLEJsYFP4+GBou/QQ4U6IOJCB4NP1c+1p9RGLpwObcT94jA5/uO+F1vBbog==}
/caniuse-lite@1.0.30001621:
resolution: {integrity: sha512-+NLXZiviFFKX0fk8Piwv3PfLPGtRqJeq2TiNoUff/qB5KJgwecJTvCXDpmlyP/eCI/GUEmp/h/y5j0yckiiZrA==}
dev: true
/chai@4.4.1:
@ -3903,8 +3902,8 @@ packages:
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
engines: {node: '>= 0.6'}
/core-js-compat@3.37.0:
resolution: {integrity: sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==}
/core-js-compat@3.37.1:
resolution: {integrity: sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==}
dependencies:
browserslist: 4.23.0
dev: true
@ -4255,8 +4254,8 @@ packages:
resolution: {integrity: sha512-q4lkcbQrUdlzWCUOxk6fwEza6bNCfV12oi4AJph5UibguD1aTfL4uD0nuzFv9hbPANXQMuUS0MxPSHQ1gqq5dg==}
dev: true
/electron-to-chromium@1.4.751:
resolution: {integrity: sha512-2DEPi++qa89SMGRhufWTiLmzqyuGmNF3SK4+PQetW1JKiZdEpF4XQonJXJCzyuYSA6mauiMhbyVhqYAP45Hvfw==}
/electron-to-chromium@1.4.777:
resolution: {integrity: sha512-n02NCwLJ3wexLfK/yQeqfywCblZqLcXphzmid5e8yVPdtEcida7li0A5WQKghHNG0FeOMCzeFOzEbtAh5riXFw==}
dev: true
/emoji-regex@10.3.0:
@ -4418,6 +4417,11 @@ packages:
engines: {node: '>=6'}
dev: true
/escalade@3.1.2:
resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
engines: {node: '>=6'}
dev: true
/escape-html@1.0.3:
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
dev: true
@ -4439,7 +4443,7 @@ packages:
eslint: '>=6.0.0'
dependencies:
eslint: 9.0.0
semver: 7.6.0
semver: 7.6.2
dev: true
/eslint-config-prettier@9.1.0(eslint@9.0.0):
@ -4455,8 +4459,8 @@ packages:
resolution: {integrity: sha512-BVO83tRo090d6a04cl45Gb761SD79cOT6wKxxWrpsH7Rv8I0SJvc79ijE11vvyxxCMiGUVq/w4NqqPJAHyYfSQ==}
dev: true
/eslint-plugin-svelte@2.38.0(eslint@9.0.0)(svelte@packages+svelte):
resolution: {integrity: sha512-IwwxhHzitx3dr0/xo0z4jjDlb2AAHBPKt+juMyKKGTLlKi1rZfA4qixMwnveU20/JTHyipM6keX4Vr7LZFYc9g==}
/eslint-plugin-svelte@2.39.0(eslint@9.0.0)(svelte@packages+svelte):
resolution: {integrity: sha512-FXktBLXsrxbA+6ZvJK2z/sQOrUKyzSg3fNWK5h0reSCjr2fjAsc9ai/s/JvSl4Hgvz3nYVtTIMwarZH5RcB7BA==}
engines: {node: ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0-0 || ^9.0.0-0
@ -4471,31 +4475,31 @@ packages:
eslint: 9.0.0
eslint-compat-utils: 0.5.0(eslint@9.0.0)
esutils: 2.0.3
known-css-properties: 0.30.0
known-css-properties: 0.31.0
postcss: 8.4.38
postcss-load-config: 3.1.4(postcss@8.4.38)
postcss-safe-parser: 6.0.0(postcss@8.4.38)
postcss-selector-parser: 6.0.16
semver: 7.6.0
postcss-selector-parser: 6.1.0
semver: 7.6.2
svelte: link:packages/svelte
svelte-eslint-parser: 0.35.0(svelte@packages+svelte)
svelte-eslint-parser: 0.36.0(svelte@packages+svelte)
transitivePeerDependencies:
- supports-color
- ts-node
dev: true
/eslint-plugin-unicorn@52.0.0(eslint@9.0.0):
resolution: {integrity: sha512-1Yzm7/m+0R4djH0tjDjfVei/ju2w3AzUGjG6q8JnuNIL5xIwsflyCooW5sfBvQp2pMYQFSWWCFONsjCax1EHng==}
engines: {node: '>=16'}
/eslint-plugin-unicorn@53.0.0(eslint@9.0.0):
resolution: {integrity: sha512-kuTcNo9IwwUCfyHGwQFOK/HjJAYzbODHN3wP0PgqbW+jbXqpNWxNVpVhj2tO9SixBwuAdmal8rVcWKBxwFnGuw==}
engines: {node: '>=18.18'}
peerDependencies:
eslint: '>=8.56.0'
dependencies:
'@babel/helper-validator-identifier': 7.24.5
'@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0)
'@eslint/eslintrc': 2.1.4
'@eslint/eslintrc': 3.1.0
ci-info: 4.0.0
clean-regexp: 1.0.0
core-js-compat: 3.37.0
core-js-compat: 3.37.1
eslint: 9.0.0
esquery: 1.5.0
indent-string: 4.0.0
@ -4505,7 +4509,7 @@ packages:
read-pkg-up: 7.0.1
regexp-tree: 0.1.27
regjsparser: 0.10.0
semver: 7.6.0
semver: 7.6.2
strip-indent: 3.0.0
transitivePeerDependencies:
- supports-color
@ -5088,13 +5092,6 @@ packages:
process: 0.11.10
dev: true
/globals@13.24.0:
resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
engines: {node: '>=8'}
dependencies:
type-fest: 0.20.2
dev: true
/globals@14.0.0:
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
engines: {node: '>=18'}
@ -5822,7 +5819,7 @@ packages:
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
engines: {node: '>=6'}
/knip@4.2.1(@types/node@20.12.7)(typescript@5.4.5):
/knip@4.2.1(@types/node@20.12.12)(typescript@5.4.5):
resolution: {integrity: sha512-KG++YCus11YyQQeiBxhXxv6NCJzol4AYER9q1kwZGFw+gwDzG/0Q6MN87McYFN74nGRX4O2xM5CA3TTPcbpn5A==}
engines: {node: '>=18.6.0'}
hasBin: true
@ -5838,7 +5835,7 @@ packages:
'@pnpm/logger': 5.0.0
'@pnpm/workspace.pkgs-graph': 2.0.13(@pnpm/logger@5.0.0)
'@snyk/github-codeowners': 1.1.0
'@types/node': 20.12.7
'@types/node': 20.12.12
'@types/picomatch': 2.3.3
easy-table: 1.2.0
fast-glob: 3.3.2
@ -5860,8 +5857,8 @@ packages:
- domexception
dev: true
/known-css-properties@0.30.0:
resolution: {integrity: sha512-VSWXYUnsPu9+WYKkfmJyLKtIvaRJi1kXUqVmBACORXZQxT5oZDsoZ2vQP+bQFDnWtpI/4eq3MLoRMjI2fnLzTQ==}
/known-css-properties@0.31.0:
resolution: {integrity: sha512-sBPIUGTNF0czz0mwGGUoKKJC8Q7On1GPbCSFPfyEsfHb2DyBG0Y4QtV+EVWpINSaiGKZblDNuF5AezxSgOhesQ==}
dev: true
/levn@0.4.1:
@ -6880,6 +6877,10 @@ packages:
/picocolors@1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
/picocolors@1.0.1:
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
dev: true
/picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
@ -6982,8 +6983,8 @@ packages:
postcss: 8.4.38
dev: true
/postcss-selector-parser@6.0.16:
resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==}
/postcss-selector-parser@6.1.0:
resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==}
engines: {node: '>=4'}
dependencies:
cssesc: 3.0.0
@ -7007,7 +7008,7 @@ packages:
engines: {node: ^10 || ^12 || >=14}
dependencies:
nanoid: 3.3.7
picocolors: 1.0.0
picocolors: 1.0.1
source-map-js: 1.2.0
dev: true
@ -7510,6 +7511,12 @@ packages:
lru-cache: 6.0.0
dev: true
/semver@7.6.2:
resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==}
engines: {node: '>=10'}
hasBin: true
dev: true
/send@0.18.0:
resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
engines: {node: '>= 0.8.0'}
@ -8065,11 +8072,11 @@ packages:
- sugarss
dev: true
/svelte-eslint-parser@0.35.0(svelte@packages+svelte):
resolution: {integrity: sha512-CtbPseajW0gjwEvHiuzYJkPDjAcHz2FaHt540j6RVYrZgnE6xWkzUBodQ4I3nV+G5AS0Svt8K6aIA/CIU9xT2Q==}
/svelte-eslint-parser@0.36.0(svelte@packages+svelte):
resolution: {integrity: sha512-/6YmUSr0FAVxW8dXNdIMydBnddPMHzaHirAZ7RrT21XYdgGGZMh0LQG6CZsvAFS4r2Y4ItUuCQc8TQ3urB30mQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
svelte: ^3.37.0 || ^4.0.0 || ^5.0.0-next.112
svelte: ^3.37.0 || ^4.0.0 || ^5.0.0-next.115
peerDependenciesMeta:
svelte:
optional: true
@ -8482,11 +8489,6 @@ packages:
engines: {node: '>=10'}
dev: true
/type-fest@0.20.2:
resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
engines: {node: '>=10'}
dev: true
/type-fest@0.6.0:
resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==}
engines: {node: '>=8'}
@ -8649,15 +8651,15 @@ packages:
picocolors: 1.0.0
dev: true
/update-browserslist-db@1.0.13(browserslist@4.23.0):
resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
/update-browserslist-db@1.0.16(browserslist@4.23.0):
resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
dependencies:
browserslist: 4.23.0
escalade: 3.1.1
picocolors: 1.0.0
escalade: 3.1.2
picocolors: 1.0.1
dev: true
/uri-js@4.4.1:

@ -53,7 +53,7 @@
"esm-env": "^1.0.0",
"marked": "^7.0.2",
"resolve.exports": "^2.0.2",
"svelte-json-tree": "^2.1.0",
"svelte-json-tree": "^2.2.0",
"zimmerframe": "^1.1.1"
}
}

@ -1,27 +1,35 @@
let uid = 1;
const noop = () => {};
export default class ReplProxy {
/** @type {HTMLIFrameElement} */
iframe;
/** @type {import("./proxy").Handlers} */
handlers = {
on_fetch_progress: noop,
on_console: noop,
on_error: noop,
on_console_group: noop,
on_console_group_collapsed: noop,
on_console_group_end: noop,
on_unhandled_rejection: noop
};
handlers;
/** @type {Map<number, { resolve: (value: any) => void, reject: (value: any) => void }>} */
pending_cmds = new Map();
/** @param {MessageEvent<any>} e */
handle_event = (e) => this.handle_repl_message(e);
/** @param {MessageEvent<any>} event */
handle_event = (event) => {
if (event.source !== this.iframe.contentWindow) return;
const { action, args } = event.data;
switch (action) {
case 'cmd_error':
case 'cmd_ok':
return this.handle_command_message(event.data);
case 'fetch_progress':
return this.handlers.on_fetch_progress(args.remaining);
case 'error':
return this.handlers.on_error(event.data);
case 'unhandledrejection':
return this.handlers.on_unhandled_rejection(event.data);
case 'console':
return this.handlers.on_console(event.data);
}
};
/**
* @param {HTMLIFrameElement} iframe
@ -77,35 +85,6 @@ export default class ReplProxy {
}
}
/**
* @param {MessageEvent<any>} event
*/
handle_repl_message(event) {
if (event.source !== this.iframe.contentWindow) return;
const { action, args } = event.data;
switch (action) {
case 'cmd_error':
case 'cmd_ok':
return this.handle_command_message(event.data);
case 'fetch_progress':
return this.handlers.on_fetch_progress(args.remaining);
case 'error':
return this.handlers.on_error(event.data);
case 'unhandledrejection':
return this.handlers.on_unhandled_rejection(event.data);
case 'console':
return this.handlers.on_console(event.data);
case 'console_group':
return this.handlers.on_console_group(event.data);
case 'console_group_collapsed':
return this.handlers.on_console_group_collapsed(event.data);
case 'console_group_end':
return this.handlers.on_console_group_end(event.data);
}
}
/** @param {string} script */
eval(script) {
return this.iframe_command('eval', { script });

@ -55,32 +55,36 @@
pending_imports = progress;
},
on_error: (event) => {
push_logs({ level: 'error', args: [event.value] });
push_logs({ command: 'error', args: [event.value] });
},
on_unhandled_rejection: (event) => {
let error = event.value;
if (typeof error === 'string') error = { message: error };
error.message = 'Uncaught (in promise): ' + error.message;
push_logs({ level: 'error', args: [error] });
push_logs({ command: 'error', args: [error] });
},
on_console: (log) => {
if (log.level === 'clear') {
clear_logs();
push_logs(log);
} else if (log.duplicate) {
increment_duplicate_log();
} else {
push_logs(log);
switch (log.command) {
case 'clear':
clear_logs();
push_logs(log);
break;
case 'group':
group_logs(log);
break;
case 'groupEnd':
ungroup_logs();
break;
case 'duplicate':
increment_duplicate_log();
break;
default:
push_logs(log);
}
},
on_console_group: (action) => {
group_logs(action.label, false);
},
on_console_group_end: () => {
ungroup_logs();
},
on_console_group_collapsed: (action) => {
group_logs(action.label, true);
}
});
@ -202,17 +206,13 @@
logs = logs;
}
/**
* @param {string} label
* @param {boolean} collapsed
*/
function group_logs(label, collapsed) {
/** @type {import('./console/console').Log} */
const group_log = { level: 'group', label, collapsed, logs: [] };
current_log_group.push({ level: 'group', label, collapsed, logs: [] });
/** @param {import('./console/console').Log} log */
function group_logs(log) {
log.logs = [];
current_log_group.push(log);
// TODO: Investigate
log_group_stack.push(current_log_group);
current_log_group = group_log.logs ?? [];
current_log_group = log.logs;
logs = logs;
}
@ -284,7 +284,7 @@
</div>
<section slot="panel-body">
<Console {logs} {theme} on:clear={clear_logs} />
<Console {logs} />
</section>
</PaneWithPanel>

@ -3,12 +3,9 @@
/** @type {import('./console').Log[]} */
export let logs;
/** @type {'light' | 'dark'} */
export let theme;
</script>
<div class="container" class:dark={theme === 'dark'}>
<div class="container">
{#each logs as log}
<ConsoleLine {log} />
{/each}
@ -16,21 +13,34 @@
<style>
.container {
--error-fg: #da106e;
--error-bg: #fff0f0;
--error-border: rgb(242, 214, 219);
--warning-bg: rgb(254, 251, 218);
--warning-border: rgb(242, 232, 163);
--json-tree-string-color: var(--sk-code-string);
}
.dark {
--json-tree-property-color: #72a2d3;
--json-tree-string-color: #6cd1c7;
--json-tree-symbol-color: #6cd1c7;
--json-tree-boolean-color: #9681f7;
--json-tree-function-color: #e59b6f;
--json-tree-number-color: #9681f7;
--json-tree-label-color: #9ca0a5;
--json-tree-arrow-color: #e8eaed;
--json-tree-null-color: #81868a;
--json-tree-undefined-color: #81868a;
--json-tree-date-color: #9ca0a5;
--json-tree-operator-color: #e8eaed;
--json-tree-regex-color: #6cd1c7;
--json-tree-font-family: var(--sk-font-mono);
:global(.dark) & {
--error-fg: rgb(235, 78, 109);
--error-bg: rgb(71, 48, 54);
--error-border: rgb(109, 65, 76);
--warning-bg: rgb(64, 56, 34);
--warning-border: rgb(86, 86, 51);
--json-tree-property-color: #72a2d3;
--json-tree-string-color: #6cd1c7;
--json-tree-symbol-color: #6cd1c7;
--json-tree-boolean-color: #9681f7;
--json-tree-function-color: #e59b6f;
--json-tree-number-color: #9681f7;
--json-tree-label-color: #9ca0a5;
--json-tree-arrow-color: #e8eaed;
--json-tree-null-color: #81868a;
--json-tree-undefined-color: #81868a;
--json-tree-date-color: #9ca0a5;
--json-tree-operator-color: #e8eaed;
--json-tree-regex-color: #6cd1c7;
}
}
</style>

@ -4,137 +4,164 @@
/** @type {import('./console').Log} */
export let log;
export let level = 1;
export let depth = 1;
function toggle_group_collapse() {
log.collapsed = !log.collapsed;
}
</script>
{#if log.args && log.level === 'table'}
<ConsoleTable data={log.args[0]} columns={log.args[1]} />
{#if log.command === 'table'}
<ConsoleTable data={log.data} columns={log.columns} />
{/if}
<span class="log console-{log.level}" style="padding-left: {level * 15}px">
{#if log.count && log.count > 1}
<span class="count">{log.count}x</span>
{/if}
{#if log.level === 'trace' || log.level === 'assert' || log.level === 'group'}
<button on:click={toggle_group_collapse}>
<span class="arrow" class:expand={!log.collapsed}> ▶️ </span>
{#if log.level === 'group'}
<span class="title">{log.label}</span>
{/if}
</button>
{/if}
<div class="{log.command} line" style="--indent: {depth * 15}px">
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
role="button"
tabindex="0"
on:click={toggle_group_collapse}
class="log"
class:expandable={log.stack || log.command === 'group'}
>
{#if log.count && log.count > 1}
<span class="count">{log.count}</span>
{/if}
{#if log.stack || log.command === 'group'}
<span class="arrow" class:expand={!log.collapsed}>{'\u25B6'}</span>
{/if}
{#if log.command === 'clear'}
<span class="meta">Console was cleared</span>
{:else if log.command === 'unclonable'}
<span class="meta meta-error">Message could not be cloned. Open devtools to see it</span>
{:else if log.command === 'table'}
<JSONNode value={log.data} />
{:else}
{#each log.args ?? [] as arg}
<JSONNode value={arg} defaultExpandedLevel={log.expanded ? 1 : 0} />
{/each}
{/if}
</div>
{#if log.level === 'assert'}
<span class="assert">Assertion failed:</span>
{#if log.stack && !log.collapsed}
<div class="stack">
{#each log.stack as line}
<span>{line.label}</span>
<span class="location">{line.location}</span>
{/each}
</div>
{/if}
{#if log.level === 'clear'}
<span class="info">Console was cleared</span>
{:else if log.level === 'unclonable'}
<span class="info error">Message could not be cloned. Open devtools to see it</span>
{:else if log.level.startsWith('system')}
{#each log.args ?? [] as arg}
{arg}
{/each}
{:else if log.args && log.level === 'table'}
<JSONNode value={log.args[0]} />
{:else}
{#each log.args ?? [] as arg}
<JSONNode value={arg} />
{/each}
{/if}
{#each new Array(level - 1) as _, idx}
{#each new Array(depth - 1) as _, idx}
<div class="outline" style="left: {idx * 15 + 15}px"></div>
{/each}
</span>
</div>
{#if log.level === 'group' && !log.collapsed}
{#if log.command === 'group' && !log.collapsed}
{#each log.logs ?? [] as childLog}
<svelte:self log={childLog} level={level + 1} />
<svelte:self log={childLog} depth={depth + 1} />
{/each}
{/if}
{#if (log.level === 'trace' || log.level === 'assert') && !log.collapsed}
<div class="trace">
{#each log.stack?.split('\n').slice(2) ?? '' as stack}
<div>{stack.replace(/^\s*at\s+/, '')}</div>
{/each}
</div>
{/if}
<style>
.log {
border-bottom: 0.5px solid var(--sk-back-4);
padding: 5px 10px 0px;
display: flex;
.line {
--bg: var(--sk-back-1);
--border: var(--sk-back-3);
display: block;
position: relative;
font-size: 12px;
font-family: var(--sk-font-mono);
}
.log > :global(*) {
margin-right: 10px;
font-family: var(--sk-font-mono);
width: 100%;
text-align: left;
border-width: 1px;
border-style: solid none none none;
border-color: var(--border);
background: var(--bg);
}
.console-warn,
.console-system-warn {
background: hsla(50, 100%, 95%, 0.4);
border-color: #fff4c4;
.warn {
--bg: var(--warning-bg);
--border: var(--warning-border);
}
.console-error,
.console-assert {
background: #fff0f0;
border-color: #fed6d7;
.error {
--bg: var(--error-bg);
--border: var(--error-border);
}
.console-group,
.arrow {
cursor: pointer;
user-select: none;
}
.warn,
.error {
border-style: solid none;
.console-trace,
.console-assert {
border-bottom: none;
& + :global(&) {
border-top: none;
}
}
.console-assert + .trace {
background: #fff0f0;
border-color: #fed6d7;
.group {
font-weight: 700;
}
.trace {
border-bottom: 1px solid #eee;
.log {
padding: 5px 10px 5px var(--indent);
display: flex;
width: 100%;
font-size: 12px;
font-family: var(--sk-font-mono);
padding: 4px 0 2px;
align-items: center;
}
.trace > :global(div) {
margin-left: 15px;
.log.expandable {
cursor: pointer;
padding-left: calc(var(--indent) + 1em);
}
.count {
color: var(--sk-text-3, #999);
.stack {
display: grid;
grid-template-columns: minmax(0, auto) minmax(auto, 1fr);
grid-gap: 0 2rem;
font-size: 12px;
line-height: 1.2;
font-family: var(--sk-font-mono);
margin: 0 1rem 0.4rem calc(1em + var(--indent));
overflow: hidden;
.location {
position: relative;
background: var(--bg);
&::before {
content: '';
position: absolute;
width: 1rem;
height: 100%;
left: -1rem;
top: 0;
background: linear-gradient(to right, transparent, var(--bg));
}
}
}
.info {
.count {
position: relative;
display: flex;
justify-content: center;
align-items: center;
min-width: 1.5em;
height: 1.4em;
padding: 0.5em;
border-radius: 0.4rem;
background-color: var(--sk-text-3, #777);
color: var(--sk-back-1);
font-size: 1rem;
}
.meta {
color: var(--sk-text-2, #666);
font-family: var(--sk-font) !important;
font-size: 12px;
}
.error {
color: #da106e; /* todo make this a var */
.meta-error {
color: var(--error-fg);
}
.outline {
@ -146,27 +173,13 @@
.arrow {
position: absolute;
font-size: 0.6em;
font-size: 0.9rem;
transition: 150ms;
transform-origin: 50% 50%;
transform: translateY(1px) translateX(-50%);
transform: translateX(-1.2rem) translateY(-1px);
}
.arrow.expand {
transform: translateY(1px) translateX(-50%) rotateZ(90deg);
}
.title {
font-family: var(--sk-font-mono);
font-size: 13px;
font-weight: bold;
padding-left: 11px;
height: 19px;
}
.assert {
padding-left: 11px;
font-weight: bold;
color: #da106e;
transform: translateX(-1.2rem) translateY(0px) rotateZ(90deg);
}
</style>

@ -7,28 +7,54 @@
/** @type {any} */
export let columns;
const INDEX_KEY = '(index)';
const VALUE_KEY = 'Value';
$: keys = Object.keys(data);
$: columns_to_render = columns || get_columns_to_render(data, keys);
$: table = create_table(data, columns);
/**
* @param {any} data
* @param {string[]} keys
* @param {string[]} [custom_columns]
*/
function get_columns_to_render(data, keys) {
const columns = new Set([INDEX_KEY]);
for (const key of keys) {
function create_table(data, custom_columns) {
let has_non_object = false;
const columns = new Set();
if (custom_columns) {
custom_columns.forEach((column) => columns.add(column));
} else {
for (const key in data) {
const value = data[key];
if (typeof value === 'object') {
Object.keys(value).forEach((key) => columns.add(key));
} else {
has_non_object = true;
}
}
}
const is_array = Array.isArray(data);
const rows = Object.keys(data).map((key) => {
const value = data[key];
if (typeof value === 'object') {
Object.keys(value).forEach((key) => columns.add(key));
} else {
columns.add(VALUE_KEY);
const values = [];
for (const column of columns) {
values.push(typeof value === 'object' && column in value ? value[column] : '');
}
if (has_non_object) {
values.push(typeof value !== 'object' ? value : '');
}
return {
key: is_array ? parseInt(key) : key,
values
};
});
if (has_non_object) {
columns.add('Value');
}
return [...columns];
return { columns, rows };
}
</script>
@ -36,24 +62,33 @@
<table>
<thead>
<tr>
{#each columns_to_render as column}
<th>(index)</th>
{#each table.columns as column}
<th>{column}</th>
{/each}
</tr>
</thead>
<tbody>
{#each keys as key}
{#each table.rows as row}
<tr>
{#each columns_to_render as column}
{#if column === INDEX_KEY}
<td>{key}</td>
{:else if column === VALUE_KEY}
<td><JSONNode value={data[key]} /></td>
{:else if column in data[key]}
<td><JSONNode value={data[key][column]} /></td>
<td>
{#if typeof row.key === 'string'}
{row.key}
{:else}
<td></td>
<JSONNode value={row.key} />
{/if}
</td>
{#each row.values as value}
<td>
{#if typeof value === 'string'}
{value}
{:else}
<JSONNode {value} />
{/if}
</td>
{/each}
</tr>
{/each}
@ -63,32 +98,48 @@
<style>
.table {
--json-tree-font-size: 1.2rem;
--json-tree-font-family: var(--sk-font-mono);
margin: 8px;
overflow: auto;
max-height: 200px;
border: 1px solid var(--sk-back-4);
border-radius: 2px;
overscroll-behavior: none;
}
table {
font-size: 12px;
font-family: var(--sk-font-mono);
border-collapse: collapse;
line-height: 1;
border: 1px solid #aaa;
}
th {
background: #f3f3f3;
padding: 4px 8px;
border: 1px solid #aaa;
background: var(--sk-back-3);
padding: 0.5rem 1rem;
border: none;
position: sticky;
font-weight: normal;
font-size: 1.4rem;
top: 0;
}
td {
padding: 2px 8px;
font-family: var(--sk-font-mono);
font-size: 1.2rem;
padding: 0.5rem 1rem;
border-bottom: none;
}
tr {
background: var(--sk-back-1);
}
tr:nth-child(2n) {
background: #f2f7fd;
background: var(--sk-back-3);
}
th,
td {
border-right: 1px solid #aaa;
border-right: 1px solid var(--sk-back-3);
}
</style>

@ -1,19 +1,12 @@
export type Log = {
level:
| 'info'
| 'warn'
| 'error'
| 'table'
| 'group'
| 'trace'
| 'assert'
| 'clear'
| 'unclonable';
command: 'info' | 'warn' | 'error' | 'table' | 'group' | 'clear' | 'unclonable';
action?: 'console';
args?: any[];
collapsed?: boolean;
expanded?: boolean;
count?: number;
logs?: Log[];
stack?: string;
label?: string;
data?: any;
columns?: string[];
};

@ -1,10 +1,4 @@
export type Handlers = Record<
| 'on_fetch_progress'
| 'on_error'
| 'on_unhandled_rejection'
| 'on_console'
| 'on_console_group'
| 'on_console_group_collapsed'
| 'on_console_group_end',
'on_fetch_progress' | 'on_error' | 'on_unhandled_rejection' | 'on_console',
(data: any) => void
>;

@ -67,34 +67,25 @@
<script>
(function () {
function handle_message(ev) {
let { action, cmd_id } = ev.data;
const send_message = (payload) => parent.postMessage({ ...payload }, ev.origin);
const send_reply = (payload) => send_message({ ...payload, cmd_id });
const send_ok = () => send_reply({ action: 'cmd_ok' });
const send_error = (message, stack) =>
send_reply({ action: 'cmd_error', message, stack });
if (action === 'set_theme') {
const { theme } = ev.data.args;
document.body.classList.toggle('dark', theme === 'dark');
send_ok();
}
function send(payload, origin = '*') {
parent.postMessage(payload, origin);
}
window.addEventListener('message', ({ origin, data }) => {
let { action, cmd_id } = data;
const reply = (payload) => send({ ...payload, cmd_id }, origin);
try {
if (action === 'set_theme') {
document.body.classList.toggle('dark', data.args.theme === 'dark');
}
if (action === 'eval') {
try {
const { script } = ev.data.args;
(0, eval)(script);
send_ok();
} catch (e) {
send_error(e.message, e.stack);
if (action === 'eval') {
(0, eval)(data.args.script);
}
}
if (action === 'catch_clicks') {
try {
const top_origin = ev.origin;
if (action === 'catch_clicks') {
document.body.addEventListener('click', (event) => {
if (event.which !== 1) return;
if (event.metaKey || event.ctrlKey || event.shiftKey) return;
@ -114,7 +105,7 @@
event.preventDefault();
if (el.href.startsWith(top_origin)) {
if (el.href.startsWith(origin)) {
const url = new URL(el.href);
if (url.hash[0] === '#') {
window.location.hash = url.hash;
@ -124,183 +115,170 @@
window.open(el.href, '_blank');
});
send_ok();
} catch (e) {
send_error(e.message, e.stack);
}
}
}
window.addEventListener('message', handle_message, false);
reply({ action: 'cmd_ok' });
} catch ({ message, stack }) {
reply({ action: 'cmd_error', message, stack });
}
});
window.onerror = function (msg, url, lineNo, columnNo, error) {
parent.postMessage({ action: 'error', value: error }, '*');
send({ action: 'error', value: error });
};
window.addEventListener('unhandledrejection', (event) => {
parent.postMessage({ action: 'unhandledrejection', value: event.reason }, '*');
});
let previous = { level: null, args: null };
['clear', 'log', 'info', 'dir', 'warn', 'error', 'table'].forEach((level) => {
const original = console[level];
console[level] = (...args) => {
const stringifiedArgs = stringify(args);
if (previous.level === level && previous.args && previous.args === stringifiedArgs) {
parent.postMessage({ action: 'console', level, duplicate: true }, '*');
} else {
previous = { level, args: stringifiedArgs };
try {
parent.postMessage({ action: 'console', level, args }, '*');
} catch (err) {
parent.postMessage({ action: 'console', level: 'unclonable' }, '*');
}
}
original(...args);
};
});
[
{ method: 'group', action: 'console_group' },
{ method: 'groupEnd', action: 'console_group_end' },
{ method: 'groupCollapsed', action: 'console_group_collapsed' }
].forEach((group_action) => {
const original = console[group_action.method];
console[group_action.method] = (label) => {
parent.postMessage({ action: group_action.action, label }, '*');
original(label);
};
send({ action: 'unhandledrejection', value: event.reason });
});
// Intercept console methods
const timers = new Map();
const original_time = console.time;
const original_timelog = console.timeLog;
const original_timeend = console.timeEnd;
console.time = (label = 'default') => {
original_time(label);
timers.set(label, performance.now());
};
console.timeLog = (label = 'default') => {
original_timelog(label);
const now = performance.now();
if (timers.has(label)) {
parent.postMessage(
{
action: 'console',
level: 'system-log',
args: [`${label}: ${now - timers.get(label)}ms`]
},
'*'
);
} else {
parent.postMessage(
{
action: 'console',
level: 'system-warn',
args: [`Timer '${label}' does not exist`]
},
'*'
);
}
};
console.timeEnd = (label = 'default') => {
original_timeend(label);
const now = performance.now();
if (timers.has(label)) {
parent.postMessage(
{
action: 'console',
level: 'system-log',
args: [`${label}: ${now - timers.get(label)}ms`]
},
'*'
);
} else {
parent.postMessage(
{
action: 'console',
level: 'system-warn',
args: [`Timer '${label}' does not exist`]
},
'*'
);
}
timers.delete(label);
};
const original_assert = console.assert;
console.assert = (condition, ...args) => {
if (condition) {
const stack = new Error().stack;
parent.postMessage({ action: 'console', level: 'assert', args, stack }, '*');
}
original_assert(condition, ...args);
};
const counter = new Map();
const original_count = console.count;
const original_countreset = console.countReset;
console.count = (label = 'default') => {
counter.set(label, (counter.get(label) || 0) + 1);
parent.postMessage(
{ action: 'console', level: 'system-log', args: `${label}: ${counter.get(label)}` },
'*'
);
original_count(label);
};
const counters = new Map();
console.countReset = (label = 'default') => {
if (counter.has(label)) {
counter.set(label, 0);
} else {
parent.postMessage(
{
action: 'console',
level: 'system-warn',
args: `Count for '${label}' does not exist`
},
'*'
);
function log(command, opts) {
try {
send({ action: 'console', command, ...opts });
} catch {
send({ action: 'console', command: 'unclonable' });
}
original_countreset(label);
};
const original_trace = console.trace;
console.trace = (...args) => {
const stack = new Error().stack;
parent.postMessage({ action: 'console', level: 'trace', args, stack }, '*');
original_trace(...args);
};
}
function stringify(args) {
try {
return JSON.stringify(args, (key, value) => {
// if we don't do this, our Set/Map from svelte/reactivity would show up wrong in the console
if (value instanceof Map) {
return {
type: 'Map',
value
};
return { type: 'Map', value };
}
if (value instanceof Set) {
return {
type: 'Set',
value
};
return { type: 'Set', value };
}
return value;
});
} catch (error) {
return null;
}
}
/** @param {string} method */
function stack(method) {
return new Error().stack
.split('\n')
.filter((line) => {
if (/[(@]about:srcdoc/.test(line)) return false;
return true;
})
.slice(1)
.map((line) => {
line = line
.replace('console[method]', `console.${method}`)
.replace(/console\.<computed> \[as \w+\]/, `console.${method}`);
let match =
/^\s+at (.+) \((.+:\d+:\d+)\)/.exec(line) || /^(.+)@(.+:\d+:\d+)?/.exec(line);
if (match) {
return {
label: match[1],
location: match[2]
};
}
return null;
})
.filter((x) => x);
}
const can_dedupe = ['log', 'info', 'dir', 'warn', 'error', 'assert', 'trace'];
const methods = {
clear: () => log('clear'),
// TODO make the command 'push' and the level/type 'info'
log: (...args) => log('info', { args }),
info: (...args) => log('info', { args }),
dir: (...args) => log('info', { args: [args[0]], expanded: true }),
warn: (...args) => log('warn', { args, stack: stack('warn'), collapsed: true }),
error: (...args) => log('error', { args, stack: stack('error'), collapsed: true }),
assert: (condition, ...args) => {
if (condition) return;
log('error', {
args: ['Assertion failed:', ...args],
stack: stack('assert'),
collapsed: true
});
},
group: (...args) => log('group', { args, collapsed: false }),
groupCollapsed: (...args) => log('group', { args, collapsed: true }),
groupEnd: () => log('groupEnd'),
table: (...args) => {
const data = args[0];
if (data && typeof data === 'object') {
log('table', { data, columns: args[1] });
} else {
log('info', { args });
}
},
time: (label = 'default') => timers.set(label, performance.now()),
timeLog: (label = 'default') => {
const now = performance.now();
if (timers.has(label)) {
log('info', { args: [`${label}: ${now - timers.get(label)}ms`] });
} else {
log('warn', { args: [`Timer '${label}' does not exist`] });
}
},
timeEnd: (label = 'default') => {
const now = performance.now();
if (timers.has(label)) {
log('info', { args: [`${label}: ${now - timers.get(label)}ms`] });
} else {
log('warn', { args: [`Timer '${label}' does not exist`] });
}
timers.delete(label);
},
count: (label = 'default') => {
counters.set(label, (counters.get(label) || 0) + 1);
log('info', { args: [`${label}: ${counters.get(label)}`] });
},
countReset: (label = 'default') => {
if (counters.has(label)) {
counters.set(label, 0);
} else {
log('warn', { args: [`Count for '${label}' does not exist`] });
}
},
trace: (...args) => {
log('info', {
args: args.length === 0 ? 'console.trace' : args,
stack: stack('trace'),
collapsed: false
});
}
};
let previous = '';
for (const method in methods) {
const original = console[method];
console[method] = (...args) => {
const stack = new Error().stack;
if (
previous === (previous = stringify({ method, args, stack })) &&
can_dedupe.includes(method) &&
args.every((arg) => !arg || typeof arg !== 'object')
) {
send({ action: 'console', command: 'duplicate' });
} else {
methods[method](...args);
}
original(...args);
};
}
})();
</script>
</head>

Loading…
Cancel
Save