opal 1.5.1 → 1.6.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +4 -1
  3. data/HACKING.md +23 -0
  4. data/UNRELEASED.md +42 -0
  5. data/benchmark/run.rb +1 -0
  6. data/docs/compiled_ruby.md +8 -0
  7. data/docs/compiler.md +1 -1
  8. data/docs/compiler_directives.md +1 -1
  9. data/docs/getting_started.md +17 -0
  10. data/docs/headless_chrome.md +1 -1
  11. data/docs/index.md +123 -0
  12. data/docs/templates.md +37 -37
  13. data/docs/unsupported_features.md +0 -4
  14. data/lib/opal/builder.rb +59 -39
  15. data/lib/opal/builder_scheduler/prefork.rb +259 -0
  16. data/lib/opal/builder_scheduler/sequential.rb +13 -0
  17. data/lib/opal/builder_scheduler.rb +29 -0
  18. data/lib/opal/cache/file_cache.rb +5 -0
  19. data/lib/opal/cli.rb +22 -18
  20. data/lib/opal/cli_options.rb +4 -0
  21. data/lib/opal/cli_runners/chrome.rb +13 -9
  22. data/lib/opal/cli_runners/chrome_cdp_interface.rb +19 -2
  23. data/lib/opal/cli_runners/compiler.rb +1 -1
  24. data/lib/opal/cli_runners/gjs.rb +3 -1
  25. data/lib/opal/cli_runners/mini_racer.rb +5 -3
  26. data/lib/opal/cli_runners/nodejs.rb +3 -3
  27. data/lib/opal/cli_runners/server.rb +13 -28
  28. data/lib/opal/cli_runners/system_runner.rb +5 -3
  29. data/lib/opal/cli_runners.rb +7 -6
  30. data/lib/opal/compiler.rb +25 -2
  31. data/lib/opal/config.rb +10 -0
  32. data/lib/opal/nodes/args/ensure_kwargs_are_kwargs.rb +2 -6
  33. data/lib/opal/nodes/args/extract_kwarg.rb +3 -4
  34. data/lib/opal/nodes/args/extract_kwargs.rb +3 -1
  35. data/lib/opal/nodes/args/extract_kwoptarg.rb +1 -1
  36. data/lib/opal/nodes/args/extract_kwrestarg.rb +4 -1
  37. data/lib/opal/nodes/args/extract_optarg.rb +1 -1
  38. data/lib/opal/nodes/args/extract_post_arg.rb +1 -1
  39. data/lib/opal/nodes/args/extract_post_optarg.rb +1 -1
  40. data/lib/opal/nodes/args/extract_restarg.rb +2 -2
  41. data/lib/opal/nodes/args/initialize_iterarg.rb +1 -1
  42. data/lib/opal/nodes/args/initialize_shadowarg.rb +1 -1
  43. data/lib/opal/nodes/args/prepare_post_args.rb +4 -2
  44. data/lib/opal/nodes/base.rb +14 -3
  45. data/lib/opal/nodes/call.rb +10 -14
  46. data/lib/opal/nodes/class.rb +3 -1
  47. data/lib/opal/nodes/closure.rb +250 -0
  48. data/lib/opal/nodes/def.rb +7 -11
  49. data/lib/opal/nodes/definitions.rb +4 -2
  50. data/lib/opal/nodes/if.rb +12 -2
  51. data/lib/opal/nodes/iter.rb +11 -17
  52. data/lib/opal/nodes/logic.rb +15 -63
  53. data/lib/opal/nodes/module.rb +3 -1
  54. data/lib/opal/nodes/rescue.rb +23 -15
  55. data/lib/opal/nodes/scope.rb +7 -1
  56. data/lib/opal/nodes/top.rb +27 -4
  57. data/lib/opal/nodes/while.rb +42 -26
  58. data/lib/opal/nodes.rb +1 -0
  59. data/lib/opal/os.rb +59 -0
  60. data/lib/opal/rewriter.rb +2 -0
  61. data/lib/opal/rewriters/returnable_logic.rb +14 -0
  62. data/lib/opal/rewriters/thrower_finder.rb +90 -0
  63. data/lib/opal/simple_server.rb +12 -6
  64. data/lib/opal/source_map/file.rb +1 -1
  65. data/lib/opal/source_map/map.rb +9 -1
  66. data/lib/opal/util.rb +1 -1
  67. data/lib/opal/version.rb +1 -1
  68. data/opal/corelib/array.rb +68 -3
  69. data/opal/corelib/basic_object.rb +1 -0
  70. data/opal/corelib/comparable.rb +1 -1
  71. data/opal/corelib/complex.rb +1 -0
  72. data/opal/corelib/constants.rb +2 -2
  73. data/opal/corelib/enumerable.rb +4 -2
  74. data/opal/corelib/enumerator/chain.rb +4 -0
  75. data/opal/corelib/enumerator/generator.rb +5 -3
  76. data/opal/corelib/enumerator/lazy.rb +3 -1
  77. data/opal/corelib/enumerator/yielder.rb +2 -4
  78. data/opal/corelib/enumerator.rb +3 -1
  79. data/opal/corelib/error/errno.rb +2 -1
  80. data/opal/corelib/error.rb +13 -2
  81. data/opal/corelib/hash.rb +39 -1
  82. data/opal/corelib/kernel.rb +56 -5
  83. data/opal/corelib/module.rb +60 -4
  84. data/opal/corelib/proc.rb +8 -5
  85. data/opal/corelib/rational.rb +1 -0
  86. data/opal/corelib/regexp.rb +15 -1
  87. data/opal/corelib/runtime.js +307 -238
  88. data/opal/corelib/string/encoding.rb +0 -6
  89. data/opal/corelib/string.rb +28 -7
  90. data/opal/corelib/time.rb +5 -2
  91. data/opal/corelib/unsupported.rb +2 -14
  92. data/spec/filters/bugs/delegate.rb +11 -0
  93. data/spec/filters/bugs/kernel.rb +1 -3
  94. data/spec/filters/bugs/language.rb +3 -23
  95. data/spec/filters/bugs/method.rb +0 -1
  96. data/spec/filters/bugs/module.rb +0 -3
  97. data/spec/filters/bugs/proc.rb +0 -3
  98. data/spec/filters/bugs/set.rb +4 -16
  99. data/spec/filters/bugs/unboundmethod.rb +0 -2
  100. data/spec/filters/unsupported/array.rb +0 -58
  101. data/spec/filters/unsupported/freeze.rb +8 -192
  102. data/spec/filters/unsupported/hash.rb +0 -25
  103. data/spec/filters/unsupported/kernel.rb +0 -1
  104. data/spec/filters/unsupported/privacy.rb +17 -0
  105. data/spec/lib/builder_spec.rb +14 -0
  106. data/spec/lib/cli_runners/server_spec.rb +2 -3
  107. data/spec/lib/cli_spec.rb +1 -1
  108. data/spec/lib/compiler_spec.rb +1 -1
  109. data/spec/opal/core/language/if_spec.rb +13 -0
  110. data/spec/opal/core/module_spec.rb +8 -0
  111. data/spec/ruby_specs +2 -1
  112. data/stdlib/await.rb +44 -7
  113. data/stdlib/delegate.rb +427 -6
  114. data/stdlib/headless_chrome.rb +6 -2
  115. data/stdlib/nodejs/file.rb +2 -1
  116. data/stdlib/opal-parser.rb +1 -1
  117. data/stdlib/opal-platform.rb +1 -1
  118. data/stdlib/opal-replutils.rb +5 -3
  119. data/stdlib/promise.rb +3 -0
  120. data/stdlib/rbconfig.rb +4 -1
  121. data/stdlib/ruby2_keywords.rb +60 -0
  122. data/stdlib/set.rb +21 -0
  123. data/tasks/performance.rake +41 -35
  124. data/tasks/releasing.rake +1 -0
  125. data/tasks/testing/mspec_special_calls.rb +1 -0
  126. data/tasks/testing.rake +5 -5
  127. data/test/nodejs/test_await.rb +39 -1
  128. metadata +27 -14
  129. data/docs/faq.md +0 -17
  130. data/lib/opal/rewriters/break_finder.rb +0 -36
  131. data/spec/opal/core/kernel/freeze_spec.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e07c91ee89f49091b5245745dc0889d8266c6c437349f6c0a5f31c99ab34e61
