rangeContextNodeParser.js 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. 'use strict';
  2. const valueParser = require('postcss-value-parser');
  3. const { assert } = require('../utils/validateTypes');
  4. const rangeOperators = new Set(['>=', '<=', '>', '<', '=']);
  5. /**
  6. * @param {string} name
  7. * @returns {boolean}
  8. */
  9. function isRangeContextName(name) {
  10. // When the node is like "(width > 10em)" or "(10em < width)"
  11. // Regex is needed because the name can either be in the first or second position
  12. return /^(?!--)\D/.test(name) || /^--./.test(name);
  13. }
  14. /**
  15. * @typedef {{ value: string, sourceIndex: number }} RangeContextNode
  16. *
  17. * @param {import('postcss-media-query-parser').Node} node
  18. * @returns {{ name: RangeContextNode, values: RangeContextNode[] }}
  19. */
  20. module.exports = function rangeContextNodeParser(node) {
  21. /** @type {import('postcss-value-parser').WordNode | undefined} */
  22. let nameNode;
  23. /** @type {import('postcss-value-parser').WordNode[]} */
  24. const valueNodes = [];
  25. valueParser(node.value).walk((valueNode) => {
  26. if (valueNode.type !== 'word') return;
  27. if (rangeOperators.has(valueNode.value)) return;
  28. if (nameNode == null && isRangeContextName(valueNode.value)) {
  29. nameNode = valueNode;
  30. return;
  31. }
  32. valueNodes.push(valueNode);
  33. });
  34. assert(nameNode);
  35. return {
  36. name: {
  37. value: nameNode.value,
  38. sourceIndex: node.sourceIndex + nameNode.sourceIndex,
  39. },
  40. values: valueNodes.map((valueNode) => ({
  41. value: valueNode.value,
  42. sourceIndex: node.sourceIndex + valueNode.sourceIndex,
  43. })),
  44. };
  45. };