bibliothecary 13.0.2 → 14.0.0

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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/lib/bibliothecary/analyser/analysis.rb +3 -24
  4. data/lib/bibliothecary/analyser.rb +5 -7
  5. data/lib/bibliothecary/dependency.rb +1 -1
  6. data/lib/bibliothecary/multi_parsers/bundler_like_manifest.rb +2 -1
  7. data/lib/bibliothecary/multi_parsers/cyclonedx.rb +3 -2
  8. data/lib/bibliothecary/multi_parsers/dependencies_csv.rb +3 -1
  9. data/lib/bibliothecary/multi_parsers/json_runtime.rb +4 -1
  10. data/lib/bibliothecary/multi_parsers/spdx.rb +1 -0
  11. data/lib/bibliothecary/parser_result.rb +37 -0
  12. data/lib/bibliothecary/parsers/bower.rb +3 -2
  13. data/lib/bibliothecary/parsers/cargo.rb +8 -4
  14. data/lib/bibliothecary/parsers/cocoapods.rb +10 -4
  15. data/lib/bibliothecary/parsers/conda.rb +8 -2
  16. data/lib/bibliothecary/parsers/cpan.rb +4 -2
  17. data/lib/bibliothecary/parsers/cran.rb +7 -5
  18. data/lib/bibliothecary/parsers/dub.rb +3 -1
  19. data/lib/bibliothecary/parsers/elm.rb +4 -2
  20. data/lib/bibliothecary/parsers/go.rb +32 -16
  21. data/lib/bibliothecary/parsers/julia.rb +3 -2
  22. data/lib/bibliothecary/parsers/maven.rb +61 -27
  23. data/lib/bibliothecary/parsers/npm.rb +46 -31
  24. data/lib/bibliothecary/parsers/nuget.rb +33 -20
  25. data/lib/bibliothecary/parsers/packagist.rb +9 -5
  26. data/lib/bibliothecary/parsers/pub.rb +7 -4
  27. data/lib/bibliothecary/parsers/pypi.rb +30 -16
  28. data/lib/bibliothecary/parsers/rubygems.rb +10 -5
  29. data/lib/bibliothecary/parsers/shard.rb +7 -4
  30. data/lib/bibliothecary/version.rb +1 -1
  31. data/lib/bibliothecary.rb +1 -0
  32. data/lib/sdl_parser.rb +3 -1
  33. metadata +3 -2
@@ -139,15 +139,17 @@ module Bibliothecary
139
139
 
140
140
  def self.parse_ivy_manifest(file_contents, options: {})
141
141
  manifest = Ox.parse file_contents
142
- manifest.dependencies.locate("dependency").map do |dependency|
142
+ dependencies = manifest.dependencies.locate("dependency").map do |dependency|
143
143
  attrs = dependency.attributes
144
144
  Dependency.new(
145
145
  name: "#{attrs[:org]}:#{attrs[:name]}",
146
146
  requirement: attrs[:rev],
147
147
  type: "runtime",
148
- source: options.fetch(:filename, nil)
148
+ source: options.fetch(:filename, nil),
149
+ platform: platform_name
149
150
  )
150
151
  end
152
+ ParserResult.new(dependencies: dependencies)
151
153
  end
152
154
 
153
155
  def self.ivy_report?(file_contents)
@@ -172,7 +174,7 @@ module Bibliothecary
172
174
  type = info.attributes[:conf]
173
175
  type = "unknown" if type.nil?
174
176
  modules = doc.locate("ivy-report/dependencies/module")
175
- modules.map do |mod|
177
+ dependencies = modules.map do |mod|
176
178
  attrs = mod.attributes
177
179
  org = attrs[:organisation]
178
180
  name = attrs[:name]
@@ -184,15 +186,17 @@ module Bibliothecary
184
186
  name: "#{org}:#{name}",
185
187
  requirement: version,
186
188
  type: type,
187
- source: options.fetch(:filename, nil)
189
+ source: options.fetch(:filename, nil),
190
+ platform: platform_name
188
191
  )
