class LicenseFinder::Yarn

def self.takes_priority_over

def self.takes_priority_over
  NPM
end

def classic_yarn_prepare_command

def classic_yarn_prepare_command
  "yarn install --ignore-engines --ignore-scripts#{classic_yarn_production_flag}"
end

def classic_yarn_production_flag

def classic_yarn_production_flag
  return '' if @ignored_groups.nil?
  @ignored_groups.include?('devDependencies') ? ' --production' : ''
end

def current_packages

def current_packages
  # the licenses plugin supports the classic production flag
  cmd = "#{Yarn::SHELL_COMMAND}#{classic_yarn_production_flag}"
  if yarn_version == 1
    cmd += ' --no-progress'
    cmd += " --cwd #{project_path}" unless project_path.nil?
    cmd += " #{@yarn_options}" unless @yarn_options.nil?
  end
  stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(cmd) }
  raise "Command '#{cmd}' failed to execute: #{stderr}" unless status.success?
  json_strings = stdout.encode('ASCII', invalid: :replace, undef: :replace, replace: '?').split("\n")
  json_objects = json_strings.map { |json_object| JSON.parse(json_object) }
  if yarn_version == 1
    get_yarn1_packages(json_objects)
  else
    get_yarn_packages(json_objects)
  end
end

def filter_yarn_internal_package(all_packages)

remove fake package created by yarn [Yarn Bug]
def filter_yarn_internal_package(all_packages)
  internal_package_pattern = /workspace-aggregator-[a-zA-z0-9]{8}-[a-zA-z0-9]{4}-[a-zA-z0-9]{4}-[a-zA-z0-9]{4}-[a-zA-z0-9]{12}/
  yarn_internal_package = all_packages.find { |package| internal_package_pattern.match(package['Name']) }
  all_packages - [yarn_internal_package]
end

def get_yarn1_packages(json_objects)

def get_yarn1_packages(json_objects)
  packages = []
  if json_objects.last['type'] == 'table'
    license_json = json_objects.pop['data']
    packages = packages_from_json(license_json)
  end
  incompatible_packages = []
  json_objects.each do |json_object|
    match = %r{(?<name>@?[\w/.-]+)@(?<version>(\d+\.?)+)} =~ json_object['data'].to_s
    if match
      package = YarnPackage.new(name, version, spec_licenses: ['unknown'])
      incompatible_packages.push(package)
    end
  end
  packages + incompatible_packages.uniq
end

def get_yarn_packages(json_objects)

def get_yarn_packages(json_objects)
  packages = []
  incompatible_packages = []
  json_objects.each do |json_object|
    license = json_object['value']
    body = json_object['children']
    body.each do |package_name, vendor_info|
      valid_match = %r{(?<name>@?[\w/.-]+)@(?<manager>\D*):\D*(?<version>(\d+\.?)+)} =~ package_name.to_s
      valid_match = %r{(?<name>@?[\w/.-]+)@virtual:.+#(\D*):\D*(?<version>(\d+\.?)+)} =~ package_name.to_s if manager.eql?('virtual')
      if valid_match
        homepage = vendor_info['children']['vendorUrl']
        author = vendor_info['children']['vendorName']
        package = YarnPackage.new(
          name,
          version,
          spec_licenses: [license],
          homepage: homepage,
          authors: author,
          install_path: project_path.join(modules_folder, name)
        )
        packages << package
      end
      incompatible_match = %r{(?<name>@?[\w/.-]+)@[a-z]*:(?<version>(\.))} =~ package_name.to_s
      if incompatible_match
        package = YarnPackage.new(name, version, spec_licenses: [license])
        incompatible_packages.push(package)
      end
    end
  end
  packages + incompatible_packages.uniq
end

def initialize(options = {})

def initialize(options = {})
  super
  @yarn_options = options[:yarn_options]
end

def modules_folder

def modules_folder
  return @modules_folder if @modules_folder
  stdout, _stderr, status = Dir.chdir(project_path) { Cmd.run('yarn config get modules-folder') }
  @modules_folder = 'node_modules' if !status.success? || stdout.strip == 'undefined'
  @modules_folder ||= stdout.strip
end

def package_management_command

def package_management_command
  'yarn'
end

def packages_from_json(json_data)

def packages_from_json(json_data)
  body = json_data['body']
  head = json_data['head']
  packages = body.map do |json_package|
    Hash[head.zip(json_package)]
  end
  valid_packages = filter_yarn_internal_package(packages)
  valid_packages.map do |package_hash|
    YarnPackage.new(
      package_hash['Name'],
      package_hash['Version'],
      spec_licenses: [package_hash['License']],
      homepage: package_hash['VendorUrl'],
      authors: package_hash['VendorName'],
      install_path: project_path.join(modules_folder, package_hash['Name'])
    )
  end
end

def possible_package_paths

def possible_package_paths
  [project_path.join('yarn.lock')]
end

def prepare

def prepare
  prep_cmd = prepare_command.to_s
  _stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(prep_cmd) }
  return if status.success?
  log_errors stderr
  raise "Prepare command '#{prep_cmd}' failed" unless @prepare_no_fail
end

def prepare_command

def prepare_command
  if yarn_version == 1
    classic_yarn_prepare_command
  else
    yarn_prepare_command
  end
end

def yarn_licenses_plugin_version

def yarn_licenses_plugin_version
  if yarn_version == 2
    'v0.6.0'
  else
    'v0.7.2'
  end
end

def yarn_plugin_production_command

def yarn_plugin_production_command
  return '' if @ignored_groups.nil?
  @ignored_groups.include?('devDependencies') ? 'yarn plugin import workspace-tools && yarn workspaces focus --all --production && ' : ''
end

def yarn_prepare_command

def yarn_prepare_command
  "#{yarn_plugin_production_command}yarn install && yarn plugin import https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/#{yarn_licenses_plugin_version}/bundles/@yarnpkg/plugin-licenses.js"
end

def yarn_version

def yarn_version
  Dir.chdir(project_path) do
    version_string, stderr_str, status = Dir.chdir(project_path) { Cmd.run('yarn -v') }
    raise "Command 'yarn -v' failed to execute: #{stderr_str}" unless status.success?
    version = version_string.split('.').map(&:to_i)
    return version[0]
  end
end