<commit_before>const { hasOwnProperty } = Object.prototype;
const shape = {
    generic: true,
    types: appendOrAssign,
    atrules: {
        prelude: appendOrAssignOrNull,
        descriptors: appendOrAssignOrNull
    },
    properties: appendOrAssign,
    parseContext: assign,
    scope: deepAssign,
    atrule: ['parse'],
    pseudo: ['parse'],
    node: ['name', 'structure', 'parse', 'generate', 'walkContext']
};

function isObject(value) {
    return value && value.constructor === Object;
}

function copy(value) {
    return isObject(value)
        ? { ...value }
        : value;
}

function assign(dest, src) {
    return Object.assign(dest, src);
}

function deepAssign(dest, src) {
    for (const key in src) {
        if (hasOwnProperty.call(src, key)) {
            if (isObject(dest[key])) {
                deepAssign(dest[key], src[key]);
            } else {
                dest[key] = copy(src[key]);
            }
        }
    }

    return dest;
}

function append(a, b) {
    if (typeof b === 'string' && /^\s*\|/.test(b)) {
        return typeof a === 'string'
            ? a + b
            : b.replace(/^\s*\|\s*/, '');
    }

    return b || null;
}

function appendOrAssign(a, b) {
    if (typeof b === 'string') {
        return append(a, b);
    }

    const result = { ...a };
    for (let key in b) {
        if (hasOwnProperty.call(b, key)) {
            result[key] = append(hasOwnProperty.call(a, key) ? a[key] : undefined, b[key]);
        }
    }

    return result;
}

function appendOrAssignOrNull(a, b) {
    const result = appendOrAssign(a, b);

    return !isObject(result) || Object.keys(result).length
        ? result
        : null;
}

function mix(dest, src, shape) {
    for (const key in shape) {
        if (hasOwnProperty.call(shape, key) === false) {
            continue;
        }

        if (shape[key] === true) {
            if (hasOwnProperty.call(src, key)) {
                dest[key] = copy(src[key]);
            }
        } else if (shape[key]) {
            if (typeof shape[key] === 'function') {
                const fn = shape[key];
                dest[key] = fn({}, dest[key]);
                dest[key] = fn(dest[key] || {}, src[key]);
            } else if (isObject(shape[key])) {
                const result = {};

                for (let name in dest[key]) {
                    result[name] = mix({}, dest[key][name], shape[key]);
                }

                for (let name in src[key]) {
                    result[name] = mix(result[name] || {}, src[key][name], shape[key]);
                }

                dest[key] = result;
            } else if (Array.isArray(shape[key])) {
                const res = {};
                const innerShape = shape[key].reduce(function(s, k) {
                    s[k] = true;
                    return s;
                }, {});

                for (const [name, value] of Object.entries(dest[key] || {})) {
                    res[name] = {};
                    if (value) {
                        mix(res[name], value, innerShape);
                    }
                }

                for (const name in src[key]) {
                    if (hasOwnProperty.call(src[key], name)) {
                        if (!res[name]) {
                            res[name] = {};
                        }

                        if (src[key] && src[key][name]) {
                            mix(res[name], src[key][name], innerShape);
                        }
                    }
                }

                dest[key] = res;
            }
        }
    }
    return dest;
}

export default (dest, src) => mix(dest, src, shape);<commit_msg>Internal refactoring: rework config mixing<commit_after>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;
}

export default 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 '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, syntax] of Object.entries(value)) {
                    result[prop][name] = { ...result[prop][name], ...syntax };
                }
                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;
}
{'fraction_non_alphanumeric': 0.14027405000706314, 'fraction_numerical': 0.0, 'mean_word_length': 1.241215574548908, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7187001', 'n_tokens_mistral': 1975, 'n_tokens_neox': 1876, 'n_words': 415}