|
@@ -487,289 +487,13 @@ window.Formatter = (function () {
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
- // 创建内联Worker
|
|
|
- // 这个版本包含基本的JSON格式化功能
|
|
|
- let workerCode = `
|
|
|
- // 创建一个处理BigInt的JSON解析器
|
|
|
- const JSONBigInt = {
|
|
|
- // 自定义的parse方法,处理大数字
|
|
|
- parse: function(text) {
|
|
|
- // 先尝试预处理字符串,将可能的大整数标记出来
|
|
|
- // 以更精确的方式匹配JSON中的大整数
|
|
|
- const preparedText = this._markBigInts(text);
|
|
|
-
|
|
|
- try {
|
|
|
- // 使用标准JSON解析,同时使用reviver函数还原BigInt
|
|
|
- return JSON.parse(preparedText, this._reviver);
|
|
|
- } catch (e) {
|
|
|
- // 如果处理失败,尝试原始解析方式
|
|
|
- console.error('BigInt处理失败,回退到标准解析', e);
|
|
|
- return JSON.parse(text);
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- // 将JSON字符串中的大整数标记为特殊格式
|
|
|
- _markBigInts: function(text) {
|
|
|
- // 这个正则匹配JSON中的数字,但需要避免匹配到引号内的字符串
|
|
|
- // 匹配模式: 找到数字前面是冒号或左方括号的情况(表示这是个值而不是键名)
|
|
|
- return text.replace(
|
|
|
- /([:,\\[]\\s*)(-?\\d{16,})([,\\]\\}])/g,
|
|
|
- function(match, prefix, number, suffix) {
|
|
|
- // 将大数字转换为特殊格式的字符串
|
|
|
- return prefix + '"__BigInt__' + number + '"' + suffix;
|
|
|
- }
|
|
|
- );
|
|
|
- },
|
|
|
-
|
|
|
- // 恢复函数,将标记的BigInt字符串转回BigInt类型
|
|
|
- _reviver: function(key, value) {
|
|
|
- // 检查是否是我们标记的BigInt字符串
|
|
|
- if (typeof value === 'string' && value.startsWith('__BigInt__')) {
|
|
|
- // 提取数字部分
|
|
|
- const numStr = value.substring(10);
|
|
|
- try {
|
|
|
- // 尝试转换为BigInt
|
|
|
- return BigInt(numStr);
|
|
|
- } catch (e) {
|
|
|
- // 如果转换失败,保留原始字符串
|
|
|
- console.warn('无法转换为BigInt:', numStr);
|
|
|
- return numStr;
|
|
|
- }
|
|
|
- }
|
|
|
- return value;
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- // 处理主线程消息
|
|
|
- self.onmessage = function(event) {
|
|
|
-
|
|
|
- // 格式化JSON
|
|
|
- if (event.data.jsonString) {
|
|
|
- // 发送格式化中的消息
|
|
|
- self.postMessage(['FORMATTING']);
|
|
|
-
|
|
|
- try {
|
|
|
- // 先预处理JSON字符串,防止大整数丢失精度
|
|
|
- let jsonObj;
|
|
|
-
|
|
|
- try {
|
|
|
- // 尝试使用自定义的BigInt解析器
|
|
|
- jsonObj = JSONBigInt.parse(event.data.jsonString);
|
|
|
- } catch (e) {
|
|
|
- // 如果解析失败,回退到标准解析
|
|
|
- console.error('BigInt解析失败,回退到标准解析', e);
|
|
|
- jsonObj = JSON.parse(event.data.jsonString);
|
|
|
- }
|
|
|
-
|
|
|
- // 如果是简单主题,直接返回格式化的JSON
|
|
|
- if (event.data.skin && event.data.skin === 'theme-simple') {
|
|
|
- // 处理BigInt特殊情况
|
|
|
- let formatted = JSON.stringify(jsonObj, function(key, value) {
|
|
|
- if (typeof value === 'bigint') {
|
|
|
- // 移除n后缀,只显示数字本身
|
|
|
- return value.toString();
|
|
|
- }
|
|
|
- // 处理普通数字,避免科学计数法
|
|
|
- if (typeof value === 'number' && value.toString().includes('e')) {
|
|
|
- // 大数字转为字符串以避免科学计数法
|
|
|
- return value.toLocaleString('fullwide', {useGrouping: false});
|
|
|
- }
|
|
|
- return value;
|
|
|
- }, 4);
|
|
|
-
|
|
|
- let html = '<div id="formattedJson"><pre class="rootItem">' +
|
|
|
- formatted.replace(/&/g, '&')
|
|
|
- .replace(/</g, '<')
|
|
|
- .replace(/>/g, '>')
|
|
|
- .replace(/"/g, '"')
|
|
|
- .replace(/'/g, ''') +
|
|
|
- '</pre></div>';
|
|
|
-
|
|
|
- self.postMessage(['FORMATTED', html]);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 默认主题 - 创建更丰富的HTML结构
|
|
|
- let html = '<div id="formattedJson">' +
|
|
|
- formatJsonToHtml(jsonObj) +
|
|
|
- '</div>';
|
|
|
-
|
|
|
- self.postMessage(['FORMATTED', html]);
|
|
|
- } catch (e) {
|
|
|
- // 处理错误情况
|
|
|
- self.postMessage(['FORMATTED', '<div id="formattedJson"><div class="error">格式化失败: ' + e.message + '</div></div>']);
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- // HTML特殊字符格式化
|
|
|
- function htmlspecialchars(str) {
|
|
|
- str = str.replace(/&/g, '&');
|
|
|
- str = str.replace(/</g, '<');
|
|
|
- str = str.replace(/>/g, '>');
|
|
|
- str = str.replace(/"/g, '"');
|
|
|
- str = str.replace(/'/g, ''');
|
|
|
- return str;
|
|
|
- }
|
|
|
-
|
|
|
- // 格式化JSON为HTML
|
|
|
- function formatJsonToHtml(json) {
|
|
|
- return createNode(json).getHTML();
|
|
|
- }
|
|
|
-
|
|
|
- // 创建节点
|
|
|
- function createNode(value) {
|
|
|
- let node = {
|
|
|
- type: getType(value),
|
|
|
- value: value,
|
|
|
- children: [],
|
|
|
-
|
|
|
- getHTML: function() {
|
|
|
- switch(this.type) {
|
|
|
- case 'string':
|
|
|
- return '<div class="item item-line"><span class="string">"' +
|
|
|
- htmlspecialchars(this.value) +
|
|
|
- '"</span></div>';
|
|
|
- case 'number':
|
|
|
- // 确保大数字不使用科学计数法
|
|
|
- let numStr = typeof this.value === 'number' && this.value.toString().includes('e')
|
|
|
- ? this.value.toLocaleString('fullwide', {useGrouping: false})
|
|
|
- : this.value;
|
|
|
- return '<div class="item item-line"><span class="number">' +
|
|
|
- numStr +
|
|
|
- '</span></div>';
|
|
|
- case 'bigint':
|
|
|
- // 对BigInt类型特殊处理,只显示数字,不添加n后缀
|
|
|
- return '<div class="item item-line"><span class="number">' +
|
|
|
- this.value.toString() +
|
|
|
- '</span></div>';
|
|
|
- case 'boolean':
|
|
|
- return '<div class="item item-line"><span class="bool">' +
|
|
|
- this.value +
|
|
|
- '</span></div>';
|
|
|
- case 'null':
|
|
|
- return '<div class="item item-line"><span class="null">null</span></div>';
|
|
|
- case 'object':
|
|
|
- return this.getObjectHTML();
|
|
|
- case 'array':
|
|
|
- return this.getArrayHTML();
|
|
|
- default:
|
|
|
- return '';
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- getObjectHTML: function() {
|
|
|
- if (!this.value || Object.keys(this.value).length === 0) {
|
|
|
- return '<div class="item item-object"><span class="brace">{</span><span class="brace">}</span></div>';
|
|
|
- }
|
|
|
-
|
|
|
- let html = '<div class="item item-object">' +
|
|
|
- '<span class="expand"></span>' +
|
|
|
- '<span class="brace">{</span>' +
|
|
|
- '<span class="ellipsis"></span>' +
|
|
|
- '<div class="kv-list">';
|
|
|
-
|
|
|
- let keys = Object.keys(this.value);
|
|
|
- keys.forEach((key, index) => {
|
|
|
- let prop = this.value[key];
|
|
|
- let childNode = createNode(prop);
|
|
|
-
|
|
|
- html += '<div class="item">' +
|
|
|
- '<span class="quote">"</span>' +
|
|
|
- '<span class="key">' + htmlspecialchars(key) + '</span>' +
|
|
|
- '<span class="quote">"</span>' +
|
|
|
- '<span class="colon">: </span>';
|
|
|
-
|
|
|
- // 添加值
|
|
|
- if (childNode.type === 'object' || childNode.type === 'array') {
|
|
|
- html += childNode.getHTML();
|
|
|
- } else {
|
|
|
- html += childNode.getHTML().replace(/^<div class="item item-line">/, '').replace(/<\\/div>$/, '');
|
|
|
- }
|
|
|
-
|
|
|
- // 如果不是最后一个属性,添加逗号
|
|
|
- if (index < keys.length - 1) {
|
|
|
- html += '<span class="comma">,</span>';
|
|
|
- }
|
|
|
-
|
|
|
- html += '</div>';
|
|
|
- });
|
|
|
-
|
|
|
- html += '</div><span class="brace">}</span></div>';
|
|
|
- return html;
|
|
|
- },
|
|
|
-
|
|
|
- getArrayHTML: function() {
|
|
|
- if (!this.value || this.value.length === 0) {
|
|
|
- return '<div class="item item-array"><span class="brace">[</span><span class="brace">]</span></div>';
|
|
|
- }
|
|
|
-
|
|
|
- let html = '<div class="item item-array">' +
|
|
|
- '<span class="expand"></span>' +
|
|
|
- '<span class="brace">[</span>' +
|
|
|
- '<span class="ellipsis"></span>' +
|
|
|
- '<div class="kv-list">';
|
|
|
-
|
|
|
- this.value.forEach((item, index) => {
|
|
|
- let childNode = createNode(item);
|
|
|
-
|
|
|
- html += '<div class="item item-block">';
|
|
|
-
|
|
|
- // 添加值
|
|
|
- if (childNode.type === 'object' || childNode.type === 'array') {
|
|
|
- html += childNode.getHTML();
|
|
|
- } else {
|
|
|
- html += childNode.getHTML().replace(/^<div class="item item-line">/, '').replace(/<\\/div>$/, '');
|
|
|
- }
|
|
|
-
|
|
|
- // 如果不是最后一个元素,添加逗号
|
|
|
- if (index < this.value.length - 1) {
|
|
|
- html += '<span class="comma">,</span>';
|
|
|
- }
|
|
|
-
|
|
|
- html += '</div>';
|
|
|
- });
|
|
|
-
|
|
|
- html += '</div><span class="brace">]</span></div>';
|
|
|
- return html;
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- return node;
|
|
|
- }
|
|
|
-
|
|
|
- // 获取值类型
|
|
|
- function getType(value) {
|
|
|
- if (value === null) return 'null';
|
|
|
- if (value === undefined) return 'undefined';
|
|
|
-
|
|
|
- let type = typeof value;
|
|
|
- // 特别处理BigInt类型
|
|
|
- if (type === 'bigint') return 'bigint';
|
|
|
- if (type === 'object') {
|
|
|
- if (Array.isArray(value)) return 'array';
|
|
|
- }
|
|
|
- return type;
|
|
|
- }
|
|
|
- `;
|
|
|
-
|
|
|
- // 创建Blob URL并实例化Worker
|
|
|
- let blob = new Blob([workerCode], {type: 'application/javascript'});
|
|
|
- let workerUrl = URL.createObjectURL(blob);
|
|
|
-
|
|
|
+ // 统一使用扩展内的脚本文件创建Worker
|
|
|
+ let workerUrl = chrome.runtime.getURL('json-format/json-worker.js');
|
|
|
workerInstance = new Worker(workerUrl);
|
|
|
|
|
|
- // 添加错误处理
|
|
|
- workerInstance.onerror = function(e) {
|
|
|
- // 如果Worker出错,清空实例允许下次重试
|
|
|
- workerInstance = null;
|
|
|
-
|
|
|
- // 避免URL内存泄漏
|
|
|
- URL.revokeObjectURL(workerUrl);
|
|
|
- };
|
|
|
-
|
|
|
return workerInstance;
|
|
|
} catch (e) {
|
|
|
+ console.error('创建Worker失败:', e);
|
|
|
// 出现任何错误,返回null
|
|
|
workerInstance = null;
|
|
|
return null;
|
|
@@ -785,38 +509,44 @@ window.Formatter = (function () {
|
|
|
_initElements();
|
|
|
jfPre.html(htmlspecialchars(cachedJsonString));
|
|
|
|
|
|
- // 获取Worker实例
|
|
|
- let worker = _getWorkerInstance();
|
|
|
-
|
|
|
- if (worker) {
|
|
|
- // 设置消息处理程序
|
|
|
- worker.onmessage = function (evt) {
|
|
|
- let msg = evt.data;
|
|
|
- switch (msg[0]) {
|
|
|
- case 'FORMATTING':
|
|
|
- formattingMsg.show();
|
|
|
- break;
|
|
|
-
|
|
|
- case 'FORMATTED':
|
|
|
- formattingMsg.hide();
|
|
|
- jfContent.html(msg[1]);
|
|
|
-
|
|
|
- _buildOptionBar();
|
|
|
- // 事件绑定
|
|
|
- _addEvents();
|
|
|
- // 支持文件下载
|
|
|
- _downloadSupport(cachedJsonString);
|
|
|
- break;
|
|
|
- }
|
|
|
- };
|
|
|
+ try {
|
|
|
+ // 获取Worker实例
|
|
|
+ let worker = _getWorkerInstance();
|
|
|
|
|
|
- // 发送格式化请求
|
|
|
- worker.postMessage({
|
|
|
- jsonString: jsonStr,
|
|
|
- skin: skin
|
|
|
- });
|
|
|
- } else {
|
|
|
- // Worker创建失败,回退到同步方式
|
|
|
+ if (worker) {
|
|
|
+ // 设置消息处理程序
|
|
|
+ worker.onmessage = function (evt) {
|
|
|
+ let msg = evt.data;
|
|
|
+ switch (msg[0]) {
|
|
|
+ case 'FORMATTING':
|
|
|
+ formattingMsg.show();
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'FORMATTED':
|
|
|
+ formattingMsg.hide();
|
|
|
+ jfContent.html(msg[1]);
|
|
|
+
|
|
|
+ _buildOptionBar();
|
|
|
+ // 事件绑定
|
|
|
+ _addEvents();
|
|
|
+ // 支持文件下载
|
|
|
+ _downloadSupport(cachedJsonString);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 发送格式化请求
|
|
|
+ worker.postMessage({
|
|
|
+ jsonString: jsonStr,
|
|
|
+ skin: skin
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // Worker创建失败,回退到同步方式
|
|
|
+ formatSync(jsonStr, skin);
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('Worker处理失败:', e);
|
|
|
+ // 出现任何错误,回退到同步方式
|
|
|
formatSync(jsonStr, skin);
|
|
|
}
|
|
|
};
|
|
@@ -863,3 +593,4 @@ window.Formatter = (function () {
|
|
|
|
|
|
|
|
|
|
|
|
+
|