bibliothecary 12.1.4 → 12.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bbe2270af80c93aaa2613434faa3c801337ec316a68bdd25d4b6d92d9979398a
4
- data.tar.gz: ee84bbf8cb2bd2beae91c080e480fe5fc3f0c2773a305743388cf3f225355eb2
3
+ metadata.gz: 28a553f3ccc80b401878d7d1f05d9b2ca1504e52fc0705b101759665391f8316
4
+ data.tar.gz: db49351f1c52f112c5936a787135fe185bc4b4b9aab6ea02376fbe85735db512
5
5
  SHA512:
6
- metadata.gz: 0ac214d1af05ecf0f156a81dc751421cbbe1d94c6306420d0aeb87c7dabf96eca819a0b199705d40d408b3a22b73227a523bb06e121c1e60c7dfbbb2f74dff10
7
- data.tar.gz: 52d620bcd946c7197f129ebd59f2ba68676e67152dbeac297a4cdd5d72f74e9f3dc32c6c11b11f513443040721ccaa18b2c322e7b77162fb775fa7827fe3edd6
6
+ metadata.gz: a63120979de0f7f661383b6c7efafda1acc0787821eae36164bb7469fc35bf5f9028cab9cf1c53e1289d30103c57cbc064bdc9cffc91feb48745744359a0ac73
7
+ data.tar.gz: 802a1ee3a8031b6b47f29f369cf8cade92e835784cbb35e7abaf25a6035160bc35043fa8fb23b47c7720b6e54139eb0f607d176f772a40869ddc030687e95bd3
data/CHANGELOG.md CHANGED
@@ -13,6 +13,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
13
13
 
14
14
  ### Removed
15
15
 
16
+ ## [12.1.6] - 2025-04-29
17
+
18
+ ### Added
19
+
20
+ ### Changed
21
+
22
+ - Use JSON.parser.parse() in bun.lock parser to work around overriden JSON.parse() method.
23
+ - Don't raise an error in pnpm-lock.yaml v9 parser if devDependencies isn't found.
24
+
25
+ ### Removed
26
+
27
+ ## [12.1.5] - 2025-03-17
28
+
29
+ ### Added
30
+
31
+ - Adds alias support for PNPM lockfiles.
32
+ - Add support for bun.lock files
33
+
34
+ ### Changed
35
+
36
+ ### Removed
37
+
16
38
  ## [12.1.4] - 2025-03-14
17
39
 
18
40
  ### Added
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_dependency "commander"
25
25
  spec.add_dependency "deb_control"
26
+ spec.add_dependency "json", "~> 2.8"
26
27
  spec.add_dependency "librariesio-gem-parser"
27
28
  spec.add_dependency "ox", ">= 2.8.1"
28
29
  spec.add_dependency "packageurl-ruby"
@@ -36,6 +36,10 @@ module Bibliothecary
36
36
  kind: "lockfile",
37
37
  parser: :parse_shrinkwrap,
38
38
  },
39
+ match_filename("bun.lock") => {
40
+ kind: "lockfile",
41
+ parser: :parse_bun_lock,
42
+ },
39
43
  }
40
44
  end
41
45
 
@@ -252,53 +256,106 @@ module Bibliothecary
252
256
  end
253
257
  end
254
258
 
