152 lines
3.4 KiB
JavaScript
152 lines
3.4 KiB
JavaScript
/**
|
|
* @param {string} type
|
|
* @param {array|string} content
|
|
* @param {number} line
|
|
* @param {number} column
|
|
* @constructor
|
|
*/
|
|
function Node(type, content, line, column) {
|
|
this.type = type;
|
|
this.content = content;
|
|
this.start = {
|
|
line: line,
|
|
column: column
|
|
};
|
|
}
|
|
|
|
Node.prototype = {
|
|
type: null,
|
|
|
|
content: null,
|
|
|
|
start: null,
|
|
|
|
/**
|
|
* @param {String} type Node type
|
|
* @return {Boolean} Whether there is a child node of given type
|
|
*/
|
|
contains: function(type) {
|
|
return this.content.some(function(node) {
|
|
return node.type === type;
|
|
});
|
|
},
|
|
|
|
/**
|
|
* @param {String} type
|
|
* @return {Node} First child node
|
|
*/
|
|
first: function(type) {
|
|
if (!type || !Array.isArray(this.content)) return this.content[0];
|
|
|
|
var i = 0;
|
|
var l = this.content.length;
|
|
|
|
for (; i < l; i++) {
|
|
if (this.content[i].type === type) return this.content[i];
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @param {String} type Node type
|
|
* @param {Function} callback Function to call for every found node
|
|
*/
|
|
forEach: function(type, callback) {
|
|
if (!Array.isArray(this.content)) return;
|
|
|
|
if (typeof type !== 'string') callback = type, type = null;
|
|
|
|
var i = 0;
|
|
var l = this.content.length;
|
|
|
|
for (; i < l; i++) {
|
|
if (!type || this.content[i] && this.content[i].type === type)
|
|
callback(this.content[i], i);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @param {Number} index
|
|
* @return {Node}
|
|
*/
|
|
get: function(index) {
|
|
return Array.isArray(this.content) && this.content[index];
|
|
},
|
|
|
|
/**
|
|
* @param {Number} index
|
|
* @param {Node} node
|
|
*/
|
|
insert: function(index, node) {
|
|
Array.isArray(this.content) && this.content.splice(index, 0, node);
|
|
},
|
|
|
|
/**
|
|
* @param {String} type
|
|
* @return {Boolean} Whether the node is of given type
|
|
*/
|
|
is: function(type) {
|
|
return this.type === type;
|
|
},
|
|
|
|
/**
|
|
* @param {String} type
|
|
* @return {Node} Last child node
|
|
*/
|
|
last: function(type) {
|
|
var i = this.content.length - 1;
|
|
|
|
if (!type || !Array.isArray(this.content))
|
|
return this.content[i];
|
|
|
|
|
|
for (;;i--) {
|
|
if (this.content[i].type === type) return this.content[i];
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @param {Function} callback
|
|
*/
|
|
map: function(callback) {
|
|
callback(this);
|
|
|
|
if (!Array.isArray(this.content)) return;
|
|
|
|
this.content.forEach(function(node) {
|
|
if (node instanceof Node)
|
|
node.map(callback);
|
|
});
|
|
},
|
|
|
|
/**
|
|
* @param {Number} index
|
|
*/
|
|
remove: function(index) {
|
|
Array.isArray(this.content) && this.content.splice(index, 1);
|
|
},
|
|
|
|
get length() {
|
|
return this.content.length;
|
|
},
|
|
|
|
toString: function() {
|
|
return JSON.stringify(this, false, 2);
|
|
},
|
|
|
|
//TODO(tonyganch): Save syntax name while creating a node.
|
|
toCSS: function(syntax) {
|
|
if (!syntax) return console.error('Empty syntax name.');
|
|
|
|
try {
|
|
stringify = require('./' + syntax + '/stringify');
|
|
} catch (e) {
|
|
var message = 'Syntax "' + syntax + '" is not supported yet, sorry';
|
|
return console.error(message);
|
|
}
|
|
|
|
return stringify(this);
|
|
}
|
|
};
|
|
|
|
module.exports = Node;
|