index.js 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. 'use strict';
  2. const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule');
  3. const keywordSets = require('../../reference/keywordSets');
  4. const parseSelector = require('../../utils/parseSelector');
  5. const report = require('../../utils/report');
  6. const ruleMessages = require('../../utils/ruleMessages');
  7. const validateOptions = require('../../utils/validateOptions');
  8. const ruleName = 'selector-pseudo-element-colon-notation';
  9. const messages = ruleMessages(ruleName, {
  10. expected: (q) => `Expected ${q} colon pseudo-element notation`,
  11. });
  12. const meta = {
  13. url: 'https://stylelint.io/user-guide/rules/list/selector-pseudo-element-colon-notation',
  14. };
  15. /** @type {import('stylelint').Rule} */
  16. const rule = (primary, _secondaryOptions, context) => {
  17. return (root, result) => {
  18. const validOptions = validateOptions(result, ruleName, {
  19. actual: primary,
  20. possible: ['single', 'double'],
  21. });
  22. if (!validOptions) {
  23. return;
  24. }
  25. let fixedColon = '';
  26. if (primary === 'single') {
  27. fixedColon = ':';
  28. } else if (primary === 'double') {
  29. fixedColon = '::';
  30. }
  31. root.walkRules((ruleNode) => {
  32. if (!isStandardSyntaxRule(ruleNode)) {
  33. return;
  34. }
  35. const selector = ruleNode.selector;
  36. // get out early if no pseudo elements or classes
  37. if (!selector.includes(':')) {
  38. return;
  39. }
  40. const fixedSelector = parseSelector(selector, result, ruleNode, (selectors) => {
  41. selectors.walkPseudos((pseudo) => {
  42. const pseudoElement = pseudo.value.replace(/:/g, '');
  43. if (!keywordSets.levelOneAndTwoPseudoElements.has(pseudoElement.toLowerCase())) {
  44. return;
  45. }
  46. const isDouble = pseudo.value.startsWith('::');
  47. if (primary === 'single' && !isDouble) {
  48. return;
  49. }
  50. if (primary === 'double' && isDouble) {
  51. return;
  52. }
  53. if (context.fix) {
  54. pseudo.replaceWith(pseudo.clone({ value: fixedColon + pseudoElement }));
  55. return;
  56. }
  57. report({
  58. message: messages.expected(primary),
  59. node: ruleNode,
  60. index: pseudo.sourceIndex,
  61. result,
  62. ruleName,
  63. });
  64. });
  65. });
  66. if (context.fix && fixedSelector) {
  67. ruleNode.selector = fixedSelector;
  68. }
  69. });
  70. };
  71. };
  72. rule.ruleName = ruleName;
  73. rule.messages = messages;
  74. rule.meta = meta;
  75. module.exports = rule;