bibliothecary 13.0.1 → 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 +22 -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 +51 -36
  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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b41280265bf9f99394621a32e95fc736518aa4cb517042bed3f3fb14de11141e
4
- data.tar.gz: 5abfea8b948e94d88e2b1a0ef48309b4783b63b9d8e1e2920ebee3af590fb42c
3
+ metadata.gz: b9a3de29330d7e021cacaf0e4533ad7e0f32f3d904b1a3d7972a0b47839fd003
4
+ data.tar.gz: f69421671f4cd8415fb5dfa19195c903991b3eeb8174dddfe7b6fa33bf4fddd2
5
5
  SHA512:
6
- metadata.gz: 36207ae0ca54c2e132a651ebf656c0fef5d9e9a0954053a115c8f829ecebda97ccd295b7a11dacb53acd290cb621016b3f7d3c98b9f0ba47c6e7d41a34196b1c
7
- data.tar.gz: e7f22290925ceec3db16011048991c5ef8c1a86e70673d9d1c720f2d41c246eb13802d637170e25f163beca8f32435a11e08297d67473647918943981a2306f3
6
+ metadata.gz: 7108853a7c073ab5b70d70932ce035d1b789502d86dcae3c797c294ec4ef6493b7684ad4eb4747824f75c040f02a1947027e6402f300f99243aed2c5c20faa7a
7
+ data.tar.gz: c2d490660288a54ef31c14dff0a8857c86dcc82c6e6cd49c203bfe6b4b66fcf5d029400ab442d8c1267b3cc4cff54dc431af189a17ae47f42a62779ad9acf13d
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
+ ## [14.0.0] - 2025-07-24
17
+
18
+ ### Added
19
+
20
+ - Added Bibliothecary::ParserResult class, which wraps the parsed dependencies along with the project name, if it was found in the manifest.
21
+
22
+ ### Changed
23
+
24
+ - Breaking: parser methods now return Bibliothecary::ParserResult instead of an Array of Bibliothecary::Dependency
25
+ - Return project_name for maven-dependency-tree.txt and maven-dependency-tree.dot results
26
+ - Breaking: require the "platform" argument to be passed to Bibliothecary::Dependency, and update the parsers to do so.
27
+
28
+ ### Removed
29
+
30
+ - Removed unused generic parser code.
31
+
32
+ ## [13.0.2] - 2025-07-21
33
+
34
+ ### Changed
35
+
36
+ - Handle scoped dependencies in PNPM lockfiles.
37
+
16
38
  ## [13.0.1] - 2025-07-03
17
39
 
18
40
  ### Changed
@@ -40,36 +40,15 @@ module Bibliothecary
40
40
  # If your Parser needs to return multiple responses for one file, please override this method
41
41
  # For example see conda.rb
42
42
  kind = determine_kind_from_info(info)
43
- dependencies = parse_file(info.relative_path, info.contents, options: options)
43
+ parser_result = parse_file(info.relative_path, info.contents, options: options)
44
+ parser_result = ParserResult.new if parser_result.nil? # work around any legacy parsers that return nil
44
45
 
45
- dependencies_to_analysis(info, kind, dependencies)
46
+ Bibliothecary::Analyser.create_analysis(platform_name, info.relative_path, kind, parser_result)
46
47
  rescue Bibliothecary::FileParsingError => e
47
48
  Bibliothecary::Analyser.create_error_analysis(platform_name, info.relative_path, kind, e.message, e.location)
48
49
  end
49
50
  alias analyze_contents_from_info analyse_contents_from_info
50
51
 
