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-before';
  10. const messages = ruleMessages(ruleName, {
  11. expectedBefore: () => 'Expected single space before "!"',
  12. rejectedBefore: () => 'Unexpected whitespace before "!"',
  13. });
  14. const meta = {
  15. url: 'https://stylelint.io/user-guide/rules/list/declaration-bang-space-before',
  16. };
  17. /** @type {import('stylelint').Rule} */
  18. const rule = (primary, _secondaryOptions, context) => {
  19. const checker = whitespaceChecker('space', primary, messages);
  20. return (root, result) => {
  21. const validOptions = validateOptions(result, ruleName, {
  22. actual: primary,
  23. possible: ['always', 'never'],
  24. });
  25. if (!validOptions) {
  26. return;
  27. }
  28. declarationBangSpaceChecker({
  29. root,
  30. result,
  31. locationChecker: checker.before,
  32. checkedRuleName: ruleName,
  33. fix: context.fix
  34. ? (decl, index) => {
  35. let bangIndex = index - declarationValueIndex(decl);
  36. const value = getDeclarationValue(decl);
  37. let target;
  38. /** @type {(val: string) => void} */
  39. let setFixed;
  40. if (bangIndex < value.length) {
  41. target = value;
  42. setFixed = (val) => {
  43. setDeclarationValue(decl, val);
  44. };
  45. } else if (decl.important) {
  46. target = decl.raws.important || ' !important';
  47. bangIndex -= value.length;
  48. setFixed = (val) => {
  49. decl.raws.important = val;
  50. };
  51. } else {
  52. return false; // not standard
  53. }
  54. const targetBefore = target.slice(0, bangIndex);
  55. const targetAfter = target.slice(bangIndex);
  56. if (primary === 'always') {
  57. // eslint-disable-next-line prefer-template
  58. setFixed(targetBefore.replace(/\s*$/, '') + ' ' + targetAfter);
  59. return true;
  60. }
  61. if (primary === 'never') {
  62. setFixed(targetBefore.replace(/\s*$/, '') + targetAfter);
  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;