4
- data.tar.gz: bef7cf7822bd78100f39044d4243a588d8a752541bb9af584c324b7d9b31ed79
3
+ metadata.gz: 799fb70bbdbc0be33af9c9757287797702fd8752f29e3beb4b3515f3dc0e7a66
4
+ data.tar.gz: 757ec0cb6cc3a5bb24e7a6e6e2aec81fa70d5f05f98025ee00528d00b0779d48
5
5
  SHA512:
6
- metadata.gz: '05894c0ce50acfcda6bf2f333410639603c994ffdd56db7c892ae579601e7f739a13fb37b430e28048ae9ea84148956a5f3b37fc629506ccd11f913a1300cf7b'
7
- data.tar.gz: deb8dfb2fecfb910d506a2707ad34a5306429debb693d4b54b61163195311807600b0b859db18e744669bdcfb4a07a610b31871050dbbb7df9f6dbf5ef712291
6
+ metadata.gz: f3024674d274a45c92bbb5094416074ef754802a78c0484a71d68a7b03815867a8ac42f8499e23a9f2d05587212afeafb752c0894cfabc4a6ace63faf0da4098
7
+ data.tar.gz: f1d8ec6f6ac95d89233d4af4a26ab4eaed8d275edd86b154dd06d6fea5477c9aa869dc644f571a2c95737bf674703f03db9b8bed7b43a8af322d5dad6e3a0516
@@ -8,6 +8,9 @@ on:
8
8
  - "*/ci-check"
