index.js 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  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/declaration-bang-space-before',
  16. fixable: true,
  17. deprecated: true,
  18. };
  19. /** @type {import('stylelint').Rule} */
  20. const rule = (primary, _secondaryOptions, context) => {
  21. const checker = whitespaceChecker('space', primary, messages);
  22. return (root, result) => {
  23. const validOptions = validateOptions(result, ruleName, {
  24. actual: primary,
  25. possible: ['always', 'never'],
  26. });
  27. if (!validOptions) {
  28. return;
  29. }
  30. declarationBangSpaceChecker({
  31. root,
  32. result,
  33. locationChecker: checker.before,
  34. checkedRuleName: ruleName,
  35. fix: context.fix
  36. ? (decl, index) => {
  37. let bangIndex = index - declarationValueIndex(decl);
  38. const value = getDeclarationValue(decl);
  39. let target;
  40. /** @type {(val: string) => void} */
  41. let setFixed;
  42. if (bangIndex < value.length) {
  43. target = value;
  44. setFixed = (val) => {
  45. setDeclarationValue(decl, val);
  46. };
  47. } else if (decl.important) {
  48. target = decl.raws.important || ' !important';
  49. bangIndex -= value.length;
  50. setFixed = (val) => {
  51. decl.raws.important = val;
  52. };
  53. } else {
  54. return false; // not standard
  55. }
  56. const targetBefore = target.slice(0, bangIndex);
  57. const targetAfter = target.slice(bangIndex);
  58. if (primary === 'always') {
  59. // eslint-disable-next-line prefer-template
  60. setFixed(targetBefore.replace(/\s*$/, '') + ' ' + targetAfter);
  61. return true;
  62. }
  63. if (primary === 'never') {
  64. setFixed(targetBefore.replace(/\s*$/, '') + targetAfter);
  65. return true;
  66. }
  67. return false;
  68. }
  69. : null,
  70. });
  71. };
  72. };
  73. rule.ruleName = ruleName;
  74. rule.messages = messages;
  75. rule.meta = meta;
  76. module.exports = rule;