4
0

functionArgumentsSearch.mjs 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. import balancedMatch from 'balanced-match';
  2. import valueParser from 'postcss-value-parser';
  3. import { assert, isRegExp, isString } from './validateTypes.mjs';
  4. /** @typedef {(expression: string, expressionIndex: number, funcNode: valueParser.FunctionNode, parsedValue: valueParser.ParsedValue) => void} Callback */
  5. /**
  6. * Search a CSS string for functions by name.
  7. * For every match, invoke the callback, passing the function's
  8. * "argument(s) string" (whatever is inside the parentheses)
  9. * as an argument.
  10. *
  11. * Callback will be called once for every matching function found,
  12. * with the function's "argument(s) string" and its starting index
  13. * as the arguments.
  14. *
  15. * @param {string} source
  16. * @param {string | RegExp} functionName
  17. * @param {Callback} callback
  18. * @returns {valueParser.ParsedValue}
  19. */
  20. export default function functionArgumentsSearch(source, functionName, callback) {
  21. const parsedValue = valueParser(source);
  22. return parsedValue.walk((node) => {
  23. if (node.type !== 'function') return;
  24. const { value } = node;
  25. if (isString(functionName) && value !== functionName) return;
  26. if (isRegExp(functionName) && !functionName.test(node.value)) return;
  27. const parensMatch = balancedMatch('(', ')', source.slice(node.sourceIndex));
  28. assert(parensMatch);
  29. const expression = parensMatch.body;
  30. const parenLength = 1; // == '('
  31. const expressionIndex = node.sourceIndex + value.length + parenLength;
  32. callback(expression, expressionIndex, node, parsedValue);
  33. });
  34. }