From eeb2b4c2eec67a434093664134c017d5d9fad39d Mon Sep 17 00:00:00 2001 From: Martin Chudoba Date: Wed, 7 Aug 2024 03:24:36 +0200 Subject: [PATCH] bar.js: initializes Tabs (#580) --- .github/workflows/coding-style.yml | 14 ++--- .github/workflows/static-analysis.yml | 4 +- .github/workflows/tests.yml | 8 +-- composer.json | 2 +- eslint.config.mjs | 26 ++++++-- package.json | 7 ++- readme.md | 35 +++++++---- src/Tracy/Bar/assets/bar.js | 70 +++++++++++----------- src/Tracy/BlueScreen/assets/bluescreen.js | 5 +- src/Tracy/Dumper/assets/dumper.js | 73 +++++++++++------------ src/Tracy/Logger/Logger.php | 2 +- src/Tracy/assets/table-sort.js | 13 ++-- src/Tracy/assets/tabs.js | 5 +- src/Tracy/assets/toggle.js | 11 ++-- 14 files changed, 148 insertions(+), 127 deletions(-) diff --git a/.github/workflows/coding-style.yml b/.github/workflows/coding-style.yml index a34ad7e8e..341f640d3 100644 --- a/.github/workflows/coding-style.yml +++ b/.github/workflows/coding-style.yml @@ -7,10 +7,10 @@ jobs: name: Nette Code Checker runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 with: - php-version: 8.0 + php-version: 8.1 coverage: none - run: composer create-project nette/code-checker temp/code-checker ^3 --no-progress @@ -21,10 +21,10 @@ jobs: name: Nette Coding Standard runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 with: - php-version: 8.0 + php-version: 8.1 coverage: none - run: composer create-project nette/coding-standard temp/coding-standard ^3 --no-progress @@ -35,6 +35,6 @@ jobs: name: Code Standard Checker (JS) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - run: npm install eslint - - run: npx eslint "src/**/*.js" + - uses: actions/checkout@v4 + - run: npm install + - run: npx eslint diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 25e44dd05..396244b28 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -7,10 +7,10 @@ jobs: name: PHPStan runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 with: - php-version: 8.0 + php-version: 8.1 coverage: none - run: composer install --no-progress --prefer-dist diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 16b7661aa..ce98e2155 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,14 +11,14 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - php: ['8.0', '8.1', '8.2', '8.3'] + php: ['8.1', '8.2', '8.3'] sapi: ['php', 'php-cgi'] fail-fast: false name: PHP ${{ matrix.php }}/${{ matrix.sapi }} tests on ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} @@ -38,10 +38,10 @@ jobs: name: Code Coverage runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 with: - php-version: 8.0 + php-version: 8.1 extensions: ds coverage: none diff --git a/composer.json b/composer.json index 09c813c44..af5ea101b 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": ">=8.0 <8.4", + "php": "8.1 - 8.3", "ext-session": "*", "ext-json": "*" }, diff --git a/eslint.config.mjs b/eslint.config.mjs index 1875e8c1f..b561b8f77 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,20 +1,36 @@ import globals from 'globals'; import pluginJs from '@eslint/js'; +import stylistic from '@stylistic/eslint-plugin'; export default [ + { + ignores: ['*/*', '!src/*'], + }, + pluginJs.configs.recommended, + + stylistic.configs.customize({ + indent: 'tab', + braceStyle: '1tbs', + arrowParens: true, + semi: true, + jsx: false, + }), + { languageOptions: { ecmaVersion: 'latest', globals: globals.browser, }, + plugins: { + '@stylistic': stylistic, + }, rules: { - indent: ['error', 'tab'], - quotes: ['error', 'single'], - semi: ['error', 'always'], + '@stylistic/no-multiple-empty-lines': ['error', { max: 2, maxEOF: 0 }], + '@stylistic/new-parens': ['error', 'never'], + '@stylistic/padded-blocks': 'off', + 'func-style': ['error', 'declaration', { allowArrowFunctions: true }], 'prefer-arrow-callback': ['error'], - 'arrow-parens': ['error'], - 'arrow-spacing': ['error'], 'no-var': ['error'], }, }, diff --git a/package.json b/package.json index 7ac905df2..57e2f01b8 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,8 @@ { "devDependencies": { - "@eslint/js": "^9.1.1", - "eslint": "^9.1.1", - "globals": "^15.1.0" + "@eslint/js": "^9.4.0", + "@stylistic/eslint-plugin": "^2.1.0", + "eslint": "^9.4.0", + "globals": "^15.3.0" } } diff --git a/readme.md b/readme.md index 6148b11fa..72c39f34e 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,4 @@ -[Tracy](https://tracy.nette.org) - PHP debugger -============================================== +[![Tracy](https://github.com/nette/tracy/assets/194960/f36323d8-486c-4a5e-b3f1-f97cd7c082ca)](https://tracy.nette.org) [![Downloads this Month](https://img.shields.io/packagist/dm/tracy/tracy.svg)](https://packagist.org/packages/tracy/tracy) [![Tests](https://github.com/nette/tracy/workflows/Tests/badge.svg?branch=master)](https://github.com/nette/tracy/actions) @@ -7,17 +6,16 @@ [![Latest Stable Version](https://poser.pugx.org/tracy/tracy/v/stable)](https://github.com/nette/tracy/releases) [![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/nette/tracy/blob/master/license.md) +  Introduction ------------ Tracy library is a useful helper for everyday PHP programmers. It helps you to: -- quickly detect and correct errors -- log errors -- dump variables -- measure execution time of scripts/queries -- see memory consumption +✅ designed to facilitate debugging PHP code
+✅ hints and corrects you just like a good friend watching your back
+✅ damn cool visualization of errors PHP is a perfect language for making hardly detectable errors because it gives great flexibility to programmers. Tracy\Debugger is more valuable because of that. It is an ultimate tool among the diagnostic ones. @@ -26,6 +24,7 @@ If you are meeting Tracy for the first time, believe me, your life starts to be Documentation can be found on the [website](https://tracy.nette.org). +  [Support Tracy](https://github.com/sponsors/dg) ----------------------------------------------- @@ -36,6 +35,7 @@ Do you like Tracy? Are you looking forward to the new features? Thank you! +  Installation and Requirements ----------------------------- @@ -48,12 +48,10 @@ composer require tracy/tracy Alternatively, you can download the whole package or [tracy.phar](https://github.com/nette/tracy/releases) file. -| Tracy | compatible with PHP | compatible with browsers -|-----------|---------------|---------- -| Tracy 3.0 | PHP 8.0 – 8.3 | Chrome 112+, Firefox 117+, Safari 16.5+ -| Tracy 2.10| PHP 8.0 – 8.3 | Chrome 64+, Firefox 69+, Safari 15.4+ -| Tracy 2.9 | PHP 7.2 – 8.2 | Chrome 64+, Firefox 69+, Safari 13.1+ +Tracy is compatible with PHP 8.1 to 8.3. + +  Usage ----- @@ -71,6 +69,7 @@ Debugger::enable(); The first thing you'll notice on the page is the Tracy Bar in the bottom right corner. If you don't see it, it may mean that Tracy is running in production mode. This is because Tracy is only visible on localhost for security reasons. To test if it works, you can temporarily put it into development mode using the `Debugger::enable(Debugger::Development)` parameter. +  Tracy Bar --------- @@ -87,6 +86,7 @@ If you do not want to show Tracy Bar, set: Debugger::$showBar = false; ``` +  Visualization of Errors and Exceptions -------------------------------------- @@ -135,6 +135,7 @@ Debugger::$strictMode = E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED; // all error Note: Tracy when activated changes the error reporting level to E_ALL. If you want to change this, do so after calling `enable()`. +  Development vs Production Mode ------------------------------ @@ -163,6 +164,7 @@ You can also directly set the development/production mode using the `Debugger::D (If you use the Nette Framework, take a look at how to set the mode for it, and it will then also be used for Tracy.) +  Error Logging ------------- @@ -205,12 +207,14 @@ Debugger::$email = 'admin@example.com'; To protect your e-mail box from flood, Tracy sends **only one message** and creates a file `email-sent`. When a developer receives the e-mail notification, he checks the log, corrects his application and deletes the `email-sent` monitoring file. This activates the e-mail sending again. +  Opening Files in the Editor --------------------------- When the error page is displayed, you can click on file names and they will open in your editor with the cursor on the corresponding line. Files can also be created (action `create file`) or bug fixed in them (action `fix it`). In order to do this, you need to [configure the browser and the system](https://tracy.nette.org/cs/open-files-in-ide). +  Variable Dumping ---------------- @@ -262,6 +266,7 @@ bdump([1, 3, 5, 7, 9], 'odd numbers up to ten'); ![bar dump](https://nette.github.io/tracy/images/bardump-en.webp) +  Stopwatch --------- @@ -299,6 +304,7 @@ Debugger::timer(); // runs the timer echo Debugger::timer(); // elapsed time in seconds ``` +  Custom Logger ------------- @@ -330,6 +336,7 @@ services: tracy.logger: SlackLogger ``` +  Monolog Integration ------------------- @@ -348,6 +355,7 @@ Debugger::log('info'); // writes: [] main-channel.INFO: info [] [] Debugger::log('warning', Debugger::WARNING); // writes: [] main-channel.WARNING: warning [] [] ``` +  Faster Loading -------------- @@ -366,6 +374,7 @@ The solution is to place `` into your tem ``` +  AJAX and Redirected Requests ---------------------------- @@ -395,6 +404,7 @@ Debugger::dispatch(); The `setSessionStorage()` function has existed since version 2.9, before that Tracy always used the native PHP session. +  Content Security Policy ----------------------- @@ -433,6 +443,7 @@ change it to try_files $uri $uri/ /index.php$is_args$args; ``` +  Integrations ------------ diff --git a/src/Tracy/Bar/assets/bar.js b/src/Tracy/Bar/assets/bar.js index 3ce40b387..4d1805f58 100644 --- a/src/Tracy/Bar/assets/bar.js +++ b/src/Tracy/Bar/assets/bar.js @@ -14,14 +14,12 @@ let defaults = { AutoRefresh: true, }; -function getOption(key) -{ +function getOption(key) { let global = window['Tracy' + key]; return global === undefined ? defaults[key] : global; } -class Panel -{ +class Panel { constructor(id) { this.id = id; this.elem = document.getElementById(this.id); @@ -32,7 +30,7 @@ class Panel init() { let elem = this.elem; - this.init = function() {}; + this.init = function () {}; elem.innerHTML = elem.dataset.tracyContent; Tracy.Dumper.init(Debug.layer); evalScripts(elem); @@ -45,7 +43,7 @@ class Panel } this.focus(); this.peekPosition = false; - } + }, }); elem.addEventListener('mousedown', () => { @@ -145,7 +143,7 @@ class Panel offset.top += typeof window.screenTop === 'number' ? window.screenTop : (window.screenY + 50); let win = window.open('', this.id.replace(/-/g, '_'), 'left=' + offset.left + ',top=' + offset.top - + ',width=' + this.elem.offsetWidth + ',height=' + this.elem.offsetHeight + ',resizable=yes,scrollbars=yes'); + + ',width=' + this.elem.offsetWidth + ',height=' + this.elem.offsetHeight + ',resizable=yes,scrollbars=yes'); if (!win) { return false; } @@ -153,14 +151,14 @@ class Panel let doc = win.document; doc.write('' + '' - + '' + + '', ); let meta = this.elem.parentElement.lastElementChild; doc.body.innerHTML = '' - + '
' + this.elem.dataset.tracyContent + '
' - + meta.outerHTML - + '
'; + + '
' + this.elem.dataset.tracyContent + '
' + + meta.outerHTML + + ''; evalScripts(doc.body); if (this.elem.querySelector('h1')) { doc.title = this.elem.querySelector('h1').textContent; @@ -190,7 +188,7 @@ class Panel reposition(deltaX, deltaY) { let pos = getPosition(this.elem); if (pos.width) { // is visible? - setPosition(this.elem, {left: pos.left + (deltaX || 0), top: pos.top + (deltaY || 0)}); + setPosition(this.elem, { left: pos.left + (deltaX || 0), top: pos.top + (deltaY || 0) }); if (this.is(Panel.RESIZED)) { let size = getWindowSize(); this.elem.style.width = Math.min(size.width, pos.width) + 'px'; @@ -204,9 +202,9 @@ class Panel let key = this.id.split(':')[0]; // remove :requestId part let pos = getPosition(this.elem); if (this.is(Panel.WINDOW)) { - localStorage.setItem(key, JSON.stringify({window: true})); + localStorage.setItem(key, JSON.stringify({ window: true })); } else if (pos.width) { // is visible? - localStorage.setItem(key, JSON.stringify({right: pos.right, bottom: pos.bottom, width: pos.width, height: pos.height, zIndex: this.elem.style.zIndex - getOption('PanelZIndex'), resized: this.is(Panel.RESIZED)})); + localStorage.setItem(key, JSON.stringify({ right: pos.right, bottom: pos.bottom, width: pos.width, height: pos.height, zIndex: this.elem.style.zIndex - getOption('PanelZIndex'), resized: this.is(Panel.RESIZED) })); } else { localStorage.removeItem(key); } @@ -244,8 +242,7 @@ Panel.RESIZED = 'tracy-panel-resized'; Panel.zIndexCounter = 1; -class Bar -{ +class Bar { init() { this.id = 'tracy-debug-bar'; this.elem = document.getElementById(this.id); @@ -255,7 +252,7 @@ class Bar draggedClass: 'tracy-dragged', stop: () => { this.savePosition(); - } + }, }); this.elem.addEventListener('mousedown', (e) => { @@ -267,7 +264,7 @@ class Bar (new MutationObserver(() => { this.restorePosition(); - })).observe(this.elem, {childList: true, characterData: true, subtree: true}); + })).observe(this.elem, { childList: true, characterData: true, subtree: true }); } @@ -318,7 +315,7 @@ class Bar left: getOffset(link).left + getPosition(link).width + 4 - pos.width, top: this.isAtTop() ? getOffset(this.elem).top + getPosition(this.elem).height + 4 - : getOffset(this.elem).top - pos.height - 4 + : getOffset(this.elem).top - pos.height - 4, }); panel.peekPosition = true; } @@ -359,7 +356,7 @@ class Bar reposition(deltaX, deltaY) { let pos = getPosition(this.elem); if (pos.width) { // is visible? - setPosition(this.elem, {left: pos.left + (deltaX || 0), top: pos.top + (deltaY || 0)}); + setPosition(this.elem, { left: pos.left + (deltaX || 0), top: pos.top + (deltaY || 0) }); this.savePosition(); } } @@ -368,14 +365,14 @@ class Bar savePosition() { let pos = getPosition(this.elem); if (pos.width) { // is visible? - localStorage.setItem(this.id, JSON.stringify(this.isAtTop() ? {right: pos.right, top: pos.top} : {right: pos.right, bottom: pos.bottom})); + localStorage.setItem(this.id, JSON.stringify(this.isAtTop() ? { right: pos.right, top: pos.top } : { right: pos.right, bottom: pos.bottom })); } } restorePosition() { let pos = JSON.parse(localStorage.getItem(this.id)); - setPosition(this.elem, pos || {right: 0, bottom: 0}); + setPosition(this.elem, pos || { right: 0, bottom: 0 }); this.savePosition(); } @@ -387,8 +384,7 @@ class Bar } -class Debug -{ +class Debug { static init(content) { Debug.bar = new Bar; Debug.panels = {}; @@ -409,6 +405,7 @@ class Debug Debug.captureAjax(); Tracy.TableSort.init(); + Tracy.Tabs.init(); } @@ -483,13 +480,13 @@ class Debug } let oldOpen = XMLHttpRequest.prototype.open; - XMLHttpRequest.prototype.open = function() { + XMLHttpRequest.prototype.open = function () { oldOpen.apply(this, arguments); if (getOption('AutoRefresh') && new URL(arguments[1], location.origin).host === location.host) { let reqId = Tracy.getAjaxHeader(); this.setRequestHeader('X-Tracy-Ajax', reqId); - this.addEventListener('load', function() { + this.addEventListener('load', function () { if (this.getAllResponseHeaders().match(/^X-Tracy-Ajax: 1/mi)) { Debug.loadScript(baseUrl + '_tracy_bar=content-ajax.' + reqId + '&XDEBUG_SESSION_STOP=1&v=' + Math.random()); } @@ -498,7 +495,7 @@ class Debug }; let oldFetch = window.fetch; - window.fetch = function(request, options) { + window.fetch = function (request, options) { request = request instanceof Request ? request : new Request(request, options || {}); let reqId = request.headers.get('X-Tracy-Ajax'); @@ -548,14 +545,14 @@ function draggable(elem, options) { let dE = document.documentElement, started, deltaX, deltaY, clientX, clientY; options = options || {}; - let redraw = function () { + let redraw = () => { if (dragging) { - setPosition(elem, {left: clientX + deltaX, top: clientY + deltaY}); + setPosition(elem, { left: clientX + deltaX, top: clientY + deltaY }); requestAnimationFrame(redraw); } }; - let onMove = function(e) { + let onMove = (e) => { if (e.buttons === 0) { return onEnd(e); } @@ -574,7 +571,7 @@ function draggable(elem, options) { return false; }; - let onEnd = function(e) { + let onEnd = (e) => { if (started) { if (options.draggedClass) { elem.classList.remove(options.draggedClass); @@ -591,7 +588,7 @@ function draggable(elem, options) { return false; }; - let onStart = function(e) { + let onStart = (e) => { e.preventDefault(); e.stopPropagation(); @@ -631,9 +628,10 @@ function draggable(elem, options) { // returns total offset for element function getOffset(elem) { - let res = {left: elem.offsetLeft, top: elem.offsetTop}; + let res = { left: elem.offsetLeft, top: elem.offsetTop }; while (elem = elem.offsetParent) { // eslint-disable-line no-cond-assign - res.left += elem.offsetLeft; res.top += elem.offsetTop; + res.left += elem.offsetLeft; + res.top += elem.offsetTop; } return res; } @@ -642,7 +640,7 @@ function getOffset(elem) { function getWindowSize() { return { width: document.documentElement.clientWidth, - height: document.compatMode === 'BackCompat' ? window.innerHeight : document.documentElement.clientHeight + height: document.compatMode === 'BackCompat' ? window.innerHeight : document.documentElement.clientHeight, }; } @@ -670,7 +668,7 @@ function getPosition(elem) { right: win.width - elem.offsetWidth - elem.offsetLeft, bottom: win.height - elem.offsetHeight - elem.offsetTop, width: elem.offsetWidth, - height: elem.offsetHeight + height: elem.offsetHeight, }; } diff --git a/src/Tracy/BlueScreen/assets/bluescreen.js b/src/Tracy/BlueScreen/assets/bluescreen.js index 7a1b5b68f..c69cd5cf4 100644 --- a/src/Tracy/BlueScreen/assets/bluescreen.js +++ b/src/Tracy/BlueScreen/assets/bluescreen.js @@ -2,8 +2,7 @@ * This file is part of the Tracy (https://tracy.nette.org) */ -class BlueScreen -{ +class BlueScreen { static init(ajax) { BlueScreen.globalInit(); @@ -51,7 +50,7 @@ class BlueScreen window.addEventListener('scroll', stickyFooter); - BlueScreen.globalInit = function() {}; + BlueScreen.globalInit = function () {}; } diff --git a/src/Tracy/Dumper/assets/dumper.js b/src/Tracy/Dumper/assets/dumper.js index 9ee7246ca..1651935b7 100644 --- a/src/Tracy/Dumper/assets/dumper.js +++ b/src/Tracy/Dumper/assets/dumper.js @@ -15,8 +15,7 @@ const HINT_CTRL = 'Ctrl-Click to open in editor', HINT_ALT = 'Alt-Click to expand/collapse all child nodes'; -class Dumper -{ +class Dumper { static init(context) { // full lazy (context || document).querySelectorAll('[data-tracy-snapshot][data-tracy-dump]').forEach((pre) => { //
@@ -146,19 +145,19 @@ function build(data, repository, collapsed, parentIds, keyType) {
 		return createEl(null, null, [
 			createEl(
 				'span',
-				{'class': 'tracy-dump-' + type.replace('ean', '')},
-				[data + '']
-			)
+				{ class: 'tracy-dump-' + type.replace('ean', '') },
+				[data + ''],
+			),
 		]);
 
 	} else if (type === 'string') {
 		data = {
 			string: data.replace(/&/g, '&').replace(/\'' + s + '\''}
+					{ class: 'tracy-dump-string' },
+					{ html: '\'' + s + '\'' },
 				),
 			]);
 
