Module: Dependabot::NpmAndYarn::Helpers

Extended by:
T::Sig
Defined in:
lib/dependabot/npm_and_yarn/helpers.rb

Overview

rubocop:disable Metrics/ModuleLength

Constant Summary collapse

YARN_PATH_NOT_FOUND =
/^.*(?<error>The "yarn-path" option has been set \(in [^)]+\), but the specified location doesn't exist)/
NPM_V11 =

NPM Version Constants

11
NPM_V10 =
10
NPM_V8 =
8
NPM_V6 =
6
NPM_DEFAULT_VERSION =
NPM_V11
PNPM_V10 =

PNPM Version Constants

10
PNPM_V9 =
9
PNPM_V8 =
8
PNPM_V7 =
7
PNPM_V6 =
6
PNPM_DEFAULT_VERSION =
PNPM_V10
PNPM_FALLBACK_VERSION =
PNPM_V6
YARN_V3 =

YARN Version Constants

3
YARN_V2 =
2
YARN_V1 =
1
YARN_DEFAULT_VERSION =
YARN_V3
YARN_FALLBACK_VERSION =
YARN_V1
SUPPORTED_COREPACK_PACKAGE_MANAGERS =

corepack supported package managers

%w(npm yarn pnpm).freeze
COREPACK_SIGNATURE_METADATA_ERROR =
"No compatible signature found in package metadata"

Class Method Summary collapse

Class Method Details

.build_corepack_env_variablesObject



628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 628

def self.build_corepack_env_variables
  return nil unless Dependabot::Experiments.enabled?(:enable_private_registry_for_corepack)
  return nil if dependency_files.nil? || credentials.nil?

  files = T.must(dependency_files)
  creds = T.must(credentials)

  registry_helper = RegistryHelper.new(
    {
      npmrc: files.find { |f| f.name.end_with?(".npmrc") },
      yarnrc: files.find { |f| f.name.end_with?(".yarnrc") && !f.name.end_with?(".yarnrc.yml") },
      yarnrc_yml: files.find { |f| f.name.end_with?(".yarnrc.yml") }
    },
    creds
  )

  registry_helper.find_corepack_env_variables
end

.command_observer(output) ⇒ Object



347
348
349
350
351
352
353
354
355
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 347

def self.command_observer(output)
  # Observe the output for specific error
  return {} unless output.include?("npm ERR! ERESOLVE")

  {
    gracefully_stop: true, # value must be a String
    reason: "NPM Resolution Error"
  }
end

.corepack_supported_package_manager?(name) ⇒ Boolean

Returns:

  • (Boolean)


717
718
719
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 717

def self.corepack_supported_package_manager?(name)
  SUPPORTED_COREPACK_PACKAGE_MANAGERS.include?(name)
end

.credentialsObject



38
39
40
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 38

def credentials
  T.cast(Thread.current[:npm_and_yarn_credentials], T.nilable(T::Array[Dependabot::Credential]))
end

.credentials=(creds) ⇒ Object



33
34
35
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 33

def credentials=(creds)
  Thread.current[:npm_and_yarn_credentials] = creds
end

.default_npm_registry?(registry) ⇒ Boolean

Returns:

  • (Boolean)


693
694
695
696
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 693

def self.default_npm_registry?(registry)
  normalized_registry = RegistryHelper.normalize_registry_url(registry)
  normalized_registry == RegistryHelper::DEFAULT_NPM_REGISTRY
end

.dependencies_with_all_versions_metadata(dependency_set) ⇒ Object



709
710
711
712
713
714
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 709

def self.(dependency_set)
  dependency_set.dependencies.map do |dependency|
    dependency.[:all_versions] = dependency_set.all_versions_for_name(dependency.name)
    dependency
  end
end

.dependency_filesObject



28
29
30
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 28

def dependency_files
  T.cast(Thread.current[:npm_and_yarn_dependency_files], T.nilable(T::Array[Dependabot::DependencyFile]))
end

.dependency_files=(files) ⇒ Object



23
24
25
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 23

def dependency_files=(files)
  Thread.current[:npm_and_yarn_dependency_files] = files
end

.fallback_to_local_version(name, env: {}) ⇒ Object



482
483
484
485
486
487
488
489
490
491
492
493
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 482

def self.fallback_to_local_version(name, env: {})
  return "Corepack does not support #{name}" unless corepack_supported_package_manager?(name)

  Dependabot.logger.info("Falling back to activate the currently installed version of #{name}.")

  # Fetch the currently installed version directly from the environment
  current_version = local_package_manager_version(name)
  Dependabot.logger.info("Activating currently installed version of #{name}: #{current_version}")

  # Prepare the existing version
  package_manager_activate(name, current_version, env: env)
