pax_global_header00006660000000000000000000000064130230014170014501gustar00rootroot0000000000000052 comment=6d351f3c8eec030fb69a56d18c359a299a9cc475 ltx-2.6.2/000077500000000000000000000000001302300141700123175ustar00rootroot00000000000000ltx-2.6.2/.editorconfig000066400000000000000000000003071302300141700147740ustar00rootroot00000000000000# EditorConfig is awesome: http://EditorConfig.org root = true [*] end_of_line = lf insert_final_newline = true charset = utf-8 trim_trailing_whitespace = true indent_style = space indent_size = 2 ltx-2.6.2/.gitignore000066400000000000000000000001301302300141700143010ustar00rootroot00000000000000!.editorconfig !.gitignore !.npmignore !.travis.yml node_modules/ bundle.js yarn.lock ltx-2.6.2/.npmignore000066400000000000000000000001241302300141700143130ustar00rootroot00000000000000benchmarks/ test/ .editorconfig .gitignore .npmignore .travis.yml CONTRIBUTING.md ltx-2.6.2/.travis.yml000066400000000000000000000003061302300141700144270ustar00rootroot00000000000000sudo: false language: node_js env: - CXX="g++-4.8" node_js: - '4' - '5' - '6' - '7' addons: apt: sources: - ubuntu-toolchain-r-test packages: - g++-4.8 - gcc-4.8 ltx-2.6.2/CONTRIBUTING.md000066400000000000000000000030521302300141700145500ustar00rootroot00000000000000# Contributing guide ## Thank you Firstly, thanks for thinking about contributing to `ltx`! Here's some guidelines that will help you get your pull requests merged more quickly/easily. __Note:__ If there's a feature you'd like, there's a bug you'd like to fix, or you'd just like to get involved please raise an issue and start a conversation. We'll help as much as we can so you can get contributing - although we may not always get back right away :) ## Coding standards Most of the coding standards are covered by `.jshintrc`. You can also test any changes with `grunt test` (this will also run the tests). Things not covered by jshint: * Unless required __no semicolons__ they are not required * Short one-line `if` statements do not require nipple brackets (provided functionality is clear) * Multiple conditionals within an `if` statement should be surrounded by brackets * `exports`/`module.exports` should be at the end of the file * Longer, descriptive variable names are preferred, e.g. `error` vs `err` We acknowledge all the code does not meet these standards but we are working to change this over time. ## Tests All code (unless very trivial, or documentation) should be accompanied by tests. If you are unsure about testing please make a pull request and we'll try and help you get some tests in place for your code. Tests are run using `npm test` and should all pass before you make a pull request. If you pull request relates to an issue, please name your test after the issue number (e.g. 'issue #58') so we can track it if there is a regression. ltx-2.6.2/LICENSE000066400000000000000000000020411302300141700133210ustar00rootroot00000000000000Copyright (c) 2010 Stephan Maka Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ltx-2.6.2/README.md000066400000000000000000000044571302300141700136100ustar00rootroot00000000000000ltx === `JavaScript XML library` [![build status](https://img.shields.io/travis/node-xmpp/ltx/master.svg?style=flat-square)](https://travis-ci.org/node-xmpp/ltx/branches) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](http://standardjs.com/) ltx is a fast XML builder, parser, serialization and manipulation library for JavaScript. The builder is a convenient and succinct API to build XML documents represented in memory as JavaScript primitives that can be serialized to XML strings. The parser can parse XML documents or streams and support [multiple parsers](#parsers). Features: * succinct API to build and manipulate XML objects * parse XML strings * parse XML streams * [multiple parser backends](#parsers) * [JSX](https://facebook.github.io/jsx/) compatible (with `ltx.createElement` pragma) * [tagged template](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/template_strings) support `` ltx`` `` ## Install `npm install ltx` ## Parsers By default ltx uses its own parser which is the fastest but doesn't support advanced XML features. ltx supports third party parsers when such features are needed. | parser | ops/sec | native | stream | |--------------------------------------------------------------------------------------------|--------:|:------:|:------:| | [sax-js](https://github.com/isaacs/sax-js) | 99,412 | ☐ | ☑ | | [node-xml](https://github.com/dylang/node-xml) | 130,631 | ☐ | ☑ | | [libxmljs](https://github.com/polotek/libxmljs) | 276,136 | ☑ | ☐ | | [node-expat](https://github.com/node-xmpp/node-expat) | 322,769 | ☑ | ☑ | | **[ltx/lib/parsers/ltx](https://github.com/node-xmpp/ltx/blob/master/lib/parsers/ltx.js)** | 641,327 | ☐ | ☑ | From [ltx/benchmarks/parsers.js](https://github.com/node-xmpp/ltx/blob/master/benchmarks/parsers.js), higher is better. ## Documentation http://node-xmpp.org/doc/ltx.html ## Benchmark ``` npm run benchmark ``` ## Test ``` npm install npm test ``` ltx-2.6.2/benchmarks/000077500000000000000000000000001302300141700144345ustar00rootroot00000000000000ltx-2.6.2/benchmarks/index.js000066400000000000000000000007671302300141700161130ustar00rootroot00000000000000'use strict' var readdir = require('fs').readdirSync var basename = require('path').basename readdir(__dirname).forEach(function (file) { if (file === basename(__filename)) return var suite = require('./' + file) console.log('suite', suite.name) suite .on('cycle', function (event) { console.log(event.target.toString()) }) .on('complete', function () { console.log('Fastest is "' + this.filter('fastest').map('name') + '"') }) .run({'async': false}) console.log('\n') }) ltx-2.6.2/benchmarks/ltx.js000066400000000000000000000033771302300141700156130ustar00rootroot00000000000000'use strict' /* benchmark the speed of the different methods to create elements Not all tests are equally functional but it gives a good idea of what to expect from the different techniques. */ var benchmark = require('benchmark') var ltx = require('../index') var createElement = ltx.createElement var tag = ltx.tag var Element = ltx.Element var parse = ltx.parse var XML = [ '', 'Where there is love there is life.', '' ].join('') var el = parse(XML) var suite = new benchmark.Suite('ltx') suite.add('tag with template literal', function () { tag` ${'Where there is love there is life.'} ` }) suite.add('tag with direct call', function () { tag( [ '\n \n ', '\n \n' ], 'foo@bar', 'bar@foo', 'chat', 'foobar', 'Where there is love there is life.' ) }) suite.add('serialize and parse', function () { parse(el.toString()) }) suite.add('parse', function () { parse(XML) }) suite.add('createElement (jsx)', function () { createElement( 'message', {to: 'foo@bar', from: 'bar@foo', type: 'chat', id: 'foobar'}, createElement('body', null, 'Where there is love there is life.') ) }) suite.add('serialize', function () { el.toString() }) suite.add('clone', function () { el.clone() }) suite.add('Element', function () { new Element('message', {to: 'foo@bar', from: 'bar@foo', type: 'chat', id: 'foobar'}) .c('body').t('Where there is love there is life.').root() }) module.exports = suite ltx-2.6.2/benchmarks/parse.js000066400000000000000000000010451302300141700161040ustar00rootroot00000000000000'use strict' /* benchmark the parsing speed of the supported backends */ var benchmark = require('benchmark') var ltx = require('../index') var parsers = require('../lib/parsers') var XML = [ '', 'Where there is love there is life.', '' ].join('') var suite = new benchmark.Suite('backends parse') parsers.forEach(function (Parser) { suite.add(Parser.name.slice(3), function () { ltx.parse(XML, {Parser: Parser}) }) }) module.exports = suite ltx-2.6.2/benchmarks/parsers.js000066400000000000000000000027761302300141700164650ustar00rootroot00000000000000'use strict' /* * benchmark the parsing speed of the supported backends * difference with parse.js benchmark is that this doesn't use ltx at all */ var benchmark = require('benchmark') var nodeXml = require('node-xml') var libxml = require('libxmljs') var expat = require('node-expat') var sax = require('sax') // var ltx = require('..') var LtxSaxParser = require('../lib/parsers/ltx') function NodeXmlParser () { var parser = new nodeXml.SaxParser(function (cb) {}) this.parse = function (s) { parser.parseString(s) } this.name = 'node-xml' } function LibXmlJsParser () { var parser = new libxml.SaxPushParser(function (cb) {}) this.parse = function (s) { parser.push(s, false) } this.name = 'libxmljs' } function SaxParser () { var parser = sax.parser() this.parse = function (s) { parser.write(s).close() } this.name = 'sax' } function ExpatParser () { var parser = new expat.Parser() this.parse = function (s) { parser.parse(s, false) } this.name = 'node-expat' } function LtxParser () { var parser = new LtxSaxParser() this.parse = function (s) { parser.write(s) } this.name = 'ltx' } var parsers = [ SaxParser, NodeXmlParser, LibXmlJsParser, ExpatParser, LtxParser ].map(function (Parser) { return new Parser() }) var suite = new benchmark.Suite('XML parsers comparison') parsers.forEach(function (parser) { parser.parse('') suite.add(parser.name, function () { parser.parse('quux') }) }) module.exports = suite ltx-2.6.2/benchmarks/write.js000066400000000000000000000010641302300141700161250ustar00rootroot00000000000000'use strict' /* benchmark the serialization speed of the the supported backends */ var benchmark = require('benchmark') var parsers = require('../lib/parsers') var XML = [ '', 'Where there is love there is life.', '' ].join('') var suite = new benchmark.Suite('backends write') parsers.forEach(function (Parser) { var parser = new Parser() parser.write('') suite.add(Parser.name.slice(3), function () { parser.write(XML) }) }) module.exports = suite ltx-2.6.2/index.js000066400000000000000000000021411302300141700137620ustar00rootroot00000000000000'use strict' var parse = require('./lib/parse') var Parser = require('./lib/Parser') var escape = require('./lib/escape') var Element = require('./lib/Element') var equal = require('./lib/equal') var createElement = require('./lib/createElement') var tag = require('./lib/tag') var tagString = require('./lib/tagString') var is = require('./lib/is') var clone = require('./lib/clone') var stringify = require('./lib/stringify') exports = module.exports = function ltx () { return tag.apply(null, arguments) } exports.Element = Element exports.equal = equal.equal exports.nameEqual = equal.name exports.attrsEqual = equal.attrs exports.childrenEqual = equal.children exports.isNode = is.isNode exports.isElement = is.isElement exports.isText = is.isText exports.clone = clone exports.createElement = createElement exports.escapeXML = escape.escapeXML exports.unescapeXML = escape.unescapeXML exports.escapeXMLText = escape.escapeXMLText exports.unescapeXMLText = escape.unescapeXMLText exports.Parser = Parser exports.parse = parse exports.tag = tag exports.tagString = tagString exports.stringify = stringify ltx-2.6.2/lib/000077500000000000000000000000001302300141700130655ustar00rootroot00000000000000ltx-2.6.2/lib/DOMElement.js000066400000000000000000000050211302300141700153520ustar00rootroot00000000000000'use strict' var inherits = require('inherits') var Element = require('./Element') function DOMElement (name, attrs) { Element.call(this, name, attrs) this.nodeType = 1 this.nodeName = this.localName } inherits(DOMElement, Element) DOMElement.prototype._getElement = function (name, attrs) { var element = new DOMElement(name, attrs) return element } Object.defineProperty(DOMElement.prototype, 'localName', { get: function () { return this.getName() } }) Object.defineProperty(DOMElement.prototype, 'namespaceURI', { get: function () { return this.getNS() } }) Object.defineProperty(DOMElement.prototype, 'parentNode', { get: function () { return this.parent } }) Object.defineProperty(DOMElement.prototype, 'childNodes', { get: function () { return this.children } }) Object.defineProperty(DOMElement.prototype, 'textContent', { get: function () { return this.getText() }, set: function (value) { this.children.push(value) } }) DOMElement.prototype.getElementsByTagName = function (name) { return this.getChildren(name) } DOMElement.prototype.getAttribute = function (name) { return this.getAttr(name) } DOMElement.prototype.setAttribute = function (name, value) { this.attr(name, value) } DOMElement.prototype.getAttributeNS = function (ns, name) { if (ns === 'http://www.w3.org/XML/1998/namespace') { return this.getAttr(['xml', name].join(':')) } return this.getAttr(name, ns) } DOMElement.prototype.setAttributeNS = function (ns, name, value) { var prefix if (ns === 'http://www.w3.org/XML/1998/namespace') { prefix = 'xml' } else { var nss = this.getXmlns() prefix = nss[ns] || '' } if (prefix) { this.attr([prefix, name].join(':'), value) } } DOMElement.prototype.removeAttribute = function (name) { this.attr(name, null) } DOMElement.prototype.removeAttributeNS = function (ns, name) { var prefix if (ns === 'http://www.w3.org/XML/1998/namespace') { prefix = 'xml' } else { var nss = this.getXmlns() prefix = nss[ns] || '' } if (prefix) { this.attr([prefix, name].join(':'), null) } } DOMElement.prototype.appendChild = function (el) { this.cnode(el) } DOMElement.prototype.removeChild = function (el) { this.remove(el) } DOMElement.createElement = function (name, attrs /*, child1, child2, ... */) { var el = new DOMElement(name, attrs) var children = Array.prototype.slice.call(arguments, 2) children.forEach(function (child) { el.appendChild(child) }) return el } module.exports = DOMElement ltx-2.6.2/lib/Element.js000066400000000000000000000204431302300141700150170ustar00rootroot00000000000000'use strict' var escape = require('./escape') var escapeXML = escape.escapeXML var escapeXMLText = escape.escapeXMLText var equality = require('./equal') var equal = equality.equal var nameEqual = equality.name var attrsEqual = equality.attrs var childrenEqual = equality.children var clone = require('./clone') /** * Element * * Attributes are in the element.attrs object. Children is a list of * either other Elements or Strings for text content. **/ function Element (name, attrs) { this.name = name this.parent = null this.children = [] this.attrs = {} this.setAttrs(attrs) } /* Accessors */ /** * if (element.is('message', 'jabber:client')) ... **/ Element.prototype.is = function (name, xmlns) { return (this.getName() === name) && (!xmlns || (this.getNS() === xmlns)) } /* without prefix */ Element.prototype.getName = function () { if (this.name.indexOf(':') >= 0) { return this.name.substr(this.name.indexOf(':') + 1) } else { return this.name } } /** * retrieves the namespace of the current element, upwards recursively **/ Element.prototype.getNS = function () { if (this.name.indexOf(':') >= 0) { var prefix = this.name.substr(0, this.name.indexOf(':')) return this.findNS(prefix) } return this.findNS() } /** * find the namespace to the given prefix, upwards recursively **/ Element.prototype.findNS = function (prefix) { if (!prefix) { /* default namespace */ if (this.attrs.xmlns) { return this.attrs.xmlns } else if (this.parent) { return this.parent.findNS() } } else { /* prefixed namespace */ var attr = 'xmlns:' + prefix if (this.attrs[attr]) { return this.attrs[attr] } else if (this.parent) { return this.parent.findNS(prefix) } } } /** * Recursiverly gets all xmlns defined, in the form of {url:prefix} **/ Element.prototype.getXmlns = function () { var namespaces = {} if (this.parent) { namespaces = this.parent.getXmlns() } for (var attr in this.attrs) { var m = attr.match('xmlns:?(.*)') if (this.attrs.hasOwnProperty(attr) && m) { namespaces[this.attrs[attr]] = m[1] } } return namespaces } Element.prototype.setAttrs = function (attrs) { if (typeof attrs === 'string') { this.attrs.xmlns = attrs } else if (attrs) { Object.keys(attrs).forEach(function (key) { this.attrs[key] = attrs[key] }, this) } } /** * xmlns can be null, returns the matching attribute. **/ Element.prototype.getAttr = function (name, xmlns) { if (!xmlns) { return this.attrs[name] } var namespaces = this.getXmlns() if (!namespaces[xmlns]) { return null } return this.attrs[[namespaces[xmlns], name].join(':')] } /** * xmlns can be null **/ Element.prototype.getChild = function (name, xmlns) { return this.getChildren(name, xmlns)[0] } /** * xmlns can be null **/ Element.prototype.getChildren = function (name, xmlns) { var result = [] for (var i = 0; i < this.children.length; i++) { var child = this.children[i] if (child.getName && (child.getName() === name) && (!xmlns || (child.getNS() === xmlns))) { result.push(child) } } return result } /** * xmlns and recursive can be null **/ Element.prototype.getChildByAttr = function (attr, val, xmlns, recursive) { return this.getChildrenByAttr(attr, val, xmlns, recursive)[0] } /** * xmlns and recursive can be null **/ Element.prototype.getChildrenByAttr = function (attr, val, xmlns, recursive) { var result = [] for (var i = 0; i < this.children.length; i++) { var child = this.children[i] if (child.attrs && (child.attrs[attr] === val) && (!xmlns || (child.getNS() === xmlns))) { result.push(child) } if (recursive && child.getChildrenByAttr) { result.push(child.getChildrenByAttr(attr, val, xmlns, true)) } } if (recursive) { result = [].concat.apply([], result) } return result } Element.prototype.getChildrenByFilter = function (filter, recursive) { var result = [] for (var i = 0; i < this.children.length; i++) { var child = this.children[i] if (filter(child)) { result.push(child) } if (recursive && child.getChildrenByFilter) { result.push(child.getChildrenByFilter(filter, true)) } } if (recursive) { result = [].concat.apply([], result) } return result } Element.prototype.getText = function () { var text = '' for (var i = 0; i < this.children.length; i++) { var child = this.children[i] if ((typeof child === 'string') || (typeof child === 'number')) { text += child } } return text } Element.prototype.getChildText = function (name, xmlns) { var child = this.getChild(name, xmlns) return child ? child.getText() : null } /** * Return all direct descendents that are Elements. * This differs from `getChildren` in that it will exclude text nodes, * processing instructions, etc. */ Element.prototype.getChildElements = function () { return this.getChildrenByFilter(function (child) { return child instanceof Element }) } /* Builder */ /** returns uppermost parent */ Element.prototype.root = function () { if (this.parent) { return this.parent.root() } return this } Element.prototype.tree = Element.prototype.root /** just parent or itself */ Element.prototype.up = function () { if (this.parent) { return this.parent } return this } /** create child node and return it */ Element.prototype.c = function (name, attrs) { return this.cnode(new Element(name, attrs)) } Element.prototype.cnode = function (child) { this.children.push(child) if (typeof child === 'object') { child.parent = this } return child } /** add text node and return element */ Element.prototype.t = function (text) { this.children.push(text) return this } /* Manipulation */ /** * Either: * el.remove(childEl) * el.remove('author', 'urn:...') */ Element.prototype.remove = function (el, xmlns) { var filter if (typeof el === 'string') { /* 1st parameter is tag name */ filter = function (child) { return !(child.is && child.is(el, xmlns)) } } else { /* 1st parameter is element */ filter = function (child) { return child !== el } } this.children = this.children.filter(filter) return this } Element.prototype.clone = function () { return clone(this) } Element.prototype.text = function (val) { if (val && this.children.length === 1) { this.children[0] = val return this } return this.getText() } Element.prototype.attr = function (attr, val) { if (typeof val !== 'undefined' || val === null) { if (!this.attrs) { this.attrs = {} } this.attrs[attr] = val return this } return this.attrs[attr] } /* Serialization */ Element.prototype.toString = function () { var s = '' this.write(function (c) { s += c }) return s } Element.prototype.toJSON = function () { return { name: this.name, attrs: this.attrs, children: this.children.map(function (child) { return child && child.toJSON ? child.toJSON() : child }) } } Element.prototype._addChildren = function (writer) { writer('>') for (var i = 0; i < this.children.length; i++) { var child = this.children[i] /* Skip null/undefined */ if (child || (child === 0)) { if (child.write) { child.write(writer) } else if (typeof child === 'string') { writer(escapeXMLText(child)) } else if (child.toString) { writer(escapeXMLText(child.toString(10))) } } } writer('') } Element.prototype.write = function (writer) { writer('<') writer(this.name) for (var k in this.attrs) { var v = this.attrs[k] if (v != null) { // === null || undefined writer(' ') writer(k) writer('="') if (typeof v !== 'string') { v = v.toString() } writer(escapeXML(v)) writer('"') } } if (this.children.length === 0) { writer('/>') } else { this._addChildren(writer) } } Element.prototype.nameEquals = function (el) { return nameEqual(this, el) } Element.prototype.attrsEquals = function (el) { return attrsEqual(this, el) } Element.prototype.childrenEquals = function (el) { return childrenEqual(this, el) } Element.prototype.equals = function (el) { return equal(this, el) } module.exports = Element ltx-2.6.2/lib/Parser.js000066400000000000000000000030201302300141700146520ustar00rootroot00000000000000'use strict' var EventEmitter = require('events').EventEmitter var inherits = require('inherits') var Element = require('./Element') var LtxParser = require('./parsers/ltx') var Parser = function (options) { EventEmitter.call(this) var ParserInterface = this.Parser = (options && options.Parser) || this.DefaultParser var ElementInterface = this.Element = (options && options.Element) || this.DefaultElement this.parser = new ParserInterface() var el var self = this this.parser.on('startElement', function (name, attrs) { var child = new ElementInterface(name, attrs) if (!el) { el = child } else { el = el.cnode(child) } }) this.parser.on('endElement', function (name) { if (!el) { /* Err */ } else if (name === el.name) { if (el.parent) { el = el.parent } else if (!self.tree) { self.tree = el el = undefined } } }) this.parser.on('text', function (str) { if (el) { el.t(str) } }) this.parser.on('error', function (e) { self.error = e self.emit('error', e) }) } inherits(Parser, EventEmitter) Parser.prototype.DefaultParser = LtxParser Parser.prototype.DefaultElement = Element Parser.prototype.write = function (data) { this.parser.write(data) } Parser.prototype.end = function (data) { this.parser.end(data) if (!this.error) { if (this.tree) { this.emit('tree', this.tree) } else { this.emit('error', new Error('Incomplete document')) } } } module.exports = Parser ltx-2.6.2/lib/clone.js000066400000000000000000000004031302300141700145200ustar00rootroot00000000000000'use strict' module.exports = function clone (el) { var clone = new el.constructor(el.name, el.attrs) for (var i = 0; i < el.children.length; i++) { var child = el.children[i] clone.cnode(child.clone ? child.clone() : child) } return clone } ltx-2.6.2/lib/createElement.js000066400000000000000000000010271302300141700162000ustar00rootroot00000000000000'use strict' var Element = require('./Element') /** * JSX compatible API, use this function as pragma * https://facebook.github.io/jsx/ * * @param {string} name name of the element * @param {object} attrs object of attribute key/value pairs * @return {Element} Element */ module.exports = function createElement (name, attrs /*, child1, child2, ... */) { var el = new Element(name, attrs) for (var i = 2; i < arguments.length; i++) { var child = arguments[i] if (child) el.cnode(child) } return el } ltx-2.6.2/lib/equal.js000066400000000000000000000023361302300141700145360ustar00rootroot00000000000000'use strict' function nameEqual (a, b) { return a.name === b.name } function attrsEqual (a, b) { var attrs = a.attrs var keys = Object.keys(attrs) var length = keys.length if (length !== Object.keys(b.attrs).length) return false for (var i = 0, l = length; i < l; i++) { var key = keys[i] var value = attrs[key] if (value == null || b.attrs[key] == null) { // === null || undefined if (value !== b.attrs[key]) return false } else if (value.toString() !== b.attrs[key].toString()) { return false } } return true } function childrenEqual (a, b) { var children = a.children var length = children.length if (length !== b.children.length) return false for (var i = 0, l = length; i < l; i++) { var child = children[i] if (typeof child === 'string') { if (child !== b.children[i]) return false } else { if (!child.equals(b.children[i])) return false } } return true } function equal (a, b) { if (!nameEqual(a, b)) return false if (!attrsEqual(a, b)) return false if (!childrenEqual(a, b)) return false return true } module.exports.name = nameEqual module.exports.attrs = attrsEqual module.exports.children = childrenEqual module.exports.equal = equal ltx-2.6.2/lib/escape.js000066400000000000000000000016301302300141700146630ustar00rootroot00000000000000'use strict' var escapeXMLTable = { '&': '&', '<': '<', '>': '>', '"': '"', '\'': ''' } function escapeXMLReplace (match) { return escapeXMLTable[match] } var unescapeXMLTable = { '&': '&', '&': '&', '<': '<', '<': '<', '>': '>', '>': '>', '"': '"', '"': '"', ''': "'", ''': "'" } function unescapeXMLReplace (match) { return unescapeXMLTable[match] } exports.escapeXML = function escapeXML (s) { return s.replace(/&|<|>|"|'/g, escapeXMLReplace) } exports.unescapeXML = function unescapeXML (s) { return s.replace(/&(amp|#38|lt|#60|gt|#62|quot|#34|apos|#39);/g, unescapeXMLReplace) } exports.escapeXMLText = function escapeXMLText (s) { return s.replace(/&|<|>/g, escapeXMLReplace) } exports.unescapeXMLText = function unescapeXMLText (s) { return s.replace(/&(amp|#38|lt|#60|gt|#62);/g, unescapeXMLReplace) } ltx-2.6.2/lib/is.js000066400000000000000000000005011302300141700140320ustar00rootroot00000000000000'use strict' var Element = require('./Element') module.exports.isNode = function is (el) { return el instanceof Element || typeof el === 'string' } module.exports.isElement = function isElement (el) { return el instanceof Element } module.exports.isText = function isText (el) { return typeof el === 'string' } ltx-2.6.2/lib/parse.js000066400000000000000000000007321302300141700145370ustar00rootroot00000000000000'use strict' var Parser = require('./Parser') module.exports = function parse (data, options) { var p if (typeof options === 'function') { p = new options() // eslint-disable-line } else { p = new Parser(options) } var result = null var error = null p.on('tree', function (tree) { result = tree }) p.on('error', function (e) { error = e }) p.write(data) p.end() if (error) { throw error } else { return result } } ltx-2.6.2/lib/parsers/000077500000000000000000000000001302300141700145445ustar00rootroot00000000000000ltx-2.6.2/lib/parsers/index.js000066400000000000000000000002321302300141700162060ustar00rootroot00000000000000'use strict' module.exports = [ 'sax-js', 'node-xml', 'libxmljs', 'node-expat', 'ltx' ].map(function (name) { return require('./' + name) }) ltx-2.6.2/lib/parsers/libxmljs.js000066400000000000000000000025361302300141700167340ustar00rootroot00000000000000'use strict' var inherits = require('inherits') var EventEmitter = require('events').EventEmitter var libxmljs = require('libxmljs') function SaxLibxmljs () { EventEmitter.call(this) this.parser = new libxmljs.SaxPushParser() var that = this this.parser.on('startElementNS', function (name, attrs, prefix, uri, nss) { var a = {} attrs.forEach(function (attr) { var name = attr[0] if (attr[1]) name = attr[1] + ':' + name a[name] = attr[3] }) nss.forEach(function (ns) { var name = 'xmlns' if (ns[0] !== null) { name += (':' + ns[0]) } a[name] = ns[1] }) that.emit('startElement', (prefix ? prefix + ':' : '') + name, a) }) this.parser.on('endElementNS', function (name, prefix) { that.emit('endElement', (prefix ? prefix + ':' : '') + name) }) this.parser.on('characters', function (str) { that.emit('text', str) }) this.parser.on('cadata', function (str) { that.emit('text', str) }) this.parser.on('error', function (err) { that.emit('error', err) }) } inherits(SaxLibxmljs, EventEmitter) SaxLibxmljs.prototype.write = function (data) { if (typeof data !== 'string') { data = data.toString() } this.parser.push(data) } SaxLibxmljs.prototype.end = function (data) { if (data) { this.write(data) } } module.exports = SaxLibxmljs ltx-2.6.2/lib/parsers/ltx.js000066400000000000000000000110151302300141700157070ustar00rootroot00000000000000'use strict' var inherits = require('inherits') var EventEmitter = require('events').EventEmitter var unescapeXML = require('../escape').unescapeXML var STATE_TEXT = 0 var STATE_IGNORE_COMMENT = 1 var STATE_IGNORE_INSTRUCTION = 2 var STATE_TAG_NAME = 3 var STATE_TAG = 4 var STATE_ATTR_NAME = 5 var STATE_ATTR_EQ = 6 var STATE_ATTR_QUOT = 7 var STATE_ATTR_VALUE = 8 var SaxLtx = module.exports = function SaxLtx () { EventEmitter.call(this) var state = STATE_TEXT var remainder var tagName var attrs var endTag var selfClosing var attrQuote var recordStart = 0 var attrName this._handleTagOpening = function (endTag, tagName, attrs) { if (!endTag) { this.emit('startElement', tagName, attrs) if (selfClosing) { this.emit('endElement', tagName) } } else { this.emit('endElement', tagName) } } this.write = function (data) { if (typeof data !== 'string') { data = data.toString() } var pos = 0 /* Anything from previous write()? */ if (remainder) { data = remainder + data pos += remainder.length remainder = null } function endRecording () { if (typeof recordStart === 'number') { var recorded = data.slice(recordStart, pos) recordStart = undefined return recorded } } for (; pos < data.length; pos++) { var c = data.charCodeAt(pos) switch (state) { case STATE_TEXT: if (c === 60 /* < */) { var text = endRecording() if (text) { this.emit('text', unescapeXML(text)) } state = STATE_TAG_NAME recordStart = pos + 1 attrs = {} } break case STATE_TAG_NAME: if (c === 47 /* / */ && recordStart === pos) { recordStart = pos + 1 endTag = true } else if (c === 33 /* ! */) { recordStart = undefined state = STATE_IGNORE_COMMENT } else if (c === 63 /* ? */) { recordStart = undefined state = STATE_IGNORE_INSTRUCTION } else if (c <= 32 || c === 47 /* / */ || c === 62 /* > */) { tagName = endRecording() pos-- state = STATE_TAG } break case STATE_IGNORE_COMMENT: if (c === 62 /* > */) { var prevFirst = data.charCodeAt(pos - 1) var prevSecond = data.charCodeAt(pos - 2) if (prevFirst === 45 /* - */ && prevSecond === 45 /* - */) { state = STATE_TEXT } } break case STATE_IGNORE_INSTRUCTION: if (c === 62 /* > */) { var prev = data.charCodeAt(pos - 1) if (prev === 63 /* ? */) { state = STATE_TEXT } } break case STATE_TAG: if (c === 62 /* > */) { this._handleTagOpening(endTag, tagName, attrs) tagName = undefined attrs = undefined endTag = undefined selfClosing = undefined state = STATE_TEXT recordStart = pos + 1 } else if (c === 47 /* / */) { selfClosing = true } else if (c > 32) { recordStart = pos state = STATE_ATTR_NAME } break case STATE_ATTR_NAME: if (c <= 32 || c === 61 /* = */) { attrName = endRecording() pos-- state = STATE_ATTR_EQ } break case STATE_ATTR_EQ: if (c === 61 /* = */) { state = STATE_ATTR_QUOT } break case STATE_ATTR_QUOT: if (c === 34 /* " */ || c === 39 /* ' */) { attrQuote = c state = STATE_ATTR_VALUE recordStart = pos + 1 } break case STATE_ATTR_VALUE: if (c === attrQuote) { var value = unescapeXML(endRecording()) attrs[attrName] = value attrName = undefined state = STATE_TAG } break } } if (typeof recordStart === 'number' && recordStart <= data.length) { remainder = data.slice(recordStart) recordStart = 0 } } /* var origEmit = this.emit this.emit = function() { console.log('ltx', arguments) origEmit.apply(this, arguments) } */ } inherits(SaxLtx, EventEmitter) SaxLtx.prototype.end = function (data) { if (data) { this.write(data) } /* Uh, yeah */ this.write = function () {} } ltx-2.6.2/lib/parsers/node-expat.js000066400000000000000000000021021302300141700171410ustar00rootroot00000000000000'use strict' var inherits = require('inherits') var EventEmitter = require('events').EventEmitter var expat = require('node-expat') var SaxExpat = module.exports = function SaxExpat () { EventEmitter.call(this) this.parser = new expat.Parser('UTF-8') var that = this this.parser.on('startElement', function (name, attrs) { that.emit('startElement', name, attrs) }) this.parser.on('endElement', function (name) { that.emit('endElement', name) }) this.parser.on('text', function (str) { that.emit('text', str) }) // TODO: other events, esp. entityDecl (billion laughs!) } inherits(SaxExpat, EventEmitter) SaxExpat.prototype.write = function (data) { if (!this.parser.parse(data, false)) { this.emit('error', new Error(this.parser.getError())) // Premature error thrown, // disable all functionality: this.write = function () {} this.end = function () {} } } SaxExpat.prototype.end = function () { if (!this.parser.parse('', true)) { this.emit('error', new Error(this.parser.getError())) } else { this.emit('end') } } ltx-2.6.2/lib/parsers/node-xml.js000066400000000000000000000031741302300141700166320ustar00rootroot00000000000000'use strict' var inherits = require('inherits') var EventEmitter = require('events').EventEmitter var xml = require('node-xml') var unescapeXML = require('../escape').unescapeXML /** * This cannot be used as long as node-xml starts parsing only after * setTimeout(f, 0) */ var SaxNodeXML = module.exports = function SaxNodeXML () { EventEmitter.call(this) var self = this this.parser = new xml.SaxParser(function (handler) { handler.onStartElementNS(function (elem, attrs, prefix, uri, namespaces) { var i var attrsHash = {} if (prefix) { elem = prefix + ':' + elem } for (i = 0; i < attrs.length; i++) { var attr = attrs[i] attrsHash[attr[0]] = unescapeXML(attr[1]) } for (i = 0; i < namespaces.length; i++) { var namespace = namespaces[i] var k = !namespace[0] ? 'xmlns' : 'xmlns:' + namespace[0] attrsHash[k] = unescapeXML(namespace[1]) } self.emit('startElement', elem, attrsHash) }) handler.onEndElementNS(function (elem, prefix) { if (prefix) { elem = prefix + ':' + elem } self.emit('endElement', elem) }) handler.onCharacters(function (str) { self.emit('text', str) }) handler.onCdata(function (str) { self.emit('text', str) }) handler.onError(function (e) { self.emit('error', e) }) // TODO: other events, esp. entityDecl (billion laughs!) }) } inherits(SaxNodeXML, EventEmitter) SaxNodeXML.prototype.write = function (data) { this.parser.parseString(data) } SaxNodeXML.prototype.end = function (data) { if (data) { this.write(data) } } ltx-2.6.2/lib/parsers/sax-js.js000066400000000000000000000016401302300141700163100ustar00rootroot00000000000000'use strict' var inherits = require('inherits') var EventEmitter = require('events').EventEmitter var sax = require('sax') var SaxSaxjs = module.exports = function SaxSaxjs () { EventEmitter.call(this) this.parser = sax.parser(true) var that = this this.parser.onopentag = function (a) { that.emit('startElement', a.name, a.attributes) } this.parser.onclosetag = function (name) { that.emit('endElement', name) } this.parser.ontext = function (str) { that.emit('text', str) } this.parser.onend = function () { that.emit('end') } this.parser.onerror = function (e) { that.emit('error', e) } } inherits(SaxSaxjs, EventEmitter) SaxSaxjs.prototype.write = function (data) { if (typeof data !== 'string') { data = data.toString() } this.parser.write(data) } SaxSaxjs.prototype.end = function (data) { if (data) { this.parser.write(data) } this.parser.close() } ltx-2.6.2/lib/stringify.js000066400000000000000000000013031302300141700154360ustar00rootroot00000000000000'use strict' function stringify (el, indent, level) { if (typeof indent === 'number') indent = ' '.repeat(indent) if (!level) level = 1 var s = '' s += '<' + el.name Object.keys(el.attrs).forEach(function (k) { s += ' ' + k + '=' + '"' + el.attrs[k] + '"' }) if (el.children.length) { s += '>' el.children.forEach(function (child, i) { if (indent) s += '\n' + indent.repeat(level) if (typeof child === 'string') { s += child } else { s += stringify(child, indent, level + 1) } }) if (indent) s += '\n' + indent.repeat(level - 1) s += '' } else { s += '/>' } return s } module.exports = stringify ltx-2.6.2/lib/tag.js000066400000000000000000000003151302300141700141750ustar00rootroot00000000000000'use strict' var tagString = require('./tagString') var parse = require('./parse') module.exports = function tag (/* [literals], ...substitutions */) { return parse(tagString.apply(null, arguments)) } ltx-2.6.2/lib/tagString.js000066400000000000000000000005311302300141700153640ustar00rootroot00000000000000'use strict' var escape = require('./escape').escapeXML module.exports = function tagString (/* [literals], ...substitutions */) { var literals = arguments[0] var str = '' for (var i = 1; i < arguments.length; i++) { str += literals[i - 1] str += escape(arguments[i]) } str += literals[literals.length - 1] return str } ltx-2.6.2/package.json000066400000000000000000000020211302300141700146000ustar00rootroot00000000000000{ "name": "ltx", "version": "2.6.2", "description": "", "author": "Astro", "repository": "github:node-xmpp/ltx", "homepage": "http://github.com/node-xmpp/ltx", "bugs": "http://github.com/node-xmpp/ltx/issues", "contributors": [ "Stephan Maka", "Will Fife", "Markus Kohlhase", "Julien Genestoux", "▟ ▖▟ ▖", "Sonny Piers" ], "license": "MIT", "engine": "node", "scripts": { "prepublish": "npm run bundle", "preversion": "npm test", "benchmark": "node benchmarks/", "bundle": "browserify -s ltx index.js -o bundle.js", "unit": "vows --spec", "lint": "standard", "test": "npm run unit && npm run lint && npm run bundle" }, "dependencies": { "inherits": "^2.0.1" }, "devDependencies": { "benchmark": "^2.1.0", "browserify": "^13.0.1", "libxmljs": "^0.18.0", "microtime": "^2.1.2", "node-expat": "^2.3.13", "node-xml": "^1.0.2", "sax": "^1.1.5", "standard": "^8.5.0", "vows": "^0.8.1" } } ltx-2.6.2/test/000077500000000000000000000000001302300141700132765ustar00rootroot00000000000000ltx-2.6.2/test/createElement-test.js000066400000000000000000000015621302300141700173720ustar00rootroot00000000000000'use strict' var vows = require('vows') var assert = require('assert') var ltx = require('..') var Element = ltx.Element var createElement = ltx.createElement vows.describe('createElement').addBatch({ 'create a new element and set children': function () { var c = new Element('bar') var e = createElement('foo', {'foo': 'bar'}, 'foo', c) assert(e instanceof Element) assert(e.is('foo')) assert.equal(e.attrs.foo, 'bar') assert.equal(e.children.length, 2) assert.equal(e.children[0], 'foo') assert.equal(e.children[1], c) }, 'null and undefined children are discarded': function () { var e = createElement('foo', null, undefined, 'bar', null, createElement('test'), 'baz') var b = new Element('foo') .t('bar') .c('test').up() .t('baz') assert.equal(e.root().toString(), b.root().toString()) } }).export(module) ltx-2.6.2/test/dom-element-test.js000066400000000000000000000035041302300141700170210ustar00rootroot00000000000000'use strict' var vows = require('vows') var assert = require('assert') var ltx = require('..') var parsers = require('../lib/parsers') var DOMElement = require('../lib/DOMElement') parsers.forEach(function (Parser) { var parse = function (s) { return ltx.parse(s, {Parser: Parser, Element: DOMElement}) } vows.describe("Parsing returns DOMElement's").addBatch({ 'DOMElement': { 'Returns DOMElement on parse': function () { var stanza = '' + '

