opal 1.2.0 → 1.3.0.alpha1

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 (159) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.await.js +6 -0
  3. data/.eslintrc.js +34 -0
  4. data/.github/workflows/build.yml +8 -0
  5. data/.rubocop.yml +9 -0
  6. data/CHANGELOG.md +4 -0
  7. data/README.md +1 -1
  8. data/Rakefile +1 -0
  9. data/UNRELEASED.md +64 -38
  10. data/docs/async.md +109 -0
  11. data/docs/roda-sprockets.md +0 -2
  12. data/exe/opal +2 -0
  13. data/exe/opal-repl +2 -2
  14. data/lib/opal/builder.rb +5 -1
  15. data/lib/opal/builder_processors.rb +7 -2
  16. data/lib/opal/cache/file_cache.rb +119 -0
  17. data/lib/opal/cache.rb +71 -0
  18. data/lib/opal/cli.rb +35 -1
  19. data/lib/opal/cli_options.rb +21 -0
  20. data/lib/opal/cli_runners/chrome.rb +21 -14
  21. data/lib/opal/cli_runners/chrome_cdp_interface.js +30285 -0
  22. data/lib/opal/cli_runners/{chrome.js → chrome_cdp_interface.rb} +27 -6
  23. data/lib/opal/cli_runners/compiler.rb +2 -1
  24. data/lib/opal/cli_runners/gjs.rb +27 -0
  25. data/lib/opal/cli_runners/mini_racer.rb +36 -0
  26. data/lib/opal/cli_runners/source-map-support-browser.js +276 -91
  27. data/lib/opal/cli_runners/source-map-support-node.js +276 -91
  28. data/lib/opal/cli_runners/source-map-support.js +60 -18
  29. data/lib/opal/cli_runners.rb +2 -0
  30. data/lib/opal/compiler.rb +99 -10
  31. data/lib/opal/fragment.rb +77 -14
  32. data/lib/opal/nodes/args/extract_kwrestarg.rb +6 -4
  33. data/lib/opal/nodes/args/extract_restarg.rb +10 -12
  34. data/lib/opal/nodes/args.rb +28 -0
  35. data/lib/opal/nodes/base.rb +29 -5
  36. data/lib/opal/nodes/call.rb +123 -2
  37. data/lib/opal/nodes/case.rb +7 -1
  38. data/lib/opal/nodes/class.rb +12 -2
  39. data/lib/opal/nodes/def.rb +3 -23
  40. data/lib/opal/nodes/definitions.rb +21 -4
  41. data/lib/opal/nodes/helpers.rb +2 -2
  42. data/lib/opal/nodes/if.rb +39 -9
  43. data/lib/opal/nodes/iter.rb +15 -3
  44. data/lib/opal/nodes/lambda.rb +3 -1
  45. data/lib/opal/nodes/literal.rb +13 -7
  46. data/lib/opal/nodes/logic.rb +2 -2
  47. data/lib/opal/nodes/module.rb +12 -2
  48. data/lib/opal/nodes/rescue.rb +59 -34
  49. data/lib/opal/nodes/scope.rb +88 -6
  50. data/lib/opal/nodes/super.rb +52 -25
  51. data/lib/opal/nodes/top.rb +13 -7
  52. data/lib/opal/nodes/while.rb +7 -1
  53. data/lib/opal/parser/patch.rb +2 -1
  54. data/lib/opal/repl.rb +137 -49
  55. data/lib/opal/rewriters/binary_operator_assignment.rb +10 -10
  56. data/lib/opal/rewriters/block_to_iter.rb +3 -3
  57. data/lib/opal/rewriters/for_rewriter.rb +7 -7
  58. data/lib/opal/rewriters/js_reserved_words.rb +5 -3
  59. data/lib/opal/source_map/file.rb +7 -4
  60. data/lib/opal/source_map/map.rb +17 -3
  61. data/lib/opal/version.rb +1 -1
  62. data/opal/corelib/array.rb +2 -2
  63. data/opal/corelib/binding.rb +46 -0
  64. data/opal/corelib/boolean.rb +54 -4
  65. data/opal/corelib/class.rb +2 -0
  66. data/opal/corelib/constants.rb +2 -2
  67. data/opal/corelib/error.rb +98 -12
  68. data/opal/corelib/io.rb +250 -38
  69. data/opal/corelib/kernel/format.rb +5 -2
  70. data/opal/corelib/kernel.rb +44 -23
  71. data/opal/corelib/main.rb +5 -0
  72. data/opal/corelib/method.rb +1 -0
  73. data/opal/corelib/module.rb +28 -0
  74. data/opal/corelib/number.rb +12 -1
  75. data/opal/corelib/random/seedrandom.js.rb +2 -2
  76. data/opal/corelib/regexp.rb +47 -3
  77. data/opal/corelib/runtime.js +152 -12
  78. data/opal/corelib/string/encoding.rb +17 -17
  79. data/opal/corelib/string.rb +2 -0
  80. data/opal/corelib/struct.rb +10 -3
  81. data/opal/corelib/trace_point.rb +57 -0
  82. data/opal/opal/full.rb +2 -0
  83. data/package.json +3 -2
  84. data/spec/filters/bugs/array.rb +0 -1
  85. data/spec/filters/bugs/basicobject.rb +0 -1
  86. data/spec/filters/bugs/binding.rb +27 -0
  87. data/spec/filters/bugs/enumerator.rb +132 -0
  88. data/spec/filters/bugs/exception.rb +70 -93
  89. data/spec/filters/bugs/float.rb +0 -1
  90. data/spec/filters/bugs/kernel.rb +3 -9
  91. data/spec/filters/bugs/language.rb +15 -58
  92. data/spec/filters/bugs/main.rb +16 -0
  93. data/spec/filters/bugs/matrix.rb +39 -0
  94. data/spec/filters/bugs/method.rb +0 -2
  95. data/spec/filters/bugs/module.rb +36 -79
  96. data/spec/filters/bugs/proc.rb +0 -1
  97. data/spec/filters/bugs/regexp.rb +0 -16
  98. data/spec/filters/bugs/trace_point.rb +12 -0
  99. data/spec/filters/bugs/warnings.rb +0 -4
  100. data/spec/filters/unsupported/freeze.rb +2 -0
  101. data/spec/filters/unsupported/privacy.rb +4 -0
  102. data/spec/lib/compiler_spec.rb +7 -1
  103. data/spec/lib/repl_spec.rb +4 -2
  104. data/spec/lib/source_map/file_spec.rb +1 -1
  105. data/spec/mspec-opal/formatters.rb +18 -4
  106. data/spec/mspec-opal/runner.rb +2 -2
  107. data/spec/opal/core/boolean_spec.rb +44 -0
  108. data/spec/opal/core/hash_spec.rb +8 -0
  109. data/spec/opal/core/number/to_s_spec.rb +11 -0
  110. data/spec/opal/stdlib/json/ext_spec.rb +3 -3
  111. data/spec/opal/stdlib/logger/logger_spec.rb +10 -1
  112. data/spec/ruby_specs +18 -0
  113. data/stdlib/await.rb +83 -0
  114. data/stdlib/base64.rb +4 -4
  115. data/stdlib/bigdecimal/bignumber.js.rb +4 -2
  116. data/stdlib/bigdecimal.rb +1 -0
  117. data/stdlib/gjs/io.rb +33 -0
  118. data/stdlib/gjs/kernel.rb +5 -0
  119. data/stdlib/gjs.rb +2 -0
  120. data/stdlib/js.rb +4 -0
  121. data/stdlib/json.rb +3 -3
  122. data/stdlib/logger.rb +1 -1
  123. data/stdlib/nashorn/file.rb +2 -0
  124. data/stdlib/nodejs/env.rb +7 -0
  125. data/stdlib/nodejs/file.rb +6 -41
  126. data/stdlib/nodejs/io.rb +21 -5
  127. data/stdlib/nodejs/js-yaml-3-6-1.js +2 -2
  128. data/stdlib/opal/miniracer.rb +6 -0
  129. data/stdlib/opal/platform.rb +4 -0
  130. data/stdlib/opal/repl_js.rb +5 -0
  131. data/stdlib/opal/replutils.rb +271 -0
  132. data/stdlib/opal-parser.rb +24 -11
  133. data/stdlib/opal-platform.rb +8 -0
  134. data/stdlib/promise/v2.rb +16 -4
  135. data/stdlib/promise.rb +14 -0
  136. data/stdlib/stringio.rb +13 -110
  137. data/stdlib/thread.rb +29 -0
  138. data/tasks/building.rake +10 -4
  139. data/tasks/linting-parse-eslint-results.js +39 -0
  140. data/tasks/linting.rake +38 -28
  141. data/tasks/performance/asciidoctor_test.rb.erb +6 -0
  142. data/tasks/performance/optimization_status.rb +77 -0
  143. data/tasks/performance.rake +149 -0
  144. data/tasks/testing.rake +9 -1
  145. data/test/nodejs/test_await.rb +169 -0
  146. data/test/opal/promisev2/test_error.rb +9 -3
  147. data/test/opal/unsupported_and_bugs.rb +5 -0
  148. data/vendored-minitest/minitest/benchmark.rb +9 -7
  149. data/vendored-minitest/minitest/test.rb +14 -12
  150. data/vendored-minitest/minitest.rb +19 -16
  151. data/yarn.lock +686 -117
  152. metadata +60 -23
  153. data/.jshintrc +0 -41
  154. data/spec/filters/unsupported/refinements.rb +0 -8
  155. data/vendored-minitest/minitest/hell.rb +0 -11
  156. data/vendored-minitest/minitest/parallel.rb +0 -65
  157. data/vendored-minitest/minitest/pride.rb +0 -4
  158. data/vendored-minitest/minitest/pride_plugin.rb +0 -142
  159. data/vendored-minitest/minitest/unit.rb +0 -45
