package_json 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3f527631df066948ba8540040c1979df5555cf1493a2c9e9b2b27bb07fcab8b6
4
- data.tar.gz: cad2ae8ff9ec1502d0c9674416a036740394e61a834887b8abdebb038ade2cd0
3
+ metadata.gz: f55805d478e11aa4c918eb7b8acd0b1dc2dfead0488cc931f50a10a1b0b4ea18
4
+ data.tar.gz: 727ce06575bfe624628999e5ad6ef18b07caf10c4bad32af75a8fb78837b4f6d
5
5
  SHA512:
6
- metadata.gz: 1528327c30b61584871ced376ee3d2baf656c7a5d46b053f901e66bc296cfeee432145b24fafc5c92c4cac17c16111594a834aac4e54520796362992c42a842d
7
- data.tar.gz: 624ca23fea5c8afd0758f3240677630a2f4c28bc432a26242d23a990e3efa58d6a5727f7f521c171644fbd6effa41483a79e217bfb2608de9700009bc4ace60c
6
+ metadata.gz: 876cae7108678cb22b42c15e8fa68a65e301235b4420309a077410dc06fc311a531335d0d5382c581477d70e2cd96dabc5f7177b2be05c05f7b9d623ae19ef97
7
+ data.tar.gz: f91171d95c197651ee4257d0beb728d9b5c504cd2d3290a8bfae5a36d1d18163108ec119a17c04408c3bf9c9c7fec0da8600b909a6f44989f9b4c8b477bac8ff
@@ -0,0 +1,255 @@
1
+ # Update Changelog
2
+
3
+ You are helping to add an entry to the CHANGELOG.md file for the PackageJson
4
+ project.
5
+
6
+ ## Critical Requirements
7
+
8
+ 1. **User-visible changes only**: Only add changelog entries for user-visible
9
+ changes:
10
+ - New features
11
+ - Bug fixes
12
+ - Breaking changes
13
+ - Deprecations
14
+ - Performance improvements
15
+ - Security fixes
16
+ - Changes to public APIs or configuration options
17
+
18
+ 2. **Do NOT add entries for**:
19
+ - Linting fixes
20
+ - Code formatting
21
+ - Internal refactoring
22
+ - Test updates
23
+ - Documentation fixes (unless they fix incorrect docs about behavior)
24
+ - CI/CD changes
25
+
26
+ ## Formatting Requirements
27
+
28
+ ### Entry Format
29
+
30
+ Each changelog entry MUST follow this exact format:
31
+
32
+ ```markdown
33
+ - **Bold description of change**.
34
+ [PR 1818](https://github.com/shakacode/package_json/pull/1818) by
35
+ [username](https://github.com/username). Optional additional context or
36
+ details.
37
+ ```
38
+
39
+ **Important formatting rules**:
40
+
41
+ - Start with a dash and space: `- `
42
+ - Use **bold** for the main description
43
+ - End the bold description with a period before the link
44
+ - Always link to the PR:
45
+ `[PR 1818](https://github.com/shakacode/package_json/pull/1818)` - **NO hash
46
+ symbol**
47
+ - Always link to the author: `by [username](https://github.com/username)`
48
+ - End with a period after the author link
49
+ - Additional details can be added after the main entry, using proper indentation
50
+ for multi-line entries
51
+
52
+ ### Breaking Changes Format
53
+
54
+ For breaking changes, use this format:
55
+
56
+ ```markdown
57
+ - **Feature Name**: Description of the breaking change. See migration guide
58
+ below. [PR 1818](https://github.com/shakacode/package_json/pull/1818) by
59
+ [username](https://github.com/username).
60
+
61
+ **Migration Guide:**
62
+
63
+ 1. Step one
64
+ 2. Step two
65
+ ```
66
+
67
+ ### Category Organization
68
+
69
+ Entries should be organized under these section headings. The project uses both
70
+ standard and custom headings:
71
+
72
+ **Standard headings** (from keepachangelog.com) - use these for most changes:
73
+
74
+ - `#### Added` - New features
75
+ - `#### Changed` - Changes to existing functionality
76
+ - `#### Deprecated` - Deprecation notices
77
+ - `#### Removed` - Removed features
78
+ - `#### Fixed` - Bug fixes
79
+ - `#### Security` - Security-related changes
80
+ - `#### Improved` - Improvements to existing features
81
+
82
+ **Custom headings** (project-specific) - use sparingly when standard headings
83
+ don't fit:
84
+
85
+ - `#### Breaking Changes` - Breaking changes with migration guides
86
+ - `#### Performance` - Performance improvements
87
+
88
+ **Prefer standard headings.** Only use custom headings when the change needs
89
+ more specific categorization.
90
+
91
+ **Only include section headings that have entries.**
92
+
93
+ ### Version Management
94
+
95
+ After adding entries, use the rake task to manage version headers:
96
+
97
+ ```bash
98
+ bundle exec rake update_changelog
99
+ ```
100
+
101
+ This will:
102
+
103
+ - Add headers for the new version
104
+ - Update version diff links at the bottom of the file
105
+
106
+ ## Process
107
+
108
+ ### For Regular Changelog Updates
109
+
110
+ 1. **Determine the correct version tag to compare against**:
111
+ - First, check the tag dates:
112
+ `git log --tags --simplify-by-decoration --pretty="format:%ai %d" | head -10`
113
+ - Find the latest version tag and its date
114
+ - Compare main branch date to the tag date
115
+ - If the tag is NEWER than main, it means main needs to be updated to include
116
+ the tag's commits
117
+ - **CRITICAL**: Always use `git log TAG..BRANCH` to find commits that are in
118
+ the tag but not in the branch, as the tag may be ahead
119
+
120
+ 2. **Check commits and version boundaries**:
121
+ - Run `git log --oneline LAST_TAG..main` to see commits since the last
122
+ release
123
+ - Also check `git log --oneline main..LAST_TAG` to see if the tag is ahead of
124
+ main
125
+ - If the tag is ahead, entries in "Unreleased" section may actually belong to
126
+ that tagged version
127
+ - Identify which commits contain user-visible changes
128
+ - Extract PR numbers and author information from commit messages
129
+ - **Never ask the user for PR details** - get them from the git history
130
+
131
+ 3. **Validate** that changes are user-visible (per the criteria above). If not
132
+ user-visible, skip those commits.
133
+
134
+ 4. **Read the current CHANGELOG.md** to understand the existing structure and
135
+ formatting.
136
+
137
+ 5. **Determine where entries should go**:
138
+ - If the latest version tag is NEWER than main branch, move entries from
139
+ "Unreleased" to that version section
140
+ - If main is ahead of the latest tag, add new entries to "Unreleased"
141
+ - Always verify the version date in CHANGELOG.md matches the actual tag date
142
+
143
+ 6. **Add or move entries** to the appropriate section under appropriate category
144
+ headings.
145
+ - **CRITICAL**: When moving entries from "Unreleased" to a version section,
146
+ merge them with existing entries under the same category heading
147
+ - **NEVER create duplicate section headings** (e.g., don't create two "###
148
+ Fixed" sections)
149
+ - If the version section already has a category heading (e.g., "### Fixed"),
150
+ add the moved entries to that existing section
151
+ - Maintain the category order as defined above
152
+
153
+ 7. **Verify formatting**:
154
+ - Bold description with period
155
+ - Proper PR link (NO hash symbol)
156
+ - Proper author link
157
+ - Consistent with existing entries
158
+ - File ends with a newline character
159
+
160
+ 8. **Run linting** after making changes:
161
+
162
+ ```bash
163
+ bundle exec rubocop
164
+ yarn run prettier
165
+ ```
166
+
167
+ 9. **Show the user** the added or moved entries and explain what was done.
168
+
169
+ ### For Beta to Non-Beta Version Release
170
+
171
+ When releasing from beta to a stable version (e.g., v1.1.0-beta.3 → v1.1.0):
172
+
173
+ 1. **Remove all beta version labels** from the changelog:
174
+ - Change `### [v1.1.0-beta.1]`, `### [v1.1.0-beta.2]`, etc. to a single
175
+ `### [v1.1.0]` section
176
+ - Combine all beta entries into the stable release section
177
+
178
+ 2. **Consolidate duplicate entries**:
179
+ - If bug fixes or changes were made to features introduced in earlier betas,
180
+ keep only the final state
181
+ - Remove redundant changelog entries for fixes to beta features
182
+ - Keep the most recent/accurate description of each change
183
+
184
+ 3. **Update version diff links** using `bundle exec rake update_changelog`
185
+
186
+ ### For New Beta Version Release
187
+
188
+ When creating a new beta version, ask the user which approach to take:
189
+
190
+ **Option 1: Process changes since last beta**
191
+
192
+ - Only add entries for commits since the previous beta version
193
+ - Maintains detailed history of what changed in each beta
194
+
195
+ **Option 2: Collapse all prior betas into current beta**
196
+
197
+ - Combine all beta changelog entries into the new beta version
198
+ - Removes previous beta version sections
199
+ - Cleaner changelog with less version noise
200
+
201
+ After the user chooses, proceed with that approach.
202
+
203
+ ## Examples
204
+
205
+ Run this command to see real formatting examples from the codebase:
206
+
207
+ ```bash
208
+ grep -A 3 "^#### " CHANGELOG.md | head -30
209
+ ```
210
+
211
+ ### Good Entry Example
212
+
213
+ ```markdown
214
+ - **New feature description**: Added helpful functionality that users will
215
+ appreciate. [PR 123](https://github.com/shakacode/package_json/pull/123) by
216
+ [username](https://github.com/username).
217
+ ```
218
+
219
+ ### Entry with Sub-bullets Example
220
+
221
+ ```markdown
222
+ - **Multi-part feature**: Added new configuration options for enhanced
223
+ functionality:
224
+ - `option_name`: Description of the option and its purpose.
225
+ [PR 123](https://github.com/shakacode/package_json/pull/123) by
226
+ [username](https://github.com/username)
227
+ - `another_option`: Description of another option.
228
+ [PR 124](https://github.com/shakacode/package_json/pull/124) by
229
+ [username](https://github.com/username)
230
+ ```
231
+
232
+ ### Breaking Change Example
233
+
234
+ ```markdown
235
+ - **Method Removal**: Several deprecated methods have been removed. If you're
236
+ using any of the following methods, you'll need to migrate:
237
+ - `old_method_one()`
238
+ - `old_method_two()`
239
+
240
+ **Migration Guide:**
241
+
242
+ To migrate:
243
+
244
+ 1. Replace `old_method_one()` with `new_method()`
245
+ 2. Update configuration to use new format
246
+ ```
247
+
248
+ ## Additional Notes
249
+
250
+ - Keep descriptions concise but informative
251
+ - Focus on the "what" and "why", not the "how"
252
+ - Use past tense for the description
253
+ - Be consistent with existing formatting in the changelog
254
+ - Always ensure the file ends with a trailing newline
255
+ - See CHANGELOG.md for additional contributor guidelines
data/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.2.0] - 2025-11-06
4
+
5
+ ### Added
6
+
7
+ - Add support for `exact` parameter in `add` method to install packages with
8
+ exact versions ([#29](https://github.com/shakacode/package_json/pull/29))
9
+
10
+ ### Fixed
11
+
12
+ - Ensure RBS for `PackageJson` class is correct
13
+ ([#39](https://github.com/shakacode/package_json/pull/39))
14
+
15
+ ## [0.1.1] - 2025-11-04
16
+
17
+ ### Changed
18
+
19
+ - Strip ANSI/CSI escape sequences when fetching `yarn bin` path
20
+ ([#31](https://github.com/shakacode/package_json/pull/31))
21
+
3
22
  ## [0.1.0] - 2023-09-15
4
23
 
5
24
  - Initial release
data/CLAUDE.md ADDED
@@ -0,0 +1,100 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with
4
+ code in this repository.
5
+
6
+ ## ⚠️ CRITICAL REQUIREMENTS
7
+
8
+ **BEFORE EVERY COMMIT/PUSH:**
9
+
10
+ 1. **ALWAYS run `bundle exec rubocop` and fix ALL violations**
11
+ 2. **ALWAYS ensure files end with a newline character**
12
+ 3. **NEVER push without running full lint check first**
13
+
14
+ These requirements are non-negotiable. CI will fail if not followed.
15
+
16
+ ## Development Commands
17
+
18
+ ### Essential Commands
19
+
20
+ - **Install dependencies**: `bundle install`
21
+ - **Run tests**: `rake spec` or `bundle exec rspec`
22
+ - **Linting** (MANDATORY BEFORE EVERY COMMIT):
23
+ - **REQUIRED**: `bundle exec rubocop` - Must pass with zero offenses
24
+ - Auto-fix RuboCop violations: `bundle exec rubocop -a`
25
+ - **⚠️ MANDATORY BEFORE GIT PUSH**: `bundle exec rubocop` and fix ALL
26
+ violations + ensure trailing newlines
27
+ - **Default task** (runs tests and rubocop): `rake`
28
+
29
+ ## Changelog
30
+
31
+ - **Update CHANGELOG.md for user-visible changes only** (features, bug fixes,
32
+ breaking changes, deprecations, performance improvements)
33
+ - **Do NOT add entries for**: linting, formatting, refactoring, tests, or
34
+ documentation fixes
35
+ - **Format**:
36
+ `[PR 123](https://github.com/shakacode/package_json/pull/123) by [username](https://github.com/username)`
37
+ (no hash in PR number)
38
+ - **Use `/update-changelog` command** for guided changelog updates with
39
+ automatic formatting
40
+ - **Version management**: Run `bundle exec rake update_changelog` after releases
41
+ to update version headers (if task exists)
42
+ - **Examples**: Run `grep -A 3 "^#### " CHANGELOG.md | head -30` to see real
43
+ formatting examples
44
+
45
+ ## ⚠️ FORMATTING RULES
46
+
47
+ **RuboCop is the SOLE authority for formatting Ruby files. NEVER manually format
48
+ code.**
49
+
50
+ ### Standard Workflow
51
+
52
+ 1. Make code changes
53
+ 2. Run `bundle exec rubocop -a` to auto-fix violations
54
+ 3. Commit changes
55
+
56
+ ### Debugging Formatting Issues
57
+
58
+ - Check for violations: `bundle exec rubocop`
59
+ - Fix violations: `bundle exec rubocop -a`
60
+ - If CI fails on formatting, always run automated fixes, never manual fixes
61
+
62
+ ## Project Architecture
63
+
64
+ ### Core Components
65
+
66
+ This is a Ruby gem that provides a Ruby interface for managing `package.json`
67
+ files and JavaScript package managers.
68
+
69
+ #### Ruby Side (`lib/package_json/`)
70
+
71
+ - **`lib/package_json.rb`**: Main entry point and core PackageJson class
72
+ - **`lib/package_json/manager.rb`**: Base class for package manager abstraction
73
+ - **`lib/package_json/managers/`**: Specific implementations for npm, yarn,
74
+ pnpm, bun, etc.
75
+
76
+ ### Build System
77
+
78
+ - **Ruby**: Standard gemspec-based build (see `package_json.gemspec`)
79
+ - **Testing**: RSpec for Ruby tests
80
+ - **Linting**: RuboCop for Ruby
81
+
82
+ ## Type Signatures & Documentation
83
+
84
+ **This project uses RBS (Ruby Signature) files for type documentation**
85
+
86
+ Everything should be captured in the type definitions, including private
87
+ methods.
88
+
89
+ ## Important Notes
90
+
91
+ - This gem provides a "middle-level" abstraction over JavaScript package
92
+ managers
93
+ - Supports npm, yarn (classic and berry), pnpm, and bun
94
+ - Does not capture or intercept package manager output by default
95
+ - Uses `Kernel.system` under the hood for package manager operations
96
+
97
+ ## Contributing
98
+
99
+ Bug reports and pull requests are welcome on GitHub at
100
+ https://github.com/shakacode/package_json.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- package_json (0.1.0)
4
+ package_json (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -9,7 +9,7 @@ GEM
9
9
  ast (2.4.2)
10
10
  diff-lcs (1.5.0)
11
11
  docile (1.4.0)
12
- json (2.6.3)
12
+ json (2.7.6)
13
13
  parallel (1.23.0)
14
14
  parser (3.2.2.3)
15
15
  ast (~> 2.4.1)
@@ -18,7 +18,7 @@ GEM
18
18
  rainbow (3.1.1)
19
19
  rake (13.0.6)
20
20
  regexp_parser (2.8.1)
21
- rexml (3.2.6)
21
+ rexml (3.4.2)
22
22
  rspec (3.12.0)
23
23
  rspec-core (~> 3.12.0)
24
24
  rspec-expectations (~> 3.12.0)
@@ -63,6 +63,9 @@ GEM
63
63
 
64
64
  PLATFORMS
65
65
  arm64-darwin-21
66
+ arm64-darwin-22
67
+ arm64-darwin-23
68
+ arm64-darwin-24
66
69
  x64-mingw-ucrt
67
70
  x64-mingw32
68
71
  x86_64-darwin-19
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # PackageJson
2
2
 
3
+ [![License](https://img.shields.io/badge/license-mit-green.svg)](LICENSE.md)
4
+ [![Gem Version](https://badge.fury.io/rb/package_json.svg)](https://badge.fury.io/rb/package_json)
5
+ [![Ruby](https://github.com/shakacode/package_json/actions/workflows/checks.yml/badge.svg)](https://github.com/shakacode/package_json/actions/workflows/checks.yml)
6
+
3
7
  The missing gem for managing `package.json` files, without having to know about
4
8
  package managers (mostly).
5
9
 
@@ -34,7 +38,7 @@ executing:
34
38
  package_json = PackageJson.new
35
39
 
36
40
  # adds eslint, eslint-plugin-prettier, and prettier as development dependencies
37
- package_json.manager.add(%w[eslint prettier], :dev)
41
+ package_json.manager.add(%w[eslint prettier], type: :dev)
38
42
 
39
43
  # adds the "lint" and "format" scripts, preserving any existing scripts
40
44
  package_json.merge! do |pj|
@@ -74,7 +78,7 @@ in the `package.json`.
74
78
  > **Note**
75
79
  >
76
80
  > Only the name of the package manager is used; the version (if present) is
77
- > _not_ checked, nor is [`codepack`](https://nodejs.org/api/corepack.html) used
81
+ > _not_ checked, nor is [`corepack`](https://nodejs.org/api/corepack.html) used
78
82
  > to ensure that the package manager is installed.
79
83
  >
80
84
  > The manager will be invoked by its name in the directory of the
@@ -173,11 +177,15 @@ package_json.manager.add(["eslint", "prettier"], type: :dev)
173
177
 
174
178
  # adds dotenv-webpack v6 as a production dependency
175
179
  package_json.manager.add(["dotenv-webpack@^6"])
180
+
181
+ # adds react-on-rails with exact version (no ^ or ~)
182
+ package_json.manager.add(["react-on-rails@16.0.0"], exact: true)
176
183
  ```
177
184
 
178
- | Option | Description |
179
- | ------ | ------------------------------------------------------------------------------------------- |
180
- | `type` | The type to add the dependencies as; either `:production` (default), `:dev`, or `:optional` |
185
+ | Option | Description |
186
+ | ------- | ------------------------------------------------------------------------------------------- |
187
+ | `type` | The type to add the dependencies as; either `:production` (default), `:dev`, or `:optional` |
188
+ | `exact` | If true, saves packages with exact versions (no `^` or `~` prefix) |
181
189
 
182
190
  #### Removing dependencies
183
191
 
@@ -259,18 +267,17 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
259
267
  prompt that will allow you to experiment.
260
268
 
261
269
  To install this gem onto your local machine, run `bundle exec rake install`. To
262
- release a new version, update the version number in `version.rb`, and then run
263
- `bundle exec rake release`, which will create a git tag for the version, push
264
- git commits and the created tag, and push the `.gem` file to
265
- [rubygems.org](https://rubygems.org).
270
+ release a new version, update the version number in `version.rb`, and then tag
271
+ the commit with the version prefixed with a `v`, which will trigger the release
272
+ workflow to publish the new version to [rubygems.org](https://rubygems.org).
266
273
 
267
274
  ## Contributing
268
275
 
269
276
  Bug reports and pull requests are welcome on GitHub at
270
- https://github.com/[USERNAME]/package_json. This project is intended to be a
277
+ https://github.com/shakacode/package_json. This project is intended to be a
271
278
  safe, welcoming space for collaboration, and contributors are expected to adhere
272
279
  to the
273
- [code of conduct](https://github.com/[USERNAME]/package_json/blob/main/CODE_OF_CONDUCT.md).
280
+ [code of conduct](https://github.com/shakacode/package_json/blob/main/CODE_OF_CONDUCT.md).
274
281
 
275
282
  ## License
276
283
 
@@ -281,4 +288,4 @@ The gem is available as open source under the terms of the
281
288
 
282
289
  Everyone interacting in the PackageJson project's codebases, issue trackers,
283
290
  chat rooms and mailing lists is expected to follow the
284
- [code of conduct](https://github.com/[USERNAME]/package_json/blob/main/CODE_OF_CONDUCT.md).
291
+ [code of conduct](https://github.com/shakacode/package_json/blob/main/CODE_OF_CONDUCT.md).
@@ -40,13 +40,13 @@ class PackageJson
40
40
  end
41
41
 
42
42
  # Adds the given packages
43
- def add(packages, type: :production)
43
+ def add(packages, type: :production, exact: false)
44
44
  raise NotImplementedError
45
45
  end
46
46
 
47
47
  # Adds the given packages
48
- def add!(packages, type: :production)
49
- raise_exited_with_non_zero_code_error unless add(packages, type: type)
48
+ def add!(packages, type: :production, exact: false)
49
+ raise_exited_with_non_zero_code_error unless add(packages, type: type, exact: exact)
50
50
  end
51
51
 
52
52
  # Removes the given packages
@@ -16,8 +16,9 @@ class PackageJson
16
16
  end
17
17
 
18
18
  # Adds the given packages
19
- def add(packages, type: :production)
20
- raw("add", [package_type_install_flag(type)].compact + packages)
19
+ def add(packages, type: :production, exact: false)
20
+ flags = [package_type_install_flag(type), exact_flag(exact)].compact
21
+ raw("add", flags + packages)
21
22
  end
22
23
 
23
24
  # Removes the given packages
@@ -62,6 +63,12 @@ class PackageJson
62
63
  []
63
64
  end
64
65
 
66
+ def exact_flag(exact)
67
+ return "--exact" if exact
68
+
69
+ nil
70
+ end
71
+
65
72
  def package_type_install_flag(type)
66
73
  case type
67
74
  when :production
@@ -22,8 +22,9 @@ class PackageJson
22
22
  end
23
23
 
24
24
  # Adds the given packages
25
- def add(packages, type: :production)
26
- raw("install", [package_type_install_flag(type)] + packages)
25
+ def add(packages, type: :production, exact: false)
26
+ flags = [package_type_install_flag(type), exact_flag(exact)].compact
27
+ raw("install", flags + packages)
27
28
  end
28
29
 
29
30
  # Removes the given packages
@@ -66,6 +67,12 @@ class PackageJson
66
67
  args
67
68
  end
68
69
 
70
+ def exact_flag(exact)
71
+ return "--save-exact" if exact
72
+
73
+ nil
74
+ end
75
+
69
76
  def package_type_install_flag(type)
70
77
  case type
71
78
  when :production
@@ -16,8 +16,9 @@ class PackageJson
16
16
  end
17
17
 
18
18
  # Adds the given packages
19
- def add(packages, type: :production)
20
- raw("add", [package_type_install_flag(type)] + packages)
19
+ def add(packages, type: :production, exact: false)
20
+ flags = [package_type_install_flag(type), exact_flag(exact)].compact
21
+ raw("add", flags + packages)
21
22
  end
22
23
 
23
24
  # Removes the given packages
@@ -67,6 +68,12 @@ class PackageJson
67
68
  ["--no-frozen-lockfile"]
68
69
  end
69
70
 
71
+ def exact_flag(exact)
72
+ return "--save-exact" if exact
73
+
74
+ nil
75
+ end
76
+
70
77
  def package_type_install_flag(type)
71
78
  case type
72
79
  when :production
@@ -16,8 +16,9 @@ class PackageJson
16
16
  end
17
17
 
18
18
  # Adds the given packages
19
- def add(packages, type: :production)
20
- raw("add", [package_type_install_flag(type)].compact + packages)
19
+ def add(packages, type: :production, exact: false)
20
+ flags = [package_type_install_flag(type), exact_flag(exact)].compact
21
+ raw("add", flags + packages)
21
22
  end
22
23
 
23
24
  # Removes the given packages
@@ -64,6 +65,12 @@ class PackageJson
64
65
  ["--no-immutable"]
65
66
  end
66
67
 
68
+ def exact_flag(exact)
69
+ return "--exact" if exact
70
+
71
+ nil
72
+ end
73
+
67
74
  def package_type_install_flag(type)
68
75
  case type
69
76
  when :production
@@ -16,8 +16,9 @@ class PackageJson
16
16
  end
17
17
 
18
18
  # Adds the given packages
19
- def add(packages, type: :production)
20
- raw("add", [package_type_install_flag(type)].compact + packages)
19
+ def add(packages, type: :production, exact: false)
20
+ flags = [package_type_install_flag(type), exact_flag(exact)].compact
21
+ raw("add", flags + packages)
21
22
  end
22
23
 
23
24
  # Removes the given packages
@@ -62,7 +63,8 @@ class PackageJson
62
63
  raise PackageJson::Error, "#{command} failed with exit code #{status.exitstatus}: #{stderr}"
63
64
  end
64
65
 
65
- stdout.chomp
66
+ # Strip ANSI/CSI escape sequences that may be present when invoked via tools like concurrently
67
+ stdout.chomp.gsub(/\e\[[^\x40-\x7E]*[\x40-\x7E]/, "")
66
68
  end
67
69
 
68
70
  def build_run_args(script_name, args, silent:)
@@ -78,6 +80,12 @@ class PackageJson
78
80
  []
79
81
  end
80
82
 
83
+ def exact_flag(exact)
84
+ return "--exact" if exact
85
+
86
+ nil
87
+ end
88
+
81
89
  def package_type_install_flag(type)
82
90
  case type
83
91
  when :production
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class PackageJson
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/package_json.rb CHANGED
@@ -79,16 +79,21 @@ class PackageJson
79
79
 
80
80
  name, version = package_manager.split("@")
81
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
82
+ return determine_yarn_version(version) if name == "yarn"
88
83
 
89
84
  name.to_sym
90
85
  end
91
86
 
87
+ def determine_yarn_version(version)
88
+ raise Error, "a major version must be present for Yarn" if version.nil? || version.empty?
89
+
90
+ # check to see if we're meant to be using Yarn v1 based on the versions major component,
91
+ # and accounting for the presence of version constraints like ^, ~, and =
92
+ return :yarn_classic if version.match?(/^[~=^]?1(\.|$)/)
93
+
94
+ :yarn_berry
95
+ end
96
+
92
97
  def new_package_manager(package_manager_name)
93
98
  case package_manager_name
94
99
  when :npm
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/package_json/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "package_json"
7
+ spec.version = PackageJson::VERSION
8
+ spec.authors = ["Gareth Jones"]
9
+ spec.email = %w[open-source@ackama.com]
10
+
11
+ spec.summary = "The missing gem for managing package.json files in Ruby"
12
+ spec.homepage = "https://github.com/shakacode/package_json"
13
+ spec.license = "MIT"
14
+ spec.required_ruby_version = ">= 2.6.0"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = spec.homepage
18
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
19
+ spec.metadata["rubygems_mfa_required"] = "true"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(__dir__) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
26
+ end
27
+ end
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+ end
@@ -13,9 +13,9 @@ class PackageJson
13
13
 
14
14
  def native_install_command: (?frozen: bool) -> Array[String]
15
15
 
16
- def add: (Array[String] packages, ?type: :production | :dev | :optional) -> (bool | nil)
16
+ def add: (Array[String] packages, ?type: :production | :dev | :optional, ?exact: bool) -> (bool | nil)
17
17
 
18
- def add!: (Array[String] packages, ?type: :production | :dev | :optional) -> void
18
+ def add!: (Array[String] packages, ?type: :production | :dev | :optional, ?exact: bool) -> void
19
19
 
20
20
  def remove: (Array[String] packages) -> (bool | nil)
21
21
 
@@ -13,6 +13,8 @@ class PackageJson
13
13
 
14
14
  def with_frozen_flag: (bool frozen) -> Array[String]
15
15
 
16
+ def exact_flag: (bool exact) -> (String | nil)
17
+
16
18
  def package_type_install_flag: (Symbol type) -> (String | nil)
17
19
  end
18
20
  end
@@ -11,6 +11,8 @@ class PackageJson
11
11
  silent: bool
12
12
  ) -> Array[String]
13
13
 
14
+ def exact_flag: (bool exact) -> (String | nil)
15
+
14
16
  def package_type_install_flag: (Symbol type) -> String
15
17
  end
16
18
  end
@@ -13,6 +13,8 @@ class PackageJson
13
13
 
14
14
  def with_frozen_flag: (bool frozen) -> Array[String]
15
15
 
16
+ def exact_flag: (bool exact) -> (String | nil)
17
+
16
18
  def package_type_install_flag: (Symbol type) -> String
17
19
  end
18
20
  end
@@ -13,6 +13,8 @@ class PackageJson
13
13
 
14
14
  def with_frozen_flag: (bool frozen) -> Array[String]
15
15
 
16
+ def exact_flag: (bool exact) -> (String | nil)
17
+
16
18
  def package_type_install_flag: (Symbol type) -> (String | nil)
17
19
  end
18
20
  end
@@ -15,6 +15,8 @@ class PackageJson
15
15
 
16
16
  def with_frozen_flag: (bool frozen) -> Array[String]
17
17
 
18
+ def exact_flag: (bool exact) -> (String | nil)
19
+
18
20
  def package_type_install_flag: (Symbol type) -> (String | nil)
19
21
  end
20
22
  end
data/sig/package_json.rbs CHANGED
@@ -12,14 +12,18 @@ class PackageJson
12
12
 
13
13
  def self.fetch_default_fallback_manager: () -> Symbol
14
14
 
15
- def self.read: (?String path_to_directory, ?package_manager: (:npm | :yarn_berry | :yarn_classic | :pnpm | :bun)) -> PackageJson
15
+ def self.read: (?String path_to_directory, ?fallback_manager: (:npm | :yarn_berry | :yarn_classic | :pnpm | :bun)) -> PackageJson
16
16
 
17
- def initialize: (?String path_to_directory, ?package_manager: (:npm | :yarn_berry | :yarn_classic | :pnpm | :bun)) -> PackageJson
17
+ def initialize: (?String path_to_directory, ?fallback_manager: (:npm | :yarn_berry | :yarn_classic | :pnpm | :bun)) -> PackageJson
18
18
 
19
19
  def fetch: (String key, ?untyped default) -> (String | Hash[String, untyped] | Array[untyped])
20
20
 
21
21
  def merge!: () { (Hash[String | Symbol, untyped]) -> Hash[String | Symbol, untyped] } -> void
22
22
 
23
+ def delete!: (String key) -> untyped
24
+
25
+ def record_package_manager!: () -> void
26
+
23
27
  private
24
28
 
25
29
  @directory: String
@@ -30,9 +34,9 @@ class PackageJson
30
34
 
31
35
  def package_json_path: () -> String
32
36
 
33
- def ensure_package_json_exists: ((:npm | :yarn_berry | :yarn_classic | :pnpm | :bun) package_manager) -> void
37
+ def ensure_package_json_exists: () -> bool
34
38
 
35
- def read_package_json: () -> void
39
+ def read_package_json: () -> Hash[String, untyped]
36
40
 
37
41
  def write_package_json: (_ToJson contents) -> void
38
42
  end
metadata CHANGED
@@ -1,22 +1,21 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: package_json
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gareth Jones
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2023-09-15 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies: []
13
- description:
14
12
  email:
15
13
  - open-source@ackama.com
16
14
  executables: []
17
15
  extensions: []
18
16
  extra_rdoc_files: []
19
17
  files:
18
+ - ".claude/commands/update-changelog.md"
20
19
  - ".editorconfig"
21
20
  - ".prettierignore"
22
21
  - ".prettierrc.json"
@@ -24,6 +23,7 @@ files:
24
23
  - ".rubocop.yml"
25
24
  - ".ruby-version"
26
25
  - CHANGELOG.md
26
+ - CLAUDE.md
27
27
  - CODE_OF_CONDUCT.md
28
28
  - Gemfile
29
29
  - Gemfile.lock
@@ -38,6 +38,7 @@ files:
38
38
  - lib/package_json/managers/yarn_berry_like.rb
39
39
  - lib/package_json/managers/yarn_classic_like.rb
40
40
  - lib/package_json/version.rb
41
+ - package_json.gemspec
41
42
  - sig/package_json.rbs
42
43
  - sig/package_json/managers/base.rbs
43
44
  - sig/package_json/managers/bun_like.rbs
@@ -45,15 +46,14 @@ files:
45
46
  - sig/package_json/managers/pnpm_like.rbs
46
47
  - sig/package_json/managers/yarn_berry_like.rbs
47
48
  - sig/package_json/managers/yarn_classic_like.rbs
48
- homepage: https://github.com/G-Rath/package_json
49
+ homepage: https://github.com/shakacode/package_json
49
50
  licenses:
50
51
  - MIT
51
52
  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
53
+ homepage_uri: https://github.com/shakacode/package_json
54
+ source_code_uri: https://github.com/shakacode/package_json
55
+ changelog_uri: https://github.com/shakacode/package_json/blob/main/CHANGELOG.md
55
56
  rubygems_mfa_required: 'true'
56
- post_install_message:
57
57
  rdoc_options: []
58
58
  require_paths:
59
59
  - lib
@@ -68,8 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
68
  - !ruby/object:Gem::Version
69
69
  version: '0'
70
70
  requirements: []
71
- rubygems_version: 3.3.26
72
- signing_key:
71
+ rubygems_version: 3.6.9
73
72
  specification_version: 4
74
73
  summary: The missing gem for managing package.json files in Ruby
75
74
  test_files: []