| Index: third_party/WebKit/Source/devtools/front_end/formatter_worker/RelaxedJSONParser.js
|
| diff --git a/third_party/WebKit/Source/devtools/front_end/formatter_worker/RelaxedJSONParser.js b/third_party/WebKit/Source/devtools/front_end/formatter_worker/RelaxedJSONParser.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2c0b38042f2d4a54fe37accb73e5bcdc9c4c7409
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/devtools/front_end/formatter_worker/RelaxedJSONParser.js
|
| @@ -0,0 +1,201 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +WebInspector.RelaxedJSONParser = {};
|
| +
|
| +/** @enum {string} */
|
| +WebInspector.RelaxedJSONParser.States = {
|
| + ExpectKey: "ExpectKey",
|
| + ExpectValue: "ExpectValue"
|
| +};
|
| +
|
| +/** @enum {*} */
|
| +WebInspector.RelaxedJSONParser.Keywords = {
|
| + "NaN": NaN,
|
| + "true": true,
|
| + "false": false,
|
| + "Infinity": Infinity,
|
| + "undefined": undefined,
|
| + "null": null
|
| +};
|
| +
|
| +/**
|
| + * @param {string} content
|
| + * @return {*}
|
| + */
|
| +WebInspector.RelaxedJSONParser.parse = function(content)
|
| +{
|
| + var Keywords = WebInspector.RelaxedJSONParser.Keywords;
|
| + var States = WebInspector.RelaxedJSONParser.States;
|
| + content = "(" + content + ")";
|
| +
|
| + try {
|
| + var root = acorn.parse(content, {});
|
| + } catch (e) {
|
| + return null;
|
| + }
|
| +
|
| + var walker = new WebInspector.ESTreeWalker(beforeVisit, afterVisit);
|
| +
|
| + var rootTip = [];
|
| +
|
| + /** @type {!Array.<!WebInspector.RelaxedJSONParser.Context>} */
|
| + var stack = [];
|
| +
|
| + var stackData = /** @type {!WebInspector.RelaxedJSONParser.Context} */ ({
|
| + key: 0,
|
| + tip: rootTip,
|
| + state: States.ExpectValue,
|
| + parentIsArray: true
|
| + });
|
| +
|
| + walker.setWalkNulls(true);
|
| + var hasExpression = false;
|
| +
|
| + walker.walk(root);
|
| +
|
| + if (hasExpression)
|
| + return null;
|
| + return rootTip.length ? rootTip[0] : null;
|
| +
|
| + /**
|
| + * @param {!WebInspector.RelaxedJSONParser.Context} newStack
|
| + */
|
| + function pushStack(newStack)
|
| + {
|
| + stack.push(stackData);
|
| + stackData = newStack;
|
| + }
|
| +
|
| + function popStack()
|
| + {
|
| + stackData = stack.pop();
|
| + }
|
| +
|
| + /**
|
| + * @param {*} value
|
| + */
|
| + function applyValue(value)
|
| + {
|
| + stackData.tip[stackData.key] = value;
|
| + if (stackData.parentIsArray)
|
| + stackData.key++;
|
| + else
|
| + stackData.state = null;
|
| + }
|
| +
|
| + /**
|
| + * @param {!ESTree.Node} node
|
| + * @return {!Object|undefined}
|
| + */
|
| + function beforeVisit(node)
|
| + {
|
| + switch (node.type) {
|
| + case "ObjectExpression":
|
| + var newTip = {};
|
| + applyValue(newTip);
|
| +
|
| + pushStack(/** @type {!WebInspector.RelaxedJSONParser.Context} */ ({
|
| + key: null,
|
| + tip: newTip,
|
| + state: null,
|
| + parentIsArray: false
|
| + }));
|
| + break;
|
| + case "ArrayExpression":
|
| + var newTip = [];
|
| + applyValue(newTip);
|
| +
|
| + pushStack(/** @type {!WebInspector.RelaxedJSONParser.Context} */ ({
|
| + key: 0,
|
| + tip: newTip,
|
| + state: States.ExpectValue,
|
| + parentIsArray: true
|
| + }));
|
| + break;
|
| + case "Property":
|
| + stackData.state = States.ExpectKey;
|
| + break;
|
| + case "Literal":
|
| + if (stackData.state === States.ExpectKey) {
|
| + stackData.key = node.value;
|
| + stackData.state = States.ExpectValue;
|
| + } else if (stackData.state === States.ExpectValue) {
|
| + applyValue(extractValue(node));
|
| + return WebInspector.ESTreeWalker.SkipSubtree;
|
| + }
|
| + break;
|
| + case "Identifier":
|
| + if (stackData.state === States.ExpectKey) {
|
| + stackData.key = /** @type {string} */ (node.name);
|
| + stackData.state = States.ExpectValue;
|
| + } else if (stackData.state === States.ExpectValue) {
|
| + applyValue(extractValue(node));
|
| + return WebInspector.ESTreeWalker.SkipSubtree;
|
| + }
|
| + break;
|
| + case "UnaryExpression":
|
| + if (stackData.state === States.ExpectValue) {
|
| + applyValue(extractValue(node));
|
| + return WebInspector.ESTreeWalker.SkipSubtree;
|
| + }
|
| + break;
|
| + case "Program":
|
| + case "ExpressionStatement":
|
| + break;
|
| + default:
|
| + if (stackData.state === States.ExpectValue)
|
| + applyValue(extractValue(node));
|
| + return WebInspector.ESTreeWalker.SkipSubtree;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @param {!ESTree.Node} node
|
| + */
|
| + function afterVisit(node)
|
| + {
|
| + if (node.type === "ObjectExpression" || node.type === "ArrayExpression")
|
| + popStack();
|
| + }
|
| +
|
| + /**
|
| + * @param {!ESTree.Node} node
|
| + * @return {*}
|
| + */
|
| + function extractValue(node)
|
| + {
|
| + var isNegative = false;
|
| + var originalNode = node;
|
| + var value;
|
| + if (node.type === "UnaryExpression" && (node.operator === "-" || node.operator === "+")) {
|
| + if (node.operator === "-")
|
| + isNegative = true;
|
| + node = /** @type {!ESTree.Node} */ (node.argument);
|
| + }
|
| +
|
| + if (node.type === "Literal") {
|
| + value = node.value;
|
| + } else if (node.type === "Identifier" && Keywords.hasOwnProperty(node.name)) {
|
| + value = Keywords[node.name];
|
| + } else {
|
| + hasExpression = true;
|
| + return content.substring(originalNode.start, originalNode.end);
|
| + }
|
| +
|
| + if (isNegative) {
|
| + if (typeof value !== "number") {
|
| + hasExpression = true;
|
| + return content.substring(originalNode.start, originalNode.end);
|
| + }
|
| + value = -(value);
|
| + }
|
| + return value;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * @typedef {!{key: (number|string), tip: (!Array|!Object), state: ?WebInspector.RelaxedJSONParser.States, parentIsArray: boolean}}
|
| + */
|
| +WebInspector.RelaxedJSONParser.Context;
|
|
|