node.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. 'use strict';
  2. let cloneNode = function (obj, parent) {
  3. let cloned = new obj.constructor();
  4. for (let i in obj) {
  5. if (!obj.hasOwnProperty(i)) continue;
  6. let value = obj[i],
  7. type = typeof value;
  8. if (i === 'parent' && type === 'object') {
  9. if (parent) cloned[i] = parent;
  10. }
  11. else if (i === 'source') {
  12. cloned[i] = value;
  13. }
  14. else if (value instanceof Array) {
  15. cloned[i] = value.map(j => cloneNode(j, cloned));
  16. }
  17. else if (i !== 'before' && i !== 'after' && i !== 'between' && i !== 'semicolon') {
  18. if (type === 'object' && value !== null) value = cloneNode(value);
  19. cloned[i] = value;
  20. }
  21. }
  22. return cloned;
  23. };
  24. module.exports = class Node {
  25. constructor (defaults) {
  26. defaults = defaults || {};
  27. this.raws = { before: '', after: '' };
  28. for (let name in defaults) {
  29. this[name] = defaults[name];
  30. }
  31. }
  32. remove () {
  33. if (this.parent) {
  34. this.parent.removeChild(this);
  35. }
  36. this.parent = undefined;
  37. return this;
  38. }
  39. toString () {
  40. return [
  41. this.raws.before,
  42. String(this.value),
  43. this.raws.after
  44. ].join('');
  45. }
  46. clone (overrides) {
  47. overrides = overrides || {};
  48. let cloned = cloneNode(this);
  49. for (let name in overrides) {
  50. cloned[name] = overrides[name];
  51. }
  52. return cloned;
  53. }
  54. cloneBefore (overrides) {
  55. overrides = overrides || {};
  56. let cloned = this.clone(overrides);
  57. this.parent.insertBefore(this, cloned);
  58. return cloned;
  59. }
  60. cloneAfter (overrides) {
  61. overrides = overrides || {};
  62. let cloned = this.clone(overrides);
  63. this.parent.insertAfter(this, cloned);
  64. return cloned;
  65. }
  66. replaceWith () {
  67. let nodes = Array.prototype.slice.call(arguments);
  68. if (this.parent) {
  69. for (let node of nodes) {
  70. this.parent.insertBefore(this, node);
  71. }
  72. this.remove();
  73. }
  74. return this;
  75. }
  76. moveTo (container) {
  77. this.cleanRaws(this.root() === container.root());
  78. this.remove();
  79. container.append(this);
  80. return this;
  81. }
  82. moveBefore (node) {
  83. this.cleanRaws(this.root() === node.root());
  84. this.remove();
  85. node.parent.insertBefore(node, this);
  86. return this;
  87. }
  88. moveAfter (node) {
  89. this.cleanRaws(this.root() === node.root());
  90. this.remove();
  91. node.parent.insertAfter(node, this);
  92. return this;
  93. }
  94. next () {
  95. let index = this.parent.index(this);
  96. return this.parent.nodes[index + 1];
  97. }
  98. prev () {
  99. let index = this.parent.index(this);
  100. return this.parent.nodes[index - 1];
  101. }
  102. toJSON () {
  103. let fixed = { };
  104. for (let name in this) {
  105. if (!this.hasOwnProperty(name)) continue;
  106. if (name === 'parent') continue;
  107. let value = this[name];
  108. if (value instanceof Array) {
  109. fixed[name] = value.map(i => {
  110. if (typeof i === 'object' && i.toJSON) {
  111. return i.toJSON();
  112. }
  113. else {
  114. return i;
  115. }
  116. });
  117. }
  118. else if (typeof value === 'object' && value.toJSON) {
  119. fixed[name] = value.toJSON();
  120. }
  121. else {
  122. fixed[name] = value;
  123. }
  124. }
  125. return fixed;
  126. }
  127. root () {
  128. let result = this;
  129. while (result.parent) result = result.parent;
  130. return result;
  131. }
  132. cleanRaws (keepBetween) {
  133. delete this.raws.before;
  134. delete this.raws.after;
  135. if (!keepBetween) delete this.raws.between;
  136. }
  137. positionInside (index) {
  138. let string = this.toString(),
  139. column = this.source.start.column,
  140. line = this.source.start.line;
  141. for (let i = 0; i < index; i++) {
  142. if (string[i] === '\n') {
  143. column = 1;
  144. line += 1;
  145. }
  146. else {
  147. column += 1;
  148. }
  149. }
  150. return { line, column };
  151. }
  152. positionBy (opts) {
  153. let pos = this.source.start;
  154. if (Object(opts).index) {
  155. pos = this.positionInside(opts.index);
  156. }
  157. else if (Object(opts).word) {
  158. let index = this.toString().indexOf(opts.word);
  159. if (index !== -1) pos = this.positionInside(index);
  160. }
  161. return pos;
  162. }
  163. };