index.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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. };
  14. /** @type {import('stylelint').Rule} */
  15. const rule = (primary, _secondaryOptions, context) => {
  16. return (root, result) => {
  17. const checker = whitespaceChecker('space', primary, messages);
  18. const validOptions = validateOptions(result, ruleName, {
  19. actual: primary,
  20. possible: ['always', 'never'],
  21. });
  22. if (!validOptions) {
  23. return;
  24. }
  25. selectorAttributeOperatorSpaceChecker({
  26. root,
  27. result,
  28. locationChecker: checker.after,
  29. checkedRuleName: ruleName,
  30. checkBeforeOperator: false,
  31. fix: context.fix
  32. ? (attributeNode) => {
  33. /** @type {{ operatorAfter: string, setOperatorAfter: (fixed: string) => void }} */
  34. const { operatorAfter, setOperatorAfter } = (() => {
  35. const rawOperator = attributeNode.raws.operator;
  36. if (rawOperator) {
  37. return {
  38. operatorAfter: rawOperator.slice(
  39. attributeNode.operator ? attributeNode.operator.length : 0,
  40. ),
  41. setOperatorAfter(fixed) {
  42. delete attributeNode.raws.operator;
  43. if (!attributeNode.raws.spaces) attributeNode.raws.spaces = {};
  44. if (!attributeNode.raws.spaces.operator)
  45. attributeNode.raws.spaces.operator = {};
  46. attributeNode.raws.spaces.operator.after = fixed;
  47. },
  48. };
  49. }
  50. const rawSpacesOperator =
  51. attributeNode.raws.spaces && attributeNode.raws.spaces.operator;
  52. const rawOperatorAfter = rawSpacesOperator && rawSpacesOperator.after;
  53. if (rawOperatorAfter) {
  54. return {
  55. operatorAfter: rawOperatorAfter,
  56. setOperatorAfter(fixed) {
  57. rawSpacesOperator.after = fixed;
  58. },
  59. };
  60. }
  61. return {
  62. operatorAfter:
  63. (attributeNode.spaces.operator && attributeNode.spaces.operator.after) || '',
  64. setOperatorAfter(fixed) {
  65. if (!attributeNode.spaces.operator) attributeNode.spaces.operator = {};
  66. attributeNode.spaces.operator.after = fixed;
  67. },
  68. };
  69. })();
  70. if (primary === 'always') {
  71. setOperatorAfter(operatorAfter.replace(/^\s*/, ' '));
  72. return true;
  73. }
  74. if (primary === 'never') {
  75. setOperatorAfter(operatorAfter.replace(/^\s*/, ''));
  76. return true;
  77. }
  78. return false;
  79. }
  80. : null,
  81. });
  82. };
  83. };
  84. rule.ruleName = ruleName;
  85. rule.messages = messages;
  86. rule.meta = meta;
  87. module.exports = rule;