ruby2js 3.5.3 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +5 -665
- data/lib/ruby2js.rb +60 -15
- data/lib/ruby2js/converter.rb +39 -3
- data/lib/ruby2js/converter/args.rb +6 -1
- data/lib/ruby2js/converter/assign.rb +159 -0
- data/lib/ruby2js/converter/begin.rb +7 -2
- data/lib/ruby2js/converter/case.rb +7 -2
- data/lib/ruby2js/converter/class.rb +80 -21
- data/lib/ruby2js/converter/class2.rb +107 -33
- data/lib/ruby2js/converter/def.rb +7 -3
- data/lib/ruby2js/converter/dstr.rb +8 -3
- data/lib/ruby2js/converter/for.rb +1 -1
- data/lib/ruby2js/converter/hash.rb +28 -6
- data/lib/ruby2js/converter/hide.rb +13 -0
- data/lib/ruby2js/converter/if.rb +10 -2
- data/lib/ruby2js/converter/import.rb +19 -4
- data/lib/ruby2js/converter/kwbegin.rb +9 -2
- data/lib/ruby2js/converter/literal.rb +14 -2
- data/lib/ruby2js/converter/logical.rb +1 -1
- data/lib/ruby2js/converter/module.rb +41 -4
- data/lib/ruby2js/converter/next.rb +10 -2
- data/lib/ruby2js/converter/opasgn.rb +8 -0
- data/lib/ruby2js/converter/redo.rb +14 -0
- data/lib/ruby2js/converter/return.rb +2 -1
- data/lib/ruby2js/converter/send.rb +73 -8
- data/lib/ruby2js/converter/vasgn.rb +5 -0
- data/lib/ruby2js/converter/while.rb +1 -1
- data/lib/ruby2js/converter/whilepost.rb +1 -1
- data/lib/ruby2js/converter/xstr.rb +2 -3
- data/lib/ruby2js/demo.rb +53 -0
- data/lib/ruby2js/es2022.rb +5 -0
- data/lib/ruby2js/es2022/strict.rb +3 -0
- data/lib/ruby2js/filter.rb +9 -1
- data/lib/ruby2js/filter/active_functions.rb +44 -0
- data/lib/ruby2js/filter/camelCase.rb +6 -3
- data/lib/ruby2js/filter/cjs.rb +2 -0
- data/lib/ruby2js/filter/esm.rb +118 -26
- data/lib/ruby2js/filter/functions.rb +137 -109
- data/lib/ruby2js/filter/{wunderbar.rb → jsx.rb} +29 -7
- data/lib/ruby2js/filter/node.rb +58 -14
- data/lib/ruby2js/filter/nokogiri.rb +12 -12
- data/lib/ruby2js/filter/react.rb +182 -57
- data/lib/ruby2js/filter/require.rb +102 -11
- data/lib/ruby2js/filter/return.rb +13 -1
- data/lib/ruby2js/filter/stimulus.rb +187 -0
- data/lib/ruby2js/jsx.rb +309 -0
- data/lib/ruby2js/namespace.rb +75 -0
- data/lib/ruby2js/serializer.rb +19 -12
- data/lib/ruby2js/sprockets.rb +40 -0
- data/lib/ruby2js/version.rb +3 -3
- data/ruby2js.gemspec +2 -2
- metadata +23 -13
- data/lib/ruby2js/filter/esm_migration.rb +0 -72
- data/lib/ruby2js/rails.rb +0 -63
data/lib/ruby2js.rb
CHANGED
@@ -10,9 +10,15 @@ end
|
|
10
10
|
|
11
11
|
require 'ruby2js/converter'
|
12
12
|
require 'ruby2js/filter'
|
13
|
+
require 'ruby2js/namespace'
|
13
14
|
|
14
15
|
module Ruby2JS
|
15
16
|
class SyntaxError < RuntimeError
|
17
|
+
attr_reader :diagnostic
|
18
|
+
def initialize(message, diagnostic=nil)
|
19
|
+
super(message)
|
20
|
+
@diagnostic = diagnostic
|
21
|
+
end
|
16
22
|
end
|
17
23
|
|
18
24
|
@@eslevel_default = 2009 # ecmascript 5
|
@@ -61,26 +67,42 @@ module Ruby2JS
|
|
61
67
|
include Ruby2JS::Filter
|
62
68
|
BINARY_OPERATORS = Converter::OPERATORS[2..-1].flatten
|
63
69
|
|
64
|
-
attr_accessor :prepend_list
|
70
|
+
attr_accessor :prepend_list, :disable_autoimports, :namespace
|
65
71
|
|
66
72
|
def initialize(comments)
|
67
73
|
@comments = comments
|
74
|
+
|
75
|
+
# check if magic comment is present:
|
76
|
+
first_comment = @comments.values.first&.map(&:text)&.first
|
77
|
+
@disable_autoimports = first_comment&.include?(" autoimports: false")
|
78
|
+
@disable_autoexports = first_comment&.include?(" autoexports: false")
|
79
|
+
|
68
80
|
@ast = nil
|
69
81
|
@exclude_methods = []
|
70
|
-
@esm = false
|
71
82
|
@prepend_list = Set.new
|
72
83
|
end
|
73
84
|
|
74
85
|
def options=(options)
|
75
86
|
@options = options
|
76
87
|
|
77
|
-
@included =
|
78
|
-
@excluded =
|
88
|
+
@included = Filter.included_methods
|
89
|
+
@excluded = Filter.excluded_methods
|
79
90
|
|
80
91
|
include_all if options[:include_all]
|
81
92
|
include_only(options[:include_only]) if options[:include_only]
|
82
93
|
include(options[:include]) if options[:include]
|
83
94
|
exclude(options[:exclude]) if options[:exclude]
|
95
|
+
|
96
|
+
filters = options[:filters] || DEFAULTS
|
97
|
+
@modules_enabled =
|
98
|
+
(defined? Ruby2JS::Filter::ESM and
|
99
|
+
filters.include? Ruby2JS::Filter::ESM) or
|
100
|
+
(defined? Ruby2JS::Filter::CJS and
|
101
|
+
filters.include? Ruby2JS::Filter::CJS)
|
102
|
+
end
|
103
|
+
|
104
|
+
def modules_enabled?
|
105
|
+
@modules_enabled
|
84
106
|
end
|
85
107
|
|
86
108
|
def es2015
|
@@ -111,6 +133,10 @@ module Ruby2JS
|
|
111
133
|
@options[:eslevel] >= 2021
|
112
134
|
end
|
113
135
|
|
136
|
+
def es2022
|
137
|
+
@options[:eslevel] >= 2022
|
138
|
+
end
|
139
|
+
|
114
140
|
def process(node)
|
115
141
|
ast, @ast = @ast, node
|
116
142
|
replacement = super
|
@@ -125,6 +151,7 @@ module Ruby2JS
|
|
125
151
|
end
|
126
152
|
|
127
153
|
# handle all of the 'invented/synthetic' ast types
|
154
|
+
def on_assign(node); end
|
128
155
|
def on_async(node); on_def(node); end
|
129
156
|
def on_asyncs(node); on_defs(node); end
|
130
157
|
def on_attr(node); on_send(node); end
|
@@ -132,17 +159,23 @@ module Ruby2JS
|
|
132
159
|
def on_await(node); on_send(node); end
|
133
160
|
def on_call(node); on_send(node); end
|
134
161
|
def on_class_extend(node); on_send(node); end
|
162
|
+
def on_class_hash(node); on_class(node); end
|
135
163
|
def on_class_module(node); on_send(node); end
|
136
164
|
def on_constructor(node); on_def(node); end
|
165
|
+
def on_deff(node); on_def(node); end
|
137
166
|
def on_defm(node); on_defs(node); end
|
138
167
|
def on_defp(node); on_defs(node); end
|
139
168
|
def on_for_of(node); on_for(node); end
|
140
169
|
def on_in?(node); on_send(node); end
|
141
170
|
def on_method(node); on_send(node); end
|
171
|
+
def on_module_hash(node); on_module(node); end
|
142
172
|
def on_prop(node); on_array(node); end
|
143
173
|
def on_prototype(node); on_begin(node); end
|
174
|
+
def on_send!(node); on_send(node); end
|
144
175
|
def on_sendw(node); on_send(node); end
|
145
176
|
def on_undefined?(node); on_defined?(node); end
|
177
|
+
def on_defineProps(node); end
|
178
|
+
def on_hide(node); on_begin(node); end
|
146
179
|
def on_nil(node); end
|
147
180
|
def on_xnode(node); end
|
148
181
|
def on_export(node); end
|
@@ -160,10 +193,12 @@ module Ruby2JS
|
|
160
193
|
return on_block s(:block, s(:send, *node.children[0..-2]),
|
161
194
|
s(:args, s(:arg, :a), s(:arg, :b)), s(:return,
|
162
195
|
process(s(:send, s(:lvar, :a), method, s(:lvar, :b)))))
|
163
|
-
|
196
|
+
elsif node.children.last.children.first.type == :sym
|
164
197
|
return on_block s(:block, s(:send, *node.children[0..-2]),
|
165
198
|
s(:args, s(:arg, :item)), s(:return,
|
166
199
|
process(s(:attr, s(:lvar, :item), method))))
|
200
|
+
else
|
201
|
+
super
|
167
202
|
end
|
168
203
|
end
|
169
204
|
super
|
@@ -172,6 +207,7 @@ module Ruby2JS
|
|
172
207
|
end
|
173
208
|
|
174
209
|
def self.convert(source, options={})
|
210
|
+
options = options.dup
|
175
211
|
options[:eslevel] ||= @@eslevel_default
|
176
212
|
options[:strict] = @@strict_default if options[:strict] == nil
|
177
213
|
options[:module] ||= @@module_default || :esm
|
@@ -188,9 +224,11 @@ module Ruby2JS
|
|
188
224
|
source = ast.loc.expression.source_buffer.source
|
189
225
|
else
|
190
226
|
ast, comments = parse( source, options[:file] )
|
191
|
-
comments = Parser::Source::Comment.associate(ast, comments)
|
227
|
+
comments = ast ? Parser::Source::Comment.associate(ast, comments) : {}
|
192
228
|
end
|
193
229
|
|
230
|
+
namespace = Namespace.new
|
231
|
+
|
194
232
|
filters = (options[:filters] || Filter::DEFAULTS)
|
195
233
|
|
196
234
|
unless filters.empty?
|
@@ -205,11 +243,13 @@ module Ruby2JS
|
|
205
243
|
filter = filter.new(comments)
|
206
244
|
|
207
245
|
filter.options = options
|
246
|
+
filter.namespace = namespace
|
208
247
|
ast = filter.process(ast)
|
209
248
|
|
210
|
-
|
249
|
+
unless filter.prepend_list.empty?
|
211
250
|
prepend = filter.prepend_list.sort_by {|ast| ast.type == :import ? 0 : 1}
|
212
|
-
ast
|
251
|
+
prepend.reject! {|ast| ast.type == :import} if filter.disable_autoimports
|
252
|
+
ast = Parser::AST::Node.new(:begin, [*prepend, ast])
|
213
253
|
end
|
214
254
|
end
|
215
255
|
|
@@ -222,7 +262,10 @@ module Ruby2JS
|
|
222
262
|
ruby2js.comparison = options[:comparison] || :equality
|
223
263
|
ruby2js.or = options[:or] || :logical
|
224
264
|
ruby2js.module_type = options[:module] || :esm
|
225
|
-
ruby2js.underscored_private = (options[:eslevel] <
|
265
|
+
ruby2js.underscored_private = (options[:eslevel] < 2022) || options[:underscored_private]
|
266
|
+
|
267
|
+
ruby2js.namespace = namespace
|
268
|
+
|
226
269
|
if ruby2js.binding and not ruby2js.ivars
|
227
270
|
ruby2js.ivars = ruby2js.binding.eval \
|
228
271
|
'Hash[instance_variables.map {|var| [var, instance_variable_get(var)]}]'
|
@@ -240,23 +283,25 @@ module Ruby2JS
|
|
240
283
|
|
241
284
|
ruby2js.timestamp options[:file]
|
242
285
|
|
286
|
+
ruby2js.file_name = options[:file] || ast&.loc&.expression&.source_buffer&.name || ''
|
287
|
+
|
243
288
|
ruby2js
|
244
289
|
end
|
245
290
|
|
246
291
|
def self.parse(source, file=nil, line=1)
|
247
292
|
buffer = Parser::Source::Buffer.new(file, line)
|
248
|
-
buffer.source = source.encode('
|
293
|
+
buffer.source = source.encode('UTF-8')
|
249
294
|
parser = Parser::CurrentRuby.new
|
250
|
-
parser.
|
251
|
-
|
252
|
-
|
253
|
-
|
295
|
+
parser.diagnostics.all_errors_are_fatal = true
|
296
|
+
parser.diagnostics.consumer = lambda {|diagnostic| nil}
|
297
|
+
parser.builder.emit_file_line_as_literals = false
|
298
|
+
parser.parse_with_comments(buffer)
|
254
299
|
rescue Parser::SyntaxError => e
|
255
300
|
split = source[0..e.diagnostic.location.begin_pos].split("\n")
|
256
301
|
line, col = split.length, split.last.length
|
257
302
|
message = "line #{line}, column #{col}: #{e.diagnostic.message}"
|
258
303
|
message += "\n in file #{file}" if file
|
259
|
-
raise Ruby2JS::SyntaxError.new(message)
|
304
|
+
raise Ruby2JS::SyntaxError.new(message, e.diagnostic)
|
260
305
|
end
|
261
306
|
|
262
307
|
def self.find_block(ast, line)
|
data/lib/ruby2js/converter.rb
CHANGED
@@ -14,7 +14,7 @@ module Ruby2JS
|
|
14
14
|
|
15
15
|
class Converter < Serializer
|
16
16
|
attr_accessor :ast
|
17
|
-
|
17
|
+
|
18
18
|
LOGICAL = :and, :not, :or
|
19
19
|
OPERATORS = [:[], :[]=], [:not, :!], [:**], [:*, :/, :%], [:+, :-],
|
20
20
|
[:>>, :<<], [:&], [:^, :|], [:<=, :<, :>, :>=], [:==, :!=, :===, :"!=="],
|
@@ -34,7 +34,7 @@ module Ruby2JS
|
|
34
34
|
|
35
35
|
VASGN = [:cvasgn, :ivasgn, :gvasgn, :lvasgn]
|
36
36
|
|
37
|
-
attr_accessor :binding, :ivars
|
37
|
+
attr_accessor :binding, :ivars, :namespace
|
38
38
|
|
39
39
|
def initialize( ast, comments, vars = {} )
|
40
40
|
super()
|
@@ -66,6 +66,7 @@ module Ruby2JS
|
|
66
66
|
@comparison = :equality
|
67
67
|
@or = :logical
|
68
68
|
@underscored_private = true
|
69
|
+
@redoable = false
|
69
70
|
end
|
70
71
|
|
71
72
|
def width=(width)
|
@@ -160,6 +161,10 @@ module Ruby2JS
|
|
160
161
|
@eslevel >= 2021
|
161
162
|
end
|
162
163
|
|
164
|
+
def es2022
|
165
|
+
@eslevel >= 2022
|
166
|
+
end
|
167
|
+
|
163
168
|
@@handlers = []
|
164
169
|
def self.handle(*types, &block)
|
165
170
|
types.each do |type|
|
@@ -239,6 +244,34 @@ module Ruby2JS
|
|
239
244
|
end
|
240
245
|
end
|
241
246
|
|
247
|
+
def redoable(block)
|
248
|
+
save_redoable = @redoable
|
249
|
+
|
250
|
+
has_redo = proc do |node|
|
251
|
+
node.children.any? do |child|
|
252
|
+
next false unless child.is_a? Parser::AST::Node
|
253
|
+
next true if child.type == :redo
|
254
|
+
next false if %i[for while while_post until until_post].include? child.type
|
255
|
+
has_redo[child]
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
@redoable = has_redo[@ast]
|
260
|
+
|
261
|
+
if @redoable
|
262
|
+
put es2015 ? 'let ' : 'var '
|
263
|
+
put "redo$#@sep"
|
264
|
+
puts 'do {'
|
265
|
+
put "redo$ = false#@sep"
|
266
|
+
scope block
|
267
|
+
put "#@nl} while(redo$)"
|
268
|
+
else
|
269
|
+
scope block
|
270
|
+
end
|
271
|
+
ensure
|
272
|
+
@redoable = save_redoable
|
273
|
+
end
|
274
|
+
|
242
275
|
def timestamp(file)
|
243
276
|
super
|
244
277
|
|
@@ -248,7 +281,7 @@ module Ruby2JS
|
|
248
281
|
if ast.loc and ast.loc.expression
|
249
282
|
filename = ast.loc.expression.source_buffer.name
|
250
283
|
if filename and not filename.empty?
|
251
|
-
@timestamps[filename] ||= File.mtime(filename)
|
284
|
+
@timestamps[filename] ||= File.mtime(filename) rescue nil
|
252
285
|
end
|
253
286
|
end
|
254
287
|
|
@@ -295,6 +328,7 @@ end
|
|
295
328
|
require 'ruby2js/converter/arg'
|
296
329
|
require 'ruby2js/converter/args'
|
297
330
|
require 'ruby2js/converter/array'
|
331
|
+
require 'ruby2js/converter/assign'
|
298
332
|
require 'ruby2js/converter/begin'
|
299
333
|
require 'ruby2js/converter/block'
|
300
334
|
require 'ruby2js/converter/blockpass'
|
@@ -314,6 +348,7 @@ require 'ruby2js/converter/dstr'
|
|
314
348
|
require 'ruby2js/converter/fileline'
|
315
349
|
require 'ruby2js/converter/for'
|
316
350
|
require 'ruby2js/converter/hash'
|
351
|
+
require 'ruby2js/converter/hide'
|
317
352
|
require 'ruby2js/converter/if'
|
318
353
|
require 'ruby2js/converter/in'
|
319
354
|
require 'ruby2js/converter/import'
|
@@ -329,6 +364,7 @@ require 'ruby2js/converter/nil'
|
|
329
364
|
require 'ruby2js/converter/nthref'
|
330
365
|
require 'ruby2js/converter/opasgn'
|
331
366
|
require 'ruby2js/converter/prototype'
|
367
|
+
require 'ruby2js/converter/redo'
|
332
368
|
require 'ruby2js/converter/regexp'
|
333
369
|
require 'ruby2js/converter/return'
|
334
370
|
require 'ruby2js/converter/self'
|
@@ -30,13 +30,18 @@ module Ruby2JS
|
|
30
30
|
if kw.type == :kwarg
|
31
31
|
put kw.children.first
|
32
32
|
elsif kw.type == :kwoptarg
|
33
|
-
put kw.children.first
|
33
|
+
put kw.children.first
|
34
|
+
unless kw.children.last == s(:send, nil, :undefined)
|
35
|
+
put '='; parse kw.children.last
|
36
|
+
end
|
34
37
|
elsif kw.type == :kwrestarg
|
35
38
|
raise 'Rest arg requires ES2018' unless es2018
|
36
39
|
put '...'; put kw.children.first
|
37
40
|
end
|
38
41
|
end
|
39
42
|
put ' }'
|
43
|
+
|
44
|
+
put ' = {}' unless kwargs.any? {|kw| kw.type == :kwarg}
|
40
45
|
end
|
41
46
|
end
|
42
47
|
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# Kinda like Object.assign, except it handles properties
|
2
|
+
#
|
3
|
+
# Note: Object.defineProperties, Object.getOwnPropertyNames, etc. technically
|
4
|
+
# were not part of ES5, but were implemented by IE prior to ES6, and are
|
5
|
+
# the only way to implement getters and setters.
|
6
|
+
|
7
|
+
module Ruby2JS
|
8
|
+
class Converter
|
9
|
+
|
10
|
+
# (assign
|
11
|
+
# target
|
12
|
+
# (hash)
|
13
|
+
# ...
|
14
|
+
|
15
|
+
handle :assign do |target, *args|
|
16
|
+
collapsible = false
|
17
|
+
|
18
|
+
nonprop = proc do |node|
|
19
|
+
next false unless node.is_a? Parser::AST::Node
|
20
|
+
next false if node.type == :pair and node.children.first.type == :prop and es2015
|
21
|
+
next true unless node.type == :def
|
22
|
+
next false if node.children.first.to_s.end_with? '='
|
23
|
+
node.is_method?
|
24
|
+
end
|
25
|
+
|
26
|
+
collapsible = true if args.length == 1 and args.first.type == :hash and
|
27
|
+
args.first.children.length == 1
|
28
|
+
|
29
|
+
collapsible = true if args.length == 1 and args.first.type == :class_module and
|
30
|
+
args.first.children.length == 3 and nonprop[args.first.children.last]
|
31
|
+
|
32
|
+
if es2015 and not collapsible and args.all? {|arg|
|
33
|
+
case arg.type
|
34
|
+
when :pair, :hash, :class_module
|
35
|
+
arg.children.all? {|child| nonprop[child]}
|
36
|
+
when :const
|
37
|
+
false
|
38
|
+
else
|
39
|
+
true
|
40
|
+
end
|
41
|
+
}
|
42
|
+
parse s(:send, s(:const, nil, :Object), :assign, target, *args)
|
43
|
+
else
|
44
|
+
|
45
|
+
if target == s(:hash)
|
46
|
+
copy = [s(:gvasgn, :$$, target)]
|
47
|
+
target = s(:gvar, :$$)
|
48
|
+
shadow = [s(:shadowarg, :$$)]
|
49
|
+
elsif collapsible or es2015 or
|
50
|
+
(%i(send const).include? target.type and
|
51
|
+
target.children.length == 2 and target.children[0] == nil)
|
52
|
+
then
|
53
|
+
copy = []
|
54
|
+
shadow = []
|
55
|
+
else
|
56
|
+
copy = [s(:gvasgn, :$0, target)]
|
57
|
+
target = s(:gvar, :$0)
|
58
|
+
shadow = [s(:shadowarg, :$0)]
|
59
|
+
end
|
60
|
+
|
61
|
+
body = [*copy,
|
62
|
+
*args.map {|modname|
|
63
|
+
if modname.type == :hash and
|
64
|
+
modname.children.all? {|pair| pair.children.first.type == :prop}
|
65
|
+
|
66
|
+
if modname.children.length == 1
|
67
|
+
pair = modname.children.first
|
68
|
+
s(:send, s(:const, nil, :Object), :defineProperty, target,
|
69
|
+
s(:sym, pair.children.first.children.last),
|
70
|
+
s(:hash, *pair.children.last.map {|name, value| s(:pair,
|
71
|
+
s(:sym, name), value)}))
|
72
|
+
else
|
73
|
+
pair = modname.children.first
|
74
|
+
s(:send, s(:const, nil, :Object), :defineProperties, target,
|
75
|
+
s(:hash, *modname.children.map {|pair| s(:pair,
|
76
|
+
s(:sym, pair.children.first.children.last),
|
77
|
+
s(:hash, *pair.children.last.map {|name, value| s(:pair,
|
78
|
+
s(:sym, name), value)})
|
79
|
+
)}))
|
80
|
+
end
|
81
|
+
|
82
|
+
elsif modname.type == :hash and
|
83
|
+
modname.children.all? {|child| nonprop[child]}
|
84
|
+
|
85
|
+
s(:begin, *modname.children.map {|pair|
|
86
|
+
if pair.children.first.type == :prop
|
87
|
+
s(:send, s(:const, nil, :Object), :defineProperty, target,
|
88
|
+
s(:sym, pair.children.first.children.last),
|
89
|
+
s(:hash, *pair.children.last.map {|name, value| s(:pair,
|
90
|
+
s(:sym, name), value)}))
|
91
|
+
else
|
92
|
+
s(:send, target, :[]=, *pair.children)
|
93
|
+
end
|
94
|
+
})
|
95
|
+
|
96
|
+
elsif modname.type == :class_module and
|
97
|
+
modname.children[2..-1].all? {|child| nonprop[child]}
|
98
|
+
|
99
|
+
s(:begin, *modname.children[2..-1].map {|pair|
|
100
|
+
s(:send, target, :[]=, s(:sym, pair.children.first),
|
101
|
+
pair.updated(:defm, [nil, *pair.children[1..-1]]))
|
102
|
+
})
|
103
|
+
|
104
|
+
elsif modname.type == :lvar and not es2015
|
105
|
+
s(:for, s(:lvasgn, :$_), modname,
|
106
|
+
s(:send, target, :[]=,
|
107
|
+
s(:lvar, :$_), s(:send, modname, :[], s(:lvar, :$_))))
|
108
|
+
|
109
|
+
else
|
110
|
+
if es2017
|
111
|
+
s(:send, s(:const, nil, :Object), :defineProperties, target,
|
112
|
+
s(:send, s(:const, nil, :Object), :getOwnPropertyDescriptors, modname))
|
113
|
+
else
|
114
|
+
if modname.type == :lvar or (%i(send const).include? modname.type and
|
115
|
+
modname.children.length == 2 and modname.children[0] == nil)
|
116
|
+
|
117
|
+
object = modname
|
118
|
+
else
|
119
|
+
shadow += [s(:shadowarg, :$1)]
|
120
|
+
object = s(:gvar, :$1)
|
121
|
+
end
|
122
|
+
|
123
|
+
copy = s(:send,
|
124
|
+
s(:const, nil, :Object), :defineProperties, target,
|
125
|
+
s(:send,
|
126
|
+
s(:send, s(:const, nil, :Object), :getOwnPropertyNames, object),
|
127
|
+
:reduce,
|
128
|
+
s(:block,
|
129
|
+
s(:send, nil, :lambda),
|
130
|
+
s(:args, s(:arg, :$2), s(:arg, :$3)),
|
131
|
+
s(:begin,
|
132
|
+
s(:send,
|
133
|
+
s(:lvar, :$2), :[]=, s(:lvar, :$3),
|
134
|
+
s(:send, s(:const, nil, :Object), :getOwnPropertyDescriptor,
|
135
|
+
object, s(:lvar, :$3))),
|
136
|
+
s(:return, s(:lvar, :$2)))),
|
137
|
+
s(:hash)))
|
138
|
+
|
139
|
+
|
140
|
+
if object.type == :gvar
|
141
|
+
s(:begin, s(:gvasgn, object.children.last, modname), copy)
|
142
|
+
else
|
143
|
+
copy
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
}]
|
148
|
+
|
149
|
+
if @state == :statement and shadow.empty?
|
150
|
+
parse s(:begin, *body)
|
151
|
+
else
|
152
|
+
body.push s(:return, target) if @state == :expression
|
153
|
+
parse s(:send, s(:block, s(:send, nil, :lambda), s(:args, *shadow),
|
154
|
+
s(:begin, *body)), :[])
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|