index.cjs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // NOTICE: This file is generated by Rollup. To modify it,
  2. // please instead edit the ESM counterpart and rebuild with Rollup (npm run build).
  3. 'use strict';
  4. const valueParser = require('postcss-value-parser');
  5. const validateTypes = require('../../utils/validateTypes.cjs');
  6. const nodeFieldIndices = require('../../utils/nodeFieldIndices.cjs');
  7. const isCustomProperty = require('../../utils/isCustomProperty.cjs');
  8. const isStandardSyntaxFunction = require('../../utils/isStandardSyntaxFunction.cjs');
  9. const matchesStringOrRegExp = require('../../utils/matchesStringOrRegExp.cjs');
  10. const report = require('../../utils/report.cjs');
  11. const ruleMessages = require('../../utils/ruleMessages.cjs');
  12. const validateOptions = require('../../utils/validateOptions.cjs');
  13. const vendor = require('../../utils/vendor.cjs');
  14. const ruleName = 'function-allowed-list';
  15. const messages = ruleMessages(ruleName, {
  16. rejected: (name) => `Unexpected function "${name}"`,
  17. });
  18. const meta = {
  19. url: 'https://stylelint.io/user-guide/rules/function-allowed-list',
  20. };
  21. /** @type {import('stylelint').CoreRules[ruleName]} */
  22. const rule = (primary, secondaryOptions) => {
  23. return (root, result) => {
  24. const validOptions = validateOptions(
  25. result,
  26. ruleName,
  27. {
  28. actual: primary,
  29. possible: [validateTypes.isString, validateTypes.isRegExp],
  30. },
  31. {
  32. actual: secondaryOptions,
  33. possible: {
  34. exceptWithoutPropertyFallback: [validateTypes.isString, validateTypes.isRegExp],
  35. },
  36. optional: true,
  37. },
  38. );
  39. if (!validOptions) {
  40. return;
  41. }
  42. const exceptWithoutPropertyFallback = secondaryOptions?.exceptWithoutPropertyFallback ?? [];
  43. root.walkDecls((decl) => {
  44. valueParser(decl.value).walk((node) => {
  45. if (node.type !== 'function') {
  46. return;
  47. }
  48. if (!isStandardSyntaxFunction(node)) {
  49. return;
  50. }
  51. const unprefixedName = vendor.unprefixed(node.value);
  52. if (matchesStringOrRegExp(unprefixedName, primary)) {
  53. // Check if function requires fallback
  54. if (!matchesStringOrRegExp(unprefixedName, exceptWithoutPropertyFallback)) {
  55. return;
  56. }
  57. if (hasPrevPropertyDeclaration(decl)) return;
  58. }
  59. const index = nodeFieldIndices.declarationValueIndex(decl) + node.sourceIndex;
  60. const endIndex = index + node.value.length;
  61. report({
  62. message: messages.rejected,
  63. messageArgs: [node.value],
  64. node: decl,
  65. index,
  66. endIndex,
  67. result,
  68. ruleName,
  69. });
  70. });
  71. });
  72. };
  73. };
  74. /**
  75. * @param {import('postcss').Declaration} decl
  76. * @returns {boolean}
  77. */
  78. function hasPrevPropertyDeclaration(decl) {
  79. const prop = decl.prop.toLowerCase();
  80. if (isCustomProperty(prop)) return false;
  81. let prev = decl.prev();
  82. while (prev) {
  83. if (prev.type === 'decl' && prev.prop.toLowerCase() === prop) {
  84. return true;
  85. }
  86. prev = prev.prev();
  87. }
  88. return false;
  89. }
  90. rule.primaryOptionArray = true;
  91. rule.ruleName = ruleName;
  92. rule.messages = messages;
  93. rule.meta = meta;
  94. module.exports = rule;