index.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // @ts-nocheck
  2. 'use strict';
  3. const _ = require('lodash');
  4. const declarationValueIndex = require('../../utils/declarationValueIndex');
  5. const isStandardSyntaxFunction = require('../../utils/isStandardSyntaxFunction');
  6. const keywordSets = require('../../reference/keywordSets');
  7. const matchesStringOrRegExp = require('../../utils/matchesStringOrRegExp');
  8. const report = require('../../utils/report');
  9. const ruleMessages = require('../../utils/ruleMessages');
  10. const validateOptions = require('../../utils/validateOptions');
  11. const valueParser = require('postcss-value-parser');
  12. const ruleName = 'function-name-case';
  13. const messages = ruleMessages(ruleName, {
  14. expected: (actual, expected) => `Expected "${actual}" to be "${expected}"`,
  15. });
  16. const mapLowercaseFunctionNamesToCamelCase = new Map();
  17. keywordSets.camelCaseFunctionNames.forEach((func) => {
  18. mapLowercaseFunctionNamesToCamelCase.set(func.toLowerCase(), func);
  19. });
  20. function rule(expectation, options, context) {
  21. return (root, result) => {
  22. const validOptions = validateOptions(
  23. result,
  24. ruleName,
  25. {
  26. actual: expectation,
  27. possible: ['lower', 'upper'],
  28. },
  29. {
  30. actual: options,
  31. possible: {
  32. ignoreFunctions: [_.isString, _.isRegExp],
  33. },
  34. optional: true,
  35. },
  36. );
  37. if (!validOptions) {
  38. return;
  39. }
  40. root.walkDecls((decl) => {
  41. let needFix = false;
  42. const parsed = valueParser(decl.raws.value ? decl.raws.value.raw : decl.value);
  43. parsed.walk((node) => {
  44. if (node.type !== 'function' || !isStandardSyntaxFunction(node)) {
  45. return;
  46. }
  47. const functionName = node.value;
  48. const functionNameLowerCase = functionName.toLowerCase();
  49. const ignoreFunctions = (options && options.ignoreFunctions) || [];
  50. if (ignoreFunctions.length > 0 && matchesStringOrRegExp(functionName, ignoreFunctions)) {
  51. return;
  52. }
  53. let expectedFunctionName = null;
  54. if (
  55. expectation === 'lower' &&
  56. mapLowercaseFunctionNamesToCamelCase.has(functionNameLowerCase)
  57. ) {
  58. expectedFunctionName = mapLowercaseFunctionNamesToCamelCase.get(functionNameLowerCase);
  59. } else if (expectation === 'lower') {
  60. expectedFunctionName = functionNameLowerCase;
  61. } else {
  62. expectedFunctionName = functionName.toUpperCase();
  63. }
  64. if (functionName === expectedFunctionName) {
  65. return;
  66. }
  67. if (context.fix) {
  68. needFix = true;
  69. node.value = expectedFunctionName;
  70. return;
  71. }
  72. report({
  73. message: messages.expected(functionName, expectedFunctionName),
  74. node: decl,
  75. index: declarationValueIndex(decl) + node.sourceIndex,
  76. result,
  77. ruleName,
  78. });
  79. });
  80. if (context.fix && needFix) {
  81. const statement = parsed.toString();
  82. if (decl.raws.value) {
  83. decl.raws.value.raw = statement;
  84. } else {
  85. decl.value = statement;
  86. }
  87. }
  88. });
  89. };
  90. }
  91. rule.ruleName = ruleName;
  92. rule.messages = messages;
  93. module.exports = rule;