index.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. 'use strict';
  2. const declarationBangSpaceChecker = require('../declarationBangSpaceChecker');
  3. const declarationValueIndex = require('../../utils/declarationValueIndex');
  4. const getDeclarationValue = require('../../utils/getDeclarationValue');
  5. const ruleMessages = require('../../utils/ruleMessages');
  6. const setDeclarationValue = require('../../utils/setDeclarationValue');
  7. const validateOptions = require('../../utils/validateOptions');
  8. const whitespaceChecker = require('../../utils/whitespaceChecker');
  9. const ruleName = 'declaration-bang-space-after';
  10. const messages = ruleMessages(ruleName, {
  11. expectedAfter: () => 'Expected single space after "!"',
  12. rejectedAfter: () => 'Unexpected whitespace after "!"',
  13. });
  14. const meta = {
  15. url: 'https://stylelint.io/user-guide/rules/declaration-bang-space-after',
  16. fixable: true,
  17. };
  18. /** @type {import('stylelint').Rule} */
  19. const rule = (primary, _secondaryOptions, context) => {
  20. const checker = whitespaceChecker('space', primary, messages);
  21. return (root, result) => {
  22. const validOptions = validateOptions(result, ruleName, {
  23. actual: primary,
  24. possible: ['always', 'never'],
  25. });
  26. if (!validOptions) {
  27. return;
  28. }
  29. declarationBangSpaceChecker({
  30. root,
  31. result,
  32. locationChecker: checker.after,
  33. checkedRuleName: ruleName,
  34. fix: context.fix
  35. ? (decl, index) => {
  36. let bangIndex = index - declarationValueIndex(decl);
  37. const declValue = getDeclarationValue(decl);
  38. let target;
  39. /** @type {(value: string) => void} */
  40. let setFixed;
  41. if (bangIndex < declValue.length) {
  42. target = declValue;
  43. setFixed = (value) => {
  44. setDeclarationValue(decl, value);
  45. };
  46. } else if (decl.important) {
  47. target = decl.raws.important || ' !important';
  48. bangIndex -= declValue.length;
  49. setFixed = (value) => {
  50. decl.raws.important = value;
  51. };
  52. } else {
  53. return false; // not standard
  54. }
  55. const targetBefore = target.slice(0, bangIndex + 1);
  56. const targetAfter = target.slice(bangIndex + 1);
  57. if (primary === 'always') {
  58. setFixed(targetBefore + targetAfter.replace(/^\s*/, ' '));
  59. return true;
  60. }
  61. if (primary === 'never') {
  62. setFixed(targetBefore + targetAfter.replace(/^\s*/, ''));
  63. return true;
  64. }
  65. return false;
  66. }
  67. : null,
  68. });
  69. };
  70. };
  71. rule.ruleName = ruleName;
  72. rule.messages = messages;
  73. rule.meta = meta;
  74. module.exports = rule;