1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
# frozen_string_literal: true
module Packages
module Npm
class GenerateMetadataService
include API::Helpers::RelatedResourcesHelpers
# Allowed fields are those defined in the abbreviated form
# defined here: https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md#abbreviated-version-object
# except: name, version, dist, dependencies and xDependencies. Those are generated by this service.
PACKAGE_JSON_ALLOWED_FIELDS = %w[deprecated bin directories dist engines _hasShrinkwrap].freeze
def initialize(name, packages)
@name = name
@packages = packages
end
def execute(only_dist_tags: false)
ServiceResponse.success(payload: metadata(only_dist_tags))
end
private
attr_reader :name, :packages
def metadata(only_dist_tags)
result = { dist_tags: dist_tags }
unless only_dist_tags
result[:name] = name
result[:versions] = versions
end
result
end
def versions
package_versions = {}
packages.each_batch do |relation|
batched_packages = relation.including_dependency_links
.preload_files
.preload_npm_metadatum
batched_packages.each do |package|
package_file = package.installable_package_files.last
next unless package_file
package_versions[package.version] = build_package_version(package, package_file)
end
end
package_versions
end
def dist_tags
build_package_tags.tap { |t| t['latest'] ||= sorted_versions.last }
end
def build_package_tags
package_tags.to_h { |tag| [tag.name, tag.package.version] }
end
def build_package_version(package, package_file)
abbreviated_package_json(package).merge(
name: package.name,
version: package.version,
dist: {
shasum: package_file.file_sha1,
tarball: tarball_url(package, package_file)
}
).tap do |package_version|
package_version.merge!(build_package_dependencies(package))
end
end
def tarball_url(package, package_file)
expose_url api_v4_projects_packages_npm_package_name___file_name_path(
{ id: package.project_id, package_name: package.name, file_name: package_file.file_name }, true
)
end
def build_package_dependencies(package)
dependencies = Hash.new { |h, key| h[key] = {} }
package.dependency_links.each do |dependency_link|
dependency = dependency_link.dependency
dependencies[dependency_link.dependency_type][dependency.name] = dependency.version_pattern
end
dependencies
end
def sorted_versions
versions = packages.pluck_versions.compact
VersionSorter.sort(versions)
end
def package_tags
Packages::Tag.for_package_ids(packages)
.preload_package
end
def abbreviated_package_json(package)
json = package.npm_metadatum&.package_json || {}
json.slice(*PACKAGE_JSON_ALLOWED_FIELDS)
end
end
end
end
|