From 4b5d8453e310084740eae470d6ccfb8f84abbf9a Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Fri, 5 Apr 2024 09:24:59 -0700 Subject: [PATCH] [osd/std] Add fallback mechanism when recovery from false-positives in handling of long numerals fails (#6253) (#6259) Signed-off-by: Miki (cherry picked from commit 312075c9b8b1c881fb434a7c82c58a4c34780599) Signed-off-by: github-actions[bot] # Conflicts: # CHANGELOG.md Co-authored-by: github-actions[bot] --- packages/osd-std/src/json.ts | 129 ++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 62 deletions(-) diff --git a/packages/osd-std/src/json.ts b/packages/osd-std/src/json.ts index 7387790169a3..d8bb27e1eb6a 100644 --- a/packages/osd-std/src/json.ts +++ b/packages/osd-std/src/json.ts @@ -143,77 +143,82 @@ const parseStringWithLongNumerals = ( * To find those instances, we try to parse and watch for the location of any errors. If an error * is caused by the marking, we remove that single marking and try again. */ - do { - try { - hadException = false; - obj = parseMarkedText(markedJSON); - } catch (e) { - hadException = true; - /* There are two types of exception objects that can be raised: - * 1) a textual message with the position that we need to parse - * i. Unexpected [token|string ...] at position ... - * ii. Expected ',' or ... after ... in JSON at position ... - * iii. expected ',' or ... after ... in object at line ... column ... - * 2) a proper object with lineNumber and columnNumber which we can use - * Note: this might refer to the part of the code that threw the exception but - * we will try it anyway; the regex is specific enough to not produce - * false-positives. - */ - let { lineNumber, columnNumber } = e; - - if (typeof e?.message === 'string') { - /* Check for 1-i and 1-ii - * Finding "..."෴1111"..." inside a string value, the extra quotes throw a syntax error - * and the position points to " that is assumed to be the begining of a value. + try { + do { + try { + hadException = false; + obj = parseMarkedText(markedJSON); + } catch (e) { + hadException = true; + /* There are two types of exception objects that can be raised: + * 1) a textual message with the position that we need to parse + * i. Unexpected [token|string ...] at position ... + * ii. Expected ',' or ... after ... in JSON at position ... + * iii. expected ',' or ... after ... in object at line ... column ... + * 2) a proper object with lineNumber and columnNumber which we can use + * Note: this might refer to the part of the code that threw the exception but + * we will try it anyway; the regex is specific enough to not produce + * false-positives. */ - let match = e.message.match(/^(?:Une|E)xpected .*at position (\d+)(\D|$)/i); - if (match) { - lineNumber = 1; - // Add 1 to reach the marker - columnNumber = parseInt(match[1], 10) + 1; - } else { - /* Check for 1-iii - * Finding "...,"෴1111"..." inside a string value, the extra quotes throw a syntax error - * and the column number points to the marker after the " that is assumed to be terminating the - * value. - * PS: There are different versions of this error across browsers and platforms. + let { lineNumber, columnNumber } = e; + + if (typeof e?.message === 'string') { + /* Check for 1-i and 1-ii + * Finding "..."෴1111"..." inside a string value, the extra quotes throw a syntax error + * and the position points to " that is assumed to be the begining of a value. */ - // ToDo: Add functional tests for this path - match = e.message.match(/expected .*line (\d+) column (\d+)(\D|$)/i); + let match = e.message.match(/^(?:Un)?expected .*at position (\d+)(\D|$)/i); if (match) { - lineNumber = parseInt(match[1], 10); - columnNumber = parseInt(match[2], 10); + lineNumber = 1; + // Add 1 to reach the marker + columnNumber = parseInt(match[1], 10) + 1; + } else { + /* Check for 1-iii + * Finding "...,"෴1111"..." inside a string value, the extra quotes throw a syntax error + * and the column number points to the marker after the " that is assumed to be terminating the + * value. + * PS: There are different versions of this error across browsers and platforms. + */ + // ToDo: Add functional tests for this path + match = e.message.match(/expected .*line (\d+) column (\d+)(\D|$)/i); + if (match) { + lineNumber = parseInt(match[1], 10); + columnNumber = parseInt(match[2], 10); + } } } - } - if (lineNumber < 1 || columnNumber < 2) { - /* The problem is not with this replacement. - * Note: This will never happen because the outer parse would have already thrown. - */ - // coverage:ignore-line - throw e; - } + if (lineNumber < 1 || columnNumber < 2) { + /* The problem is not with this replacement. + * Note: This will never happen because the outer parse would have already thrown. + */ + // coverage:ignore-line + throw e; + } - /* We need to skip e.lineNumber - 1 number of `\n` occurrences. - * Then, we need to go to e.columnNumber - 2 to look for `"\d+"`; we need to `-1` to - * account for the quote but an additional `-1` is needed because columnNumber starts from 1. - */ - const re = new RegExp( - `^((?:.*\\n){${lineNumber - 1}}[^\\n]{${columnNumber - 2}})"${marker}(-?\\d+)"` - ); - if (!re.test(markedJSON)) { - /* The exception is not caused by adding the marker. - * Note: This will never happen because the outer parse would have already thrown. + /* We need to skip e.lineNumber - 1 number of `\n` occurrences. + * Then, we need to go to e.columnNumber - 2 to look for `"\d+"`; we need to `-1` to + * account for the quote but an additional `-1` is needed because columnNumber starts from 1. */ - // coverage:ignore-line - throw e; - } + const re = new RegExp( + `^((?:.*\\n){${lineNumber - 1}}[^\\n]{${columnNumber - 2}})"${marker}(-?\\d+)"` + ); + if (!re.test(markedJSON)) { + /* The exception is not caused by adding the marker. + * Note: This will never happen because the outer parse would have already thrown. + */ + // coverage:ignore-line + throw e; + } - // We have found a bad replacement; let's remove it. - markedJSON = markedJSON.replace(re, '$1$2'); - } - } while (hadException); + // We have found a bad replacement; let's remove it. + markedJSON = markedJSON.replace(re, '$1$2'); + } + } while (hadException); + } catch (ex) { + // If parsing of marked `text` fails, fallback to parsing the original `text` + obj = JSON.parse(text, reviver || undefined); + } return obj; };