Skip to content

v3.0.7 #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Mar 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ node_modules/
*.crx
manifest.json
bundle/js
*.log

4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@
"url": "https://json.schemastore.org/chrome-manifest.json"
}
],
"typescript.tsdk": "node_modules/typescript/lib"
"typescript.tsdk": "node_modules/typescript/lib",
"spellright.language": ["en-US-10-1."],
"spellright.documentTypes": ["latex", "plaintext", "markdown"]
}
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ all:
make lint
make test
make prod
make zip_chrome
make zip_firefox
make zip_chrome

lint:
pnpm exec prettier . --write
Expand All @@ -30,6 +30,7 @@ test:
pnpm exec tsx --test

dev:
rm -rf ./bundle/js/
NODE_OPTIONS="--import=tsx --trace-deprecation" \
pnpm exec webpack --progress --watch --mode=development

Expand Down
146 changes: 76 additions & 70 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,84 +1,53 @@
### ![](./bundle/img/panel-icon28.png) JSDiff

An extension for developers that enhances the console API by incorporating the ability to compare objects and adds a JSDiff tab (parallel to Elements, Network panels) within your dev-tools for viewing the results.
An extension for developers that enhances the console API by incorporating the ability to compare objects and adds a `JSDiff` tab (parallel to Elements, Network panels) within your dev-tools for viewing the results.

