index.es.mjs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import postcss from 'postcss';
  2. import valueParser from 'postcss-values-parser';
  3. // return whether a node is a valid comma
  4. var getComma = (node => Object(node).type === 'comma');
  5. const imageSetFunctionMatchRegExp = /^(-webkit-)?image-set$/i; // return a valid image
  6. var getImage = (node => // <url> | <image()> | <cross-fade()> | <gradient>
  7. // the image-set() function can not be nested inside of itself
  8. Object(node).type === 'func' && /^(cross-fade|image|(repeating-)?(conic|linear|radial)-gradient|url)$/i.test(node.value) && !(node.parent.parent && node.parent.parent.type === 'func' && imageSetFunctionMatchRegExp.test(node.parent.parent.value)) ? String(node) : Object(node).type === 'string' ? node.value : false);
  9. const dpiRatios = {
  10. dpcm: 2.54,
  11. dpi: 1,
  12. dppx: 96,
  13. x: 96
  14. }; // return a valid @media rule
  15. var getMedia = ((node, mediasByDpr) => {
  16. if (Object(node).type === 'number' && node.unit in dpiRatios) {
  17. // calculate min-device-pixel-ratio and min-resolution
  18. const dpi = Number(node.value) * dpiRatios[node.unit.toLowerCase()];
  19. const dpr = Math.floor(dpi / dpiRatios.x * 100) / 100;
  20. if (dpi in mediasByDpr) {
  21. return false;
  22. } else {
  23. const media = mediasByDpr[dpi] = postcss.atRule({
  24. name: 'media',
  25. params: `(-webkit-min-device-pixel-ratio: ${dpr}), (min-resolution: ${dpi}dpi)`
  26. });
  27. return media;
  28. }
  29. } else {
  30. return false;
  31. }
  32. });
  33. var handleInvalidation = ((opts, message, word) => {
  34. if (opts.oninvalid === 'warn') {
  35. opts.decl.warn(opts.result, message, {
  36. word: String(word)
  37. });
  38. } else if (opts.oninvalid === 'throw') {
  39. throw opts.decl.error(message, {
  40. word: String(word)
  41. });
  42. }
  43. });
  44. var processImageSet = ((imageSetOptionNodes, decl, opts) => {
  45. const parent = decl.parent;
  46. const mediasByDpr = {};
  47. let length = imageSetOptionNodes.length;
  48. let index = -1;
  49. while (index < length) {
  50. const _ref = [index < 0 ? true : getComma(imageSetOptionNodes[index]), getImage(imageSetOptionNodes[index + 1]), getMedia(imageSetOptionNodes[index + 2], mediasByDpr)],
  51. comma = _ref[0],
  52. value = _ref[1],
  53. media = _ref[2]; // handle invalidations
  54. if (!comma) {
  55. return handleInvalidation(opts, 'unexpected comma', imageSetOptionNodes[index]);
  56. } else if (!value) {
  57. return handleInvalidation(opts, 'unexpected image', imageSetOptionNodes[index + 1]);
  58. } else if (!media) {
  59. return handleInvalidation(opts, 'unexpected resolution', imageSetOptionNodes[index + 2]);
  60. } // prepare @media { decl: <image> }
  61. const parentClone = parent.clone().removeAll();
  62. const declClone = decl.clone({
  63. value
  64. });
  65. parentClone.append(declClone);
  66. media.append(parentClone);
  67. index += 3;
  68. }
  69. const medias = Object.keys(mediasByDpr).sort((a, b) => a - b).map(params => mediasByDpr[params]); // conditionally prepend previous siblings
  70. if (medias.length) {
  71. const firstDecl = medias[0].nodes[0].nodes[0];
  72. if (medias.length === 1) {
  73. decl.value = firstDecl.value;
  74. } else {
  75. const siblings = parent.nodes;
  76. const previousSiblings = siblings.slice(0, siblings.indexOf(decl)).concat(firstDecl);
  77. if (previousSiblings.length) {
  78. const parentClone = parent.cloneBefore().removeAll();
  79. parentClone.append(previousSiblings);
  80. } // prepend any @media { decl: <image> } rules
  81. parent.before(medias.slice(1)); // conditionally remove the current rule
  82. if (!opts.preserve) {
  83. decl.remove(); // and then conditionally remove its parent
  84. if (!parent.nodes.length) {
  85. parent.remove();
  86. }
  87. }
  88. }
  89. }
  90. });
  91. const imageSetValueMatchRegExp = /(^|[^\w-])(-webkit-)?image-set\(/;
  92. const imageSetFunctionMatchRegExp$1 = /^(-webkit-)?image-set$/i;
  93. var index = postcss.plugin('postcss-image-set-function', opts => {
  94. // prepare options
  95. const preserve = 'preserve' in Object(opts) ? Boolean(opts.preserve) : true;
  96. const oninvalid = 'oninvalid' in Object(opts) ? opts.oninvalid : 'ignore';
  97. return (root, result) => {
  98. // for every declaration
  99. root.walkDecls(decl => {
  100. const value = decl.value; // if a declaration likely uses an image-set() function
  101. if (imageSetValueMatchRegExp.test(value)) {
  102. const valueAST = valueParser(value).parse(); // process every image-set() function
  103. valueAST.walkType('func', node => {
  104. if (imageSetFunctionMatchRegExp$1.test(node.value)) {
  105. processImageSet(node.nodes.slice(1, -1), decl, {
  106. decl,
  107. oninvalid,
  108. preserve,
  109. result
  110. });
  111. }
  112. });
  113. }
  114. });
  115. };
  116. });
  117. export default index;
  118. //# sourceMappingURL=index.es.mjs.map