opal 1.2.0 → 1.3.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
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')