- Available in Chrome Web Store as [console.diff()](https://chromewebstore.google.com/detail/consolediff/iefeamoljhdcpigpnpggeiiabpnpgonb)
- Available in Firefox Add-ons as [jsdiff.diff()](https://addons.mozilla.org/addon/jsdiff-diff/)

<details>
<summary> <strong>Examples</strong> </summary>
<summary> <strong>Screenshots</strong> </summary>

- Comparing two objects
![screenshot](./doc/screenshot-01.png)

- Tracking changes in localStorage (unchanged are hidden)
- Tracking changes in `localStorage` (unchanged are hidden)
![screenshot](./doc/screenshot-02.png)

</details>
<details>
<summary> <strong>How it works</strong> </summary>

- Chrome mv3
![screenshot](./doc/design.chrome.png)
- Firefox
![screenshot](./doc/design.firefox.png)

</details>
### Motivation

### Based on

- [jsondiffpatch](https://github.com/benjamine/jsondiffpatch) by Benjamín Eidelman
- [vuejs](https://github.com/vuejs) by Evan You
- Track object mutations during runtime and/or while debugging with intention to find expected or unexpected changes.

### Features

- Symple user interface:
- User interface:

- Button to hide/show unchanged properties.
- Button to copy changed properties in format of `jsondiffpatch` Delta object.
- Button to clear current result.
- Search input to highlight patterns
- Hide / show unchanged properties.
- Copy changed properties in format of `jsondiffpatch` Delta object.
- Clear current result.
- Search input to highlight patterns.
- If search query contains at least one upper-case letter - the search will be case-sensitive.
- Indicator of the last update time.
- Indicator of a fatal error (out of storage memory).
- Devtools light/dark colour scheme support.

- Compare objects between multiple [sub]domains, chrome tabs, or single page reloads.

- JSDiff devtools panel reflects current state of comparison, regardless the tab[s] it was opened from.

- Internal search inside comparison results
- DevTools light/dark color scheme support.

- If search query contains at least one upper-case letter - the search will be case-sensitive.
- Compare objects between multiple [sub]domains, Chrome tabs, or single page reloads.

- Using `console.diff` functions from within online code editors like: [codesandbox.io](https://codesandbox.io), [coderpad.io](https://coderpad.io), [flems.io](https://flems.io), [codepen.io](https://codepen.io), [jsfiddle.net](https://jsfiddle.net).
- `JSDiff` DevTools panel reflects current state of comparison, regardless the tab[s] it was opened from.

- Functions are included in comparison result in order to detect possible alterations, in form of a string combined from a function name (if present) and a SHA-256 hash of a `function.toString()` body. Native functions are shown as `ƒ⟪native⟫`.
- Fail-safe serialization of objects having security issues while accessing their properties or objects having `toJSON()` function; when instead of serialization of all object properties, - only `toJSON()` return value is serialized, like `JSON.strigify()` does.

- Some DOM objects like Document or Element are not worth to be shown entirely, since that is not the purpose of this extension. So if they are present anywhere, they are serialized as `0x####: ⟪unserializable⟫`.
- Can be used from within online code editors like: [codesandbox.io](https://codesandbox.io), [coderpad.io](https://coderpad.io), [flems.io](https://flems.io), [codepen.io](https://codepen.io), [jsfiddle.net](https://jsfiddle.net), [mdn playground](https://developer.mozilla.org/play).

- Object, Array, Map, Set - serialized only once and the rest of their ocurrances are mentioned with unique reference like: `0x####: {♻️}`, `0x####: [♻️]`, `0x####: Map{♻️}`, `0x####: Set[♻️]` respectivly.
#### Limitations

- Map keys, unless they are primitive types, serialized by their pseudo ids.
- Map keys like `0` and `'0'` would be merged due to `Map to Object` conversion.

- Symbols serialized with his pseudo id like: `0x####: Symbol(name)`.
- While paused in debug mode, `JSDiff` panel won't reflect the result until runtime is resumed (see [#10](https://github.com/zendive/jsdiff/issues/10)).

- Serialization of numerics like `+/-Infinity`, `NaN`, `BigInt`, or `undefined` serialized like: `Number⟪Infinity⟫`, `Number⟪NaN⟫`, `BigInt⟪#⟫`, `⟪undefined⟫` respectivly.

- Failsafe serialization of objects having security issues while accessing their properties.

- Failsefe serialization of objects having `toJSON()` function (when instead of serialization of all object properties, - only toJSON() return value is serialized, similar to the way native `JSON.strigify()` works).

### Legend

- Pseudo id, assigned to non-primitive data types, used in order to detect reference recurrences and, in case of Symbols - symbol uniqueness. Id for an object shown in the output only if it seen more than once. It being assigned in the scope of serialization of a high level argument instance, while comparing left or right side; that means if some object, having id 0x0001 on the left side, is not guarantied to have same id on the right side.

### Limitations

- While paused in debug mode, JSDiff panel won't reflect the result until runtime is resumed (see [#10][i10]).

[i10]: https://github.com/zendive/jsdiff/issues/10

- Compared objects, after being serialized, stored in `chrome.storage.local` wich has 10MB limit (before chrome v114 was 5MB).
- Compared objects, after being serialized, stored in `chrome.storage.local` which has 10 MB limit.

- In Firefox the API is under `jsdiff` object for now, cause extension API's not fully compatible.

Expand Down Expand Up @@ -114,7 +83,7 @@ console.diffLeft(Date.now());
console.diffRight(Date.now());
```

### Typescript
#### Typescript

Global Console interface declaration for quick copy/paste when used from typescript:

Expand All @@ -129,41 +98,78 @@ declare global {
}
```

### Usage basics

Historically, left side represents the old state and right side the new state.
### Serialization by types

- Things that are present on the left side but missing on the right side are colour-coded as red (old).
| Input | Output |
| ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| XMLHttpRequest<sup>[1]</sup> | ƒ XMLHttpRequest⟪native⟫ |
| function test(){}<sup>[1]</sup> | ƒ test⟪1374b28d22b674e53a044425556a9cd48b82fd5aba3bf19e3545d51704227b10⟫ |
| document.body | {0001}<sup>[2,3]</sup> DOM⟪BODY⟫ |
| ±Infinity | Number⟪±Infinity⟫ |
| NaN | Number⟪NaN⟫ |
| 98765432109876543210n | BigInt⟪98765432109876543210⟫ |
| void 0 | ⟪undefined⟫ |
| /example/i | RegExp⟪/example/i⟫ |
| new URL('https:\//example.com/') | URL⟪https:\//example.com/⟫ |
| Symbol('example') | {0001}<sup>[3]</sup> Symbol(example) |
| Symbol.for('global') | Symbol(global) |
| (obj = {key: 1}, {first: obj, second: obj}) | {"first": {"key": 1}, "second": "[0002]<sup>[4]</sup> Object⟪♻️⟫"} |
| (key2= {}, map = new Map(\[['key1', 1], [key2, 2]]), {first: map, second: map}) | {"first": {"[0003]<sup>[4,5]</sup> Object⟪♻️⟫": 2, "key1": 1}, "second": "[0002]<sup>[4]</sup> Map⟪♻️⟫"} |
| (arr = [1], {first: arr, second: arr}) | {"first": [1], "second": "[0002]<sup>[4]</sup> Array⟪♻️⟫"} |
| (set = new Set([1]), {first: set, second: set}) | {"first: [1], "second": "[0002]<sup>[4]</sup> Set⟪♻️⟫"} |

- Things that are missing on the left side but present on the right side are colour-coded as green (new).
<sup>1</sup> Functions included in comparison result in order to detect possible alterations, in form of a string combined from a function name (if present) and a hash of a `function.toString()` body.

- To track changes of the same variable in timed manner you can push it with `diffPush` or `diff` with a single argument, - that will shift objects from right to left, showing differences with previous push state.
<sup>2</sup> DOM element serialized by pseudo `id` and `nodeName`.

### How to build
<sup>3</sup> Notation `{}` denotes pseudo `id` from a Set of unique instances, which is assigned during serialization of compared sides and remains inside internal `WeakMap` lookup catalog until its garbage collected or page is reloaded.

Requires
<sup>4</sup> Notation `[]` denotes pseudo `id` from a [Multiset](https://en.wikipedia.org/wiki/Multiset) of recurring instances, which is assigned in the scope of serialization of a high level argument instance, while comparing left or right side; that means - if some object, having `id` of `[0001]` on the left side, is not guarantied to have same `id` on the right side.

- Linux
- node 22.11 (LTS)

```sh
make install # to install dependencies
make all # build for prod and make extension.${browser}.zip
make tune2chrome # or tune2firefox for relevant manifest.json file
make dev # local development
```
<sup>5</sup> `Map` key, unless it's a primitive type, serialized by his pseudo `id`.

### Protection

- How to protect your site from this extension:
- Well, tests on chrome show that even `Content-Security-Policy: default-src 'none';` header won't prevent injection of extension content-scripts...

- Tests in Chrome show that even `Content-Security-Policy: default-src 'none';` header won't prevent injection of extension content-scripts...

- Avoid assigning to `window` or `globalThis` any application object.
See also [accidental global variables and memory leaks](https://www.tutorialspoint.com/explain-in-detail-about-memory-leaks-in-javascript).

- In general, you can incapacitate console functions:

```js
for (const prop in console) {
if (typeof console[prop] === 'function' && prop !== 'error') {
console[prop] = function noop() {};
}
}
```

### Build instructions

- Linux
- node 22.14 (LTS)

```sh
make install # install dependencies
make all # build for prod and make extension.${browser}.zip
make tune2chrome # or tune2firefox for relevant manifest.json file
make dev # local development
```

#### Based on

- [jsondiffpatch](https://github.com/benjamine/jsondiffpatch) by Benjamín Eidelman
- [vuejs](https://github.com/vuejs) by Evan You

<details>
<summary> <strong>Communication schemes between Content-script and DevTools panel</strong> </summary>

- Chrome mv3
![screenshot](./doc/design.chrome.png)
- Firefox
![screenshot](./doc/design.firefox.png)

</details>
2 changes: 1 addition & 1 deletion manifest.chrome.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "console.diff(...)",
"version": "3.0.6",
"version": "3.0.7",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlCx2Bl0li+3idvfrH9cQL/MzphafGFqMUA2P+0vbyhwxsxWl0llOaGQbkirX5qCoAVHoUCPqu3hCjpVCv35igPbfqDs5bdLZZmXt2F0HjEQnWI/eZKd9IKcKYMplEeL2BodmpU02VrP1UnUzQHZeeMWk9ybgWOqCimkwliILVubRj5dxNB9AidLwO4Z5iGq/OvW9AJMYdxKxrLP2lF6/GGNcCBg+iCJZwlQOhFB9LbUjytT4ws3bIEX4b5zmWLqGKR1NiZfGug2eCWXt9oEKg2WkbXmBBzFKqxnM/bBUrVR29N9qNgx0f42qnyhsW3Bo4kPzE3d0asXCV5nofLTLEwIDAQAB",
"description": "Compare objects in memory with console.diff(old, new) devtools function",
"minimum_chrome_version": "100.0",
Expand Down
33 changes: 18 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
{
"type": "module",
"devDependencies": {
"@types/chrome": "0.0.280",
"@noble/hashes": "1.7.1",
"@types/chrome": "0.0.307",
"@types/diff-match-patch": "1.0.36",
"@types/firefox-webext-browser": "120.0.4",
"@types/webpack-bundle-analyzer": "4.7.0",
"@vue/compiler-sfc": "3.5.12",
"clean-webpack-plugin": "4.0.0",
"@vue/compiler-sfc": "3.5.13",
"css-loader": "7.1.2",
"diff-match-patch": "1.0.5",
"esbuild": "0.24.0",
"esbuild-loader": "4.2.2",
"esbuild": "0.25.0",
"esbuild-loader": "4.3.0",
"jsondiffpatch": "0.6.0",
"pinia": "2.2.6",
"prettier": "3.3.3",
"sass": "1.80.6",
"sass-loader": "16.0.3",
"pinia": "3.0.1",
"prettier": "3.5.3",
"sass": "1.85.1",
"sass-loader": "16.0.5",
"style-loader": "4.0.0",
"tsx": "4.19.2",
"typescript": "5.6.3",
"vue": "3.5.12",
"tsx": "4.19.3",
"typescript": "5.8.2",
"vue": "3.5.13",
"vue-loader": "17.4.2",
"webpack": "5.96.1",
"webpack": "5.98.0",
"webpack-bundle-analyzer": "4.10.2",
"webpack-cli": "5.1.4"
"webpack-cli": "6.0.1"
},
"pnpm": {
"overrides": {}
"overrides": {},
"onlyBuiltDependencies": [
"sass"
]
}
}
Loading