end

.fetch_yarnrc_yml_value(key, default_value) ⇒ Object



145
146
147
148
149
150
151
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 145

def self.fetch_yarnrc_yml_value(key, default_value)
  if File.exist?(".yarnrc.yml") && (yarnrc = YAML.load_file(".yarnrc.yml"))
    yarnrc.fetch(key, default_value)
  else
    default_value
  end
end

.handle_subprocess_failure(error) ⇒ Object



199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 199

def self.handle_subprocess_failure(error)
  message = error.message
  if YARN_PATH_NOT_FOUND.match?(message)
    error = T.must(T.must(YARN_PATH_NOT_FOUND.match(message))[:error]).sub(Dir.pwd, ".")
    raise MisconfiguredTooling.new("Yarn", error)
  end

  if message.include?("Internal Error") && message.include?(".yarnrc.yml")
    raise MisconfiguredTooling.new("Invalid .yarnrc.yml file", message)
  end

  raise
end

.install(name, version, env: {}) ⇒ Object



453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 453

def self.install(name, version, env: {})
  Dependabot.logger.info("Installing \"#{name}@#{version}\"")

  begin
    # Try to activate the specified version
    output = package_manager_activate(name, version, env: env)

    # Confirm success based on the output
    if output.include?("immediate activation...")
      Dependabot.logger.info("#{name}@#{version} successfully installed.")

      Dependabot.logger.info("Activating currently installed version of #{name}: #{version}")
    else
      Dependabot.logger.error("Corepack installation output unexpected: #{output}")
      fallback_to_local_version(name, env: env)
    end
  rescue StandardError => e
    Dependabot.logger.error("Error activating #{name}@#{version}: #{e.message}")
    fallback_to_local_version(name, env: env)
  end

  # Verify the installed version
  installed_version = package_manager_version(name, env: env)

  installed_version
end

.local_package_manager_version(name) ⇒ Object



529
530
531
532
533
534
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 529

def self.local_package_manager_version(name)
  Dependabot::SharedHelpers.run_shell_command(
    "#{name} -v",
    fingerprint: "#{name} -v"
  ).strip
end

.merge_corepack_env(env) ⇒ Object



619
620
621
622
623
624
625
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 619

def self.merge_corepack_env(env)
  corepack_env = build_corepack_env_variables
  return env if corepack_env.nil? || corepack_env.empty?
  return corepack_env if env.nil?

  corepack_env.merge(env)
end

.node_versionObject



358
359
360
361
362
363
364
365
366
367
368
369
370
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 358

def self.node_version
  version = run_node_command("-v", fingerprint: "-v").strip

  # Validate the output format (e.g., "v20.18.1" or "20.18.1")
  if version.match?(/^v?\d+(\.\d+){2}$/)
    parsed_version = version.strip.delete_prefix("v") # Remove the "v" prefix if present
    Dependabot.logger.info("Using node version: #{parsed_version}")
    parsed_version
  end
rescue StandardError => e
  Dependabot.logger.error("Error retrieving Node.js version: #{e.message}")
  nil
end

.normalize_npm_scope(scope) ⇒ Object



722
723
724
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 722

def self.normalize_npm_scope(scope)
  scope.start_with?("@") ? scope : "@#{scope}"
end

.npm_version_numeric(lockfile) ⇒ Object



74
75
76
77
78
79
80
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 74

def self.npm_version_numeric(lockfile)
  detected_npm_version = detect_npm_version(lockfile)

  return NPM_DEFAULT_VERSION if detected_npm_version.nil? || detected_npm_version == NPM_V6

  detected_npm_version
end

.package_manager_activate(name, version, env: {}) ⇒ Object



516
517
518
519
520
521
522
523
524
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 516

def self.package_manager_activate(name, version, env: {})
  return "Corepack does not support #{name}" unless corepack_supported_package_manager?(name)

  run_corepack_command(
    "corepack prepare #{name}@#{version} --activate",
    fingerprint: "corepack prepare <name>@<version> --activate",
    env: env
  )
end

.package_manager_install(name, version, env: {}) ⇒ Object



504
505
506
507
508
509
510
511
512
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 504

def self.package_manager_install(name, version, env: {})
  return "Corepack does not support #{name}" unless corepack_supported_package_manager?(name)

  run_corepack_command(
    "corepack install #{name}@#{version} --global --cache-only",
    fingerprint: "corepack install <name>@<version> --global --cache-only",
    env: env
  )
