# frozen_string_literal: true module LicenseFinder class Yarn INCOMPATIBLE_PACKAGE_REGEX = /(?[\w,\-]+)@(?(\d+\.?)+)/.freeze PHANTOM_PACKAGE_REGEX = /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}/.freeze def possible_package_paths [project_path.join('yarn.lock')] end def prepare within_project_path do tool_box.install(tool: :nodejs, version: nodejs_version, env: default_env) shell.execute([ :yarn, :install, '--ignore-engines', '--ignore-scripts', '--production' ], env: default_env, capture: false) end end def current_packages stdout, _stderr, status = within_project_path do shell.execute(list_licenses_command) end return [] unless status.success? stdout.each_line.flat_map do |line| dependencies_from(JSON.parse(line)) end end private def list_licenses_command [ :yarn, :licenses, :list, '--no-progress', '--json', '--production', '--cwd', project_path || Pathname.pwd ] end def install_path_for(name) if project_path project_path.join('node_modules', name) else Pathname.pwd.join('node_modules', name) end end def map_from(hash) build( hash['Name'], hash['Version'], spec_licenses: [hash['License']], install_path: install_path_for(hash['Name']).to_s, homepage: hash['VendorUrl'] ) end def dependencies_from(json) case json['type'] when 'table' from_json_table(json) when 'info' from_json_info(json) else [] end end def from_json_table(json) head = json['data']['head'] json['data']['body'].map do |array| hash = Hash[head.zip(array)] map_from(hash) unless PHANTOM_PACKAGE_REGEX.match(hash['Name']) end.compact end def from_json_info(json) matches = json['data'].to_s.match(INCOMPATIBLE_PACKAGE_REGEX) return [] unless matches [build(matches['name'], matches['version'], spec_licenses: ['unknown'])] end def build(name, version, options = {}) Dependency.new('Yarn', name, version, options.merge(detection_path: detected_package_path)) end def default_env { 'NPM_CONFIG_CAFILE' => ENV.fetch('NPM_CONFIG_CAFILE', shell.default_certificate_path).to_s } end def nodejs_version @nodejs_version ||= tool_box.version_of(:nodejs) end end end