data/lib/opal/cache.rb ADDED
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'opal/paths'
4
+ require 'digest/sha2' unless RUBY_ENGINE == 'opal'
5
+
6
+ if RUBY_ENGINE != 'opal'
7
+ require 'opal/cache/file_cache'
8
+ end
9
+
10
+ module Opal
11
+ # A Sprockets-compatible cache, for example an instance of
12
+ # Opal::Cache::FileCache or Opal::Cache::NullCache.
13
+ singleton_class.attr_writer :cache
14
+
15
+ def self.cache
16
+ @cache ||=
17
+ if RUBY_ENGINE == 'opal' || ENV['OPAL_CACHE_DISABLE'] || !Cache::FileCache.find_dir
18
+ Cache::NullCache.new
19
+ else
20
+ Cache::FileCache.new
21
+ end
22
+ end
23
+
24
+ module Cache
25
+ class NullCache
26
+ def fetch(*)
27
+ yield
28
+ end
29
+ end
30
+
31
+ module_function
32
+
33
+ def fetch(cache, key, &block)
34
+ # Extension to the Sprockets API of Cache, if a cache responds
35
+ # to #fetch, then we call it instead of using #get and #set.
36
+ return cache.fetch(key, &block) if cache.respond_to? :fetch
37
+
38
+ key = digest(key.join('/')) + '-' + runtime_key
39
+
40
+ data = cache.get(key)
41
+
42
+ data || begin
43
+ compiler = yield
44
+ cache.set(key, compiler)
45
+ compiler
46
+ end
47
+ end
48
+
49
+ def runtime_key
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)})
58
+
59
+ digest [
60
+ files.sort.map { |f| "#{f}:#{File.size(f)}:#{File.mtime(f).to_f}" },
61
+ RUBY_VERSION,
62
+ RUBY_PATCHLEVEL
63
+ ].join('/')
64
+ end
65
+ end
66
+
67
+ def digest(string)
68
+ ::Digest::SHA256.hexdigest(string)[-32..-1].to_i(16).to_s(36)
69
+ end
70
+ end
71
+ end
data/lib/opal/cli.rb CHANGED
@@ -8,7 +8,8 @@ module Opal
8
8
  class CLI