end

.package_manager_run_command(name, command, fingerprint: nil, output_observer: nil, env: nil) ⇒ Object



561
562
563
564
565
566
567
568
569
570
571
572
573
574
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 561

def self.package_manager_run_command(
  name,
  command,
  fingerprint: nil,
  output_observer: nil,
  env: nil
)
  run_corepack_command(
    "corepack #{name} #{command}",
    fingerprint: "corepack #{name} #{fingerprint || command}",
    output_observer: output_observer,
    env: env
  )
end

.package_manager_version(name, env: nil) ⇒ Object



538
539
540
541
542
543
544
545
546
547
548
549
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 538

def self.package_manager_version(name, env: nil)
  Dependabot.logger.info("Fetching version for package manager: #{name}")

  version = package_manager_run_command(name, "-v", env: env).strip

  Dependabot.logger.info("Installed version of #{name}: #{version}")

  version
rescue StandardError => e
  Dependabot.logger.error("Error fetching version for package manager #{name}: #{e.message}")
  raise
end

.parse_npm8?(package_lock) ⇒ Boolean

Returns:

  • (Boolean)


154
155
156
157
158
159
160
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 154

def self.parse_npm8?(package_lock)
  return true unless package_lock&.content

  detected_npm = detect_npm_version(package_lock)
  # For conversion reading properly from npm 6 lockfile we need to check if detected version is npm 6
  detected_npm.nil? || detected_npm != NPM_V6
end

.pnpm_lockfile_version(pnpm_lock) ⇒ Object



701
702
703
704
705
706
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 701

