opal 1.6.1 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (212) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +17 -0
  3. data/CHANGELOG.md +35 -1
  4. data/Gemfile +1 -0
  5. data/HACKING.md +47 -26
  6. data/benchmark/benchmarks +415 -103
  7. data/benchmark/bm_call_overhead.yml +28 -0
  8. data/benchmark/run.rb +61 -40
  9. data/docs/cdp_common.json +3364 -0
  10. data/docs/cdp_common.md +18 -0
  11. data/docs/{headless_chrome.md → headless_browsers.md} +31 -12
  12. data/lib/opal/ast/builder.rb +1 -1
  13. data/lib/opal/builder.rb +6 -1
  14. data/lib/opal/builder_processors.rb +5 -3
  15. data/lib/opal/cache.rb +1 -7
  16. data/lib/opal/cli_options.rb +72 -58
  17. data/lib/opal/cli_runners/chrome.rb +47 -9
  18. data/lib/opal/cli_runners/chrome_cdp_interface.rb +238 -112
  19. data/lib/opal/cli_runners/compiler.rb +146 -13
  20. data/lib/opal/cli_runners/deno.rb +32 -0
  21. data/lib/opal/cli_runners/firefox.rb +350 -0
  22. data/lib/opal/cli_runners/firefox_cdp_interface.rb +212 -0
  23. data/lib/opal/cli_runners/node_modules/.bin/chrome-remote-interface.cmd +17 -0
  24. data/lib/opal/cli_runners/node_modules/.bin/chrome-remote-interface.ps1 +28 -0
  25. data/lib/opal/cli_runners/node_modules/.package-lock.json +41 -0
  26. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/LICENSE +1 -1
  27. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/README.md +322 -182
  28. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/bin/client.js +99 -114
  29. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/chrome-remote-interface.js +1 -11
  30. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/index.js +16 -11
  31. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/api.js +41 -33
  32. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/chrome.js +224 -214
  33. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/devtools.js +71 -191
  34. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/external-request.js +26 -6
  35. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/protocol.json +20788 -9049
  36. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/websocket-wrapper.js +10 -3
  37. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/package.json +59 -123
  38. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/webpack.config.js +25 -32
  39. data/lib/opal/cli_runners/node_modules/commander/History.md +298 -0
  40. data/lib/opal/cli_runners/node_modules/commander/LICENSE +22 -0
  41. data/lib/opal/cli_runners/node_modules/commander/Readme.md +217 -61
  42. data/lib/opal/cli_runners/node_modules/commander/index.js +431 -145
  43. data/lib/opal/cli_runners/node_modules/commander/package.json +16 -79
  44. data/lib/opal/cli_runners/node_modules/ws/README.md +334 -98
  45. data/lib/opal/cli_runners/node_modules/ws/browser.js +8 -0
  46. data/lib/opal/cli_runners/node_modules/ws/index.js +5 -10
  47. data/lib/opal/cli_runners/node_modules/ws/lib/buffer-util.js +129 -0
  48. data/lib/opal/cli_runners/node_modules/ws/lib/constants.js +10 -0
  49. data/lib/opal/cli_runners/node_modules/ws/lib/event-target.js +184 -0
  50. data/lib/opal/cli_runners/node_modules/ws/lib/extension.js +223 -0
  51. data/lib/opal/cli_runners/node_modules/ws/lib/limiter.js +55 -0
  52. data/lib/opal/cli_runners/node_modules/ws/lib/permessage-deflate.js +518 -0
  53. data/lib/opal/cli_runners/node_modules/ws/lib/receiver.js +607 -0
  54. data/lib/opal/cli_runners/node_modules/ws/lib/sender.js +409 -0
  55. data/lib/opal/cli_runners/node_modules/ws/lib/stream.js +180 -0
  56. data/lib/opal/cli_runners/node_modules/ws/lib/validation.js +104 -0
  57. data/lib/opal/cli_runners/node_modules/ws/lib/websocket-server.js +447 -0
  58. data/lib/opal/cli_runners/node_modules/ws/lib/websocket.js +1195 -0
  59. data/lib/opal/cli_runners/node_modules/ws/package.json +40 -106
  60. data/lib/opal/cli_runners/package-lock.json +62 -0
  61. data/lib/opal/cli_runners/package.json +1 -1
  62. data/lib/opal/cli_runners.rb +26 -4
  63. data/lib/opal/nodes/args/prepare_post_args.rb +2 -2
  64. data/lib/opal/nodes/def.rb +8 -8
  65. data/lib/opal/nodes/iter.rb +12 -12
  66. data/lib/opal/nodes/logic.rb +1 -1
  67. data/lib/opal/nodes/masgn.rb +2 -2
  68. data/lib/opal/parser/with_ruby_lexer.rb +1 -1
  69. data/lib/opal/paths.rb +14 -0
  70. data/lib/opal/rewriter.rb +2 -0
  71. data/lib/opal/rewriters/forward_args.rb +52 -4
  72. data/lib/opal/rewriters/targeted_patches.rb +94 -0
  73. data/lib/opal/version.rb +1 -1
  74. data/opal/corelib/basic_object.rb +1 -1
  75. data/opal/corelib/boolean.rb +2 -2
  76. data/opal/corelib/class.rb +11 -0
  77. data/opal/corelib/constants.rb +3 -3
  78. data/opal/corelib/enumerable.rb +4 -0
  79. data/opal/corelib/enumerator.rb +1 -1
  80. data/opal/corelib/hash.rb +2 -2
  81. data/opal/corelib/helpers.rb +1 -1
  82. data/opal/corelib/kernel.rb +3 -3
  83. data/opal/corelib/method.rb +1 -1
  84. data/opal/corelib/module.rb +29 -8
  85. data/opal/corelib/proc.rb +7 -5
  86. data/opal/corelib/runtime.js +141 -78
  87. data/opal/corelib/set.rb +252 -0
  88. data/opal/corelib/string.rb +2 -1
  89. data/opal/corelib/time.rb +2 -2
  90. data/opal/opal.rb +1 -0
  91. data/opal.gemspec +1 -0
  92. data/spec/filters/bugs/array.rb +22 -13
  93. data/spec/filters/bugs/base64.rb +5 -5
  94. data/spec/filters/bugs/basicobject.rb +16 -8
  95. data/spec/filters/bugs/bigdecimal.rb +161 -160
  96. data/spec/filters/bugs/binding.rb +10 -10
  97. data/spec/filters/bugs/class.rb +8 -8
  98. data/spec/filters/bugs/complex.rb +2 -1
  99. data/spec/filters/bugs/date.rb +79 -81
  100. data/spec/filters/bugs/datetime.rb +29 -29
  101. data/spec/filters/bugs/delegate.rb +1 -3
  102. data/spec/filters/bugs/encoding.rb +69 -69
  103. data/spec/filters/bugs/enumerable.rb +22 -20
  104. data/spec/filters/bugs/enumerator.rb +88 -85
  105. data/spec/filters/bugs/exception.rb +46 -40
  106. data/spec/filters/bugs/file.rb +32 -32
  107. data/spec/filters/bugs/float.rb +26 -21
  108. data/spec/filters/bugs/freeze.rb +88 -0
  109. data/spec/filters/bugs/hash.rb +39 -38
  110. data/spec/filters/bugs/integer.rb +57 -44
  111. data/spec/filters/bugs/io.rb +1 -1
  112. data/spec/filters/bugs/kernel.rb +349 -269
  113. data/spec/filters/bugs/language.rb +220 -188
  114. data/spec/filters/bugs/main.rb +5 -3
  115. data/spec/filters/bugs/marshal.rb +38 -38
  116. data/spec/filters/bugs/math.rb +2 -1
  117. data/spec/filters/bugs/method.rb +73 -62
  118. data/spec/filters/bugs/module.rb +163 -143
  119. data/spec/filters/bugs/numeric.rb +6 -6
  120. data/spec/filters/bugs/objectspace.rb +16 -16
  121. data/spec/filters/bugs/openstruct.rb +1 -1
  122. data/spec/filters/bugs/pack_unpack.rb +51 -51
  123. data/spec/filters/bugs/pathname.rb +7 -7
  124. data/spec/filters/bugs/proc.rb +63 -63
  125. data/spec/filters/bugs/random.rb +7 -6
  126. data/spec/filters/bugs/range.rb +12 -9
  127. data/spec/filters/bugs/rational.rb +8 -7
  128. data/spec/filters/bugs/regexp.rb +49 -48
  129. data/spec/filters/bugs/ruby-32.rb +56 -0
  130. data/spec/filters/bugs/set.rb +30 -30
  131. data/spec/filters/bugs/singleton.rb +4 -4
  132. data/spec/filters/bugs/string.rb +187 -99
  133. data/spec/filters/bugs/stringio.rb +7 -0
  134. data/spec/filters/bugs/stringscanner.rb +68 -68
  135. data/spec/filters/bugs/struct.rb +11 -9
  136. data/spec/filters/bugs/symbol.rb +1 -1
  137. data/spec/filters/bugs/time.rb +78 -63
  138. data/spec/filters/bugs/trace_point.rb +4 -4
  139. data/spec/filters/bugs/unboundmethod.rb +32 -17
  140. data/spec/filters/bugs/warnings.rb +8 -12
  141. data/spec/filters/unsupported/array.rb +24 -107
  142. data/spec/filters/unsupported/basicobject.rb +12 -12
  143. data/spec/filters/unsupported/bignum.rb +27 -52
  144. data/spec/filters/unsupported/class.rb +1 -2
  145. data/spec/filters/unsupported/delegator.rb +3 -3
  146. data/spec/filters/unsupported/enumerable.rb +2 -9
  147. data/spec/filters/unsupported/enumerator.rb +2 -11
  148. data/spec/filters/unsupported/file.rb +1 -1
  149. data/spec/filters/unsupported/float.rb +28 -47
  150. data/spec/filters/unsupported/hash.rb +8 -14
  151. data/spec/filters/unsupported/integer.rb +75 -91
  152. data/spec/filters/unsupported/kernel.rb +17 -35
  153. data/spec/filters/unsupported/language.rb +11 -19
  154. data/spec/filters/unsupported/marshal.rb +22 -41
  155. data/spec/filters/unsupported/matchdata.rb +28 -52
  156. data/spec/filters/unsupported/math.rb +1 -1
  157. data/spec/filters/unsupported/privacy.rb +229 -285
  158. data/spec/filters/unsupported/range.rb +1 -5
  159. data/spec/filters/unsupported/regexp.rb +40 -66
  160. data/spec/filters/unsupported/set.rb +2 -2
  161. data/spec/filters/unsupported/singleton.rb +4 -4
  162. data/spec/filters/unsupported/string.rb +305 -508
  163. data/spec/filters/unsupported/struct.rb +3 -4
  164. data/spec/filters/unsupported/symbol.rb +15 -18
  165. data/spec/filters/unsupported/thread.rb +1 -7
  166. data/spec/filters/unsupported/time.rb +159 -202
  167. data/spec/filters/unsupported/usage_of_files.rb +170 -259
  168. data/spec/lib/builder_spec.rb +4 -4
  169. data/spec/lib/rewriters/forward_args_spec.rb +32 -12
  170. data/spec/mspec-opal/runner.rb +2 -0
  171. data/spec/ruby_specs +4 -0
  172. data/stdlib/deno/base.rb +28 -0
  173. data/stdlib/deno/file.rb +340 -0
  174. data/stdlib/{headless_chrome.rb → headless_browser/base.rb} +1 -1
  175. data/stdlib/headless_browser/file.rb +15 -0
  176. data/stdlib/headless_browser.rb +4 -0
  177. data/stdlib/native.rb +1 -1
  178. data/stdlib/nodejs/file.rb +5 -0
  179. data/stdlib/opal/platform.rb +8 -6
  180. data/stdlib/opal-platform.rb +14 -8
  181. data/stdlib/set.rb +1 -258
  182. data/tasks/benchmarking.rake +62 -19
  183. data/tasks/performance.rake +1 -1
  184. data/tasks/testing.rake +5 -3
  185. data/test/nodejs/test_file.rb +29 -10
  186. data/test/opal/http_server.rb +28 -11
  187. data/test/opal/unsupported_and_bugs.rb +2 -1
  188. metadata +89 -50
  189. data/lib/opal/cli_runners/node_modules/ultron/LICENSE +0 -22
  190. data/lib/opal/cli_runners/node_modules/ultron/index.js +0 -138
  191. data/lib/opal/cli_runners/node_modules/ultron/package.json +0 -112
  192. data/lib/opal/cli_runners/node_modules/ws/SECURITY.md +0 -33
  193. data/lib/opal/cli_runners/node_modules/ws/lib/BufferUtil.fallback.js +0 -56
  194. data/lib/opal/cli_runners/node_modules/ws/lib/BufferUtil.js +0 -15
  195. data/lib/opal/cli_runners/node_modules/ws/lib/ErrorCodes.js +0 -28
  196. data/lib/opal/cli_runners/node_modules/ws/lib/EventTarget.js +0 -158
  197. data/lib/opal/cli_runners/node_modules/ws/lib/Extensions.js +0 -69
  198. data/lib/opal/cli_runners/node_modules/ws/lib/PerMessageDeflate.js +0 -339
  199. data/lib/opal/cli_runners/node_modules/ws/lib/Receiver.js +0 -520
  200. data/lib/opal/cli_runners/node_modules/ws/lib/Sender.js +0 -438
  201. data/lib/opal/cli_runners/node_modules/ws/lib/Validation.fallback.js +0 -9
  202. data/lib/opal/cli_runners/node_modules/ws/lib/Validation.js +0 -17
  203. data/lib/opal/cli_runners/node_modules/ws/lib/WebSocket.js +0 -705
  204. data/lib/opal/cli_runners/node_modules/ws/lib/WebSocketServer.js +0 -336
  205. data/spec/filters/bugs/boolean.rb +0 -3
  206. data/spec/filters/bugs/matrix.rb +0 -3
  207. data/spec/filters/unsupported/fixnum.rb +0 -15
  208. data/spec/filters/unsupported/freeze.rb +0 -102
  209. data/spec/filters/unsupported/pathname.rb +0 -4
  210. data/spec/filters/unsupported/proc.rb +0 -4
  211. data/spec/filters/unsupported/random.rb +0 -5
  212. data/spec/filters/unsupported/taint.rb +0 -162
