From f6b5e3e4ed0a547bfb48694b7ead62409bc3a646 Mon Sep 17 00:00:00 2001 From: uki00a Date: Fri, 17 Jul 2020 07:36:15 +0900 Subject: [PATCH] fix(encoding/toml): could not parse strings with apostrophes/semicolons (denoland/deno#6781) --- encoding/testdata/string.toml | 5 ++++- encoding/toml.ts | 35 +++++++++++++++++++++++++++++++---- encoding/toml_test.ts | 2 ++ 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/encoding/testdata/string.toml b/encoding/testdata/string.toml index f811824eb..55e3fca34 100644 --- a/encoding/testdata/string.toml +++ b/encoding/testdata/string.toml @@ -27,4 +27,7 @@ The first newline is trimmed in raw strings. All other whitespace is preserved. -''' \ No newline at end of file +''' + +withApostrophe = "What if it's not?" +withSemicolon = "const message = 'hello world';" diff --git a/encoding/toml.ts b/encoding/toml.ts index 7d340c8e8..43788c06a 100644 --- a/encoding/toml.ts +++ b/encoding/toml.ts @@ -2,6 +2,8 @@ import { deepAssign } from "../_util/deep_assign.ts"; import { assert } from "../_util/assert.ts"; +class TOMLError extends Error {} + class KeyValuePair { constructor(public key: string, public value: unknown) {} } @@ -230,10 +232,7 @@ class Parser { if (invalidArr) { dataString = dataString.replace(/,]/g, "]"); } - const m = /(?:\'|\[|{|\").*(?:\'|\]|\"|})\s*[^#]/g.exec(dataString); - if (m) { - dataString = m[0].trim(); - } + dataString = this._stripComment(dataString); if (dataString[0] === "{" && dataString[dataString.length - 1] === "}") { const reg = /([a-zA-Z0-9-_\.]*) (=)/gi; let result; @@ -260,6 +259,34 @@ class Parser { } return eval(dataString); } + private _stripComment(dataString: string): string { + const isString = dataString.startsWith('"') || dataString.startsWith("'"); + if (isString) { + const [quote] = dataString; + let indexOfNextQuote = 0; + while ( + (indexOfNextQuote = dataString.indexOf(quote, indexOfNextQuote + 1)) !== + -1 + ) { + const isEscaped = dataString[indexOfNextQuote - 1] === "\\"; + if (!isEscaped) { + break; + } + } + if (indexOfNextQuote === -1) { + throw new TOMLError("imcomplete string literal"); + } + const endOfString = indexOfNextQuote + 1; + return dataString.slice(0, endOfString); + } + + const m = /(?:|\[|{|).*(?:|\]||})\s*[^#]/g.exec(dataString); + if (m) { + return m[0].trim(); + } else { + return dataString; + } + } _isLocalTime(str: string): boolean { const reg = /(\d{2}):(\d{2}):(\d{2})/; return reg.test(str); diff --git a/encoding/toml_test.ts b/encoding/toml_test.ts index 5c4c63b5a..5d651c822 100644 --- a/encoding/toml_test.ts +++ b/encoding/toml_test.ts @@ -29,6 +29,8 @@ Deno.test({ str6: "The quick brown\nfox jumps over\nthe lazy dog.", lines: "The first newline is\ntrimmed in raw strings.\n All other " + "whitespace\n is preserved.", + withApostrophe: "What if it's not?", + withSemicolon: `const message = 'hello world';`, }, }; const actual = parseFile(path.join(testFilesDir, "string.toml"));