9
9
  attr_reader :options, :file, :compiler_options, :evals, :load_paths, :argv,
10
10
  :output, :requires, :rbrequires, :gems, :stubs, :verbose, :runner_options,
11
- :preload, :filename, :debug, :no_exit, :lib_only, :missing_require_severity
11
+ :preload, :filename, :debug, :no_exit, :lib_only, :missing_require_severity,
12
+ :no_cache
12
13
 
13
14
  class << self
14
15
  attr_accessor :stdout
@@ -23,6 +24,7 @@ module Opal
23
24
 
24
25
  @options = options
25
26
  @sexp = options.delete(:sexp)
27
+ @repl = options.delete(:repl)
26
28
  @file = options.delete(:file)
27
29
  @no_exit = options.delete(:no_exit)
28
30
  @lib_only = options.delete(:lib_only)
@@ -38,6 +40,9 @@ module Opal
38
40
  @filename = options.delete(:filename) { @file && @file.path }
39
41
  @requires = options.delete(:requires) { [] }
40
42
  @rbrequires = options.delete(:rbrequires) { [] }
43
+ @no_cache = options.delete(:no_cache) { false }
44
+
45
+ @debug_source_map = options.delete(:debug_source_map) { false }
41
46
 
42
47
  @missing_require_severity = options.delete(:missing_require_severity) { Opal::Config.missing_require_severity }