51
- def dependencies_to_analysis(info, kind, dependencies)
52
- dependencies ||= [] # work around any legacy parsers that return nil
53
- if generic?
54
- grouped = dependencies.group_by { |dep| dep[:platform] }
55
- all_analyses = grouped.keys.map do |platform|
56
- deplatformed_dependencies = grouped[platform].map do |d|
57
- d.delete(:platform)
58
- d
59
- end
60
- Bibliothecary::Analyser.create_analysis(platform, info.relative_path, kind, deplatformed_dependencies)
61
- end
62
- # this is to avoid a larger refactor for the time being. The larger refactor
63
- # needs to make analyse_contents return multiple analysis, or add another
64
- # method that can return multiple and deprecate analyse_contents, perhaps.
65
- raise "File contains zero or multiple platforms, currently must have exactly one" if all_analyses.length != 1
66
-
67
- all_analyses.first
68
- else
69
- Bibliothecary::Analyser.create_analysis(platform_name, info.relative_path, kind, dependencies)
70
- end
71
- end
72
-
73
52
  # Call the matching parse class method for this file with
74
53
  # these contents
75
54
  def parse_file(filename, contents, options: {})
@@ -18,11 +18,12 @@ module Bibliothecary
18
18
  }
19
19
  end
20
20
 
21
- def self.create_analysis(platform_name, relative_path, kind, dependencies)
21
+ def self.create_analysis(platform_name, relative_path, kind, parser_result)
22
22
  {
23
23
  platform: platform_name,
24
24
  path: relative_path,
25
- dependencies: dependencies,
25
+ project_name: parser_result.project_name,
26
+ dependencies: parser_result.dependencies,
26
27
  kind: kind,
27
28
  success: true,
28
29
  }
@@ -50,17 +51,14 @@ module Bibliothecary
50
51
  end
51
52
 
52
53
  module ClassMethods
53
- def generic?
54
- platform_name == "generic"
55
- end
56
-
57
54
  def platform_name
58
- name.to_s.split("::").last.downcase
55
+ @platform_name ||= name.to_s.split("::").last.downcase.freeze
59
56
  end
60
57
 
61
58
  def map_dependencies(hash, key, type, source = nil)
62
59
  hash.fetch(key, []).map do |name, requirement|