DOM

' var el = parse(stanza) assert(el.getChild('body') instanceof DOMElement) assert.equal(el.getChild('body').constructor.name, 'DOMElement') var body = el.getChild('body') assert.isDefined(body.localName) assert.equal(body.localName, 'body') assert.isDefined(body.namespaceURI) assert.equal(body.namespaceURI, 'http://www.w3.org/1999/xhtml') assert.isDefined(body.parentNode) assert.equal(body.parentNode.getName(), 'message') assert.isDefined(body.childNodes) assert.isArray(body.childNodes) assert.equal(body.childNodes.length, 1) assert.isDefined(body.textContent) assert.equal(body.textContent, '') assert.equal(body.getChild('p').textContent, 'DOM') } }, 'createElement': { 'create a new element and set children': function () { var c = new DOMElement('bar') var e = DOMElement.createElement('foo', {'foo': 'bar'}, 'foo', c) assert(e instanceof DOMElement) assert.equal(e.localName, 'foo') assert.equal(e.getAttribute('foo'), 'bar') assert.equal(e.childNodes.length, 2) assert.equal(e.childNodes[0], 'foo') assert.equal(e.childNodes[1], c) } } }).export(module) }) ltx-2.6.2/test/element-test.js000066400000000000000000000230021302300141700162370ustar00rootroot00000000000000'use strict' var vows = require('vows') var assert = require('assert') var inherits = require('inherits') var ltx = require('..') var Element = ltx.Element vows.describe('Element').addBatch({ 'new element': { "doesn't reference original attrs object": function () { var o = { foo: 'bar' } var e = new Element('e', o) assert.notEqual(e.attrs, o) e.attrs.bar = 'foo' assert.equal(o.bar, undefined) o.foobar = 'barfoo' assert.equal(e.attrs.foobar, undefined) }, 'set xmlns attribute if a string is passed as second argument': function () { var ns = 'xmlns:test' var e = new Element('e', ns) assert.equal(e.attrs.xmlns, ns) assert.equal(e.getAttr('xmlns'), ns) } }, 'serialization': { 'serialize an element': function () { var e = new Element('e') assert.equal(e.toString(), '') }, 'serialize an element with attributes': function () { var e = new Element('e', { a1: 'foo' }) assert.equal(e.toString(), '') }, 'serialize an element with attributes to entities': function () { var e = new Element('e', { a1: '"well"' }) assert.equal(e.toString(), '') }, 'serialize an element with text': function () { var e = new Element('e').t('bar').root() assert.equal(e.toString(), 'bar') }, 'serialize an element with text to entities': function () { var e = new Element('e').t('1 < 2').root() assert.equal(e.toString(), '1 < 2') }, 'serialize an element with a number attribute': function () { var e = new Element('e', { a: 23 }) assert.equal(e.toString(), '') }, 'serialize an element with number contents': function () { var e = new Element('e') e.c('foo').t(23) e.c('bar').t(0) assert.equal(e.toString(), '230') }, 'serialize with undefined attribute': function () { var e = new Element('e', { foo: undefined }) assert.equal(e.toString(), '') }, 'serialize with null attribute': function () { var e = new Element('e', { foo: null }) assert.equal(e.toString(), '') }, 'serialize with number attribute': function () { var e = new Element('e', { foo: 23, bar: 0 }) var s = e.toString() assert.ok(s.match(/foo="23"/)) assert.ok(s.match(/bar="0"/)) }, 'serialize with undefined child': function () { var e = new Element('e') e.children = [undefined] assert.equal(e.toString(), '') }, 'serialize with null child': function () { var e = new Element('e') e.children = [null] assert.equal(e.toString(), '') }, 'serialize with integer text': function () { var e = new Element('e').t(1000) assert.equal(e.getText(), 1000) }, 'serialize to json': function () { var e = new Element('e', { foo: 23, bar: 0, nil: null }).c('f').t(1000).up() assert.deepEqual(e.toJSON(), { name: 'e', attrs: { foo: 23, bar: 0, nil: null }, children: [ { name: 'f', attrs: {}, children: [1000] } ] }) } }, 'remove': { 'by element': function () { var el = new Element('e').c('c').c('x').up().up().c('c2').up().c('c').up() el.remove(el.getChild('c')) assert.equal(el.getChildren('c').length, 1) assert.equal(el.getChildren('c2').length, 1) }, 'by name': function () { var el = new Element('e').c('c').up().c('c2').up().c('c').up() el.remove('c') assert.equal(el.getChildren('c').length, 0) assert.equal(el.getChildren('c2').length, 1) } }, 'getAttr': { 'without ns': function () { var stanza = '' + '' var doc = ltx.parse(stanza) var el = doc.getChild('person') assert.equal(el.getAttr('name'), 'julien') }, 'with ns': function () { var stanza = '' + '' var doc = ltx.parse(stanza) var el = doc.getChild('person') assert.equal(el.getAttr('title', 'http://site.tld/job'), 'hacker') } }, // extensively tested in equality-test.js 'equality': { 'name': function () { var a = new Element('foo') var b = new Element('foo') assert.equal(a.nameEquals(a), true) assert.equal(a.nameEquals(b), true) assert.equal(b.nameEquals(a), true) b = new Element('b') assert.equal(a.nameEquals(b), false) assert.equal(b.nameEquals(a), false) }, 'attrs': function () { var a = new Element('foo', {foo: 'bar'}) var b = new Element('foo', {foo: 'bar'}) assert.equal(a.attrsEquals(a), true) assert.equal(a.attrsEquals(b), true) assert.equal(b.attrsEquals(a), true) b = new Element('foo', {bar: 'foo'}) assert.equal(a.attrsEquals(b), false) assert.equal(b.attrsEquals(a), false) }, 'children': function () { var a = new Element('foo').c('foo').root() var b = new Element('foo').c('foo').root() assert.equal(a.childrenEquals(a), true) assert.equal(a.childrenEquals(b), true) assert.equal(b.childrenEquals(a), true) b = new Element('foo').c('bar').root() assert.equal(a.childrenEquals(b), false) assert.equal(b.childrenEquals(a), false) } }, 'clone': { 'clones': function () { var orig = new Element('msg', { type: 'get' }).c('content').t('foo').root() var clone = orig.clone() assert.equal(clone.name, orig.name) assert.equal(clone.attrs.type, orig.attrs.type) assert.equal(clone.attrs.to, orig.attrs.to) assert.equal(clone.children.length, orig.children.length) assert.equal(clone.getChildText('content'), orig.getChildText('content')) assert.equal(orig.getChild('content').up(), orig) assert.equal(clone.getChild('content').up(), clone) }, 'mod attr': function () { var orig = new Element('msg', { type: 'get' }) var clone = orig.clone() clone.attrs.type += '-result' assert.equal(orig.attrs.type, 'get') assert.equal(clone.attrs.type, 'get-result') }, 'rm attr': function () { var orig = new Element('msg', { from: 'me' }) var clone = orig.clone() delete clone.attrs.from clone.attrs.to = 'you' assert.equal(orig.attrs.from, 'me') assert.equal(orig.attrs.to, undefined) assert.equal(clone.attrs.from, undefined) assert.equal(clone.attrs.to, 'you') }, 'mod child': function () { var orig = new Element('msg', { type: 'get' }).c('content').t('foo').root() var clone = orig.clone() clone.getChild('content').t('bar').name = 'description' assert.equal(orig.children[0].name, 'content') assert.equal(orig.getChildText('content'), 'foo') assert.equal(clone.children[0].name, 'description') assert.equal(clone.getChildText('description'), 'foobar') }, 'use original constructor for the clone': function () { var Foo = function (name, attrs) { Element.call(this, name, attrs) } inherits(Foo, Element) var foo = new Foo() assert(foo.clone() instanceof Element) assert(foo.clone() instanceof Foo) } }, 'children': { 'getChildren': function () { var el = new Element('a') .c('b') .c('b2').up().up() .t('foo') .c('c').t('cbar').up() .t('bar') .root() var children = el.children assert.equal(children.length, 4) assert.equal(children[0].name, 'b') assert.equal(children[1], 'foo') assert.equal(children[2].name, 'c') assert.equal(children[3], 'bar') }, 'getChildElements': function () { var el = new Element('a') .c('b') .c('b2').up().up() .t('foo') .c('c').t('cbar').up() .t('bar') .root() var children = el.getChildElements() assert.equal(children.length, 2) assert.equal(children[0].name, 'b') assert.equal(children[1].name, 'c') } }, 'recursive': { 'getChildrenByAttr': function () { var el = new Element('a') .c('b') .c('c', {myProperty: 'x'}).t('bar').up().up().up() .c('d', {id: 'x'}) .c('e', {myProperty: 'x'}).root() var results = el.getChildrenByAttr('myProperty', 'x', null, true) assert.equal(results[0].toString(), 'bar') assert.equal(results[1].toString(), '') }, 'getChildByAttr': function () { var el = new Element('a') .c('b') .c('c', {id: 'x'}) .t('bar').root() assert.equal(el.getChildByAttr('id', 'x', null, true).toString(), 'bar') } }, 'issue #15: Inconsistency with prefixed elements': { topic: function () { return ltx.parse('bar') }, 'getChildText prefixed': function (el) { assert.equal(el.getChildText('x:foo'), null) }, 'getChildText unprefixed': function (el) { assert.equal(el.getChildText('foo'), 'bar') }, 'getChild prefixed': function (el) { assert.equal(el.getChild('x:foo'), null) }, 'getChild unprefixed': function (el) { assert.equal(el.getChild('foo').getText(), 'bar') } }, 'issue-37: Element instanceof Fails': { 'instanceof': function () { var el = new Element('root').c('children') assert.ok(el instanceof Element) } } }).export(module) ltx-2.6.2/test/equality-test.js000066400000000000000000000105711302300141700164520ustar00rootroot00000000000000'use strict' var vows = require('vows') var assert = require('assert') var ltx = require('../index') var Element = ltx.Element var nameEqual = ltx.nameEqual var attrsEqual = ltx.attrsEqual var childrenEqual = ltx.childrenEqual var equal = ltx.equal vows.describe('equality').addBatch({ 'nameEqual': { 'it returns true if elements name are equal': function () { var a = new Element('foo') var b = new Element('foo') assert.equal(nameEqual(a, b), true) var c = new Element('foo:bar') var d = new Element('foo:bar') assert.equal(nameEqual(c, d), true) }, 'it returns false if elements name differ': function () { var a = new Element('foo') var b = new Element('bar') assert.equal(nameEqual(a, b), false) var c = new Element('foo:bar') var d = new Element('bar:bar') assert.equal(nameEqual(c, d), false) var e = new Element('foo:bar') var f = new Element('foo:foo') assert.equal(nameEqual(e, f), false) } }, 'attrsEqual': { 'it returns true if elements attributes are equal': function () { var a = new Element('foo', {a: 'b', b: 'c'}) var b = new Element('foo', {a: 'b', b: 'c'}) assert.equal(attrsEqual(a, b), true) var c = new Element('foo', {a: 'b', b: 'c'}) var d = new Element('foo', {b: 'c', a: 'b'}) assert.equal(attrsEqual(c, d), true) }, 'it returns true if elements attributes are serialized equaly': function () { var a = new Element('foo', {foo: 'false'}) var b = new Element('foo', {foo: false}) assert.equal(attrsEqual(a, b), true) var c = new Element('foo', {foo: '0'}) var d = new Element('foo', {foo: 0}) assert.equal(attrsEqual(c, d), true) var foo = {toString: function () { return 'hello' }} var e = new Element('foo', {foo: foo}) var f = new Element('foo', {foo: 'hello'}) assert.equal(attrsEqual(e, f), true) }, 'it returns false if elements attributes differ': function () { var a = new Element('foo', {a: 'b'}) var b = new Element('foo') assert.equal(attrsEqual(a, b), false) var c = new Element('foo') var d = new Element('foo', {a: 'b'}) assert.equal(attrsEqual(c, d), false) var e = new Element('foo', {b: 'a'}) var f = new Element('foo', {a: 'b'}) assert.equal(attrsEqual(e, f), false) var g = new Element('foo', {foo: 'bar'}) var h = new Element('foo', {bar: 'bar'}) assert.equal(attrsEqual(g, h), false) } }, 'childrenEqual': { 'it returns true if elements children are equal': function () { var a = new Element('foo').c('bar').up().c('foo').root() assert.equal(childrenEqual(a, a), true) var b = new Element('foo').c('bar').up().c('foo').root() assert.equal(childrenEqual(a, b), true) }, 'it returns false if elements children name differ': function () { var a = new Element('foo').c('bar').root() var b = new Element('foo').c('foo').root() assert.equal(childrenEqual(a, b), false) }, 'it returns false if elements children attrs differ': function () { var a = new Element('foo').c('foo', {foo: 'bar'}).root() var b = new Element('foo').c('foo', {bar: 'foo'}).root() assert.equal(childrenEqual(a, b), false) }, 'it returns false if elements children order differ': function () { var a = new Element('foo').c('foo').up().c('bar').root() var b = new Element('foo').c('bar').up().c('foo').root() assert.equal(childrenEqual(a, b), false) } }, 'equal': { 'it returns true if elements are equal': function () { var a = new Element('a', {foo: 'bar'}).c('hello').root() assert.equal(equal(a, a), true) var b = new Element('a', {foo: 'bar'}).c('hello').root() assert.equal(equal(a, b), true) }, 'it returns false if elements name differ': function () { var a = new Element('foo') var b = new Element('bar') assert.equal(equal(a, b), false) }, 'it returns false if elements attrs differ': function () { var a = new Element('foo', {foo: 'bar'}) var b = new Element('foo') assert.equal(equal(a, b), false) }, 'it returns false if elements children differ': function () { var a = new Element('foo').c('foo').root() var b = new Element('foo').c('bar').root() assert.equal(equal(a, b), false) } } }).export(module) ltx-2.6.2/test/escape-test.js000066400000000000000000000042271302300141700160560ustar00rootroot00000000000000'use strict' var vows = require('vows') var assert = require('assert') var ltx = require('..') var escape = require('../lib/escape') var escapeXML = escape.escapeXML var unescapeXML = escape.unescapeXML var escapeXMLText = escape.escapeXMLText var unescapeXMLText = escape.unescapeXMLText vows.describe('escape').addBatch({ 'escapeXML': { 'exported correctly': function () { assert.equal(ltx.escapeXML, escapeXML) }, 'escapes &': function () { assert.equal(escapeXML('&'), '&') }, 'escapes <': function () { assert.equal(escapeXML('<'), '<') }, 'escapes >': function () { assert.equal(escapeXML('>'), '>') }, 'escapes "': function () { assert.equal(escapeXML('"'), '"') }, 'escapes \'': function () { assert.equal(escapeXML('\''), ''') } }, 'unescapeXML': { 'exported correctly': function () { assert.equal(ltx.unescapeXML, unescapeXML) }, 'unescapes &': function () { assert.equal(unescapeXML('&'), '&') }, 'unescapes <': function () { assert.equal(unescapeXML('<'), '<') }, 'unescapes >': function () { assert.equal(unescapeXML('>'), '>') }, 'unescapes "': function () { assert.equal(unescapeXML('"'), '"') }, 'unescapes \'': function () { assert.equal(unescapeXML('''), '\'') } }, 'escapeXMLText': { 'exported correctly': function () { assert.equal(ltx.escapeXMLText, escapeXMLText) }, 'escapes &': function () { assert.equal(escapeXMLText('&'), '&') }, 'escapes <': function () { assert.equal(escapeXMLText('<'), '<') }, 'escapes >': function () { assert.equal(escapeXMLText('>'), '>') } }, 'unescapeXMLText': { 'exported correctly': function () { assert.equal(ltx.unescapeXMLText, unescapeXMLText) }, 'unescapes &': function () { assert.equal(unescapeXMLText('&'), '&') }, 'unescapes <': function () { assert.equal(unescapeXMLText('<'), '<') }, 'unescapes >': function () { assert.equal(unescapeXMLText('>'), '>') } } }).export(module) ltx-2.6.2/test/is-test.js000066400000000000000000000030301302300141700152200ustar00rootroot00000000000000'use strict' var vows = require('vows') var assert = require('assert') var ltx = require('..') var is = require('../lib/is') var Element = ltx.Element vows.describe('isNode').addBatch({ 'isNode': { 'exported correctly': function () { assert.equal(ltx.isNode, is.isNode) }, 'returns true for Element': function () { assert.strictEqual(is.isNode(new Element()), true) }, 'returns true for strings': function () { assert.strictEqual(is.isNode('string'), true) }, 'returns false for anything else': function () { [123, null, undefined, {}, [], true].forEach(function (value) { assert.strictEqual(is.isNode(value), false) }) } }, 'isElement': { 'exported correctly': function () { assert.equal(ltx.isElement, is.isElement) }, 'returns true for Element': function () { assert.strictEqual(is.isElement(new Element()), true) }, 'returns false for anything else': function () { [123, null, undefined, {}, 'string', [], true].forEach(function (value) { assert.strictEqual(is.isElement(value), false) }) } }, 'isText': { 'exported correctly': function () { assert.equal(ltx.isText, is.isText) }, 'returns true for strings': function () { assert.strictEqual(is.isText('foo'), true) }, 'returns false for anything else': function () { [123, null, undefined, {}, Element, [], true].forEach(function (value) { assert.strictEqual(is.isText(value), false) }) } } }).export(module) ltx-2.6.2/test/ltx-test.js000066400000000000000000000005601302300141700154210ustar00rootroot00000000000000'use strict' var vows = require('vows') var assert = require('assert') var ltx = require('..') var tag = require('../lib/tag') vows.describe('ltx').addBatch({ 'returns same result as tag': function () { var a = tag(['', ''], 'bar') var b = ltx(['', ''], 'bar') assert.strictEqual(a.toString(), b.toString()) } }).export(module) ltx-2.6.2/test/parse-test.js000066400000000000000000000151141302300141700157250ustar00rootroot00000000000000'use strict' var vows = require('vows') var assert = require('assert') var ltx = require('..') var parsers = require('../lib/parsers') parsers.forEach(function (Parser) { var parse = function (s) { return ltx.parse(s, {Parser: Parser}) } vows.describe('ltx with ' + Parser.name).addBatch({ 'DOM parsing': { 'simple document': function () { var el = parse('') assert.equal(el.name, 'root') assert.equal(0, el.children.length) }, 'text with commas': function () { var el = parse("sa'sa'1'sasa") assert.equal("sa'sa'1'sasa", el.getText()) }, 'text with entities': function () { var el = parse('<>&"'') assert.equal('<>&"\'', el.getText()) }, 'attribute with entities': function () { var el = parse("") assert.equal('<>&"\'', el.attrs.title) }, 'erroneous document raises error': function () { assert.throws(function () { parse('') }) }, 'incomplete document raises error': function () { assert.throws(function () { parse('') }) }, 'namespace declaration': function () { var el = parse("") assert.equal(el.name, 'root') assert.equal(el.attrs.xmlns, 'https://github.com/astro/ltx') assert.ok(el.is('root', 'https://github.com/astro/ltx')) }, 'namespace declaration with prefix': function () { var el = parse("") assert.equal(el.name, 'x:root') assert.equal(el.getName(), 'root') assert.ok(el.is('root', 'https://github.com/astro/ltx')) }, 'buffer': function () { var buf = new Buffer('') var el = parse(buf) assert.equal(el.name, 'root') assert.equal(0, el.children.length) }, 'utf-8 text': function () { var el = parse('Möwe') assert.equal(el.name, 'text') assert.equal(el.getText(), 'Möwe') }, 'iso8859-1 text': function () { if (Parser.name === 'SaxLibxmljs') return var el = parse('M\xF6we') assert.equal(el.name, 'text') assert.equal(el.getText(), 'Möwe') } }, 'SAX parsing': { 'XMPP stream': function () { var parser = new Parser() var events = [] parser.on('startElement', function (name, attrs) { events.push({ start: name, attrs: attrs }) }) parser.on('endElement', function (name) { events.push({ end: name }) }) parser.on('text', function (s) { events.push({ text: s }) }) parser.write("<") assert.equal(events.length, 1) testStanza(events[0], { name: 'stream:stream', attrs: { xmlns: 'jabber:client', 'xmlns:stream': 'http://etherx.jabber.org/streams', id: '556890365', from: 'jabber.ccc.de', version: '1.0', 'xml:lang': 'en' } }) parser.write("stream:features>PLAINDIGEST-MD5= 9) parser.write('mechanism>SCRAM-SHA-1') assert.equal(events.length, 15) parser.write("') assert.equal(events.length, 18) }, 'bug: partial attrs': function () { var parser = new Parser() var events = [] parser.on('startElement', function (name, attrs) { events.push({ start: name, attrs: attrs }) }) parser.on('endElement', function (name) { events.push({ end: name }) }) parser.on('text', function (s) { events.push({ text: s }) }) parser.write('<') parser.write('stream:features') // otherwise libxmljs complains stream is not a defined NS parser.write(' xmlns:stream="http://etherx.jabber.org/streams"') parser.write('>') parser.write('<') parser.write('mechanisms') parser.write(' ') parser.write('xmlns') parser.write('="') parser.write('urn:ietf:params:xml:ns:xmpp-sasl') parser.write('"') parser.write('>') assert.equal(events.length, 2) testStanza(events[0], { name: 'stream:features', attrs: { 'xmlns:stream': 'http://etherx.jabber.org/streams' } }) testStanza(events[1], { name: 'mechanisms', attrs: { xmlns: 'urn:ietf:params:xml:ns:xmpp-sasl' } }) }, 'bug: elements in comments': function () { var parser = new Parser() var events = [] parser.on('startElement', function (name, attrs) { events.push({ start: name, attrs: attrs }) }) parser.on('endElement', function (name) { events.push({ end: name }) }) parser.on('comment', function (s) { events.push({ comment: s }) }) parser.write("") assert.deepEqual(events, [ { start: 'root', attrs: {} }, { end: 'root' } ]) } } }).export(module) }) function testStanza (data, stanza) { assert.equal(data.start, stanza.name) assert.equal(Object.keys(data.attrs).length, Object.keys(stanza.attrs).length) for (var k in stanza.attrs) { assert.equal(data.attrs[k], stanza.attrs[k]) } } ltx-2.6.2/test/stringify-test.js000066400000000000000000000016261302300141700166340ustar00rootroot00000000000000'use strict' var vows = require('vows') var assert = require('assert') var ltx = require('..') var stringify = require('../lib/stringify') vows.describe('stringify').addBatch({ 'is exported correctly': function () { assert.equal(ltx.stringify, stringify) }, 'returns the same result than .toString()': function () { const el = ltx` text text ` assert.equal(el.toString(), stringify(el)) }, 'indents correctly': function () { const el = ltx`text` const expected = [ '', ' ', ' text', ' ', ' ', '' ].join('\n') assert.equal(stringify(el, 2), expected) assert.equal(stringify(el, ' '), expected) } }).export(module) ltx-2.6.2/test/tag-test.js000066400000000000000000000016571302300141700153750ustar00rootroot00000000000000'use strict' var vows = require('vows') var assert = require('assert') var ltx = require('..') var tag = require('../lib/tag') var Element = ltx.Element vows.describe('tag').addBatch({ 'exported correctly': function () { assert.equal(ltx.tag, tag) }, 'parses the string and return an Element object': function () { // var r = tag`${'bar'}` var r = tag(['', ''], 'bar') assert(r instanceof Element) var c = new Element('foo').t('bar') assert(c.equals(r)) assert(r.equals(c)) assert.strictEqual(r.toString(), c.toString()) }, 'multiple substitutions': function () { // var r = tag`${'bar'}` var r = tag(['', ''], 'b', 'bar') assert(r instanceof Element) var c = new Element('foo', {a: 'b'}).t('bar') assert(c.equals(r)) assert(r.equals(c)) assert.strictEqual(r.toString(), c.toString()) } }).export(module) ltx-2.6.2/test/unicode-test.js000066400000000000000000000026631302300141700162460ustar00rootroot00000000000000'use strict' var vows = require('vows') var assert = require('assert') var Element = require('../lib/Element') vows.describe('unicode').addBatch({ 'unicode forming': { 'issue-29': function () { var text = 'Hello ɝ' var element = new Element('iq') element.t(text) assert.equal(element.toString(), '' + text + '') }, /* 'issue-29 test #2': function() { var text = '니코드<' var element = new Element( 'message', { to: 'you@server.com', type: 'chat' } ) .c('body').t('니코드<'.toString('utf8')) assert.equal(element.getChildText('body'), text) }, */ 'issue-29 test #3': function () { var text = '니코드<' var element = new Element( 'message', { to: 'you@server.com', type: 'chat' } ).c('body').t('니코드<'.toString('utf8')) assert.equal(element.getText(), text) }, 'issue-29 test write': function () { var text = '유니코드' var result = '<0message0 0to0="0-1@chat.fb.com0"0 0type0="0chat0"0>0<0body0>'.split(0) result.push(text) result = result.concat('0'.split(0)) var element = new Element('message', {to: '-1@chat.fb.com', type: 'chat'}) element.c('body').t(text.toString('utf8')) element.write(function (c) { assert.equal(result.shift(), c) }) assert.equal(result.length, 0) } } }).export(module)