index.cjs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  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 regexes = require('../../utils/regexes.cjs');
  6. const nodeFieldIndices = require('../../utils/nodeFieldIndices.cjs');
  7. const isVarFunction = require('../../utils/isVarFunction.cjs');
  8. const report = require('../../utils/report.cjs');
  9. const ruleMessages = require('../../utils/ruleMessages.cjs');
  10. const validateOptions = require('../../utils/validateOptions.cjs');
  11. const ruleName = 'custom-property-no-missing-var-function';
  12. const messages = ruleMessages(ruleName, {
  13. rejected: (customProperty) => `Unexpected missing var function for "${customProperty}"`,
  14. });
  15. const meta = {
  16. url: 'https://stylelint.io/user-guide/rules/custom-property-no-missing-var-function',
  17. };
  18. /** @typedef {import('postcss-value-parser').Node} Node */
  19. // Properties that can receive a custom-ident
  20. const IGNORED_PROPERTIES = new Set([
  21. 'animation',
  22. 'animation-name',
  23. 'container-name',
  24. 'counter-increment',
  25. 'counter-reset',
  26. 'counter-set',
  27. 'grid-column',
  28. 'grid-column-end',
  29. 'grid-column-start',
  30. 'grid-row',
  31. 'grid-row-end',
  32. 'grid-row-start',
  33. 'list-style',
  34. 'list-style-type',
  35. 'transition',
  36. 'transition-property',
  37. 'view-transition-name',
  38. 'will-change',
  39. ]);
  40. /** @type {import('stylelint').CoreRules[ruleName]} */
  41. const rule = (primary) => {
  42. return (root, result) => {
  43. const validOptions = validateOptions(result, ruleName, { actual: primary });
  44. if (!validOptions) return;
  45. /** @type {Set<string>} */
  46. const knownCustomProperties = new Set();
  47. root.walkAtRules(regexes.atRuleRegexes.propertyName, ({ params }) => {
  48. knownCustomProperties.add(params);
  49. });
  50. root.walkDecls(/^--/, ({ prop }) => {
  51. knownCustomProperties.add(prop);
  52. });
  53. root.walkDecls((decl) => {
  54. const { prop, value } = decl;
  55. if (!value.includes('--')) return;
  56. if (IGNORED_PROPERTIES.has(prop.toLowerCase())) return;
  57. valueParser(value).nodes.forEach((childNode) => {
  58. check(childNode, decl);
  59. });
  60. });
  61. /**
  62. * @param {Node} node
  63. * @param {import('postcss').Declaration} decl
  64. */
  65. function check(node, decl) {
  66. if (node.type === 'function') {
  67. const name = node.value.toLowerCase();
  68. let args = node.nodes;
  69. if (name === 'var') args = node.nodes.slice(1);
  70. else if (name === 'running') {
  71. const [child] = node.nodes;
  72. const mustDrill = child && isVarFunction(child);
  73. if (mustDrill) args = child.nodes.slice(1);
  74. else return;
  75. }
  76. args.forEach((arg) => check(arg, decl));
  77. return;
  78. }
  79. if (!isDashedIdent(node)) return;
  80. if (!knownCustomProperties.has(node.value)) return;
  81. const index = nodeFieldIndices.declarationValueIndex(decl) + node.sourceIndex;
  82. const endIndex = index + node.value.length;
  83. report({
  84. message: messages.rejected,
  85. messageArgs: [node.value],
  86. node: decl,
  87. index,
  88. endIndex,
  89. result,
  90. ruleName,
  91. });
  92. }
  93. };
  94. };
  95. /**
  96. * @param {Node} node
  97. */
  98. function isDashedIdent({ type, value }) {
  99. return type === 'word' && value.startsWith('--');
  100. }
  101. rule.ruleName = ruleName;
  102. rule.messages = messages;
  103. rule.meta = meta;
  104. module.exports = rule;