189
192
  end.compact
193
+ ParserResult.new(dependencies: dependencies)
190
194
  end
191
195
 
192
196
  def self.parse_gradle_resolved(file_contents, options: {})
193
197
  current_type = nil
194
198
 
195
- file_contents.split("\n").map do |line|
199
+ dependencies = file_contents.split("\n").map do |line|
196
200
  current_type_match = GRADLE_TYPE_REGEXP.match(line)
197
201
  current_type = current_type_match.captures[0] if current_type_match
198
202
 
@@ -232,7 +236,8 @@ module Bibliothecary
232
236
  name: dep[-3..-2].join(":"),
233
237
  requirement: dep[-1],
234
238
  type: current_type,
235
- source: options.fetch(:filename, nil)
239
+ source: options.fetch(:filename, nil),
240
+ platform: platform_name
236
241
  )
237
242
  elsif dep.count == 5
238
243
  # get name from renamed package resolution "org:name -> renamed_org:name:version"
@@ -242,7 +247,8 @@ module Bibliothecary
242
247
  name: dep[-3..-2].join(":"),
243
248
  requirement: dep[-1],
244
249
  type: current_type,
245
- source: options.fetch(:filename, nil)
250
+ source: options.fetch(:filename, nil),
251
+ platform: platform_name
246
252
  )
247
253
  else
248
254
  # get name from version conflict resolution ("org:name:version -> version") and no-resolution ("org:name:version")
@@ -250,21 +256,24 @@ module Bibliothecary
250
256
  name: dep[0..1].join(":"),
251
257
  requirement: dep[-1],
252
258
  type: current_type,
253
- source: options.fetch(:filename, nil)
259
+ source: options.fetch(:filename, nil),
260
+ platform: platform_name
254
261
  )
255
262
  end
256
263
  end
257
264
  .compact
258
265
  .uniq { |item| [item.name, item.requirement, item.type, item.original_name, item.original_requirement] }
266
+ ParserResult.new(dependencies: dependencies)
259
267
  end
260
268
 
261
269
  def self.parse_maven_resolved(file_contents, options: {})
262
- file_contents
270
+ dependencies = file_contents
263
271
  .gsub(ANSI_MATCHER, "")
264
272
  .split("\n")
265
273
  .map { |line| parse_resolved_dep_line(line, options: options) }
266
274
  .compact
267
275
  .uniq
276
+ ParserResult.new(dependencies: dependencies)
268
277
  end
269
278
 
270
279
  # Return each item in the ascii art tree with a depth of that item,
@@ -318,19 +327,20 @@ module Bibliothecary
318
327
 
319
328
  projects_to_exclude = {}
320
329
 
321
- if keep_subprojects
322
- # traditional behavior: we only exclude the root project, and only if we parsed multiple lines
323
- (root_name, root_version, _root_type) = parse_maven_tree_dependency(items.shift[1])
324
- unless items.empty?
325
- projects_to_exclude[root_name] = Set.new
326
- projects_to_exclude[root_name].add(root_version)
327
- end
330
+ (root_name, root_version, _root_type) = parse_maven_tree_dependency(items[0][1])
331
+
332
+ # traditional behavior: we only exclude the root project, and only if we parsed multiple lines
333
+ if keep_subprojects && !items.empty?
334
+ items.shift
335
+ projects_to_exclude[root_name] = Set.new
336
+ projects_to_exclude[root_name].add(root_version)
328
337
  end
329
338
 
330
339
  unique_items = items.map do |(depth, item)|
331
340
  # new behavior: we exclude root and subprojects (depth 0 items)
332
341
  (name, version, type) = parse_maven_tree_dependency(item)
333
342
  if depth == 0 && !keep_subprojects
343
+
334
344
  # record and then remove the depth 0
335
345
  projects_to_exclude[name] ||= Set.new
336
346
  projects_to_exclude[name].add(version)
@@ -340,7 +350,7 @@ module Bibliothecary
340
350
  end
341
351
  end.compact.uniq
342
352
 
