node.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. var util_1 = require("../util");
  4. var cloneNode = function (obj, parent, depth) {
  5. if (depth === void 0) { depth = 0; }
  6. // Bound recursion so a pathologically deep node tree raises a catchable
  7. // error instead of overflowing the call stack (CVE-2026-9358 / CWE-674).
  8. if (depth > util_1.MAX_NESTING_DEPTH) {
  9. throw new Error("Cannot clone selector: nesting depth exceeds the maximum of ".concat(util_1.MAX_NESTING_DEPTH, "."));
  10. }
  11. if (typeof obj !== "object" || obj === null) {
  12. return obj;
  13. }
  14. var cloned = new obj.constructor();
  15. for (var i in obj) {
  16. if (!obj.hasOwnProperty(i)) {
  17. continue;
  18. }
  19. var value = obj[i];
  20. var type = typeof value;
  21. if (i === "parent" && type === "object") {
  22. if (parent) {
  23. cloned[i] = parent;
  24. }
  25. }
  26. else if (value instanceof Array) {
  27. cloned[i] = value.map(function (j) { return cloneNode(j, cloned, depth + 1); });
  28. }
  29. else {
  30. cloned[i] = cloneNode(value, cloned, depth + 1);
  31. }
  32. }
  33. return cloned;
  34. };
  35. var Node = /** @class */ (function () {
  36. function Node(opts) {
  37. if (opts === void 0) { opts = {}; }
  38. Object.assign(this, opts);
  39. this.spaces = this.spaces || {};
  40. this.spaces.before = this.spaces.before || "";
  41. this.spaces.after = this.spaces.after || "";
  42. }
  43. Node.prototype.remove = function () {
  44. if (this.parent) {
  45. this.parent.removeChild(this);
  46. }
  47. this.parent = undefined;
  48. return this;
  49. };
  50. Node.prototype.replaceWith = function () {
  51. if (this.parent) {
  52. for (var index in arguments) {
  53. this.parent.insertBefore(this, arguments[index]);
  54. }
  55. this.remove();
  56. }
  57. return this;
  58. };
  59. Node.prototype.next = function () {
  60. return this.parent.at(this.parent.index(this) + 1);
  61. };
  62. Node.prototype.prev = function () {
  63. return this.parent.at(this.parent.index(this) - 1);
  64. };
  65. Node.prototype.clone = function (overrides) {
  66. if (overrides === void 0) { overrides = {}; }
  67. var cloned = cloneNode(this);
  68. for (var name in overrides) {
  69. cloned[name] = overrides[name];
  70. }
  71. return cloned;
  72. };
  73. /**
  74. * Some non-standard syntax doesn't follow normal escaping rules for css.
  75. * This allows non standard syntax to be appended to an existing property
  76. * by specifying the escaped value. By specifying the escaped value,
  77. * illegal characters are allowed to be directly inserted into css output.
  78. * @param {string} name the property to set
  79. * @param {any} value the unescaped value of the property
  80. * @param {string} valueEscaped optional. the escaped value of the property.
  81. */
  82. Node.prototype.appendToPropertyAndEscape = function (name, value, valueEscaped) {
  83. if (!this.raws) {
  84. this.raws = {};
  85. }
  86. var originalValue = this[name];
  87. var originalEscaped = this.raws[name];
  88. this[name] = originalValue + value; // this may trigger a setter that updates raws, so it has to be set first.
  89. if (originalEscaped || valueEscaped !== value) {
  90. this.raws[name] = (originalEscaped || originalValue) + valueEscaped;
  91. }
  92. else {
  93. delete this.raws[name]; // delete any escaped value that was created by the setter.
  94. }
  95. };
  96. /**
  97. * Some non-standard syntax doesn't follow normal escaping rules for css.
  98. * This allows the escaped value to be specified directly, allowing illegal
  99. * characters to be directly inserted into css output.
  100. * @param {string} name the property to set
  101. * @param {any} value the unescaped value of the property
  102. * @param {string} valueEscaped the escaped value of the property.
  103. */
  104. Node.prototype.setPropertyAndEscape = function (name, value, valueEscaped) {
  105. if (!this.raws) {
  106. this.raws = {};
  107. }
  108. this[name] = value; // this may trigger a setter that updates raws, so it has to be set first.
  109. this.raws[name] = valueEscaped;
  110. };
  111. /**
  112. * When you want a value to passed through to CSS directly. This method
  113. * deletes the corresponding raw value causing the stringifier to fallback
  114. * to the unescaped value.
  115. * @param {string} name the property to set.
  116. * @param {any} value The value that is both escaped and unescaped.
  117. */
  118. Node.prototype.setPropertyWithoutEscape = function (name, value) {
  119. this[name] = value; // this may trigger a setter that updates raws, so it has to be set first.
  120. if (this.raws) {
  121. delete this.raws[name];
  122. }
  123. };
  124. /**
  125. *
  126. * @param {number} line The number (starting with 1)
  127. * @param {number} column The column number (starting with 1)
  128. */
  129. Node.prototype.isAtPosition = function (line, column) {
  130. if (this.source && this.source.start && this.source.end) {
  131. if (this.source.start.line > line) {
  132. return false;
  133. }
  134. if (this.source.end.line < line) {
  135. return false;
  136. }
  137. if (this.source.start.line === line && this.source.start.column > column) {
  138. return false;
  139. }
  140. if (this.source.end.line === line && this.source.end.column < column) {
  141. return false;
  142. }
  143. return true;
  144. }
  145. return undefined;
  146. };
  147. Node.prototype.stringifyProperty = function (name) {
  148. return (this.raws && this.raws[name]) || this[name];
  149. };
  150. Object.defineProperty(Node.prototype, "rawSpaceBefore", {
  151. get: function () {
  152. var rawSpace = this.raws && this.raws.spaces && this.raws.spaces.before;
  153. if (rawSpace === undefined) {
  154. rawSpace = this.spaces && this.spaces.before;
  155. }
  156. return rawSpace || "";
  157. },
  158. set: function (raw) {
  159. (0, util_1.ensureObject)(this, "raws", "spaces");
  160. this.raws.spaces.before = raw;
  161. },
  162. enumerable: false,
  163. configurable: true
  164. });
  165. Object.defineProperty(Node.prototype, "rawSpaceAfter", {
  166. get: function () {
  167. var rawSpace = this.raws && this.raws.spaces && this.raws.spaces.after;
  168. if (rawSpace === undefined) {
  169. rawSpace = this.spaces.after;
  170. }
  171. return rawSpace || "";
  172. },
  173. set: function (raw) {
  174. (0, util_1.ensureObject)(this, "raws", "spaces");
  175. this.raws.spaces.after = raw;
  176. },
  177. enumerable: false,
  178. configurable: true
  179. });
  180. Node.prototype.valueToString = function () {
  181. return String(this.stringifyProperty("value"));
  182. };
  183. Node.prototype.toString = function () {
  184. return [this.rawSpaceBefore, this.valueToString(), this.rawSpaceAfter].join("");
  185. };
  186. // Internal recursion entry point used by Container serialization. Leaf
  187. // nodes don't recurse, so they ignore the depth/limit and stringify
  188. // themselves. Containers override this to thread the nesting depth.
  189. Node.prototype._stringify = function () {
  190. return this.toString();
  191. };
  192. return Node;
  193. }());
  194. exports.default = Node;
  195. //# sourceMappingURL=node.js.map