From 933d2798113c2a54264cf927fc8eabe660bfd17a Mon Sep 17 00:00:00 2001 From: David Taylor Date: Mon, 29 Jul 2019 10:28:24 +0100 Subject: [PATCH] FIX: Support multi-file stylesheets in theme components (#7950) --- lib/stylesheet/importer.rb | 37 ++++++++++++--------- spec/components/stylesheet/importer_spec.rb | 16 +++++++++ 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/lib/stylesheet/importer.rb b/lib/stylesheet/importer.rb index 473bec80a74..728731e3c59 100644 --- a/lib/stylesheet/importer.rb +++ b/lib/stylesheet/importer.rb @@ -16,7 +16,7 @@ module Stylesheet end register_import "theme_field" do - Import.new("#{theme_dir}/theme_field.scss", source: @theme_field) + Import.new("#{theme_dir(@theme_id)}/theme_field.scss", source: @theme_field) end register_import "plugins" do @@ -101,6 +101,7 @@ module Stylesheet # make up an id so other stuff does not bail out @theme_id = @theme.id || -1 end + @importable_theme_fields = {} end def import_files(files) @@ -140,15 +141,19 @@ module Stylesheet @theme == :nil ? nil : @theme end - def theme_dir - "theme_#{theme.id}" + def theme_dir(import_theme_id) + "theme_#{import_theme_id}" end - def importable_theme_fields - return {} unless theme - @importable_theme_fields ||= begin + def extract_theme_id(path) + path[/^theme_([0-9]+)\//, 1] + end + + def importable_theme_fields(import_theme_id) + return {} unless theme && import_theme = Theme.find(import_theme_id) + @importable_theme_fields[import_theme_id] ||= begin hash = {} - @theme.theme_fields.where(target_id: Theme.targets[:extra_scss]).each do |field| + import_theme.theme_fields.where(target_id: Theme.targets[:extra_scss]).each do |field| hash[field.name] = field.value end hash @@ -156,18 +161,18 @@ module Stylesheet end def match_theme_import(path, parent_path) - # Only allow importing theme stylesheets from within other theme stylesheets - return false unless theme && parent_path.start_with?("#{theme_dir}/") + # Only allow importing theme stylesheets from within stylesheets in the same theme + return false unless theme && import_theme_id = extract_theme_id(parent_path) # Could be a child theme parent_dir, _ = File.split(parent_path) # Could be relative to the importing file, or relative to the root of the theme directory - search_paths = [parent_dir, theme_dir].uniq + search_paths = [parent_dir, theme_dir(import_theme_id)].uniq search_paths.each do |search_path| resolved = Pathname.new("#{search_path}/#{path}").cleanpath.to_s # Remove unnecessary ./ and ../ - next unless resolved.start_with?("#{theme_dir}/") - resolved.sub!("#{theme_dir}/", "") - if importable_theme_fields.keys.include?(resolved) - return resolved + next unless resolved.start_with?("#{theme_dir(import_theme_id)}/") + resolved_within_theme = resolved.sub(/^theme_[0-9]+\//, "") + if importable_theme_fields(import_theme_id).keys.include?(resolved_within_theme) + return resolved, importable_theme_fields(import_theme_id)[resolved_within_theme] end end false @@ -189,8 +194,8 @@ module Stylesheet end elsif callback = Importer.special_imports[asset] instance_eval(&callback) - elsif resolved = match_theme_import(asset, parent_path) - Import.new("#{theme_dir}/#{resolved}", source: importable_theme_fields[resolved]) + elsif (path, source = match_theme_import(asset, parent_path)) + Import.new(path, source: source) else Import.new(asset + ".scss") end diff --git a/spec/components/stylesheet/importer_spec.rb b/spec/components/stylesheet/importer_spec.rb index 8f0d8b5a4a8..f143bd0b396 100644 --- a/spec/components/stylesheet/importer_spec.rb +++ b/spec/components/stylesheet/importer_spec.rb @@ -63,11 +63,20 @@ describe Stylesheet::Importer do context "extra_scss" do let(:scss) { "body { background: red}" } + let(:child_scss) { "body { background: green}" } + let(:theme) { Fabricate(:theme).tap { |t| t.set_field(target: :extra_scss, name: "my_files/magic", value: scss) t.save! }} + let(:child_theme) { Fabricate(:theme).tap { |t| + t.component = true + t.set_field(target: :extra_scss, name: "my_files/moremagic", value: child_scss) + t.save! + theme.add_child_theme!(t) + }} + let(:importer) { described_class.new(theme: theme) } it "should be able to import correctly" do @@ -105,6 +114,13 @@ describe Stylesheet::Importer do "./magic", "theme_#{theme.id}/my_files/myfile.scss" ).source).to eq(scss) + + # Import within a child theme + expect( + importer.imports( + "my_files/moremagic", + "theme_#{child_theme.id}/theme_field.scss" + ).source).to eq(child_scss) end end