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
@@ -0,0 +1,271 @@
1
+ require 'pp'
2
+ require 'stringio'
3
+
4
+
5
+ module REPLUtils
6
+ module_function
7
+
8
+ def ls(object, colorize)
9
+ methods = imethods = object.methods
10
+ ancestors = object.class.ancestors
11
+ constants = []
12
+ ivs = object.instance_variables
13
+ cvs = []
14
+
15
+ if [Class, Module].include? object.class
16
+ imethods = object.instance_methods
17
+ ancestors = object.ancestors
18
+ constants = object.constants
19
+ cvs = object.class_variables
20
+ end
21
+
22
+ if colorize
23
+ blue = ->(i) { "\e[1;34m#{i}\e[0m" }
24
+ dark_blue = ->(i) { "\e[34m#{i}\e[0m" }
25
+ else
26
+ blue = dark_blue = ->(i) { i }
27
+ end
28
+
29
+ out = ''
30
+ out = "#{blue['class variables']}: #{cvs.map { |i| dark_blue[i] }.sort.join(' ')}\n" + out unless cvs.empty?
31
+ out = "#{blue['instance variables']}: #{ivs.map { |i| dark_blue[i] }.sort.join(' ')}\n" + out unless ivs.empty?
32
+ ancestors.each do |a|
33
+ im = a.instance_methods(false)
34
+ meths = (im & imethods)
35
+ methods -= meths
36
+ imethods -= meths
37
+ next if meths.empty? || [Object, BasicObject, Kernel, PP::ObjectMixin].include?(a)
38
+ out = "#{blue["#{a.name}#methods"]}: #{meths.sort.join(' ')}\n" + out
39
+ end
40
+ methods &= object.methods(false)
41
+ out = "#{blue['self.methods']}: #{methods.sort.join(' ')}\n" + out unless methods.empty?
42
+ out = "#{blue['constants']}: #{constants.map { |i| dark_blue[i] }.sort.join(' ')}\n" + out unless constants.empty?
43
+ out
44
+ end
45
+
46
+ def eval_and_print(func, mode, colorize)
47
+ printer = if colorize
48
+ ->(i) { ColorPrinter.default(i) }
49
+ else
50
+ ->(i) { out = []; PP.pp(i, out); out.join }
51
+ end
52
+
53
+ %x{
54
+ var $_result = eval(func);
55
+
56
+ if (mode == 'silent') return nil;
57
+
58
+ if (typeof $_result === 'null') {
59
+ return "=> null";
60
+ }
61
+ else if (typeof $_result === 'undefined') {
62
+ return "=> undefined";
63
+ }
64
+ else if (typeof $_result.$$class === 'undefined') {
65
+ try {
66
+ var json = JSON.stringify($_result, null, 2);
67
+ if (!colorize) json = #{ColorPrinter.colorize(`json`)}
68
+ return "=> " + $_result.toString() + " => " + json;
69
+ }
70
+ catch(e) {
71
+ return "=> " + $_result.toString();
72
+ }
73
+ }
74
+ else {
75
+ if (mode == 'ls') {
76
+ return #{ls(`$_result`, colorize)};
77
+ }
78
+ else {
79
+ var pretty = #{printer.call(`$_result`)};
80
+ // Is it multiline? If yes, add a linebreak
81
+ if (pretty.match(/\n.*?\n/)) pretty = "\n" + pretty;
82
+ return "=> " + pretty;
83
+ }
84
+ }
85
+ }
86
+ rescue Exception => e # rubocop:disable Lint/RescueException
87
+ e.full_message(highlight: true)
88
+ end
89
+
90
+ def js_repl
91
+ while (line = gets)
92
+ input = JSON.parse(line)
93
+
94
+ out = eval_and_print(input[:code], input[:mode], input[:colors])
95
+ puts out if out
96
+ puts '<<<ready>>>'
97
+ end
98
+ end
99
+
100
+ # Slightly based on Pry's implementation
101
+ class ColorPrinter < ::PP
102
+ # Taken from CodeRay
103
+ TOKEN_COLORS = {
104
+ debug: "\e[1;37;44m",
105
+
106
+ annotation: "\e[34m",
107
+ attribute_name: "\e[35m",
108
+ attribute_value: "\e[31m",
109
+ binary: {
110
+ self: "\e[31m",
111
+ char: "\e[1;31m",
112
+ delimiter: "\e[1;31m",
113
+ },
114
+ char: {
115
+ self: "\e[35m",
116
+ delimiter: "\e[1;35m"
117
+ },
118
+ class: "\e[1;35;4m",
119
+ class_variable: "\e[36m",
120
+ color: "\e[32m",
121
+ comment: {
122
+ self: "\e[1;30m",
123
+ char: "\e[37m",
124
+ delimiter: "\e[37m",
125
+ },
126
+ constant: "\e[1;34;4m",
127
+ decorator: "\e[35m",
128
+ definition: "\e[1;33m",
129
+ directive: "\e[33m",
130
+ docstring: "\e[31m",
131
+ doctype: "\e[1;34m",
132
+ done: "\e[1;30;2m",
133
+ entity: "\e[31m",
134
+ error: "\e[1;37;41m",
135
+ exception: "\e[1;31m",
136
+ float: "\e[1;35m",
137
+ function: "\e[1;34m",
138
+ global_variable: "\e[1;32m",
139
+ hex: "\e[1;36m",
140
+ id: "\e[1;34m",
141
+ include: "\e[31m",
142
+ integer: "\e[1;34m",
143
+ imaginary: "\e[1;34m",
144
+ important: "\e[1;31m",
145
+ key: {
146
+ self: "\e[35m",
147
+ char: "\e[1;35m",
148
+ delimiter: "\e[1;35m",
149
+ },
150
+ keyword: "\e[32m",
151
+ label: "\e[1;33m",
152
+ local_variable: "\e[33m",
153
+ namespace: "\e[1;35m",
154
+ octal: "\e[1;34m",
155
+ predefined: "\e[36m",
156
+ predefined_constant: "\e[1;36m",
157
+ predefined_type: "\e[1;32m",
158
+ preprocessor: "\e[1;36m",
159
+ pseudo_class: "\e[1;34m",
160
+ regexp: {
161
+ self: "\e[35m",
162
+ delimiter: "\e[1;35m",
163
+ modifier: "\e[35m",
164
+ char: "\e[1;35m",
165
+ },
166
+ reserved: "\e[32m",
167
+ shell: {
168
+ self: "\e[33m",
169
+ char: "\e[1;33m",
170
+ delimiter: "\e[1;33m",
171
+ escape: "\e[1;33m",
172
+ },
173
+ string: {
174
+ self: "\e[31m",
175
+ modifier: "\e[1;31m",
176
+ char: "\e[1;35m",
177
+ delimiter: "\e[1;31m",
178
+ escape: "\e[1;31m",
179
+ },
180
+ symbol: {
181
+ self: "\e[33m",
182
+ delimiter: "\e[1;33m",
183
+ },
184
+ tag: "\e[32m",
185
+ type: "\e[1;34m",
186
+ value: "\e[36m",
187
+ variable: "\e[34m",
188
+
189
+ insert: {
190
+ self: "\e[42m",
191
+ insert: "\e[1;32;42m",
192
+ eyecatcher: "\e[102m",
193
+ },
194
+ delete: {
195
+ self: "\e[41m",
196
+ delete: "\e[1;31;41m",
197
+ eyecatcher: "\e[101m",
198
+ },
199
+ change: {
200
+ self: "\e[44m",
201
+ change: "\e[37;44m",
202
+ },
203
+ head: {
204
+ self: "\e[45m",
205
+ filename: "\e[37;45m"
206
+ },
207
+ }
208
+
209
+ TOKEN_COLORS[:keyword] = TOKEN_COLORS[:reserved]
210
+ TOKEN_COLORS[:method] = TOKEN_COLORS[:function]
211
+ TOKEN_COLORS[:escape] = TOKEN_COLORS[:delimiter]
212
+
213
+ def self.default(obj, width = 79)
214
+ pager = StringIO.new
215
+ pp(obj, pager, width)
216
+ pager.string
217
+ end
218
+
219
+ def self.pp(obj, output = $DEFAULT_OUTPUT, max_width = 79)
220
+ queue = ColorPrinter.new(output, max_width, "\n")
221
+ queue.guard_inspect_key { queue.pp(obj) }
222
+ queue.flush
223
+ output << "\n"
224
+ end
225
+
226
+ def text(str, max_width = str.length)
227
+ super(ColorPrinter.colorize(str), max_width)
228
+ end
229
+
230
+ def self.token(string, *name)
231
+ TOKEN_COLORS.dig(*name) + string + "\e[0m"
232
+ end
233
+
234
+ NUMBER = '[+-]?[0-9.]+(?:e[+-][0-9]+|i)?'
235
+ REGEXP = '/.*?/[iesu]*'
236
+ TOKEN_REGEXP = /(\s+|=>|[@$:]?[a-z]\w+|[A-Z]\w+|#{NUMBER}|#{REGEXP}|".*?"|#<.*?[> ]|.)/
237
+
238
+ def self.tokenize(str)
239
+ str.scan(TOKEN_REGEXP).map(&:first)
240
+ end
241
+
242
+ def self.colorize(str)
243
+ tokens = tokenize(str)
244
+
245
+ tokens.map do |tok|
246
+ case tok
247
+ when /^[0-9+-]/
248
+ if /[.e]/ =~ tok
249
+ token(tok, :float)
250
+ else
251
+ token(tok, :integer)
252
+ end
253
+ when /^"/
254
+ token(tok, :string, :self)
255
+ when /^:/
256
+ token(tok, :symbol, :self)
257
+ when /^[A-Z]/
258
+ token(tok, :constant)
259
+ when /^#</, '=', '>'
260
+ token(tok, :keyword)
261
+ when /^\/./
262
+ token(tok, :regexp, :self)
263
+ when 'true', 'false', 'nil'
264
+ token(tok, :predefined_constant)
265
+ else
266
+ tok
267
+ end
268
+ end.join
269
+ end
270
+ end
271
+ end
@@ -6,16 +6,20 @@ require 'opal/erb'
6
6
  require 'opal/version'
7
7
 
8
8
  module Kernel
9
- def eval(str)
9
+ def eval(str, binding = nil, file = nil, line = nil)
10
10
  str = Opal.coerce_to!(str, String, :to_str)
11
- default_eval_options = { file: '(eval)', eval: true }
11
+ default_eval_options = { file: file || '(eval)', eval: true }
12
12
  compiling_options = __OPAL_COMPILER_CONFIG__.merge(default_eval_options)
13
- code = Opal.compile str, compiling_options
14
- %x{
15
- return (function(self) {
16
- return eval(#{code});
17
- })(self)
18
- }
13
+ code = `Opal.compile(str, compiling_options)`
14
+ if binding
15
+ binding.js_eval(code)
16
+ else
17
+ %x{
18
+ return (function(self) {
19
+ return eval(#{code});
20
+ })(self)
21
+ }
22
+ end
19
23
  end
20
24
 
21
25
  def require_remote(url)
@@ -30,10 +34,19 @@ end
30
34
 
31
35
  %x{
32
36
  Opal.compile = function(str, options) {
33
- if (options) {
34
- options = Opal.hash(options);
37
+ try {
38
+ str = #{Opal.coerce_to!(`str`, String, :to_str)}
39
+ if (options) options = Opal.hash(options);
40
+ return Opal.Opal.$compile(str, options);
41
+ }
42
+ catch (e) {
43
+ if (e.$$class === Opal.Opal.SyntaxError) {
44
+ var err = Opal.SyntaxError.$new(e.message);
45
+ err.$set_backtrace(e.$backtrace());
46
+ throw(err);
47
+ }
48
+ else { throw e; }
35
49
  }
36
- return Opal.Opal.$compile(str, options);
37
50
  };
38
51
 
39
52
  Opal['eval'] = function(str, options) {
@@ -1,7 +1,11 @@
1
+ `/* global Java, GjsFileImporter */`
2
+
1
3
  browser = `typeof(document) !== "undefined"`
2
4
  node = `typeof(process) !== "undefined" && process.versions && process.versions.node`
3
5
  nashorn = `typeof(Java) !== "undefined" && Java.type`
4
6
  headless_chrome = `typeof(navigator) !== "undefined" && /\bHeadlessChrome\//.test(navigator.userAgent)`
7
+ gjs = `typeof(window) !== "undefined" && typeof(GjsFileImporter) !== 'undefined'`
8
+ opalminiracer = `typeof(opalminiracer) !== 'undefined'`
5
9
 
6
10
  OPAL_PLATFORM = if nashorn
7
11
  'nashorn'
@@ -9,5 +13,9 @@ OPAL_PLATFORM = if nashorn
9
13
  'nodejs'
10
14
  elsif headless_chrome
11
15
  'headless-chrome'
16
+ elsif gjs
17
+ 'gjs'
18
+ elsif opalminiracer
19
+ 'opal-miniracer'
12
20
  else # possibly browser, which is the primary target
13
21
  end
data/stdlib/promise/v2.rb CHANGED
@@ -98,10 +98,12 @@
98
98
  # end
99
99
  #
100
100
 
101
- warn 'PromiseV2 is a technology preview, which means it may change its behavior ' \
102
- 'in the future until this warning is removed. If you are interested in this part, ' \
103
- 'please make sure you track the async/await/promises tag on Opal issues: ' \
104
- 'https://github.com/opal/opal/issues?q=label%3Aasync%2Fawait%2Fpromises'
101
+ if `Opal.config.experimental_features_severity == 'warning'`
102
+ warn 'PromiseV2 is a technology preview, which means it may change its behavior ' \
103
+ 'in the future until this warning is removed. If you are interested in this part, ' \
104
+ 'please make sure you track the async/await/promises tag on Opal issues: ' \
105
+ 'https://github.com/opal/opal/issues?q=label%3Aasync%2Fawait%2Fpromises'
106
+ end
105
107
 
106
108
  class PromiseV2 < `Promise`
107
109
  class << self
@@ -360,6 +362,16 @@ class PromiseV2 < `Promise`
360
362
  yield self if block_given?
361
363
  end
362
364
 
365
+ alias to_v2 itself
366
+
367
+ def to_v1
368
+ v1 = PromiseV1.new
369
+
370
+ self.then { |i| v1.resolve(i) }.rescue { |i| v1.reject(i) }
371
+
372
+ v1
373
+ end
374
+
363
375
  alias to_n itself
364
376
 
365
377
  def inspect
data/stdlib/promise.rb CHANGED
@@ -337,6 +337,18 @@ class Promise
337
337
  result
338
338
  end
339
339
 
340
+ alias to_v1 itself
341
+
342
+ def to_v2
343
+ v2 = PromiseV2.new
344
+
345
+ self.then { |i| v2.resolve(i) }.rescue { |i| v2.reject(i) }
346
+
347
+ v2
348
+ end
349
+
350
+ alias to_n to_v2
351
+
340
352
  class Trace < self
341
353
  def self.it(promise)
342
354
  current = []
@@ -444,3 +456,5 @@ class Promise
444
456
  end
445
457
  end
446
458
  end
459
+
460
+ PromiseV1 = Promise
data/stdlib/stringio.rb CHANGED
@@ -1,7 +1,4 @@
1
1
  class StringIO < IO
2
- include IO::Readable
3
- include IO::Writable
4
-
5
2
  def self.open(string = "", mode = nil, &block)
6
3
  io = new(string, mode)
7
4
  res = block.call(io)
@@ -14,13 +11,9 @@ class StringIO < IO
14
11
 
15
12
  def initialize(string = "", mode = 'rw')
16
13
  @string = string
17
- @position = string.length
14
+ @position = 0
18
15
 
19
- if mode.include?('r') and not mode.include?('w')
20
- @closed = :write
21
- elsif mode.include?('w') and not mode.include?('r')
22
- @closed = :read
23
- end
16
+ super(nil, mode)
24
17
  end
25
18
 
26
19
  def eof?
@@ -32,6 +25,9 @@ class StringIO < IO
32
25
  alias eof eof?
33
26
 
34
27
  def seek(pos, whence = IO::SEEK_SET)
28
+ # Let's reset the read buffer, because it will be most likely wrong
29
+ @read_buffer = ''
30
+
35
31
  case whence
36
32
  when IO::SEEK_SET
37
33
  raise Errno::EINVAL unless pos >= 0
@@ -68,70 +64,12 @@ class StringIO < IO
68
64
  seek 0
69
65
  end
70
66
 
71
- def each_byte(&block)
72
- return enum_for :each_byte unless block
73
-
74
- check_readable
75
-
76
- i = @position
77
- until eof?
78
- block.call(@string[i].ord)
79
- i += 1
80
- end
81
-
82
- self
83
- end
84
-
85
- def each_char(&block)
86
- return enum_for :each_char unless block
87
-
88
- check_readable
89
-
90
- i = @position
91
- until eof?
92
- block.call(@string[i])
93
- i += 1
94
- end
95
-
96
- self
97
- end
98
-
99
- def each(separator = $/)
100
- return enum_for :each_line unless block_given?
101
- check_readable
102
- chomp_lines = false
103
- if ::Hash === separator
104
- separator = (chomp_lines = separator[:chomp]) ? /\r?\n/ : $/
105
- elsif separator
106
- separator = separator.to_str
107
- else
108
- separator = `undefined`
109
- end
110
- %x{
111
- var str = self.string, stringLength = str.length;
112
- if (self.position < stringLength) str = str.substr(self.position);
113
- if (separator) {
114
- var chomped = #{`str`.chomp}, trailing = str.length !== chomped.length, splitted = chomped.split(separator);
115
- for (var i = 0, len = splitted.length; i < len; i++) {
116
- var line = chomp_lines ? splitted[i] : (i < len - 1 || trailing ? splitted[i] + separator : splitted[i]);
117
- #{yield `line`};
118
- }
119
- } else if (separator === undefined) {
120
- #{yield `str`};
121
- } else {
122
- var m, re = /(.+(?:\n\n|$))\n*/g;
123
- while ((m = re.exec(str))) #{yield `m[1]`};
124
- }
125
- self.position = stringLength;
126
- }
127
- self
128
- end
129
-
130
- alias each_line each
131
-
132
67
  def write(string)
133
68
  check_writable
134
69
 
70
+ # Let's reset the read buffer, because it will be most likely wrong
71
+ @read_buffer = ''
72
+
135
73
  string = String(string)
136
74
 
137
75
  if @string.length == @position
@@ -154,6 +92,7 @@ class StringIO < IO
154
92
  string = if length
155
93
  str = @string[@position, length]
156
94
  @position += length
95
+ @position = @string.length if @position > @string.length
157
96
  str
158
97
  else
159
98
  str = @string[@position .. -1]
@@ -168,47 +107,11 @@ class StringIO < IO
168
107
  end
169
108
  end
170
109
 
171
- def close
172
- @closed = :both
173
- end
174
-
175
- def close_read
176
- if @closed == :write
177
- @closed = :both
178
- else
179
- @closed = :read
180
- end
181
- end
182
-
183
- def close_write
184
- if @closed == :read
185
- @closed = :both
186
- else
187
- @closed = :write
188
- end
189
- end
190
-
191
- def closed?
192
- @closed == :both
193
- end
194
-
195
- def closed_read?
196
- @closed == :read || @closed == :both
197
- end
198
-
199
- def closed_write?
200
- @closed == :write || @closed == :both
201
- end
110
+ def sysread(length)
111
+ check_readable
202
112
 
203
- def check_writable
204
- if closed_write?
205
- raise IOError, "not opened for writing"
206
- end
113
+ read(length)
207
114
  end
208
115
 
209
- def check_readable
210
- if closed_read?
211
- raise IOError, "not opened for reading"
212
- end
213
- end
116
+ alias readpartial read
214
117
  end
data/stdlib/thread.rb CHANGED
@@ -111,6 +111,35 @@ class Thread
111
111
  @storage.each(&block)
112
112
  end
113
113
  end
114
+
115
+ class Backtrace
116
+ class Location
117
+ def initialize(str)
118
+ @str = str
119
+
120
+ str =~ /^(.*?):(\d+):(\d+):in `(.*?)'$/
121
+ @path = Regexp.last_match(1)
122
+ @label = Regexp.last_match(4)
123
+ @lineno = Regexp.last_match(2).to_i
124
+
125
+ @label =~ /(\w+)$/
126
+ @base_label = Regexp.last_match(1) || @label
127
+ end
128
+
129
+ def to_s
130
+ @str
131
+ end
132
+
133
+ def inspect
134
+ @str.inspect
135
+ end
136
+
137
+ attr_reader :base_label, :label, :lineno, :path
138
+
139
+ # TODO: Make it somehow provide the absolute path.
140
+ alias absolute_path path
141
+ end
142
+ end
114
143
  end
115
144
 
116
145
  Queue = Thread::Queue
data/tasks/building.rake CHANGED
@@ -4,11 +4,13 @@ desc <<-DESC
4
4
  Build *corelib* and *stdlib* to "build/"
5
5
 
6
6
  You can restrict the file list with the FILES env var (comma separated)
7
- and the destination dir with the DIR env var.
7
+ and the destination dir with the DIR env var, FORMATS to select output formats.
8
8
 
9
9
  Example: rake dist DIR=/tmp/foo FILES='opal.rb,base64.rb'
10
10
  Example: rake dist DIR=cdn/opal/#{Opal::VERSION}
11
11
  Example: rake dist DIR=cdn/opal/master
12
+ Example: rake dist DIR=cdn/opal/master FORMATS=js,min,gz
13
+ Example: rake dist DIR=cdn/opal/master FORMATS=js,map
12
14
  DESC
13
15
  task :dist do
14
16
  require 'opal/util'
@@ -22,6 +24,7 @@ task :dist do
22
24
  build_dir = ENV['DIR'] || 'build'
23
25
  files = ENV['FILES'] ? ENV['FILES'].split(',') :
24
26
  Dir['{opal,stdlib}/*.rb'].map { |lib| File.basename(lib, '.rb') }
27
+ formats = (ENV['FORMATS'] || 'js,min,gz').split(',')
25
28
 
26
29
  mkdir_p build_dir unless File.directory? build_dir
27
30
  width = files.map(&:size).max
@@ -34,9 +37,12 @@ task :dist do
34
37
 
35
38
  # Set requirable to true, unless building opal. This allows opal to be auto-loaded.
36
39
  requirable = (lib != 'opal')
37
- src = Opal::Builder.build(lib, requirable: requirable).to_s
38
- min = Opal::Util.uglify src
39
- gzp = Opal::Util.gzip min
40
+ builder = Opal::Builder.build(lib, requirable: requirable)
41
+
42
+ src = builder.to_s if (formats & %w[js min gz]).any?
43
+ src << ";" << builder.source_map.to_data_uri_comment if (formats & %w[map]).any?
44
+ min = Opal::Util.uglify src if (formats & %w[min gz]).any?
45
+ gzp = Opal::Util.gzip min if (formats & %w[gz]).any?
40
46
 
41
47
  File.open("#{build_dir}/#{lib}.js", 'w+') { |f| f << src }
42
48
  File.open("#{build_dir}/#{lib}.min.js", 'w+') { |f| f << min } if min
@@ -0,0 +1,39 @@
1
+ const SourceMapConsumer = require('source-map').SourceMapConsumer
2
+ const path = require('path')
3
+ const fs = require('fs')
4
+ const root = `${__dirname}/..`
5
+ const results = JSON.parse(fs.readFileSync(`${root}/tmp/lint/result.json`, 'utf8'))
6
+ const bufferFrom = require('buffer-from');
7
+ const puts = (string = '') => process.stdout.write(`${string}\n`)
8
+ const retrieveSourceMapURL = (fileData) => {
9
+ var re = /(?:\/\/[@#][\s]*sourceMappingURL=([^\s'"]+)[\s]*$)|(?:\/\*[@#][\s]*sourceMappingURL=([^\s*'"]+)[\s]*(?:\*\/)[\s]*$)/mg;
10
+ var matches = fileData.match(re);
11
+ return matches[matches.length - 1];
12
+ }
13
+
14
+ let count = 0
15
+
16
+ results.forEach(
17
+ ({filePath, messages}) => {
18
+ if (messages.length === 0) {return}
19
+
20
+ const sourceMappingURL = retrieveSourceMapURL(fs.readFileSync(filePath, 'utf8'))
21
+ const rawData = sourceMappingURL.split(',', 2)[1]
22
+ const sourceMapData = bufferFrom(rawData, "base64").toString();
23
+ const consumer = new SourceMapConsumer(sourceMapData);
24
+
25
+ messages.forEach((error) => {
26
+ const original = consumer.originalPositionFor({ line: error.line, column: error.column })
27
+ count++
28
+
29
+ puts()
30
+ puts(`* ${error.message}`)
31
+ if (error.ruleId) puts(` - Read more: https://eslint.org/docs/rules/${error.ruleId}`)
32
+ ;(error.suggestions || []).forEach((suggestion) => puts(` - Suggestion: ${suggestion.desc}`))
33
+ puts(` - Compiled: ${path.relative(root, filePath)}:${error.line}:${error.column}`)
34
+ puts(` - Original: ${original.source}:${original.line}:${original.column}`)
35
+ })
36
+ }
37
+ )
38
+
39
+ puts(`\nFailed with ${count} error${count === 1 ? '' : 's'}.`)