mix.cjs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. 'use strict';
  2. function appendOrSet(a, b) {
  3. if (typeof b === 'string' && /^\s*\|/.test(b)) {
  4. return typeof a === 'string'
  5. ? a + b
  6. : b.replace(/^\s*\|\s*/, '');
  7. }
  8. return b || null;
  9. }
  10. function sliceProps(obj, props) {
  11. const result = Object.create(null);
  12. for (const [key, value] of Object.entries(obj)) {
  13. if (value) {
  14. result[key] = {};
  15. for (const prop of Object.keys(value)) {
  16. if (props.includes(prop)) {
  17. result[key][prop] = value[prop];
  18. }
  19. }
  20. }
  21. }
  22. return result;
  23. }
  24. function mix(dest, src) {
  25. const result = { ...dest };
  26. for (const [prop, value] of Object.entries(src)) {
  27. switch (prop) {
  28. case 'generic':
  29. result[prop] = Boolean(value);
  30. break;
  31. case 'cssWideKeywords':
  32. result[prop] = dest[prop]
  33. ? [...dest[prop], ...value]
  34. : value || [];
  35. break;
  36. case 'units':
  37. result[prop] = { ...dest[prop] };
  38. for (const [name, patch] of Object.entries(value)) {
  39. result[prop][name] = Array.isArray(patch) ? patch : [];
  40. }
  41. break;
  42. case 'atrules':
  43. result[prop] = { ...dest[prop] };
  44. for (const [name, atrule] of Object.entries(value)) {
  45. const exists = result[prop][name] || {};
  46. const current = result[prop][name] = {
  47. prelude: exists.prelude || null,
  48. descriptors: {
  49. ...exists.descriptors
  50. }
  51. };
  52. if (!atrule) {
  53. continue;
  54. }
  55. current.prelude = atrule.prelude
  56. ? appendOrSet(current.prelude, atrule.prelude)
  57. : current.prelude || null;
  58. for (const [descriptorName, descriptorValue] of Object.entries(atrule.descriptors || {})) {
  59. current.descriptors[descriptorName] = descriptorValue
  60. ? appendOrSet(current.descriptors[descriptorName], descriptorValue)
  61. : null;
  62. }
  63. if (!Object.keys(current.descriptors).length) {
  64. current.descriptors = null;
  65. }
  66. }
  67. break;
  68. case 'types':
  69. case 'properties':
  70. result[prop] = { ...dest[prop] };
  71. for (const [name, syntax] of Object.entries(value)) {
  72. result[prop][name] = appendOrSet(result[prop][name], syntax);
  73. }
  74. break;
  75. case 'scope':
  76. case 'features':
  77. result[prop] = { ...dest[prop] };
  78. for (const [name, props] of Object.entries(value)) {
  79. result[prop][name] = { ...result[prop][name], ...props };
  80. }
  81. break;
  82. case 'parseContext':
  83. result[prop] = {
  84. ...dest[prop],
  85. ...value
  86. };
  87. break;
  88. case 'atrule':
  89. case 'pseudo':
  90. result[prop] = {
  91. ...dest[prop],
  92. ...sliceProps(value, ['parse'])
  93. };
  94. break;
  95. case 'node':
  96. result[prop] = {
  97. ...dest[prop],
  98. ...sliceProps(value, ['name', 'structure', 'parse', 'generate', 'walkContext'])
  99. };
  100. break;
  101. }
  102. }
  103. return result;
  104. }
  105. module.exports = mix;