@@ -0,0 +1,18 @@
1
+ ### Common CDP of Chrome, Firefox, Node and Deno
2
+
3
+ cdp_common.json documents a subset of the common CDP as reported by Chrome, version 107 and Firefox, version 106.
4
+ All entries that where marked as "experimental" or "deprecated" have been removed.
5
+ Only entries, that where included in both browsers with equal state have been kept.
6
+
7
+ The CDP as implemented by Chrome or Firefox can be retrieved directly from the browsers by starting them with the `--remote-debugging-port` option
8
+ and visiting the (http://localhost:9222/json/protocol)[http://localhost:9222/json/protocol] endpoint.
9
+
10
+ Unfortunately, Firefox advertising this protocol support doesn't mean it actually is available or even works!
11
+ Various domains and methods, advertised as available from Firefox, present a "UnknownMethodError" or other errors.
12
+
13
+ The Node and Deno CDP protocol can be inspected by starting them with the `--inspect` option and visiting the
14
+ (http://localhost:9229/json/protocol)[http://localhost:9229/json/protocol] endpoint.
15
+
16
+ The actual websocket endpoint uri can be retrieved at (http://localhost:9222/json/version)[http://localhost:9222/json/version]
17
+ or as list of targets at (http://localhost:9222/json/list)[http://localhost:9222/json/list],
18
+ likewise in Node or Deno with the adjusted port number.
@@ -1,16 +1,21 @@
1
- # Running code in a Headless Chrome
1
+ # Running code in a Headless Browsers
2
2
 
3
3
  ## Requirements
4
4
 
5
- First of all, make sure that you have Chrome at least 59.0 installed.
5
+ First of all, make sure that you have Chrome, at least version 59.0, installed or Firefox, at least version 106.
6
6
 
7
- ## Using the runner
7
+ ## Using the runners
8
8
 
9
- To run your code using headless chrome, use `-R chrome` (`--runner chrome`) option:
9
+ To run your code using headless Chrome, use `-R chrome` (`--runner chrome`) option:
10
10
 
11
11
  $ opal -Rchrome -e "puts 'Hello, Opal'"
12
12
  Hello, Opal
13
13
 
14
+ To run your code using headless Firefox, use `-R firefox` (`--runner firefox`) option:
15
+
16
+ $ opal -Rfirefox -e "puts 'Hello, Opal'"
17
+ Hello, Opal
18
+
14
19
  The runner also listens for any exceptions and prints formatted stracktraces back to your console:
15
20
 
16
21
  $ opal -Rchrome -e "
@@ -27,7 +32,7 @@ The runner also listens for any exceptions and prints formatted stracktraces bac
27
32
 
28
33
  ## Using exit codes
29
34
 
30
- By default headless chrome runner explicitly sets exit code to 1 when there was any error in the code.
35
+ By default headless browser runner explicitly sets exit code to 1 when there was any error in the code.
31
36
 
32
37
  $ opal -Rchrome -e "42"; echo $?
33
38
  0
@@ -46,23 +51,21 @@ You can change final exit code by using `Kernel#exit`, but make sure to require
46
51
  $ opal -Rchrome -ropal/platform -e "exit(1)"; echo $?
47
52
  1
48
53
 
49
- Also `Kernel#exit` doesn't abort your script. It simply takes the value that was passed to the first
50
- invocation and persists it in `window.OPAL_EXIT_CODE`. Later headless chrome runner extracts it from the chrome runtime.
51
-
52
54
  ## Known limitations
53
55
 
54
- 1. `exit` doesn't abort you script (but `raise/throw` does)
55
- 2. When you call `console.log(one, two, three)` from your code headless chrome prints only the first passed object.
56
+ 1. When you call `console.log(one, two, three)` from your code headless chrome prints only the first passed object.
56
57
  The reason behind it is the format of the message that chrome sends to the runner.
57
58
  Opal intentionally uses a simplified method from Chrome API (`Console.messageAdded`) to catch `console.log` invocations.
58
59
  (Check `lib/opal/cli_runners/chrome.js` do get more information)
59
60
 
60
61
  ## Internals
61
62
 
63
+ ### Chrome
64
+
62
65
  Under the hood when you call `opal -Rchrome -e 'your code'` Opal uses chrome runner that is defined in
63
66
  `lib/opal/cli_runners/chrome.rb`. This runner tries to connect to `localhost:9222` (9222 is a default port for a headless chrome server)
64
- or runs the server on its own. It detects your platform and uses a default path to the chrome executable
65
- (`Opal::CliRunners::Chrome#chrome_executable`) but you can override it by specifying `GOOGLE_CHROME_BINARY` environment
67
+ or runs the server on its own. It detects your platform and uses a default path to the Chrome executable
68
+ (`Opal::CliRunners::Chrome#chrome_executable`), but you can override it by specifying `GOOGLE_CHROME_BINARY` environment
66
69
  variable.
67
70
 
68
71
  When the server is up and running it passes compiled js code to `lib/opal/cli_runners/chrome_cdp_interface.rb`
@@ -70,6 +73,18 @@ as a plain input using stdin (basically, it's a second part of the runner).
70
73
  `chrome_cdp_interface.rb` is a node js + Opal script that does the main job. It runs any provided code on the running chrome server,
71
74
  catches errors and forwards console messages.
72
75
 
76
+ ### Firefox
77
+
78
+ This runner tries to connect to `localhost:9333` (9333 is the default port for a headless firefox server used by Opal to prevent accidental
79
+ connection to a lingering Chrome at port 9222)
80
+ or runs the server on its own. It detects your platform and uses a default path to the Firefox executable
81
+ (`Opal::CliRunners::Firefox#firefox_executable`), but you can override it by specifying `MOZILLA_FIREFOX_BINARY` environment
82
+ variable.
83
+
84
+ When the server is up and running it passes compiled js code to `lib/opal/cli_runners/firefox_cdp_interface.rb`
85
+ as a plain input using stdin (basically, it's a second part of the runner).
86
+ `firefox_cdp_interface.rb` is a node js + Opal script that does the main job. It runs any provided code on the running chrome server,
87
+ catches errors and forwards console messages.
73
88
 
74
89
  ## Using a remote chrome server
75
90
 
@@ -82,6 +97,8 @@ you can override default values by specifying `CHROME_HOST` and `CHROME_PORT` en
82
97
 
83
98
  NOTE: `CHROME_HOST` requires a chrome server to be started. You can't start remotely a server on a different host.
84
99
 
100
+ The `CHROME_HOST` and `CHROME_PORT` environment variables are also used by the Firefox runner, the underlying 'chrome-remote-interface'
101
+ node module depends on them.
85
102
 
86
103
  ## Additional options
87
104
 
@@ -93,3 +110,5 @@ If you need to pass additional CLI options to the Chrome executable you can do s
93
110
  Docker users may need `CHROME_OPTS="--no-sandbox"` due to the user namespaces limitations.
94
111
 
95
112
  _For a list of additional options see https://developers.google.com/web/updates/2017/04/headless-chrome_
113
+
114
+ For the Firefox runner use the `FIREFOX_OPTS` environment variable instead.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'opal/ast/node'
4
- require 'parser/ruby31'
4
+ require 'parser/ruby32'
5
5
 
6
6
  module Opal
7
7
  module AST
data/lib/opal/builder.rb CHANGED
@@ -192,6 +192,11 @@ module Opal
192
192
  end
193
193
  end
194
194
 
195
+ # Return a list of dependent files, for watching purposes
196
+ def dependent_files
197
+ processed.map(&:abs_path).compact.select { |fn| File.exist?(fn) }
198
+ end
199
+
195
200
  private
196
201
 
197
202
  def process_requires(rel_path, requires, autoloads, options)
@@ -231,7 +236,7 @@ module Opal
231
236
 
232
237
  options = options.merge(cache: cache)
233
238
 
234
- processor.new(source, rel_path, @compiler_options.merge(options))
239
+ processor.new(source, rel_path, abs_path, @compiler_options.merge(options))
235
240
  end
236
241
 
237
242
  def read(path, autoload)
@@ -6,15 +6,17 @@ require 'opal/erb'
6
6
  module Opal
7
7
  module BuilderProcessors
8
8
  class Processor
9
- def initialize(source, filename, options = {})
9
+ def initialize(source, filename, abs_path = nil, options = {})
10
+ options = abs_path if abs_path.is_a? Hash
11
+
10
12
  source += "\n" unless source.end_with?("\n")
11
- @source, @filename, @options = source, filename, options.dup
13
+ @source, @filename, @abs_path, @options = source, filename, abs_path, options.dup
12
14
  @cache = @options.delete(:cache) { Opal.cache }
13
15
  @requires = []
14
16
  @required_trees = []
15
17
  @autoloads = []
16
18
  end
17
- attr_reader :source, :filename, :options, :requires, :required_trees, :autoloads
19
+ attr_reader :source, :filename, :options, :requires, :required_trees, :autoloads, :abs_path
18
20
 
19
21
  def to_s
20
22
  source.to_s
data/lib/opal/cache.rb CHANGED
@@ -48,13 +48,7 @@ module Opal
48
48
 
49
49
  def runtime_key
50
50
  @runtime_key ||= begin
51
- # We want to ensure the compiler and any Gemfile/gemspec (for development)
52
- # stays untouched
53
- opal_path = File.expand_path('..', Opal.gem_dir)
54
- files = Dir["#{opal_path}/{Gemfile*,*.gemspec,lib/**/*}"]
55
-
56
- # Also check if parser wasn't changed:
57
- files += $LOADED_FEATURES.grep(%r{lib/(parser|ast)})
51
+ files = Opal.dependent_files
58
52
 
59
53
  digest [
60
54
  files.sort.map { |f| "#{f}:#{File.size(f)}:#{File.mtime(f).to_f}" },
@@ -13,6 +13,10 @@ module Opal
13
13
 
14
14
  separator ''
15
15
 
16
+ on('--repl', 'Run the Opal REPL') do
17
+ options[:repl] = true
18
+ end
19
+
16
20
  on('-v', '--verbose', 'print version number, then turn on verbose mode') do
17
21
  print_version
18
22
  exit if ARGV.empty?
@@ -32,10 +36,6 @@ module Opal
32
36
  exit
33
37
  end
34
38
 
35
- on('--repl', 'Run the Opal REPL') do
36
- options[:repl] = true
37
- end
38
-
39
39
  on('-h', '--help', 'Show this message') do
40
40
  puts self
41
41
  exit
@@ -43,11 +43,6 @@ module Opal
43
43
 
44
44
  section 'Basic Options:'
45
45
 
46
- on('-I', '--include DIR', 'Append a load path (may be used more than once)') do |i|
47
- options[:load_paths] ||= []
48
- options[:load_paths] << i
49
- end
50
-
51
46
  on('-e', '--eval SOURCE', String,
52
47
  'One line of script. Several -e\'s allowed. Omit [programfile]'
53
48
  ) do |source|
@@ -69,6 +64,11 @@ module Opal
69
64
  options[:rbrequires] << library
70
65
  end
71
66
 
67
+ on('-I', '--include DIR', 'Append a load path (may be used more than once)') do |i|
68
+ options[:load_paths] ||= []
69
+ options[:load_paths] << i
70
+ end
71
+
72
72
  on('-s', '--stub FILE', String, 'Stubbed files will be compiled as empty files') do |stub|
73
73
  options[:stubs] ||= []
74
74
  options[:stubs] << stub
@@ -86,54 +86,78 @@ module Opal
86
86
 
87
87
  section 'Running Options:'
88
88
 
89
- on('--sexp', 'Show Sexps') do
90
- options[:sexp] = true
89
+ on('-R', '--runner RUNNER', Opal::CliRunners.to_h.keys, 'Choose the runner:', "nodejs (default), #{(Opal::CliRunners.to_h.keys - %i[nodejs compiler]).join(', ')}") do |runner|
90
+ options[:runner] = runner.to_sym
91
91
  end
92
92
 
93
- on('--debug-source-map', 'Debug source map') do
94
- options[:debug_source_map] = true
93
+ on('--server-port PORT', 'Set the port for the server runner (default port: 3000)') do |port|
94
+ options[:runner_options] ||= {}
95
+ options[:runner_options][:port] = port.to_i
96
+ end
97
+
98
+ on('--runner-options JSON', 'Set options specific to the selected runner as a JSON string (e.g. port for server)') do |json_options|
99
+ require 'json'
100
+ runner_options = JSON.parse(json_options, symbolize_names: true)
101
+ options[:runner_options] ||= {}
102
+ options[:runner_options].merge!(runner_options)
95
103
  end
96
104
 
105
+ section 'Builder Options:'
106
+
97
107
  on('-c', '--compile', 'Compile to JavaScript') do
98
108
  options[:runner] = :compiler
99
109
  end
100
110
 
101
- on('-R', '--runner RUNNER', Opal::CliRunners.to_h.keys, "Choose the runner: nodejs (default), #{(Opal::CliRunners.to_h.keys - [:nodejs]).join(', ')}") do |runner|
102
- options[:runner] = runner.to_sym
111
+ on('-o', '--output FILE', 'Output JavaScript to FILE') do |file|
112
+ options[:output] = File.open(file, 'w')
103
113
  end
104
114
 
105
- on('--runner-options JSON', 'Set options specific to the selected runner as a JSON string (e.g. port for server)') do |json_options|
106
- require 'json'
107
- runner_options = JSON.parse(json_options, symbolize_names: true)
115
+ on('-P', '--map FILE', 'Output source map to FILE') do |file|
108
116
  options[:runner_options] ||= {}
109
- options[:runner_options].merge!(runner_options)
117
+ options[:runner_options][:map_file] = file
110
118
  end
111
119
 
112
- on('--server-port PORT', '(deprecated, use --runner-options) Set the port for the server runner (default port: 3000)') do |port|
120
+ on('--no-source-map', "Don't append source map to a compiled file") do
113
121
  options[:runner_options] ||= {}
114
- options[:runner_options][:port] = port.to_i
122
+ options[:runner_options][:no_source_map] = true
115
123
  end
116
124
 
117
- on('-E', '--no-exit', 'Do not append a Kernel#exit at the end of file') do
118
- options[:no_exit] = true
125
+ on('--watch', 'Run the compiler in foreground, recompiling every filesystem change') do
126
+ options[:runner_options] ||= {}
127
+ options[:runner_options][:watch] = true
119
128
  end
120
129
 
121
- section 'Compilation Options:'
130
+ on('--no-cache', 'Disable filesystem cache') do
131
+ options[:no_cache] = true
132
+ end
122
133
 
123
- on('-M', '--no-method-missing', 'Disable method missing') do
124
- options[:method_missing] = false
134
+ on('-L', '--library', 'Compile only required libraries. Omit [programfile] and [-e]. Assumed [-cOE].') do
135
+ options[:lib_only] = true
136
+ options[:no_exit] = true
137
+ options[:compile] = true
138
+ options[:skip_opal_require] = true
125
139
  end
126
140
 
127
141
  on('-O', '--no-opal', 'Disable implicit `require "opal"`') do
128
142
  options[:skip_opal_require] = true
129
143
  end
130
144
 
131
- on('-A', '--arity-check', 'Enable arity check') do
132
- options[:arity_check] = true
145
+ on('-E', '--no-exit', 'Do not append a Kernel#exit at the end of file') do
146
+ options[:no_exit] = true
133
147
  end
134
148
 
135
- on('-V', 'Enable inline Operators') do
136
- options[:inline_operators] = true
149
+ section 'Compiler Options:'
150
+
151
+ on('--use-strict', 'Enables JavaScript\'s strict mode (i.e., adds \'use strict\'; statement)') do
152
+ options[:use_strict] = true
153
+ end
154
+
155
+ on('--esm', 'Wraps compiled bundle as for ES6 module') do
156
+ options[:esm] = true
157
+ end
158
+
159
+ on('-A', '--arity-check', 'Enable arity check') do
160
+ options[:arity_check] = true
137
161
  end
138
162
 
139
163
  dynamic_require_levels = %w[error warning ignore]
@@ -152,53 +176,43 @@ module Opal
152
176
  options[:missing_require_severity] = level.to_sym
153
177
  end
154
178
 
155
- on('-P', '--map FILE', 'Output path to FILE') do |file|
156
- options[:runner_options] ||= {}
157
- options[:runner_options][:map_file] = file
158
- end
159
-
160
- on('--no-source-map', "Don't append source map to a compiled file") do
161
- options[:runner_options] ||= {}
162
- options[:runner_options][:no_source_map] = true
179
+ on('--enable-source-location', 'Compiles source location for each method definition.') do
180
+ options[:enable_source_location] = true
163
181
  end
164
182
 
165
- on('-F', '--file FILE', 'Set filename for compiled code') do |file|
166
- options[:file] = file
183
+ on('--parse-comments', 'Compiles comments for each method definition.') do
184
+ options[:parse_comments] = true
167
185
  end
168
186
 
169
- on('-L', '--library', 'Compile only required libraries. Omit [programfile] and [-e]. Assumed [-cOE].') do
170
- options[:lib_only] = true
171
- options[:no_exit] = true
172
- options[:compile] = true
173
- options[:skip_opal_require] = true
187
+ on('--enable-file-source-embed', 'Embeds file sources to be accessed by applications.') do
188
+ options[:enable_file_source_embed] = true
174
189
  end
175
190
 
176
191
  on('--irb', 'Enable IRB var mode') do
177
192
  options[:irb] = true
178
193
  end
179
194
 
180
- on('--enable-source-location', 'Compiles source location for each method definition.') do
181
- options[:enable_source_location] = true
195
+ on('-M', '--no-method-missing', 'Disable method missing') do
196
+ options[:method_missing] = false
182
197
  end
183
198
 
184
- on('--enable-file-source-embed', 'Embeds file sources to be accessed by applications.') do
185
- options[:enable_file_source_embed] = true
199
+ on('-F', '--file FILE', 'Set filename for compiled code') do |file|
200
+ options[:file] = file
186
201
  end
187
202
 
188
- on('--use-strict', 'Enables JavaScript\'s strict mode (i.e., adds \'use strict\'; statement)') do
189
- options[:use_strict] = true
203
+ on('-V', '(deprecated; always enabled) Enable inline Operators') do
204
+ warn '* -V is deprecated and has no effect'
205
+ options[:inline_operators] = true
190
206
  end
191
207
 
192
- on('--parse-comments', 'Compiles comments for each method definition.') do
193
- options[:parse_comments] = true
194
- end
208
+ section 'Debug Options:'
195
209
 
196
- on('--no-cache', 'Disable filesystem cache') do
197
- options[:no_cache] = true
210
+ on('--sexp', 'Show Sexps') do
211
+ options[:sexp] = true
198
212
  end
199
213
 
200
- on('--esm', 'Wraps compiled bundle as for ES6 module(requires -c or -L)') do
201
- options[:esm] = true
214
+ on('--debug-source-map', 'Debug source map') do
215
+ options[:debug_source_map] = true
202
216
  end
203
217
 
204
218
  separator ''
@@ -21,16 +21,14 @@ module Opal
21
21
  end
22
22
 
23
23
  def initialize(data)
24
- builder = data[:builder].call
25
- options = data[:options]
26
- argv = data[:argv]
27
-
24
+ argv = data[:argv]
28
25
  if argv && argv.any?
29
26
  warn "warning: ARGV is not supported by the Chrome runner #{argv.inspect}"
30
27
  end
31
28
 
32
- @output = options.fetch(:output, $stdout)
33
- @builder = builder
29
+ options = data[:options]
30
+ @output = options.fetch(:output, $stdout)
31
+ @builder = data[:builder].call
34
32
  end
35
33
 
36
34
  attr_reader :output, :exit_status, :builder
@@ -43,7 +41,8 @@ module Opal
43
41
  env = {
44
42
  'CHROME_HOST' => chrome_host,
45
43
  'CHROME_PORT' => chrome_port.to_s,
46
- 'NODE_PATH' => File.join(__dir__, 'node_modules')
44
+ 'NODE_PATH' => File.join(__dir__, 'node_modules'),
45
+ 'OPAL_CDP_EXT' => builder.output_extension
47
46
  }
48
47
 
49
48
  cmd = [
@@ -53,7 +52,7 @@ module Opal
53
52
  '-I', __dir__,
54
53
  '-r', 'source-map-support-node',
55
54
  SCRIPT_PATH,
56
- dir,
55
+ dir
57
56
  ]
58
57
 
59
58
  Kernel.exec(env, *cmd)
@@ -75,10 +74,12 @@ module Opal
75
74
  # https://groups.google.com/a/chromium.org/forum/#!topic/chromium-discuss/U5qyeX_ydBo
76
75
  # The only way is to create temporary files and pass them to chrome.
77
76
  File.binwrite("#{dir}/index.#{ext}", js)
77
+ File.binwrite("#{dir}/index.map", map)
78
78
  File.binwrite("#{dir}/source-map-support.js", stack)
79
79
  File.binwrite("#{dir}/index.html", <<~HTML)
80
80
  <html><head>
81
81
  <meta charset='utf-8'>
82
+ <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
82
83
  <script src='./source-map-support.js'></script>
83
84
  <script>
84
85
  window.opalheadlesschrome = true;
@@ -115,14 +116,46 @@ module Opal
115
116
  def run_chrome_server
116
117
  raise 'Chrome server can be started only on localhost' if chrome_host != DEFAULT_CHROME_HOST
117
118
 
119
+ profile = mktmpprofile
120
+
118
121
  # Disable web security with "--disable-web-security" flag to be able to do XMLHttpRequest (see test_openuri.rb)
122
+ # For other options see https://github.com/puppeteer/puppeteer/blob/main/packages/puppeteer-core/src/node/ChromeLauncher.ts
119
123
  chrome_server_cmd = %{#{OS.shellescape(chrome_executable)} \
124
+ --allow-pre-commit-input \
125
+ --disable-background-networking \
126
+ --enable-features=NetworkServiceInProcess2 \
127
+ --disable-background-timer-throttling \
128
+ --disable-backgrounding-occluded-windows \
129
+ --disable-breakpad \
130
+ --disable-client-side-phishing-detection \
131
+ --disable-component-extensions-with-background-pages \
132
+ --disable-default-apps \
133
+ --disable-dev-shm-usage \
134
+ --disable-extensions \
135
+ --disable-features=Translate,BackForwardCache,AcceptCHFrame,AvoidUnnecessaryBeforeUnloadCheckSync \
136
+ --disable-hang-monitor \
137
+ --disable-ipc-flooding-protection \
138
+ --disable-popup-blocking \
139
+ --disable-prompt-on-repost \
140
+ --disable-renderer-backgrounding \
141
+ --disable-sync \
142
+ --force-color-profile=srgb \
143
+ --metrics-recording-only \
144
+ --no-first-run \
145
+ --enable-automation \
146
+ --password-store=basic \
147
+ --use-mock-keychain \
148
+ --enable-blink-features=IdleDetection \
149
+ --export-tagged-pdf \
120
150
  --headless \
151
+ --user-data-dir=#{profile} \
152
+ --hide-scrollbars \
153
+ --mute-audio \
121
154
  --disable-web-security \
122
155
  --remote-debugging-port=#{chrome_port} \
123
156
  #{ENV['CHROME_OPTS']}}
124
157
 
125
- chrome_pid = Process.spawn(chrome_server_cmd)
158
+ chrome_pid = Process.spawn(chrome_server_cmd, in: OS.dev_null, out: OS.dev_null, err: OS.dev_null)
126
159
 
127
160
  Timeout.timeout(30) do
128
161
  loop do
@@ -142,6 +175,7 @@ module Opal
142
175
  elsif chrome_pid
143
176
  Process.kill('HUP', chrome_pid)
144
177
  end
178
+ FileUtils.rm_rf(profile) if profile
145
179
  end
146
180
 
147
181
  def chrome_server_running?
@@ -181,6 +215,10 @@ module Opal
181
215
  def mktmpdir(&block)
182
216
  Dir.mktmpdir('chrome-opal-', &block)
183
217
  end
218
+
219
+ def mktmpprofile
220
+ Dir.mktmpdir('chrome-opal-profile-')
221
+ end
184
222
  end
185
223
  end
186
224
  end