package_json 0.1.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.
@@ -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: []