@@ -196,10 +195,10 @@ function build(data, repository, collapsed, parentIds, keyType) {
 				createEl(
 					'span',
 					{
-						'class': classes[typeof keyType === 'string' ? PROP_PRIVATE : keyType],
-						'title': typeof keyType === 'string' ? 'declared in ' + keyType : null,
+						class: classes[typeof keyType === 'string' ? PROP_PRIVATE : keyType],
+						title: typeof keyType === 'string' ? 'declared in ' + keyType : null,
 					},
-					{html: s}
+					{ html: s },
 				),
 			]);
 		}
@@ -208,15 +207,15 @@ function build(data, repository, collapsed, parentIds, keyType) {
 		if (count) {
 			let collapsed = count >= COLLAPSE_COUNT;
 			return createEl(null, null, [
-				createEl('span', {'class': collapsed ? 'tracy-toggle tracy-collapsed' : 'tracy-toggle'}, ['string']),
+				createEl('span', { class: collapsed ? 'tracy-toggle tracy-collapsed' : 'tracy-toggle' }, ['string']),
 				'\n',
 				createEl(
 					'div',
 					{
-						'class': 'tracy-dump-string' + (collapsed ? ' tracy-collapsed' : ''),
-						'title': data.length + (data.bin ? ' bytes' : ' characters'),
+						class: 'tracy-dump-string' + (collapsed ? ' tracy-collapsed' : ''),
+						title: data.length + (data.bin ? ' bytes' : ' characters'),
 					},
-					{html: '\'' + s + '\''}
+					{ html: '\'' + s + '\'' },
 				),
 			]);
 		}
@@ -225,21 +224,21 @@ function build(data, repository, collapsed, parentIds, keyType) {
 			createEl(
 				'span',
 				{
-					'class': 'tracy-dump-string',
-					'title': data.length + (data.bin ? ' bytes' : ' characters'),
+					class: 'tracy-dump-string',
+					title: data.length + (data.bin ? ' bytes' : ' characters'),
 				},
-				{html: '\'' + s + '\''}
+				{ html: '\'' + s + '\'' },
 			),
 		]);
 
 	} else if (data.number) {
 		return createEl(null, null, [
-			createEl('span', {'class': 'tracy-dump-number'}, [data.number])
+			createEl('span', { class: 'tracy-dump-number' }, [data.number]),
 		]);
 
 	} else if (data.text !== undefined) {
 		return createEl(null, null, [
-			createEl('span', {class: 'tracy-dump-virtual'}, [data.text])
+			createEl('span', { class: 'tracy-dump-virtual' }, [data.text]),
 		]);
 
 	} else { // object || resource || array
@@ -250,17 +249,17 @@ function build(data, repository, collapsed, parentIds, keyType) {
 
 		let span = data.array !== undefined
 			? [
-				createEl('span', {'class': 'tracy-dump-array'}, ['array']),
-				' (' + (data.length || data.items.length) + ')'
-			]
+					createEl('span', { class: 'tracy-dump-array' }, ['array']),
+					' (' + (data.length || data.items.length) + ')',
+				]
 			: [
-				createEl('span', {
-					'class': data.object ? 'tracy-dump-object' : 'tracy-dump-resource',
-					title: data.editor ? 'Declared in file ' + data.editor.file + ' on line ' + data.editor.line + (data.editor.url ? '\n' + HINT_CTRL : '') + '\n' + HINT_ALT : null,
-					'data-tracy-href': data.editor ? data.editor.url : null
-				}, nameEl),
-				...(id ? [' ', createEl('span', {'class': 'tracy-dump-hash'}, [data.resource ? '@' + id.substr(1) : '#' + id])] : [])
-			];
+					createEl('span', {
+						'class': data.object ? 'tracy-dump-object' : 'tracy-dump-resource',
+						'title': data.editor ? 'Declared in file ' + data.editor.file + ' on line ' + data.editor.line + (data.editor.url ? '\n' + HINT_CTRL : '') + '\n' + HINT_ALT : null,
+						'data-tracy-href': data.editor ? data.editor.url : null,
+					}, nameEl),
+					...(id ? [' ', createEl('span', { class: 'tracy-dump-hash' }, [data.resource ? '@' + id.substr(1) : '#' + id])] : []),
+				];
 
 		parentIds = parentIds ? parentIds.slice() : [];
 		let recursive = id && parentIds.indexOf(id) > -1;
