diff --git a/lib/importmap/packager.rb b/lib/importmap/packager.rb index 76f0661..32e642e 100644 --- a/lib/importmap/packager.rb +++ b/lib/importmap/packager.rb @@ -39,16 +39,17 @@ def pin_for(package, url) def vendored_pin_for(package, url) filename = package_filename(package) version = extract_package_version_from(url) + line_formatted_pin_options = + pin_options_for_package(package). + tap { |options| "#{package}.js" == filename ? options.delete("to") : options["to"] = filename }. + map { |option, value| %(#{option}: #{value.is_a?(String) ? %("#{value}") : value}) } + pin_components = [%(pin "#{package}"), *line_formatted_pin_options] - if "#{package}.js" == filename - %(pin "#{package}" # #{version}) - else - %(pin "#{package}", to: "#{filename}" # #{version}) - end + %(#{pin_components.join(", ")} # #{version}) end def packaged?(package) - importmap.match(/^pin ["']#{package}["'].*$/) + package_line_in_importmap(package).present? end def download(package, url) @@ -62,6 +63,19 @@ def remove(package) remove_package_from_importmap(package) end + def pin_options_for_package(package) + line = package_line_in_importmap(package) || "" + raw_options = line.match(/^#{base_package_line_regex(package)}?,[\s+]?(?.*) #.*$/) + + return {} if raw_options.blank? + + raw_options[:pin_options].split(/,\s?/).each_with_object({}) do |option, hash| + match_data = option.match(/^(?[^:]*):[\s+]?["']?(?.*[^"'])["']?$/) + + hash[match_data[:option_name]] = cast_option_value(match_data[:option_value]) + end + end + private def post_json(body) Net::HTTP.post(self.class.endpoint, body.to_json, "Content-Type" => "application/json") @@ -146,4 +160,19 @@ def package_filename(package) def extract_package_version_from(url) url.match(/@\d+\.\d+\.\d+/)&.to_a&.first end + + def package_line_in_importmap(package) + importmap.match(/^#{base_package_line_regex(package)}.*$/).try(:[], 0) + end + + def base_package_line_regex(package) + /pin ["']#{package}["']/ + end + + def cast_option_value(object) + return true if object == "true" + return false if object == "false" + + object + end end diff --git a/test/fixtures/files/pins_with_various_options_importmap.rb b/test/fixtures/files/pins_with_various_options_importmap.rb new file mode 100644 index 0000000..1285857 --- /dev/null +++ b/test/fixtures/files/pins_with_various_options_importmap.rb @@ -0,0 +1,8 @@ +pin_all_from "app/assets/javascripts" + +pin "md5", to: "https://cdn.skypack.dev/md5", preload: true # 1.0.2 +pin "not_there", to: "nowhere.js", preload: false # 1.9.1 +pin "some_file" # 0.2.1 +pin "another_file",to:'another_file.js' # @0.0.16 +pin "random", random_option: "foobar", hello: "world" # 7.7.7 +pin "javascript/typescript", preload: true, to: "https://cdn.skypack.dev/typescript" # 0.0.0 diff --git a/test/packager_test.rb b/test/packager_test.rb index 29ce7f6..baced4d 100644 --- a/test/packager_test.rb +++ b/test/packager_test.rb @@ -3,7 +3,7 @@ require "minitest/mock" class Importmap::PackagerTest < ActiveSupport::TestCase - setup { @packager = Importmap::Packager.new(Rails.root.join("config/importmap.rb")) } + setup { @packager = Importmap::Packager.new(Rails.root.join("../fixtures/files/pins_with_various_options_importmap.rb")) } test "successful import with mock" do response = Class.new do @@ -54,5 +54,15 @@ def code() "200" end test "vendored_pin_for" do assert_equal %(pin "react" # @17.0.2), @packager.vendored_pin_for("react", "https://cdn/react@17.0.2") assert_equal %(pin "javascript/react", to: "javascript--react.js" # @17.0.2), @packager.vendored_pin_for("javascript/react", "https://cdn/react@17.0.2") + assert_equal %(pin "md5", preload: true # @2.1.3), @packager.vendored_pin_for("md5", "https://cdn/md5@2.1.3") + assert_equal %(pin "random", random_option: "foobar", hello: "world" # @8.8.8), @packager.vendored_pin_for("random", "https://cdn/random@8.8.8") + assert_equal %(pin "javascript/typescript", preload: true, to: "javascript--typescript.js" # @0.0.1), @packager.vendored_pin_for("javascript/typescript", "https://cdn/typescript@0.0.1") + end + + test "pin_options_for_package" do + assert_equal ({ "to" => "https://cdn.skypack.dev/md5", "preload" => true }), @packager.pin_options_for_package('md5') + assert_equal ({ "to" => "nowhere.js", "preload" => false }), @packager.pin_options_for_package('not_there') + assert_equal ({ }), @packager.pin_options_for_package('some_file') + assert_equal ({ "to" => "another_file.js" }), @packager.pin_options_for_package('another_file') end end