index.js 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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. 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.before,
  33. checkedRuleName: ruleName,
  34. fix: context.fix
  35. ? (decl, index) => {
  36. let bangIndex = index - declarationValueIndex(decl);
  37. const value = getDeclarationValue(decl);
  38. let target;
  39. /** @type {(val: string) => void} */
  40. let setFixed;
  41. if (bangIndex < value.length) {
  42. target = value;
  43. setFixed = (val) => {
  44. setDeclarationValue(decl, val);
  45. };
  46. } else if (decl.important) {
  47. target = decl.raws.important || ' !important';
  48. bangIndex -= value.length;
  49. setFixed = (val) => {
  50. decl.raws.important = val;
  51. };
  52. } else {
  53. return false; // not standard
  54. }
  55. const targetBefore = target.slice(0, bangIndex);
  56. const targetAfter = target.slice(bangIndex);
  57. if (primary === 'always') {
  58. // eslint-disable-next-line prefer-template
  59. setFixed(targetBefore.replace(/\s*$/, '') + ' ' + targetAfter);
  60. return true;
  61. }
  62. if (primary === 'never') {
  63. setFixed(targetBefore.replace(/\s*$/, '') + targetAfter);
  64. return true;
  65. }
  66. return false;
  67. }
  68. : null,
  69. });
  70. };
  71. };
  72. rule.ruleName = ruleName;
  73. rule.messages = messages;
  74. rule.meta = meta;
  75. module.exports = rule;