@@ -272,7 +271,7 @@ function build(data, repository, collapsed, parentIds, keyType) {
 		}
 
 		collapsed = collapsed === true || data.collapsed || (data.items && data.items.length >= collapseCount);
-		let toggle = createEl('span', {'class': collapsed ? 'tracy-toggle tracy-collapsed' : 'tracy-toggle'}, span);
+		let toggle = createEl('span', { class: collapsed ? 'tracy-toggle tracy-collapsed' : 'tracy-toggle' }, span);
 
 		return createEl(null, null, [
 			toggle,
@@ -285,7 +284,7 @@ function build(data, repository, collapsed, parentIds, keyType) {
 
 function buildStruct(data, repository, toggle, collapsed, parentIds) {
 	if (Array.isArray(data)) {
-		data = {items: data};
+		data = { items: data };
 
 	} else if (data.ref) {
 		parentIds = parentIds.slice();
@@ -295,11 +294,11 @@ function buildStruct(data, repository, toggle, collapsed, parentIds) {
 
 	let cut = data.items && data.length > data.items.length;
 	let type = data.object ? TYPE_OBJECT : data.resource ? TYPE_RESOURCE : TYPE_ARRAY;
-	let div = createEl('div', {'class': collapsed ? 'tracy-collapsed' : null});
+	let div = createEl('div', { class: collapsed ? 'tracy-collapsed' : null });
 
 	if (collapsed) {
 		let handler;
-		toggle.addEventListener('tracy-toggle', handler = function() {
+		toggle.addEventListener('tracy-toggle', handler = function () {
 			toggle.removeEventListener('tracy-toggle', handler);
 			createItems(div, data.items, type, repository, parentIds, null);
 			if (cut) {
@@ -351,7 +350,7 @@ function createItems(el, items, type, repository, parentIds, collapsed) {
 		createEl(el, null, [
 			build(key, null, null, null, type === TYPE_ARRAY ? TYPE_ARRAY : vis),
 			type === TYPE_ARRAY ? ' => ' : ': ',
-			...(ref ? [createEl('span', {'class': 'tracy-dump-hash'}, ['&' + ref]), ' '] : []),
+			...(ref ? [createEl('span', { class: 'tracy-dump-hash' }, ['&' + ref]), ' '] : []),
 			tmp = build(val, repository, collapsed, parentIds),
 			tmp.lastElementChild.tagName === 'DIV' ? '' : '\n',
 		]);
@@ -370,7 +369,7 @@ function toggleChildren(cont, usedIds) {
 			Tracy.Toggle.toggle(el, false);
 		} else {
 			usedIds[id] = true;
-			Tracy.Toggle.toggle(el, true, {usedIds: usedIds});
+			Tracy.Toggle.toggle(el, true, { usedIds: usedIds });
 		}
 	});
 }
diff --git a/src/Tracy/Logger/Logger.php b/src/Tracy/Logger/Logger.php
index 7c9e65bc5..58173b29a 100644
--- a/src/Tracy/Logger/Logger.php
+++ b/src/Tracy/Logger/Logger.php
@@ -120,7 +120,7 @@ public function getExceptionFile(\Throwable $exception, string $level = self::EX
 			];
 		}
 
-		$hash = substr(md5(serialize($data)), 0, 10);
+		$hash = substr(hash('xxh128', serialize($data)), 0, 10);
 		$dir = strtr($this->directory . '/', '\\/', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR);
 		foreach (new \DirectoryIterator($this->directory) as $file) {
 			if (strpos($file->getBasename(), $hash)) {
diff --git a/src/Tracy/assets/table-sort.js b/src/Tracy/assets/table-sort.js
index 02a524729..10e72c111 100644
--- a/src/Tracy/assets/table-sort.js
+++ b/src/Tracy/assets/table-sort.js
@@ -3,8 +3,7 @@
  */
 
 // enables 
-class TableSort
-{
+class TableSort {
 	static init() {
 		document.documentElement.addEventListener('click', (e) => {
 			if ((window.getSelection().type !== 'Range')
@@ -14,7 +13,7 @@ class TableSort
 			}
 		});
 
-		TableSort.init = function() {};
+		TableSort.init = function () {};
 	}
 
 	static sort(tcell) {
@@ -22,16 +21,16 @@ class TableSort
 		let preserveFirst = !tcell.closest('thead') && !tcell.parentNode.querySelectorAll('td').length;
 		let asc = !(tbody.tracyAsc === tcell.cellIndex);
 		tbody.tracyAsc = asc ? tcell.cellIndex : null;
-		let getText = (cell) => { return cell ? (cell.getAttribute('data-order') || cell.innerText) : ''; };
+		let getText = (cell) => cell ? (cell.getAttribute('data-order') || cell.innerText) : '';
 
 		Array.from(tbody.children)
 			.slice(preserveFirst ? 1 : 0)
 			.sort((a, b) => {
-				return function(v1, v2) {
+				return (function (v1, v2) {
 					return v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2)
 						? v1 - v2
-						: v1.toString().localeCompare(v2, undefined, {numeric: true, sensitivity: 'base'});
-				}(getText((asc ? a : b).children[tcell.cellIndex]), getText((asc ? b : a).children[tcell.cellIndex]));
+						: v1.toString().localeCompare(v2, undefined, { numeric: true, sensitivity: 'base' });
+				}(getText((asc ? a : b).children[tcell.cellIndex]), getText((asc ? b : a).children[tcell.cellIndex])));
 			})
 			.forEach((tr) => { tbody.appendChild(tr); });
 	}
diff --git a/src/Tracy/assets/tabs.js b/src/Tracy/assets/tabs.js
index 9e0a55a60..8ec2fe7b2 100644
--- a/src/Tracy/assets/tabs.js
+++ b/src/Tracy/assets/tabs.js
@@ -3,8 +3,7 @@
  */
 
 // enables .tracy-tabs, .tracy-tab-label, .tracy-tab-panel, .tracy-active
-class Tabs
-{
+class Tabs {
 	static init() {
 		document.documentElement.addEventListener('click', (e) => {
 			let label, context;
@@ -19,7 +18,7 @@ class Tabs
 			}
 		});
 
-		Tabs.init = function() {};
+		Tabs.init = function () {};
 	}
 
 	static toggle(context, label) {
diff --git a/src/Tracy/assets/toggle.js b/src/Tracy/assets/toggle.js
index 1406f33ef..aabefb5f1 100644
--- a/src/Tracy/assets/toggle.js
+++ b/src/Tracy/assets/toggle.js
@@ -5,8 +5,7 @@
 const MOVE_THRESHOLD = 100;
 
 // enables  or  toggling
-class Toggle
-{
+class Toggle {
 	static init() {
 		let start;
 		document.documentElement.addEventListener('mousedown', (e) => {
@@ -25,7 +24,7 @@ class Toggle
 				e.stopImmediatePropagation();
 			}
 		});
-		Toggle.init = function() {};
+		Toggle.init = function () {};
 	}
 
 
@@ -41,7 +40,7 @@ class Toggle
 
 		el.dispatchEvent(new CustomEvent('tracy-beforetoggle', {
 			bubbles: true,
-			detail: {collapsed: !expand, originalEvent: e}
+			detail: { collapsed: !expand, originalEvent: e },
 		}));
 
 		if (!ref || ref === '#') {
@@ -60,7 +59,7 @@ class Toggle
 
 		el.dispatchEvent(new CustomEvent('tracy-toggle', {
 			bubbles: true,
-			detail: {relatedTarget: dest, collapsed: !expand, originalEvent: e}
+			detail: { relatedTarget: dest, collapsed: !expand, originalEvent: e },
 		}));
 	}
 
@@ -91,7 +90,7 @@ class Toggle
 
 		window.addEventListener('pagehide', () => {
 			toggles = saved.map((el) => {
-				let item = {path: [], text: el.textContent, expand: !el.classList.contains('tracy-collapsed')};
+				let item = { path: [], text: el.textContent, expand: !el.classList.contains('tracy-collapsed') };
 				do {
 					item.path.unshift(Array.from(el.parentNode.children).indexOf(el));
 					el = el.parentNode;