lib/svelte_on_rails/installer/npm.rb



module SvelteOnRails
  module Installer
    module Npm

      def self.install_or_update_package(package_name, version_specifier: 'latest', dev_dependency: false)
        pkg = inspect_package(package_name)
        puts "#{package_name} already installed (#{pkg[:version].join('.')}, specified: #{version_specifier})" if pkg
        major_version = version_specifier.to_s.match(/^\d+(?=\.|$)/)

        to_do = if !pkg
                  true
                elsif major_version
                  r = pkg[:version].first != major_version.to_s.to_i
                  if r
                    puts "updating to major version #{major_version}"
                  else
                    puts "nothing to do (major version #{major_version} OK)"
                  end
                  r
                else
                  puts 'nothing to do'
                  false
                end

        save_dev = (dev_dependency ? ' --save-dev' : '')
        if to_do

          cmd = "npm install #{package_name}#{'@' + version_specifier if version_specifier}#{save_dev}"

          stdout, stderr, status = Open3.capture3(cmd)

          puts cmd

          if stderr.present?
            raise "ERROR #{cmd} => #{stderr}"
          end

          notice = [
            (pkg ? "Updated" : "Installed"),
            package_name,
            (pkg ? "from version #{pkg[:version].join('.')}" : nil),
            (pkg ? "to" : nil),
            "@latest"
          ].compact.join(' ')

          puts notice

        else
          puts "#{package_name} already installed (#{pkg[:version].join('.')}, required: «#{version_specifier}»), skipping."
        end
      end

      def self.link_local_package(package_name, local_package_url)
        Dir.chdir(local_package_url) do
          `npm unlink`
          `npm link`
        end
        Dir.chdir(Rails.root) do
          # Instead of just `npm link`, use `npm install` to add the local package to package.json
          `npm install #{local_package_url} --save`
          stdout, stderr, status = Open3.capture3("npm ls #{package_name}")
          if stderr.present?
            raise "ERROR: npm link failed for #{package_name} => #{stderr}"
          end
          puts "Successfully linked #{package_name} to #{local_package_url}"
          puts "  • `npm ls #{package_name}` => «#{stdout}»"
        end
      end

      def self.inspect_package(package_name)
        pkg = nil
        version = nil

        if File.exist?('package-lock.json')
          pl = JSON.parse(File.read('package-lock.json'))
          unless pl['packages']
            raise "ERROR: package-lock.json found, but no packages found, seems to be corrupted."
          end
          pkg = pl['packages'].keys.grep(/\/#{package_name}$/).first
          version = pl['packages'][pkg]['version'] if pkg
        end

        if pkg
          {
            type: pkg.match(/^.*?(?=\/[^\/]*$)/).to_s,
            version: version&.split('.')&.map(&:to_i)
          }
        end

      end

    end
  end
end