From 449d5d3bcb9127076348d299cd6e46b1a4c4817c Mon Sep 17 00:00:00 2001 From: Ariya Hidayat <ariya@metabase.com> Date: Mon, 15 Nov 2021 07:41:17 -0800 Subject: [PATCH] Custom expression tokenizer: rewind on an unterminated string literal (#18969) --- .../src/metabase/lib/expressions/tokenizer.js | 15 +++++++++++---- .../lib/expressions/completer.unit.spec.js | 2 -- .../lib/expressions/tokenizer.unit.spec.js | 12 ++++++++++++ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/frontend/src/metabase/lib/expressions/tokenizer.js b/frontend/src/metabase/lib/expressions/tokenizer.js index c627187980e..c5a6449f18b 100644 --- a/frontend/src/metabase/lib/expressions/tokenizer.js +++ b/frontend/src/metabase/lib/expressions/tokenizer.js @@ -215,10 +215,17 @@ export function tokenize(expression) { } } const type = TOKEN.String; - const end = index; - const terminated = quote === source[end - 1]; - const error = terminated ? null : t`Missing closing quotes`; - return { type, value, start, end, error }; + let error = null; + + const terminated = quote === source[index - 1]; + if (!terminated) { + // unterminated string, rewind after the opening quote + index = start + 1; + value = quote; + error = t`Missing closing quotes`; + } + + return { type, value, start, end: index, error }; }; const scanBracketIdentifier = () => { diff --git a/frontend/test/metabase/lib/expressions/completer.unit.spec.js b/frontend/test/metabase/lib/expressions/completer.unit.spec.js index 59e0e23c23c..1c876fe3418 100644 --- a/frontend/test/metabase/lib/expressions/completer.unit.spec.js +++ b/frontend/test/metabase/lib/expressions/completer.unit.spec.js @@ -22,8 +22,6 @@ describe("metabase/lib/expressions/completer", () => { expect(partialMatch("X OR")).toEqual(null); expect(partialMatch("42 +")).toEqual(null); expect(partialMatch("3.14")).toEqual(null); - expect(partialMatch('"Hello')).toEqual(null); - expect(partialMatch("'world")).toEqual(null); }); it("should handle empty input", () => { diff --git a/frontend/test/metabase/lib/expressions/tokenizer.unit.spec.js b/frontend/test/metabase/lib/expressions/tokenizer.unit.spec.js index 91a2163cbe8..4bf1d977fed 100644 --- a/frontend/test/metabase/lib/expressions/tokenizer.unit.spec.js +++ b/frontend/test/metabase/lib/expressions/tokenizer.unit.spec.js @@ -66,6 +66,18 @@ describe("metabase/lib/expressions/tokenizer", () => { expect(errors('"double')[0].message).toEqual("Missing closing quotes"); }); + it("should continue to tokenize when encountering an unterminated string literal", () => { + expect(types("CONCAT(universe') = [answer]")).toEqual([ + T.Identifier, + T.Operator, + T.Identifier, + T.String, + T.Operator, + T.Operator, + T.Identifier, + ]); + }); + it("should tokenize identifiers", () => { expect(types("Price")).toEqual([T.Identifier]); expect(types("Special_Deal")).toEqual([T.Identifier]); -- GitLab