@stringsync/vexml
Version:
MusicXML to Vexflow
99 lines (98 loc) • 3.45 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.NamedElement = void 0;
const value_1 = require("./value");
/**
* A readonly wrapper that enforces compile-time checking on an element's name.
*
* For example, requiring a signature to use NamedElement<'foo'> will force the caller to assert that an element's name
* is foo. As long as types aren't being dynamically casted, this is also backed by the compiler.
*
* It also provides convenience methods on top of the Element API.
*/
class NamedElement {
element;
name;
constructor(element, name) {
this.element = element;
this.name = name;
}
/** Creates a NamedNode from a document node. */
static of(element) {
return new NamedElement(element, element.nodeName);
}
/** Determines if the node has the given name. */
isNamed(name) {
return this.name === name;
}
/** Casts the underlying node to an Element. */
native() {
return this.element;
}
children(...tagNames) {
let nodes;
if (tagNames.length === 0) {
nodes = Array.from(this.element.children);
}
else {
const selector = tagNames.map((tagName) => `:scope > ${tagName}`).join(', ');
nodes = Array.from(this.element.querySelectorAll(selector));
}
return nodes.map((node) => NamedElement.of(node));
}
/** Returns the first _descendant_ node matching the tag name. Defaults to null. */
first(tagName) {
const element = this.element.getElementsByTagName(tagName).item(0);
return element ? NamedElement.of(element) : null;
}
/** Returns all _descendant_ node matching the tag name. */
all(tagName) {
return Array.from(this.element.getElementsByTagName(tagName)).map((node) => NamedElement.of(node));
}
/** Returns the next _sibling_ node matching the tag name. */
next(tagName) {
let sibling = this.element.nextElementSibling;
while (sibling) {
const element = NamedElement.of(sibling);
if (element.isNamed(tagName)) {
return element;
}
sibling = sibling.nextElementSibling;
}
return null;
}
/** Returns the previous _sibling_ node matching the tag name. */
previous(tagName) {
let sibling = this.element.previousElementSibling;
while (sibling) {
const element = NamedElement.of(sibling);
if (element.isNamed(tagName)) {
return element;
}
sibling = sibling.previousElementSibling;
}
return null;
}
/** Returns the _ancestor_ matching the tag name. Defaults to null. */
ancestor(tagName) {
let parent = this.element.parentElement;
while (parent) {
const element = NamedElement.of(parent);
if (element.isNamed(tagName)) {
return element;
}
parent = parent.parentElement;
}
return null;
}
/** Returns an attr wrapper for the attribute of the given name. */
attr(name) {
const value = this.element.getAttribute(name);
return value_1.Value.of(value);
}
/** Returns the text content of the node. */
content() {
return value_1.Value.of(this.element.textContent || null);
}
}
exports.NamedElement = NamedElement;