From 89822e86d8da3771f5a72c2d33888af76aec9d6e Mon Sep 17 00:00:00 2001
From: Liceth Ovalles <liceova22@gmail.com>
Date: Sun, 20 Nov 2016 16:35:37 -0500
Subject: Add package.json for Yarn if --yarn option is added

---
 railties/lib/rails/generators/app_base.rb          | 52 ++++++++++++++++++++++
 .../rails/generators/rails/app/app_generator.rb    |  7 ++-
 .../generators/rails/app/templates/package.json    |  7 +++
 railties/test/generators/app_generator_test.rb     | 23 ++++++++++
 4 files changed, 88 insertions(+), 1 deletion(-)
 create mode 100644 railties/lib/rails/generators/rails/app/templates/package.json

diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 2951d6c83d..f54604b54d 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -33,6 +33,9 @@ module Rails
         class_option :javascript,         type: :string, aliases: "-j",
                                           desc: "Preconfigure for selected JavaScript library"
 
+        class_option :yarn,               type: :boolean, default: false,
+                                          desc: "Preconfigure for assets management with Yarn"
+
         class_option :skip_gemfile,       type: :boolean, default: false,
                                           desc: "Don't create a Gemfile"
 
@@ -414,6 +417,55 @@ module Rails
         bundle_command("install") if bundle_install?
       end
 
+      def run_yarn
+        if package_json_exist?
+          if yarn_path
+            say_status :run, "yarn install"
+            yarn_command("install")
+          else
+            say_status :warning, "yarn option passed but Yarn executable was not detected in the system.", :yellow
+            say_status :warning, "Download Yarn at https://yarnpkg.com/en/docs/install", :yellow
+          end
+        end
+      end
+
+      def package_json_exist?
+        File.exist?("package.json")
+      end
+
+      def yarn_path
+        commands = ["yarn"]
+
+        if RbConfig::CONFIG["host_os"] =~ /mswin|cygwin/
+          ENV["PATHEXT"].split(File::PATH_SEPARATOR).each do |ext|
+            commands << commands[0] + ext
+          end
+        end
+
+        yarn_path = commands.find do |cmd|
+          paths = ENV["PATH"].split(File::PATH_SEPARATOR)
+
+          path = paths.find do |p|
+            full_path = File.expand_path(cmd, p)
+            File.executable?(full_path) && File.file?(full_path)
+          end
+
+          path && File.expand_path(cmd, path)
+        end
+
+        yarn_path
+      end
+
+      def yarn_command(command)
+        full_command = "#{yarn_path} #{command}"
+
+        if options[:quiet]
+          system(full_command, out: File::NULL)
+        else
+          system(full_command)
+        end
+      end
+
       def generate_spring_binstubs
         if bundle_install? && spring_install?
           bundle_command("exec spring binstub --all")
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index d6ffa2d89d..03fd298fbc 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -53,6 +53,10 @@ module Rails
       template "gitignore", ".gitignore"
     end
 
+    def packagejson
+      template "package.json"
+    end
+
     def app
       directory "app"
 
@@ -205,6 +209,7 @@ module Rails
         build(:readme)
         build(:rakefile)
         build(:configru)
+        build(:packagejson) if options[:yarn]
         build(:gitignore) unless options[:skip_git]
         build(:gemfile)   unless options[:skip_gemfile]
       end
@@ -355,7 +360,7 @@ module Rails
       end
 
       public_task :apply_rails_template, :run_bundle
-      public_task :generate_spring_binstubs
+      public_task :run_yarn, :generate_spring_binstubs
 
       def run_after_bundle_callbacks
         @after_bundle_callbacks.each(&:call)
diff --git a/railties/lib/rails/generators/rails/app/templates/package.json b/railties/lib/rails/generators/rails/app/templates/package.json
new file mode 100644
index 0000000000..78f4a2e6b0
--- /dev/null
+++ b/railties/lib/rails/generators/rails/app/templates/package.json
@@ -0,0 +1,7 @@
+{
+  "name": "<%= app_name %>",
+  "private": true,
+  "dependencies": {
+    "rails-ujs": "rails/rails-ujs"
+  }
+}
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 2d01da7f46..f673058de8 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -494,6 +494,11 @@ class AppGeneratorTest < Rails::Generators::TestCase
     end
   end
 
+  def test_generator_if_yarn_option_is_given
+    run_generator([destination_root, "--yarn"])
+    assert_file "package.json", /dependencies/
+  end
+
   def test_inclusion_of_jbuilder
     run_generator
     assert_gem "jbuilder"
@@ -614,6 +619,10 @@ class AppGeneratorTest < Rails::Generators::TestCase
     assert_generates_with_bundler
   end
 
+  def test_generation_runs_yarn_install_with_yarn_option
+    assert_generates_with_yarn yarn: true
+  end
+
   def test_dev_option
     assert_generates_with_bundler dev: true
     rails_path = File.expand_path("../../..", Rails.root)
@@ -839,4 +848,18 @@ class AppGeneratorTest < Rails::Generators::TestCase
         quietly { generator.invoke_all }
       end
     end
+
+    def assert_generates_with_yarn(options = {})
+      generator([destination_root], options)
+
+      command_check = -> command do
+        @install_called ||= 0
+        @install_called += 1
+        assert_equal 1, @install_called, "install expected to be called once, but was called #{@install_called} times"
+      end
+
+      generator.stub :yarn_command, command_check do
+        quietly { generator.invoke_all }
+      end
+    end
 end
-- 
cgit v1.2.3