From 8283935a262aaac9353a0249b5de46e3b19c16c9 Mon Sep 17 00:00:00 2001 From: Ben Hollis Date: Wed, 3 May 2023 11:51:06 -0700 Subject: [PATCH] Simplify json global value --- src/content.ts | 23 ++++------- src/jsonformatter.ts | 94 +++++++++++++++++++++++++------------------- 2 files changed, 61 insertions(+), 56 deletions(-) diff --git a/src/content.ts b/src/content.ts index 5f7a24b..f084fdb 100644 --- a/src/content.ts +++ b/src/content.ts @@ -3,23 +3,16 @@ import { errorPage, jsonToHTML } from "./jsonformatter"; import { installCollapseEventListeners } from "./collapse"; import { safeStringEncodeNums } from "./safe-encode-numbers"; -function setJsonAsGlobalVariable(jsonObj: JSON) { +function setJsonAsGlobalVariable(this: any, jsonObj: any) { const script = document.createElement("script"); - const jsonStr = JSON.stringify(jsonObj).replace(/\\/g, "\\\\"); - script.text = `window.data=JSON.parse('${jsonStr}');`; + script.text = `Object.defineProperty(window, 'data', { value: ${JSON.stringify( + jsonObj + )}, writable: false, configurable: false });`; document.documentElement.appendChild(script); // log info message // with this queueMicrotask user can not see source file information in log - queueMicrotask(() => - console.log( - "%c%s%c%s", - "color: green; font-size: 16px;", - "JSON is exposed as variable called ", - "background-color: rgba(175, 184, 193, 0.2); font-size: 16px; margin: 0; padding: 0.2em 0.4em; border-radius: 6px", - "data" - ) - ); + queueMicrotask(() => console.log('JSON is exposed as a global variable called "data"')); } /** @@ -34,15 +27,14 @@ chrome.runtime.sendMessage({}, (response: boolean) => { // At least in chrome, the JSON is wrapped in a pre tag. const content = document.getElementsByTagName("pre")[0].textContent; let outputDoc = ""; + let jsonObj = null; if (content === null) { outputDoc = errorPage(new Error("No content"), "", document.URL); } else { try { - const jsonObj = JSON.parse(safeStringEncodeNums(content)); + jsonObj = JSON.parse(safeStringEncodeNums(content)); outputDoc = jsonToHTML(jsonObj, document.URL); - - setJsonAsGlobalVariable(jsonObj); } catch (e: any) { outputDoc = errorPage( e instanceof Error ? e : new Error(e.toString()), @@ -54,4 +46,5 @@ chrome.runtime.sendMessage({}, (response: boolean) => { document.documentElement.innerHTML = outputDoc; installCollapseEventListeners(); + setJsonAsGlobalVariable(jsonObj); }); diff --git a/src/jsonformatter.ts b/src/jsonformatter.ts index f1d1602..58c29c3 100644 --- a/src/jsonformatter.ts +++ b/src/jsonformatter.ts @@ -10,12 +10,12 @@ export function jsonToHTML(json: any, uri: string) { /** Convert a whole JSON value / JSONP response into an HTML body, without title and scripts */ function jsonToHTMLBody(json: any) { - return `
${valueToHTML(json, '')}
`; + return `
${valueToHTML(json, "")}
`; } /** Produce an error document for when parsing fails. */ export function errorPage(error: Error, data: string, uri: string) { - return toHTML(errorPageBody(error, data), uri + ' - Error'); + return toHTML(errorPageBody(error, data), uri + " - Error"); } /** Produce an error content for when parsing fails. */ @@ -25,7 +25,7 @@ function errorPageBody(error: Error, data: string) { const errorInfo = massageError(error); - let output = `
${chrome.i18n.getMessage('errorParsing')}`; + let output = `
${chrome.i18n.getMessage("errorParsing")}`; if (errorInfo.message) { output += `
${errorInfo.message}
`; } @@ -37,13 +37,15 @@ function errorPageBody(error: Error, data: string) { * Encode a string to be used in HTML */ function htmlEncode(t: any): string { - return (typeof t !== "undefined" && t !== null) ? t.toString() - .replace(/&/g, "&") - .replace(/"/g, """) - .replace(/'/g, "'") - .replace(//g, ">") - : ''; + return typeof t !== "undefined" && t !== null + ? t + .toString() + .replace(/&/g, "&") + .replace(/"/g, """) + .replace(/'/g, "'") + .replace(//g, ">") + : ""; } /** @@ -74,59 +76,61 @@ function valueToHTML(value: any, path: string) { const valueType = typeof value; if (value === null) { - return decorateWithSpan('null', 'null'); + return decorateWithSpan("null", "null"); } else if (Array.isArray(value)) { return arrayToHTML(value, path); - } else if (valueType === 'object') { + } else if (valueType === "object") { return objectToHTML(value, path); - } else if (valueType === 'number') { - return decorateWithSpan(value, 'num'); - } else if (valueType === 'string' && - value.charCodeAt(0) === 8203 && - !isNaN(value.slice(1))) { - return decorateWithSpan(value.slice(1), 'num'); - } else if (valueType === 'string') { + } else if (valueType === "number") { + return decorateWithSpan(value, "num"); + } else if (valueType === "string" && value.charCodeAt(0) === 8203 && !isNaN(value.slice(1))) { + return decorateWithSpan(value.slice(1), "num"); + } else if (valueType === "string") { if (/^(http|https|file):\/\/[^\s]+$/i.test(value)) { - return `"${jsString(value)}"`; + return `"${jsString( + value + )}"`; } else { return `"${jsString(value)}"`; } - } else if (valueType === 'boolean') { - return decorateWithSpan(value, 'bool'); + } else if (valueType === "boolean") { + return decorateWithSpan(value, "bool"); } - return ''; + return ""; } // Convert an array into an HTML fragment function arrayToHTML(json: any, path: string) { if (json.length === 0) { - return '[ ]'; + return "[ ]"; } - let output = ''; + let output = ""; for (let i = 0; i < json.length; i++) { const subPath = `${path}[${i}]`; - output += '
  • ' + valueToHTML(json[i], subPath); + output += "
  • " + valueToHTML(json[i], subPath); if (i < json.length - 1) { - output += ','; + output += ","; } - output += '
  • '; + output += ""; } - return (json.length === 0 ? '' : '') + - `[
      ${output}
    ]`; + return ( + (json.length === 0 ? "" : '') + + `[
      ${output}
    ]` + ); } // Convert a JSON object to an HTML fragment function objectToHTML(json: any, path: string) { let numProps = Object.keys(json).length; if (numProps === 0) { - return '{ }'; + return "{ }"; } - let output = ''; + let output = ""; for (const prop in json) { - let subPath = ''; + let subPath = ""; let escapedProp = JSON.stringify(prop).slice(1, -1); const bare = isBareProp(prop); if (bare) { @@ -134,11 +138,15 @@ function objectToHTML(json: any, path: string) { } else { escapedProp = `"${escapedProp}"`; } - output += `
  • "${jsString(prop)}": ${valueToHTML(json[prop], subPath)}`; + output += `
  • "${jsString( + prop + )}": ${valueToHTML(json[prop], subPath)}`; if (numProps > 1) { - output += ','; + output += ","; } - output += '
  • '; + output += ""; numProps--; } @@ -155,7 +163,7 @@ function massageError(error: Error): { return error; } - const message = error.message.replace(/^JSON.parse: /, '').replace(/of the JSON data/, ''); + const message = error.message.replace(/^JSON.parse: /, "").replace(/of the JSON data/, ""); const parts = /line (\d+) column (\d+)/.exec(message); if (!parts || parts.length !== 3) { return error; @@ -164,7 +172,7 @@ function massageError(error: Error): { return { message: htmlEncode(message), line: Number(parts[1]), - column: Number(parts[2]) + column: Number(parts[2]), }; } @@ -175,14 +183,18 @@ function highlightError(data: string, lineNum?: number, columnNum?: number) { const lines = data.match(/^.*((\r\n|\n|\r)|$)/gm)!; - let output = ''; + let output = ""; for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (i === lineNum - 1) { output += ''; - output += `${htmlEncode(line.substring(0, columnNum - 1))}${htmlEncode(line[columnNum - 1])}${htmlEncode(line.substring(columnNum))}`; - output += ''; + output += `${htmlEncode( + line.substring(0, columnNum - 1) + )}${htmlEncode(line[columnNum - 1])}${htmlEncode( + line.substring(columnNum) + )}`; + output += ""; } else { output += htmlEncode(line); }