From 4072b24cef4a2361662e94a9536aa98961bdc4d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Fri, 13 Dec 2024 14:37:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=89=A9=E7=BC=96json?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E7=BB=86=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/editorTable/editorData.ts | 32 +++++----- src/editorTable/editorJson.ts | 106 +++++++++++++++++++++------------- src/tools/json.ts | 58 ++++++++++--------- 3 files changed, 114 insertions(+), 82 deletions(-) diff --git a/src/editorTable/editorData.ts b/src/editorTable/editorData.ts index 53789f8..579bc7b 100644 --- a/src/editorTable/editorData.ts +++ b/src/editorTable/editorData.ts @@ -51,7 +51,7 @@ interface KVShape { prop_cls: "PText"|"PBool"|"PFloat"|"PInt", remark: string, show_in_attr: boolean, - sort: number, + sort: bigint, type: keyof typeof Table.type.type, value: string|number|boolean, } @@ -59,7 +59,7 @@ interface KVShape { function fromKV(kvMap: Record): KV { let result: Record = {}; // 按照 sort 字段的值排序,然后将重新组成 { K: V.value } 的形式 - let kvList = Object.values(kvMap).sort((a, b) => a.sort - b.sort); + let kvList = Object.values(kvMap).sort((a, b) => Number(a.sort - b.sort)); for (let kv of kvList) { result[kv.key] = kv.value; } @@ -75,26 +75,24 @@ function toKV(kv: KV, raw: Record): Record { ...result[key], value, }; - sort = Math.max(sort, result[key].sort); + sort = Math.max(sort, Number(result[key].sort)); } else { let etype, type, prop_cls; if (typeof value === 'string') { - etype = 0; - type = 0; + etype = 0n; + type = 0n; prop_cls = 'PText'; } else if (typeof value === 'number') { - if (Number.isInteger(value)) { - etype = 1; - type = 2; - prop_cls = 'PInt'; - } else { - etype = 2; - type = 1; - prop_cls = 'PFloat'; - } + etype = 2n; + type = 1n; + prop_cls = 'PFloat'; + } else if (typeof value === 'bigint') { + etype = 1n; + type = 2n; + prop_cls = 'PInt'; } else if (typeof value === 'boolean') { - etype = 4; - type = 3; + etype = 4n; + type = 3n; prop_cls = 'PBool'; } else { continue; @@ -107,7 +105,7 @@ function toKV(kv: KV, raw: Record): Record { prop_cls: prop_cls as any, remark: '', show_in_attr: false, - sort: ++sort, + sort: BigInt(++sort), type: type as any, value, }; diff --git a/src/editorTable/editorJson.ts b/src/editorTable/editorJson.ts index d87d6c5..7e2261b 100644 --- a/src/editorTable/editorJson.ts +++ b/src/editorTable/editorJson.ts @@ -1,52 +1,80 @@ -import * as jsonc from 'jsonc-parser'; import * as y3 from 'y3-helper'; import { Json } from '../tools/json'; +import * as jsonc from 'jsonc-parser'; -const jsonFormatOptions: y3.json.formatOptions = { - stringify: (value) => { - if (typeof value === 'bigint') { +function stringify(value: any, tabLevel = 0): string { + switch (typeof value) { + case 'bigint': { return value.toString(); - } - if (typeof value === 'number' && isFinite(value)) { - return value.toFixed(1); - } - if (typeof value === 'string') { - // 将所有的 unicode 转为 \uXXXX 形式 - let result = JSON.stringify(value); - result = result.replace(/[\u0080-\uffff]/g, (ch) => { + }; + case 'number': { + if (isFinite(value)) { + return value.toFixed(1); + } else { + return JSON.stringify(value); + } + }; + case 'string': { + return JSON.stringify(value).replace(/[\u0080-\uffff]/g, (ch) => { return '\\u' + ('0000' + ch.charCodeAt(0).toString(16)).slice(-4); }); - return result; - } - }, - patchEdit: (edit) => { - let scanner = jsonc.createScanner(edit.content); - let edits: jsonc.Edit[] = []; - while (scanner.scan() !== jsonc.SyntaxKind.EOF) { - if (scanner.getToken() === jsonc.SyntaxKind.StringLiteral) { - let start = scanner.getTokenOffset(); - let length = scanner.getTokenLength(); - let value = edit.content.slice(start + 1, start + length - 1); - let newValue = value.replace(/[\u0080-\uffff]/g, (ch) => { - return '\\u' + ('0000' + ch.charCodeAt(0).toString(16)).slice(-4); - }); - if (value !== newValue) { - edits.push({ - offset: start + 1, - length: value.length, - content: newValue, - }); + }; + case 'object': { + if (value === null) { + return 'null'; + } + if (Array.isArray(value)) { + if (value.length === 0) { + return '[]'; + } + let result = '[\n'; + const tab = ' '.repeat(tabLevel + 1); + for (let i = 0; i < value.length; i++) { + let item = value[i]; + result += tab + stringify(item, tabLevel + 1); + if (i < value.length - 1) { + result += ', '; + } + result += '\n'; } + result += ' '.repeat(tabLevel) + ']'; + return result; + } else { + let keys = Object.keys(value); + if (keys.length === 0) { + return '{}'; + } + keys.sort(); + let result = '{\n'; + const tab = ' '.repeat(tabLevel + 1); + for (let i = 0; i < keys.length; i++) { + let key = keys[i]; + let item = value[key]; + result += tab + stringify(key) + ': ' + stringify(item, tabLevel + 1); + if (i < keys.length - 1) { + result += ', '; + } + result += '\n'; + } + result += ' '.repeat(tabLevel) + '}'; + return result; } - } - edit.content = jsonc.applyEdits(edit.content, edits); - edit.content = edit.content.replace(/,([\r\n])/g, ', $1'); - return edit; - }, -}; + }; + default: { + return JSON.stringify(value); + }; + } +} export class EditorJson extends Json { constructor(text: string) { - super(text, jsonFormatOptions); + super(text, { + stringify: stringify, + patchJson: true, + patchEdit: (edit: jsonc.Edit) => { + edit.content = edit.content.replace(/,\n/g, ', \n'); + return edit; + } + }); } } diff --git a/src/tools/json.ts b/src/tools/json.ts index 47cfa16..12b1c7a 100644 --- a/src/tools/json.ts +++ b/src/tools/json.ts @@ -21,6 +21,7 @@ export type JObject = { [key: string]: Item }; export interface formatOptions { stringify?: (value: any) => string | undefined; patchEdit?: (edit: jsonc.Edit) => jsonc.Edit; + patchJson?: boolean; } export class Json { @@ -82,38 +83,43 @@ export class Json { } this._tree = undefined; - let originStringify: typeof JSON.stringify | undefined; - if (this.options?.stringify) { - originStringify = JSON.stringify; - let hookedStringfy = (value: any, replacer?: any, space?: any) => { - if (replacer) { + if (this.options?.patchJson) { + let originStringify: typeof JSON.stringify | undefined; + if (this.options?.stringify) { + originStringify = JSON.stringify; + let hookedStringfy = (value: any, replacer?: any, space?: any) => { + if (replacer) { + return originStringify!(value, replacer, space); + } + JSON.stringify = originStringify!; + let result = this.options!.stringify!(value); + JSON.stringify = hookedStringfy; + if (result !== undefined) { + return result; + } return originStringify!(value, replacer, space); - } - JSON.stringify = originStringify!; - let result = this.options!.stringify!(value); + }; JSON.stringify = hookedStringfy; - if (result !== undefined) { - return result; - } - return originStringify!(value, replacer, space); - }; - JSON.stringify = hookedStringfy; - } + } - try { - for (const key in this._patch) { - const value = this._patch[key]; - let edits = jsonc.modify(this._text, [key], value, editOptions); - if (this.options?.patchEdit) { - edits = edits.map(this.options.patchEdit); + try { + for (const key in this._patch) { + const value = this._patch[key]; + let edits = jsonc.modify(this._text, [key], value, editOptions); + if (this.options?.patchEdit) { + edits = edits.map(this.options.patchEdit); + } + this._text = jsonc.applyEdits(this._text, edits); + } + } finally { + this._patch = undefined; + if (originStringify) { + JSON.stringify = originStringify; } - this._text = jsonc.applyEdits(this._text, edits); } - } finally { + } else { this._patch = undefined; - if (originStringify) { - JSON.stringify = originStringify; - } + this._text = this.options?.stringify?.(this.data) ?? JSON.stringify(this.data, null, 4); } } }