255
- # This method currently has been tested to support:
256
- # lockfileVersion: '9.0'
257
- # lockfileVersion: '6.0'
258
- # lockfileVersion: '5.4'
259
- def self.parse_pnpm_lock(contents, _source = nil)
260
- parsed = YAML.load(contents)
261
- lockfile_version = parsed["lockfileVersion"].to_i
259
+ def self.parse_v5_pnpm_lock(parsed_contents, _source = nil)
260
+ dependency_mapping = parsed_contents.fetch("dependencies", {})
261
+ .merge(parsed_contents.fetch("devDependencies", {}))
262
+
263
+ parsed_contents["packages"]
264
+ .map do |name_version, details|
265
+ # e.g. "/debug/2.6.9:"
266
+ name, version = name_version.sub(/^\//, "").split("/", 2)
267
+
268
+ # e.g. "/debug/2.2.0_supports-color@1.2.0:"
269
+ version = version.split("_", 2)[0]
270
+
271
+ # e.g. "alias-package: /zod/3.24.2"
272
+ original_name = nil
273
+ original_requirement = nil
274
+ if (alias_dep = dependency_mapping.find { |_n, v| v.start_with?("/#{name}/") })
275
+ original_name = alias_dep[0]
276
+ original_requirement = alias_dep[1].split("/", 3)[2] # e.g. "/zod/3.24.2"
277
+ end
278
+
279
+ is_dev = details["dev"] == true
280
+
281
+ Dependency.new(
282
+ name: name,
283
+ requirement: version,
284
+ original_name: original_name,
285
+ original_requirement: original_requirement,
286
+ type: is_dev ? "development" : "runtime"
287
+ )
288
+ end
289
+ end
290
+
291
+ def self.parse_v6_pnpm_lock(parsed_contents, _source = nil)
292
+ dependency_mapping = parsed_contents.fetch("dependencies", {})
293
+ .merge(parsed_contents.fetch("devDependencies", {}))
294
+
295
+ parsed_contents["packages"]
296
+ .map do |name_version, details|
297
+ # e.g. "/debug@2.6.9:"
298
+ name, version = name_version.sub(/^\//, "").split("@", 2)
299
+
300
+ # e.g. "debug@2.2.0(supports-color@1.2.0)"
301
+ version = version.split("(", 2).first
302
+
303
+ # e.g.
304
+ # alias-package:
305
+ # specifier: npm:zod
306
+ # version: /zod@3.24.2
307
+ original_name = nil
308
+ original_requirement = nil
309
+ if (alias_dep = dependency_mapping.find { |_n, info| info["specifier"] == "npm:#{name}" })
310
+ original_name = alias_dep[0]
311
+ original_requirement = alias_dep[1]["version"].sub(/^\//, "").split("@", 2)[1]
312
+ end
313
+
314
+ is_dev = details["dev"] == true
315
+
316
+ Dependency.new(
317
+ name: name,
318
+ requirement: version,
319
+ original_name: original_name,
320
+ original_requirement: original_requirement,
321
+ type: is_dev ? "development" : "runtime"
322
+ )
323
+ end
324
+ end
262
325
 
263
- dev_dependencies = parsed.dig("importers", ".", "devDependencies") # <= v9
264
- dev_dependencies ||= parsed["devDependencies"] # <v9
326
+ def self.parse_v9_pnpm_lock(parsed_contents, _source = nil)
327
+ dependencies = parsed_contents.fetch("importers", {}).fetch(".", {}).fetch("dependencies", {})
328
+ dev_dependencies = parsed_contents.fetch("importers", {}).fetch(".", {}).fetch("devDependencies", {})
329
+ dependency_mapping = dependencies.merge(dev_dependencies)
265
330
 
266
331
  # "dependencies" is in "packages" for < v9 and in "snapshots" for >= v9
267
332
  # as of https://github.com/pnpm/pnpm/pull/7700.
268
- (parsed["snapshots"] || parsed["packages"])
269
- .map do |name_version, details|
270
- name, version = case lockfile_version
271
- when 5
272
- # e.g. '/debug/2.6.9:'
273
- n, v = name_version.sub(/^\//, "").split("/", 2)
274
- # e.g. '/debug/2.2.0_supports-color@1.2.0:'
275
- v = v.split("_", 2)[0]
276
- [n, v] # rubocop:disable Style/IdenticalConditionalBranches
277
- when 6
278
- # e.g. '/debug@2.6.9:'
279
- n, v = name_version.sub(/^\//, "").split("@", 2)
280
- # e.g. "debug@2.2.0(supports-color@1.2.0)"
281
- v = v.split("(", 2).first
282
- [n, v] # rubocop:disable Style/IdenticalConditionalBranches
283
- else
284
- # e.g. 'debug@2.6.9:'
285
- n, v = name_version.split("@", 2)
286
- # e.g. "debug@2.2.0(supports-color@1.2.0)"
287
- v = v.split("(", 2).first
288
- [n, v] # rubocop:disable Style/IdenticalConditionalBranches
289
- end
333
+ parsed_contents["snapshots"]
334
+ .map do |name_version, _details|
335
+ # e.g. "debug@2.6.9:"
336
+ name, version = name_version.split("@", 2)
337
+
338
+ # e.g. "debug@2.2.0(supports-color@1.2.0)"
339
+ version = version.split("(", 2).first
340
+
341
+ # e.g.
342
+ # alias-package:
343
+ # specifier: npm:zod
344
+ # version: zod@3.24.2
345
+ original_name = nil
346
+ original_requirement = nil
347
+ if (alias_dep = dependency_mapping.find { |_n, info| info["specifier"] == "npm:#{name}" })
348
+ original_name = alias_dep[0]
349
+ original_requirement = alias_dep[1]["version"].split("@", 2)[1]
350
+ end
290
351
 
291
352
  # TODO: the "dev" field was removed in v9 lockfiles (https://github.com/pnpm/pnpm/pull/7808)
292
- # so this will only exist in v6 and below and might be unreliable.
293
353
  # The proper way to set this for v9+ is to build a lookup of deps to
294
354
  # their "dependencies", and then recurse through each package's
295
355
  # parents. If the direct dep(s) that required them are all
296
356
  # "devDependencies" then we can consider them "dev == true". This
297
357
  # should be done using a DAG data structure, though, to be efficient
298
358
  # and avoid cycles.
299
- is_dev = details["dev"] == true
300
-
301
- # Fallback for v9+: this only detects dev deps that are direct.
302
359
  is_dev ||= dev_dependencies.any? do |dev_name, dev_details|
303
360
  dev_name == name && dev_details["version"] == version
304
361
  end
@@ -306,17 +363,64 @@ module Bibliothecary
306
363
  Dependency.new(
307
364
  name: name,
308
365
  requirement: version,
366
+ original_name: original_name,
367
+ original_requirement: original_requirement,
309
368
  type: is_dev ? "development" : "runtime"
310
369
  )
311
370
  end
312
371
  end
313
372
 
373
+ # This method currently has been tested to support:
374
+ # lockfileVersion: '9.0'
375
+ # lockfileVersion: '6.0'
376
+ # lockfileVersion: '5.4'
377
+ def self.parse_pnpm_lock(contents, _source = nil)
378
+ parsed = YAML.load(contents)
379
+ lockfile_version = parsed["lockfileVersion"].to_i
380
+
381
+ case lockfile_version
382
+ when 5
383
+ parse_v5_pnpm_lock(parsed)
384
+ when 6
385
+ parse_v6_pnpm_lock(parsed)
386
+ else # v9+
387
+ parse_v9_pnpm_lock(parsed)
388
+ end
389
+ end
390
+
314
391
  def self.parse_ls(file_contents, options: {})
315
392
  manifest = JSON.parse(file_contents)
316
393
 
317
394
  transform_tree_to_array(manifest.fetch("dependencies", {}), options.fetch(:filename, nil))
318
395
  end
319
396
 
397
+ def self.parse_bun_lock(file_contents, options: {})
398
+ # The stdlib JSON gem 2.8+ supports trailing commas.
399
+ # The Oj gem does not support them as of writing, and will override
400
+ # JSON.parse() if Oj.mimic_json/optimize_rails has been called. Luckily
401
+ # JSON.parser is not overridden by Oj, so use it to call parse directly.
402
+ manifest = JSON.parser.parse(file_contents, allow_trailing_comma: true)
403
+ source = options.fetch(:filename, nil)
404
+
405
+ dev_deps = manifest.dig("workspaces", "", "devDependencies")&.keys&.to_set
406
+
407
+ manifest.fetch("packages", []).map do |name, info|
408
+ info_name, _, version = info.first.rpartition("@")
409
+ is_local = version&.start_with?("file:")
410
+ is_alias = info_name != name
411
+
412
+ Dependency.new(
413
+ name: info_name,
414
+ original_name: is_alias ? name : nil,
415
+ requirement: version,
416
+ original_requirement: is_alias ? version : nil,
417
+ type: dev_deps&.include?(name) ? "development" : "runtime",
418
+ local: is_local,
419
+ source: source
420
+ )
421
+ end
422
+ end
423
+
320
424
  def self.lockfile_preference_order(file_infos)
321
425
  files = file_infos.each_with_object({}) do |file_info, obj|
322
426
  obj[File.basename(file_info.full_path)] = file_info
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bibliothecary
4
- VERSION = "12.1.4"
4
+ VERSION = "12.1.6"
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bibliothecary
3
3
  version: !ruby/object:Gem::Version
4
- version: 12.1.4
4
+ version: 12.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Nesbitt
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-14 00:00:00.000000000 Z
10
+ date: 2025-04-29 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: commander
@@ -37,6 +37,20 @@ dependencies:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
39
  version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: json
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.8'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.8'
40
54
  - !ruby/object:Gem::Dependency
41
55
  name: librariesio-gem-parser
42
56
  requirement: !ruby/object:Gem::Requirement