aboutsummaryrefslogtreecommitdiff
path: root/node_modules/toml/lib/compiler.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/toml/lib/compiler.js')
-rw-r--r--node_modules/toml/lib/compiler.js195
1 files changed, 195 insertions, 0 deletions
diff --git a/node_modules/toml/lib/compiler.js b/node_modules/toml/lib/compiler.js
new file mode 100644
index 00000000..10dc59a1
--- /dev/null
+++ b/node_modules/toml/lib/compiler.js
@@ -0,0 +1,195 @@
+"use strict";
+function compile(nodes) {
+ var assignedPaths = [];
+ var valueAssignments = [];
+ var currentPath = "";
+ var data = {};
+ var context = data;
+ var arrayMode = false;
+
+ return reduce(nodes);
+
+ function reduce(nodes) {
+ var node;
+ for (var i = 0; i < nodes.length; i++) {
+ node = nodes[i];
+ switch (node.type) {
+ case "Assign":
+ assign(node);
+ break;
+ case "ObjectPath":
+ setPath(node);
+ break;
+ case "ArrayPath":
+ addTableArray(node);
+ break;
+ }
+ }
+
+ return data;
+ }
+
+ function genError(err, line, col) {
+ var ex = new Error(err);
+ ex.line = line;
+ ex.column = col;
+ throw ex;
+ }
+
+ function assign(node) {
+ var key = node.key;
+ var value = node.value;
+ var line = node.line;
+ var column = node.column;
+
+ var fullPath;
+ if (currentPath) {
+ fullPath = currentPath + "." + key;
+ } else {
+ fullPath = key;
+ }
+ if (typeof context[key] !== "undefined") {
+ genError("Cannot redefine existing key '" + fullPath + "'.", line, column);
+ }
+
+ context[key] = reduceValueNode(value);
+
+ if (!pathAssigned(fullPath)) {
+ assignedPaths.push(fullPath);
+ valueAssignments.push(fullPath);
+ }
+ }
+
+
+ function pathAssigned(path) {
+ return assignedPaths.indexOf(path) !== -1;
+ }
+
+ function reduceValueNode(node) {
+ if (node.type === "Array") {
+ return reduceArrayWithTypeChecking(node.value);
+ } else if (node.type === "InlineTable") {
+ return reduceInlineTableNode(node.value);
+ } else {
+ return node.value;
+ }
+ }
+
+ function reduceInlineTableNode(values) {
+ var obj = {};
+ for (var i = 0; i < values.length; i++) {
+ var val = values[i];
+ if (val.value.type === "InlineTable") {
+ obj[val.key] = reduceInlineTableNode(val.value.value);
+ } else if (val.type === "InlineTableValue") {
+ obj[val.key] = reduceValueNode(val.value);
+ }
+ }
+
+ return obj;
+ }
+
+ function setPath(node) {
+ var path = node.value;
+ var quotedPath = path.map(quoteDottedString).join(".");
+ var line = node.line;
+ var column = node.column;
+
+ if (pathAssigned(quotedPath)) {
+ genError("Cannot redefine existing key '" + path + "'.", line, column);
+ }
+ assignedPaths.push(quotedPath);
+ context = deepRef(data, path, {}, line, column);
+ currentPath = path;
+ }
+
+ function addTableArray(node) {
+ var path = node.value;
+ var quotedPath = path.map(quoteDottedString).join(".");
+ var line = node.line;
+ var column = node.column;
+
+ if (!pathAssigned(quotedPath)) {
+ assignedPaths.push(quotedPath);
+ }
+ assignedPaths = assignedPaths.filter(function(p) {
+ return p.indexOf(quotedPath) !== 0;
+ });
+ assignedPaths.push(quotedPath);
+ context = deepRef(data, path, [], line, column);
+ currentPath = quotedPath;
+
+ if (context instanceof Array) {
+ var newObj = {};
+ context.push(newObj);
+ context = newObj;
+ } else {
+ genError("Cannot redefine existing key '" + path + "'.", line, column);
+ }
+ }
+
+ // Given a path 'a.b.c', create (as necessary) `start.a`,
+ // `start.a.b`, and `start.a.b.c`, assigning `value` to `start.a.b.c`.
+ // If `a` or `b` are arrays and have items in them, the last item in the
+ // array is used as the context for the next sub-path.
+ function deepRef(start, keys, value, line, column) {
+ var traversed = [];
+ var traversedPath = "";
+ var path = keys.join(".");
+ var ctx = start;
+
+ for (var i = 0; i < keys.length; i++) {
+ var key = keys[i];
+ traversed.push(key);
+ traversedPath = traversed.join(".");
+ if (typeof ctx[key] === "undefined") {
+ if (i === keys.length - 1) {
+ ctx[key] = value;
+ } else {
+ ctx[key] = {};
+ }
+ } else if (i !== keys.length - 1 && valueAssignments.indexOf(traversedPath) > -1) {
+ // already a non-object value at key, can't be used as part of a new path
+ genError("Cannot redefine existing key '" + traversedPath + "'.", line, column);
+ }
+
+ ctx = ctx[key];
+ if (ctx instanceof Array && ctx.length && i < keys.length - 1) {
+ ctx = ctx[ctx.length - 1];
+ }
+ }
+
+ return ctx;
+ }
+
+ function reduceArrayWithTypeChecking(array) {
+ // Ensure that all items in the array are of the same type
+ var firstType = null;
+ for (var i = 0; i < array.length; i++) {
+ var node = array[i];
+ if (firstType === null) {
+ firstType = node.type;
+ } else {
+ if (node.type !== firstType) {
+ genError("Cannot add value of type " + node.type + " to array of type " +
+ firstType + ".", node.line, node.column);
+ }
+ }
+ }
+
+ // Recursively reduce array of nodes into array of the nodes' values
+ return array.map(reduceValueNode);
+ }
+
+ function quoteDottedString(str) {
+ if (str.indexOf(".") > -1) {
+ return "\"" + str + "\"";
+ } else {
+ return str;
+ }
+ }
+}
+
+module.exports = {
+ compile: compile
+};