index.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. 'use strict';
  2. const ruleMessages = require('../../utils/ruleMessages');
  3. const selectorAttributeOperatorSpaceChecker = require('../selectorAttributeOperatorSpaceChecker');
  4. const validateOptions = require('../../utils/validateOptions');
  5. const whitespaceChecker = require('../../utils/whitespaceChecker');
  6. const ruleName = 'selector-attribute-operator-space-after';
  7. const messages = ruleMessages(ruleName, {
  8. expectedAfter: (operator) => `Expected single space after "${operator}"`,
  9. rejectedAfter: (operator) => `Unexpected whitespace after "${operator}"`,
  10. });
  11. const meta = {
  12. url: 'https://stylelint.io/user-guide/rules/list/selector-attribute-operator-space-after',
  13. fixable: true,
  14. };
  15. /** @type {import('stylelint').Rule} */
  16. const rule = (primary, _secondaryOptions, context) => {
  17. return (root, result) => {
  18. const checker = whitespaceChecker('space', primary, messages);
  19. const validOptions = validateOptions(result, ruleName, {
  20. actual: primary,
  21. possible: ['always', 'never'],
  22. });
  23. if (!validOptions) {
  24. return;
  25. }
  26. selectorAttributeOperatorSpaceChecker({
  27. root,
  28. result,
  29. locationChecker: checker.after,
  30. checkedRuleName: ruleName,
  31. checkBeforeOperator: false,
  32. fix: context.fix
  33. ? (attributeNode) => {
  34. /** @type {{ operatorAfter: string, setOperatorAfter: (fixed: string) => void }} */
  35. const { operatorAfter, setOperatorAfter } = (() => {
  36. const rawOperator = attributeNode.raws.operator;
  37. if (rawOperator) {
  38. return {
  39. operatorAfter: rawOperator.slice(
  40. attributeNode.operator ? attributeNode.operator.length : 0,
  41. ),
  42. setOperatorAfter(fixed) {
  43. delete attributeNode.raws.operator;
  44. if (!attributeNode.raws.spaces) attributeNode.raws.spaces = {};
  45. if (!attributeNode.raws.spaces.operator)
  46. attributeNode.raws.spaces.operator = {};
  47. attributeNode.raws.spaces.operator.after = fixed;
  48. },
  49. };
  50. }
  51. const rawSpacesOperator =
  52. attributeNode.raws.spaces && attributeNode.raws.spaces.operator;
  53. const rawOperatorAfter = rawSpacesOperator && rawSpacesOperator.after;
  54. if (rawOperatorAfter) {
  55. return {
  56. operatorAfter: rawOperatorAfter,
  57. setOperatorAfter(fixed) {
  58. rawSpacesOperator.after = fixed;
  59. },
  60. };
  61. }
  62. return {
  63. operatorAfter:
  64. (attributeNode.spaces.operator && attributeNode.spaces.operator.after) || '',
  65. setOperatorAfter(fixed) {
  66. if (!attributeNode.spaces.operator) attributeNode.spaces.operator = {};
  67. attributeNode.spaces.operator.after = fixed;
  68. },
  69. };
  70. })();
  71. if (primary === 'always') {
  72. setOperatorAfter(operatorAfter.replace(/^\s*/, ' '));
  73. return true;
  74. }
  75. if (primary === 'never') {
  76. setOperatorAfter(operatorAfter.replace(/^\s*/, ''));
  77. return true;
  78. }
  79. return false;
  80. }
  81. : null,
  82. });
  83. };
  84. };
  85. rule.ruleName = ruleName;
  86. rule.messages = messages;
  87. rule.meta = meta;
  88. module.exports = rule;