Skip to content

Commit

Permalink
Merge pull request #217 from bhollis/fix-floats
Browse files Browse the repository at this point in the history
Fixed a regression where floating-point numbers were truncated to integers
  • Loading branch information
bhollis authored Jun 19, 2024
2 parents bf7a463 + a6692b8 commit a10aae5
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 7 deletions.
1 change: 0 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
"editor.codeActionsOnSave": {
"source.fixAll": "explicit"
},
"jest.jestCommandLine": "pnpm test --",
"[javascript]": {
"editor.codeActionsOnSave": {
"source.organizeImports": "never"
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## JSONView 3.0.1

- Fixed a regression where floating-point numbers were truncated to integers.

## JSONView 3.0.0

- JSONView is now compatible with Manifest V3, which is required in Chrome.
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- [Install for Firefox](https://addons.mozilla.org/en-US/firefox/addon/jsonview/)
- [Install for Chrome](https://chrome.google.com/webstore/detail/jsonview/gmegofmjomhknnokphhckolhcffdaihd)
- [Install for Edge](https://microsoftedge.microsoft.com/addons/detail/jsonview/kmpfgkgaimakokfhgdahhiaaiidiphco)
- There is no version for Safari because it costs $100/year to publish a free extension to the Mac App Store.

Normally, when encountering a [JSON](http://json.org) document (content type `application/json`), Firefox simply prompts you to download the view. With the JSONView extension, JSON documents are shown in the browser similar to how XML documents are shown. The document is formatted, highlighted, and arrays and objects can be collapsed. Even if the JSON document contains errors, JSONView will still show the raw text.

Expand Down Expand Up @@ -49,3 +50,7 @@ pnpm start
```

`jsonview-chrome.zip` and `jsonview-firefox.zip` can then be manually uploaded to the extension sites.

- Chrome: https://chrome.google.com/webstore/devconsole/
- Firefox: https://addons.mozilla.org/en-US/developers/addons
- Edge: https://partner.microsoft.com/en-us/dashboard/microsoftedge/overview
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"id": "[email protected]",
"version": "3.0.0",
"version": "3.0.1",
"name": "jsonview",
"title": "JSONView",
"description": "View JSON documents in the browser.",
Expand Down
108 changes: 108 additions & 0 deletions src/jsonformatter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { strict as assert } from "node:assert";
import test from "node:test";
import { valueToHTML } from "./jsonformatter.js";
import { safeStringEncodeNums } from "./safe-encode-numbers.js";

const jsonContent = [
[`{}`, `{ }`],
[
`{ "hey": "guy" }`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.hey"><span class="q">&quot;</span>hey<span class="q">&quot;</span></span>: <span class="string">&quot;guy&quot;</span></li></ul><span class="spacer"></span>}`,
],
[
`{ "float": 10.5 }`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.float"><span class="q">&quot;</span>float<span class="q">&quot;</span></span>: <span class="num">10.5</span></li></ul><span class="spacer"></span>}`,
],
[
`{ "10.5": "hello" }`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop quoted" title=""><span class="q">&quot;</span>10.5<span class="q">&quot;</span></span>: <span class="string">&quot;hello&quot;</span></li></ul><span class="spacer"></span>}`,
],
[
// bigger than max safe integer
`{ "anumber": 9117199254740991 }`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.anumber"><span class="q">&quot;</span>anumber<span class="q">&quot;</span></span>: <span class="num">9117199254740992</span></li></ul><span class="spacer"></span>}`,
],
[
`{ "anobject": {"whoa": "nuts","anarray": [1,2,"thr<h1>ee"], "more":"stuff"} }`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.anobject"><span class="q">&quot;</span>anobject<span class="q">&quot;</span></span>: <span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.anobject.whoa"><span class="q">&quot;</span>whoa<span class="q">&quot;</span></span>: <span class="string">&quot;nuts&quot;</span>,</li><li><span class="spacer">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.anobject.anarray"><span class="q">&quot;</span>anarray<span class="q">&quot;</span></span>: <span class="collapser"></span>[<ul class="array collapsible"><li><span class="spacer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="num">1</span>,</li><li><span class="spacer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="num">2</span>,</li><li><span class="spacer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="string">&quot;thr&lt;h1&gt;ee&quot;</span></li></ul><span class="spacer">&nbsp;&nbsp;&nbsp;&nbsp;</span>],</li><li><span class="spacer">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.anobject.more"><span class="q">&quot;</span>more<span class="q">&quot;</span></span>: <span class="string">&quot;stuff&quot;</span></li></ul><span class="spacer">&nbsp;&nbsp;</span>}</li></ul><span class="spacer"></span>}`,
],
[
`{ "awesome": true }`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.awesome"><span class="q">&quot;</span>awesome<span class="q">&quot;</span></span>: <span class="bool">true</span></li></ul><span class="spacer"></span>}`,
],
[
`{ "bogus": false }`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.bogus"><span class="q">&quot;</span>bogus<span class="q">&quot;</span></span>: <span class="bool">false</span></li></ul><span class="spacer"></span>}`,
],
[
`{ "meaning": null }`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.meaning"><span class="q">&quot;</span>meaning<span class="q">&quot;</span></span>: <span class="null">null</span></li></ul><span class="spacer"></span>}`,
],
[
`{ "japanese": "明日がある。" }`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.japanese"><span class="q">&quot;</span>japanese<span class="q">&quot;</span></span>: <span class="string">&quot;明日がある。&quot;</span></li></ul><span class="spacer"></span>}`,
],
[
`{ "link": "http://jsonview.com" }`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.link"><span class="q">&quot;</span>link<span class="q">&quot;</span></span>: <a href="http://jsonview.com"><span class="q">&quot;</span>http://jsonview.com<span class="q">&quot;</span></a></li></ul><span class="spacer"></span>}`,
],
[
`{ "notLink": "http://jsonview.com is great" }`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.notLink"><span class="q">&quot;</span>notLink<span class="q">&quot;</span></span>: <span class="string">&quot;http://jsonview.com is great&quot;</span></li></ul><span class="spacer"></span>}`,
],
[
`{ "aZero": 0 }`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.aZero"><span class="q">&quot;</span>aZero<span class="q">&quot;</span></span>: <span class="num">0</span></li></ul><span class="spacer"></span>}`,
],
[
`{ "emptyString": "" }`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.emptyString"><span class="q">&quot;</span>emptyString<span class="q">&quot;</span></span>: <span class="string">&quot;&quot;</span></li></ul><span class="spacer"></span>}`,
],
[
`{"string_with_nulls":"\\u0000*\\u0000_hello"}`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.string_with_nulls"><span class="q">&quot;</span>string_with_nulls<span class="q">&quot;</span></span>: <span class="string">&quot;\\u0000*\\u0000_hello&quot;</span></li></ul><span class="spacer"></span>}`,
],
[
`{"":"18"}`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop quoted" title=""><span class="q">&quot;</span><span class="q">&quot;</span></span>: <span class="string">&quot;18&quot;</span></li></ul><span class="spacer"></span>}`,
],
[`[]`, `[ ]`],
[`null`, `<span class="null">null</span>`],
[`true`, `<span class="bool">true</span>`],
[`1`, `<span class="num">1</span>`],
[
`[1,2,"thr<h1>ee"]`,
`<span class="collapser"></span>[<ul class="array collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="num">1</span>,</li><li><span class="spacer">&nbsp;&nbsp;</span><span class="num">2</span>,</li><li><span class="spacer">&nbsp;&nbsp;</span><span class="string">&quot;thr&lt;h1&gt;ee&quot;</span></li></ul><span class="spacer"></span>]`,
],
[
`{"hey": "g'uy'"}`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.hey"><span class="q">&quot;</span>hey<span class="q">&quot;</span></span>: <span class="string">&quot;g&apos;uy&apos;&quot;</span></li></ul><span class="spacer"></span>}`,
],
[
`{ "value":[ { "@some.text":"W/\\"12241774\\"" } ] }`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.value"><span class="q">&quot;</span>value<span class="q">&quot;</span></span>: <span class="collapser"></span>[<ul class="array collapsible"><li><span class="spacer">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="prop quoted" title=""><span class="q">&quot;</span>@some.text<span class="q">&quot;</span></span>: <span class="string">&quot;W/\\&quot;12241774\\&quot;&quot;</span></li></ul><span class="spacer">&nbsp;&nbsp;&nbsp;&nbsp;</span>}</li></ul><span class="spacer">&nbsp;&nbsp;</span>]</li></ul><span class="spacer"></span>}`,
],
[
`{"key":"\\"value\\u201d"}`,
`<span class="collapser"></span>{<ul class="obj collapsible"><li><span class="spacer">&nbsp;&nbsp;</span><span class="prop" title="&lt;root&gt;.key"><span class="q">&quot;</span>key<span class="q">&quot;</span></span>: <span class="string">&quot;\\&quot;value”&quot;</span></li></ul><span class="spacer"></span>}`,
],
];

Object.defineProperties(globalThis, {
chrome: {
value: {
i18n: {
getMessage: (message: string) => message,
},
runtime: {
getURL: (url: string) => url,
},
},
},
});

for (const [content, result] of jsonContent) {
test(`valueToHTML ${content}`, () => {
assert.equal(valueToHTML(JSON.parse(safeStringEncodeNums(content)), "<root>", 0), result);
});
}
6 changes: 3 additions & 3 deletions src/jsonformatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ function decorateWithSpan(value: any, className: string) {
}

// Convert a basic JSON datatype (number, string, boolean, null, object, array) into an HTML fragment.
function valueToHTML(value: any, path: string, indent: number) {
export function valueToHTML(value: any, path: string, indent: number) {
if (value === null) {
return decorateWithSpan("null", "null");
} else if (Array.isArray(value)) {
Expand All @@ -89,8 +89,8 @@ function valueToHTML(value: any, path: string, indent: number) {
case "boolean":
return decorateWithSpan(value, "bool");
case "string":
if (value.charCodeAt(0) === 8203 && !isNaN(parseInt(value.slice(1), 10))) {
return decorateWithSpan(parseInt(value.slice(1), 10), "num");
if (value.charCodeAt(0) === 8203 /* zero-width space */ && !isNaN(Number(value.slice(1)))) {
return decorateWithSpan(Number(value.slice(1)), "num");
} else if (/^(http|https|file):\/\/[^\s]+$/i.test(value)) {
return `<a href="${htmlEncode(value)}"><span class="q">&quot;</span>${jsString(
value
Expand Down
2 changes: 1 addition & 1 deletion src/manifest.chrome.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "JSONView",
"version": "3.0.0",
"version": "3.0.1",
"description": "__MSG_extensionDescription__",
"author": "Benjamin Hollis",
"homepage_url": "https://jsonview.com/",
Expand Down
7 changes: 6 additions & 1 deletion src/manifest.firefox.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "JSONView",
"version": "3.0.0",
"version": "3.0.1",
"description": "__MSG_extensionDescription__",
"author": "Benjamin Hollis",
"homepage_url": "https://jsonview.com/",
Expand All @@ -12,6 +12,11 @@
"128": "icon128.png",
"256": "icon256.png"
},
"browser_specific_settings": {
"gecko": {
"id": "[email protected]"
}
},
"background": {
"scripts": ["background.js"],
"type": "module"
Expand Down

0 comments on commit a10aae5

Please sign in to comment.