343
- unique_items
353
+ dependencies = unique_items
344
354
  # drop the projects and subprojects
345
355
  .reject { |(name, version, _type)| projects_to_exclude[name]&.include?(version) }
346
356
  .map do |(name, version, type)|
@@ -348,14 +358,20 @@ module Bibliothecary
348
358
  name: name,
349
359
  requirement: version,
350
360
  type: type,
351
- source: options.fetch(:filename, nil)
361
+ source: options.fetch(:filename, nil),
362
+ platform: platform_name
352
363
  )
353
364
  end
365
+ ParserResult.new(
366
+ project_name: root_name,
367
+ dependencies: dependencies
368
+ )
354
369
  end
355
370
 
356
371
  def self.parse_maven_tree_dot(file_contents, options: {})
357
372
  # Project could be either the root project or a sub-module.
358
373
  project = file_contents.match(MAVEN_DOT_PROJECT_REGEXP)[1]
374
+ project_name, _project_version, _project_type = parse_maven_tree_dependency(project)
359
375
  relationships = file_contents.scan(MAVEN_DOT_RELATIONSHIP_REGEXP)
360
376
 
361
377
  direct_names_to_versions = relationships.each.with_object({}) do |(parent, child), obj|
@@ -366,17 +382,25 @@ module Bibliothecary
366
382
  obj[name].add(version)
367
383
  end
368
384
 
369
- relationships.map do |(_parent, child)|
385
+ deps = relationships.map do |(_parent, child)|
370
386
  child_name, child_version, child_type = parse_maven_tree_dependency(child)
371
387
 
372
388
  Dependency.new(
373
389
  name: child_name,
374
390
  requirement: child_version,
391
+ platform: platform_name,
375
392
  type: child_type,
376
393
  direct: direct_names_to_versions[child_name]&.include?(child_version) || false,
377
394
  source: options.fetch(:filename, nil)
378
395
  )
379
396
  end.uniq
397
+
398
+ # TODO: should we change every method to return this, or just allow both to be
399
+ # returned to an analysis? (I'm leaning towards former)
400
+ ParserResult.new(
401
+ dependencies: deps,
402
+ project_name: project_name
403
+ )
380
404
  end
381
405
 
382
406
  def self.parse_resolved_dep_line(line, options: {})
@@ -392,12 +416,14 @@ module Bibliothecary
392
416
  name: dep_parts[0, 2].join(":"),
393
417
  requirement: dep_parts[3],
394
418
  type: dep_parts[4].split("--").first.strip,
395
- source: options.fetch(:filename, nil)
419
+ source: options.fetch(:filename, nil),
420
+ platform: platform_name
396
421
  )
397
422
  end
398
423
 
399
424
  def self.parse_standalone_pom_manifest(file_contents, options: {})
400
- parse_pom_manifest(file_contents, {}, options:)
425
+ dependencies = parse_pom_manifest(file_contents, {}, options:)
426
+ ParserResult.new(dependencies: dependencies)
401
427
  end
402
428
 
403
429
  def self.parse_pom_manifest(file_contents, parent_properties = {}, options: {})
@@ -438,6 +464,7 @@ module Bibliothecary
438
464
  unless dep_hashes.key?(key)
439
465
  dep_hashes[key] = {
440
466
  name: key,
467
+ platform: platform_name,
441
468
  requirement: nil,
442
469
  type: nil,
443
470
  optional: nil,
@@ -472,7 +499,7 @@ module Bibliothecary
472
499
  end
473
500
 
474
501
  def self.parse_gradle(file_contents, options: {})
475
- file_contents
502
+ dependencies = file_contents
476
503
  .scan(GRADLE_GROOVY_SIMPLE_REGEXP) # match 'implementation "group:artifactId:version"'
477
504
  .reject { |(_type, group, artifact_id, _version)| group.nil? || artifact_id.nil? } # remove any matches with missing group/artifactId
478
505
  .map do |(type, group, artifact_id, version)|
@@ -480,13 +507,15 @@ module Bibliothecary
480
507
  name: [group, artifact_id].join(":"),
481
508
  requirement: version,
482
509
  type: type,
483
- source: options.fetch(:filename, nil)
510
+ source: options.fetch(:filename, nil),
511
+ platform: platform_name
484
512
  )