def self.pnpm_lockfile_version(pnpm_lock)
  match = T.must(pnpm_lock.content).match(/^lockfileVersion: ['"]?(?<version>[\d.]+)/)
  return match[:version] if match

  nil
end

.pnpm_version_numeric(pnpm_lock) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 126

def self.pnpm_version_numeric(pnpm_lock)
  lockfile_content = pnpm_lock&.content

  return PNPM_DEFAULT_VERSION if !lockfile_content || lockfile_content.strip.empty?

  pnpm_lockfile_version_str = pnpm_lockfile_version(pnpm_lock)

  return PNPM_FALLBACK_VERSION unless pnpm_lockfile_version_str

  pnpm_lockfile_version = pnpm_lockfile_version_str.to_f

  return PNPM_V10 if pnpm_lockfile_version >= 9.0
  return PNPM_V8 if pnpm_lockfile_version >= 6.0
  return PNPM_V7 if pnpm_lockfile_version >= 5.4

  PNPM_FALLBACK_VERSION
end

.raise_registry_error_if_not_found(error) ⇒ Object



673
674
675
676
677
678
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 673

def self.raise_registry_error_if_not_found(error)
  if error.message.match?(/Response Code.*:.*404.*\(Not Found\)/) &&
     error.message.include?("The remote server failed to provide the requested resource")
    raise RegistryError.new(404, "The remote server failed to provide the requested resource")
  end
end

.retry_without_signature_verification?(error:, env:) ⇒ Boolean

Returns:

  • (Boolean)


681
682
683
684
685
686
687
688
689
690
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 681

def self.retry_without_signature_verification?(error:, env:)
  return false unless env

  registry = env[RegistryHelper::COREPACK_NPM_REGISTRY_ENV]
  return false unless registry
  return false if default_npm_registry?(registry)
  return false unless error.message.include?(COREPACK_SIGNATURE_METADATA_ERROR)

  !env.key?(RegistryHelper::COREPACK_INTEGRITY_KEYS_ENV)
end

.run_corepack_command(full_command, fingerprint:, output_observer: nil, env: nil) ⇒ Object



588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 588

def self.run_corepack_command(full_command, fingerprint:, output_observer: nil, env: nil)
  run_corepack_shell_command(
    full_command,
    fingerprint: fingerprint,
    output_observer: output_observer,
    env: env
  )
rescue StandardError => e
  Dependabot.logger.error("Error running package manager command: #{full_command}, Error: #{e.message}")

  raise_registry_error_if_not_found(e)

  if retry_without_signature_verification?(error: e, env: env)
    retry_env = T.must(env).merge(RegistryHelper::COREPACK_INTEGRITY_KEYS_ENV => "")
    Dependabot.logger.warn(
      "Corepack signature verification failed against the configured private registry. " \
      "Retrying once with COREPACK_INTEGRITY_KEYS disabled for this command only."
    )

    return run_corepack_shell_command(
      full_command,
      fingerprint: fingerprint,
      output_observer: output_observer,
      env: retry_env
    )
  end

  raise
end

.run_corepack_shell_command(full_command, fingerprint:, output_observer:, env: nil) ⇒ Object



655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 655

def self.run_corepack_shell_command(full_command, fingerprint:, output_observer:, env: nil)
  if output_observer
    return Dependabot::SharedHelpers.run_shell_command(
      full_command,
      fingerprint: fingerprint,
      output_observer: output_observer,
      env: env
    ).strip
  end

  Dependabot::SharedHelpers.run_shell_command(
    full_command,
    fingerprint: fingerprint,
    env: env
  ).strip
end

.run_node_command(command, fingerprint: nil) ⇒ Object



373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 373

def self.run_node_command(command, fingerprint: nil)
  full_command = "node #{command}"

  Dependabot.logger.info("Running node command: #{full_command}")

  result = Dependabot::SharedHelpers.run_shell_command(
    full_command,
    fingerprint: "node #{fingerprint || command}"
  )

  Dependabot.logger.info("Command executed successfully: #{full_command}")
  result
rescue StandardError => e
  Dependabot.logger.error("Error running node command: #{full_command}, Error: #{e.message}")
  raise
end

.run_npm_command(command, fingerprint: command, env: nil) ⇒ Object



324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 324

def self.run_npm_command(command, fingerprint: command, env: nil)
  merged_env = merge_corepack_env(env)
  if Dependabot::Experiments.enabled?(:enable_corepack_for_npm_and_yarn)
    package_manager_run_command(
      NpmPackageManager::NAME,
      command,
      fingerprint: fingerprint,
      output_observer: ->(output) { command_observer(output) },
      env: merged_env
    )
  else
    Dependabot::SharedHelpers.run_shell_command(
      "npm #{command}",
      fingerprint: "npm #{fingerprint}",
      output_observer: ->(output) { command_observer(output) }
    )
  end
end

.run_pnpm_command(command, fingerprint: nil, env: nil) ⇒ Object



411
412
413
414
415
416
417
418
419
420
421
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 411

def self.run_pnpm_command(command, fingerprint: nil, env: nil)
  if Dependabot::Experiments.enabled?(:enable_corepack_for_npm_and_yarn)
    merged_env = merge_corepack_env(env)
    package_manager_run_command(PNPMPackageManager::NAME, command, fingerprint: fingerprint, env: merged_env)
  else
    Dependabot::SharedHelpers.run_shell_command(
      "pnpm #{command}",
      fingerprint: "pnpm #{fingerprint || command}"
    )
  end
end

.run_yarn_command(command, fingerprint: nil, env: nil) ⇒ Object



398
399
400
401
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 398

def self.run_yarn_command(command, fingerprint: nil, env: nil)
  setup_yarn_berry
  run_single_yarn_command(command, fingerprint: fingerprint, env: env)
end

.run_yarn_commands(*commands) ⇒ Object



305
306
307
308
309
310
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 305

def self.run_yarn_commands(*commands)
  setup_yarn_berry
  commands.each do |cmd, fingerprint|
    run_single_yarn_command(cmd, fingerprint: fingerprint) if cmd
  end
end

.setup_yarn_berryObject



278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 278

def self.setup_yarn_berry
  # Always disable immutable installs so yarn's CI detection doesn't prevent updates.
  run_single_yarn_command("config set enableImmutableInstalls false")
  # Do not generate a cache if offline cache disabled. Otherwise side effects may confuse further checks
  run_single_yarn_command("config set enableGlobalCache true") unless yarn_berry_skip_build?
  # We never want to execute postinstall scripts, either set this config or mode=skip-build must be set
  run_single_yarn_command("config set enableScripts false") if yarn_berry_disable_scripts?
  if (http_proxy = ENV.fetch("HTTP_PROXY", false))
    run_single_yarn_command("config set httpProxy #{http_proxy}", fingerprint: "config set httpProxy <proxy>")
  end
  if (https_proxy = ENV.fetch("HTTPS_PROXY", false))
    run_single_yarn_command("config set httpsProxy #{https_proxy}", fingerprint: "config set httpsProxy <proxy>")
  end
  return unless (ca_file_path = ENV.fetch("NODE_EXTRA_CA_CERTS", false))

  if yarn_4_or_higher?
    run_single_yarn_command("config set httpsCaFilePath #{ca_file_path}")
  else
    run_single_yarn_command("config set caFilePath #{ca_file_path}")
  end
end

.yarn_4_or_higher?Boolean

Returns:

  • (Boolean)


248
249
250
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 248

def self.yarn_4_or_higher?
  yarn_major_version >= 4
end

.yarn_berry?(yarn_lock) ⇒ Boolean

Returns:

  • (Boolean)


163
164
165
166
167
168
169
170
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 163

def self.yarn_berry?(yarn_lock)
  return false if yarn_lock.nil? || yarn_lock.content.nil?

  yaml = YAML.safe_load(T.must(yarn_lock.content))
  yaml.key?("__metadata")
rescue StandardError
  false
end

.yarn_berry_argsObject



225
226
227
228
229
230
231
232
233
234
235
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 225

def self.yarn_berry_args
  if yarn_major_version == 2
    ""
  elsif yarn_berry_skip_build?
    "--mode=skip-build"
  else
    # We only want this mode if the cache is not being updated/managed
    # as this improperly leaves old versions in the cache
    "--mode=update-lockfile"
  end
end

.yarn_berry_disable_scripts?Boolean

Returns:

  • (Boolean)


243
244
245
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 243

def self.yarn_berry_disable_scripts?
  yarn_major_version == YARN_V2 || !yarn_zero_install?
end

.yarn_berry_skip_build?Boolean

Returns:

  • (Boolean)


238
239
240
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 238

def self.yarn_berry_skip_build?
  yarn_major_version >= YARN_V3 && (yarn_zero_install? || yarn_offline_cache?)
end

.yarn_berry_supports_minimal_age_gate?Boolean

Returns:

  • (Boolean)


253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 253

def self.yarn_berry_supports_minimal_age_gate?
  version = Version.new(run_single_yarn_command("--version"))
  supported = version >= Version.new("4.10.0")
  if supported
    Dependabot.logger.info(
      "Yarn #{version} supports npmMinimalAgeGate. " \
      "Setting YARN_NPM_MINIMAL_AGE_GATE=0 to bypass the release-age gate for security updates."
    )
  else
    Dependabot.logger.info(
      "Yarn #{version} does not support npmMinimalAgeGate (requires 4.10.0+). " \
      "YARN_NPM_MINIMAL_AGE_GATE will not be set."
    )
  end
  supported
rescue StandardError => e
  Dependabot.logger.warn(
    "Could not determine Yarn version to check npmMinimalAgeGate support: #{e.message}. " \
    "Assuming unsupported (returning false). YARN_NPM_MINIMAL_AGE_GATE will not be set, " \
    "so the registry's release-age gate may still block security updates."
  )
  false
end

.yarn_major_versionObject



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 173

def self.yarn_major_version
  retries = 0
  output = run_single_yarn_command("--version")
  Version.new(output).major
rescue Dependabot::SharedHelpers::HelperSubprocessFailed => e
  # Should never happen, can probably be removed once this settles
  raise "Failed to replace ENV, not sure why" if T.must(retries).positive?

  message = e.message

  missing_env_var_regex = %r{Environment variable not found \((?:[^)]+)\) in #{Dir.pwd}/(?<path>\S+)}

  if message.match?(missing_env_var_regex)
    match = T.must(message.match(missing_env_var_regex))
    path = T.must(match.named_captures["path"])

    File.write(path, File.read(path).gsub(/\$\{[^}-]+\}/, ""))
    retries = T.must(retries) + 1

    retry
  end

  handle_subprocess_failure(e)
end

.yarn_offline_cache?Boolean

Returns:

  • (Boolean)


219
220
221
222
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 219

def self.yarn_offline_cache?
  yarn_cache_dir = fetch_yarnrc_yml_value("cacheFolder", ".yarn/cache")
  File.exist?(yarn_cache_dir) && (fetch_yarnrc_yml_value("nodeLinker", "") == "node-modules")
end

.yarn_version_numeric(yarn_lock) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 110

def self.yarn_version_numeric(yarn_lock)
  lockfile_content = yarn_lock&.content

  return YARN_DEFAULT_VERSION if lockfile_content.nil? || lockfile_content.strip.empty?

  if yarn_berry?(yarn_lock)
    YARN_DEFAULT_VERSION
  else
    YARN_FALLBACK_VERSION
  end
end

.yarn_zero_install?Boolean

Returns:

  • (Boolean)


214
215
216
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 214

def self.yarn_zero_install?
  File.exist?(".pnp.cjs")
end