"use strict"; function isContainer(node) { switch (node._type) { case 'Document': case 'BlockQuote': case 'List': case 'Item': case 'Paragraph': case 'Header': case 'Emph': case 'Strong': case 'Link': case 'Image': return true; default: return false; } } var resumeAt = function(node, entering) { this.current = node; this.entering = (entering === true); }; var next = function(){ var cur = this.current; var entering = this.entering; if (cur === null) { return null; } var container = isContainer(cur); if (entering && container) { if (cur._firstChild) { this.current = cur._firstChild; this.entering = true; } else { // stay on node but exit this.entering = false; } } else if (cur._next === null) { this.current = cur._parent; this.entering = false; } else { this.current = cur._next; this.entering = true; } return {entering: entering, node: cur}; }; var NodeWalker = function(root) { return { current: root, root: root, entering: true, next: next, resumeAt: resumeAt }; }; var Node = function(nodeType, sourcepos) { this._type = nodeType; this._parent = null; this._firstChild = null; this._lastChild = null; this._prev = null; this._next = null; this._sourcepos = sourcepos; this._lastLineBlank = false; this._open = true; this._strings = null; this._string_content = null; this._literal = null; this._listData = null; this._info = null; this._destination = null; this._title = null; this._isFenced = false; this._fenceChar = null; this._fenceLength = 0; this._fenceOffset = null; this._level = null; }; var proto = Node.prototype; Node.prototype.isContainer = function() { return isContainer(this); }; Object.defineProperty(proto, 'type', { get: function() { return this._type; } }); Object.defineProperty(proto, 'firstChild', { get: function() { return this._firstChild; } }); Object.defineProperty(proto, 'lastChild', { get: function() { return this._lastChild; } }); Object.defineProperty(proto, 'next', { get: function() { return this._next; } }); Object.defineProperty(proto, 'prev', { get: function() { return this._prev; } }); Object.defineProperty(proto, 'parent', { get: function() { return this._parent; } }); Object.defineProperty(proto, 'sourcepos', { get: function() { return this._sourcepos; } }); Object.defineProperty(proto, 'literal', { get: function() { return this._literal; }, set: function(s) { this._literal = s; } }); Object.defineProperty(proto, 'destination', { get: function() { return this._destination; }, set: function(s) { this._destination = s; } }); Object.defineProperty(proto, 'title', { get: function() { return this._title; }, set: function(s) { this._title = s; } }); Object.defineProperty(proto, 'info', { get: function() { return this._info; }, set: function(s) { this._info = s; } }); Object.defineProperty(proto, 'level', { get: function() { return this._level; }, set: function(s) { this._level = s; } }); Object.defineProperty(proto, 'listType', { get: function() { return this._listData.type; }, set: function(t) { this._listData.type = t; } }); Object.defineProperty(proto, 'listTight', { get: function() { return this._listData.tight; }, set: function(t) { this._listData.tight = t; } }); Object.defineProperty(proto, 'listStart', { get: function() { return this._listData.start; }, set: function(n) { this._listData.start = n; } }); Object.defineProperty(proto, 'listDelimiter', { get: function() { return this._listData.delimiter; }, set: function(delim) { this._listData.delimiter = delim; } }); Node.prototype.appendChild = function(child) { child.unlink(); child._parent = this; if (this._lastChild) { this._lastChild._next = child; child._prev = this._lastChild; this._lastChild = child; } else { this._firstChild = child; this._lastChild = child; } }; Node.prototype.prependChild = function(child) { child.unlink(); child._parent = this; if (this._firstChild) { this._firstChild._prev = child; child._next = this._firstChild; this._firstChild = child; } else { this._firstChild = child; this._lastChild = child; } }; Node.prototype.unlink = function() { if (this._prev) { this._prev._next = this._next; } else if (this._parent) { this._parent._firstChild = this._next; } if (this._next) { this._next._prev = this._prev; } else if (this._parent) { this._parent._lastChild = this._prev; } this._parent = null; this._next = null; this._prev = null; }; Node.prototype.insertAfter = function(sibling) { sibling.unlink(); sibling._next = this._next; if (sibling._next) { sibling._next._prev = sibling; } sibling._prev = this; this._next = sibling; sibling._parent = this._parent; if (!sibling._next) { sibling._parent._lastChild = sibling; } }; Node.prototype.insertBefore = function(sibling) { sibling.unlink(); sibling._prev = this._prev; if (sibling._prev) { sibling._prev._next = sibling; } sibling._next = this; this._prev = sibling; sibling._parent = this._parent; if (!sibling._prev) { sibling._parent._firstChild = sibling; } }; Node.prototype.walker = function() { var walker = new NodeWalker(this); return walker; }; module.exports = Node; /* Example of use of walker: var walker = w.walker(); var event; while (event = walker.next()) { console.log(event.entering, event.node.type()); } */