index.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // @ts-nocheck
  2. 'use strict';
  3. const valueParser = require('postcss-value-parser');
  4. const declarationValueIndex = require('../../utils/declarationValueIndex');
  5. const isStandardSyntaxDeclaration = require('../../utils/isStandardSyntaxDeclaration');
  6. const isStandardSyntaxValue = require('../../utils/isStandardSyntaxValue');
  7. const report = require('../../utils/report');
  8. const ruleMessages = require('../../utils/ruleMessages');
  9. const validateOptions = require('../../utils/validateOptions');
  10. const ruleName = 'hue-degree-notation';
  11. const messages = ruleMessages(ruleName, {
  12. expected: (unfixed, fixed) => `Expected "${unfixed}" to be "${fixed}"`,
  13. });
  14. const HUE_FIRST_ARG_FUNCS = ['hsl', 'hsla', 'hwb'];
  15. const HUE_THIRD_ARG_FUNCS = ['lch'];
  16. const HUE_FUNCS = [...HUE_FIRST_ARG_FUNCS, ...HUE_THIRD_ARG_FUNCS];
  17. function rule(primary, secondary, context) {
  18. return (root, result) => {
  19. const validOptions = validateOptions(result, ruleName, {
  20. actual: primary,
  21. possible: ['angle', 'number'],
  22. });
  23. if (!validOptions) return;
  24. root.walkDecls((decl) => {
  25. if (!isStandardSyntaxDeclaration(decl)) return;
  26. let needsFix = false;
  27. const parsedValue = valueParser(getValue(decl));
  28. parsedValue.walk((node) => {
  29. if (node.type !== 'function') return;
  30. if (!HUE_FUNCS.includes(node.value.toLowerCase())) return;
  31. const hue = findHue(node);
  32. if (!hue) return;
  33. const { value } = hue;
  34. if (!isStandardSyntaxValue(value)) return;
  35. if (!isDegree(value) && !isNumber(value)) return;
  36. if (primary === 'angle' && isDegree(value)) return;
  37. if (primary === 'number' && isNumber(value)) return;
  38. const fixed = primary === 'angle' ? asDegree(value) : asNumber(value);
  39. const unfixed = value;
  40. if (context.fix) {
  41. hue.value = fixed;
  42. needsFix = true;
  43. return;
  44. }
  45. report({
  46. message: messages.expected(unfixed, fixed),
  47. node: decl,
  48. index: declarationValueIndex(decl) + hue.sourceIndex,
  49. result,
  50. ruleName,
  51. });
  52. });
  53. if (needsFix) {
  54. setValue(decl, parsedValue.toString());
  55. }
  56. });
  57. };
  58. }
  59. function asDegree(value) {
  60. return `${value}deg`;
  61. }
  62. function asNumber(value) {
  63. const { number } = valueParser.unit(value);
  64. return number;
  65. }
  66. function findHue(node) {
  67. const args = node.nodes.filter(({ type }) => type === 'word' || type === 'function');
  68. const value = node.value.toLowerCase();
  69. if (HUE_FIRST_ARG_FUNCS.includes(value)) {
  70. return args[0];
  71. }
  72. if (HUE_THIRD_ARG_FUNCS.includes(value)) {
  73. return args[2];
  74. }
  75. return false;
  76. }
  77. function isDegree(value) {
  78. const { unit } = valueParser.unit(value);
  79. return unit && unit.toLowerCase() === 'deg';
  80. }
  81. function isNumber(value) {
  82. const { unit } = valueParser.unit(value);
  83. return unit === '';
  84. }
  85. function getValue(decl) {
  86. return decl.raws.value ? decl.raws.value.raw : decl.value;
  87. }
  88. function setValue(decl, value) {
  89. if (decl.raws.value) decl.raws.value.raw = value;
  90. else decl.value = value;
  91. return decl;
  92. }
  93. rule.ruleName = ruleName;
  94. rule.messages = messages;
  95. module.exports = rule;