485
513
  end
514
+ ParserResult.new(dependencies: dependencies)
486
515
  end
487
516
 
488
517
  def self.parse_gradle_kts(file_contents, options: {})
489
- file_contents
518
+ dependencies = file_contents
490
519
  .scan(GRADLE_KOTLIN_SIMPLE_REGEXP) # match 'implementation("group:artifactId:version")'
491
520
  .reject { |(_type, group, artifact_id, _version)| group.nil? || artifact_id.nil? } # remove any matches with missing group/artifactId
492
521
  .map do |(type, group, artifact_id, version)|
@@ -494,9 +523,11 @@ module Bibliothecary
494
523
  name: [group, artifact_id].join(":"),
495
524
  requirement: version,
496
525
  type: type,
497
- source: options.fetch(:filename, nil)
526
+ source: options.fetch(:filename, nil),
527
+ platform: platform_name
498
528
  )
499
529
  end
530
+ ParserResult.new(dependencies: dependencies)
500
531
  end
501
532
 
502
533
  def self.gradle_dependency_name(group, name)
@@ -612,11 +643,14 @@ module Bibliothecary
612
643
  dep.delete(:fields)
613
644
  end
614
645
 
615
- squished.map do |dep_kvs|
646
+ dependencies = squished.map do |dep_kvs|
616
647
  Dependency.new(
617
- **dep_kvs, source: options.fetch(:filename, nil)
648
+ **dep_kvs,
649
+ source: options.fetch(:filename, nil),
650
+ platform: platform_name
618
651
  )
619
652
  end
653
+ ParserResult.new(dependencies: dependencies)
620
654
  end
621
655
 
622
656
  def self.parse_sbt_deps(type, lines)
@@ -50,14 +50,15 @@ module Bibliothecary
50
50
  def self.parse_package_lock(file_contents, options: {})
51
51
  manifest = JSON.parse(file_contents)
52
52
  # https://docs.npmjs.com/cli/v9/configuring-npm/package-lock-json#lockfileversion
53
- if manifest["lockfileVersion"].to_i <= 1
54
- # lockfileVersion 1 uses the "dependencies" object
55
- parse_package_lock_v1(manifest, options.fetch(:filename, nil))
56
- else
57
- # lockfileVersion 2 has backwards-compatability by including both "packages" and the legacy "dependencies" object
58
- # lockfileVersion 3 has no backwards-compatibility and only includes the "packages" object
59
- parse_package_lock_v2(manifest, options.fetch(:filename, nil))
60
- end
53
+ dependencies = if manifest["lockfileVersion"].to_i <= 1
54
+ # lockfileVersion 1 uses the "dependencies" object
55
+ parse_package_lock_v1(manifest, options.fetch(:filename, nil))
56
+ else
57
+ # lockfileVersion 2 has backwards-compatability by including both "packages" and the legacy "dependencies" object
58
+ # lockfileVersion 3 has no backwards-compatibility and only includes the "packages" object
59
+ parse_package_lock_v2(manifest, options.fetch(:filename, nil))
60
+ end
61
+ ParserResult.new(dependencies: dependencies)
61
62
  end
62
63
 
63
64
  class << self
@@ -98,7 +99,8 @@ module Bibliothecary
98
99
  original_requirement: original_name.nil? ? nil : dep["version"],
99
100
  type: dep.fetch("dev", false) || dep.fetch("devOptional", false) ? "development" : "runtime",
100
101
  local: dep.fetch("link", false),
101
- source: source
102
+ source: source,
103
+ platform: platform_name
102
104
  )
103
105
  end
104
106
  end
@@ -118,14 +120,15 @@ module Bibliothecary
118
120
  name: name,
119
121
  requirement: version,
120
122
  type: type,
