opal 1.3.1 → 1.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.eslintrc.js +1 -0
- data/.github/workflows/build.yml +20 -21
- data/.rubocop.yml +5 -1
- data/CHANGELOG.md +119 -11
- data/UNRELEASED.md +4 -9
- data/benchmark-ips/bm_truthy.rb +30 -0
- data/bin/opal-mspec +1 -3
- data/bin/opal-repl +1 -2
- data/bin/remove-filters +1 -4
- data/docs/compiled_ruby.md +37 -22
- data/docs/faq.md +1 -1
- data/docs/headless_chrome.md +11 -21
- data/docs/jquery.md +1 -6
- data/docs/opal_parser.md +3 -1
- data/docs/promises.md +2 -0
- data/docs/releasing.md +3 -0
- data/docs/roda-sprockets.md +0 -1
- data/docs/source_maps.md +10 -11
- data/docs/static_applications.md +2 -2
- data/docs/unsupported_features.md +4 -0
- data/exe/opal-repl +1 -3
- data/lib/opal/ast/builder.rb +1 -1
- data/lib/opal/cli.rb +2 -2
- data/lib/opal/cli_runners/nodejs.rb +9 -2
- data/lib/opal/cli_runners/source-map-support-browser.js +80 -216
- data/lib/opal/cli_runners/source-map-support-node.js +80 -216
- data/lib/opal/cli_runners/source-map-support.js +5 -1
- data/lib/opal/cli_runners/system_runner.rb +10 -4
- data/lib/opal/compiler.rb +3 -5
- data/lib/opal/fragment.rb +5 -1
- data/lib/opal/nodes/args/extract_block_arg.rb +1 -8
- data/lib/opal/nodes/args/extract_kwoptarg.rb +1 -3
- data/lib/opal/nodes/args/extract_optarg.rb +1 -3
- data/lib/opal/nodes/args/extract_post_arg.rb +2 -5
- data/lib/opal/nodes/args/extract_post_optarg.rb +2 -7
- data/lib/opal/nodes/args/initialize_iterarg.rb +1 -3
- data/lib/opal/nodes/args/prepare_post_args.rb +5 -1
- data/lib/opal/nodes/base.rb +3 -2
- data/lib/opal/nodes/call.rb +20 -9
- data/lib/opal/nodes/call_special.rb +50 -0
- data/lib/opal/nodes/class.rb +24 -15
- data/lib/opal/nodes/constants.rb +23 -5
- data/lib/opal/nodes/def.rb +20 -23
- data/lib/opal/nodes/defined.rb +5 -5
- data/lib/opal/nodes/definitions.rb +2 -2
- data/lib/opal/nodes/defs.rb +2 -5
- data/lib/opal/nodes/helpers.rb +48 -18
- data/lib/opal/nodes/if.rb +113 -8
- data/lib/opal/nodes/iter.rb +23 -16
- data/lib/opal/nodes/literal.rb +18 -4
- data/lib/opal/nodes/logic.rb +2 -1
- data/lib/opal/nodes/masgn.rb +4 -9
- data/lib/opal/nodes/module.rb +29 -19
- data/lib/opal/nodes/node_with_args.rb +1 -7
- data/lib/opal/nodes/scope.rb +54 -15
- data/lib/opal/nodes/singleton_class.rb +5 -3
- data/lib/opal/nodes/super.rb +12 -12
- data/lib/opal/nodes/top.rb +34 -31
- data/lib/opal/nodes/variables.rb +2 -2
- data/lib/opal/nodes/x_string.rb +30 -28
- data/lib/opal/nodes.rb +0 -1
- data/lib/opal/parser/patch.rb +75 -0
- data/lib/opal/parser/with_ruby_lexer.rb +1 -1
- data/lib/opal/regexp_anchors.rb +7 -7
- data/lib/opal/requires.rb +19 -0
- data/lib/opal/rewriters/pattern_matching.rb +1 -1
- data/lib/opal/rewriters/returnable_logic.rb +102 -4
- data/lib/opal/util.rb +2 -2
- data/lib/opal/version.rb +1 -1
- data/lib/opal.rb +1 -17
- data/opal/corelib/array/pack.rb +11 -11
- data/opal/corelib/array.rb +193 -152
- data/opal/corelib/basic_object.rb +19 -15
- data/opal/corelib/binding.rb +7 -7
- data/opal/corelib/boolean.rb +12 -15
- data/opal/corelib/class.rb +23 -1
- data/opal/corelib/comparable.rb +8 -8
- data/opal/corelib/complex/base.rb +2 -2
- data/opal/corelib/complex.rb +79 -88
- data/opal/corelib/constants.rb +9 -9
- data/opal/corelib/dir.rb +4 -3
- data/opal/corelib/enumerable.rb +140 -127
- data/opal/corelib/enumerator/arithmetic_sequence.rb +177 -0
- data/opal/corelib/enumerator/chain.rb +42 -0
- data/opal/corelib/enumerator/generator.rb +35 -0
- data/opal/corelib/enumerator/lazy.rb +243 -0
- data/opal/corelib/enumerator/yielder.rb +36 -0
- data/opal/corelib/enumerator.rb +45 -300
- data/opal/corelib/error/errno.rb +47 -0
- data/opal/corelib/error.rb +62 -60
- data/opal/corelib/file.rb +26 -12
- data/opal/corelib/hash.rb +98 -107
- data/opal/corelib/helpers.rb +62 -13
- data/opal/corelib/io.rb +48 -35
- data/opal/corelib/kernel/format.rb +29 -29
- data/opal/corelib/kernel.rb +86 -83
- data/opal/corelib/main.rb +14 -12
- data/opal/corelib/marshal/read_buffer.rb +15 -15
- data/opal/corelib/marshal/write_buffer.rb +45 -44
- data/opal/corelib/marshal.rb +3 -3
- data/opal/corelib/math.rb +50 -50
- data/opal/corelib/method.rb +12 -8
- data/opal/corelib/module.rb +79 -75
- data/opal/corelib/nil.rb +9 -11
- data/opal/corelib/number.rb +113 -118
- data/opal/corelib/numeric.rb +37 -33
- data/opal/corelib/object_space.rb +11 -10
- data/opal/corelib/pack_unpack/format_string_parser.rb +3 -3
- data/opal/corelib/pattern_matching/base.rb +7 -7
- data/opal/corelib/pattern_matching.rb +1 -1
- data/opal/corelib/proc.rb +15 -16
- data/opal/corelib/process/base.rb +2 -2
- data/opal/corelib/process/status.rb +21 -0
- data/opal/corelib/process.rb +5 -5
- data/opal/corelib/random/formatter.rb +11 -11
- data/opal/corelib/random/math_random.js.rb +1 -1
- data/opal/corelib/random/mersenne_twister.rb +3 -3
- data/opal/corelib/random/seedrandom.js.rb +3 -3
- data/opal/corelib/random.rb +17 -17
- data/opal/corelib/range.rb +51 -35
- data/opal/corelib/rational/base.rb +4 -4
- data/opal/corelib/rational.rb +61 -62
- data/opal/corelib/regexp.rb +54 -45
- data/opal/corelib/runtime.js +247 -141
- data/opal/corelib/string/encoding.rb +21 -21
- data/opal/corelib/string/unpack.rb +19 -14
- data/opal/corelib/string.rb +137 -130
- data/opal/corelib/struct.rb +59 -46
- data/opal/corelib/time.rb +47 -57
- data/opal/corelib/trace_point.rb +2 -2
- data/opal/corelib/unsupported.rb +31 -120
- data/opal/corelib/variables.rb +3 -3
- data/opal/opal/base.rb +9 -8
- data/opal/opal/full.rb +8 -8
- data/opal/opal/mini.rb +17 -17
- data/opal/opal.rb +17 -18
- data/opal.gemspec +1 -1
- data/spec/filters/bugs/array.rb +4 -24
- data/spec/filters/bugs/basicobject.rb +0 -1
- data/spec/filters/bugs/bigdecimal.rb +0 -23
- data/spec/filters/bugs/binding.rb +0 -1
- data/spec/filters/bugs/boolean.rb +3 -0
- data/spec/filters/bugs/class.rb +2 -0
- data/spec/filters/bugs/date.rb +0 -5
- data/spec/filters/bugs/encoding.rb +8 -50
- data/spec/filters/bugs/enumerable.rb +4 -1
- data/spec/filters/bugs/enumerator.rb +3 -36
- data/spec/filters/bugs/exception.rb +0 -2
- data/spec/filters/bugs/file.rb +0 -2
- data/spec/filters/bugs/float.rb +0 -3
- data/spec/filters/bugs/hash.rb +5 -3
- data/spec/filters/bugs/integer.rb +2 -3
- data/spec/filters/bugs/kernel.rb +2 -31
- data/spec/filters/bugs/language.rb +29 -49
- data/spec/filters/bugs/main.rb +0 -2
- data/spec/filters/bugs/marshal.rb +2 -3
- data/spec/filters/bugs/matrix.rb +0 -36
- data/spec/filters/bugs/module.rb +7 -61
- data/spec/filters/bugs/numeric.rb +0 -7
- data/spec/filters/bugs/objectspace.rb +1 -1
- data/spec/filters/bugs/pack_unpack.rb +0 -4
- data/spec/filters/bugs/proc.rb +0 -9
- data/spec/filters/bugs/random.rb +0 -5
- data/spec/filters/bugs/range.rb +1 -6
- data/spec/filters/bugs/regexp.rb +0 -3
- data/spec/filters/bugs/set.rb +8 -1
- data/spec/filters/bugs/string.rb +9 -34
- data/spec/filters/bugs/stringscanner.rb +8 -7
- data/spec/filters/bugs/struct.rb +2 -3
- data/spec/filters/bugs/symbol.rb +0 -1
- data/spec/filters/bugs/time.rb +0 -8
- data/spec/filters/bugs/unboundmethod.rb +0 -8
- data/spec/filters/bugs/warnings.rb +1 -7
- data/spec/filters/unsupported/freeze.rb +24 -0
- data/spec/filters/unsupported/integer.rb +1 -0
- data/spec/filters/unsupported/kernel.rb +12 -0
- data/spec/filters/unsupported/privacy.rb +3 -0
- data/spec/filters/unsupported/string.rb +2 -0
- data/spec/lib/builder_spec.rb +2 -2
- data/spec/lib/cli_spec.rb +1 -1
- data/spec/lib/compiler_spec.rb +37 -37
- data/spec/lib/simple_server_spec.rb +2 -2
- data/spec/lib/source_map/file_spec.rb +1 -1
- data/spec/opal/compiler/irb_spec.rb +2 -2
- data/spec/opal/core/io/read_spec.rb +69 -0
- data/spec/opal/core/kernel/puts_spec.rb +90 -0
- data/spec/opal/core/language/super_spec.rb +21 -0
- data/spec/opal/core/language/xstring_spec.rb +13 -0
- data/spec/opal/core/language_spec.rb +14 -0
- data/spec/opal/core/string/gsub_spec.rb +8 -0
- data/spec/ruby_specs +4 -2
- data/spec/support/rewriters_helper.rb +1 -1
- data/stdlib/bigdecimal.rb +7 -11
- data/stdlib/buffer/view.rb +2 -2
- data/stdlib/buffer.rb +2 -2
- data/stdlib/date.rb +5 -6
- data/stdlib/erb.rb +1 -0
- data/stdlib/js.rb +2 -1
- data/stdlib/native.rb +7 -8
- data/stdlib/nodejs/argf.rb +4 -4
- data/stdlib/nodejs/base.rb +29 -0
- data/stdlib/nodejs/dir.rb +1 -1
- data/stdlib/nodejs/env.rb +6 -9
- data/stdlib/nodejs/file.rb +23 -17
- data/stdlib/nodejs/fileutils.rb +3 -3
- data/stdlib/nodejs/io.rb +2 -20
- data/stdlib/nodejs/irb.rb +0 -0
- data/stdlib/nodejs/kernel.rb +2 -37
- data/stdlib/nodejs.rb +1 -3
- data/stdlib/opal/miniracer.rb +2 -0
- data/stdlib/opal/platform.rb +6 -13
- data/stdlib/opal/replutils.rb +16 -5
- data/stdlib/opal-parser.rb +2 -2
- data/stdlib/optparse/ac.rb +54 -0
- data/stdlib/optparse/date.rb +14 -0
- data/stdlib/optparse/kwargs.rb +22 -0
- data/stdlib/optparse/shellwords.rb +7 -0
- data/stdlib/optparse/time.rb +15 -0
- data/stdlib/optparse/uri.rb +7 -0
- data/stdlib/optparse/version.rb +69 -0
- data/stdlib/optparse.rb +2279 -0
- data/stdlib/pathname.rb +5 -6
- data/stdlib/pp.rb +18 -2
- data/stdlib/promise/v2.rb +18 -29
- data/stdlib/promise.rb +15 -21
- data/stdlib/quickjs/io.rb +0 -2
- data/stdlib/quickjs/kernel.rb +0 -2
- data/stdlib/quickjs.rb +2 -0
- data/stdlib/set.rb +32 -32
- data/stdlib/shellwords.rb +240 -0
- data/stdlib/stringio.rb +3 -6
- data/stdlib/strscan.rb +5 -8
- data/stdlib/template.rb +2 -2
- data/stdlib/thread.rb +7 -9
- data/tasks/linting-parse-eslint-results.js +1 -0
- data/tasks/linting.rake +0 -10
- data/tasks/performance.rake +5 -2
- data/tasks/testing/mspec_special_calls.rb +0 -12
- data/tasks/testing.rake +55 -37
- data/test/nodejs/test_file.rb +11 -0
- metadata +55 -8
- data/lib/opal/nodes/case.rb +0 -114
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f199262b85612cb61bd3f3fa1d05ec8a7fb3fa6fabbd63a36baa03859e241c5c
|
4
|
+
data.tar.gz: e4af60acb540708612fbed3e4aa04fef968b750b0ff588774bda6d979586fc8f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4ece0468468bc541c155cb53185550f35b4277c89e18f32990a7bb8abff6c20beaeb9f962f02f80b1afc251a75c0916d35dd8d2944fa8153aa4a6454a7ddf8a
|
7
|
+
data.tar.gz: 81539b2993e44bfa8217cda753badaa292c26117de8366d04e50922309b95654f5c09f983a02f329b36ea1405affc52c3831c7122f4215a90e7a78c9084b9b31
|
data/.eslintrc.js
CHANGED
data/.github/workflows/build.yml
CHANGED
@@ -16,41 +16,44 @@ jobs:
|
|
16
16
|
matrix:
|
17
17
|
combo:
|
18
18
|
- name: mspec-nodejs
|
19
|
-
ruby: 3.0
|
19
|
+
ruby: '3.0'
|
20
20
|
command: bin/rake mspec_nodejs
|
21
21
|
- name: mspec-chrome
|
22
|
-
ruby: 3.0
|
22
|
+
ruby: '3.0'
|
23
23
|
command: bin/rake mspec_chrome
|
24
24
|
- name: minitest
|
25
|
-
ruby: 3.0
|
25
|
+
ruby: '3.0'
|
26
26
|
command: bin/rake minitest
|
27
27
|
- name: minitest-strict-mode
|
28
|
-
ruby: 3.0
|
28
|
+
ruby: '3.0'
|
29
29
|
command: bin/rake minitest
|
30
30
|
strict: 'true'
|
31
|
+
- name: head-ruby
|
32
|
+
ruby: head
|
33
|
+
permissive: true
|
31
34
|
- name: current-ruby
|
32
|
-
ruby: 3.
|
35
|
+
ruby: 3.1
|
33
36
|
- name: previous-ruby
|
34
|
-
ruby:
|
37
|
+
ruby: '3.0'
|
35
38
|
- name: older-ruby
|
39
|
+
ruby: 2.7
|
40
|
+
- name: near-eol-ruby
|
36
41
|
ruby: 2.6
|
37
|
-
# - name: near-eol-ruby
|
38
|
-
# ruby: 2.6
|
39
42
|
- name: smoke-test
|
40
|
-
ruby: 3.0
|
43
|
+
ruby: '3.0'
|
41
44
|
command: bin/rake smoke_test
|
42
45
|
- name: windows
|
43
46
|
# These two fail because of broken stacktraces on windows: minitest_node_nodejs mspec_nodejs
|
44
47
|
command: bundle exec rake rspec minitest_nodejs
|
45
|
-
ruby: 3.0
|
48
|
+
ruby: '3.0'
|
46
49
|
os: windows-latest
|
47
50
|
- name: lint
|
48
51
|
command: bin/rake lint
|
49
|
-
ruby: 3.0
|
52
|
+
ruby: '3.0'
|
50
53
|
- name: timezone
|
51
|
-
ruby: 3.0
|
54
|
+
ruby: '3.0'
|
52
55
|
- name: performance
|
53
|
-
ruby: 3.0
|
56
|
+
ruby: '3.0'
|
54
57
|
permissive: true
|
55
58
|
fetchdepth: '0'
|
56
59
|
command: bin/rake performance:compare
|
@@ -59,7 +62,6 @@ jobs:
|
|
59
62
|
# Currently failing:
|
60
63
|
# - ruby: truffleruby
|
61
64
|
# - ruby: jruby
|
62
|
-
# - ruby: ruby-head
|
63
65
|
|
64
66
|
runs-on: ${{ matrix.combo.os || 'ubuntu-latest' }}
|
65
67
|
continue-on-error: ${{ matrix.combo.permissive || false }}
|
@@ -71,20 +73,17 @@ jobs:
|
|
71
73
|
uses: ruby/setup-ruby@v1
|
72
74
|
with:
|
73
75
|
ruby-version: ${{ matrix.combo.ruby }}
|
74
|
-
# NOTE: Bundler 2.2.0 fails to install libv8
|
75
|
-
# https://github.com/rubyjs/libv8/issues/310
|
76
|
-
bundler: "2.1.4"
|
77
76
|
bundler-cache: false
|
78
77
|
- run: ruby bin/git-submodule-fast-install
|
79
78
|
- run: bundle lock
|
80
79
|
- uses: actions/cache@v2
|
81
80
|
with:
|
82
81
|
path: ./vendor/bundle
|
83
|
-
key: ${{ runner.os }}-${{ matrix.combo.ruby }}-
|
82
|
+
key: ${{ runner.os }}-${{ matrix.combo.ruby }}-gem-${{ github.ref }}-${{ hashFiles('**/Gemfile.lock') }}
|
84
83
|
restore-keys: |
|
85
|
-
${{ runner.os }}-${{ matrix.combo.ruby }}-
|
86
|
-
${{ runner.os }}-${{ matrix.combo.ruby }}-
|
87
|
-
${{ runner.os }}-${{ matrix.combo.ruby }}-
|
84
|
+
${{ runner.os }}-${{ matrix.combo.ruby }}-gem-${{ github.ref }}
|
85
|
+
${{ runner.os }}-${{ matrix.combo.ruby }}-gem-master
|
86
|
+
${{ runner.os }}-${{ matrix.combo.ruby }}-gem-
|
88
87
|
- uses: actions/cache@v2
|
89
88
|
with:
|
90
89
|
path: ./node_modules
|
data/.rubocop.yml
CHANGED
@@ -2,7 +2,7 @@ require: rubocop-performance
|
|
2
2
|
inherit_from: .rubocop/todo.yml
|
3
3
|
|
4
4
|
AllCops:
|
5
|
-
TargetRubyVersion: 2.
|
5
|
+
TargetRubyVersion: 2.6
|
6
6
|
Exclude:
|
7
7
|
- CHANGELOG.md
|
8
8
|
- CONDUCT.md
|
@@ -52,6 +52,10 @@ AllCops:
|
|
52
52
|
- 'stdlib/matrix/*.rb'
|
53
53
|
- 'stdlib/pp.rb'
|
54
54
|
- 'stdlib/prettyprint.rb'
|
55
|
+
- 'stdlib/optparse.rb'
|
56
|
+
- 'stdlib/optparse/*.rb'
|
57
|
+
- 'stdlib/tmpdir.rb'
|
58
|
+
- 'stdlib/tempfile.rb'
|
55
59
|
|
56
60
|
inherit_mode:
|
57
61
|
merge:
|
data/CHANGELOG.md
CHANGED
@@ -15,16 +15,128 @@ Changes are grouped as follows:
|
|
15
15
|
|
16
16
|
|
17
17
|
|
18
|
-
## [
|
18
|
+
## [1.4.1](https://github.com/opal/opal/compare/v1.4.0...v1.4.1) - 2022-01-12
|
19
|
+
|
20
|
+
|
21
|
+
### Changed
|
22
|
+
|
23
|
+
- PromiseV2 is now declared a stable interface!
|
24
|
+
|
25
|
+
### Fixed
|
26
|
+
|
27
|
+
- Args named with JS reserved words weren't always renamed when _zsuper_ was involved ([#2385](https://github.com/opal/opal/pull/2385))
|
28
|
+
|
29
|
+
<!--
|
30
|
+
### Added
|
31
|
+
### Removed
|
32
|
+
### Deprecated
|
33
|
+
### Internal
|
34
|
+
-->
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
## [1.4.0](https://github.com/opal/opal/compare/v1.3.2...v1.4.0) - 2021-12-24
|
40
|
+
|
41
|
+
|
42
|
+
### Added
|
43
|
+
|
44
|
+
- Implement `chomp:` option for `String#each_line` and `#lines` ([#2355](https://github.com/opal/opal/pull/2355))
|
45
|
+
- Ruby 3.1 support and some older Ruby features we missed ([#2347](https://github.com/opal/opal/pull/2347))
|
46
|
+
- Use parser in 3.1 mode to support new language-level features like hashes/kwargs value omission, the pin operator for pattern matching
|
47
|
+
- `Array#intersect?`
|
48
|
+
- `String#strip` and `String#lstrip` to also remove NUL bytes
|
49
|
+
- `Integer.try_convert`
|
50
|
+
- `public`, `private`, `protected`, `module_function` now return their arguments
|
51
|
+
- `Class#descendants`, `Class#subclasses`
|
52
|
+
- (<=1.8) `Kernel#local_variables`
|
53
|
+
- (<=2.3) Set local variables for regexp named captures (`/(?<b>a)/ =~ 'a'` => `b = 'a'`)
|
54
|
+
- Remove deprecated `NIL`, `TRUE`, `FALSE` constants
|
55
|
+
- `String#unpack` and `String#unpack1` to support an `offset:` kwarg
|
56
|
+
- `MatchData#match`, `MatchData#match_length`
|
57
|
+
- Enumerable modernization
|
58
|
+
- `Enumerable#tally` to support an optional hash accumulator
|
59
|
+
- `Enumerable#each_{cons,slice}` to return self
|
60
|
+
- `Enumerable#compact`
|
61
|
+
- `Refinement` becomes its own class now
|
62
|
+
- `Struct#keyword_init?`
|
63
|
+
- (pre-3.1) Large Enumerator rework
|
64
|
+
- Introduce `Enumerator::ArithmeticSequence`
|
65
|
+
- Introduce `Enumerator::Chain`
|
66
|
+
- Introduce `Enumerator#+` to create `Enumerator::Chain`s
|
67
|
+
- `Enumerator#{rewind,peek,peek_values,next,next_values}`
|
68
|
+
- Improve corelib support for beginless/endless ranges and `ArithmeticSequences`
|
69
|
+
- `String#[]`, `Array#[]`, `Array#[]=`, `Array#fill`, `Array#values_at`
|
70
|
+
- `Range#step` and `Numeric#step` return an `ArithmeticSequence` when `Numeric` values are in play
|
71
|
+
- Introduce `Range#%`
|
72
|
+
- `Enumerator::Yielder#to_proc`
|
73
|
+
- Fix #2367
|
74
|
+
- (2.7) `UnboundMethod#bind_call`
|
75
|
+
- (Opal) `{Kernel,BasicObject}#{inspect,p,pp,method_missing}` may work with JS native values now, also they now correctly report cycles
|
76
|
+
- `Enumerable#sum` uses Kahan's summation algorithm to reduce error with floating point values
|
77
|
+
- `File.dirname` supports a new `level` argument
|
78
|
+
- Vendor in `optparse` and `shellwords` ([#2326](https://github.com/opal/opal/pull/2326))
|
79
|
+
- Preliminary support for compiling the whole `bin/opal` with Opal ([#2326](https://github.com/opal/opal/pull/2326))
|
80
|
+
|
81
|
+
### Fixed
|
82
|
+
|
83
|
+
- Fix coertion for `Array#drop` ([#2371](https://github.com/opal/opal/pull/2371))
|
84
|
+
- Fix coertion for `File.absolute_path` ([#2372](https://github.com/opal/opal/pull/2372))
|
85
|
+
- Fix some `IO#puts` edge cases (no args, empty array, nested array, …) ([#2372](https://github.com/opal/opal/pull/2372))
|
86
|
+
- Preserve UNC path prefix on File.join ([#2366](https://github.com/opal/opal/pull/2366))
|
87
|
+
- Methods on `Kernel`, `BasicObject`, `Boolean` will never return boxed values anymore ([#2293](https://github.com/opal/opal/pull/2293))
|
88
|
+
- `false.tap{}` will now correctly return a JS value of `false`, not `Object(false)`
|
89
|
+
- opal-parser doesn't break on `<<~END` strings anymore ([#2364](https://github.com/opal/opal/pull/2364))
|
90
|
+
- Fix error reporting at the early stage of loading ([#2326](https://github.com/opal/opal/pull/2326))
|
91
|
+
|
92
|
+
### Changed
|
93
|
+
|
94
|
+
- Various outputted code size optimizations - 19% improvement for minified unmangled AsciiDoctor bundle - see: https://opalrb.com/blog/2021/11/24/optimizing-opal-output-for-size/ ([#2356](https://github.com/opal/opal/pull/2356))
|
95
|
+
- Second round of code size optimizations - 3% improvement for AsciiDoctor bundle on top of the first round - 23% total - see: https://github.com/opal/opal/pull/2365/commits ([#2365](https://github.com/opal/opal/pull/2365))
|
96
|
+
- The calls to `==`, `!=` and `===` changed their semantics slightly: it's impossible to monkey patch those calls for `String` and `Number`, but on other classes they can now return `nil` and it will be handled correctly
|
97
|
+
- The calls to `!` changed their semantics slightly: it's impossible to monkey patch this call for `Boolean` or `NilClass`.
|
98
|
+
- Refactored the structure of the internal `stdlib/nodejs` folder ([#2374](https://github.com/opal/opal/pull/2374))
|
99
|
+
- Added `nodejs/base` with just I/O, exit, and ARGV management
|
100
|
+
- Moved `Process::Status` to corelib
|
101
|
+
- Fixed requires to be more robust
|
102
|
+
|
103
|
+
### Removed
|
104
|
+
|
105
|
+
- Removed `nodejs/irb` from stdlib as it's been broken for some time ([#2374](https://github.com/opal/opal/pull/2374))
|
106
|
+
- Removed `Kernel#node_require` from `nodejs/kernel` as it's been deprecated for a long time ([#2374](https://github.com/opal/opal/pull/2374))
|
107
|
+
|
108
|
+
<!--
|
109
|
+
### Deprecated
|
110
|
+
### Internal
|
111
|
+
-->
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
## [1.3.2](https://github.com/opal/opal/compare/v1.3.1...v1.3.2) - 2021-11-10
|
19
117
|
|
20
118
|
|
21
119
|
### Fixed
|
22
120
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
121
|
+
- Update documentation ([#2350](https://github.com/opal/opal/pull/2350))
|
122
|
+
- Fix `IO#gets` getting an extra char under some circumstances ([#2349](https://github.com/opal/opal/pull/2349))
|
123
|
+
- Raise a `TypeError` instead of `UndefinedMethod` if not a string is passed to `__send__` ([#2346](https://github.com/opal/opal/pull/2346))
|
124
|
+
- Do not modify `$~` when calling `String#scan` from internal methods ([#2353](https://github.com/opal/opal/pull/2353))
|
125
|
+
- Stop interpreting falsey values as a missing constant in `Module#const_get` ([#2354](https://github.com/opal/opal/pull/2354))
|
126
|
+
|
127
|
+
|
128
|
+
|
129
|
+
|
130
|
+
## [1.3.1](https://github.com/opal/opal/compare/v1.3.0...v1.3.1) - 2021-11-03
|
131
|
+
|
132
|
+
|
133
|
+
### Fixed
|
134
|
+
|
135
|
+
- Fix REPL if bundler environment isn't set ([#2338](https://github.com/opal/opal/pull/2338))
|
136
|
+
- Fix Chrome runner if bundler environment isn't set and make it work on other Unixes ([#2339](https://github.com/opal/opal/pull/2339))
|
137
|
+
- `Proc#binding` to return a binding if `Binding` is defined (#2341, #2340)
|
138
|
+
- `Array#zip` to correctly `yield` (#2342, #1611)
|
139
|
+
- `String#scan` to correctly `yield` (#2342, #1660)
|
28
140
|
|
29
141
|
|
30
142
|
|
@@ -94,7 +206,7 @@ Changes are grouped as follows:
|
|
94
206
|
### Fixed
|
95
207
|
|
96
208
|
- Fixed multiple line `Regexp` literal to not generate invalid syntax as JavaScript ([#1616](https://github.com/opal/opal/pull/1616))
|
97
|
-
- Fix `Kernel#{
|
209
|
+
- Fix `Kernel#{throw,catch}` along with `UncaughtThrowError` ([#2264](https://github.com/opal/opal/pull/2264))
|
98
210
|
- Update source-map-support to fix an off-by-one error ([#2264](https://github.com/opal/opal/pull/2264))
|
99
211
|
- Source map: lines should start from 1, not 0 ([#2273](https://github.com/opal/opal/pull/2273))
|
100
212
|
- Allow for multiple underscored args with the same name in strict mode ([#2292](https://github.com/opal/opal/pull/2292))
|
@@ -123,10 +235,6 @@ Changes are grouped as follows:
|
|
123
235
|
- `Process` is now a Module, not a Class - just like in MRI ([#2332](https://github.com/opal/opal/pull/2332))
|
124
236
|
- `s = StringIO.new("a"); s << "b"; s.string` now returns "b", like MRI, but Opal used to return "ab" ([#2309](https://github.com/opal/opal/pull/2309))
|
125
237
|
|
126
|
-
### Deprecated
|
127
|
-
|
128
|
-
### Removed
|
129
|
-
|
130
238
|
### Internal
|
131
239
|
|
132
240
|
- Switch from jshint to ESLint ([#2289](https://github.com/opal/opal/pull/2289))
|
data/UNRELEASED.md
CHANGED
@@ -1,13 +1,8 @@
|
|
1
|
-
|
1
|
+
<!--
|
2
2
|
### Fixed
|
3
|
-
|
4
|
-
* Fix REPL if bundler environment isn't set (#2338)
|
5
|
-
* Fix Chrome runner if bundler environment isn't set and make it work on other Unixes (#2339)
|
6
|
-
* `Proc#binding` to return a binding if `Binding` is defined (#2341, #2340)
|
7
|
-
* `Array#zip` to correctly `yield` (#2342, #1611)
|
8
|
-
* `String#scan` to correctly `yield` (#2342, #1660)
|
9
|
-
|
10
3
|
### Changed
|
11
|
-
###
|
4
|
+
### Added
|
12
5
|
### Removed
|
6
|
+
### Deprecated
|
13
7
|
### Internal
|
8
|
+
-->
|
@@ -0,0 +1,30 @@
|
|
1
|
+
Benchmark.ips do |x|
|
2
|
+
%x{
|
3
|
+
// Old version truthy logic
|
4
|
+
var old_version = function(x) { return x !== nil && x != null && (!x.$$is_boolean || x == true); }
|
5
|
+
|
6
|
+
// New version truthy logic
|
7
|
+
var new_version_1 = function(val) { return undefined !== val && null !== val && false !== val && nil !== val && (!(val instanceof Boolean) || true === val.valueOf()); }
|
8
|
+
|
9
|
+
// Alternative new version truthy logic
|
10
|
+
var new_version_2 = function(val) { return undefined !== val && null !== val && false !== val && nil !== val && !(val instanceof Boolean && false === val.valueOf()); }
|
11
|
+
|
12
|
+
// Alternative new version, nil&false first
|
13
|
+
var new_version_3 = function(val) { return false !== val && nil !== val && undefined !== val && null !== val && !(val instanceof Boolean && false === val.valueOf()); }
|
14
|
+
|
15
|
+
// Alternative new version truthy logic that unsupports boxed booleans
|
16
|
+
var new_unboxed = function(val) { return undefined !== val && null !== val && false !== val && nil !== val; }
|
17
|
+
}
|
18
|
+
|
19
|
+
values = [123,243,35,"sd",false,nil,123413234,120412,0,1234.1234,0.34,false,false,true,"sadfasf","","0",13,123,nil,Object.new,[]]
|
20
|
+
|
21
|
+
x.time = 32
|
22
|
+
|
23
|
+
x.report('old_version') { values.map(&`old_version`) }
|
24
|
+
x.report('new_version_1') { values.map(&`new_version_1`) }
|
25
|
+
x.report('new_version_2') { values.map(&`new_version_2`) }
|
26
|
+
x.report('new_version_3') { values.map(&`new_version_3`) }
|
27
|
+
x.report('new_unboxed') { values.map(&`new_unboxed`) }
|
28
|
+
|
29
|
+
x.compare!
|
30
|
+
end
|
data/bin/opal-mspec
CHANGED
@@ -7,7 +7,5 @@ specs = ARGV.map do |s|
|
|
7
7
|
end
|
8
8
|
|
9
9
|
env = {}
|
10
|
-
env['
|
10
|
+
env['PATTERN'] = "{#{specs.join(',')}}" if specs.any?
|
11
11
|
exec env, 'rake', 'mspec'
|
12
|
-
|
13
|
-
# RUBYOPT="-rbundler/setup -rmspec/opal/special_calls" bundle exec mspec run -t opal -pspec/ruby/spec_helper spec/ruby/core/true/*
|
data/bin/opal-repl
CHANGED
data/bin/remove-filters
CHANGED
@@ -15,10 +15,7 @@
|
|
15
15
|
# 5) "Set#filter! returns nil when self was not modified"
|
16
16
|
|
17
17
|
filters = $stdin.read.split("\n").map do |i|
|
18
|
-
|
19
|
-
next if i =~ /formats the local time following the pattern/
|
20
|
-
|
21
|
-
i.scan(/\d+\) (".*")/).first.first
|
18
|
+
i.scan(/(?:\d+\)|fails) (".*")/).first.first
|
22
19
|
end.compact
|
23
20
|
filters = Regexp.union(*filters)
|
24
21
|
|
data/docs/compiled_ruby.md
CHANGED
@@ -30,8 +30,8 @@ to convert values to opal specific values.
|
|
30
30
|
|
31
31
|
NOTE: Because `true` and `false` compile to their native
|
32
32
|
javascript equivalents, they must share the same class: `Boolean`.
|
33
|
-
|
34
|
-
and `FalseClass
|
33
|
+
Thru some level of hackery, we make them pseudo-members of the appropriate
|
34
|
+
`TrueClass` and `FalseClass`.
|
35
35
|
|
36
36
|
#### Strings & Symbols
|
37
37
|
|
@@ -55,11 +55,11 @@ class. Symbols and Strings can therefore be used interchangeably.
|
|
55
55
|
|
56
56
|
#### Numbers
|
57
57
|
|
58
|
-
In Opal there is a single class for numbers; `
|
58
|
+
In Opal there is a single class for numbers; `Number`. To keep Opal
|
59
59
|
as performant as possible, Ruby numbers are mapped to native numbers.
|
60
60
|
This has the side effect that all numbers must be of the same class.
|
61
|
-
Most relevant methods from `Integer
|
62
|
-
|
61
|
+
Most relevant methods from `Integer` and `Float` are implemented on
|
62
|
+
this class.
|
63
63
|
|
64
64
|
```ruby
|
65
65
|
42 # => 42
|
@@ -104,7 +104,7 @@ else is a truthy value including `""`, `0` and `[]`. This differs from
|
|
104
104
|
JavaScript as these values are also treated as false.
|
105
105
|
|
106
106
|
For this reason, most truthy tests must check if values are `false` or
|
107
|
-
`nil
|
107
|
+
`nil` (we also check for `null` and `undefined`).
|
108
108
|
|
109
109
|
Taking the following test:
|
110
110
|
|
@@ -178,15 +178,19 @@ puts "foo"
|
|
178
178
|
This would compile directly into:
|
179
179
|
|
180
180
|
```javascript
|
181
|
-
(function(Opal) {
|
182
|
-
var self = Opal.top,
|
181
|
+
Opal.queue(function(Opal) {
|
182
|
+
var self = Opal.top, nil = Opal.nil;
|
183
183
|
|
184
|
-
Opal.add_stubs(
|
184
|
+
Opal.add_stubs('puts');
|
185
185
|
return self.$puts("foo")
|
186
|
-
})
|
186
|
+
});
|
187
187
|
```
|
188
188
|
|
189
|
-
**TIP:**
|
189
|
+
**TIP:**
|
190
|
+
|
191
|
+
you can see the compiled code with this command: `opal --compile --no-exit --no-opal --eval 'puts "foo"'`
|
192
|
+
or, more briefly: `opal -cEO -e 'puts "foo"'`
|
193
|
+
|
190
194
|
|
191
195
|
### Using compiled sources
|
192
196
|
|
@@ -204,16 +208,16 @@ obvious what went wrong.
|
|
204
208
|
|
205
209
|
As Opal just generates JavaScript, it is useful to use a native
|
206
210
|
debugger to work through JavaScript code. To use a debugger, simply
|
207
|
-
add
|
208
|
-
debug:
|
211
|
+
add a `debugger` statement:
|
209
212
|
|
210
213
|
```ruby
|
211
214
|
# .. code
|
212
|
-
|
215
|
+
debugger
|
213
216
|
# .. more code
|
214
217
|
```
|
215
|
-
|
216
|
-
JavaScript
|
218
|
+
|
219
|
+
The `debugger` statement is compiled to become a JavaScript `debugger`
|
220
|
+
statement. This statement breaks the code if you have your Inspector open.
|
217
221
|
|
218
222
|
NOTE: All local variables and method/block arguments also keep their Ruby
|
219
223
|
names except in the rare cases when the name is reserved in JavaScript.
|
@@ -246,7 +250,7 @@ in the browser.
|
|
246
250
|
}
|
247
251
|
|
248
252
|
# => opal version is:
|
249
|
-
# =>
|
253
|
+
# => 1.3.1
|
250
254
|
```
|
251
255
|
|
252
256
|
Even interpolations are supported, as seen here.
|
@@ -280,6 +284,9 @@ require 'native'
|
|
280
284
|
win = Native(`window`) # equivalent to Native::Object.new(`window`)
|
281
285
|
```
|
282
286
|
|
287
|
+
To access a Native-wrapped global JavaScript object, we can also use `$$`, after
|
288
|
+
we have the `native` module required.
|
289
|
+
|
283
290
|
Now what if we want to access one of its properties?
|
284
291
|
|
285
292
|
```ruby
|
@@ -514,10 +521,10 @@ Opal.BAZ; // => 789
|
|
514
521
|
To reach nested constants the safest way is to call `#const_get` on `Object`:
|
515
522
|
|
516
523
|
```javascript
|
517
|
-
Opal.Object
|
518
|
-
Opal.Object
|
519
|
-
Opal.Object
|
520
|
-
Opal.Object
|
524
|
+
Opal.Object.$const_get('Bar::BAR'); // => 123
|
525
|
+
Opal.Object.$const_get('Foo::BAR'); // => 123
|
526
|
+
Opal.Object.$const_get('Foo::FOO'); // => 456
|
527
|
+
Opal.Object.$const_get('BAZ'); // => 789
|
521
528
|
```
|
522
529
|
|
523
530
|
Constants can also be navigated using the `$$` property, although this is limited to constants defined directly under the current object:
|
@@ -528,6 +535,14 @@ Opal.Foo.$$.FOO // => 456
|
|
528
535
|
Opal.Foo.$$.BAR // => undefined
|
529
536
|
```
|
530
537
|
|
538
|
+
A later feature also allows you to skip the `$$` property:
|
539
|
+
|
540
|
+
```javascript
|
541
|
+
Opal.Bar.BAR // => 123
|
542
|
+
Opal.Foo.FOO // => 456
|
543
|
+
Opal.Foo.BAR // => undefined
|
544
|
+
```
|
545
|
+
|
531
546
|
|
532
547
|
### Calling methods
|
533
548
|
|
@@ -656,7 +671,7 @@ It is obvious from here, that unless an object defines any given method, it will
|
|
656
671
|
To optimise the generated code slightly, we reduce the code output from the compiler into the following JavaScript:
|
657
672
|
|
658
673
|
```javascript
|
659
|
-
Opal.add_stubs(
|
674
|
+
Opal.add_stubs("first,second,to_sym"]);
|
660
675
|
```
|
661
676
|
|
662
677
|
You will see this at the top of all your generated JavaScript files. This will add a stub method for all methods used in your file.
|
data/docs/faq.md
CHANGED
@@ -10,7 +10,7 @@ We run opal against the [ruby spec](https://github.com/ruby/spec) as our primary
|
|
10
10
|
|
11
11
|
### What version of ruby does Opal target?
|
12
12
|
|
13
|
-
We are running tests under ruby
|
13
|
+
We are running tests under ruby 3.0.0 conditions, but are mostly compatible with 2.6 level features.
|
14
14
|
|
15
15
|
### Why doesn't Opal support mutable strings?
|
16
16
|
|
data/docs/headless_chrome.md
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
## Requirements
|
4
4
|
|
5
5
|
First of all, make sure that you have Chrome at least 59.0 installed.
|
6
|
-
Also for now it's supported only on Mac and Linux. (version 60 may get support on Windows)
|
7
6
|
|
8
7
|
## Using the runner
|
9
8
|
|
@@ -22,11 +21,9 @@ The runner also listens for any exceptions and prints formatted stracktraces bac
|
|
22
21
|
raising_method
|
23
22
|
"
|
24
23
|
|
25
|
-
RuntimeError
|
26
|
-
|
27
|
-
|
28
|
-
at (file:///tmp/chrome-opal.js:21146:14)
|
29
|
-
at (file:///tmp/chrome-opal.js:21147:2)
|
24
|
+
RuntimeError: test error
|
25
|
+
from <internal:corelib/…>:2693:7:in `<main>'
|
26
|
+
from -e:1:1:in `undefined'
|
30
27
|
|
31
28
|
## Using exit codes
|
32
29
|
|
@@ -36,10 +33,9 @@ By default headless chrome runner explicitly sets exit code to 1 when there was
|
|
36
33
|
0
|
37
34
|
|
38
35
|
$ opal -Rchrome -e "raise 'error'"; echo $?
|
39
|
-
RuntimeError
|
40
|
-
|
41
|
-
|
42
|
-
at (file:///tmp/chrome-opal.js:21140:2)
|
36
|
+
RuntimeError: error
|
37
|
+
from <internal:corelib/kerne…>:2693:7:in `<main>'
|
38
|
+
from -e:1:1:in `undefined'
|
43
39
|
1
|
44
40
|
|
45
41
|
You can change final exit code by using `Kernel#exit`, but make sure to require `opal/platform` in your code.
|
@@ -69,20 +65,12 @@ or runs the server on its own. It detects your platform and uses a default path
|
|
69
65
|
(`Opal::CliRunners::Chrome#chrome_executable`) but you can override it by specifying `GOOGLE_CHROME_BINARY` environment
|
70
66
|
variable.
|
71
67
|
|
72
|
-
When the server is up and running it passes compiled js code to `
|
68
|
+
When the server is up and running it passes compiled js code to `lib/opal/cli_runners/chrome_cdp_interface.rb`
|
73
69
|
as a plain input using stdin (basically, it's a second part of the runner).
|
74
|
-
`
|
70
|
+
`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,
|
75
71
|
catches errors and forwards console messages.
|
76
72
|
|
77
73
|
|
78
|
-
Moreover, you can actually call any js using headless chrome by running
|
79
|
-
|
80
|
-
$ echo "console.log('Hello, Opal')" | node lib/opal/cli_runners/chrome.js
|
81
|
-
|
82
|
-
NOTE: to run it you need to have a chrome server running on `localhost:9222` (usually `chrome.rb` does it for you)
|
83
|
-
|
84
|
-
$ chrome --disable-gpu --headless --remote-debugging-port=9222
|
85
|
-
|
86
74
|
## Using a remote chrome server
|
87
75
|
|
88
76
|
If you want to change a default chrome port or your chrome server is running on a different host:port
|
@@ -99,7 +87,9 @@ NOTE: `CHROME_HOST` requires a chrome server to be started. You can't start remo
|
|
99
87
|
|
100
88
|
If you need to pass additional CLI options to the Chrome executable you can do so by setting the `CHROME_OPTS` environment variable:
|
101
89
|
|
102
|
-
$
|
90
|
+
$ CHROME_OPTS="--window-size=412,732" opal -Rchrome -e "puts 42"
|
103
91
|
42
|
104
92
|
|
93
|
+
Docker users may need `CHROME_OPTS="--no-sandbox"` due to the user namespaces limitations.
|
94
|
+
|
105
95
|
_For a list of additional options see https://developers.google.com/web/updates/2017/04/headless-chrome_
|
data/docs/jquery.md
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
# JQuery
|
2
2
|
|
3
|
-
`opal-jquery` offers a nicer ruby-like syntax for JQuery
|
4
|
-
useful for projects which cannot use `opal-browser` due to a reliance on jquery
|
5
|
-
for plugins or other libraries.
|
3
|
+
`opal-jquery` offers a nicer ruby-like syntax for JQuery. It is useful for projects which cannot use `opal-browser` due to a reliance on jquery for plugins or other libraries.
|
6
4
|
|
7
5
|
```ruby
|
8
6
|
foos = Element.find('.foo')
|
@@ -91,9 +89,6 @@ bridged instances of jquery objects. Just like ruby arrays are just javascript
|
|
91
89
|
arrays, `Element` instances are just jquery objects. This makes interaction
|
92
90
|
with jquery plugins much easier.
|
93
91
|
|
94
|
-
Also, `Element` will try to bridge with Zepto if it cannot find jQuery loaded,
|
95
|
-
making it ideal for mobile applications as well.
|
96
|
-
|
97
92
|
### Interacting with the DOM
|
98
93
|
|
99
94
|
#### Finding Elements
|
data/docs/opal_parser.md
CHANGED
@@ -8,12 +8,14 @@ Opal is able to compile its – pure Ruby – compiler to JavaScript (how cool i
|
|
8
8
|
require 'opal-parser'
|
9
9
|
```
|
10
10
|
|
11
|
+
_Note: For the best performance and application load times, it is strongly recommended to design your application so that it won't need the parser. A lot of methods described in this document are more fun hacks than robust solutions. But if you really want or need to use them, for example so that you can implement a Ruby REPL or an interactive Ruby playground - we have you covered, but for all other cases, we strongly discourage you to take an advice from this guide._
|
12
|
+
|
11
13
|
|
12
14
|
## Features
|
13
15
|
|
14
16
|
### `Kernel#eval`
|
15
17
|
|
16
|
-
`opal-parser` provides a partial implementation of `Kernel#eval
|
18
|
+
`opal-parser` provides a partial implementation of `Kernel#eval`.
|
17
19
|
|
18
20
|
Example:
|
19
21
|
|
data/docs/promises.md
CHANGED
@@ -8,6 +8,8 @@ It can be required inside any Opal applicaton:
|
|
8
8
|
require 'promise'
|
9
9
|
```
|
10
10
|
|
11
|
+
_Please also take a look at the Asynchronous code guide - we are in the process of modernizing the Promises, along with supporting async/await_
|
12
|
+
|
11
13
|
## Usage
|
12
14
|
|
13
15
|
This example shows how to use a `HTTP` request from `opal-jquery` from a callback style, into a promise style handler.
|
data/docs/releasing.md
CHANGED
@@ -11,11 +11,14 @@ _This guide is a work-in-progress._
|
|
11
11
|
|
12
12
|
- Ensure all the unreleased changes are documented in UNRELEASED.md
|
13
13
|
- Run `bin/rake changelog VERSION=v1.2.3` specifying the version number you're about to release
|
14
|
+
- Empty UNRELEASED.md
|
14
15
|
|
15
16
|
## The commit
|
16
17
|
|
17
18
|
- Commit the updated changelog along with the version bump using this commit message:
|
18
19
|
"Release v1.2.3"
|
20
|
+
- Push the commit and run `bin/rake release` to release the new version to Rubygems
|
21
|
+
- Go to GitHub releases and create a new release from the latest tag pasting the contents from CHANGELOG.md
|
19
22
|
|
20
23
|
## Opal docs
|
21
24
|
|