| 'use strict'; |
| |
| function appendOrSet(a, b) { |
| if (typeof b === 'string' && /^\s*\|/.test(b)) { |
| return typeof a === 'string' |
| ? a + b |
| : b.replace(/^\s*\|\s*/, ''); |
| } |
| |
| return b || null; |
| } |
| |
| function sliceProps(obj, props) { |
| const result = Object.create(null); |
| |
| for (const [key, value] of Object.entries(obj)) { |
| if (value) { |
| result[key] = {}; |
| for (const prop of Object.keys(value)) { |
| if (props.includes(prop)) { |
| result[key][prop] = value[prop]; |
| } |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| function mix(dest, src) { |
| const result = { ...dest }; |
| |
| for (const [prop, value] of Object.entries(src)) { |
| switch (prop) { |
| case 'generic': |
| result[prop] = Boolean(value); |
| break; |
| |
| case 'units': |
| result[prop] = { ...dest[prop] }; |
| for (const [name, patch] of Object.entries(value)) { |
| result[prop][name] = Array.isArray(patch) ? patch : []; |
| } |
| break; |
| |
| case 'atrules': |
| result[prop] = { ...dest[prop] }; |
| |
| for (const [name, atrule] of Object.entries(value)) { |
| const exists = result[prop][name] || {}; |
| const current = result[prop][name] = { |
| prelude: exists.prelude || null, |
| descriptors: { |
| ...exists.descriptors |
| } |
| }; |
| |
| if (!atrule) { |
| continue; |
| } |
| |
| current.prelude = atrule.prelude |
| ? appendOrSet(current.prelude, atrule.prelude) |
| : current.prelude || null; |
| |
| for (const [descriptorName, descriptorValue] of Object.entries(atrule.descriptors || {})) { |
| current.descriptors[descriptorName] = descriptorValue |
| ? appendOrSet(current.descriptors[descriptorName], descriptorValue) |
| : null; |
| } |
| |
| if (!Object.keys(current.descriptors).length) { |
| current.descriptors = null; |
| } |
| } |
| break; |
| |
| case 'types': |
| case 'properties': |
| result[prop] = { ...dest[prop] }; |
| for (const [name, syntax] of Object.entries(value)) { |
| result[prop][name] = appendOrSet(result[prop][name], syntax); |
| } |
| break; |
| |
| case 'scope': |
| result[prop] = { ...dest[prop] }; |
| for (const [name, props] of Object.entries(value)) { |
| result[prop][name] = { ...result[prop][name], ...props }; |
| } |
| break; |
| |
| case 'parseContext': |
| result[prop] = { |
| ...dest[prop], |
| ...value |
| }; |
| break; |
| |
| case 'atrule': |
| case 'pseudo': |
| result[prop] = { |
| ...dest[prop], |
| ...sliceProps(value, ['parse']) }; |
| break; |
| |
| case 'node': |
| result[prop] = { |
| ...dest[prop], |
| ...sliceProps(value, ['name', 'structure', 'parse', 'generate', 'walkContext']) |
| }; |
| break; |
| } |
| } |
| |
| return result; |
| } |
| |
| module.exports = mix; |