proscenium 0.26.1-x86_64-linux-gnu → 0.27.0-x86_64-linux-gnu

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +50 -3
  3. data/lib/proscenium/app_package.rb +8 -4
  4. data/lib/proscenium/builder/request.rb +72 -0
  5. data/lib/proscenium/builder.rb +10 -74
  6. data/lib/proscenium/cli/bun_linker.rb +2 -2
  7. data/lib/proscenium/cli/collisions.rb +7 -9
  8. data/lib/proscenium/cli/error.rb +58 -265
  9. data/lib/proscenium/cli/gem_archive.rb +4 -2
  10. data/lib/proscenium/cli/gem_check.rb +13 -11
  11. data/lib/proscenium/cli/gitignore.rb +2 -1
  12. data/lib/proscenium/cli/inspect.rb +12 -11
  13. data/lib/proscenium/cli/install.rb +35 -46
  14. data/lib/proscenium/cli/manager.rb +6 -6
  15. data/lib/proscenium/cli/platform_variants.rb +8 -8
  16. data/lib/proscenium/cli/pnpm_approvals.rb +3 -3
  17. data/lib/proscenium/cli/pnpm_workspace.rb +15 -14
  18. data/lib/proscenium/cli/project_lock.rb +3 -3
  19. data/lib/proscenium/cli/registration.rb +5 -5
  20. data/lib/proscenium/cli/reporter.rb +2 -2
  21. data/lib/proscenium/cli/verify.rb +9 -50
  22. data/lib/proscenium/cli.rb +5 -4
  23. data/lib/proscenium/contexts/map.rb +183 -0
  24. data/lib/proscenium/contexts/mapping_generation.rb +68 -0
  25. data/lib/proscenium/contexts/messages.rb +276 -0
  26. data/lib/proscenium/{cli/contexts.rb → contexts/plan.rb} +12 -12
  27. data/lib/proscenium/contexts/projection.rb +77 -0
  28. data/lib/proscenium/{cli → contexts}/rules.rb +1 -1
  29. data/lib/proscenium/contexts/stale.rb +174 -0
  30. data/lib/proscenium/contexts.rb +16 -0
  31. data/lib/proscenium/css_module/path.rb +1 -0
  32. data/lib/proscenium/css_module/transformer.rb +15 -0
  33. data/lib/proscenium/css_module.rb +3 -2
  34. data/lib/proscenium/ext/proscenium +0 -0
  35. data/lib/proscenium/helper.rb +6 -1
  36. data/lib/proscenium/importer.rb +13 -1
  37. data/lib/proscenium/middleware/base.rb +0 -4
  38. data/lib/proscenium/middleware.rb +0 -2
  39. data/lib/proscenium/railtie.rb +4 -4
  40. data/lib/proscenium/resolver.rb +3 -1
  41. data/lib/proscenium/side_load.rb +6 -2
  42. data/lib/proscenium/source_path.rb +2 -0
  43. data/lib/proscenium/utils.rb +2 -1
  44. data/lib/proscenium/version.rb +1 -1
  45. data/lib/proscenium.rb +5 -5
  46. metadata +10 -7
  47. data/lib/proscenium/context_map.rb +0 -181
  48. data/lib/proscenium/dependency_context.rb +0 -74
  49. data/lib/proscenium/mapping_generation.rb +0 -64
  50. data/lib/proscenium/stale_contexts.rb +0 -118
@@ -1,273 +1,67 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative '../contexts/messages'
4
+
3
5
  module Proscenium
4
6
  module CLI
5
7
  # Every failure the CLI reports: a stable code, the exit status it maps to, and text that states
6
- # the problem, its cause and the fix. The catalog is the single source; golden-output tests pin
7
- # the human text and the JSON event for each entry (test/cli/golden/).
8
+ # the problem, its cause and the fix. The text is Contexts::Messages', which the engine renders
9
+ # too; golden-output tests pin the human text and the JSON event for each entry
10
+ # (test/cli/golden/).
8
11
  class Error < StandardError
9
12
  EXIT = { success: 0, internal: 1, input: 2, unsupported: 3, drift: 4, integrity: 5,
10
13
  native: 6, busy: 7, interrupted: 8 }.freeze