121
- source: source
123
+ source: source,
124
+ platform: platform_name
122
125
  )] + child_dependencies
123
126
  end
124
127
  end
125
128
 
126
129
  def self.parse_manifest(file_contents, options: {})
127
130
  # on ruby 3.2 we suddenly get this JSON error, so detect and return early: "package.json: unexpected token at ''"
128
- return [] if file_contents.empty?
131
+ return ParserResult.new(dependencies: []) if file_contents.empty?
129
132
 
130
133
  manifest = JSON.parse(file_contents)
131
134
 
@@ -150,7 +153,8 @@ module Bibliothecary
150
153
  original_requirement: original_name.nil? ? nil : requirement,
151
154
  type: "runtime",
152
155
  local: requirement.start_with?("file:"),
153
- source: options.fetch(:filename, nil)
156
+ source: options.fetch(:filename, nil),
157
+ platform: platform_name
154
158
  )
155
159
  end
156
160
 
@@ -162,11 +166,12 @@ module Bibliothecary
162
166
  requirement: requirement,
163
167
  type: "development",
164
168
  local: requirement.start_with?("file:"),
165
- source: options.fetch(:filename, nil)
169
+ source: options.fetch(:filename, nil),
170
+ platform: platform_name
166
171
  )
167
172
  end
168
173
 
169
- dependencies
174
+ ParserResult.new(dependencies: dependencies)
170
175
  end
171
176
 
172
177
  def self.parse_yarn_lock(file_contents, options: {})
@@ -176,7 +181,7 @@ module Bibliothecary
176
181
  parse_v1_yarn_lock(file_contents, options.fetch(:filename, nil))
177
182
  end
178
183
 
179
- dep_hash.map do |dep|
184
+ dependencies = dep_hash.map do |dep|
180
185
  Dependency.new(
181
186
  name: dep[:name],
182
187
  original_name: dep[:original_name],
@@ -184,9 +189,11 @@ module Bibliothecary
184
189
  original_requirement: dep[:original_requirement],
185
190
  type: "runtime", # lockfile doesn't tell us more about the type of dep
186
191
  local: dep[:requirements]&.first&.start_with?("file:"),
187
- source: options.fetch(:filename, nil)
192
+ source: options.fetch(:filename, nil),
193
+ platform: platform_name
188
194
  )
189
195
  end
196
+ ParserResult.new(dependencies: dependencies)
190
197
  end
191
198
 
192
199
  # Returns a hash representation of the deps in yarn.lock, eg:
@@ -285,7 +292,8 @@ module Bibliothecary
285
292
  original_name: original_name,
286
293
  original_requirement: original_requirement,
287
294
  type: is_dev ? "development" : "runtime",
288
- source: source
295
+ source: source,
296
+ platform: platform_name
289
297
  )
290
298
  end
291
299
  end
@@ -321,7 +329,8 @@ module Bibliothecary
321
329
  original_name: original_name,
322
330
  original_requirement: original_requirement,
323
331
  type: is_dev ? "development" : "runtime",
324
- source: source
332
+ source: source,
333
+ platform: platform_name
325
334
  )
326
335
  end
327
336
  end
@@ -369,7 +378,8 @@ module Bibliothecary
369
378
  original_name: original_name,
370
379
  original_requirement: original_requirement,
371
380
  type: is_dev ? "development" : "runtime",
372
- source: source
381
+ source: source,
382
+ platform: platform_name
373
383
  )
374
384
  end
375
385
  end
@@ -382,20 +392,22 @@ module Bibliothecary
382
392
  parsed = YAML.load(contents)
383
393
  lockfile_version = parsed["lockfileVersion"].to_i
384
394
 
