From ebcb7ee6fde73dc2b52afefd8d28c715df428446 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 14 Sep 2019 17:29:31 +1000 Subject: [PATCH] Add a small JSON Parser to October framework lib (#4527) * Add a small JSON Parser to October framework lib --- .../assets/js/october.relation.js | 2 +- .../widgets/form/assets/js/october.form.js | 2 +- modules/system/assets/js/framework-min.js | 1 + .../assets/js/framework.combined-min.js | 3 +- .../system/assets/js/framework.combined.js | 1 + modules/system/assets/js/framework.extras.js | 3 + modules/system/assets/js/framework.js | 5 +- modules/system/assets/js/october.parser.js | 355 ++++++++++++++++++ modules/system/assets/ui/js/autocomplete.js | 2 +- modules/system/assets/ui/js/chart.line.js | 2 +- modules/system/assets/ui/js/popup.js | 2 +- 11 files changed, 371 insertions(+), 7 deletions(-) create mode 100644 modules/system/assets/js/october.parser.js diff --git a/modules/backend/behaviors/relationcontroller/assets/js/october.relation.js b/modules/backend/behaviors/relationcontroller/assets/js/october.relation.js index 80bf1bea4..e7fb3164e 100644 --- a/modules/backend/behaviors/relationcontroller/assets/js/october.relation.js +++ b/modules/backend/behaviors/relationcontroller/assets/js/october.relation.js @@ -87,7 +87,7 @@ if (typeof value == 'object') return value try { - return JSON.parse(JSON.stringify(eval("({" + value + "})"))) + return $.oc.JSON("{" + value + "}") } catch (e) { throw new Error('Error parsing the '+name+' attribute value. '+e) diff --git a/modules/backend/widgets/form/assets/js/october.form.js b/modules/backend/widgets/form/assets/js/october.form.js index 0936d2df3..bb0496527 100644 --- a/modules/backend/widgets/form/assets/js/october.form.js +++ b/modules/backend/widgets/form/assets/js/october.form.js @@ -264,7 +264,7 @@ if (typeof value == 'object') return value try { - return JSON.parse(JSON.stringify(eval("({" + value + "})"))) + return $.oc.JSON("{" + value + "}") } catch (e) { throw new Error('Error parsing the '+name+' attribute value. '+e) diff --git a/modules/system/assets/js/framework-min.js b/modules/system/assets/js/framework-min.js index fde32c26d..034ed6a23 100644 --- a/modules/system/assets/js/framework-min.js +++ b/modules/system/assets/js/framework-min.js @@ -1,4 +1,5 @@ +"use strict";!function(){function a(e,r,n){for(var t="",o=r;o= "0" && str[pos] <= "9")) { + var body = ""; + for (var i = pos; i < str.length; i++) { + if (str[i] === "-" || str[i] === "+" || str[i] === "." || (str[i] >= "0" && str[i] <= "9")) { + body += str[i]; + } else { + return { + originLength: body.length, + body: body + }; + } + } + throw new Error("Broken JSON number body near " + body); + } + + // parse object + if (str[pos] === "{" || str[pos] === "[") { + var stack = [str[pos]]; + var body = str[pos]; + for (var i = pos + 1; i < str.length; i++) { + body += str[i]; + if (str[i] === "\\") { + if (i + 1 < str.length) body += str[i + 1]; + i++; + } else if (str[i] === "\"") { + if (stack[stack.length - 1] === "\"") { + stack.pop(); + } else if (stack[stack.length - 1] !== "'") { + stack.push(str[i]); + } + } else if (str[i] === "'") { + if (stack[stack.length - 1] === "'") { + stack.pop(); + } else if (stack[stack.length - 1] !== "\"") { + stack.push(str[i]); + } + } else if (stack[stack.length - 1] !== "\"" && stack[stack.length - 1] !== "'") { + if (str[i] === "{") { + stack.push("{"); + } else if (str[i] === "}") { + if (stack[stack.length - 1] === "{") { + stack.pop(); + } else { + throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body); + } + } else if (str[i] === "[") { + stack.push("["); + } else if (str[i] === "]") { + if (stack[stack.length - 1] === "[") { + stack.pop(); + } else { + throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body); + } + } + } + if (!stack.length) { + return { + originLength: i - pos, + body: body + }; + } + } + throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body); + } + throw new Error("Broken JSON body near " + str.substr((pos - 5 >= 0) ? pos - 5 : 0, 50)); + } + + /* + * This is a char can be key head + * @param ch + * @returns {boolean} + */ + function canBeKeyHead(ch) { + if (ch[0] === "\\") return false; + if ((ch[0] >= 'a' && ch[0] <= 'z') || (ch[0] >= 'A' && ch[0] <= 'Z') || ch[0] === '_') return true; + if (ch[0] >= '0' && ch[0] <= '9') return true; + if (ch[0] === '$') return true; + if (ch.charCodeAt(0) > 255) return true; + return false; + } + + function isBlankChar(ch) { + return ch === " " || ch === "\n" || ch === "\t"; + } + + /* + * parse JSON + * @param str + */ + function parse(str) { + str = str.trim(); + if (!str.length) throw new Error("Broken JSON object."); + var result = ""; + + /* + * the mistake ',' + */ + while (str && str[0] === ",") { + str = str.substr(1); + } + + /* + * string + */ + if (str[0] === "\"" || str[0] === "'") { + if (str[str.length - 1] !== str[0]) { + throw new Error("Invalid string JSON object."); + } + + var body = "\""; + for (var i = 1; i < str.length; i++) { + if (str[i] === "\\") { + if (str[i + 1] === "'") { + body += str[i + 1] + } else { + body += str[i]; + body += str[i + 1]; + } + i++; + } else if (str[i] === str[0]) { + body += "\""; + return body + } else if (str[i] === "\"") { + body += "\\\"" + } else body += str[i]; + } + throw new Error("Invalid string JSON object."); + } + + /* + * boolean + */ + if (str === "true" || str === "false") { + return str; + } + + /* + * null + */ + if (str === "null") { + return "null"; + } + + /* + * number + */ + var num = parseFloat(str); + if (!isNaN(num)) { + return num.toString(); + } + + /* + * object + */ + if (str[0] === "{") { + var type = "needKey"; + var result = "{"; + + for (var i = 1; i < str.length; i++) { + if (isBlankChar(str[i])) { + continue; + } else if (type === "needKey" && (str[i] === "\"" || str[i] === "'")) { + var key = parseKey(str, i + 1, str[i]); + result += "\"" + key + "\""; + i += key.length; + i += 1; + type = "afterKey"; + } else if (type === "needKey" && canBeKeyHead(str[i])) { + var key = parseKey(str, i); + result += "\""; + result += key; + result += "\""; + i += key.length - 1; + type = "afterKey"; + } else if (type === "afterKey" && str[i] === ":") { + result += ":"; + type = ":"; + } else if (type === ":") { + var body = getBody(str, i); + + i = i + body.originLength - 1; + result += parse(body.body); + + type = "afterBody"; + } else if (type === "afterBody" || type === "needKey") { + var last = i; + while (str[last] === "," || isBlankChar(str[last])) { + last++; + } + if (str[last] === "}" && last === str.length - 1) { + while (result[result.length - 1] === ",") { + result = result.substr(0, result.length - 1); + } + result += "}"; + return result; + } else if (last !== i && result !== "{") { + result += ","; + type = "needKey"; + i = last - 1; + } + } + } + throw new Error("Broken JSON object near " + result); + } + + /* + * array + */ + if (str[0] === "[") { + var result = "["; + var type = "needBody"; + for (var i = 1; i < str.length; i++) { + if (" " === str[i] || "\n" === str[i] || "\t" === str[i]) { + continue; + } else if (type === "needBody") { + if (str[i] === ",") { + result += "null,"; + continue; + } + if (str[i] === "]" && i === str.length - 1) { + if (result[result.length - 1] === ",") result = result.substr(0, result.length - 1); + result += "]"; + return result; + } + + var body = getBody(str, i); + + i = i + body.originLength - 1; + result += parse(body.body); + + type = "afterBody"; + } else if (type === "afterBody") { + if (str[i] === ",") { + result += ","; + type = "needBody"; + + // deal with mistake "," + while (str[i + 1] === "," || isBlankChar(str[i + 1])) { + if (str[i + 1] === ",") result += "null,"; + i++; + } + } else if (str[i] === "]" && i === str.length - 1) { + result += "]"; + return result; + } + } + } + throw new Error("Broken JSON array near " + result); + } + } + + /* + * parse October JSON string into JSON object + * @param json + * @returns {*} + */ + if ($.oc === undefined) + $.oc = {} + + $.oc.JSON = function(json) { + var jsonString = parse(json); + return JSON.parse(jsonString); + }; + +})(); diff --git a/modules/system/assets/ui/js/autocomplete.js b/modules/system/assets/ui/js/autocomplete.js index dda0d799a..3bf55ca29 100644 --- a/modules/system/assets/ui/js/autocomplete.js +++ b/modules/system/assets/ui/js/autocomplete.js @@ -378,7 +378,7 @@ if (typeof value == 'object') return value try { - return JSON.parse(JSON.stringify(eval("({" + value + "})"))) + return $.oc.JSON("{" + value + "}") } catch (e) { throw new Error('Error parsing the '+name+' attribute value. '+e) diff --git a/modules/system/assets/ui/js/chart.line.js b/modules/system/assets/ui/js/chart.line.js index f89b412fa..d54fd030b 100644 --- a/modules/system/assets/ui/js/chart.line.js +++ b/modules/system/assets/ui/js/chart.line.js @@ -80,7 +80,7 @@ var parsedOptions = {} try { - parsedOptions = JSON.parse(JSON.stringify(eval("({" + options.chartOptions + "})"))); + parsedOptions = $.oc.JSON("{" + value + "}"); } catch (e) { throw new Error('Error parsing the data-chart-options attribute value. '+e); } diff --git a/modules/system/assets/ui/js/popup.js b/modules/system/assets/ui/js/popup.js index 2ba8f348e..0da4bc87d 100644 --- a/modules/system/assets/ui/js/popup.js +++ b/modules/system/assets/ui/js/popup.js @@ -395,7 +395,7 @@ if (typeof value == 'object') return value try { - return JSON.parse(JSON.stringify(eval("({" + value + "})"))) + return $.oc.JSON("{" + value + "}") } catch (e) { throw new Error('Error parsing the '+name+' attribute value. '+e)