selector.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. var trim = require('./trim');
  2. var each = require('./each');
  3. var identity = require('./identity');
  4. var map = require('./map');
  5. var whitespace = '[\\x20\\t\\r\\n\\f]';
  6. var identifier = '(?:\\\\[\\da-fA-F]{1,6}'.concat(
  7. whitespace,
  8. '?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+'
  9. );
  10. var attributes = '\\['
  11. .concat(whitespace, '*(')
  12. .concat(identifier, ')(?:')
  13. .concat(whitespace, '*([*^$|!~]?=)')
  14. .concat(
  15. whitespace,
  16. '*(?:\'((?:\\\\.|[^\\\\\'])*)\'|"((?:\\\\.|[^\\\\"])*)"|('
  17. )
  18. .concat(identifier, '))|)')
  19. .concat(whitespace, '*\\]');
  20. var pseudos = '::?('
  21. .concat(
  22. identifier,
  23. ')(?:\\(((\'((?:\\\\.|[^\\\\\'])*)\'|"((?:\\\\.|[^\\\\"])*)")|((?:\\\\.|[^\\\\()[\\]]|'
  24. )
  25. .concat(attributes, ')*)|.*)\\)|)');
  26. var regComma = new RegExp('^'.concat(whitespace, '*,').concat(whitespace, '*'));
  27. var regCombinators = new RegExp(
  28. '^'
  29. .concat(whitespace, '*([>+~]|')
  30. .concat(whitespace, ')')
  31. .concat(whitespace, '*')
  32. );
  33. var matchExpr = {
  34. id: {
  35. reg: new RegExp('^#('.concat(identifier, ')')),
  36. value: function(raw) {
  37. return raw.slice(1);
  38. },
  39. toStr: function(value) {
  40. return '#'.concat(value);
  41. }
  42. },
  43. class: {
  44. reg: new RegExp('^\\.('.concat(identifier, ')')),
  45. value: function(raw) {
  46. return raw.slice(1);
  47. },
  48. toStr: function(value) {
  49. return '.'.concat(value);
  50. }
  51. },
  52. tag: {
  53. reg: new RegExp('^('.concat(identifier, '|[*])')),
  54. value: identity
  55. },
  56. attribute: {
  57. reg: new RegExp('^'.concat(attributes)),
  58. value: function(raw) {
  59. return raw.slice(1, raw.length - 1);
  60. },
  61. toStr: function(value) {
  62. return '['.concat(value, ']');
  63. }
  64. },
  65. pseudo: {
  66. reg: new RegExp('^'.concat(pseudos)),
  67. value: identity
  68. }
  69. };
  70. each(matchExpr, function(item) {
  71. if (!item.value) item.value = identity;
  72. if (!item.toStr) item.toStr = identity;
  73. });
  74. function parse(selector) {
  75. selector = trim(selector);
  76. var groups = [];
  77. var tokens;
  78. var match;
  79. var matched;
  80. while (selector) {
  81. if (!matched || (match = regComma.exec(selector))) {
  82. if (match) {
  83. selector = selector.slice(match[0].length);
  84. }
  85. tokens = [];
  86. groups.push(tokens);
  87. }
  88. matched = false;
  89. if ((match = regCombinators.exec(selector))) {
  90. matched = match.shift();
  91. selector = selector.slice(matched.length);
  92. matched = trim(matched);
  93. if (!matched) matched = ' ';
  94. tokens.push({
  95. value: matched,
  96. type: 'combinator'
  97. });
  98. }
  99. each(matchExpr, function(_ref, type) {
  100. var reg = _ref.reg,
  101. value = _ref.value;
  102. if ((match = reg.exec(selector))) {
  103. matched = match.shift();
  104. selector = selector.slice(matched.length);
  105. matched = trim(matched);
  106. tokens.push({
  107. value: value(matched),
  108. type: type
  109. });
  110. }
  111. });
  112. if (!matched) {
  113. break;
  114. }
  115. }
  116. return groups;
  117. }
  118. function stringify(groups) {
  119. return map(groups, function(group) {
  120. group = map(group, function(_ref2) {
  121. var type = _ref2.type,
  122. value = _ref2.value;
  123. if (type === 'combinator') {
  124. return value === ' ' ? value : ' '.concat(value, ' ');
  125. }
  126. return matchExpr[type].toStr(value);
  127. });
  128. return group.join('');
  129. }).join(', ');
  130. }
  131. exports = {
  132. parse: parse,
  133. stringify: stringify
  134. };
  135. module.exports = exports;