385
- case lockfile_version
386
- when 5
387
- parse_v5_pnpm_lock(parsed, options.fetch(:filename, nil))
388
- when 6
389
- parse_v6_pnpm_lock(parsed, options.fetch(:filename, nil))
390
- else # v9+
391
- parse_v9_pnpm_lock(parsed, options.fetch(:filename, nil))
392
- end
395
+ dependencies = case lockfile_version
396
+ when 5
397
+ parse_v5_pnpm_lock(parsed, options.fetch(:filename, nil))
398
+ when 6
399
+ parse_v6_pnpm_lock(parsed, options.fetch(:filename, nil))
400
+ else # v9+
401
+ parse_v9_pnpm_lock(parsed, options.fetch(:filename, nil))
402
+ end
403
+ ParserResult.new(dependencies: dependencies)
393
404
  end
394
405
 
395
406
  def self.parse_ls(file_contents, options: {})
396
407
  manifest = JSON.parse(file_contents)
397
408
 
398
- transform_tree_to_array(manifest.fetch("dependencies", {}), options.fetch(:filename, nil))
409
+ dependencies = transform_tree_to_array(manifest.fetch("dependencies", {}), options.fetch(:filename, nil))
410
+ ParserResult.new(dependencies: dependencies)
399
411
  end
400
412
 
401
413
  def self.parse_bun_lock(file_contents, options: {})
@@ -408,7 +420,7 @@ module Bibliothecary
408
420
 
409
421
  dev_deps = manifest.dig("workspaces", "", "devDependencies")&.keys&.to_set
410
422
 
411
- manifest.fetch("packages", []).map do |name, info|
423
+ dependencies = manifest.fetch("packages", []).map do |name, info|
412
424
  info_name, _, version = info.first.rpartition("@")
413
425
  is_local = version&.start_with?("file:")
414
426
  is_alias = info_name != name
@@ -420,9 +432,11 @@ module Bibliothecary
420
432
  original_requirement: is_alias ? version : nil,
421
433
  type: dev_deps&.include?(name) ? "development" : "runtime",
422
434
  local: is_local,
423
- source: source
435
+ source: source,
436
+ platform: platform_name
424
437
  )
425
438
  end
439
+ ParserResult.new(dependencies: dependencies)
426
440
  end
427
441
 
428
442
  def self.lockfile_preference_order(file_infos)
@@ -444,7 +458,8 @@ module Bibliothecary
444
458
  name: name,
445
459
  requirement: metadata["version"],
446
460
  type: "runtime",
447
- source: source
461
+ source: source,
462
+ platform: platform_name
448
463
  ),
449
464
  ] + transform_tree_to_array(metadata.fetch("dependencies", {}), source)
450
465
  end.flatten(1)
@@ -52,15 +52,17 @@ module Bibliothecary
52
52
 
53
53
  def self.parse_project_lock_json(file_contents, options: {})
54
54
  manifest = JSON.parse file_contents
55
- manifest.fetch("libraries", []).map do |name, _requirement|
55
+ dependencies = manifest.fetch("libraries", []).map do |name, _requirement|
56
56
  dep = name.split("/")
57
57
  Dependency.new(
58
58
  name: dep[0],
59
59
  requirement: dep[1],
60
60
  type: "runtime",
61
- source: options.fetch(:filename, nil)
61
+ source: options.fetch(:filename, nil),
62
+ platform: platform_name
62
63
  )
63
64
  end
65
+ ParserResult.new(dependencies: dependencies)
64
66
  end
65
67
 
66
68
  def self.parse_packages_lock_json(file_contents, options: {})
@@ -77,7 +79,8 @@ module Bibliothecary
77
79
  # so fallback to requested is pure paranoia
78
80
  requirement: details.fetch("resolved", details.fetch("requested", "*")),
79
81
  type: "runtime",
80
- source: options.fetch(:filename, nil)
82
+ source: options.fetch(:filename, nil),
83
+ platform: platform_name
81
84
  )
82
85
  end
83
86
  end
@@ -88,23 +91,25 @@ module Bibliothecary
88
91
 
89
92
  # Note, frameworks can be empty, so remove empty ones and then return the last sorted item if any
90
93
  frameworks.delete_if { |_k, v| v.empty? }
91
- return frameworks[frameworks.keys.max] unless frameworks.empty?
94
+ return ParserResult.new(dependencies: frameworks[frameworks.keys.max]) unless frameworks.empty?
92
95
  end
