maestro-cli-roku
Version:
command line tools for maestro-roku projects
294 lines (293 loc) • 12.1 kB
JavaScript
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
};
(function () {
var sax;
var allElements = [];
var _parser = null;
if (typeof module !== 'undefined' && module.exports && !global.xmldocAssumeBrowser) {
// We're being used in a Node-like environment
sax = require('sax');
}
else {
// assume it's attached to the Window object in a browser
sax = this.sax;
if (!sax) // no sax for you!
throw new Error("Expected sax to be defined. Make sure you're including sax.js before this file.");
}
/*
XmlElement is our basic building block. Everything is an XmlElement; even XmlDocument
behaves like an XmlElement by inheriting its attributes and functions.
*/
function XmlElement(tag) {
// Capture the parser object off of the XmlDocument delegate
var parser = delegates[delegates.length - 1].parser;
this.name = tag.name;
this.attr = tag.attributes;
this.val = "";
this.children = [];
this.firstChild = null;
this.lastChild = null;
// Assign parse information
this.line = parser.line;
this.column = parser.column;
this.position = parser.position;
this.startTagPosition = parser.startTagPosition;
}
// Private methods
XmlElement.prototype._addChild = function (child) {
// add to our children array
this.children.push(child);
// update first/last pointers
if (!this.firstChild)
this.firstChild = child;
this.lastChild = child;
};
// SaxParser handlers
XmlElement.prototype._opentag = function (tag, endTagPosition) {
var child = new XmlElement(tag);
child.endTagPosition = endTagPosition;
allElements.push(child);
this._addChild(child);
delegates.unshift(child);
};
XmlElement.prototype._closetag = function (position) {
delegates.shift();
};
XmlElement.prototype._text = function (text) {
if (typeof this.children === 'undefined')
return;
this.val += text;
this._addChild(new XmlTextNode(text));
};
XmlElement.prototype._cdata = function (cdata) {
this.val += cdata;
this._addChild(new XmlCDataNode(cdata));
};
XmlElement.prototype._comment = function (comment) {
if (typeof this.children === 'undefined')
return;
this._addChild(new XmlCommentNode(comment));
};
XmlElement.prototype._error = function (err) {
throw err;
};
// Useful functions
XmlElement.prototype.eachChild = function (iterator, context) {
for (var i = 0, l = this.children.length; i < l; i++)
if (this.children[i].type === "element")
if (iterator.call(context, this.children[i], i, this.children) === false)
return;
};
XmlElement.prototype.childNamed = function (name) {
for (var i = 0, l = this.children.length; i < l; i++) {
var child = this.children[i];
if (child.name === name)
return child;
}
return undefined;
};
XmlElement.prototype.childrenNamed = function (name) {
var matches = [];
for (var i = 0, l = this.children.length; i < l; i++)
if (this.children[i].name === name)
matches.push(this.children[i]);
return matches;
};
XmlElement.prototype.childWithAttribute = function (name, value) {
for (var i = 0, l = this.children.length; i < l; i++) {
var child = this.children[i];
if (child.type === "element" && ((value && child.attr[name] === value) || (!value && child.attr[name])))
return child;
}
return undefined;
};
XmlElement.prototype.descendantWithPath = function (path) {
var descendant = this;
var components = path.split('.');
for (var i = 0, l = components.length; i < l; i++)
if (descendant && descendant.type === "element")
descendant = descendant.childNamed(components[i]);
else
return undefined;
return descendant;
};
XmlElement.prototype.valueWithPath = function (path) {
var components = path.split('@');
var descendant = this.descendantWithPath(components[0]);
if (descendant)
return components.length > 1 ? descendant.attr[components[1]] : descendant.val;
else
return undefined;
};
// String formatting (for debugging)
XmlElement.prototype.toString = function (options) {
return this.toStringWithIndent("", options);
};
XmlElement.prototype.toStringWithIndent = function (indent, options) {
var s = indent + "<" + this.name;
var linebreak = options && options.compressed ? "" : "\n";
var preserveWhitespace = options && options.preserveWhitespace;
for (var name in this.attr)
if (Object.prototype.hasOwnProperty.call(this.attr, name))
s += " " + name + '="' + escapeXML(this.attr[name]) + '"';
if (this.children.length === 1 && this.children[0].type !== "element") {
s += ">" + this.children[0].toString(options) + "</" + this.name + ">";
}
else if (this.children.length) {
s += ">" + linebreak;
var childIndent = indent + (options && options.compressed ? "" : " ");
for (var i = 0, l = this.children.length; i < l; i++) {
s += this.children[i].toStringWithIndent(childIndent, options) + linebreak;
}
s += indent + "</" + this.name + ">";
}
else if (options && options.html) {
var whiteList = [
"area", "base", "br", "col", "embed", "frame", "hr", "img", "input",
"keygen", "link", "menuitem", "meta", "param", "source", "track", "wbr"
];
if (whiteList.indexOf(this.name) !== -1)
s += "/>";
else
s += "></" + this.name + ">";
}
else {
s += "/>";
}
return s;
};
// Alternative XML nodes
function XmlTextNode(text) {
this.text = text;
}
XmlTextNode.prototype.toString = function (options) {
return formatText(escapeXML(this.text), options);
};
XmlTextNode.prototype.toStringWithIndent = function (indent, options) {
return indent + this.toString(options);
};
function XmlCDataNode(cdata) {
this.cdata = cdata;
}
XmlCDataNode.prototype.toString = function (options) {
return "<![CDATA[" + formatText(this.cdata, options) + "]]>";
};
XmlCDataNode.prototype.toStringWithIndent = function (indent, options) {
return indent + this.toString(options);
};
function XmlCommentNode(comment) {
this.comment = comment;
}
XmlCommentNode.prototype.toString = function (options) {
return "<!--" + formatText(escapeXML(this.comment), options) + "-->";
};
XmlCommentNode.prototype.toStringWithIndent = function (indent, options) {
return indent + this.toString(options);
};
// Node type tag
XmlElement.prototype.type = "element";
XmlTextNode.prototype.type = "text";
XmlCDataNode.prototype.type = "cdata";
XmlCommentNode.prototype.type = "comment";
/*
XmlDocument is the class we expose to the user; it uses the sax parser to create a hierarchy
of XmlElements.
*/
function XmlDocument(xml) {
xml && (xml = xml.toString().trim());
allElements = [];
if (!xml)
throw new Error("No XML to parse!");
// Stores doctype (if defined)
this.doctype = "";
// Expose the parser to the other delegates while the parser is running
this.parser = sax.parser(true); // strict
_parser = this.parser;
addParserEvents(this.parser);
// We'll use the file-scoped "delegates" var to remember what elements we're currently
// parsing; they will push and pop off the stack as we get deeper into the XML hierarchy.
// It's safe to use a global because JS is single-threaded.
delegates = [this];
this.parser.write(xml);
this.allElements = allElements;
// Remove the parser as it is no longer needed and should not be exposed to clients
delete this.parser;
}
// make XmlDocument inherit XmlElement's methods
extend(XmlDocument.prototype, XmlElement.prototype);
XmlDocument.prototype._opentag = function (tag, endTagPosition) {
if (typeof this.children === 'undefined')
// the first tag we encounter should be the root - we'll "become" the root XmlElement
XmlElement.call(this, tag);
else
// all other tags will be the root element's children
XmlElement.prototype._opentag.apply(this, arguments);
};
XmlDocument.prototype._doctype = function (doctype) {
this.doctype += doctype;
};
// file-scoped global stack of delegates
var delegates = null;
/*
Helper functions
*/
function addParserEvents(parser) {
parser.onopentag = parser_opentag;
parser.onclosetag = parser_closetag;
parser.ontext = parser_text;
parser.oncdata = parser_cdata;
parser.oncomment = parser_comment;
parser.ondoctype = parser_doctype;
parser.onerror = parser_error;
}
// create these closures and cache them by keeping them file-scoped
function parser_opentag() { delegates[0] && delegates[0]._opentag.apply(delegates[0], __spread(arguments, [this.position])); }
function parser_closetag() { delegates[0] && delegates[0]._closetag.apply(delegates[0], [this.position]); }
function parser_text() { delegates[0] && delegates[0]._text.apply(delegates[0], arguments); }
function parser_cdata() { delegates[0] && delegates[0]._cdata.apply(delegates[0], arguments); }
function parser_comment() { delegates[0] && delegates[0]._comment.apply(delegates[0], arguments); }
function parser_doctype() { delegates[0] && delegates[0]._doctype.apply(delegates[0], arguments); }
function parser_error() { delegates[0] && delegates[0]._error.apply(delegates[0], arguments); }
// a relatively standard extend method
function extend(destination, source) {
for (var prop in source)
if (source.hasOwnProperty(prop))
destination[prop] = source[prop];
}
// escapes XML entities like "<", "&", etc.
function escapeXML(value) {
return value.toString().replace(/&/g, '&').replace(/</g, "<").replace(/>/g, ">").replace(/'/g, ''').replace(/"/g, '"');
}
// formats some text for debugging given a few options
function formatText(text, options) {
var finalText = text;
if (options && options.trimmed && text.length > 25)
finalText = finalText.substring(0, 25).trim() + "…";
if (!(options && options.preserveWhitespace))
finalText = finalText.trim();
return finalText;
}
// Are we being used in a Node-like environment?
if (typeof module !== 'undefined' && module.exports && !global.xmldocAssumeBrowser)
module.exports.XmlDocument = XmlDocument;
else
this.XmlDocument = XmlDocument;
})();