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



610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 610

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)


699
700
701
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 699

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)


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

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



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

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



601
602
603
604
605
606
607
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 601

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



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

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)

  Dependabot::SharedHelpers.run_shell_command(
    "corepack prepare #{name}@#{version} --activate",
    fingerprint: "corepack prepare <name>@<version> --activate",
    env: env
  ).strip
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)

  Dependabot::SharedHelpers.run_shell_command(
    "corepack install #{name}@#{version} --global --cache-only",
    fingerprint: "corepack install <name>@<version> --global --cache-only",
    env: env
  ).strip
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
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
# 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
)
  full_command = T.let("corepack #{name} #{command}", String)
  command_fingerprint = T.let("corepack #{name} #{fingerprint || command}", String)

  run_corepack_shell_command(
    full_command,
    fingerprint: command_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(
      T.must(full_command),
      fingerprint: T.must(command_fingerprint),
      output_observer: output_observer,
      env: retry_env
    )
  end

  raise
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



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

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



655
656
657
658
659
660
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 655

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)


663
664
665
666
667
668
669
670
671
672
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 663

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_shell_command(full_command, fingerprint:, output_observer:, env: nil) ⇒ Object



637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
# File 'lib/dependabot/npm_and_yarn/helpers.rb', line 637

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