homura-runtime 0.3.6 → 0.3.7

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.
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'fileutils'
4
- require 'pathname'
3
+ require "fileutils"
4
+ require "pathname"
5
5
 
6
6
  module HomuraRuntime
7
7
  module BuildSupport
8
- RUNTIME_GEM_NAME = 'homura-runtime'
9
- SINATRA_GEM_NAME = 'sinatra-homura'
10
- SEQUEL_D1_GEM_NAME = 'sequel-d1'
8
+ RUNTIME_GEM_NAME = "homura-runtime"
9
+ SINATRA_GEM_NAME = "sinatra-homura"
10
+ SEQUEL_D1_GEM_NAME = "sequel-d1"
11
11
 
12
12
  class << self
13
13
  def loaded_spec(name, loaded_specs: Gem.loaded_specs)
@@ -18,22 +18,24 @@ module HomuraRuntime
18
18
  spec = loaded_spec(name, loaded_specs: loaded_specs)
19
19
  return spec.full_gem_path if spec
20
20
 
21
- raise("homura build: gem #{name} not loaded; use bundle exec from app root")
21
+ raise(
22
+ "homura build: gem #{name} not loaded; use bundle exec from app root"
23
+ )
22
24
  end
23
25
 
24
26
  def runtime_root(current_file:, loaded_specs: Gem.loaded_specs)
25
27
  spec = loaded_spec(RUNTIME_GEM_NAME, loaded_specs: loaded_specs)
26
28
  return Pathname(spec.full_gem_path) if spec
27
29
 
28
- Pathname(current_file).expand_path.join('../..')
30
+ Pathname(current_file).expand_path.join("../..")
29
31
  end
30
32
 
31
33
  def gem_lib(name, loaded_specs: Gem.loaded_specs)
32
- File.join(gem_root(name, loaded_specs: loaded_specs), 'lib')
34
+ File.join(gem_root(name, loaded_specs: loaded_specs), "lib")
33
35
  end
34
36
 
35
37
  def gem_vendor(name, loaded_specs: Gem.loaded_specs)
36
- vendor = File.join(gem_root(name, loaded_specs: loaded_specs), 'vendor')
38
+ vendor = File.join(gem_root(name, loaded_specs: loaded_specs), "vendor")
37
39
  return vendor if Dir.exist?(vendor)
38
40
 
39
41
  nil
@@ -43,64 +45,82 @@ module HomuraRuntime
43
45
  spec = loaded_spec(name, loaded_specs: loaded_specs)
44
46
  return nil unless spec
45
47
 
46
- File.join(spec.full_gem_path, 'lib')
48
+ File.join(spec.full_gem_path, "lib")
47
49
  end
48
50
 
49
51
  def maybe_gem_vendor(name, loaded_specs: Gem.loaded_specs)
50
52
  spec = loaded_spec(name, loaded_specs: loaded_specs)
51
53
  return nil unless spec
52
54
 
53
- vendor = File.join(spec.full_gem_path, 'vendor')
55
+ vendor = File.join(spec.full_gem_path, "vendor")
54
56
  return vendor if Dir.exist?(vendor)
55
57
 
56
58
  nil
57
59
  end
58
60
 
59
- def runtime_file(*names, current_file: __FILE__, loaded_specs: Gem.loaded_specs)
60
- runtime_root(current_file: current_file, loaded_specs: loaded_specs).join('runtime', *names)
61
+ def runtime_file(
62
+ *names,
63
+ current_file: __FILE__,
64
+ loaded_specs: Gem.loaded_specs
65
+ )
66
+ runtime_root(
67
+ current_file: current_file,
68
+ loaded_specs: loaded_specs
69
+ ).join("runtime", *names)
61
70
  end
62
71
 
63
- def ensure_standalone_runtime(project_root, current_file: __FILE__, loaded_specs: Gem.loaded_specs)
72
+ def ensure_standalone_runtime(
73
+ project_root,
74
+ current_file: __FILE__,
75
+ loaded_specs: Gem.loaded_specs
76
+ )
64
77
  # The homura runtime needs two .mjs glue files alongside the
65
78
  # generated `worker.entrypoint.mjs`. Until 0.2.22 we wrote them
66
79
  # to `cf-runtime/` at the project root, which made every Ruby
67
80
  # repo carry two opaque JS files in source control. Hide them
68
81
  # under `build/cf-runtime/` so the build artifact tree owns
69
82
  # them — `build/` is already in the example .gitignore template.
70
- target_dir = Pathname(project_root).join('build', 'cf-runtime')
83
+ target_dir = Pathname(project_root).join("build", "cf-runtime")
71
84
  FileUtils.mkdir_p(target_dir)
72
85
 
