From 0ce98282badd3b87eec055b145f6ff022a9a2391 Mon Sep 17 00:00:00 2001 From: Nikita Date: Thu, 12 Dec 2024 00:18:20 +0300 Subject: [PATCH] change our own JSON parser to untruncate-json lib, since it works fast and correctly --- package-lock.json | 12 +- package.json | 3 +- .../blocks-stream-processor/index.js | 149 +----------------- 3 files changed, 15 insertions(+), 149 deletions(-) diff --git a/package-lock.json b/package-lock.json index 77d085a..acb5ec8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,18 @@ { "name": "mind", - "version": "0.1.2", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mind", - "version": "0.1.2", + "version": "0.2.0", "license": "GPL-2.0-or-later", "dependencies": { "clsx": "^2.0.0", "marked": "^10.0.0", - "react-transition-group": "^4.4.5" + "react-transition-group": "^4.4.5", + "untruncate-json": "^0.0.1" }, "devDependencies": { "@wordpress/eslint-plugin": "^17.2.0", @@ -17596,6 +17597,11 @@ "node": ">=8" } }, + "node_modules/untruncate-json": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/untruncate-json/-/untruncate-json-0.0.1.tgz", + "integrity": "sha512-4W9enDK4X1y1s2S/Rz7ysw6kDuMS3VmRjMFg7GZrNO+98OSe+x5Lh7PKYoVjy3lW/1wmhs6HW0lusnQRHgMarA==" + }, "node_modules/update-browserslist-db": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", diff --git a/package.json b/package.json index 5c2b996..2fe1939 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "dependencies": { "clsx": "^2.0.0", "marked": "^10.0.0", - "react-transition-group": "^4.4.5" + "react-transition-group": "^4.4.5", + "untruncate-json": "^0.0.1" } } diff --git a/src/editor/processors/blocks-stream-processor/index.js b/src/editor/processors/blocks-stream-processor/index.js index f63cbba..c845f6c 100644 --- a/src/editor/processors/blocks-stream-processor/index.js +++ b/src/editor/processors/blocks-stream-processor/index.js @@ -1,3 +1,5 @@ +import untruncateJson from 'untruncate-json'; + import { createBlock } from '@wordpress/blocks'; export default class BlocksStreamProcessor { @@ -8,7 +10,7 @@ export default class BlocksStreamProcessor { this.lastUpdate = Date.now(); this.isJsonStarted = false; this.jsonBuffer = ''; - this.lastDispatchedBlocks = null; + this.lastDispatchedBlocks = []; this.renderDelay = 150; // In Nginx server we have the true steaming experience and receive chunks in JS as soon as they are available. @@ -148,150 +150,7 @@ export default class BlocksStreamProcessor { return '[]'; } - let result = ''; - let inString = false; - let inEscape = false; - let openBrackets = 0; - let openBraces = 0; - let lastPropertyName = ''; - let inPropertyName = false; - let currentProperty = ''; - const arrayStack = []; - const braceStack = []; - - // Process character by character - for (let i = 0; i < partial.length; i++) { - const char = partial[i]; - const nextChar = partial[i + 1]; - result += char; - - // Handle escape sequences - if (char === '\\\\' && inString) { - inEscape = true; - continue; - } - - if (inEscape) { - inEscape = false; - continue; - } - - // Track string boundaries - if (char === '"' && !inEscape) { - if (!inString) { - inString = true; - - // Check if this is a property name - if (!inPropertyName && nextChar === ':') { - inPropertyName = true; - } - } else { - inString = false; - - if (inPropertyName) { - lastPropertyName = currentProperty; - currentProperty = ''; - inPropertyName = false; - } - } - } else if (inString) { - if (inPropertyName) { - currentProperty += char; - } - } - - // Only count structure characters outside strings - if (!inString) { - if (char === '[') { - openBrackets++; - arrayStack.push(i); - } - if (char === ']') { - openBrackets--; - if (arrayStack.length > 0) { - arrayStack.pop(); - } - } - if (char === '{') { - openBraces++; - braceStack.push(i); - } - if (char === '}') { - openBraces--; - if (braceStack.length > 0) { - braceStack.pop(); - } - } - } - } - - // Complete the structure - let completed = result; - - // Handle unclosed strings - if (inString) { - completed += '"'; - } - - // Complete property values if needed - if (lastPropertyName === 'content' && inString) { - completed += '"'; - } - - // Complete objects and arrays from inside out - while (openBraces > 0) { - completed += '}'; - openBraces--; - } - - while (openBrackets > 0) { - completed += ']'; - openBrackets--; - } - - // Validate and fix common issues - try { - JSON.parse(completed); - return completed; - } catch (e) { - // Try to fix common issues - let fixed = completed; - - // Fix unclosed content property - const contentMatch = fixed.match( - /"content"\\s*:\\s*"([^"]*)(?:[^"]*)?$/ - ); - if (contentMatch) { - const contentEndIndex = - fixed.lastIndexOf(contentMatch[1]) + contentMatch[1].length; - fixed = - fixed.substring(0, contentEndIndex) + - '"' + - fixed.substring(contentEndIndex); - } - - // Fix missing commas between blocks - fixed = fixed.replace(/}(\\s*){/g, '},\\n{'); - - // Fix trailing commas - fixed = fixed.replace(/,(\\s*[}\\]])/g, '$1'); - - try { - JSON.parse(fixed); - return fixed; - } catch (e2) { - // If still invalid, try to extract valid parts - const blockMatch = fixed.match( - /\[\s*{[^{]*"name"\s*:\s*"[^"]+"\s*,\s*"attributes"\s*:\s*{[^}]+}/ - ); - if (blockMatch) { - return blockMatch[0] + '}]'; - } - - // Return minimal valid structure as last resort - return '[{"name":"core/paragraph","attributes":{"content":""},"innerBlocks":[]}]'; - } - } + return untruncateJson(partial); } transformToBlock(blockData) {