43
48
 
@@ -60,6 +65,9 @@ module Opal
60
65
 
61
66
  def run
62
67
  return show_sexp if @sexp
68
+ return debug_source_map if @debug_source_map
69
+ return run_repl if @repl
70
+
63
71
  @exit_status = runner.call(
64
72
  options: runner_options,
65
73
  output: output,
@@ -73,6 +81,13 @@ module Opal
73
81
  raise(ArgumentError, "unknown runner: #{@runner_type.inspect}")
74
82
  end
75
83
 
84
+ def run_repl
85
+ require 'opal/repl'
86
+
87
+ repl = REPL.new
88
+ repl.run(OriginalARGV)
89
+ end
90
+
76
91
  attr_reader :exit_status
77
92
 
78
93
  def builder
@@ -88,6 +103,9 @@ module Opal
88
103
  missing_require_severity: missing_require_severity,
89
104
  )
90
105
 
106
+ # --no-cache
107
+ builder.cache = Opal::Cache::NullCache.new if no_cache
108
+
91
109
  # --include
92
110
  builder.append_paths(*load_paths)
93
111
 
@@ -124,6 +142,21 @@ module Opal
124
142
  end
125
143
  end
126
144
 
145
+ def debug_source_map
146
+ evals_or_file do |contents, filename|
147
+ compiler = Opal::Compiler.new(contents, file: filename, **compiler_options)
148
+
149
+ compiler.compile
150
+
151
+ result = compiler.result
152
+ source_map = compiler.source_map.to_json
153
+
154
+ b64 = [result, source_map, contents].map { |i| Base64.strict_encode64(i) }.join(',')
155
+
156
+ output.puts "https://sokra.github.io/source-map-visualization/#base64,#{b64}"
157
+ end
158
+ end
159
+
127
160
  def compiler_option_names
128
161
  %w[
129
162
  method_missing
@@ -135,6 +168,7 @@ module Opal
135
168
  enable_source_location
136
169
  use_strict
137
170
  parse_comments
171
+ esm
138
172
  ]
139
173
  end
140
174
 
@@ -32,6 +32,10 @@ module Opal
32
32
  exit
33
33
  end
34
34
 
35
+ on('--repl', 'Run the Opal REPL') do
36
+ options[:repl] = true
37
+ end
38
+
35
39
  on('-h', '--help', 'Show this message') do
36
40
  puts self
37
41
  exit
@@ -86,6 +90,10 @@ module Opal
86
90
  options[:sexp] = true
87
91
  end
88
92
 
93
+ on('--debug-source-map', 'Debug source map') do
94
+ options[:debug_source_map] = true
95
+ end
96
+
89
97
  on('-c', '--compile', 'Compile to JavaScript') do
90
98
  options[:runner] = :compiler
91
99
  end
@@ -149,6 +157,11 @@ module Opal
149
157
  options[:runner_options][:map_file] = file
150
158
  end
151
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
163
+ end
164
+
152
165
  on('-F', '--file FILE', 'Set filename for compiled code') do |file|
153
166
  options[:file] = file
