json-worker.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. // 创建一个处理BigInt的JSON解析器
  2. const JSONBigInt = {
  3. // 自定义的parse方法,处理大数字
  4. parse: function(text) {
  5. // 先尝试预处理字符串,将可能的大整数标记出来
  6. // 以更精确的方式匹配JSON中的大整数
  7. const preparedText = this._markBigInts(text);
  8. try {
  9. // 使用标准JSON解析,同时使用reviver函数还原BigInt
  10. return JSON.parse(preparedText, this._reviver);
  11. } catch (e) {
  12. // 如果处理失败,尝试原始解析方式
  13. console.error('BigInt处理失败,回退到标准解析', e);
  14. return JSON.parse(text);
  15. }
  16. },
  17. // 将JSON字符串中的大整数标记为特殊格式
  18. _markBigInts: function(text) {
  19. // 这个正则匹配JSON中的数字,但需要避免匹配到引号内的字符串
  20. // 匹配模式: 找到数字前面是冒号或左方括号的情况(表示这是个值而不是键名)
  21. return text.replace(
  22. /([:,\[]\s*)(-?\d{16,})([,\]\}])/g,
  23. function(match, prefix, number, suffix) {
  24. // 将大数字转换为特殊格式的字符串
  25. return prefix + '"__BigInt__' + number + '"' + suffix;
  26. }
  27. );
  28. },
  29. // 恢复函数,将标记的BigInt字符串转回BigInt类型
  30. _reviver: function(key, value) {
  31. // 检查是否是我们标记的BigInt字符串
  32. if (typeof value === 'string' && value.startsWith('__BigInt__')) {
  33. // 提取数字部分
  34. const numStr = value.substring(10);
  35. try {
  36. // 尝试转换为BigInt
  37. return BigInt(numStr);
  38. } catch (e) {
  39. // 如果转换失败,保留原始字符串
  40. console.warn('无法转换为BigInt:', numStr);
  41. return numStr;
  42. }
  43. }
  44. return value;
  45. }
  46. };
  47. // 处理主线程消息
  48. self.onmessage = function(event) {
  49. // 格式化JSON
  50. if (event.data.jsonString) {
  51. // 发送格式化中的消息
  52. self.postMessage(['FORMATTING']);
  53. try {
  54. // 先预处理JSON字符串,防止大整数丢失精度
  55. let jsonObj;
  56. try {
  57. // 尝试使用自定义的BigInt解析器
  58. jsonObj = JSONBigInt.parse(event.data.jsonString);
  59. } catch (e) {
  60. // 如果解析失败,回退到标准解析
  61. console.error('BigInt解析失败,回退到标准解析', e);
  62. jsonObj = JSON.parse(event.data.jsonString);
  63. }
  64. // 如果是简单主题,直接返回格式化的JSON
  65. if (event.data.skin && event.data.skin === 'theme-simple') {
  66. // 处理BigInt特殊情况
  67. let formatted = JSON.stringify(jsonObj, function(key, value) {
  68. if (typeof value === 'bigint') {
  69. // 移除n后缀,只显示数字本身
  70. return value.toString();
  71. }
  72. // 处理普通数字,避免科学计数法
  73. if (typeof value === 'number' && value.toString().includes('e')) {
  74. // 大数字转为字符串以避免科学计数法
  75. return value.toLocaleString('fullwide', {useGrouping: false});
  76. }
  77. return value;
  78. }, 4);
  79. let html = '<div id="formattedJson"><pre class="rootItem">' +
  80. formatted.replace(/&/g, '&amp;')
  81. .replace(/</g, '&lt;')
  82. .replace(/>/g, '&gt;')
  83. .replace(/"/g, '&quot;')
  84. .replace(/'/g, '&#039;') +
  85. '</pre></div>';
  86. self.postMessage(['FORMATTED', html]);
  87. return;
  88. }
  89. // 默认主题 - 创建更丰富的HTML结构
  90. let html = '<div id="formattedJson">' +
  91. formatJsonToHtml(jsonObj) +
  92. '</div>';
  93. self.postMessage(['FORMATTED', html]);
  94. } catch (e) {
  95. // 处理错误情况
  96. self.postMessage(['FORMATTED', '<div id="formattedJson"><div class="error">格式化失败: ' + e.message + '</div></div>']);
  97. }
  98. }
  99. };
  100. // HTML特殊字符格式化
  101. function htmlspecialchars(str) {
  102. str = str.replace(/&/g, '&amp;');
  103. str = str.replace(/</g, '&lt;');
  104. str = str.replace(/>/g, '&gt;');
  105. str = str.replace(/"/g, '&quot;');
  106. str = str.replace(/'/g, '&#039;');
  107. return str;
  108. }
  109. // 格式化JSON为HTML
  110. function formatJsonToHtml(json) {
  111. return createNode(json).getHTML();
  112. }
  113. // 创建节点
  114. function createNode(value) {
  115. let node = {
  116. type: getType(value),
  117. value: value,
  118. children: [],
  119. getHTML: function() {
  120. switch(this.type) {
  121. case 'string':
  122. return '<div class="item item-line"><span class="string">"' +
  123. htmlspecialchars(this.value) +
  124. '"</span></div>';
  125. case 'number':
  126. // 确保大数字不使用科学计数法
  127. let numStr = typeof this.value === 'number' && this.value.toString().includes('e')
  128. ? this.value.toLocaleString('fullwide', {useGrouping: false})
  129. : this.value;
  130. return '<div class="item item-line"><span class="number">' +
  131. numStr +
  132. '</span></div>';
  133. case 'bigint':
  134. // 对BigInt类型特殊处理,只显示数字,不添加n后缀
  135. return '<div class="item item-line"><span class="number">' +
  136. this.value.toString() +
  137. '</span></div>';
  138. case 'boolean':
  139. return '<div class="item item-line"><span class="bool">' +
  140. this.value +
  141. '</span></div>';
  142. case 'null':
  143. return '<div class="item item-line"><span class="null">null</span></div>';
  144. case 'object':
  145. return this.getObjectHTML();
  146. case 'array':
  147. return this.getArrayHTML();
  148. default:
  149. return '';
  150. }
  151. },
  152. getObjectHTML: function() {
  153. if (!this.value || Object.keys(this.value).length === 0) {
  154. return '<div class="item item-object"><span class="brace">{</span><span class="brace">}</span></div>';
  155. }
  156. let html = '<div class="item item-object">' +
  157. '<span class="expand"></span>' +
  158. '<span class="brace">{</span>' +
  159. '<span class="ellipsis"></span>' +
  160. '<div class="kv-list">';
  161. let keys = Object.keys(this.value);
  162. keys.forEach((key, index) => {
  163. let prop = this.value[key];
  164. let childNode = createNode(prop);
  165. html += '<div class="item">' +
  166. '<span class="quote">"</span>' +
  167. '<span class="key">' + htmlspecialchars(key) + '</span>' +
  168. '<span class="quote">"</span>' +
  169. '<span class="colon">: </span>';
  170. // 添加值
  171. if (childNode.type === 'object' || childNode.type === 'array') {
  172. html += childNode.getHTML();
  173. } else {
  174. html += childNode.getHTML().replace(/^<div class="item item-line">/, '').replace(/<\/div>$/, '');
  175. }
  176. // 如果不是最后一个属性,添加逗号
  177. if (index < keys.length - 1) {
  178. html += '<span class="comma">,</span>';
  179. }
  180. html += '</div>';
  181. });
  182. html += '</div><span class="brace">}</span></div>';
  183. return html;
  184. },
  185. getArrayHTML: function() {
  186. if (!this.value || this.value.length === 0) {
  187. return '<div class="item item-array"><span class="brace">[</span><span class="brace">]</span></div>';
  188. }
  189. let html = '<div class="item item-array">' +
  190. '<span class="expand"></span>' +
  191. '<span class="brace">[</span>' +
  192. '<span class="ellipsis"></span>' +
  193. '<div class="kv-list">';
  194. this.value.forEach((item, index) => {
  195. let childNode = createNode(item);
  196. html += '<div class="item item-block">';
  197. // 添加值
  198. if (childNode.type === 'object' || childNode.type === 'array') {
  199. html += childNode.getHTML();
  200. } else {
  201. html += childNode.getHTML().replace(/^<div class="item item-line">/, '').replace(/<\/div>$/, '');
  202. }
  203. // 如果不是最后一个元素,添加逗号
  204. if (index < this.value.length - 1) {
  205. html += '<span class="comma">,</span>';
  206. }
  207. html += '</div>';
  208. });
  209. html += '</div><span class="brace">]</span></div>';
  210. return html;
  211. }
  212. };
  213. return node;
  214. }
  215. // 获取值类型
  216. function getType(value) {
  217. if (value === null) return 'null';
  218. if (value === undefined) return 'undefined';
  219. let type = typeof value;
  220. // 特别处理BigInt类型
  221. if (type === 'bigint') return 'bigint';
  222. if (type === 'object') {
  223. if (Array.isArray(value)) return 'array';
  224. }
  225. return type;
  226. }