63
60
  Dependency.new(
61
+ platform: platform_name,
64
62
  name: name,
65
63
  requirement: requirement,
66
64
  type: type,
@@ -40,8 +40,8 @@ module Bibliothecary
40
40
  def initialize(
41
41
  name:,
42
42
  requirement:,
43
+ platform:,
43
44
  original_requirement: nil,
44
- platform: nil,
45
45
  type: nil,
46
46
  direct: nil,
47
47
  deprecated: nil,
@@ -5,9 +5,10 @@ module Bibliothecary
5
5
  module BundlerLikeManifest
6
6
  # this takes parsed Bundler and Bundler-like (CocoaPods)
7
7
  # manifests and turns them into a list of dependencies.
8
- def parse_ruby_manifest(manifest, source = nil)
8
+ def parse_ruby_manifest(manifest, platform, source = nil)
9
9
  manifest.dependencies.inject([]) do |deps, dep|
10
10
  deps.push(Dependency.new(
11
+ platform: platform,
11
12
  name: dep.name,
12
13
  requirement: dep
13
14
  .requirement
@@ -38,6 +38,7 @@ module Bibliothecary
38
38
  @manifests[mapping] << Dependency.new(
39
39
  name: PurlUtil.full_name(purl),
40
40
  requirement: purl.version,
41
+ platform: mapping.to_s,
41
42
  type: "lockfile",
42
43
  source: source
43
44
  )
@@ -105,7 +106,7 @@ module Bibliothecary
105
106
  component["purl"]
106
107
  end
107
108
 
108
- entries[platform_name.to_sym]
109
+ ParserResult.new(dependencies: entries[platform_name.to_sym])
109
110
  end
110
111
 
111
112
  def parse_cyclonedx_xml(file_contents, options: {})
@@ -130,7 +131,7 @@ module Bibliothecary
130
131
  component.locate("purl").first&.text
131
132
  end
132
133
 
133
- entries[platform_name.to_sym]
134
+ ParserResult.new(dependencies: entries[platform_name.to_sym])
134
135
  end
135
136
  end
136
137
  end
@@ -139,7 +139,7 @@ module Bibliothecary
139
139
  raw_csv_file
140
140
  end
141
141
 
142
- csv_file
142
+ dependencies = csv_file
143
143
  .result
144
144
  .find_all { |dependency| dependency[:platform] == platform_name.to_s }
145
145
  .map do |dep_kvs|
@@ -147,6 +147,8 @@ module Bibliothecary
147
147
  **dep_kvs, source: options.fetch(:filename, nil)
148
148
  )
149
149
  end
150
+
151
+ ParserResult.new(dependencies: dependencies)
150
152
  end
151
153
  end
152
154
  end
@@ -5,14 +5,17 @@ module Bibliothecary
5
5
  # Provide JSON Runtime Manifest parsing
6
6
  module JSONRuntime
7
7
  def parse_json_runtime_manifest(file_contents, options: {})
8
- JSON.parse(file_contents).fetch("dependencies", []).map do |name, requirement|
8
+ dependencies = JSON.parse(file_contents).fetch("dependencies", []).map do |name, requirement|
9
9
  Dependency.new(
10
+ platform: platform_name,
10
11
  name: name,
11
12
  requirement: requirement,
12
13
  type: "runtime",
13
14
  source: options.fetch(:filename, nil)
14
15
  )
15
16
  end
17
+
18
+ ParserResult.new(dependencies: dependencies)
16
19
  end
17
20
  end
18
21
  end
@@ -137,6 +137,7 @@ module Bibliothecary
137
137
 
138
138
  entries[platform.to_sym] ||= []
139
139
  entries[platform.to_sym] << Dependency.new(
140
+ platform: platform.to_s,
140
141
  name: package_name,
141
142
  requirement: package_version,
142
143
  type: "lockfile",
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bibliothecary
4
+ # ParserResult bundles together a list of dependencies and the project name.
5
+ #
6
+ # @attr_reader [Array<Dependency>] dependencies The list of Dependency objects
7
+ # @attr_reader [String,nil] project_name The name of the project
8
+ class ParserResult
9
+ FIELDS = %i[
10
+ dependencies
11
+ project_name
12
+ ].freeze
13
+
14
+ attr_reader(*FIELDS)
15
+
16
+ def initialize(
17
+ dependencies:,
18
+ project_name: nil
19
+ )
20
+ @dependencies = dependencies
21
+ @project_name = project_name
22
+ end
23
+
24
+ def eql?(other)
25
+ FIELDS.all? { |f| public_send(f) == other.public_send(f) }
26
+ end
27
+ alias == eql?
28
+
29
+ def to_h
30
+ FIELDS.to_h { |f| [f, public_send(f)] }
31
+ end
32
+
33
+ def hash
34
+ FIELDS.map { |f| public_send(f) }.hash
35
+ end
36
+ end
37
+ end
@@ -20,8 +20,9 @@ module Bibliothecary
20
20
 
21
21
  def self.parse_manifest(file_contents, options: {})
22
22
  json = JSON.parse(file_contents)
23
- map_dependencies(json, "dependencies", "runtime", options.fetch(:filename, nil)) +
24
- map_dependencies(json, "devDependencies", "development", options.fetch(:filename, nil))
23
+ dependencies = map_dependencies(json, "dependencies", "runtime", options.fetch(:filename, nil)) +
24
+ map_dependencies(json, "devDependencies", "development", options.fetch(:filename, nil))
25
+ ParserResult.new(dependencies: dependencies)
25
26
  end
26
27
  end
27
28
  end
@@ -37,27 +37,31 @@ module Bibliothecary
37
37
  name: name,
38
38
  requirement: requirement,
39
39
  type: index.zero? ? "runtime" : "development",
40
- source: options.fetch(:filename, nil)
40
+ source: options.fetch(:filename, nil),
41
+ platform: platform_name
41
42
  )
42
43
  end
43
44
  end
44
45
 
45
- parsed_dependencies.flatten.compact
46
+ dependencies = parsed_dependencies.flatten.compact
47
+ ParserResult.new(dependencies: dependencies)
46
48
  end
47
49
 
48
50
  def self.parse_lockfile(file_contents, options: {})
49
51
  manifest = Tomlrb.parse(file_contents)
50
- manifest.fetch("package", []).map do |dependency|
52
+ dependencies = manifest.fetch("package", []).map do |dependency|
51
53
  next if !dependency["source"] || !dependency["source"].start_with?("registry+")
52
54
 
53
55
  Dependency.new(
54
56
  name: dependency["name"],
55
57
  requirement: dependency["version"],
56
58
  type: "runtime",
57
- source: options.fetch(:filename, nil)
59
+ source: options.fetch(:filename, nil),
60
+ platform: platform_name
58
61
  )
59
62
  end
60
63
  .compact
64
+ ParserResult.new(dependencies: dependencies)
61
65
  end
62
66
  end
63
67
  end
@@ -39,38 +39,44 @@ module Bibliothecary
39
39
 
40
40
  def self.parse_podfile_lock(file_contents, options: {})
41
41
  manifest = YAML.load file_contents
42
- manifest["PODS"].map do |row|
42
+ dependencies = manifest["PODS"].map do |row|
43
43
  pod = row.is_a?(String) ? row : row.keys.first
44
44
  match = pod.match(/(.+?)\s\((.+?)\)/i)
45
45
  Dependency.new(
46
+ platform: platform_name,
46
47
  name: match[1].split("/").first,
47
48
  requirement: match[2],
48
49
  type: "runtime",
49
50
  source: options.fetch(:filename, nil)
50
51
  )
51
52
  end.compact
53
+ ParserResult.new(dependencies: dependencies)
52
54
  end
53
55
 
54
56
  def self.parse_podspec(file_contents, options: {})
55
57
  manifest = Gemnasium::Parser.send(:podspec, file_contents)
56
- parse_ruby_manifest(manifest, options.fetch(:filename, nil))
58
+ dependencies = parse_ruby_manifest(manifest, platform_name, options.fetch(:filename, nil))
59
+ ParserResult.new(dependencies: dependencies)
57
60
  end
58
61
 
59
62
  def self.parse_podfile(file_contents, options: {})
60
63
  manifest = Gemnasium::Parser.send(:podfile, file_contents)
61
- parse_ruby_manifest(manifest, options.fetch(:filename, nil))
64
+ dependencies = parse_ruby_manifest(manifest, platform_name, options.fetch(:filename, nil))
65
+ ParserResult.new(dependencies: dependencies)
62
66
  end
63
67
 
64
68
  def self.parse_json_manifest(file_contents, options: {})
65
69
  manifest = JSON.parse(file_contents)
66
- manifest["dependencies"].inject([]) do |deps, dep|
70
+ dependencies = manifest["dependencies"].inject([]) do |deps, dep|
67
71
  deps.push(Dependency.new(
72
+ platform: platform_name,
68
73
  name: dep[0],
69
74
  requirement: dep[1],
70
75
  type: "runtime",
71
76
  source: options.fetch(:filename, nil)
72
77
  ))
73
78
  end.uniq
79
+ ParserResult.new(dependencies: dependencies)
74
80
  end
75
81
  end
76
82
  end
@@ -27,12 +27,18 @@ module Bibliothecary
27
27
  def self.parse_conda(file_contents, options: {})
28
28
  manifest = YAML.load(file_contents)
29
29
  deps = manifest["dependencies"]
30
- deps.map do |dep|
30
+ dependencies = deps.map do |dep|
31
31
  next unless dep.is_a? String # only deal with strings to skip parsing pip stuff
32
32
 
33
33
  parsed = parse_name_requirement_from_matchspec(dep)
34
- Dependency.new(**parsed, type: "runtime", source: options.fetch(:filename, nil))
34
+ Dependency.new(
35
+ **parsed,
36
+ type: "runtime",
37
+ source: options.fetch(:filename, nil),
38
+ platform: platform_name
39
+ )
35
40
  end.compact
41
+ ParserResult.new(dependencies: dependencies)
36
42
  end
37
43
 
38
44
  def self.parse_name_requirement_from_matchspec(matchspec)
@@ -25,14 +25,16 @@ module Bibliothecary
25
25
 
26
26
  def self.parse_json_manifest(file_contents, options: {})
27
27
  manifest = JSON.parse file_contents
28
- manifest["prereqs"].map do |_group, deps|
28
+ dependencies = manifest["prereqs"].map do |_group, deps|
29
29
  map_dependencies(deps, "requires", "runtime", options.fetch(:filename, nil))
30
30
  end.flatten
31
+ ParserResult.new(dependencies: dependencies)
31
32
  end
32
33
 
33
34
  def self.parse_yaml_manifest(file_contents, options: {})
34
35
  manifest = YAML.load file_contents
35
- map_dependencies(manifest, "requires", "runtime", options.fetch(:filename, nil))
36
+ dependencies = map_dependencies(manifest, "requires", "runtime", options.fetch(:filename, nil))
37
+ ParserResult.new(dependencies: dependencies)
36
38
  end
37
39
  end
38
40
  end
@@ -24,10 +24,11 @@ module Bibliothecary
24
24
 
25
25
  def self.parse_description(file_contents, options: {})
26
26
  manifest = DebControl::ControlFileBase.parse(file_contents)
27
- parse_section(manifest, "Depends", options.fetch(:filename, nil)) +
28
- parse_section(manifest, "Imports", options.fetch(:filename, nil)) +
29
- parse_section(manifest, "Suggests", options.fetch(:filename, nil)) +
30
- parse_section(manifest, "Enhances", options.fetch(:filename, nil))
27
+ dependencies = parse_section(manifest, "Depends", options.fetch(:filename, nil)) +
28
+ parse_section(manifest, "Imports", options.fetch(:filename, nil)) +
29
+ parse_section(manifest, "Suggests", options.fetch(:filename, nil)) +
30
+ parse_section(manifest, "Enhances", options.fetch(:filename, nil))
31
+ ParserResult.new(dependencies: dependencies)
31
32
  end
32
33
 
33
34
  def self.parse_section(manifest, name, source = nil)
@@ -40,7 +41,8 @@ module Bibliothecary
40
41
  name: dep[1],
41
42
  requirement: dep[2],
42
43
  type: name.downcase,
43
- source: source
44
+ source: source,
45
+ platform: platform_name
44
46
  )
45
47
  end
46
48
  end
@@ -25,7 +25,9 @@ module Bibliothecary
25
25
  add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
26
26
 
27
27
  def self.parse_sdl_manifest(file_contents, options: {})
28
- SdlParser.new(:runtime, file_contents, options.fetch(:filename, nil)).dependencies
28
+ ParserResult.new(
29
+ dependencies: SdlParser.new(:runtime, file_contents, platform_name, options.fetch(:filename, nil)).dependencies
30
+ )
29
31
  end
30
32
  end
31
33
  end
@@ -25,14 +25,16 @@ module Bibliothecary
25
25
 
26
26
  def self.parse_json_lock(file_contents, options: {})
27
27
  manifest = JSON.parse file_contents
28
- manifest.map do |name, requirement|
28
+ dependencies = manifest.map do |name, requirement|
29
29
  Dependency.new(
30
30
  name: name,
31
31
  requirement: requirement,
32
32
  type: "runtime",
33
- source: options.fetch(:filename, nil)
33
+ source: options.fetch(:filename, nil),
34
+ platform: platform_name
34
35
  )
35
36
  end
37
+ ParserResult.new(dependencies: dependencies)
36
38
  end
37
39
  end
38
40
  end
@@ -78,7 +78,8 @@ module Bibliothecary
78
78
 
79
79
  def self.parse_godep_json(file_contents, options: {})
80
80
  manifest = JSON.parse file_contents
81
- map_dependencies(manifest, "Deps", "ImportPath", "Rev", "runtime", options.fetch(:filename, nil))
81
+ dependencies = map_dependencies(manifest, "Deps", "ImportPath", "Rev", "runtime", options.fetch(:filename, nil))
82
+ ParserResult.new(dependencies: dependencies)
82
83
  end
83
84
 
84
85
  def self.parse_gpm(file_contents, options: {})
@@ -91,48 +92,55 @@ module Bibliothecary
91
92
  name: match[1].strip,
92
93
  requirement: match[2].strip,
93
94
  type: "runtime",
94
- source: options.fetch(:filename, nil)
95
+ source: options.fetch(:filename, nil),
96
+ platform: platform_name
95
97
  )
96
98
  end
97
- deps
99
+ ParserResult.new(dependencies: deps)
98
100
  end
99
101
 
100
102
  def self.parse_govendor(file_contents, options: {})
101
103
  manifest = JSON.parse file_contents
102
- map_dependencies(manifest, "package", "path", "revision", "runtime", options.fetch(:filename, nil))
104
+ dependencies = map_dependencies(manifest, "package", "path", "revision", "runtime", options.fetch(:filename, nil))
105
+ ParserResult.new(dependencies: dependencies)
103
106
  end
104
107
 
105
108
  def self.parse_glide_yaml(file_contents, options: {})
106
109
  manifest = YAML.load file_contents
107
- map_dependencies(manifest, "import", "package", "version", "runtime", options.fetch(:filename, nil)) +
108
- map_dependencies(manifest, "devImports", "package", "version", "development", options.fetch(:filename, nil))
110
+ dependencies = map_dependencies(manifest, "import", "package", "version", "runtime", options.fetch(:filename, nil)) +
111
+ map_dependencies(manifest, "devImports", "package", "version", "development", options.fetch(:filename, nil))
112
+ ParserResult.new(dependencies: dependencies)
109
113
  end
110
114
 
111
115
  def self.parse_glide_lockfile(file_contents, options: {})
112
116
  # glide.lock files contain an "updated" Time field, but Ruby 3.2+ requires us to safelist that class
113
117
  manifest = YAML.load file_contents, permitted_classes: [Time]
114
- map_dependencies(manifest, "imports", "name", "version", "runtime", options.fetch(:filename, nil))
118
+ dependencies = map_dependencies(manifest, "imports", "name", "version", "runtime", options.fetch(:filename, nil))
119
+ ParserResult.new(dependencies: dependencies)
115
120
  end
116
121
 
117
122
  def self.parse_gb_manifest(file_contents, options: {})
118
123
  manifest = JSON.parse file_contents
119
- map_dependencies(manifest, "dependencies", "importpath", "revision", "runtime", options.fetch(:filename, nil))
124
+ dependencies = map_dependencies(manifest, "dependencies", "importpath", "revision", "runtime", options.fetch(:filename, nil))
125
+ ParserResult.new(dependencies: dependencies)
120
126
  end
121
127
 
122
128
  def self.parse_dep_toml(file_contents, options: {})
123
129
  manifest = Tomlrb.parse file_contents
124
- map_dependencies(manifest, "constraint", "name", "version", "runtime", options.fetch(:filename, nil))
130
+ dependencies = map_dependencies(manifest, "constraint", "name", "version", "runtime", options.fetch(:filename, nil))
131
+ ParserResult.new(dependencies: dependencies)
125
132
  end
126
133
 
127
134
  def self.parse_dep_lockfile(file_contents, options: {})
128
135
  manifest = Tomlrb.parse file_contents
129
- map_dependencies(manifest, "projects", "name", "revision", "runtime", options.fetch(:filename, nil))
136
+ dependencies = map_dependencies(manifest, "projects", "name", "revision", "runtime", options.fetch(:filename, nil))
137
+ ParserResult.new(dependencies: dependencies)
130
138
  end
131
139
 
132
140
  def self.parse_go_mod(file_contents, options: {})
133
141
  categorized_deps = parse_go_mod_categorized_deps(file_contents, options.fetch(:filename, nil))
134
142
 
135
- categorized_deps["require"]
143
+ dependencies = categorized_deps["require"]
136
144
  .map do |dep|
137
145
  # NOTE: A "replace" directive doesn't add the dep to the module graph unless the original dep is also in a "require" directive,
138
146
  # so we need to track down replacements here and use those instead of the originals, if present.
@@ -148,6 +156,7 @@ module Bibliothecary
148
156
 
149
157
  replaced_dep || dep
150
158
  end
159
+ ParserResult.new(dependencies: dependencies)
151
160
  end
152
161
 
153
162
  def self.parse_go_mod_categorized_deps(file_contents, source)
@@ -186,14 +195,16 @@ module Bibliothecary
186
195
  name: match[1].strip,
187
196
  requirement: match[2].strip.split("/").first,
188
197
  type: "runtime",
189
- source: options.fetch(:filename, nil)
198
+ source: options.fetch(:filename, nil),
199
+ platform: platform_name
190
200
  )
