stringify.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. "use strict";
  2. var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
  3. if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
  4. if (ar || !(i in from)) {
  5. if (!ar) ar = Array.prototype.slice.call(from, 0, i);
  6. ar[i] = from[i];
  7. }
  8. }
  9. return to.concat(ar || Array.prototype.slice.call(from));
  10. };
  11. Object.defineProperty(exports, "__esModule", { value: true });
  12. exports.stringify = void 0;
  13. var types_1 = require("./types");
  14. var attribValChars = ["\\", '"'];
  15. var pseudoValChars = __spreadArray(__spreadArray([], attribValChars, true), ["(", ")"], false);
  16. var charsToEscapeInAttributeValue = new Set(attribValChars.map(function (c) { return c.charCodeAt(0); }));
  17. var charsToEscapeInPseudoValue = new Set(pseudoValChars.map(function (c) { return c.charCodeAt(0); }));
  18. var charsToEscapeInName = new Set(__spreadArray(__spreadArray([], pseudoValChars, true), [
  19. "~",
  20. "^",
  21. "$",
  22. "*",
  23. "+",
  24. "!",
  25. "|",
  26. ":",
  27. "[",
  28. "]",
  29. " ",
  30. ".",
  31. ], false).map(function (c) { return c.charCodeAt(0); }));
  32. /**
  33. * Turns `selector` back into a string.
  34. *
  35. * @param selector Selector to stringify.
  36. */
  37. function stringify(selector) {
  38. return selector
  39. .map(function (token) { return token.map(stringifyToken).join(""); })
  40. .join(", ");
  41. }
  42. exports.stringify = stringify;
  43. function stringifyToken(token, index, arr) {
  44. switch (token.type) {
  45. // Simple types
  46. case types_1.SelectorType.Child:
  47. return index === 0 ? "> " : " > ";
  48. case types_1.SelectorType.Parent:
  49. return index === 0 ? "< " : " < ";
  50. case types_1.SelectorType.Sibling:
  51. return index === 0 ? "~ " : " ~ ";
  52. case types_1.SelectorType.Adjacent:
  53. return index === 0 ? "+ " : " + ";
  54. case types_1.SelectorType.Descendant:
  55. return " ";
  56. case types_1.SelectorType.ColumnCombinator:
  57. return index === 0 ? "|| " : " || ";
  58. case types_1.SelectorType.Universal:
  59. // Return an empty string if the selector isn't needed.
  60. return token.namespace === "*" &&
  61. index + 1 < arr.length &&
  62. "name" in arr[index + 1]
  63. ? ""
  64. : "".concat(getNamespace(token.namespace), "*");
  65. case types_1.SelectorType.Tag:
  66. return getNamespacedName(token);
  67. case types_1.SelectorType.PseudoElement:
  68. return "::".concat(escapeName(token.name, charsToEscapeInName)).concat(token.data === null
  69. ? ""
  70. : "(".concat(escapeName(token.data, charsToEscapeInPseudoValue), ")"));
  71. case types_1.SelectorType.Pseudo:
  72. return ":".concat(escapeName(token.name, charsToEscapeInName)).concat(token.data === null
  73. ? ""
  74. : "(".concat(typeof token.data === "string"
  75. ? escapeName(token.data, charsToEscapeInPseudoValue)
  76. : stringify(token.data), ")"));
  77. case types_1.SelectorType.Attribute: {
  78. if (token.name === "id" &&
  79. token.action === types_1.AttributeAction.Equals &&
  80. token.ignoreCase === "quirks" &&
  81. !token.namespace) {
  82. return "#".concat(escapeName(token.value, charsToEscapeInName));
  83. }
  84. if (token.name === "class" &&
  85. token.action === types_1.AttributeAction.Element &&
  86. token.ignoreCase === "quirks" &&
  87. !token.namespace) {
  88. return ".".concat(escapeName(token.value, charsToEscapeInName));
  89. }
  90. var name_1 = getNamespacedName(token);
  91. if (token.action === types_1.AttributeAction.Exists) {
  92. return "[".concat(name_1, "]");
  93. }
  94. return "[".concat(name_1).concat(getActionValue(token.action), "=\"").concat(escapeName(token.value, charsToEscapeInAttributeValue), "\"").concat(token.ignoreCase === null ? "" : token.ignoreCase ? " i" : " s", "]");
  95. }
  96. }
  97. }
  98. function getActionValue(action) {
  99. switch (action) {
  100. case types_1.AttributeAction.Equals:
  101. return "";
  102. case types_1.AttributeAction.Element:
  103. return "~";
  104. case types_1.AttributeAction.Start:
  105. return "^";
  106. case types_1.AttributeAction.End:
  107. return "$";
  108. case types_1.AttributeAction.Any:
  109. return "*";
  110. case types_1.AttributeAction.Not:
  111. return "!";
  112. case types_1.AttributeAction.Hyphen:
  113. return "|";
  114. case types_1.AttributeAction.Exists:
  115. throw new Error("Shouldn't be here");
  116. }
  117. }
  118. function getNamespacedName(token) {
  119. return "".concat(getNamespace(token.namespace)).concat(escapeName(token.name, charsToEscapeInName));
  120. }
  121. function getNamespace(namespace) {
  122. return namespace !== null
  123. ? "".concat(namespace === "*"
  124. ? "*"
  125. : escapeName(namespace, charsToEscapeInName), "|")
  126. : "";
  127. }
  128. function escapeName(str, charsToEscape) {
  129. var lastIdx = 0;
  130. var ret = "";
  131. for (var i = 0; i < str.length; i++) {
  132. if (charsToEscape.has(str.charCodeAt(i))) {
  133. ret += "".concat(str.slice(lastIdx, i), "\\").concat(str.charAt(i));
  134. lastIdx = i + 1;
  135. }
  136. }
  137. return ret.length > 0 ? ret + str.slice(lastIdx) : str;
  138. }