proscenium 0.26.0-aarch64-linux-gnu → 0.27.0-aarch64-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.
- checksums.yaml +4 -4
- data/README.md +50 -3
- data/lib/proscenium/app_package.rb +8 -4
- data/lib/proscenium/builder/request.rb +72 -0
- data/lib/proscenium/builder.rb +10 -74
- data/lib/proscenium/cli/bun_linker.rb +2 -2
- data/lib/proscenium/cli/collisions.rb +7 -9
- data/lib/proscenium/cli/error.rb +58 -265
- data/lib/proscenium/cli/gem_archive.rb +4 -2
- data/lib/proscenium/cli/gem_check.rb +13 -11
- data/lib/proscenium/cli/gitignore.rb +2 -1
- data/lib/proscenium/cli/inspect.rb +12 -11
- data/lib/proscenium/cli/install.rb +35 -46
- data/lib/proscenium/cli/manager.rb +6 -6
- data/lib/proscenium/cli/platform_variants.rb +8 -8
- data/lib/proscenium/cli/pnpm_approvals.rb +3 -3
- data/lib/proscenium/cli/pnpm_workspace.rb +15 -14
- data/lib/proscenium/cli/project_lock.rb +3 -3
- data/lib/proscenium/cli/registration.rb +5 -5
- data/lib/proscenium/cli/reporter.rb +2 -2
- data/lib/proscenium/cli/verify.rb +9 -50
- data/lib/proscenium/cli.rb +5 -4
- data/lib/proscenium/contexts/map.rb +183 -0
- data/lib/proscenium/contexts/mapping_generation.rb +68 -0
- data/lib/proscenium/contexts/messages.rb +276 -0
- data/lib/proscenium/{cli/contexts.rb → contexts/plan.rb} +12 -12
- data/lib/proscenium/contexts/projection.rb +77 -0
- data/lib/proscenium/{cli → contexts}/rules.rb +1 -1
- data/lib/proscenium/contexts/stale.rb +174 -0
- data/lib/proscenium/contexts.rb +16 -0
- data/lib/proscenium/css_module/path.rb +1 -0
- data/lib/proscenium/css_module/transformer.rb +15 -0
- data/lib/proscenium/css_module.rb +3 -2
- data/lib/proscenium/ext/proscenium +0 -0
- data/lib/proscenium/helper.rb +6 -1
- data/lib/proscenium/importer.rb +13 -1
- data/lib/proscenium/middleware/base.rb +0 -4
- data/lib/proscenium/middleware.rb +0 -2
- data/lib/proscenium/railtie.rb +4 -4
- data/lib/proscenium/resolver.rb +3 -1
- data/lib/proscenium/side_load.rb +6 -2
- data/lib/proscenium/source_path.rb +2 -0
- data/lib/proscenium/utils.rb +2 -1
- data/lib/proscenium/version.rb +1 -1
- data/lib/proscenium.rb +5 -5
- metadata +10 -7
- data/lib/proscenium/context_map.rb +0 -181
- data/lib/proscenium/dependency_context.rb +0 -74
- data/lib/proscenium/mapping_generation.rb +0 -64
- data/lib/proscenium/stale_contexts.rb +0 -118
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Proscenium
|
|
4
|
-
module
|
|
4
|
+
module Contexts
|
|
5
5
|
# The author contract for a participating gem's package.json (#154): what `gem check` and
|
|
6
6
|
# `install` refuse. Each rule yields a problem as [error code, format arguments]; the caller
|
|
7
7
|
# decides whether a problem is fatal and how to word the escape.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require_relative '../app_package'
|
|
5
|
+
require_relative '../bundled_gems'
|
|
6
|
+
require_relative 'map'
|
|
7
|
+
require_relative 'projection'
|
|
8
|
+
require_relative 'plan'
|
|
9
|
+
require_relative 'messages'
|
|
10
|
+
|
|
11
|
+
module Proscenium
|
|
12
|
+
module Contexts
|
|
13
|
+
# Whether an adopted app's committed gem dependency contexts are what its bundle calls for
|
|
14
|
+
# (#154). A stale context resolves a gem's imports against the wrong dependency graph, so the
|
|
15
|
+
# engine refuses to build until `proscenium install` brings them up to date. Built from
|
|
16
|
+
# committed files and Bundler only. The engine and the CLI both load it, so it loads nothing
|
|
17
|
+
# the CLI may not, and nothing of cli/ (both directions are pinned by
|
|
18
|
+
# test/cli/load_isolation_test.rb).
|
|
19
|
+
module Stale
|
|
20
|
+
COMMAND = 'Run `bundle exec proscenium install` and commit .proscenium/packages.'
|
|
21
|
+
# Why a committed context is not the one install would write, by its `drift`. The engine,
|
|
22
|
+
# `install --frozen` and `inspect` all classify a context with `drift`, so they name one
|
|
23
|
+
# cause.
|
|
24
|
+
REASONS = {
|
|
25
|
+
missing: "its dependency context hasn't been written yet",
|
|
26
|
+
invalid: 'its dependency context is not valid JSON',
|
|
27
|
+
projection: 'its dependency context was written by a different version of Proscenium',
|
|
28
|
+
edited: 'its dependency context was edited by hand',
|
|
29
|
+
changed: 'its NPM dependencies changed since its dependency context was written'
|
|
30
|
+
}.freeze
|
|
31
|
+
ORPHAN = '%<gem>s: its dependency context is left over, as the gem is no longer in the ' \
|
|
32
|
+
'bundle or no longer opted in'
|
|
33
|
+
|
|
34
|
+
module_function
|
|
35
|
+
|
|
36
|
+
# One line for each way the committed contexts differ from the bundle; empty when current, or
|
|
37
|
+
# before the app adopts. A context is stale when a participating gem has none, when its gem
|
|
38
|
+
# left Gemfile.lock or stopped participating, when its projection hash is not the gem's
|
|
39
|
+
# current one, or when that hash is not the one its own fields produce (a hand edit). A
|
|
40
|
+
# locked gem that is not installed (a group BUNDLE_WITHOUT excludes) keeps its context as
|
|
41
|
+
# committed.
|
|
42
|
+
def problems(root, specs = BundledGems.installed_specs, locked = BundledGems.locked_names)
|
|
43
|
+
registrar = Map.registrar(root)
|
|
44
|
+
return [] unless registrar
|
|
45
|
+
|
|
46
|
+
# Only the registration in use: a Bun app does not read a pnpm-workspace.yaml left over.
|
|
47
|
+
unparsable = unparsable_workspace(root) if registrar == 'pnpm-workspace.yaml'
|
|
48
|
+
return [unparsable] if unparsable
|
|
49
|
+
|
|
50
|
+
participating = BundledGems.participating(specs, overrides: BundledGems.overrides(root))
|
|
51
|
+
contexts = Plan.new(root, participating)
|
|
52
|
+
committed = Plan.committed(root)
|
|
53
|
+
found = contexts.problems.map { |code, args| Messages.message(code, **args) }
|
|
54
|
+
contexts.contexts.each_value do |context|
|
|
55
|
+
problem = compare(context, committed[context.gem])
|
|
56
|
+
found << "#{context.gem}: #{problem}" if problem
|
|
57
|
+
end
|
|
58
|
+
excluded = (locked || []) - specs.map(&:name)
|
|
59
|
+
orphans = committed.keys - participating.keys - excluded
|
|
60
|
+
found + orphans.map { format(ORPHAN, gem: it) } +
|
|
61
|
+
split_peers(root, contexts.contexts.keys & committed.keys)
|
|
62
|
+
rescue BundledGems::ConfigError => e
|
|
63
|
+
[e.message]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# An app counts as adopted when a pnpm-workspace.yaml it cannot parse names the contexts, so
|
|
67
|
+
# the engine never silently switches them off; it refuses until the file parses. Not
|
|
68
|
+
# package.json: Bun reads JSON that Ruby refuses, such as a trailing comma.
|
|
69
|
+
def unparsable_workspace(root)
|
|
70
|
+
path = File.join(root, 'pnpm-workspace.yaml')
|
|
71
|
+
return unless File.exist?(path)
|
|
72
|
+
|
|
73
|
+
Map.yaml_packages(Map.utf8(File.read(path)).delete_prefix(Map::BOM))
|
|
74
|
+
nil
|
|
75
|
+
rescue Psych::SyntaxError => e
|
|
76
|
+
"pnpm-workspace.yaml: it is not valid YAML (#{e.problem} at line #{e.line})"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# A peer meant to be shared that the gem and the app reach as two copies, as an app-only
|
|
80
|
+
# `pnpm update react` can leave it: install checks this too, and the engine repeats it for
|
|
81
|
+
# each generation.
|
|
82
|
+
def split_peers(root, gems)
|
|
83
|
+
gem, package = peer_split(root, gems)
|
|
84
|
+
gem ? [Messages.message('PSM-E-PEER-SPLIT', gem:, package:)] : []
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# The first `[gem, package]` where a peer a context declares, that the app also depends on,
|
|
88
|
+
# resolves from the context and from the app to two different real directories; nil when
|
|
89
|
+
# every one is a single copy. A context that is missing or not valid JSON has no peers to
|
|
90
|
+
# check: `problems` and `install --frozen` report it themselves.
|
|
91
|
+
def peer_split(root, gems)
|
|
92
|
+
app = app_dependencies(root)
|
|
93
|
+
gems.each do |gem|
|
|
94
|
+
dir = File.join(root, Map::CONTEXTS, gem)
|
|
95
|
+
(peers(dir).keys & app).each do |name|
|
|
96
|
+
from_gem = real_dependency_dir(root, dir, name)
|
|
97
|
+
from_app = real_dependency_dir(root, root, name)
|
|
98
|
+
return [gem, name] unless from_gem.nil? || from_app.nil? || from_gem == from_app
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
nil
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def peers(dir)
|
|
105
|
+
context = Map.read_json(File.join(dir, 'package.json'))
|
|
106
|
+
peers = context['peerDependencies'] if context.is_a?(Hash)
|
|
107
|
+
peers.is_a?(Hash) ? peers : {}
|
|
108
|
+
rescue Errno::ENOENT, JSON::ParserError
|
|
109
|
+
{}
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def app_dependencies(root)
|
|
113
|
+
package = Map.read_json(File.join(root, 'package.json'))
|
|
114
|
+
return [] unless package.is_a?(Hash)
|
|
115
|
+
|
|
116
|
+
AppPackage::DEPENDENCY_FIELDS.flat_map { package[it].is_a?(Hash) ? package[it].keys : [] }
|
|
117
|
+
rescue Errno::ENOENT, JSON::ParserError
|
|
118
|
+
[]
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# The real directory `name` resolves to from `dir`, walking up node_modules as Node does,
|
|
122
|
+
# but no higher than the app at `root`.
|
|
123
|
+
def real_dependency_dir(root, dir, name)
|
|
124
|
+
current = dir
|
|
125
|
+
loop do
|
|
126
|
+
candidate = File.join(current, 'node_modules', name)
|
|
127
|
+
return File.realpath(candidate) if File.exist?(candidate)
|
|
128
|
+
return nil if current == root || current == File.dirname(current)
|
|
129
|
+
|
|
130
|
+
current = File.dirname(current)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Why the engine refuses the committed context at `path`, or nil when it builds with it.
|
|
135
|
+
def compare(context, path) = REASONS[drift(context, path)]
|
|
136
|
+
|
|
137
|
+
# How the committed context at `path` differs from `context`, as a key of REASONS, or nil
|
|
138
|
+
# when it holds the same JSON. It is projected again from the fields it holds, not taken on
|
|
139
|
+
# trust: a hand edit that kept the reported hash would build against a graph no install
|
|
140
|
+
# produced.
|
|
141
|
+
def drift(context, path)
|
|
142
|
+
return :missing unless path && File.exist?(path)
|
|
143
|
+
|
|
144
|
+
committed = Map.read_json(path)
|
|
145
|
+
return :invalid unless committed.is_a?(Hash) && committed['proscenium'].is_a?(Hash)
|
|
146
|
+
return :projection if committed['proscenium']['projection'] != Projection::PROJECTION
|
|
147
|
+
|
|
148
|
+
# Parsed, so reformatting is not an edit; whole, so its name and the other generated fields
|
|
149
|
+
# count as well as its hash.
|
|
150
|
+
return :edited if Projection.project(context.gem, committed) != committed
|
|
151
|
+
|
|
152
|
+
:changed unless committed == JSON.parse(context.json)
|
|
153
|
+
rescue JSON::ParserError
|
|
154
|
+
:invalid
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# The build error for the app at `root`, or nil when its contexts are current. Read once per
|
|
158
|
+
# mapping generation, as Map.config is.
|
|
159
|
+
def message(root, generation = 0)
|
|
160
|
+
@message ||= {}
|
|
161
|
+
key = [root, generation]
|
|
162
|
+
return @message[key] if @message.key?(key)
|
|
163
|
+
|
|
164
|
+
found = problems(root)
|
|
165
|
+
@message[key] = if found.any?
|
|
166
|
+
"Gem dependency contexts are out of date:\n" \
|
|
167
|
+
"#{found.map { " - #{it}" }.join("\n")}\n#{COMMAND}"
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def reset! = @message = {}
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Proscenium
|
|
4
|
+
# The model of gem dependency contexts (#154), which the engine and the `proscenium` CLI share.
|
|
5
|
+
# Its files load nothing of either: not ActiveSupport, and nothing under cli/. The CLI requires
|
|
6
|
+
# each file it needs; the engine reaches them through these autoloads.
|
|
7
|
+
module Contexts
|
|
8
|
+
autoload :Map, "#{__dir__}/contexts/map"
|
|
9
|
+
autoload :MappingGeneration, "#{__dir__}/contexts/mapping_generation"
|
|
10
|
+
autoload :Messages, "#{__dir__}/contexts/messages"
|
|
11
|
+
autoload :Plan, "#{__dir__}/contexts/plan"
|
|
12
|
+
autoload :Projection, "#{__dir__}/contexts/projection"
|
|
13
|
+
autoload :Rules, "#{__dir__}/contexts/rules"
|
|
14
|
+
autoload :Stale, "#{__dir__}/contexts/stale"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Proscenium
|
|
4
|
+
# @api public: an extension point for component gems (README, "Extending Proscenium").
|
|
4
5
|
module CssModule::Path
|
|
5
6
|
# Returns the path to the CSS module file for this class, where the file is located alongside
|
|
6
7
|
# the class file, and has the same name as the class file, but with a `.module.css` extension.
|
|
@@ -55,6 +55,8 @@ module Proscenium
|
|
|
55
55
|
# @yieldparam transformed_name [String]
|
|
56
56
|
# @yieldparam side_load_path [String, nil]
|
|
57
57
|
# @return [Array<String>] the transformed CSS module names.
|
|
58
|
+
#
|
|
59
|
+
# @api public: an extension point for component gems (README, "Extending Proscenium").
|
|
58
60
|
def class_names(*names, require_prefix: true)
|
|
59
61
|
self.class.filter_names(names).map do |name|
|
|
60
62
|
transformed, path = transform_class_name(name, require_prefix: require_prefix)
|
|
@@ -63,6 +65,19 @@ module Proscenium
|
|
|
63
65
|
end
|
|
64
66
|
end
|
|
65
67
|
|
|
68
|
+
# Transforms one class `name` to its CSS module name against the CSS module at `path`, whatever
|
|
69
|
+
# its prefix, and side loads that module. `original_name` is the name as the caller wrote it,
|
|
70
|
+
# for the error raised when there is no path.
|
|
71
|
+
#
|
|
72
|
+
# transformer.class_name!(:title, 'cssm:title') # => "title_<digest>"
|
|
73
|
+
#
|
|
74
|
+
# @param name [String, Symbol]
|
|
75
|
+
# @param original_name [String]
|
|
76
|
+
# @param path [Pathname, String] the CSS module; by default, the transformer's own.
|
|
77
|
+
# @raise [Proscenium::CssModule::TransformError] when there is no path.
|
|
78
|
+
# @return [String] the transformed CSS module name.
|
|
79
|
+
#
|
|
80
|
+
# @api public: apps call it directly (README, "Extending Proscenium").
|
|
66
81
|
def class_name!(name, original_name, path: @source_path)
|
|
67
82
|
unless path
|
|
68
83
|
raise Proscenium::CssModule::TransformError.new(original_name, 'CSS module path not given')
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# @api public: an extension point for component gems (README, "Extending Proscenium").
|
|
3
4
|
module Proscenium::CssModule
|
|
4
5
|
extend ActiveSupport::Autoload
|
|
5
6
|
|
|
@@ -17,14 +18,14 @@ module Proscenium::CssModule
|
|
|
17
18
|
|
|
18
19
|
module ClassMethods
|
|
19
20
|
def css_module(*names, path: nil)
|
|
20
|
-
path ||= respond_to?(:css_module_path)
|
|
21
|
+
path ||= css_module_path if respond_to?(:css_module_path)
|
|
21
22
|
|
|
22
23
|
cssm = Transformer.new(path)
|
|
23
24
|
cssm.class_names(*names, require_prefix: false).join(' ')
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
def class_names(*names, path: nil)
|
|
27
|
-
path ||= respond_to?(:css_module_path)
|
|
28
|
+
path ||= css_module_path if respond_to?(:css_module_path)
|
|
28
29
|
names = Transformer.filter_names(names)
|
|
29
30
|
|
|
30
31
|
cssm = Transformer.new(path)
|
|
Binary file
|
data/lib/proscenium/helper.rb
CHANGED
|
@@ -45,9 +45,14 @@ module Proscenium
|
|
|
45
45
|
@proscenium_sideload_assets_options ||= {}
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
# A tag helper's source with no leading slash, looked up in the manifest's own key space:
|
|
49
|
+
# `/app/...` for an app file, `@rubygems/...` for a gem's. An entry holds its outputs, the
|
|
50
|
+
# entry's own first. With no entry, the URL the middleware serves it at, as Resolver builds it.
|
|
48
51
|
def compute_asset_path(path, options = {})
|
|
49
52
|
if %i[javascript stylesheet].include?(options[:type])
|
|
50
|
-
|
|
53
|
+
gem = path.start_with?('@rubygems/')
|
|
54
|
+
return Proscenium::Manifest[gem ? path : "/#{path}"]&.first ||
|
|
55
|
+
(gem ? "/node_modules/#{path}" : "/#{path}")
|
|
51
56
|
end
|
|
52
57
|
|
|
53
58
|
super
|
data/lib/proscenium/importer.rb
CHANGED
|
@@ -32,7 +32,9 @@ module Proscenium
|
|
|
32
32
|
# or a URL, which has no file on disk. Should be the actual asset file, eg. app.css,
|
|
33
33
|
# some/component.js.
|
|
34
34
|
# @return [String|nil] the digest of the imported file path if a css module (*.module.css).
|
|
35
|
-
|
|
35
|
+
#
|
|
36
|
+
# @api public: an extension point for component gems (README, "Extending Proscenium").
|
|
37
|
+
def import(filepath, sideloaded: false, **)
|
|
36
38
|
self.imported ||= {}
|
|
37
39
|
|
|
38
40
|
if filepath.end_with?('.module.css')
|
|
@@ -90,6 +92,8 @@ module Proscenium
|
|
|
90
92
|
#
|
|
91
93
|
# @param filepath [Pathname] Absolute file system path of the Ruby file to sideload.
|
|
92
94
|
# @param options [Hash] Options to pass to `import`.
|
|
95
|
+
#
|
|
96
|
+
# @api public: an extension point for component gems (README, "Extending Proscenium").
|
|
93
97
|
def sideload(filepath, **options)
|
|
94
98
|
return if !Proscenium.config.side_load || (options[:js] == false && options[:css] == false)
|
|
95
99
|
|
|
@@ -129,6 +133,10 @@ module Proscenium
|
|
|
129
133
|
end
|
|
130
134
|
end
|
|
131
135
|
|
|
136
|
+
# Yields each imported stylesheet, with its options. `delete: true` also removes each one from
|
|
137
|
+
# the imports, so it is written only once.
|
|
138
|
+
#
|
|
139
|
+
# @api public: apps call it to write their own tags (README, "Extending Proscenium").
|
|
132
140
|
def each_stylesheet(delete: false)
|
|
133
141
|
return if imported.blank?
|
|
134
142
|
|
|
@@ -142,6 +150,10 @@ module Proscenium
|
|
|
142
150
|
delete ? imported.delete_if(&blk) : imported.each(&blk)
|
|
143
151
|
end
|
|
144
152
|
|
|
153
|
+
# Yields each imported script, with its options. `delete: true` also removes each one from the
|
|
154
|
+
# imports, so it is written only once.
|
|
155
|
+
#
|
|
156
|
+
# @api public: apps call it to write their own tags (README, "Extending Proscenium").
|
|
145
157
|
def each_javascript(delete: false)
|
|
146
158
|
return if imported.blank?
|
|
147
159
|
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
module Proscenium
|
|
4
4
|
class Middleware
|
|
5
5
|
class Base
|
|
6
|
-
include ActiveSupport::Benchmarkable
|
|
7
|
-
|
|
8
6
|
def self.attempt(request)
|
|
9
7
|
new(request).renderable!&.attempt
|
|
10
8
|
end
|
|
@@ -70,8 +68,6 @@ module Proscenium
|
|
|
70
68
|
when '.js', '.mjs', '.ts', '.tsx', '.jsx' then 'application/javascript'
|
|
71
69
|
when '.css' then 'text/css'
|
|
72
70
|
when '.map' then 'application/json'
|
|
73
|
-
else
|
|
74
|
-
::Rack::Mime.mime_type(::File.extname(path_to_build), nil) || 'application/javascript'
|
|
75
71
|
end
|
|
76
72
|
end
|
|
77
73
|
|
data/lib/proscenium/railtie.rb
CHANGED
|
@@ -36,16 +36,16 @@ module Proscenium
|
|
|
36
36
|
|
|
37
37
|
Proscenium::Manifest.load!
|
|
38
38
|
|
|
39
|
-
project = Proscenium::
|
|
40
|
-
if (notice = Proscenium::
|
|
39
|
+
project = Proscenium::Contexts::Map.project_root
|
|
40
|
+
if (notice = Proscenium::Contexts::Map.adoption_notice(project))
|
|
41
41
|
Rails.logger.info "[Proscenium] #{notice}"
|
|
42
42
|
end
|
|
43
43
|
# Production finds stale contexts at assets:precompile, which refuses to compile. Elsewhere
|
|
44
44
|
# the first mapping generation starts here, so a change after boot, such as running
|
|
45
45
|
# `proscenium install`, starts the next one. No Go call: Puma may fork after boot.
|
|
46
46
|
unless Rails.env.production?
|
|
47
|
-
generation, = Proscenium::MappingGeneration.refresh(project)
|
|
48
|
-
if (stale = Proscenium::
|
|
47
|
+
generation, = Proscenium::Contexts::MappingGeneration.refresh(project)
|
|
48
|
+
if (stale = Proscenium::Contexts::Stale.message(project, generation))
|
|
49
49
|
Rails.logger.warn "[Proscenium] #{stale}"
|
|
50
50
|
end
|
|
51
51
|
end
|
data/lib/proscenium/resolver.rb
CHANGED
|
@@ -10,6 +10,8 @@ module Proscenium
|
|
|
10
10
|
# @param as_array [Boolean] whether or not to return the manifest path, non-manifest path, and
|
|
11
11
|
# absolute file system path as an array. Only returns the resolved path if false (default).
|
|
12
12
|
# @return [String, Array<String>]
|
|
13
|
+
#
|
|
14
|
+
# @api public: an extension point for component gems (README, "Extending Proscenium").
|
|
13
15
|
def self.resolve(path, as_array: false)
|
|
14
16
|
# Normalised before anything reads it, the guard and the cache key included. The bun test
|
|
15
17
|
# harness hands this Bun's own spelling of a module path, which on Windows is `D:\...`;
|
|
@@ -55,7 +57,7 @@ module Proscenium
|
|
|
55
57
|
def self.generation
|
|
56
58
|
return 0 if Rails.env.production?
|
|
57
59
|
|
|
58
|
-
number, changed = MappingGeneration.refresh(
|
|
60
|
+
number, changed = Contexts::MappingGeneration.refresh(Contexts::Map.project_root)
|
|
59
61
|
reset if changed
|
|
60
62
|
number
|
|
61
63
|
end
|
data/lib/proscenium/side_load.rb
CHANGED
|
@@ -38,7 +38,7 @@ module Proscenium
|
|
|
38
38
|
opts = opts.merge(data: opts[:data] || {})
|
|
39
39
|
opts = opts.merge(preload_links_header: false) if fragments
|
|
40
40
|
|
|
41
|
-
out << helpers.stylesheet_link_tag(path
|
|
41
|
+
out << helpers.stylesheet_link_tag(path, extname: false, **opts)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
if fragments
|
|
@@ -64,7 +64,7 @@ module Proscenium
|
|
|
64
64
|
opts = opts[:js].is_a?(Hash) ? opts[:js] : {}
|
|
65
65
|
opts = opts.merge(preload_links_header: false) if fragments
|
|
66
66
|
|
|
67
|
-
out << helpers.javascript_include_tag(path
|
|
67
|
+
out << helpers.javascript_include_tag(path, extname: false, **opts)
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
if fragments
|
|
@@ -95,6 +95,8 @@ module Proscenium
|
|
|
95
95
|
#
|
|
96
96
|
# If the class responds to `.sideload`, it will be called after the regular side loading. You
|
|
97
97
|
# can use this to customise what is side loaded.
|
|
98
|
+
#
|
|
99
|
+
# @api public: an extension point for component gems (README, "Extending Proscenium").
|
|
98
100
|
def sideload_inheritance_chain(obj, options)
|
|
99
101
|
return unless Proscenium.config.side_load
|
|
100
102
|
|
|
@@ -168,6 +170,8 @@ module Proscenium
|
|
|
168
170
|
# attribute, so writing to it would leak one request's options into every later one. Values
|
|
169
171
|
# other than hashes are passed through as they are, not copied: `dup` on an ActiveRecord
|
|
170
172
|
# model returns a new record with no id.
|
|
173
|
+
#
|
|
174
|
+
# @api public: an extension point for component gems (README, "Extending Proscenium").
|
|
171
175
|
def merge_options(base, override, receiver)
|
|
172
176
|
options = base.nil? ? {} : base
|
|
173
177
|
options = { js: options, css: options } unless options.is_a?(Hash)
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
# Include this into any class to expose a `source_path` class and instance method, which will return
|
|
4
4
|
# the absolute file system path to the current object.
|
|
5
|
+
#
|
|
6
|
+
# @api public: an extension point for component gems (README, "Extending Proscenium").
|
|
5
7
|
module Proscenium::SourcePath
|
|
6
8
|
def self.included(base)
|
|
7
9
|
base.extend ClassMethods
|
data/lib/proscenium/utils.rb
CHANGED
|
@@ -79,7 +79,7 @@ module Proscenium
|
|
|
79
79
|
# Example:
|
|
80
80
|
#
|
|
81
81
|
# def tab(name, *args, href:, **attributes)
|
|
82
|
-
#
|
|
82
|
+
# UiGem::Utils.merge_bang_attributes!(args, attributes, [:current])
|
|
83
83
|
# end
|
|
84
84
|
#
|
|
85
85
|
# Allowing you to use either of the following API's:
|
|
@@ -87,6 +87,7 @@ module Proscenium
|
|
|
87
87
|
# tab 'Tab 1', required: true
|
|
88
88
|
# tab 'Tab 1', :required!
|
|
89
89
|
#
|
|
90
|
+
# @api public: an extension point for component gems (README, "Extending Proscenium").
|
|
90
91
|
def merge_bang_attributes!(names, kw_attributes, allowed)
|
|
91
92
|
allowed.each do |name|
|
|
92
93
|
sym_name = name.to_sym
|
data/lib/proscenium/version.rb
CHANGED
data/lib/proscenium.rb
CHANGED
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
require 'active_support'
|
|
4
4
|
require_relative 'proscenium/error'
|
|
5
|
+
# Required rather than autoloaded: the model's files are also required directly (by the CLI), and
|
|
6
|
+
# one that defined Contexts first would leave its autoloads unregistered.
|
|
7
|
+
require_relative 'proscenium/contexts'
|
|
5
8
|
|
|
6
9
|
module Proscenium
|
|
7
10
|
extend ActiveSupport::Autoload
|
|
8
11
|
|
|
9
|
-
#
|
|
10
|
-
#
|
|
12
|
+
# Rails' default asset directories. Nothing in Proscenium reads this; it is public, and its
|
|
13
|
+
# removal waits on a release note (H-3 in docs/AUDIT.md, closed as not planned in #92).
|
|
11
14
|
DEFAULT_RAILS_ASSET_PATHS = {
|
|
12
15
|
stylesheet: 'app/assets/stylesheets/',
|
|
13
16
|
javascript: 'app/javascript/'
|
|
@@ -39,9 +42,6 @@ module Proscenium
|
|
|
39
42
|
autoload :Importer
|
|
40
43
|
autoload :Resolver
|
|
41
44
|
autoload :BundledGems
|
|
42
|
-
autoload :ContextMap
|
|
43
|
-
autoload :StaleContexts
|
|
44
|
-
autoload :MappingGeneration
|
|
45
45
|
|
|
46
46
|
class Deprecator
|
|
47
47
|
def deprecation_warning(name, message, _caller_backtrace = nil)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: proscenium
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.27.0
|
|
5
5
|
platform: aarch64-linux-gnu
|
|
6
6
|
authors:
|
|
7
7
|
- Joel Moss
|
|
@@ -61,13 +61,13 @@ files:
|
|
|
61
61
|
- lib/proscenium.rb
|
|
62
62
|
- lib/proscenium/app_package.rb
|
|
63
63
|
- lib/proscenium/builder.rb
|
|
64
|
+
- lib/proscenium/builder/request.rb
|
|
64
65
|
- lib/proscenium/bundled_gems.rb
|
|
65
66
|
- lib/proscenium/cli.rb
|
|
66
67
|
- lib/proscenium/cli/brackets.rb
|
|
67
68
|
- lib/proscenium/cli/bun_linker.rb
|
|
68
69
|
- lib/proscenium/cli/capabilities.json
|
|
69
70
|
- lib/proscenium/cli/collisions.rb
|
|
70
|
-
- lib/proscenium/cli/contexts.rb
|
|
71
71
|
- lib/proscenium/cli/diff.rb
|
|
72
72
|
- lib/proscenium/cli/error.rb
|
|
73
73
|
- lib/proscenium/cli/gem_archive.rb
|
|
@@ -82,14 +82,19 @@ files:
|
|
|
82
82
|
- lib/proscenium/cli/project_lock.rb
|
|
83
83
|
- lib/proscenium/cli/registration.rb
|
|
84
84
|
- lib/proscenium/cli/reporter.rb
|
|
85
|
-
- lib/proscenium/cli/rules.rb
|
|
86
85
|
- lib/proscenium/cli/runner.rb
|
|
87
86
|
- lib/proscenium/cli/verify.rb
|
|
88
|
-
- lib/proscenium/
|
|
87
|
+
- lib/proscenium/contexts.rb
|
|
88
|
+
- lib/proscenium/contexts/map.rb
|
|
89
|
+
- lib/proscenium/contexts/mapping_generation.rb
|
|
90
|
+
- lib/proscenium/contexts/messages.rb
|
|
91
|
+
- lib/proscenium/contexts/plan.rb
|
|
92
|
+
- lib/proscenium/contexts/projection.rb
|
|
93
|
+
- lib/proscenium/contexts/rules.rb
|
|
94
|
+
- lib/proscenium/contexts/stale.rb
|
|
89
95
|
- lib/proscenium/css_module.rb
|
|
90
96
|
- lib/proscenium/css_module/path.rb
|
|
91
97
|
- lib/proscenium/css_module/transformer.rb
|
|
92
|
-
- lib/proscenium/dependency_context.rb
|
|
93
98
|
- lib/proscenium/ensure_loaded.rb
|
|
94
99
|
- lib/proscenium/error.rb
|
|
95
100
|
- lib/proscenium/ext/proscenium
|
|
@@ -98,7 +103,6 @@ files:
|
|
|
98
103
|
- lib/proscenium/importer.rb
|
|
99
104
|
- lib/proscenium/log_subscriber.rb
|
|
100
105
|
- lib/proscenium/manifest.rb
|
|
101
|
-
- lib/proscenium/mapping_generation.rb
|
|
102
106
|
- lib/proscenium/middleware.rb
|
|
103
107
|
- lib/proscenium/middleware/base.rb
|
|
104
108
|
- lib/proscenium/middleware/chunks.rb
|
|
@@ -115,7 +119,6 @@ files:
|
|
|
115
119
|
- lib/proscenium/runtime/server.rb
|
|
116
120
|
- lib/proscenium/side_load.rb
|
|
117
121
|
- lib/proscenium/source_path.rb
|
|
118
|
-
- lib/proscenium/stale_contexts.rb
|
|
119
122
|
- lib/proscenium/templates/rescues/build_error.html.erb
|
|
120
123
|
- lib/proscenium/utils.rb
|
|
121
124
|
- lib/proscenium/version.rb
|