From d0fbc34fa0c2910cae7e1ced4ac49b7b0e6dff11 Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Sat, 10 Oct 2026 23:20:35 +0300 Subject: [PATCH] perf(theme): scan JSONC string literals once and copy them as a slice stripJsonc scanned every string literal twice (copy, then skip) and built a StringBuffer per literal. A single scan now finds the closing quote and the literal is written as a substring. Closes #1360. --- lib/core/theme/parser/jsonc_preprocessor.dart | 43 ++++++------------- .../theme/parser/jsonc_preprocessor_test.dart | 30 +++++++++++++ 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/lib/core/theme/parser/jsonc_preprocessor.dart b/lib/core/theme/parser/jsonc_preprocessor.dart index 8497172b..9f6e92c0 100644 --- a/lib/core/theme/parser/jsonc_preprocessor.dart +++ b/lib/core/theme/parser/jsonc_preprocessor.dart @@ -9,8 +9,10 @@ String stripJsonc(String input) { final next = i + 1 < len ? input[i + 1] : ''; if (ch == '"') { - out.write(_copyStringLiteral(input, i)); - i = _skipStringLiteral(input, i); + // One scan finds the closing quote; the literal is copied as a slice. + final end = _stringLiteralEnd(input, i); + out.write(input.substring(i, end)); + i = end; continue; } @@ -54,37 +56,20 @@ String stripJsonc(String input) { bool _isWhitespace(String c) => c == ' ' || c == '\t' || c == '\n' || c == '\r'; -String _copyStringLiteral(String s, int start) { - final buf = StringBuffer(); - var i = start; - buf.write(s[i]); - i++; - while (i < s.length) { - final ch = s[i]; - buf.write(ch); - if (ch == '\\' && i + 1 < s.length) { - i++; - buf.write(s[i]); - } else if (ch == '"') { - i++; - break; - } - i++; - } - return buf.toString(); -} - -int _skipStringLiteral(String s, int start) { +/// Offset after the string literal that opens at [start] (a `"`): past its +/// closing quote, or the end of [s] when it is not terminated. A backslash +/// escapes the next character. +int _stringLiteralEnd(String s, int start) { + final len = s.length; var i = start + 1; - while (i < s.length) { - if (s[i] == '\\') { + while (i < len) { + final c = s.codeUnitAt(i); + if (c == 0x5C) { i += 2; continue; } - if (s[i] == '"') { - return i + 1; - } + if (c == 0x22) return i + 1; i++; } - return s.length; + return len; } diff --git a/test/core/theme/parser/jsonc_preprocessor_test.dart b/test/core/theme/parser/jsonc_preprocessor_test.dart index 77c94752..39196cec 100644 --- a/test/core/theme/parser/jsonc_preprocessor_test.dart +++ b/test/core/theme/parser/jsonc_preprocessor_test.dart @@ -42,5 +42,35 @@ void main() { expect(cleaned.contains(',}'), isFalse); expect(cleaned, contains('"editor.background"')); }); + + test('keeps string literals byte for byte, escapes included', () { + const input = r'{"a": "q\"uote // not a comment", "b": "back\\"}'; + expect(stripJsonc(input), input); + }); + + test('comment markers and trailing commas inside strings survive', () { + const input = r'{"a": "/* x */", "b": "[1,]", "c": "x,}"}'; + expect(stripJsonc(input), input); + }); + + test('an unterminated string is copied to the end', () { + expect(stripJsonc('{"a": "oops'), '{"a": "oops'); + }); + + test('a trailing backslash at the end of input does not throw', () { + expect(stripJsonc(r'{"a": "x\'), r'{"a": "x\'); + }); + + test('comments and trailing commas around many strings', () { + final input = StringBuffer('{\n'); + for (var i = 0; i < 200; i++) { + input.write(' // token $i\n "k$i": "#${i.toRadixString(16).padLeft(6, '0')}",\n'); + } + input.write('}'); + final cleaned = stripJsonc(input.toString()); + expect(cleaned.contains('//'), isFalse); + expect(cleaned.contains(',\n}'), isFalse); + expect(cleaned, contains('"k199": "#0000c7"')); + }); }); }