/* eslint-disable no-dupe-class-members */ const libxmljs = require('libxmljs'); const utils = require('./utils'); class Document { static TYPE_XML = 0; static TYPE_HTML = 1; static TYPE_HTML_FRAGMENT = 2; _original = null; _hasContent = false; namespace = null; constructor(source = null, type = Document.TYPE_XML, options = null) { if (source !== null) { switch (type) { case Document.TYPE_XML: this._original = libxmljs.parseXml(source, options); break; case Document.TYPE_HTML: this._original = libxmljs.parseHtml(source, options); break; case Document.TYPE_HTML_FRAGMENT: this._original = libxmljs.parseHtmlFragment(source, options); break; default: break; } this._hasContent = true; } else { this._original = new libxmljs.Document(); } } get errors() { if (!this._original) return []; return this._original.errors; } get validationErrors() { if (!this._original) return undefined; return this._original.validationErrors; } child(idx) { this.assertNoContentError(); if (!idx) idx = 0; return this._original.child(idx); } childNodes() { this.assertNoContentError(); return this._original.childNodes(); } count(xpath) { return this.get(`count(${xpath})`); } encoding() { return this._original.encoding(); } encoding(enc) { return this._original.encoding(enc); } find(xpath) { this.assertNoContentError(); if (typeof xpath !== 'string') throw new Error('xpath must be a string.'); if (!this.namespace) return this._original.find(xpath); const fullXPath = utils.addNamespacePrefixInPath(this.namespace.alias, xpath); return this._original.find(fullXPath, { [this.namespace.alias]: this.namespace.url }); } fromHtml(html, options = {}) { if (typeof html !== 'string') throw new Error('html must be a string.'); if (typeof options !== 'object') throw new Error('options must be an object.'); this._original = libxmljs.Document.fromHtml(html, options); this._hasContent = true; return this; } fromHtmlFragment(htmlFragment, options = {}) { if (typeof htmlFragment !== 'string') throw new Error('htmlFragment must be a string.'); if (typeof options !== 'object') throw new Error('options must be an object.'); this._original = libxmljs.Document.fromHtmlFragment(htmlFragment, options); this._hasContent = true; return this; } fromXml(xml, options = {}) { if (typeof xml !== 'string') throw new Error('htmlFragment must be a string.'); if (typeof options !== 'object') throw new Error('options must be an object.'); this._original = libxmljs.Document.fromXml(xml, options); this._hasContent = true; return this; } get(xpath) { const found = this.find(xpath); if (found.length === undefined) return found; // found is not an array so we just return it. if (found.length === 0) return null; // found is an empty array so we return null. return found[0]; // found is a non-empty array so we return the first element. } getDtd() { return this._original.getDtd(); } namespaces() { this.assertNoContentError(); return this._original.namespaces(); } node(name, content) { if (!this._hasContent) this._hasContent = true; return this._original.node(name, content); } rngValidate(rng) { return this._original.rngValidate(rng); } root() { this.assertNoContentError(); return this._original.root(); } root(node) { this.assertNoContentError(); return this._original.root(node); } setDtd(name, ext, sys) { return this._original.setDtd(name, ext, sys); } setNamespace(alias, url) { if (typeof alias !== 'string') throw new Error('alias must be a string.'); if (typeof url !== 'string') throw new Error('url must be a string.'); if (!utils.isValidURL(url)) throw new Error('url is not a valid URL.'); this.namespace = { alias, url, }; } toString(formatting = true) { return this._original.toString(formatting); } type() { return this._original.type(); } validate(xsdDoc) { this.assertNoContentError(); if (!xsdDoc) throw new Error('No XSD document to validate against.'); return this._original.validate(xsdDoc); } version() { return this._original.version(); } assertNoContentError() { if (!this._hasContent) { const err = new Error('No parsed content found.'); err.name = 'NoContentError'; throw err; } } } module.exports = Document;