node.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /**
  2. * @param {string} type
  3. * @param {array|string} content
  4. * @param {number} line
  5. * @param {number} column
  6. * @constructor
  7. */
  8. function Node(type, content, line, column) {
  9. this.type = type;
  10. this.content = content;
  11. this.start = {
  12. line: line,
  13. column: column
  14. };
  15. }
  16. Node.prototype = {
  17. type: null,
  18. content: null,
  19. start: null,
  20. /**
  21. * @param {String} type Node type
  22. * @return {Boolean} Whether there is a child node of given type
  23. */
  24. contains: function(type) {
  25. return this.content.some(function(node) {
  26. return node.type === type;
  27. });
  28. },
  29. /**
  30. * @param {String} type
  31. * @return {Node} First child node
  32. */
  33. first: function(type) {
  34. if (!type || !Array.isArray(this.content)) return this.content[0];
  35. var i = 0;
  36. var l = this.content.length;
  37. for (; i < l; i++) {
  38. if (this.content[i].type === type) return this.content[i];
  39. }
  40. },
  41. /**
  42. * @param {String} type Node type
  43. * @param {Function} callback Function to call for every found node
  44. */
  45. forEach: function(type, callback) {
  46. if (!Array.isArray(this.content)) return;
  47. if (typeof type !== 'string') callback = type, type = null;
  48. var i = 0;
  49. var l = this.content.length;
  50. for (; i < l; i++) {
  51. if (!type || this.content[i] && this.content[i].type === type)
  52. callback(this.content[i], i);
  53. }
  54. },
  55. /**
  56. * @param {Number} index
  57. * @return {Node}
  58. */
  59. get: function(index) {
  60. return Array.isArray(this.content) && this.content[index];
  61. },
  62. /**
  63. * @param {Number} index
  64. * @param {Node} node
  65. */
  66. insert: function(index, node) {
  67. Array.isArray(this.content) && this.content.splice(index, 0, node);
  68. },
  69. /**
  70. * @param {String} type
  71. * @return {Boolean} Whether the node is of given type
  72. */
  73. is: function(type) {
  74. return this.type === type;
  75. },
  76. /**
  77. * @param {String} type
  78. * @return {Node} Last child node
  79. */
  80. last: function(type) {
  81. var i = this.content.length - 1;
  82. if (!type || !Array.isArray(this.content))
  83. return this.content[i];
  84. for (;;i--) {
  85. if (this.content[i].type === type) return this.content[i];
  86. }
  87. },
  88. /**
  89. * @param {Function} callback
  90. */
  91. map: function(callback) {
  92. callback(this);
  93. if (!Array.isArray(this.content)) return;
  94. this.content.forEach(function(node) {
  95. if (node instanceof Node)
  96. node.map(callback);
  97. });
  98. },
  99. /**
  100. * @param {Number} index
  101. */
  102. remove: function(index) {
  103. Array.isArray(this.content) && this.content.splice(index, 1);
  104. },
  105. get length() {
  106. return this.content.length;
  107. },
  108. toString: function() {
  109. return JSON.stringify(this, false, 2);
  110. },
  111. //TODO(tonyganch): Save syntax name while creating a node.
  112. toCSS: function(syntax) {
  113. if (!syntax) return console.error('Empty syntax name.');
  114. try {
  115. stringify = require('./' + syntax + '/stringify');
  116. } catch (e) {
  117. var message = 'Syntax "' + syntax + '" is not supported yet, sorry';
  118. return console.error(message);
  119. }
  120. return stringify(this);
  121. }
  122. };
  123. module.exports = Node;