154
167
  end
@@ -176,6 +189,14 @@ module Opal
176
189
  options[:parse_comments] = true
177
190
  end
178
191
 
192
+ on('--no-cache', 'Disable filesystem cache') do
193
+ options[:no_cache] = true
194
+ end
195
+
196
+ on('--esm', 'Wraps compiled bundle as for ES6 module(requires -c or -L)') do
197
+ options[:esm] = true
198
+ end
199
+
179
200
  separator ''
180
201
  end
181
202
 
@@ -8,7 +8,7 @@ require 'tmpdir'
8
8
  module Opal
9
9
  module CliRunners
10
10
  class Chrome
11
- SCRIPT_PATH = File.expand_path('chrome.js', __dir__).freeze
11
+ SCRIPT_PATH = File.expand_path('chrome_cdp_interface.js', __dir__).freeze
12
12
 
13
13
  DEFAULT_CHROME_HOST = 'localhost'
14
14
  DEFAULT_CHROME_PORT = 9222
@@ -16,7 +16,6 @@ module Opal
16
16
  def self.call(data)
17
17
  runner = new(data)
18
18
  runner.run
19
- runner.exit_status
20
19
  end
21
20
 
22
21
  def initialize(data)
@@ -37,23 +36,24 @@ module Opal
37
36
  def run
38
37
  mktmpdir do |dir|
39
38
  with_chrome_server do
39
+ # This has to be moved to some generator.
40
+ system(%{bundle exec opal -r opal/cli_runners/source-map-support-node } +
41
+ %{-cE #{__dir__}/chrome_cdp_interface.rb > "#{SCRIPT_PATH}"}
42
+ )
43
+
44
+ prepare_files_in(dir)
45
+
40
46
  cmd = [
41
47
  'env',
42
48
  "CHROME_HOST=#{chrome_host}",
43
49
  "CHROME_PORT=#{chrome_port}",
44
50
  'node',
45
- '--require', "#{__dir__}/source-map-support",
46
- SCRIPT_PATH
51
+ SCRIPT_PATH,
52
+ dir,
47
53
  ]
48
54
 
49
- prepare_files_in(dir)
50
-
51
- IO.popen(cmd, 'w', out: output) do |io|
52
- io.write dir
53
- end
55
+ Kernel.exec(*cmd)
54
56
  end
55
-
56
- @exit_status = $?.exitstatus
57
57
  end
58
58
  end
59
59
 
@@ -108,11 +108,11 @@ module Opal
108
108
  raise 'Chrome server can be started only on localhost' if chrome_host != DEFAULT_CHROME_HOST
109
109
 
110
110
  # Disable web security with "--disable-web-security" flag to be able to do XMLHttpRequest (see test_openuri.rb)
111
- chrome_server_cmd = "#{chrome_executable} \
111
+ chrome_server_cmd = %{"#{chrome_executable}" \
112
112
  --headless \
113
113
  --disable-web-security \
114
114
  --remote-debugging-port=#{chrome_port} \
115
- #{ENV['CHROME_OPTS']}"
115
+ #{ENV['CHROME_OPTS']}}
116
116
 
117
117
  chrome_pid = Process.spawn(chrome_server_cmd)
118
118
 
@@ -144,13 +144,20 @@ module Opal
144
144
  ENV['GOOGLE_CHROME_BINARY'] ||
145
145
  case RbConfig::CONFIG['host_os']
146
146
  when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
147
- raise 'Headless chrome is supported only by Mac OS and Linux'
147
+ [
148
+ 'C:/Program Files/Google/Chrome Dev/Application/chrome.exe',
149
+ 'C:/Program Files/Google/Chrome/Application/chrome.exe'
150
+ ].each do |path|
151
+ next unless File.exist? path
152
+ return path
153
+ end
148
154
  when /darwin|mac os/
149
155
  '/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome'
150
156
  when /linux/
151
157
  %w[
152
158
  google-chrome-stable
153
159
  chromium
160
+ chromium-freeworld
154
161
  chromium-browser
155
162
  ].each do |name|
156
163
  next unless system('sh', '-c', "command -v #{name.shellescape}", out: '/dev/null')