src/lib.js
function filterKeyframes(css, unusedRules) {
    const usedAnimations = [];
    css.walkDecls((decl) => {
        if (_.endsWith(decl.prop, 'animation-name')) {
            /* Multiple animations, separated by comma */
            usedAnimations.push(...postcss.list.comma(decl.value));
        } else if (_.endsWith(decl.prop, 'animation')) {
            /* Support multiple animations */
            postcss.list.comma(decl.value).forEach((anim) => {
                /* If declared as animation, name can be anywhere in the string; so we include all the properties */
                usedAnimations.push(...postcss.list.space(anim));
            });
        }
    });
    const usedAnimationsSet = new Set(usedAnimations);
    css.walkAtRules(/keyframes$/, (atRule) => {
        if (!usedAnimationsSet.has(atRule.params)) {
            unusedRules.push(atRule);
            atRule.remove();
        }
    });
}
function filterKeyframes(css, unusedRules) {
    const usedAnimations = [];
    css.walkDecls((decl) => {
        if (_.endsWith(decl.prop, 'animation-name')) {
            /* Multiple animations, separated by comma */
            usedAnimations.push(...postcss.list.comma(decl.value));
        } else if (_.endsWith(decl.prop, 'animation')) {
            /* Support multiple animations */
            postcss.list.comma(decl.value).forEach((anim) => {
                /* If declared as animation, name can be anywhere in the string; so we include all the properties */
                usedAnimations.push(...postcss.list.space(anim));
            });
        }
    });
    const usedAnimationsSet = new Set(usedAnimations);
    css.walkAtRules(/keyframes$/, (atRule) => {
        if (!usedAnimationsSet.has(atRule.params)) {
            unusedRules.push(atRule);
            atRule.remove();
        }
    });
}
Filter @keyframes that are not used
@param  {Object} css             The postcss.Root node
@param  {Array}  animations
@param  {Array}  unusedRules
@return {Array}