191
201
  end
192
- deps.uniq
202
+ dependencies = deps.uniq
203
+ ParserResult.new(dependencies: dependencies)
193
204
  end
194
205
 
195
206
  def self.parse_go_resolved(file_contents, options: {})
196
- JSON.parse(file_contents)
207
+ dependencies = JSON.parse(file_contents)
197
208
  .reject { |dep| dep["Main"] == "true" }
198
209
  .map do |dep|
199
210
  if dep["Replace"].is_a?(String) && dep["Replace"] != "<nil>" && dep["Replace"] != ""
@@ -203,19 +214,21 @@ module Bibliothecary
203
214
  name, requirement = dep["Replace"].split(" ", 2)
204
215
  requirement = "*" if requirement.to_s.strip == ""
205
216
  Dependency.new(
206
- name: name, requirement: requirement, original_name: dep["Path"], original_requirement: dep["Version"], type: dep.fetch("Scope", "runtime"), source: options.fetch(:filename, nil)
217
+ platform: platform_name, name: name, requirement: requirement, original_name: dep["Path"], original_requirement: dep["Version"], type: dep.fetch("Scope", "runtime"), source: options.fetch(:filename, nil)
207
218
  )
208
219
  else
209
220
  Dependency.new(
210
- name: dep["Path"], requirement: dep["Version"], type: dep.fetch("Scope", "runtime"), source: options.fetch(:filename, nil)
221
+ platform: platform_name, name: dep["Path"], requirement: dep["Version"], type: dep.fetch("Scope", "runtime"), source: options.fetch(:filename, nil)
211
222
  )
