133 lines
3.2 KiB
Ruby
133 lines
3.2 KiB
Ruby
|
# frozen_string_literal: true
|
||
|
|
||
|
require "sass"
|
||
|
require "jekyll/utils"
|
||
|
|
||
|
module Jekyll
|
||
|
module Converters
|
||
|
class Scss < Converter
|
||
|
BYTE_ORDER_MARK = %r!^\xEF\xBB\xBF!
|
||
|
SyntaxError = Class.new(ArgumentError)
|
||
|
|
||
|
safe true
|
||
|
priority :low
|
||
|
|
||
|
ALLOWED_STYLES = %w(nested expanded compact compressed).freeze
|
||
|
|
||
|
def matches(ext)
|
||
|
ext =~ %r!^\.scss$!i
|
||
|
end
|
||
|
|
||
|
def output_ext(_ext)
|
||
|
".css"
|
||
|
end
|
||
|
|
||
|
def safe?
|
||
|
!!@config["safe"]
|
||
|
end
|
||
|
|
||
|
def jekyll_sass_configuration
|
||
|
options = @config["sass"] || {}
|
||
|
unless options["style"].nil?
|
||
|
options["style"] = options["style"].to_s.gsub(%r!\A:!, "").to_sym
|
||
|
end
|
||
|
options
|
||
|
end
|
||
|
|
||
|
def sass_build_configuration_options(overrides)
|
||
|
if safe?
|
||
|
{
|
||
|
:load_paths => sass_load_paths,
|
||
|
:syntax => syntax,
|
||
|
:style => sass_style,
|
||
|
:cache => false,
|
||
|
}
|
||
|
else
|
||
|
Jekyll::Utils.symbolize_hash_keys(
|
||
|
Jekyll::Utils.deep_merge_hashes(
|
||
|
jekyll_sass_configuration,
|
||
|
overrides
|
||
|
)
|
||
|
)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def syntax
|
||
|
:scss
|
||
|
end
|
||
|
|
||
|
def sass_dir
|
||
|
return "_sass" if jekyll_sass_configuration["sass_dir"].to_s.empty?
|
||
|
jekyll_sass_configuration["sass_dir"]
|
||
|
end
|
||
|
|
||
|
def sass_style
|
||
|
style = jekyll_sass_configuration.fetch("style", :compact)
|
||
|
ALLOWED_STYLES.include?(style.to_s) ? style.to_sym : :compact
|
||
|
end
|
||
|
|
||
|
def user_sass_load_paths
|
||
|
Array(jekyll_sass_configuration["load_paths"])
|
||
|
end
|
||
|
|
||
|
def sass_dir_relative_to_site_source
|
||
|
Jekyll.sanitized_path(site_source, sass_dir)
|
||
|
end
|
||
|
|
||
|
def sass_load_paths
|
||
|
paths = user_sass_load_paths + [sass_dir_relative_to_site_source]
|
||
|
|
||
|
if safe?
|
||
|
# Sanitize paths to prevent any attack vectors (.e.g. `/**/*`)
|
||
|
paths.map! { |path| Jekyll.sanitized_path(site_source, path) }
|
||
|
end
|
||
|
|
||
|
# Expand file globs (e.g. `node_modules/*/node_modules` )
|
||
|
Dir.chdir(site_source) do
|
||
|
paths = paths.map { |path| Dir.glob(path) }.flatten.uniq
|
||
|
|
||
|
paths.map! do |path|
|
||
|
if safe?
|
||
|
# Sanitize again in case globbing was able to do something crazy.
|
||
|
Jekyll.sanitized_path(site_source, path)
|
||
|
else
|
||
|
File.expand_path(path)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
paths.select { |path| File.directory?(path) }
|
||
|
end
|
||
|
|
||
|
def allow_caching?
|
||
|
!safe?
|
||
|
end
|
||
|
|
||
|
def add_charset?
|
||
|
!!jekyll_sass_configuration["add_charset"]
|
||
|
end
|
||
|
|
||
|
def sass_configs
|
||
|
sass_build_configuration_options({
|
||
|
"syntax" => syntax,
|
||
|
"cache" => allow_caching?,
|
||
|
"load_paths" => sass_load_paths,
|
||
|
})
|
||
|
end
|
||
|
|
||
|
def convert(content)
|
||
|
output = ::Sass.compile(content, sass_configs)
|
||
|
replacement = add_charset? ? '@charset "UTF-8";' : ""
|
||
|
output.sub(BYTE_ORDER_MARK, replacement)
|
||
|
rescue ::Sass::SyntaxError => e
|
||
|
raise SyntaxError, "#{e} on line #{e.sass_line}"
|
||
|
end
|
||
|
|
||
|
private
|
||
|
def site_source
|
||
|
@site_source ||= File.expand_path(@config["source"]).freeze
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|