93
- []
96
+ ParserResult.new(dependencies: [])
94
97
  end
95
98
 
96
99
  def self.parse_packages_config(file_contents, options: {})
97
100
  manifest = Ox.parse file_contents
98
- manifest.packages.locate("package").map do |dependency|
101
+ dependencies = manifest.packages.locate("package").map do |dependency|
99
102
  Dependency.new(
100
103
  name: dependency.id,
101
104
  requirement: (dependency.version if dependency.respond_to? "version"),
102
105
  type: dependency.respond_to?("developmentDependency") && dependency.developmentDependency == "true" ? "development" : "runtime",
103
- source: options.fetch(:filename, nil)
106
+ source: options.fetch(:filename, nil),
107
+ platform: platform_name
104
108
  )
105
109
  end
110
+ ParserResult.new(dependencies: dependencies)
106
111
  rescue StandardError
107
- []
112
+ ParserResult.new(dependencies: [])
108
113
  end
109
114
 
110
115
  def self.parse_csproj(file_contents, options: {})
@@ -138,7 +143,8 @@ module Bibliothecary
138
143
  name: dependency.Include,
139
144
  requirement: requirement,
140
145
  type: type,
141
- source: options.fetch(:filename, nil)
146
+ source: options.fetch(:filename, nil),
147
+ platform: platform_name
142
148
  )
143
149
  end
144
150
 
@@ -154,27 +160,31 @@ module Bibliothecary
154
160
  name: name,
155
161
  requirement: vals["Version"] || "*",
156
162
  type: "runtime",
157
- source: options.fetch(:filename, nil)
163
+ source: options.fetch(:filename, nil),
164
+ platform: platform_name
158
165
  )
159
166
  end
160
167
 
161
- packages.uniq(&:name)
168
+ dependencies = packages.uniq(&:name)
169
+ ParserResult.new(dependencies: dependencies)
162
170
  rescue StandardError
163
- []
171
+ ParserResult.new(dependencies: [])
164
172
  end
165
173
 
166
174
  def self.parse_nuspec(file_contents, options: {})
167
175
  manifest = Ox.parse file_contents
168
- manifest.package.metadata.dependencies.locate("dependency").map do |dependency|
176
+ dependencies = manifest.package.metadata.dependencies.locate("dependency").map do |dependency|
169
177
  Dependency.new(
170
178
  name: dependency.id,
171
179
  requirement: dependency.attributes[:version],
172
180
  type: dependency.respond_to?("developmentDependency") && dependency.developmentDependency == "true" ? "development" : "runtime",
173
- source: options.fetch(:filename, nil)
181
+ source: options.fetch(:filename, nil),
182
+ platform: platform_name
174
183
  )
175
184
  end
185
+ ParserResult.new(dependencies: dependencies)
176
186
  rescue StandardError
177
- []
187
+ ParserResult.new(dependencies: [])
178
188
  end
179
189
 
180
190
  def self.parse_paket_lock(file_contents, options: {})
@@ -185,11 +195,13 @@ module Bibliothecary
185
195
  name: match[:name].strip,
186
196
  requirement: match[:version],
187
197
  type: "runtime",
188
- source: options.fetch(:filename, nil)
198
+ source: options.fetch(:filename, nil),
199
+ platform: platform_name
189
200
  )
190
201
  end
191
202
  # we only have to enforce uniqueness by name because paket ensures that there is only the single version globally in the project
192
- packages.uniq(&:name)
203
+ dependencies = packages.uniq(&:name)
204
+ ParserResult.new(dependencies: dependencies)
193
205
  end
194
206
 
195
207
  def self.parse_project_assets_json(file_contents, options: {})
@@ -205,7 +217,8 @@ module Bibliothecary
205
217
  name: name_split[0],
206
218
  requirement: name_split[1],
207
219
  type: "runtime",
208
- source: options.fetch(:filename, nil)
220
+ source: options.fetch(:filename, nil),
221
+ platform: platform_name
209
222
  )
