lib/svelte_on_rails/configuration.rb



require "yaml"

module SvelteOnRails
  class Configuration

    def self.instance
      @instance ||= new
    end

    attr_accessor :configs

    def initialize
      @configs = {
        development: {
          watch_changes: true,
        },
        test: {
          watch_changes: true,
        }
      }
      load_yaml_config if defined?(Rails)
    end

    def watch_changes?
      if @configs[Rails.env]
        @configs[Rails.env]['watch_changes'] == true
      else
        false
      end
    end

    def rails_root(root_url = nil)
      root_url || Rails.root
    end

    def frontend_folder
      Pathname.new(@configs['frontend_folder'].to_s)
    end

    def frontend_folder_full
      rails_root.join(@configs['frontend_folder'].to_s)
    end

    def components_folder
      Pathname.new(@configs['components_folder'].to_s)
    end

    def components_folder_full
      Pathname.new(frontend_folder_full).join(components_folder.to_s)
    end

    def assets_folder
      dist_folder.join('assets')
    end

    def ssr_manifest
      file = rails_root.join('public', 'vite-ssr', 'manifest.json')

      if watch_changes?
        begin
          JSON.parse(File.read(file))
        rescue
          raise "ERROR: Could not read public/vite-ssr/manifest.json."
        end
      else
        @manifest ||= JSON.parse(File.read(file))
      end

    end

    # def manifest=(manifest_hash)
    #   file = dist_folder.join('manifest.json')
    #   @manifest = manifest_hash
    #   File.write(file, JSON.pretty_generate(manifest_hash))
    # end

    def ssr
      rss = @configs['ssr']
      if rss == false || rss == :auto
        rss
      else
        true
      end
    end

    # def dist_folder(app_root = nil)
    #   rails_root(app_root).join('public', 'svelteDist')
    # end

    def client_dist_folder(app_root = nil)
      if Rails.env.development?
        rails_root(app_root).join('public', 'vite')
      else
        rails_root(app_root).join('public', 'vite')
      end
    end

    def ssr_dist_folder(app_root = nil)
      rails_root(app_root).join('public', 'vite-ssr')
    end

    def system_type
      :vite_rails
    end

    def node_bin_path
      @node_bin_path ||= begin
                           n = ENV['SVELTE_ON_RAILS_NODE_BIN'] || 'node'

                           if n == 'node'
                             nvm_installed = false
                             nvm_dir = ENV['NVM_DIR'] || File.expand_path('~/.nvm')
                             nvm_installed ||= File.exist?("#{nvm_dir}/nvm.sh")

                             if nvm_installed
                               # Check for .nvmrc in the project root
                               project_root = rails_root || Dir.pwd
                               nvmrc_path = File.join(project_root, '.nvmrc')
                               use_nvmrc = File.exist?(nvmrc_path)

                               if use_nvmrc
                                 # Read the version from .nvmrc
                                 node_version = File.read(nvmrc_path).strip
                                 # Ensure NVM is sourced and use the version from .nvmrc
                                 command = "[ -s \"#{nvm_dir}/nvm.sh\" ] && . \"#{nvm_dir}/nvm.sh\" && nvm use #{node_version} > /dev/null 2>&1 && nvm which #{node_version}"
                               else
                                 # Fallback to current NVM version
                                 command = "[ -s \"#{nvm_dir}/nvm.sh\" ] && . \"#{nvm_dir}/nvm.sh\" && nvm which current"
                               end

                               node_path, status = Open3.capture2("bash -lc '#{command}'")

                               # Only update n if the command succeeded and output is non-empty
                               n = node_path.strip if status.success? && !node_path.strip.empty?
                             end
                           end

                           # Validate node_bin
                           unless n && !n.empty? && system("#{n} --version > /dev/null 2>&1")
                             raise "Node.js not found at '#{n || 'unknown'}'. Please configure SVELTE_ON_RAILS_NODE_BIN (e.g., to ~/.nvm/versions/node/vX.Y.Z/bin/node) or ensure 'node' is in the PATH. If using NVM, run `nvm alias default <version>` to set a default version or ensure a valid .nvmrc file is present."
                           end

                           n
                         rescue StandardError => e
                           raise "Failed to detect Node.js binary: «#{e.message}». Ensure Node.js is installed and accessible, or set SVELTE_ON_RAILS_NODE_BIN. If using .nvmrc, ensure the specified version is installed via NVM."
                         end
    end

    private

    def load_yaml_config
      begin
        config_path = Rails.root.join("config", "svelte_on_rails.yml")
        return unless File.exist?(config_path)
      rescue
        return
      end

      config_data = YAML.load_file(config_path)

      if config_data
        @configs = @configs.merge(config_data)
      end
    end
  end
end