9
9
  pull_request: {}
10
10
 
11
+ permissions:
12
+ contents: read
13
+
11
14
  jobs:
12
15
  rake:
13
16
  name: ${{ matrix.combo.name || matrix.combo.ruby }}
@@ -58,7 +61,7 @@ jobs:
58
61
  permissive: true
59
62
  fetchdepth: '0'
60
63
  command: bin/rake performance:compare
61
- os: ryzen
64
+ # os: ryzen
62
65
 
63
66
  # Currently failing:
64
67
  # - ruby: truffleruby
data/HACKING.md CHANGED
@@ -185,6 +185,29 @@ Array#permutation_returns_an_Enumerator_which_works_as_expected_even_when_the_ar
185
185
  Array#permutation_generates_from_a_defensive_copy,_ignoring_mutations 0.038
186
186
  ```
187
187
 
188
+ ### AsciiDoctor Benchmark and git branch performance comparison
189
+
190
+ It is testing the performance for the real life application AsciiDoctor, compiling it, running it and asset size.
191
+ It prints a nice summary to compare the current branch with the master branch.
192
+ On Windows make sure to have the Ruby DevKit enabled with `ridk enable`.
193
+
194
+ Run the task on any system with: `bundle exec rake performance:compare`
195
+
196
+ Example output:
197
+ ```
198
+ === Summary ===
199
+ Summary of performance changes between (previous) master and (current) v1.5.1-48-gc470e969:
200
+
201
+ Comparison of V8 function optimization status:
202
+ Dateien tmp/performance/optstatus_previous und tmp/performance/optstatus_current sind identisch.
203
+
204
+ Comparison of the Asciidoctor (a real-life Opal application) compile and run:
205
+ Compile time: 9.367 (±2.21%) -> 9.579 (±17.53%) (change: +2.26%)
206
+ Run time: 2.049 (±9.25%) -> 2.147 (±19.70%) (change: +4.80%)
207
+ Bundle size: 4740.27 kB -> 4740.27 kB (change: +0.00%)
208
+ Minified bundle size: 995.10 kB -> 995.10 kB (change: +0.00%)
209
+ Mangled & minified: 706.32 kB -> 706.32 kB (change: +0.00%)
210
+ ```
188
211
 
189
212
  ## Parser
190
213
 
data/UNRELEASED.md CHANGED
@@ -7,3 +7,45 @@
7
7
  ### Performance
8
8
  ### Fixed
9
9
  -->
10
+
11
+ ### Changed
12
+
13
+ - No longer truncate stacktraces to 15 lines (#2440)
14
+
15
+ ### Performance
16
+
17
+ - Improve method block performance for runtime (#2449)
18
+ - Uninline non-typical argument handling (#2419)
19
+ - Logic optimization of runtime.js (#2415)
20
+ - Windows support for `performance:compare` CI check (#2450)
21
+ - Improve block performance for even more cases (#2465)
22
+
23
+ ### Added
24
+
25
+ - Added support for `#freeze` and `#frozen?` (#2444, #2468)
26
+ - Add CLI support for ESM, at least for Chrome, NodeJS, QuickJS and GJS (#2435)
27
+ - Support exit in Chrome CLI Runner, both sync and async (#2439)
28
+ - Make sure the Server CLI Runner can pick up changes in sources (#2436)
29
+ - Delegate and ruby2_keywords (#2446)
30
+ - Source code can now be embedded in the compiled file to improve development/debugging, e.g. RSpec reports, `Proc#source_location` (#2440)
31
+ - Added `Kernel#caller_locations` (#2440)
32
+ - `Opal::Builder::Prefork` for blazingly fast multicore compilation times (#2263, #2462, #2454)
33
+
34
+ ### Fixed
35
+
36
+ - Closure tracking support fixes a whole array of bugs handling `break` / `next` / `retry` / … (#2357)
37
+ - Fix an edge case of if in the most complex form not returning (#2433)
38
+ - `String#length` is now available when using `opal/mini` (#2438)
39
+ - Auto-await produced invalid code (#2440)
40
+ - Fix `Enumerable#collect_concat` and `#flat_map` implementation (#2440)
41
+ - Improved await support for PromiseV1 (#2440)
42
+ - Compilation error occurs while compiling `being/end` returning a `case/when` (#2459)
43
+ - Ensure UTF-8 encoding of `.sourcesContent` of source maps (#2451)
44
+ - Benchmarks require string/unpack (#2453)
45
+
46
+ ### Internal
47
+
48
+ - GitHub Workflows security hardening (#2432)
49
+ - Retry if file cache write operation exits with Zlib::BufError (#2463)
50
+ - Eliminate redundant `var constructor` in `allocate_class` (#2452)
51
+ - Fix `performance:compare` asset size calculation (#2457)
data/benchmark/run.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  if RUBY_ENGINE == 'opal'
2
2
  require 'opal/compiler'
3
3
  require 'nodejs'
4
+ require 'corelib/string/unpack'
4
5
  end
5
6
 
6
7
  BEST_OF_N = Integer(ENV['BEST_OF_N']) rescue 1
@@ -617,6 +617,14 @@ myHash.$to_n(); // provided by the Native module
617
617
 
618
618
  NOTE: Be aware `Hash#to_n` produces a duplicate copy of the hash.
619
619
 
620
+
621
+ ### Freezing Objects
622
+
623
+ Starting with Opal 1.6.0 freezing objects is supported in general but a few differences to Ruby apply.
624
+ Contrary to Ruby, where #freeze is often used to optimize performance, there is no performance benefit when freezing objects in Opal, instead its main use case is to prevent modification of objects.
625
+ There are a few edge cases, where accessing frozen objects in Opal behaves different from Ruby. In those cases a modification attempt will fail silently, with no "FrozenError" exception thrown.
626
+
627
+
620
628
  ## Advanced Compilation
621
629
 
622
630
  ### Method Missing
data/docs/compiler.md CHANGED
@@ -9,7 +9,7 @@ other runtime helpers.
9
9
 
10
10
  The compiler can be broken down into 3 separate stages:
11
11
 
12
- * lexing/parsing
12
+ * lexing + parsing
13
13
  * code generation
14
14
 
15
15
  ### Lexer/Parser
@@ -1,4 +1,4 @@
1
- # Compiler Directives
1
+ # Compiler File Loading Directives
2
2
 
3
3
  The Opal compiler supports some special directives that can optimize or
4
4
  enhance the output of compiled Ruby code to suit the Ruby environment.
@@ -45,3 +45,20 @@ Opal.append_path '../my_lib'
45
45
  Now, any ruby files in this directory can be discovered.
46
46
 
47
47
 
48
+ ## FAQ
49
+
50
+ ### Why does Opal exist?
51
+
52
+ To try and keep ruby relevant in a world where client-side applications are making javascript the primary development platform.
53
+
54
+ ### How compatible is Opal?
55
+
56
+ We run opal against the [ruby spec](https://github.com/ruby/spec) as our primary testing setup. We try to make Opal as compatible as possible, whilst also taking into account restrictions of JavaScript when applicable. Opal supports the majority of ruby syntax features, as well as a very large part of the corelib implementation. We support method\_missing, modules, classes, instance\_exec, blocks, procs and lots lots more. Opal can compile and run RSpec unmodified, as well as self hosting the compiler at runtime.
57
+
58
+ ### What version of ruby does Opal target?
59
+
60
+ We are running tests under ruby 3.0.0 conditions, but are mostly compatible with 2.6 level features.
61
+
62
+ ### Why doesn't Opal support mutable strings?
63
+
64
+ All strings in Opal are immutable because ruby strings just get compiled directly into javascript strings, which are immutable. Wrapping ruby strings as a custom JavaScript object would add a lot of overhead as well as making interaction between ruby and javascript libraries more difficult.
@@ -1,4 +1,4 @@
1
- # Headless Chrome
1
+ # Running code in a Headless Chrome
2
2
 
3
3
  ## Requirements
4
4
 
data/docs/index.md ADDED
@@ -0,0 +1,123 @@
1
+ # Opal Guides for v1.6.dev
2
+
3
+ These guides are designed to make you immediately productive with Opal, and to help you understand how all of the pieces fit together.
4
+
5
+ The guides for earlier releases are [available here](/docs).
6
+
7
+ ---
8
+
9
+ ## Start here
10
+
11
+ #### [Getting Started with Opal](etting_started.html)
12
+
13
+ Everything you need to know to install Opal and create your first application.
14
+
15
+ ---
16
+
17
+ ## Using JavaScript Features from Ruby
18
+
19
+ #### [Async](async.html)
20
+
21
+ Learn more about JavaScript `async`/`await` support in Opal and how you can use it to avoid explicit callbacks and promises.
22
+
23
+ #### [Promises](promises.html)
24
+
25
+ How to interact and leverage the power of JavaScript promises from Ruby.
26
+
27
+ #### [Source Maps](source_maps.html)
28
+
29
+ How to enable and consume source-maps for your Opal application and be able to debug your Ruby scripts right inside the browser.
30
+
31
+ ---
32
+
33
+ ## Using Ruby Features
34
+
35
+ #### [Working with ERB and Haml Templates](templates.html)
36
+
37
+ How to work with template libraries in Opal, be it to share the templates with the server or to write your own.
38
+
39
+ ---
40
+
41
+ ## Working with Frameworks
42
+
43
+ #### [Rails](rails.html)
44
+
45
+ How to use `opal-rails` to use Opal as the JavaScript compiler.
46
+
47
+ #### [Static Applications](static_applications.html)
48
+
49
+ The most basic setup for a static Opal powered website that can be hosted anywhere.
50
+
51
+ #### [Sinatra](sinatra.html)
52
+
53
+ Serve Opal applications through Sinatra and `opal-sprockets`.
54
+
55
+ #### [Roda + Sprockets](roda-sprockets.html)
56
+
57
+ Setup Roda + Sprockets to start serving Opal applications from Roda.
58
+
59
+ ---
60
+
61
+ ## Interacting with Other Libraries
62
+
63
+ #### [jQuery](jquery.html)
64
+
65
+ This guide covers the `opal-jquery` wrapper around the popular library.
66
+
67
+ #### [RSpec](rspec.html)
68
+
69
+ Write specs for your Opal code RSpec and run them on Node.js or in a browser.
70
+
71
+ #### [Using Sprockets](using_sprockets.html)
72
+
73
+ Configure the long-lasting asset handler to work with Opal.
74
+
75
+ ---
76
+
77
+ ## Digging Deeper
78
+
79
+ #### [Configuring Gems](configuring_gems.html)
80
+
81
+ How to make your gem work in Opal and differentiate code for the JavaScript environment.
82
+
83
+ #### [Compiler](compiler.html)
84
+
85
+ A very general overview of how the Opal compiler works.
86
+
87
+ #### [Compiled Ruby](compiled_ruby.html)
88
+
89
+ This guide documents how each part of Ruby is mapped to JavaScript internally.
90
+
91
+ #### [Compiler File Loading Directives](compiler_directives.html)
92
+
93
+ The Opal compiler supports some special directives that can optimize or
94
+ enhance the output of compiled Ruby code to suit the Ruby environment.
95
+
96
+ #### [Using the Opal parser inside a JavaScript environment](opal_parser.html)
97
+
98
+ This guide documents how to parse and run Ruby scripts within a browser or any supported JavaScript environment
99
+
100
+ #### [Encoding](encoding.html)
101
+
102
+ (WIP) How to handle encoding within Opal in the browser and in the code.
103
+
104
+ #### [Running code in a Headless Chrome](headless_chrome.html)
105
+
106
+ How to run your Opal application in a headless Chrome from the CLI instead of Node.js.
107
+
108
+ #### [Unsupported Features](unsupported_features.html)
109
+
110
+ Some things that are very difficult, impossible, or outright incompatible with a JavaScript environment.
111
+
112
+ ---
113
+
114
+ ## Releases
115
+
116
+ #### [Upgrading Opal](upgrading.html)
117
+
118
+ This guide provides steps to be followed when you upgrade your applications to a newer version of Opal.
119
+
120
+ #### [Releasing Instructions](releasing.html)
121
+
122
+ (WIP) A step-by-step guide on who to release a new version of Opal.
123
+
data/docs/templates.md CHANGED
@@ -42,6 +42,43 @@ Template['login']
42
42
  # => #<Template: 'login'>
43
43
  ```
44
44
 
45
+ ## ERB Templates
46
+
47
+ Support for `erb` templates is built in directly to the opal gem and stdlib.
48
+ There is one caveat though when working with sprockets - it must have the
49
+ `.opalerb` file extension, instead of `.erb`. This is because sprockets has a
50
+ built in handler for `.erb` files.
51
+
52
+ If we have the same user class as above, create an `app/views/user.opalerb`
53
+ file:
54
+
55
+ ```erb
56
+ <!-- app/views/user.opalerb -->
57
+ <div class="row">
58
+ <div class="col-md-3"><%= self.name %></div>
59
+ </div>
60
+ ```
61
+
62
+ Again, you must then require the template (without the `.opalerb` extension):
63
+
64
+ ```ruby
65
+ # app/application.rb
66
+ require 'opal'
67
+ require 'views/user'
68
+ ```
69
+
70
+ And then you can access and render the template:
71
+
72
+ ```ruby
73
+ # app/application.rb
74
+
75
+ template = Template['views/user']
76
+ user = User.new('Ford Prefect')
77
+
78
+ puts template.render(user)
79
+ # => "<div class="row">...</div>"
80
+ ```
81
+
45
82
  ## Haml templates
46
83
 
47
84
  `opal-haml` allows `.haml` templates to be compiled, just like opal compiles
@@ -111,40 +148,3 @@ check it out, you should see it compiled into something like the following:
111
148
  </div>
112
149
  </div>
113
150
  ```
114
-
115
- ## ERB Templates
116
-
117
- Support for `erb` templates is built in directly to the opal gem and stdlib.
118
- There is one caveat though when working with sprockets - it must have the
119
- `.opalerb` file extension, instead of `.erb`. This is because sprockets has a
120
- built in handler for `.erb` files.
121
-
122
- If we have the same user class as above, create an `app/views/user.opalerb`
123
- file:
124
-
125
- ```erb
126
- <!-- app/views/user.opalerb -->
127
- <div class="row">
128
- <div class="col-md-3"><%= self.name %></div>
129
- </div>
130
- ```
131
-
132
- Again, you must then require the template (without the `.opalerb` extension):
133
-
134
- ```ruby
135
- # app/application.rb
136
- require 'opal'
137
- require 'views/user'
138
- ```
139
-
140
- And then you can access and render the template:
141
-
142
- ```ruby
143
- # app/application.rb
144
-
145
- template = Template['views/user']
146
- user = User.new('Ford Prefect')
147
-
148
- puts template.render(user)
149
- # => "<div class="row">...</div>"
150
- ```
@@ -24,10 +24,6 @@ Encodings only have a very small implementation inside Opal.
24
24
 
25
25
  JavaScript does not have a native `Thread` implementation, so they are not present inside Opal. There is a placeholder `Thread` class just to provide some small level of compatibility with libraries that expect it. It does not have any function.
26
26
 
27
- #### Frozen Objects ####
28
-
29
- Opal does not currently support frozen objects, but has placeholder methods to prevent other libraries breaking when expecting these methods. Opal could support frozen objects in the future once a similar implementation becomes available across JavaScript runtimes.
30
-
31
27
  #### Private, Public and Protected methods ####
32
28
 
33
29
  All methods in Opal are defined as `public` to avoid additional runtime overhead. `Module#private` and `Module#protected` exist as just placeholder methods and are no-op methods.
data/lib/opal/builder.rb CHANGED
@@ -4,6 +4,7 @@ require 'opal/path_reader'
4
4
  require 'opal/paths'
5
5
  require 'opal/config'
6
6
  require 'opal/cache'
7
+ require 'opal/builder_scheduler'
7
8
  require 'set'
8
9
 
9
10
  module Opal
@@ -55,8 +56,6 @@ module Opal
55
56
  processor_extensions.each { |ext| extensions << ext }
56
57
  end
57
58
 
58
-
59
-
60
59
  class MissingRequire < LoadError
61
60
  end
62
61
 
@@ -76,6 +75,11 @@ module Opal
76
75
  @compiler_options ||= Opal::Config.compiler_options
77
76
  @missing_require_severity ||= Opal::Config.missing_require_severity
78
77
  @cache ||= Opal.cache
78
+ @scheduler ||= Opal.builder_scheduler
79
+
80
+ if @scheduler.respond_to? :new
81
+ @scheduler = @scheduler.new(self)
82
+ end
79
83
 
80
84
  @processed = []
81
85
  end
@@ -99,11 +103,10 @@ module Opal
99
103
  rel_path = expand_ext(rel_path)
100
104
  asset = processor_for(source, rel_path, abs_path, false, options)
101
105
  requires = preload + asset.requires + tree_requires(asset, abs_path)
102
- requires.map { |r| process_require(r, asset.autoloads, options) }
106
+ # Don't automatically load modules required by the module
107
+ process_requires(rel_path, requires, asset.autoloads, options.merge(load: false))
103
108
  processed << asset
104
109
  self
105
- rescue MissingRequire => error
106
- raise error, "A file required by #{rel_path.inspect} wasn't found.\n#{error.message}", error.backtrace
107
110
  end
108
111
 
109
112
  def build_require(path, options = {})
@@ -134,6 +137,39 @@ module Opal
134
137
  path_reader.append_paths(*paths)
135
138
  end
136
139
 
140
+ def process_require_threadsafely(rel_path, autoloads, options)
141
+ return if prerequired.include?(rel_path)
142
+
143
+ autoload = autoloads.include? rel_path
144
+
145
+ source = stub?(rel_path) ? '' : read(rel_path, autoload)
146
+
147
+ # The handling is delegated to the runtime
148
+ return if source.nil?
149
+
150
+ abs_path = expand_path(rel_path)
151
+ rel_path = expand_ext(rel_path)
152
+ asset = processor_for(source, rel_path, abs_path, autoload, options.merge(requirable: true))
153
+ process_requires(
154
+ rel_path,
155
+ asset.requires + tree_requires(asset, abs_path),
156
+ asset.autoloads,
157
+ options
158
+ )
159
+ asset
160
+ end
161
+
162
+ def process_require(rel_path, autoloads, options)
163
+ return if already_processed.include?(rel_path)
164
+ already_processed << rel_path
165
+ asset = process_require_threadsafely(rel_path, autoloads, options)
166
+ processed << asset if asset
167
+ end
168
+
169
+ def already_processed
170
+ @already_processed ||= Set.new
171
+ end
172
+
137
173
  include UseGem
138
174
 
139
175
  attr_reader :processed
@@ -141,8 +177,26 @@ module Opal
141
177
  attr_accessor :processors, :path_reader, :stubs, :prerequired, :preload,
142
178
  :compiler_options, :missing_require_severity, :cache
143
179
 
180
+ def esm?
181
+ @compiler_options[:esm]
182
+ end
183
+
184
+ # Output extension, to be used by runners. At least Node.JS switches
185
+ # to ESM mode only if the extension is "mjs"
186
+ def output_extension
187
+ if esm?
188
+ 'mjs'
189
+ else
190
+ 'js'
191
+ end
192
+ end
193
+
144
194
  private
145
195
 
196
+ def process_requires(rel_path, requires, autoloads, options)
197
+ @scheduler.process_requires(rel_path, requires, autoloads, options)
198
+ end
199
+
146
200
  def tree_requires(asset, asset_path)
147
201
  dirname = asset_path.to_s.empty? ? Pathname.pwd : Pathname(asset_path).expand_path.dirname
148
202
  abs_base_paths = path_reader.paths.map { |p| File.expand_path(p) }
@@ -201,30 +255,6 @@ module Opal
201
255
  end
202
256
  end
203
257
 
204
- def process_require(rel_path, autoloads, options)
205
- return if prerequired.include?(rel_path)
206
- return if already_processed.include?(rel_path)
207
- already_processed << rel_path
208
-
209
- autoload = autoloads.include? rel_path
210
-
211
- source = stub?(rel_path) ? '' : read(rel_path, autoload)
212
-
213
- # The handling is delegated to the runtime
214
- return if source.nil?
215
-
216
- abs_path = expand_path(rel_path)
217
- rel_path = expand_ext(rel_path)
218
- asset = processor_for(source, rel_path, abs_path, autoload, options.merge(requirable: true))
219
- process_requires(
220
- rel_path,
221
- asset.requires + tree_requires(asset, abs_path),
222
- asset.autoloads,
223
- options
224
- )
225
- processed << asset
226
- end
227
-
228
258
  def expand_ext(path)
229
259
  abs_path = path_reader.expand(path)
230
260
 
@@ -243,16 +273,6 @@ module Opal
243
273
  (path_reader.expand(path) || File.expand_path(path)).to_s
244
274
  end
245
275
 
246
- def process_requires(rel_path, requires, autoloads, options)
247
- requires.map { |r| process_require(r, autoloads, options) }
248
- rescue MissingRequire => error
249
- raise error, "A file required by #{rel_path.inspect} wasn't found.\n#{error.message}", error.backtrace
250
- end
251
-
252
- def already_processed
253
- @already_processed ||= Set.new
254
- end
255
-
256
276
  def stub?(path)
257
277
  stubs.include?(path)
258
278
  end