envygeeks/jekyll-assets

View on GitHub
lib/jekyll/assets/plugins/alternates.rb

Summary

Maintainability
A
2 hrs
Test Coverage
# Frozen-string-literal: true
# Copyright: 2012 - 2020 - ISC License
# Author: Jordon Bedwell
# Encoding: utf-8

if Jekyll::Assets::Utils.activate("crass")
  module Jekyll
    module Assets
      module Plugins
        NODER = %r!/\*\! @alternate \*/!.freeze
        RTEST = %r!#{Regexp.union(%w(-ms- -webkit- -moz- -o-).freeze)}!.freeze
        NODE1 = { node: :whitespace, pos: 28, raw: ' ' }.freeze
        NODE2 = {
          raw: '/*! @alternate */',
          pos: 0, # It's ignored. @see Crass::Parser.stringify
          value: '! @alternate ',
          node: :comment
        }.freeze

        NODE3 = {
          value: '@alternate ',
          raw: '/* @alternate */',
          node: :comment,
          pos: 0
        }.freeze

        class Alternates
          def call(input)
            comp = input[:environment].asset_config[:compression]
            data = Crass.parse(input[:data] || "", preserve_comments: true)
            data.each do |v|
              next unless v[:node] == :style_rule
              v[:children] = v[:children].each_with_object([]) do |c, a|
                if alternate?(c)
                  a << (comp ? NODE2 : NODE3)
                  a << NODE1
                end

                a << c
              end
            end

            {
              data: Crass::Parser.stringify(data, {
                preserve_comments: true,
              }),
            }
          end

          private
          def alternate?(c)
            c[:node] == :property && (
              c[:name] =~ RTEST || c[:value] =~ RTEST
            )
          end
        end

        # --
        # When compression is enabled we need to make sure to
        # run an extra step, because when compression is being
        # ran, we have to guard with /*! so we've to strip.
        # --
        Hook.register :asset, :after_compression do |_, o, t|
          next o unless t == "text/css"
          o.gsub(NODER,
            " #{NODE3[:raw]} "
          )
        end

        # --
        Hook.register :env, :after_init, priority: 2 do
          register_bundle_processor "text/css",
            Alternates.new
        end
      end
    end
  end
end