73
86
  %w[setup-node-crypto.mjs worker_module.mjs].each do |name|
74
- FileUtils.cp(runtime_file(name, current_file: current_file, loaded_specs: loaded_specs), target_dir.join(name))
87
+ FileUtils.cp(
88
+ runtime_file(
89
+ name,
90
+ current_file: current_file,
91
+ loaded_specs: loaded_specs
92
+ ),
93
+ target_dir.join(name)
94
+ )
75
95
  end
76
96
 
77
97
  target_dir
78
98
  end
79
99
 
80
- def standalone_load_paths(project_root, with_db:, loaded_specs: Gem.loaded_specs)
100
+ def standalone_load_paths(
101
+ project_root,
102
+ with_db:,
103
+ loaded_specs: Gem.loaded_specs
104
+ )
81
105
  root = Pathname(project_root)
82
106
  load_paths = []
83
107
 
84
108
  hv = vendor_from_gemfile(root)
85
109
  load_paths << hv.to_s if hv
86
110
 
87
- load_paths += ['.', 'build/auto_await', 'build/auto_await/app', 'app']
111
+ load_paths += %w[. build/auto_await build/auto_await/app app]
88
112
  [
89
113
  gem_lib(RUNTIME_GEM_NAME, loaded_specs: loaded_specs),
90
114
  gem_vendor(RUNTIME_GEM_NAME, loaded_specs: loaded_specs),
91
115
  maybe_gem_lib(SINATRA_GEM_NAME, loaded_specs: loaded_specs),
92
116
  maybe_gem_vendor(SINATRA_GEM_NAME, loaded_specs: loaded_specs)
93
- ].compact.each do |path|
94
- load_paths << path
95
- end
117
+ ].compact.each { |path| load_paths << path }
96
118
 
97
119
  if with_db
98
120
  [
99
121
  gem_vendor(SEQUEL_D1_GEM_NAME, loaded_specs: loaded_specs),
100
122
  gem_lib(SEQUEL_D1_GEM_NAME, loaded_specs: loaded_specs)
101
- ].compact.each do |path|
102
- load_paths << path
103
- end
123
+ ].compact.each { |path| load_paths << path }
104
124
  end
105
125
 
106
126
  # Pick up any other gems that should ship in the Workers bundle:
@@ -117,7 +137,8 @@ module HomuraRuntime
117
137
  # app code.
118
138
  opal_gem_paths(root, loaded_specs: loaded_specs).each do |gem_path|
119
139
  basename = gem_path.basename.to_s
120
- rewritten_lib = root.join('build', 'auto_await', "gem_#{basename}", 'lib')
140
+ rewritten_lib =
141
+ root.join("build", "auto_await", "gem_#{basename}", "lib")
121
142
  load_paths << rewritten_lib.to_s if rewritten_lib.directory?
122
143
  %w[lib vendor].each do |sub|
123
144
  dir = gem_path.join(sub)
@@ -125,8 +146,8 @@ module HomuraRuntime
125
146
  end
126
147
  end
127
148
 
128
- load_paths << 'vendor' if root.join('vendor').directory?
129
- load_paths << 'build'
149
+ load_paths << "vendor" if root.join("vendor").directory?
150
+ load_paths << "build"
130
151
  load_paths.uniq
131
152
  end
132
153
 
@@ -134,20 +155,27 @@ module HomuraRuntime
134
155
  base = Pathname(project_root).basename.to_s
135
156
  parts = base.split(/[^A-Za-z0-9]+/).reject(&:empty?)
136
157
  module_name = parts.map { |part| part[0].upcase + part[1..].to_s }.join
137
- module_name = 'App' if module_name.empty?
158
+ module_name = "App" if module_name.empty?
138
159
  module_name = "App#{module_name}" if module_name.match?(/\A\d/)
139
160
  "#{module_name}#{suffix}"
140
161
  end
141
162
 
142
163
  def vendor_from_gemfile(project_root)
143
- gf = Pathname(project_root).join('Gemfile')
164
+ gf = Pathname(project_root).join("Gemfile")
144
165
  return unless gf.file?
145
166
 
146
167
  txt = gf.read