210
223
  end
211
224
  end
@@ -216,9 +229,9 @@ module Bibliothecary
216
229
 
217
230
  # Note, frameworks can be empty, so remove empty ones and then return the last sorted item if any
218
231
  frameworks.delete_if { |_k, v| v.empty? }
219
- return frameworks[frameworks.keys.max] unless frameworks.empty?
232
+ return ParserResult.new(dependencies: frameworks[frameworks.keys.max]) unless frameworks.empty?
220
233
  end
221
- []
234
+ ParserResult.new(dependencies: [])
222
235
  end
223
236
  end
224
237
  end
@@ -26,7 +26,7 @@ module Bibliothecary
26
26
 
27
27
  def self.parse_lockfile(file_contents, options: {})
28
28
  manifest = JSON.parse file_contents
29
- manifest.fetch("packages", []).map do |dependency|
29
+ dependencies = manifest.fetch("packages", []).map do |dependency|
30
30
  requirement = dependency["version"]
31
31
 
32
32
  # Store Drupal version if Drupal, but include the original manifest version for reference
@@ -40,7 +40,8 @@ module Bibliothecary
40
40
  requirement: requirement,
41
41
  type: "runtime",
42
42
  original_requirement: original_requirement,
43
- source: options.fetch(:filename, nil)
43
+ source: options.fetch(:filename, nil),
44
+ platform: platform_name
44
45
  )
45
46
  end + manifest.fetch("packages-dev", []).map do |dependency|
46
47
  requirement = dependency["version"]
@@ -56,15 +57,18 @@ module Bibliothecary
56
57
  requirement: requirement,
57
58
  type: "development",
58
59
  original_requirement: original_requirement,
59
- source: options.fetch(:filename, nil)
60
+ source: options.fetch(:filename, nil),
61
+ platform: platform_name
60
62
  )
61
63
  end
64
+ ParserResult.new(dependencies: dependencies)
62
65
  end
63
66
 
64
67
  def self.parse_manifest(file_contents, options: {})
65
68
  manifest = JSON.parse file_contents
66
- map_dependencies(manifest, "require", "runtime", options.fetch(:filename, nil)) +
67
- map_dependencies(manifest, "require-dev", "development", options.fetch(:filename, nil))
69
+ dependencies = map_dependencies(manifest, "require", "runtime", options.fetch(:filename, nil)) +
70
+ map_dependencies(manifest, "require-dev", "development", options.fetch(:filename, nil))
71
+ ParserResult.new(dependencies: dependencies)
68
72
  end
69
73
 
70
74
  # Drupal hosts its own Composer repository, where its "modules" are indexed and searchable. The best way to
@@ -24,20 +24,23 @@ module Bibliothecary
24
24
 
25
25
  def self.parse_yaml_manifest(file_contents, options: {})
26
26
  manifest = YAML.load file_contents
27
- map_dependencies(manifest, "dependencies", "runtime", options.fetch(:filename, nil)) +
28
- map_dependencies(manifest, "dev_dependencies", "development", options.fetch(:filename, nil))
27
+ dependencies = map_dependencies(manifest, "dependencies", "runtime", options.fetch(:filename, nil)) +
28
+ map_dependencies(manifest, "dev_dependencies", "development", options.fetch(:filename, nil))
29
+ ParserResult.new(dependencies: dependencies)
29
30
  end
30
31
 
31
32
  def self.parse_yaml_lockfile(file_contents, options: {})
32
33
  manifest = YAML.load file_contents
33
- manifest.fetch("packages", []).map do |name, dep|
34
+ dependencies = manifest.fetch("packages", []).map do |name, dep|
34
35
  Dependency.new(
35
36
  name: name,
36
37
  requirement: dep["version"],
37
38
  type: "runtime",
38
- source: options.fetch(:filename, nil)
39
+ source: options.fetch(:filename, nil),
40
+ platform: platform_name
39
41
  )
40
42
  end
43
+ ParserResult.new(dependencies: dependencies)
41
44
  end
42
45
  end
43
46
  end