commonmark
Version:
a strongly specified, highly compatible variant of Markdown
255 lines (213 loc) • 5.97 kB
JavaScript
"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._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;
Object.defineProperty(proto, 'isContainer', {
get: 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);
}
*/