diff --git a/Gemfile.lock b/Gemfile.lock index 5c3ccc3..b2f2894 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,28 +3,59 @@ PATH specs: easol-canvas (2.2.0) cli-ui (~> 1.5) + dartsass-rails (~> 0.4.0) json-schema (~> 3) liquid (~> 5.3) nokogiri (~> 1.13) - sassc (~> 2.4) thor (~> 1.2) GEM remote: https://rubygems.org/ specs: + actionpack (7.0.3.1) + actionview (= 7.0.3.1) + activesupport (= 7.0.3.1) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actionview (7.0.3.1) + activesupport (= 7.0.3.1) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activesupport (7.0.3.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) ast (2.4.2) + builder (3.2.4) cli-ui (1.5.1) coderay (1.1.3) + concurrent-ruby (1.1.10) + crass (1.0.6) + dartsass-rails (0.4.0) + railties (>= 6.0.0) diff-lcs (1.5.0) - ffi (1.15.5) + erubi (1.11.0) + i18n (1.12.0) + concurrent-ruby (~> 1.0) json-schema (3.0.0) addressable (>= 2.8) liquid (5.4.0) + loofah (2.18.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) method_source (1.0.0) + minitest (5.16.3) nokogiri (1.13.8-arm64-darwin) racc (~> 1.4) + nokogiri (1.13.8-x86_64-linux) + racc (~> 1.4) parallel (1.21.0) parser (3.0.3.2) ast (~> 2.4.1) @@ -33,7 +64,23 @@ GEM method_source (~> 1.0) public_suffix (4.0.7) racc (1.6.0) + rack (2.2.4) + rack-test (2.0.2) + rack (>= 1.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.3) + loofah (~> 2.3) + railties (7.0.3.1) + actionpack (= 7.0.3.1) + activesupport (= 7.0.3.1) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) rainbow (3.0.0) + rake (13.0.6) regexp_parser (2.2.0) rexml (3.2.5) rspec (3.10.0) @@ -64,17 +111,19 @@ GEM rubocop (>= 1.7.0, < 2.0) rubocop-ast (>= 0.4.0) ruby-progressbar (1.11.0) - sassc (2.4.0) - ffi (~> 1.9) standard (1.5.0) rubocop (= 1.23.0) rubocop-performance (= 1.12.0) thor (1.2.1) + tzinfo (2.0.5) + concurrent-ruby (~> 1.0) unicode-display_width (2.1.0) + zeitwerk (2.6.0) PLATFORMS arm64-darwin-20 arm64-darwin-21 + x86_64-linux DEPENDENCIES easol-canvas! diff --git a/canvas.gemspec b/canvas.gemspec index 559b72c..d73400f 100644 --- a/canvas.gemspec +++ b/canvas.gemspec @@ -22,6 +22,6 @@ Gem::Specification.new do |s| s.add_dependency "nokogiri", "~> 1.13" s.add_dependency "cli-ui", "~> 1.5" s.add_dependency "liquid", "~> 5.3" - s.add_dependency "sassc", "~> 2.4" + s.add_dependency "dartsass-rails", "~> 0.4.0" s.add_dependency "json-schema", "~> 3" end diff --git a/lib/canvas/dartsass.rb b/lib/canvas/dartsass.rb new file mode 100644 index 0000000..96370b8 --- /dev/null +++ b/lib/canvas/dartsass.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require "open3" + +module Canvas + # This is a thin wrapper around the dartsass binary as provided by + # dartsass-rails. + # + # It is compatible with SassC::Engine as much as we were using it, but 100% + # compatability is not a goal. + class DartSass + Error = Class.new(StandardError) + + def initialize(css, config) + @css = css + @config = config + end + + def render + stdout, stderr, status = Open3.capture3(*command, stdin_data: @css) + + if status == 0 + stdout + else + raise Error.new(stderr) + end + end + + private + + def command + [dartsass, "--stdin", style, *load_paths].compact + end + + def dartsass + Gem.bin_path("dartsass-rails", "dartsass").shellescape + end + + def style + (s = @config[:style]) && "--style=#{s.to_s.shellescape}" + end + + def load_paths + Array(@config[:load_paths]).map { "--load-path=#{_1.shellescape}" } + end + end +end diff --git a/lib/canvas/validators/sass.rb b/lib/canvas/validators/sass.rb index 24e67c0..28d8921 100644 --- a/lib/canvas/validators/sass.rb +++ b/lib/canvas/validators/sass.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require "sassc" +require "canvas/dartsass" module Canvas module Validator @@ -15,9 +15,9 @@ def initialize(file) end def validate - SassC::Engine.new(@file, style: :compressed).render + DartSass.new(@file, style: :compressed).render true - rescue SassC::SyntaxError => e + rescue DartSass::Error => e @errors = [e.message] false end diff --git a/spec/lib/canvas/checks/valid_sass_check_spec.rb b/spec/lib/canvas/checks/valid_sass_check_spec.rb index 03b4951..2cce447 100644 --- a/spec/lib/canvas/checks/valid_sass_check_spec.rb +++ b/spec/lib/canvas/checks/valid_sass_check_spec.rb @@ -15,16 +15,15 @@ it "adds an offense when a file contains invalid Sass" do copy_example_directory("alchemist") subject.run - message = <<~MESSAGE.chop - Invalid Sass: assets/index.css - \n - Error: Undefined variable: "$gray-100". - on line 1:13 of stdin - >> h1 { color: $gray-100 } - MESSAGE expect(subject.offenses).to match_array( [ - have_attributes(message: include(message.squeeze("\n"))) + have_attributes( + message: include("Invalid Sass: assets/index.css") & + include("Error: Undefined variable") & + include("1:13") & + include("h1 { color: $gray-100 }") + ) ] ) end