147
- return unless (m = txt.match(/#{Regexp.escape(RUNTIME_GEM_NAME)}['"]\s*,\s*path:\s*['"]([^'"]+)['"]/))
168
+ unless (
169
+ m =
170
+ txt.match(
171
+ /#{Regexp.escape(RUNTIME_GEM_NAME)}['"]\s*,\s*path:\s*['"]([^'"]+)['"]/
172
+ )
173
+ )
174
+ return
175
+ end
148
176
 
149
177
  runtime_path = Pathname.new(m[1]).expand_path(project_root)
150
- vend = runtime_path.join('..', '..', 'vendor').expand_path
178
+ vend = runtime_path.join("..", "..", "vendor").expand_path
151
179
  vend if vend.directory?
152
180
  end
153
181
 
@@ -166,8 +194,8 @@ module HomuraRuntime
166
194
  next if wired.include?(spec.name)
167
195
  meta = spec.metadata
168
196
  next unless meta.is_a?(Hash)
169
- flag = meta['homura.auto_await']
170
- next unless flag == 'true' || flag == true
197
+ flag = meta["homura.auto_await"]
198
+ next unless flag == "true" || flag == true
171
199
  next if spec.full_gem_path.nil?
172
200
  gem_path = Pathname(spec.full_gem_path)
173
201
  out << gem_path if gem_path.directory?
@@ -185,10 +213,17 @@ module HomuraRuntime
185
213
  # * `require: false` gems (dev tooling like `gem 'rspec', path: ..., require: false`)
186
214
  # * gems declared inside `group :development do … end` /
187
215
  # `group :test do … end` blocks (they don't ship to production)
188
- EXCLUDED_GROUPS = %i[development test dev_test development_test ci tools].freeze
216
+ EXCLUDED_GROUPS = %i[
217
+ development
218
+ test
219
+ dev_test
220
+ development_test
221
+ ci
222
+ tools
223
+ ].freeze
189
224
 
190
225
  def path_gemfile_entries(project_root)
191
- gf = Pathname(project_root).join('Gemfile')
226
+ gf = Pathname(project_root).join("Gemfile")
192
227
  return [] unless gf.file?
193
228
 
194
229
  wired = [RUNTIME_GEM_NAME, SINATRA_GEM_NAME, SEQUEL_D1_GEM_NAME]
@@ -197,14 +232,15 @@ module HomuraRuntime
197
232
 
198
233
  gf.read.each_line do |line|
199
234
  stripped = line.strip
200
- next if stripped.empty? || stripped.start_with?('#')
235
+ next if stripped.empty? || stripped.start_with?("#")
201
236
 
202
237
  if (m = stripped.match(/\Agroup\s+(.+?)\s+do\b/))
203
- groups = m[1].scan(/[:'"]([A-Za-z0-9_]+)['"]?/).flatten.map(&:to_sym)
238
+ groups =
239
+ m[1].scan(/[:'"]([A-Za-z0-9_]+)['"]?/).flatten.map(&:to_sym)
204
240
  group_stack.push(groups)
205
241
  next
206
242
  end
207
- if stripped == 'end'
243
+ if stripped == "end"
208
244
  group_stack.pop unless group_stack.empty?
209
245
  next
210
246
  end
@@ -50,7 +50,7 @@ module Cloudflare
50
50
  attr_reader :operation
51
51
  def initialize(message, operation: nil)
52
52
  @operation = operation
53
- super("[Cloudflare::Cache] op=#{operation || 'match'}: #{message}")
53
+ super("[Cloudflare::Cache] op=#{operation || "match"}: #{message}")
54
54
  end
55
55
  end
56
56
 
@@ -62,7 +62,10 @@ module Cloudflare
62
62
  # Returns a fresh wrapper each call; the underlying JS object is a
63
63
  # singleton per isolate.
64
64
  def self.default
65
- Cache.new(`(typeof caches !== 'undefined' && caches ? caches.default : null)`, 'default')
65
+ Cache.new(
66
+ `(typeof caches !== 'undefined' && caches ? caches.default : null)`,
67
+ "default"
68
+ )
66
69
  end
67
70
 
68
71
  # caches.open(name) — named cache partitions. Returns a JS Promise
@@ -71,12 +74,13 @@ module Cloudflare
71
74
  # don't re-open the handle.
72
75
  def self.open(name)
73
76
  name_str = name.to_s
74
- js_promise = `(typeof caches !== 'undefined' && caches && caches.open ? caches.open(#{name_str}) : Promise.resolve(null))`
77
+ js_promise =
78
+ `(typeof caches !== 'undefined' && caches && caches.open ? caches.open(#{name_str}) : Promise.resolve(null))`
75
79
  js_cache = js_promise.__await__
76
80
  Cache.new(js_cache, name_str)
77
81
  end
78
82
 
79
- def initialize(js_cache, name = 'default')
83
+ def initialize(js_cache, name = "default")
80
84
  @js_cache = js_cache
81
85
  @name = name.to_s
82
86
  end
@@ -109,19 +113,22 @@ module Cloudflare
109
113
  # JS Request. Derive the URL from the same shapes supported by
110
114
  # `request_to_js` so the `url` field on the returned
111
115
  # HTTPResponse is always a real URL.
112
- url_str = if request_or_url.is_a?(String)
113
- request_or_url
114
- elsif defined?(Cloudflare::HTTPResponse) && request_or_url.is_a?(Cloudflare::HTTPResponse)
115
- request_or_url.url.to_s
116
- elsif `(#{request_or_url} != null && typeof #{request_or_url} === 'object' && typeof #{request_or_url}.url === 'string')`
117
- `String(#{request_or_url}.url)`
118
- else
119
- request_or_url.to_s
120
- end
116
+ url_str =
117
+ if request_or_url.is_a?(String)
118
+ request_or_url
119
+ elsif defined?(Cloudflare::HTTPResponse) &&
120
+ request_or_url.is_a?(Cloudflare::HTTPResponse)
121
+ request_or_url.url.to_s
122
+ elsif `(#{request_or_url} != null && typeof #{request_or_url} === 'object' && typeof #{request_or_url}.url === 'string')`
123
+ `String(#{request_or_url}.url)`
124
+ else
125
+ request_or_url.to_s
126
+ end
121
127
 
122
128
  # Single-line backtick IIFE — see `put` for the Opal multi-line
123
129
  # x-string quirk that silently drops the returned Promise.
124
- js_promise = `(async function(js, req, Kernel, err_klass) { if (js == null || js === Opal.nil) return null; var cached; try { cached = await js.match(req); } catch (e) { Kernel.$raise(err_klass.$new(e && e.message ? e.message : String(e), Opal.hash({ operation: 'match' }))); } if (cached == null) return null; var text = ''; try { text = await cached.text(); } catch (_) { text = ''; } var hk = []; var hv = []; if (cached.headers && typeof cached.headers.forEach === 'function') { cached.headers.forEach(function(v, k) { hk.push(String(k).toLowerCase()); hv.push(String(v)); }); } return { status: cached.status|0, text: text, hkeys: hk, hvals: hv }; })(#{js}, #{req}, #{Kernel}, #{err_klass})`
130
+ js_promise =
131
+ `(async function(js, req, Kernel, err_klass) { if (js == null || js === Opal.nil) return null; var cached; try { cached = await js.match(req); } catch (e) { Kernel.$raise(err_klass.$new(e && e.message ? e.message : String(e), Opal.hash({ operation: 'match' }))); } if (cached == null) return null; var text = ''; try { text = await cached.text(); } catch (_) { text = ''; } var hk = []; var hv = []; if (cached.headers && typeof cached.headers.forEach === 'function') { cached.headers.forEach(function(v, k) { hk.push(String(k).toLowerCase()); hv.push(String(v)); }); } return { status: cached.status|0, text: text, hkeys: hk, hvals: hv }; })(#{js}, #{req}, #{Kernel}, #{err_klass})`
125
132
  js_result = js_promise.__await__
126
133
  return nil if `#{js_result} == null`
127
134
 
@@ -135,10 +142,10 @@ module Cloudflare
135
142
  i += 1
136
143
  end
137
144
  response_klass.new(
138
- status: `#{js_result}.status`,
145
+ status: `#{js_result}.status`,
139
146
  headers: h,
140
- body: `#{js_result}.text`,
141
- url: url_str
147
+ body: `#{js_result}.text`,
148
+ url: url_str
142
149
  )
143
150
  end
144
151
 
@@ -203,17 +210,17 @@ module Cloudflare
203
210
  # support but the impl only covered JS Request-like objects — both
204
211
  # the docs AND the code now line up.)
205
212
  def request_to_js(request_or_url)
206
- if request_or_url.is_a?(String)
207
- return `new Request(#{request_or_url})`
208
- end
209
- if defined?(Cloudflare::HTTPResponse) && request_or_url.is_a?(Cloudflare::HTTPResponse)
213
+ return `new Request(#{request_or_url})` if request_or_url.is_a?(String)
214
+ if defined?(Cloudflare::HTTPResponse) &&
215
+ request_or_url.is_a?(Cloudflare::HTTPResponse)
210
216
  url_str = request_or_url.url.to_s
211
217
  return `new Request(#{url_str})`
212
218
  end
213
219
  if `(#{request_or_url} != null && typeof #{request_or_url} === 'object' && typeof #{request_or_url}.url === 'string')`
214
220
  return request_or_url
215
221
  end
216
- raise ArgumentError, "Cloudflare::Cache request must be a String URL, Cloudflare::HTTPResponse, or JS Request (got #{request_or_url.class})"
222
+ raise ArgumentError,
223
+ "Cloudflare::Cache request must be a String URL, Cloudflare::HTTPResponse, or JS Request (got #{request_or_url.class})"
217
224
  end
218
225
 
219
226
  def ruby_headers_to_js(hash)