package_json 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,81 @@
1
+ class PackageJson
2
+ module Managers
3
+ class YarnBerryLike < Base
4
+ def initialize(package_json)
5
+ super(package_json, binary_name: "yarn")
6
+ end
7
+
8
+ # Installs the dependencies specified in the `package.json` file
9
+ def install(frozen: false)
10
+ raw("install", with_frozen_flag(frozen))
11
+ end
12
+
13
+ # Provides the "native" command for installing dependencies with this package manager for embedding into scripts
14
+ def native_install_command(frozen: false)
15
+ build_full_cmd("install", with_frozen_flag(frozen))
16
+ end
17
+
18
+ # Adds the given packages
19
+ def add(packages, type: :production)
20
+ raw("add", [package_type_install_flag(type)].compact + packages)
21
+ end
22
+
23
+ # Removes the given packages
24
+ def remove(packages)
25
+ raw("remove", packages)
26
+ end
27
+
28
+ # Runs the script assuming it is defined in the `package.json` file
29
+ def run(
30
+ script_name,
31
+ args = [],
32
+ silent: false
33
+ )
34
+ raw("run", build_run_args(script_name, args, _silent: silent))
35
+ end
36
+
37
+ # Provides the "native" command for running the script with args for embedding into shell scripts
38
+ def native_run_command(
39
+ script_name,
40
+ args = [],
41
+ silent: false
42
+ )
43
+ build_full_cmd("run", build_run_args(script_name, args, _silent: silent))
44
+ end
45
+
46
+ def native_exec_command(
47
+ script_name,
48
+ args = []
49
+ )
50
+ build_full_cmd("exec", build_run_args(script_name, args, _silent: false))
51
+ end
52
+
53
+ private
54
+
55
+ def build_run_args(script_name, args, _silent:)
56
+ [script_name, *args]
57
+ end
58
+
59
+ def with_frozen_flag(frozen)
60
+ return ["--immutable"] if frozen
61
+
62
+ # we make frozen lockfile behaviour consistent with the other package managers as
63
+ # yarn berry automatically enables frozen lockfile if it detects it's running in CI
64
+ ["--no-immutable"]
65
+ end
66
+
67
+ def package_type_install_flag(type)
68
+ case type
69
+ when :production
70
+ nil
71
+ when :dev
72
+ "--dev"
73
+ when :optional
74
+ "--optional"
75
+ else
76
+ raise Error, "unsupported package install type \"#{type}\""
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,95 @@
1
+ class PackageJson
2
+ module Managers
3
+ class YarnClassicLike < Base
4
+ def initialize(package_json)
5
+ super(package_json, binary_name: "yarn")
6
+ end
7
+
8
+ # Installs the dependencies specified in the `package.json` file
9
+ def install(frozen: false)
10
+ raw("install", with_frozen_flag(frozen))
11
+ end
12
+
13
+ # Provides the "native" command for installing dependencies with this package manager for embedding into scripts
14
+ def native_install_command(frozen: false)
15
+ build_full_cmd("install", with_frozen_flag(frozen))
16
+ end
17
+
18
+ # Adds the given packages
19
+ def add(packages, type: :production)
20
+ raw("add", [package_type_install_flag(type)].compact + packages)
21
+ end
22
+
23
+ # Removes the given packages
24
+ def remove(packages)
25
+ raw("remove", packages)
26
+ end
27
+
28
+ # Runs the script assuming it is defined in the `package.json` file
29
+ def run(
30
+ script_name,
31
+ args = [],
32
+ silent: false
33
+ )
34
+ raw("run", build_run_args(script_name, args, silent: silent))
35
+ end
36
+
37
+ # Provides the "native" command for running the script with args for embedding into shell scripts
38
+ def native_run_command(
39
+ script_name,
40
+ args = [],
41
+ silent: false
42
+ )
43
+ build_full_cmd("run", build_run_args(script_name, args, silent: silent))
44
+ end
45
+
46
+ def native_exec_command(
47
+ script_name,
48
+ args = []
49
+ )
50
+ [File.join(fetch_bin_path, script_name), *args]
51
+ end
52
+
53
+ private
54
+
55
+ def fetch_bin_path
56
+ require "open3"
57
+
58
+ command = build_full_cmd("bin", []).join(" ")
59
+ stdout, stderr, status = Open3.capture3(command, chdir: @package_json.directory)
60
+
61
+ unless status.success?
62
+ raise PackageJson::Error, "#{command} failed with exit code #{status.exitstatus}: #{stderr}"
63
+ end
64
+
65
+ stdout.chomp
66
+ end
67
+
68
+ def build_run_args(script_name, args, silent:)
69
+ args = [script_name, *args]
70
+
71
+ args.unshift("--silent") if silent
72
+ args
73
+ end
74
+
75
+ def with_frozen_flag(frozen)
76
+ return ["--frozen-lockfile"] if frozen
77
+
78
+ []
79
+ end
80
+
81
+ def package_type_install_flag(type)
82
+ case type
83
+ when :production
84
+ nil
85
+ when :dev
86
+ "--dev"
87
+ when :optional
88
+ "--optional"
89
+ else
90
+ raise Error, "unsupported package install type \"#{type}\""
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PackageJson
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "package_json/managers/base"
4
+ require_relative "package_json/managers/bun_like"
5
+ require_relative "package_json/managers/npm_like"
6
+ require_relative "package_json/managers/pnpm_like"
7
+ require_relative "package_json/managers/yarn_berry_like"
8
+ require_relative "package_json/managers/yarn_classic_like"
9
+ require_relative "package_json/version"
10
+ require "json"
11
+
12
+ class PackageJson
13
+ class Error < StandardError; end
14
+
15
+ class NotImplementedError < Error; end
16
+
17
+ attr_reader :manager, :directory
18
+
19
+ def self.fetch_default_fallback_manager
20
+ ENV.fetch("PACKAGE_JSON_FALLBACK_MANAGER", "npm").to_sym
21
+ end
22
+
23
+ def self.read(path_to_directory = Dir.pwd, fallback_manager: PackageJson.fetch_default_fallback_manager)
24
+ unless File.exist?("#{path_to_directory}/package.json")
25
+ raise Error, "#{path_to_directory} does not contain a package.json"
26
+ end
27
+
28
+ new(path_to_directory, fallback_manager: fallback_manager)
29
+ end
30
+
31
+ def initialize(path_to_directory = Dir.pwd, fallback_manager: PackageJson.fetch_default_fallback_manager)
32
+ @directory = File.absolute_path(path_to_directory)
33
+
34
+ existed = ensure_package_json_exists
35
+
36
+ @manager = new_package_manager(determine_package_manager(fallback_manager))
37
+
38
+ # only record the packageManager automatically if we created the package.json
39
+ record_package_manager! unless existed
40
+ end
41
+
42
+ def fetch(key, default = (no_default_set_by_user = true; nil))
43
+ contents = read_package_json
44
+
45
+ if no_default_set_by_user
46
+ contents.fetch(key)
47
+ else
48
+ contents.fetch(key, default)
49
+ end
50
+ end
51
+
52
+ # Merges the hash returned by the passed block into the existing content of the `package.json`
53
+ def merge!
54
+ pj = read_package_json
55
+
56
+ write_package_json(pj.merge(yield read_package_json))
57
+ end
58
+
59
+ def delete!(key)
60
+ pj = read_package_json
61
+
62
+ value = pj.delete(key)
63
+
64
+ write_package_json(pj)
65
+
66
+ value
67
+ end
68
+
69
+ def record_package_manager!
70
+ merge! { { "packageManager" => "#{manager.binary}@#{manager.version}" } }
71
+ end
72
+
73
+ private
74
+
75
+ def determine_package_manager(fallback_manager)
76
+ package_manager = fetch("packageManager", nil)
77
+
78
+ return fallback_manager if package_manager.nil?
79
+
80
+ name, version = package_manager.split("@")
81
+
82
+ if name == "yarn"
83
+ raise Error, "a major version must be present for Yarn" if version.nil? || version.empty?
84
+ return :yarn_classic if version.start_with?("1")
85
+
86
+ return :yarn_berry
87
+ end
88
+
89
+ name.to_sym
90
+ end
91
+
92
+ def new_package_manager(package_manager_name)
93
+ case package_manager_name
94
+ when :npm
95
+ PackageJson::Managers::NpmLike.new(self)
96
+ when :yarn_berry
97
+ PackageJson::Managers::YarnBerryLike.new(self)
98
+ when :yarn_classic
99
+ PackageJson::Managers::YarnClassicLike.new(self)
100
+ when :pnpm
101
+ PackageJson::Managers::PnpmLike.new(self)
102
+ when :bun
103
+ PackageJson::Managers::BunLike.new(self)
104
+ else
105
+ raise Error, "unsupported package manager \"#{package_manager_name}\""
106
+ end
107
+ end
108
+
109
+ def package_json_path
110
+ "#{directory}/package.json"
111
+ end
112
+
113
+ def ensure_package_json_exists
114
+ return true if File.exist?(package_json_path)
115
+
116
+ write_package_json({})
117
+
118
+ false
119
+ end
120
+
121
+ def read_package_json
122
+ JSON.parse(File.read(package_json_path))
123
+ end
124
+
125
+ def write_package_json(contents)
126
+ File.write(package_json_path, "#{JSON.pretty_generate(contents)}\n")
127
+ end
128
+ end
@@ -0,0 +1,57 @@
1
+ class PackageJson
2
+ module Managers
3
+ class Base
4
+ attr_reader binary: String
5
+
6
+ def initialize: (PackageJson package_json, binary_name: String) -> self
7
+
8
+ def version: () -> String
9
+
10
+ def install: (?frozen: bool) -> (bool | nil)
11
+
12
+ def install!: (?frozen: bool) -> void
13
+
14
+ def native_install_command: (?frozen: bool) -> Array[String]
15
+
16
+ def add: (Array[String] packages, ?type: :production | :dev | :optional) -> (bool | nil)
17
+
18
+ def add!: (Array[String] packages, ?type: :production | :dev | :optional) -> void
19
+
20
+ def remove: (Array[String] packages) -> (bool | nil)
21
+
22
+ def remove!: (Array[String] packages) -> void
23
+
24
+ def run: (
25
+ String script_name,
26
+ ?Array[String] args,
27
+ ?silent: bool
28
+ ) -> (bool | nil)
29
+
30
+ def run!: (
31
+ String script_name,
32
+ ?Array[String] args,
33
+ ?silent: bool
34
+ ) -> void
35
+
36
+ def native_run_command: (
37
+ String script_name,
38
+ ?Array[String] args,
39
+ ?silent: bool
40
+ ) -> Array[String]
41
+
42
+ def native_exec_command: (
43
+ String script_name,
44
+ ?Array[String] args
45
+ ) -> Array[String]
46
+
47
+ private
48
+
49
+ @binary: String
50
+ @package_json: PackageJson
51
+
52
+ def build_full_cmd: (String sub_cmd, Array[String] args) -> Array[String]
53
+
54
+ def raw: (String sub_cmd, Array[String] args) -> (bool | nil)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,19 @@
1
+ class PackageJson
2
+ module Managers
3
+ class BunLike < Base
4
+ def initialize: (PackageJson package_json) -> self
5
+
6
+ private
7
+
8
+ def build_run_args: (
9
+ String script_name,
10
+ Array[String] args,
11
+ _silent: bool
12
+ ) -> Array[String]
13
+
14
+ def with_frozen_flag: (bool frozen) -> Array[String]
15
+
16
+ def package_type_install_flag: (Symbol type) -> (String | nil)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ class PackageJson
2
+ module Managers
3
+ class NpmLike < Base
4
+ def initialize: (PackageJson package_json) -> self
5
+
6
+ private
7
+
8
+ def build_run_args: (
9
+ String script_name,
10
+ Array[String] args,
11
+ silent: bool
12
+ ) -> Array[String]
13
+
14
+ def package_type_install_flag: (Symbol type) -> String
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ class PackageJson
2
+ module Managers
3
+ class PnpmLike < Base
4
+ def initialize: (PackageJson package_json) -> self
5
+
6
+ private
7
+
8
+ def build_run_args: (
9
+ String script_name,
10
+ Array[String] args,
11
+ silent: bool
12
+ ) -> Array[String]
13
+
14
+ def with_frozen_flag: (bool frozen) -> Array[String]
15
+
16
+ def package_type_install_flag: (Symbol type) -> String
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ class PackageJson
2
+ module Managers
3
+ class YarnBerryLike < Base
4
+ def initialize: (PackageJson package_json) -> self
5
+
6
+ private
7
+
8
+ def build_run_args: (
9
+ String script_name,
10
+ Array[String] args,
11
+ _silent: bool
12
+ ) -> Array[String]
13
+
14
+ def with_frozen_flag: (bool frozen) -> Array[String]
15
+
16
+ def package_type_install_flag: (Symbol type) -> (String | nil)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ class PackageJson
2
+ module Managers
3
+ class YarnClassicLike < Base
4
+ def initialize: (PackageJson package_json) -> self
5
+
6
+ private
7
+
8
+ def fetch_bin_path: () -> String
9
+
10
+ def build_run_args: (
11
+ String script_name,
12
+ Array[String] args,
13
+ silent: bool
14
+ ) -> Array[String]
15
+
16
+ def with_frozen_flag: (bool frozen) -> Array[String]
17
+
18
+ def package_type_install_flag: (Symbol type) -> (String | nil)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,38 @@
1
+ class PackageJson
2
+ VERSION: String
3
+
4
+ class Error < StandardError
5
+ end
6
+
7
+ class NotImplementedError < Error
8
+ end
9
+
10
+ attr_reader manager: Managers::Base
11
+ attr_reader directory: String
12
+
13
+ def self.fetch_default_fallback_manager: () -> Symbol
14
+
15
+ def self.read: (?String path_to_directory, ?package_manager: (:npm | :yarn_berry | :yarn_classic | :pnpm | :bun)) -> PackageJson
16
+
17
+ def initialize: (?String path_to_directory, ?package_manager: (:npm | :yarn_berry | :yarn_classic | :pnpm | :bun)) -> PackageJson
18
+
19
+ def fetch: (String key, ?untyped default) -> (String | Hash[String, untyped] | Array[untyped])
20
+
21
+ def merge!: () { (Hash[String | Symbol, untyped]) -> Hash[String | Symbol, untyped] } -> void
22
+
23
+ private
24
+
25
+ @directory: String
26
+
27
+ def determine_package_manager: (Symbol fallback_manager) -> Symbol
28
+
29
+ def new_package_manager: (Symbol package_manager_name) -> Managers::Base
30
+
31
+ def package_json_path: () -> String
32
+
33
+ def ensure_package_json_exists: ((:npm | :yarn_berry | :yarn_classic | :pnpm | :bun) package_manager) -> void
34
+
35
+ def read_package_json: () -> void
36
+
37
+ def write_package_json: (_ToJson contents) -> void
38
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: package_json
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Gareth Jones
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-09-15 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - open-source@ackama.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".editorconfig"
21
+ - ".prettierignore"
22
+ - ".prettierrc.json"
23
+ - ".rspec"
24
+ - ".rubocop.yml"
25
+ - ".ruby-version"
26
+ - CHANGELOG.md
27
+ - CODE_OF_CONDUCT.md
28
+ - Gemfile
29
+ - Gemfile.lock
30
+ - LICENSE.txt
31
+ - README.md
32
+ - Rakefile
33
+ - lib/package_json.rb
34
+ - lib/package_json/managers/base.rb
35
+ - lib/package_json/managers/bun_like.rb
36
+ - lib/package_json/managers/npm_like.rb
37
+ - lib/package_json/managers/pnpm_like.rb
38
+ - lib/package_json/managers/yarn_berry_like.rb
39
+ - lib/package_json/managers/yarn_classic_like.rb
40
+ - lib/package_json/version.rb
41
+ - sig/package_json.rbs
42
+ - sig/package_json/managers/base.rbs
43
+ - sig/package_json/managers/bun_like.rbs
44
+ - sig/package_json/managers/npm_like.rbs
45
+ - sig/package_json/managers/pnpm_like.rbs
46
+ - sig/package_json/managers/yarn_berry_like.rbs
47
+ - sig/package_json/managers/yarn_classic_like.rbs
48
+ homepage: https://github.com/G-Rath/package_json
49
+ licenses:
50
+ - MIT
51
+ metadata:
52
+ homepage_uri: https://github.com/G-Rath/package_json
53
+ source_code_uri: https://github.com/G-Rath/package_json
54
+ changelog_uri: https://github.com/G-Rath/package_json
55
+ rubygems_mfa_required: 'true'
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 2.6.0
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ requirements: []
71
+ rubygems_version: 3.3.26
72
+ signing_key:
73
+ specification_version: 4
74
+ summary: The missing gem for managing package.json files in Ruby
75
+ test_files: []