11
14
 
12
- # code => [exit, message template, fix template]. Templates take keyword arguments.
13
- CATALOG = {
14
- 'PSM-E-USAGE' => [
15
- :input, '%<detail>s',
16
- 'Run `bundle exec proscenium --help` to see the commands and their options.'
17
- ],
18
- 'PSM-E-GEMSPEC' => [
19
- :input, 'Expected one gemspec in %<path>s, but found %<found>s.',
20
- "Run `proscenium gem check` from the gem's own directory, or pass it that directory " \
21
- 'or a built .gem file.'
22
- ],
23
- 'PSM-E-NOT-OPTED-IN' => [
24
- :input, '%<gem>s has not opted in to having Proscenium install its NPM ' \
25
- 'dependencies.',
26
- "Add `spec.metadata['proscenium.dependencies'] = 'true'` to its gemspec."
27
- ],
28
- 'PSM-E-FRONTEND-ROOT' => [
29
- :input, "%<gem>s's proscenium.frontend_root (%<root>s) points outside the gem.",
30
- "Set proscenium.frontend_root to a directory inside the gem, relative to the gem's root."
31
- ],
32
- 'PSM-E-MANIFEST' => [
33
- :input, "%<gem>s's %<path>s can't be used, because %<cause>s.",
34
- 'Ship a valid package.json there: a JSON object whose dependency fields map package ' \
35
- 'names to version strings.'
36
- ],
37
- 'PSM-E-GEM-FILES' => [
38
- :input, "%<gem>s's gemspec doesn't list %<files>s in spec.files, so the built gem " \
39
- "won't include it.",
40
- 'Add package.json, and every frontend file the gem serves, to spec.files.'
41
- ],
42
- 'PSM-E-NAME' => [
43
- :input, "The gem name %<gem>s can't be used as a JavaScript package name " \
44
- '(@rubygems/%<gem>s).',
45
- 'JavaScript package names use only lowercase letters, digits and - . _ ~, are at most ' \
46
- "214 characters long, and can't end in a dot or be a Windows device name such as con " \
47
- 'or nul. The gem needs a valid name before Proscenium can install its dependencies.'
48
- ],
49
- 'PSM-E-WORKSPACES' => [
50
- :input, "%<gem>s's package.json declares workspaces, which a gem's package.json " \
51
- "can't do.",
52
- "Remove \"workspaces\" from the gem's package.json."
53
- ],
54
- 'PSM-E-HOOK' => [
55
- :input, '%<gem>s needs build steps at install time (%<hooks>s), and Proscenium never ' \
56
- 'runs them.',
57
- "Ship the gem's assets already built, and remove those install-time hooks."
58
- ],
59
- 'PSM-E-SPEC' => [
60
- :input, "%<gem>s depends on %<name>s as \"%<spec>s\", which Proscenium doesn't allow.",
61
- 'Use a version range or tag, an npm:<package> alias, a github:, git+https: or git+ssh: ' \
62
- 'URL, or an https: tarball URL.'
63
- ],
64
- 'PSM-E-CREDENTIAL' => [
65
- :input, "%<gem>s's dependency %<name>s has a password or token in its URL, which " \
66
- 'would be committed to your repository.',
67
- 'Remove it from the URL. Apps log in to private registries in their own .npmrc.'
68
- ],
69
- 'PSM-E-ALIAS' => [
70
- :input, "%<gem>s aliases %<name>s to \"%<spec>s\", which is another gem's " \
71
- 'dependency context.',
72
- "Add the other gem to the gemspec's dependencies, and use @rubygems/<gem> directly."
73
- ],
74
- 'PSM-E-REACT' => [
75
- :input, '%<gem>s lists %<packages>s as dependencies, so it would get its own copy and ' \
76
- 'the page would load two.',
77
- "List %<packages>s under peerDependencies instead, so the gem uses the app's copy."
78
- ],
79
- 'PSM-E-CROSS-GEM' => [
80
- :input, "%<gem>s's package.json uses @rubygems/%<other>s, but its gemspec doesn't " \
81
- 'depend on the %<other>s gem.',
82
- "Add `spec.add_dependency '%<other>s'` to the gemspec, or stop using " \
83
- '@rubygems/%<other>s.'
84
- ],
85
- 'PSM-E-NO-MANAGER' => [
86
- :input, "Proscenium can't tell which package manager this app uses: there is no " \
87
- 'packageManager field in package.json, and no pnpm-lock.yaml or bun.lock.',
88
- 'Run again with --manager pnpm or --manager bun, or add a packageManager field to ' \
89
- 'package.json.'
90
- ],
91
- 'PSM-E-MANAGER-CONFLICT' => [
92
- :input, 'This app points to more than one package manager: %<signals>s.',
93
- 'Keep just one: delete the other lockfile, or make packageManager in package.json ' \
94
- 'match the lockfile. (--manager only decides when nothing else does.)'
95
- ],
96
- 'PSM-E-UNSUPPORTED-MANAGER' => [
97
- :unsupported, 'This app uses %<manager>s, but Proscenium can only install ' \
98
- "gems' NPM dependencies with pnpm or Bun.",
99
- "Switch the app to pnpm or Bun, or keep adding gems' NPM dependencies to " \
100
- 'package.json yourself.'
101
- ],
102
- 'PSM-E-BUN-LOCKB' => [
103
- :unsupported, "This app only has bun.lockb, Bun's older binary lockfile, which " \
104
- "Proscenium can't read.",
105
- 'Run `bun install --save-text-lockfile` to write bun.lock, then commit it.'
106
- ],
107
- 'PSM-E-MANAGER-MISSING' => [
108
- :unsupported, "%<manager>s isn't installed, or isn't on your PATH.",
109
- 'Install %<manager>s the way this project normally does (Corepack, mise, Volta or its ' \
110
- 'own installer), then try again.'
111
- ],
112
- 'PSM-E-MANAGER-VERSION' => [
113
- :unsupported, "Proscenium doesn't support %<manager>s %<version>s.",
114
- 'Use a supported version of %<manager>s (%<supported>s). To experiment locally with ' \
115
- 'another, add --experimental-manager-version.'
116
- ],
117
- 'PSM-E-EXPERIMENTAL-FROZEN' => [
118
- :unsupported, "--experimental-manager-version can't be combined with --frozen.",
119
- 'Use a supported package manager version wherever --frozen runs, such as CI.'
120
- ],
121
- 'PSM-E-BUN-LINKER' => [
122
- :unsupported, "bunfig.toml doesn't say which linker Bun uses (hoisted or isolated), " \
123
- 'and adding gem dependency contexts could make Bun switch linkers.',
124
- 'Add `linker = "hoisted"` (or "isolated", whichever your app uses today) to the ' \
125
- '`[install]` table in bunfig.toml, creating the table if there is none.'
126
- ],
127
- 'PSM-E-NESTED-WORKSPACE' => [
128
- :unsupported, 'This app is inside the JavaScript workspace at %<enclosing>s, and ' \
129
- "Proscenium doesn't support that yet.",
130
- "Keep adding gems' NPM dependencies to that workspace yourself, as you do today."
131
- ],
132
- 'PSM-E-REGISTRATION' => [
133
- :input, "Proscenium couldn't add the gem dependency contexts to %<file>s without " \
134
- 'rewriting the file.',
135
- 'Check that %<file>s is valid (package.json must be strict JSON, with no comments or ' \
136
- 'trailing commas). Then add ".proscenium/packages/*" yourself, to `packages` in ' \
137
- 'pnpm-workspace.yaml or `workspaces` in package.json, and run ' \
138
- '`bundle exec proscenium install` again.'
139
- ],
140
- 'PSM-E-REGISTRATION-EXCLUDED' => [
141
- :input, '%<file>s excludes .proscenium/packages/ with a "!" pattern, so your package ' \
142
- 'manager would never install the gem dependency contexts.',
143
- 'Remove that pattern from %<file>s, then run `bundle exec proscenium install` again.'
144
- ],
145
- 'PSM-E-BUSY' => [
146
- :busy, '%<holder>s is already running in this project.',
147
- 'Wait for it to finish, then run your command again. If nothing is actually ' \
148
- 'installing, delete .proscenium/manager, which an earlier run left behind.'
149
- ],
150
- 'PSM-E-NATIVE' => [
151
- :native, '`%<command>s` failed (exit status %<status>s).',
152
- 'Its output is above. Fix what it reports, then run `bundle exec proscenium install` ' \
153
- "again. Proscenium hasn't changed your package manager or regenerated your lockfile."
154
- ],
155
- 'PSM-E-INTERRUPTED' => [
156
- :interrupted, '`%<command>s` was stopped before it finished.',
157
- 'Run `bundle exec proscenium install` again to finish.'
158
- ],
159
- 'PSM-E-CROSS-GEM-TARGET' => [
160
- :input, "%<gem>s's package.json uses @rubygems/%<other>s, but %<other>s hasn't " \
161
- 'opted in to having Proscenium install its NPM dependencies.',
162
- 'Opt %<other>s in: its author adds proscenium.dependencies to its gemspec, or you add ' \
163
- '`"proscenium": {"gemOverrides": {"%<other>s": {"participate": true}}}` to your ' \
164
- 'package.json.'
165
- ],
166
- 'PSM-E-CONFIG' => [
167
- :input, "Proscenium can't read its settings: %<detail>s.",
168
- 'Fix package.json. Proscenium reads one setting from it: ' \
169
- '`"proscenium": {"gemOverrides": {"<gem>": {"participate": true}}}`, with true or ' \
170
- 'false for each gem.'
171
- ],
172
- 'PSM-E-PROBLEMS' => [
173
- :input, 'The install stopped because of the problems above. Nothing was changed.',
174
- 'Fix each one as it says, then run `bundle exec proscenium install` again.'
175
- ],
176
- 'PSM-E-DRIFT' => [
177
- :drift, "Some files are out of date with your bundle:\n%<list>s",
178
- 'Run `bundle exec proscenium install`, then commit the files it lists.'
179
- ],
180
- 'PSM-E-NOT-REGISTERED' => [
181
- :drift, "%<file>s doesn't list .proscenium/packages/*, so %<manager>s won't install " \
182
- "your gems' NPM dependencies.",
183
- 'Run `bundle exec proscenium install`, then commit %<file>s.'
184
- ],
185
- 'PSM-E-GITIGNORE' => [
186
- :drift, ".gitignore is missing some of Proscenium's lines, or a later rule hides the " \
187
- 'dependency contexts you need to commit.',
188
- 'Run `bundle exec proscenium install` to add them, then commit .gitignore.'
189
- ],
190
- 'PSM-E-LOCKFILE-MISSING' => [
191
- :drift, '%<lockfile>s is missing.',
192
- 'Run `bundle exec proscenium install`, then commit %<lockfile>s.'
193
- ],
194
- 'PSM-E-NOT-INSTALLED' => [
195
- :drift, "Your NPM dependencies aren't installed: there is no node_modules " \
196
- 'directory.',
197
- 'Run `bundle exec proscenium install`, or `bundle exec proscenium install --frozen` on ' \
198
- 'a fresh checkout or in CI.'
199
- ],
200
- 'PSM-E-REGISTRY-TARBALL' => [
201
- :integrity, 'The lockfile installs %<packages>s from a registry or Git, instead of ' \
202
- 'from the gem itself.',
203
- 'Remove the registry or GitHub dependency on it from your package.json, since ' \
204
- 'Gemfile.lock provides the gem now, then run `bundle exec proscenium install`.'
205
- ],
206
- 'PSM-E-WORKSPACE-MISSING' => [
207
- :integrity, "%<manager>s didn't install the dependency contexts for %<gems>s.",
208
- 'Check that `packages` in pnpm-workspace.yaml, or `workspaces` in package.json, ' \
209
- 'lists ".proscenium/packages/*", then run `bundle exec proscenium install` again.'
210
- ],
211
- 'PSM-E-PEER-SPLIT' => [
212
- :integrity, '%<gem>s and your app use different copies of %<package>s, so the page ' \
213
- 'would load it twice.',
214
- "Change your app's %<package>s to a version within %<gem>s's peer range, then run " \
215
- '`bundle exec proscenium install` again.'
216
- ],
217
- 'PSM-E-COLLISION' => [
218
- :input, "Some of your app's dependencies use a name a gem's dependency context " \
219
- "needs:\n%<list>s",
220
- 'Remove each one, since Gemfile.lock provides the gem now, or rename the package.'
221
- ],
222
- 'PSM-E-BUN-DEFAULT-TRUSTED' => [
223
- :unsupported, "`bun pm default-trusted` didn't print Bun's default list of trusted " \
224
- "packages, so Proscenium can't check whose install scripts Bun would run.",
225
- 'Add `"trustedDependencies": []` to package.json, listing any packages whose install ' \
226
- 'scripts your app needs, so Bun uses that list instead of its default.'
227
- ],
228
- 'PSM-E-TRUSTED-SOURCE' => [
229
- :input, 'Some gems install a package from Git, a URL or an alias to another package, ' \
230
- 'under a name your package manager trusts to run install scripts, so that ' \
231
- "code's install script would run:\n%<list>s",
232
- "Ask the gem's author to depend on the registry package instead, or opt the gem out " \
233
- 'with `"proscenium": {"gemOverrides": {"<gem>": {"participate": false}}}` in ' \
234
- 'package.json. pnpm trusts the packages pnpm-workspace.yaml approves builds for; Bun ' \
235
- 'trusts trustedDependencies in package.json, or its own default list without one.'
236
- ],
237
- 'PSM-E-PLATFORM-VARIANT' => [
238
- :unsupported, 'The platform-specific builds of %<variants>s differ from the one ' \
239
- 'installed here in their NPM dependencies or whether they opt ' \
240
- "in, or don't pass `proscenium gem check`.",
241
- 'Make every platform build of the gem ship the same package.json dependencies and ' \
242
- 'proscenium.dependencies setting, each passing `proscenium gem check`. Your lockfile ' \
243
- 'can only hold one set.'
244
- ],
245
- 'PSM-E-UNC-SHIM' => [
246
- :unsupported, "%<manager>s is installed as a .cmd script, and cmd.exe can't run in " \
247
- "%<root>s because it's a network (UNC) path: it would run in " \
248
- 'C:\\Windows instead.',
249
- 'Map a drive letter to the share (`net use Z: \\\\server\\share`) and run from that ' \
250
- 'drive, or install %<manager>s as a native executable.'
251
- ],
252
- 'PSM-E-OWNED-LINK' => [
253
- :input, '%<paths>s is a symbolic link, so installing would write outside your app.',
254
- 'Replace it with a real directory. Proscenium only writes inside .proscenium/.'
255
- ],
256
- 'PSM-E-OWNED-DIR' => [
257
- :input, ".proscenium/packages/ contains things Proscenium didn't create: %<entries>s.",
258
- 'Move them somewhere else. Proscenium manages that directory, and treats everything ' \
259
- 'in it as a gem dependency context.'
260
- ],
261
- 'PSM-W-END-OF-LIFE' => [
262
- :success, '%<manager>s %<version>s reaches end of life on %<eol>s, and a future ' \
263
- 'Proscenium release may stop supporting it.',
264
- 'Plan an upgrade to a newer %<manager>s version; the upgrade guide explains the steps.'
265
- ],
266
- 'PSM-E-INTERNAL' => [
267
- :internal, 'Something went wrong inside Proscenium: %<detail>s',
268
- 'This is a bug in Proscenium. Please report it at ' \
269
- 'https://github.com/joelmoss/proscenium/issues, including the output above.'
270
- ]
15
+ # code => the exit status it maps to.
16
+ STATUS = {
17
+ 'PSM-E-USAGE' => :input,
18
+ 'PSM-E-GEMSPEC' => :input,
19
+ 'PSM-E-NOT-OPTED-IN' => :input,
20
+ 'PSM-E-FRONTEND-ROOT' => :input,
21
+ 'PSM-E-MANIFEST' => :input,
22
+ 'PSM-E-GEM-FILES' => :input,
23
+ 'PSM-E-NAME' => :input,
24
+ 'PSM-E-WORKSPACES' => :input,
25
+ 'PSM-E-HOOK' => :input,
26
+ 'PSM-E-SPEC' => :input,
27
+ 'PSM-E-CREDENTIAL' => :input,
28
+ 'PSM-E-ALIAS' => :input,
29
+ 'PSM-E-REACT' => :input,
30
+ 'PSM-E-CROSS-GEM' => :input,
31
+ 'PSM-E-NO-MANAGER' => :input,
32
+ 'PSM-E-MANAGER-CONFLICT' => :input,
33
+ 'PSM-E-UNSUPPORTED-MANAGER' => :unsupported,
34
+ 'PSM-E-BUN-LOCKB' => :unsupported,
35
+ 'PSM-E-MANAGER-MISSING' => :unsupported,
36
+ 'PSM-E-MANAGER-VERSION' => :unsupported,
37
+ 'PSM-E-EXPERIMENTAL-FROZEN' => :unsupported,
38
+ 'PSM-E-BUN-LINKER' => :unsupported,
39
+ 'PSM-E-NESTED-WORKSPACE' => :unsupported,
40
+ 'PSM-E-REGISTRATION' => :input,
41
+ 'PSM-E-REGISTRATION-EXCLUDED' => :input,
42
+ 'PSM-E-BUSY' => :busy,
43
+ 'PSM-E-NATIVE' => :native,
44
+ 'PSM-E-INTERRUPTED' => :interrupted,
45
+ 'PSM-E-CROSS-GEM-TARGET' => :input,
46
+ 'PSM-E-CONFIG' => :input,
47
+ 'PSM-E-PROBLEMS' => :input,
48
+ 'PSM-E-DRIFT' => :drift,
49
+ 'PSM-E-NOT-REGISTERED' => :drift,
50
+ 'PSM-E-GITIGNORE' => :drift,
51
+ 'PSM-E-LOCKFILE-MISSING' => :drift,
52
+ 'PSM-E-NOT-INSTALLED' => :drift,
53
+ 'PSM-E-REGISTRY-TARBALL' => :integrity,
54
+ 'PSM-E-WORKSPACE-MISSING' => :integrity,
55
+ 'PSM-E-PEER-SPLIT' => :integrity,
56
+ 'PSM-E-COLLISION' => :input,
57
+ 'PSM-E-BUN-DEFAULT-TRUSTED' => :unsupported,
58
+ 'PSM-E-TRUSTED-SOURCE' => :input,
59
+ 'PSM-E-PLATFORM-VARIANT' => :unsupported,
60
+ 'PSM-E-UNC-SHIM' => :unsupported,
61
+ 'PSM-E-OWNED-LINK' => :input,
62
+ 'PSM-E-OWNED-DIR' => :input,
63
+ 'PSM-W-END-OF-LIFE' => :success,
64
+ 'PSM-E-INTERNAL' => :internal
271
65
  }.freeze
272
66
 
273
67
  attr_reader :code, :fix, :details
@@ -278,11 +72,10 @@ module Proscenium
278
72
  # fix.
279
73
  def initialize(code, details: {}, escape: nil, **args)
280
74
  @code = code
281
- status, message, fix = CATALOG.fetch(code)
282
- @status = status
283
- @fix = [format(fix, **args), escape].compact.join(' ')
75
+ @status = STATUS.fetch(code)
76
+ @fix = [Contexts::Messages.fix(code, **args), escape].compact.join(' ')
284
77
  @details = details
285
- super(format(message, **args))
78
+ super(Contexts::Messages.message(code, **args))
286
79
  end
287
80
 
288
81
  def exit_status = EXIT.fetch(@status)
@@ -3,7 +3,7 @@
3
3
  require 'rubygems/package'
4
4
  require 'zlib'
5
5
  require_relative '../bundled_gems'
6
- require_relative 'rules'
6
+ require_relative '../contexts/rules'
7
7
 
8
8
  module Proscenium
9
9
  module CLI
@@ -35,7 +35,9 @@ module Proscenium
35
35
 
36
36
  def manifest_entry(entry)
37
37
  return [nil, 'it is not a regular file'] unless entry.file?
38
- return [nil, 'it is larger than 1 MB'] if entry.header.size > Rules::MANIFEST_LIMIT
38
+
39
+ limit = Contexts::Rules::MANIFEST_LIMIT
40
+ return [nil, 'it is larger than 1 MB'] if entry.header.size > limit
39
41
 
40
42
  [entry.read, nil]
41
43
  end
@@ -4,9 +4,9 @@ require 'json'
4
4
  require 'rubygems/package'
5
5
  require 'zlib'
6
6
  require_relative 'gem_archive'
7
- require_relative 'rules'
7
+ require_relative '../contexts/rules'
8
8
  require_relative '../bundled_gems'
9
- require_relative '../context_map'
9
+ require_relative '../contexts/map'
10
10
 
11
11
  module Proscenium
12
12
  module CLI
@@ -67,8 +67,9 @@ module Proscenium
67
67
  end
68
68
 
69
69
  gyp = root.empty? ? 'binding.gyp' : File.join(root, 'binding.gyp')
70
- problems = Rules.check(gem, manifest, root: source_root(root), path: manifest_path,
71
- binding_gyp: files.include?(gyp))
70
+ problems = Contexts::Rules.check(gem, manifest, root: source_root(root),
71
+ path: manifest_path,
72
+ binding_gyp: files.include?(gyp))
72
73
  # A field of the wrong type stops here: the checks below read it as an object.
73
74
  return problems if problems.any? { it.first == 'PSM-E-MANIFEST' }
74
75
 
@@ -86,15 +87,16 @@ module Proscenium
86
87
  # A reference to another gem's context needs that gem as a runtime dependency.
87
88
  def cross_gem(spec, manifest)
88
89
  runtime = spec.runtime_dependencies.map(&:name)
89
- Rules::DEPENDENCY_FIELDS.flat_map { (manifest[it] || {}).keys }
90
- .grep(%r{\A@rubygems/})
91
- .map { it.delete_prefix('@rubygems/') }
92
- .reject { runtime.include?(it) }
93
- .map { ['PSM-E-CROSS-GEM', { gem: spec.name, other: it }] }
90
+ fields = Contexts::Rules::DEPENDENCY_FIELDS
91
+ fields.flat_map { (manifest[it] || {}).keys }
92
+ .grep(%r{\A@rubygems/})
93
+ .map { it.delete_prefix('@rubygems/') }
94
+ .reject { runtime.include?(it) }
95
+ .map { ['PSM-E-CROSS-GEM', { gem: spec.name, other: it }] }
94
96
  end
95
97
 
96
98
  def parse(text)
97
- manifest = ContextMap.parse_json(text)
99
+ manifest = Contexts::Map.parse_json(text)
98
100
  manifest.is_a?(Hash) ? manifest : 'it is not a JSON object'
99
101
  rescue JSON::ParserError => e
100
102
  "it is not valid JSON (#{e.message.lines.first.strip})"
@@ -115,7 +117,7 @@ module Proscenium
115
117
  @source = @path
116
118
  return [spec, spec.files, nil, nil] unless File.exist?(manifest)
117
119
 
118
- cause = Rules.manifest_file_problem(manifest, @path)
120
+ cause = Contexts::Rules.manifest_file_problem(manifest, @path)
119
121
  [spec, spec.files, cause ? nil : File.read(manifest), cause]
120
122
  end
121
123
 
@@ -44,7 +44,8 @@ module Proscenium
44
44
  # Git's `**/` also matches no directory at all. Ruby's does too with FNM_PATHNAME, inside a
45
45
  # pattern, but not at its start, so that prefix is also dropped; without FNM_PATHNAME, a
46
46
  # trailing `**` (and `*`) crosses `/` as Git's trailing `/**` does.
47
- # Any segment of the rule may name a gem's directory, such as `.proscenium/packages/hue/**`,
47
+ # Any segment of the rule may name a gem's directory, such as
48
+ # `.proscenium/packages/ui-gem/**`,
48
49
  # and one with a wildcard, class or brace, such as `[ah]ue`, may match any of them.
49
50
  names = ['gem', *pattern.split('/')]
50
51
  wide = pattern.split('/').map { it.match?(/[*?\[{]/) ? '*' : it }.join('/')
@@ -3,12 +3,12 @@
3
3
  require 'json'
4
4
  require 'bundler'
5
5
  require_relative '../bundled_gems'
6
- require_relative 'contexts'
6
+ require_relative '../contexts/plan'
7
7
  require_relative 'gitignore'
8
8
  require_relative 'manager'
9
9
  require_relative 'registration'
10
10
  require_relative 'verify'
11
- require_relative '../stale_contexts'
11
+ require_relative '../contexts/stale'
12
12
 
13
13
  module Proscenium
14
14
  module CLI
@@ -56,14 +56,14 @@ module Proscenium
56
56
  'dependencies through Proscenium')
57
57
  end
58
58
 
59
- contexts = Contexts.new(@root, participating)
60
- committed = Contexts.committed(@root)
59
+ contexts = Contexts::Plan.new(@root, participating)
60
+ committed = Contexts::Plan.committed(@root)
61
61
  gems = participating.keys.select { @only.nil? || it == @only }.map do |name|
62
62
  gem_report(name, participating[name], contexts, committed)
63
63
  end
64
64
  manager, problems = select_manager
65
65
  # An app that uses none of this has nothing to set up, whatever its manager.
66
- if participating.any? || committed.any? || ContextMap.registrar(@root)
66
+ if participating.any? || committed.any? || Contexts::Map.registrar(@root)
67
67
  problems += project_problems(manager, contexts, committed)
68
68
  else
69
69
  problems = []
@@ -72,7 +72,7 @@ module Proscenium
72
72
  { 'schema' => 1, 'manager' => manager_report(manager), 'gems' => gems,
73
73
  'notParticipating' => BundledGems.unparticipating_with_manifest(specs, overrides:),
74
74
  # Every reason the engine refuses to build: orphans and split peers as well.
75
- 'buildRefused' => StaleContexts.problems(@root, specs),
75
+ 'buildRefused' => Contexts::Stale.problems(@root, specs),
76
76
  'problems' => problems.map { problem_report(it) } }
77
77
  rescue BundledGems::ConfigError => e
78
78
  raise Error.new('PSM-E-CONFIG', detail: e.message)
@@ -88,21 +88,22 @@ module Proscenium
88
88
  'context' => ".proscenium/packages/#{name}",
89
89
  'status' => status(context, on_disk, path),
90
90
  'projectionSha256' => current&.dig('proscenium', 'projectionSha256'),
91
- 'kept' => current ? (current.keys & DependencyContext::FIELDS) : [],
91
+ 'kept' => current ? (current.keys & Contexts::Projection::FIELDS) : [],
92
92
  'gitAndUrl' => (context&.git_and_url || []).map { redact(it) },
93
93
  'optionalPeers' => optional_peers(current)
94
94
  }
95
95
  end
96
96
 
97
- # `stale` exactly when the engine refuses to build: the projection hash differs. Different
98
- # bytes with the same hash are a hand edit, which only `install --frozen` refuses.
97
+ # `edited` when the gem's dependencies are what install would write but the file is not: a
98
+ # reformat, which the engine builds with and only `install --frozen` refuses, or a hand edit
99
+ # to its fields, which the engine refuses too (`buildRefused` says which). `stale` when
100
+ # install would write something else, and the engine refuses it.
99
101
  def status(context, on_disk, path)
100
102
  return 'invalid' unless context
101
103
  return 'missing' unless on_disk
102
104
  return 'current' if on_disk == context.json
103
105
 
104
- reason = StaleContexts.compare(context, path)
105
- reason.nil? || reason == StaleContexts::EDITED ? 'edited' : 'stale'
106
+ [nil, :edited].include?(Contexts::Stale.drift(context, path)) ? 'edited' : 'stale'
106
107
  end
107
108
 
108
109
  # Where Gemfile.lock takes the gem from.