From aa247e934367dd7717e4940f3dc22d464c917fb8 Mon Sep 17 00:00:00 2001 From: keiya sasaki Date: Mon, 6 Mar 2023 09:56:51 +0900 Subject: [PATCH] fix: parse reserved word when property name includes reserved word on reearth/core (#508) * wip * fix: replace reserved word * fix * Update src/core/mantle/evaluator/simple/expression/runtime.ts Co-authored-by: rot1024 * Update src/core/mantle/evaluator/simple/expression/variableReplacer.ts Co-authored-by: Piyush Chauhan <42397980+pyshx@users.noreply.github.com> * Update src/core/mantle/evaluator/simple/expression/variableReplacer.test.ts Co-authored-by: Piyush Chauhan <42397980+pyshx@users.noreply.github.com> * fix: use $ --------- Co-authored-by: rot1024 Co-authored-by: Piyush Chauhan <42397980+pyshx@users.noreply.github.com> --- .../evaluator/simple/expression/runtime.ts | 3 +- .../expression/variableReplacer.test.ts | 9 ++++++ .../simple/expression/variableReplacer.ts | 25 ++++++++++++++- .../mantle/evaluator/simple/index.test.ts | 32 +++++++++++++++++++ 4 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src/core/mantle/evaluator/simple/expression/runtime.ts b/src/core/mantle/evaluator/simple/expression/runtime.ts index a790f71d7d..19f95b6547 100644 --- a/src/core/mantle/evaluator/simple/expression/runtime.ts +++ b/src/core/mantle/evaluator/simple/expression/runtime.ts @@ -4,6 +4,7 @@ import { ExpressionNodeType, unaryOperators, binaryOperators, replacementRegex } import { Expression } from "./expression"; import { unaryFunctions, binaryFunctions } from "./functions"; import { Node } from "./node"; +import { restoreReservedWord } from "./variableReplacer"; export function createRuntimeAst(expression: Expression, ast: any): Node | Error { let node: Node | Error = new Error("failed to parse"); @@ -260,5 +261,5 @@ function isVariable(name: string): boolean { } function getPropertyName(variable: string): string { - return variable.substring(4); + return restoreReservedWord(variable).substring(4); } diff --git a/src/core/mantle/evaluator/simple/expression/variableReplacer.test.ts b/src/core/mantle/evaluator/simple/expression/variableReplacer.test.ts index b66f4e101e..4468f45118 100644 --- a/src/core/mantle/evaluator/simple/expression/variableReplacer.test.ts +++ b/src/core/mantle/evaluator/simple/expression/variableReplacer.test.ts @@ -37,4 +37,13 @@ describe("replaceVariables", () => { }); expect(res[0].literalValue).toBe("iPhone"); }); + + test("should replace reserved word", () => { + const [result, _] = replaceVariables( + "${va[ria]ble} + ${variable[0]} + ${variable['key']} + ${variable[\"key\"]} + ${variable[variable]} + ${variable[variable].nested} + ${variable[variable]['nested']}", + ); + expect(result).toBe( + `czm_va$reearth_opened_square_bracket_$ria$reearth_closed_square_bracket_$ble + czm_variable[0] + czm_variable['key'] + czm_variable["key"] + czm_variable[variable] + czm_variable[variable].nested + czm_variable[variable]['nested']`, + ); + }); }); diff --git a/src/core/mantle/evaluator/simple/expression/variableReplacer.ts b/src/core/mantle/evaluator/simple/expression/variableReplacer.ts index c40cf2c2c7..e1774658bd 100644 --- a/src/core/mantle/evaluator/simple/expression/variableReplacer.ts +++ b/src/core/mantle/evaluator/simple/expression/variableReplacer.ts @@ -43,7 +43,8 @@ export function replaceVariables(expression: string, feature?: any): [string, JP throw new Error(`replaceVariable: ${varExp} is not a valid JSONPath`); } } else { - result += `czm_${varExp}`; + const replacedVarExp = replaceReservedWord(varExp); + result += `czm_${replacedVarExp}`; } exp = exp.substring(j + 1); i = exp.indexOf("${"); @@ -95,3 +96,25 @@ function containsValidJSONPath(expression: string, feature: Feature): boolean { return false; } } + +const makeReservedWord = (str: string) => `$reearth_${str}_$`; +const RESERVED_WORDS: Record = { + "[": makeReservedWord("opened_square_bracket"), + "]": makeReservedWord("closed_square_bracket"), + "{": makeReservedWord("opened_curly_bracket"), + "}": makeReservedWord("closed_curly_bracket"), + "(": makeReservedWord("opened_parentheses"), + ")": makeReservedWord("closed_parentheses"), +}; + +const replaceReservedWord = (word: string) => { + return word.replaceAll( + /(.*)(\[|\{|\()(.*)(\]|\}|\))(?!\.|\[)(.+)/g, + (_match, prefix, openedBracket, inner, closedBracket, suffix) => { + return `${prefix}${RESERVED_WORDS[openedBracket]}${inner}${RESERVED_WORDS[closedBracket]}${suffix}`; + }, + ); +}; + +export const restoreReservedWord = (text: string) => + Object.entries(RESERVED_WORDS).reduce((res, [key, val]) => res.replace(val, key), text); diff --git a/src/core/mantle/evaluator/simple/index.test.ts b/src/core/mantle/evaluator/simple/index.test.ts index 826013f56d..27f93d9d53 100644 --- a/src/core/mantle/evaluator/simple/index.test.ts +++ b/src/core/mantle/evaluator/simple/index.test.ts @@ -421,4 +421,36 @@ describe("Conditional styling", () => { }, }); }); + + test("Property has reserved word", () => { + expect( + evalLayerAppearances( + { + marker: { + pointColor: "#FF0000", + pointSize: { + expression: { + conditions: [ + ["${he[llo]world} === 'value'", "100"], + ["true", "1"], + ], + }, + }, + }, + }, + { + id: "x", + type: "simple", + properties: { + "he[llo]world": "value", + }, + }, + ), + ).toEqual({ + marker: { + pointColor: "#FF0000", // blue + pointSize: 100, + }, + }); + }); });