212
223
  end
213
224
  end
225
+ ParserResult.new(dependencies: dependencies)
214
226
  end
215
227
 
216
228
  def self.map_dependencies(manifest, attr_name, dep_attr_name, version_attr_name, type, source = nil)
217
229
  manifest.fetch(attr_name, []).map do |dependency|
218
230
  Dependency.new(
231
+ platform: platform_name,
219
232
  name: dependency[dep_attr_name],
220
233
  requirement: dependency[version_attr_name],
221
234
  type: type,
@@ -231,6 +244,7 @@ module Bibliothecary
231
244
  replacement_dep = line.split(GOMOD_REPLACEMENT_SEPARATOR_REGEXP, 2).last
232
245
  replacement_match = replacement_dep.match(GOMOD_DEP_REGEXP)
233
246
  Dependency.new(
247
+ platform: platform_name,
234
248
  original_name: match[:name],
235
249
  original_requirement: match[:requirement],
236
250
  name: replacement_match[:name],
@@ -241,6 +255,7 @@ module Bibliothecary
241
255
  )
242
256
  when "retract"
243
257
  Dependency.new(
258
+ platform: platform_name,
244
259
  name: match[:name],
245
260
  requirement: match[:requirement],
246
261
  type: "runtime",
@@ -250,6 +265,7 @@ module Bibliothecary
250
265
  )
251
266
  else
252
267
  Dependency.new(
268
+ platform: platform_name,
253
269
  name: match[:name],
254
270
  requirement: match[:requirement],
255
271
  type: "runtime",
@@ -36,10 +36,11 @@ module Bibliothecary
36
36
  name: name,
37
37
  requirement: reqs,
38
38
  type: "runtime",
39
- source: options.fetch(:filename, nil)
39
+ source: options.fetch(:filename, nil),
40
+ platform: platform_name
40
41
  )
41
42
  end
42
- deps
43
+ ParserResult.new(dependencies: deps)
43
44
  end
44
45
  end
45
46
  end