ruby2js 2.1.24 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +91 -50
  3. data/lib/ruby2js/converter/args.rb +10 -0
  4. data/lib/ruby2js/converter/block.rb +1 -1
  5. data/lib/ruby2js/converter/case.rb +1 -1
  6. data/lib/ruby2js/converter/casgn.rb +6 -1
  7. data/lib/ruby2js/converter/class.rb +7 -2
  8. data/lib/ruby2js/converter/class2.rb +167 -0
  9. data/lib/ruby2js/converter/def.rb +54 -6
  10. data/lib/ruby2js/converter/defs.rb +11 -5
  11. data/lib/ruby2js/converter/dstr.rb +26 -0
  12. data/lib/ruby2js/converter/for.rb +3 -3
  13. data/lib/ruby2js/converter/hash.rb +31 -6
  14. data/lib/ruby2js/converter/if.rb +1 -1
  15. data/lib/ruby2js/converter/ivasgn.rb +5 -2
  16. data/lib/ruby2js/converter/masgn.rb +41 -4
  17. data/lib/ruby2js/converter/send.rb +71 -10
  18. data/lib/ruby2js/converter/super.rb +21 -8
  19. data/lib/ruby2js/converter/vasgn.rb +5 -1
  20. data/lib/ruby2js/converter/while.rb +13 -0
  21. data/lib/ruby2js/converter.rb +32 -5
  22. data/lib/ruby2js/es2015/strict.rb +3 -0
  23. data/lib/ruby2js/es2015.rb +5 -0
  24. data/lib/ruby2js/es2016/strict.rb +3 -0
  25. data/lib/ruby2js/es2016.rb +5 -0
  26. data/lib/ruby2js/es2017/strict.rb +3 -0
  27. data/lib/ruby2js/es2017.rb +5 -0
  28. data/lib/ruby2js/execjs.rb +1 -1
  29. data/lib/ruby2js/filter/camelCase.rb +1 -1
  30. data/lib/ruby2js/filter/functions.rb +49 -2
  31. data/lib/ruby2js/filter/vue.rb +66 -45
  32. data/lib/ruby2js/strict.rb +3 -0
  33. data/lib/ruby2js/version.rb +3 -3
  34. data/lib/ruby2js.rb +41 -0
  35. data/ruby2js.gemspec +3 -1
  36. metadata +10 -6
  37. data/lib/ruby2js/filter/angular-resource.rb +0 -25
  38. data/lib/ruby2js/filter/angular-route.rb +0 -44
  39. data/lib/ruby2js/filter/angularrb.rb +0 -604
  40. data/lib/ruby2js/filter/strict.rb +0 -20
@@ -1,604 +0,0 @@
1
- require 'ruby2js'
2
-
3
- module Ruby2JS
4
- module Filter
5
- module AngularRB
6
- include SEXP
7
-
8
- def self.s(type, *args)
9
- Parser::AST::Node.new type, args
10
- end
11
-
12
- Angular = s(:const, nil, :Angular)
13
-
14
- # convert simple assignments, simple method calls, and simple method
15
- # definitions into a hash when possible; return false otherwise
16
- def self.hash(pairs)
17
- if pairs.length == 1 and pairs.first.type == :begin
18
- pairs = pairs.first.children
19
- end
20
-
21
- s(:hash, *pairs.map {|pair|
22
- if pair.type == :send and pair.children[0] == nil
23
- s(:pair, s(:sym, pair.children[1]), pair.children[2])
24
- elsif pair.type == :lvasgn
25
- s(:pair, s(:sym, pair.children[0]), pair.children[1])
26
- elsif pair.type == :def
27
- s(:pair, s(:sym, pair.children[0]), s(:block, s(:send, nil, :proc),
28
- *pair.children[1..-1]))
29
- else
30
- return false
31
- end
32
- })
33
- end
34
-
35
- def initialize(*args)
36
- @ngApp = nil
37
- @ngContext = nil
38
- @ngAppUses = []
39
- @ngClassUses = []
40
- @ngClassOmit = []
41
- @ngScope = nil
42
- super
43
- end
44
-
45
- # input:
46
- # module Angular::AppName
47
- # use :Dependency
48
- # ...
49
- # end
50
- #
51
- # output:
52
- # AppName = angular.module("AppName", ["Dependency"])
53
- # ...
54
-
55
- def on_module(node)
56
- ngContext, @ngContext = @ngContext, :module
57
- @ngModule = node.children
58
- if @ngModule.last and @ngModule.last.type == :begin
59
- @ngModule = @ngModule.last.children
60
- end
61
- module_name = node.children[0]
62
- parent_name = module_name.children[0]
63
-
64
- return super unless parent_name == Angular
65
-
66
- @ngApp = s(:lvar, module_name.children[1])
67
- @ngChildren = node.children[1..-1]
68
- while @ngChildren.length == 1 and @ngChildren.first and @ngChildren.first.type == :begin
69
- @ngChildren = @ngChildren.first.children.dup
70
- end
71
- @ngAppUses = []
72
-
73
- block = process_all(node.children[1..-1])
74
-
75
- # convert use calls into dependencies
76
- depends = @ngAppUses.map {|sym| s(:sym, sym)} + extract_uses(block)
77
- depends = depends.map {|dnode| dnode.children.first.to_s}.uniq.sort.
78
- map {|sym| s(:str, sym)}
79
-
80
- ngApp, @ngApp, @ngChildren = @ngApp, nil, nil
81
- name = module_name.children[1].to_s
82
-
83
- # construct app
84
- app = s(:send, s(:lvar, :angular), :module,
85
- s(:str, name), s(:array, *depends.uniq))
86
-
87
- # return a single chained statement when there is only one call
88
- block.compact!
89
- if block.length == 0
90
- return app
91
- elsif block.length == 1
92
- call = block.first.children.first
93
- if block.first.type == :send and call == ngApp
94
- return block.first.updated nil, [app, *block.first.children[1..-1]]
95
- elsif block.first.type == :block and call.children.first == ngApp
96
- call = call.updated nil, [app, *call.children[1..-1]]
97
- return block.first.updated nil, [call, *block.first.children[1..-1]]
98
- end
99
- end
100
-
101
- # replace module with a constant assign followed by the module
102
- # contents all wrapped in an anonymous function
103
- s(:send, s(:block, s(:send, nil, :proc), s(:args),
104
- s(:begin, s(:casgn, nil, name, app), *block)), :[])
105
- ensure
106
- @ngContext = ngContext
107
- end
108
-
109
- # input:
110
- # class name {...}
111
- #
112
- # output:
113
- # app.factory(uses) do
114
- # ...
115
- # end
116
- def on_class(node)
117
- ngContext, @ngContext = @ngContext, :class
118
- return super unless @ngApp and @ngChildren.include? node
119
-
120
- name = node.children.first
121
- if name.children.first == nil
122
- @ngClassUses, @ngClassOmit = [], []
123
- @ngClassUses << node.children[1].children[1] if node.children[1]
124
-
125
- block = [node.children.last]
126
- uses = extract_uses(block)
127
- node = s(:class, name, node.children[1],
128
- s(:begin, *process_all(block)))
129
-
130
- @ngClassUses -= @ngClassOmit + [name.children.last]
131
- args = @ngClassUses.map {|sym| s(:arg, sym)} + uses
132
- args = args.map {|anode| anode.children.first.to_sym}.uniq.sort.
133
- map {|sym| s(:arg, sym)}
134
- @ngClassUses, @ngClassOmit = [], []
135
-
136
- s(:block, s(:send, @ngApp, :factory,
137
- s(:sym, name.children.last)), s(:args, *args),
138
- s(:begin, node, s(:return, s(:const, nil, name.children.last))))
139
- else
140
- super
141
- end
142
- ensure
143
- @ngClassUses, @ngClassOmit = [], []
144
- @ngContext = ngContext
145
- end
146
-
147
- # input:
148
- # filter :name { ... }
149
- # controller :name { ... }
150
- # factory :name { ... }
151
- # directive :name { ... }
152
-
153
- def on_block(node)
154
- ngApp = @ngApp
155
- call = node.children.first
156
- target = call.children.first
157
- if target and target.type == :const and target.children.first == Angular
158
- @ngApp = s(:send, s(:lvar, :angular), :module, s(:str,
159
- target.children.last.to_s))
160
- else
161
- return super if target
162
- return super unless @ngApp
163
- end
164
-
165
- begin
166
- case call.children[1]
167
- when :controller
168
- ng_controller(node, :controller)
169
- when :factory
170
- ng_factory(node)
171
- when :filter
172
- ng_filter(node)
173
- when :config
174
- ng_config(node)
175
- when :directive
176
- hash = AngularRB.hash(node.children[2..-1])
177
- if hash
178
- node = node.updated nil, [*node.children[0..1], s(:return, hash)]
179
- end
180
- ng_controller(node, :directive)
181
- when :watch
182
- ng_watch(node, :$watch)
183
- when :on
184
- ng_watch(node, :$on)
185
- when :observe
186
- ng_observe(node)
187
- when :timeout, :interval
188
- method = (call.children[1] == :timeout ? :$timeout : :$interval)
189
- process s(:gvar, method) # for dependency injection purposes
190
- process s(:send, nil, method, s(:block, s(:send, nil, :proc),
191
- *node.children[1..-1]), *call.children[2..-1])
192
- else
193
- super
194
- end
195
- ensure
196
- @ngApp = ngApp
197
- end
198
- end
199
-
200
- # input:
201
- # config :service do
202
- # name = value
203
- # end
204
- #
205
- # output:
206
- # AppName.config("service") do |service|
207
- # service.name = value
208
- # end
209
- def ng_config(node)
210
- call = node.children.first
211
- services = call.children[2..-1].map {|sym| sym.children[0]}
212
- list = node.children[2..-1]
213
-
214
- if services.length == 1
215
- hash = AngularRB.hash(node.children[2..-1])
216
- if hash
217
- service = call.children[2].children[0]
218
- list = hash.children.map do |pair|
219
- s(:send, s(:gvar, service), "#{pair.children[0].children[0]}=",
220
- pair.children[1])
221
- end
222
- end
223
- end
224
-
225
- s(:send, @ngApp, :config,
226
- s(:array, *services.map {|sym| s(:str, sym.to_s)},
227
- s(:block, s(:send, nil, :proc),
228
- s(:args, *services.map {|sym| s(:arg, sym)}), s(:begin, *list))))
229
- end
230
-
231
- # input:
232
- # controller :name do
233
- # ...
234
- # end
235
- #
236
- # output:
237
- # AppName.controller("name") do |uses|
238
- # ...
239
- # end
240
- def ng_controller(node, scope)
241
- ngContext, @ngContext = @ngContext, scope
242
- @ngClassUses, @ngClassOmit = [], []
243
- target = node.children.first
244
- target = target.updated(nil, [@ngApp, *target.children[1..-1]])
245
-
246
- block = process_all(node.children[2..-1])
247
-
248
- # convert use calls into args
249
- @ngClassUses -= @ngClassOmit
250
- args = node.children[1].children
251
- args += @ngClassUses.map {|sym| s(:arg, sym)} + extract_uses(block)
252
- args = args.map {|anode| anode.children.first.to_sym}.uniq.sort.
253
- map {|sym| s(:arg, sym)}
254
-
255
- node.updated :block, [target, s(:args, *args), s(:begin, *block)]
256
- ensure
257
- @ngClassUses, @ngClassOmit = [], []
258
- @ngContext = ngContext
259
- end
260
-
261
- # input:
262
- # filter :name do |input|
263
- # ...
264
- # end
265
- #
266
- # output:
267
- # AppName.filter :name do
268
- # return proc {|input| return ... }
269
- # end
270
- EXPRESSION = [ :and, :array, :attr, :const, :cvar, :defined?, :dstr,
271
- :dsym, :false, :float, :gvar, :hash, :int, :ivar, :lvar, :nil, :not,
272
- :or, :regexp, :self, :send, :str, :sym, :true, :undefined?, :xstr ]
273
-
274
- def ng_filter(node)
275
- ngContext, @ngContext = @ngContext, :filter
276
- @ngClassUses, @ngClassOmit = [], []
277
- call = node.children.first
278
-
279
- # insert return
280
- args = process_all(node.children[1].children)
281
- block = process_all(node.children[2..-1])
282
- uses = (@ngClassUses - @ngClassOmit).uniq.sort.map {|sym| s(:arg, sym)}
283
- tail = [block.pop || s(:nil)]
284
- while tail.length == 1 and tail.first.type == :begin
285
- tail = tail.first.children.dup
286
- end
287
- tail.push s(:return, tail.pop) if EXPRESSION.include? tail.last.type
288
- block.push (tail.length == 1 ? tail.first : s(:begin, *tail))
289
-
290
- # construct a function returning a function
291
- inner = s(:block, s(:send, nil, :proc), s(:args, *args), *block)
292
- outer = s(:send, @ngApp, :filter, *call.children[2..-1])
293
-
294
- node.updated nil, [outer, s(:args, *uses), s(:return, inner)]
295
- ensure
296
- @ngClassUses, @ngClassOmit = [], []
297
- @ngContext = ngContext
298
- end
299
-
300
- # input:
301
- # factory :name do |uses|
302
- # ...
303
- # end
304
- #
305
- # output:
306
- # AppName.factory :name, [uses, proc {|uses| ...}]
307
- def ng_factory(node)
308
- ngContext, @ngContext = @ngContext, :factory
309
- call = node.children.first
310
- call = call.updated(nil, [@ngApp, *call.children[1..-1]])
311
-
312
- # insert return
313
- block = process_all(node.children[2..-1])
314
- tail = [block.pop || s(:nil)]
315
- while tail.length == 1 and tail.first.type == :begin
316
- tail = tail.first.children.dup
317
- end
318
- tail.push s(:return, tail.pop) unless tail.last.type == :return
319
- block.push (tail.length == 1 ? tail.first : s(:begin, *tail))
320
-
321
- # extract dependencies
322
- @ngClassUses.delete call.children[2].children[0]
323
- args = process_all(node.children[1].children)
324
- args += @ngClassUses.map {|sym| s(:arg, sym)} + extract_uses(block)
325
- args = args.map {|anode| anode.children.first.to_sym}.uniq.sort.
326
- map {|sym| s(:arg, sym)}
327
-
328
- # construct a function
329
- function = s(:block, s(:send, nil, :proc), s(:args, *args), *block)
330
- array = args.map {|arg| s(:str, arg.children.first.to_s)}
331
-
332
- s(:send, *call.children, s(:array, *array, function))
333
- ensure
334
- @ngClassUses, @ngClassOmit = [], []
335
- @ngContext = ngContext
336
- end
337
-
338
- # input:
339
- # Constant = ...
340
- #
341
- # output:
342
- # AppName.factory :name, [uses, proc {|uses| ...}]
343
- def on_casgn(node)
344
- return super if node.children[0]
345
- @ngClassOmit << node.children[1]
346
- return super unless @ngApp and @ngChildren.include? node
347
- ng_factory s(:block, s(:send, nil, :factory, s(:sym, node.children[1])),
348
- s(:args), process(node.children[2]))
349
- end
350
-
351
- # convert ivar referencess in controllers to $scope
352
- def on_ivar(node)
353
- if @ngContext == :controller
354
- process s(:attr, s(:gvar, :$scope), node.children.first.to_s[1..-1])
355
- else
356
- super
357
- end
358
- end
359
-
360
- # convert cvar referencess in controllers to self
361
- def on_cvar(node)
362
- if @ngContext == :controller
363
- process s(:attr, s(:self), node.children.first.to_s[2..-1])
364
- else
365
- super
366
- end
367
- end
368
-
369
- # input:
370
- # watch 'expression' do |oldvalue, newvalue|
371
- # ...
372
- # end
373
- #
374
- # output:
375
- # $scope.$watch 'expression' do |oldvalue, newvalue|
376
- # ...
377
- # end
378
- #
379
- # also handles 'on'
380
- #
381
- def ng_watch(node, method)
382
- call = node.children.first
383
- if @ngContext == :controller and call.children.first == nil
384
- target = s(:gvar, :$scope)
385
- expression = call.children[2]
386
- if not [:str, :dstr, :sym, :dsym].include? expression.type
387
- expression = s(:block, s(:send, nil, :proc), s(:args),
388
- s(:return, expression))
389
- end
390
- else
391
- target = nil
392
- method = call.children[1]
393
- expression = call.children[2]
394
- end
395
- call = s(:send, process(target), method, process(expression),
396
- *process_all(call.children[3..-1]))
397
- node.updated nil, [call, *process_all(node.children[1..-1])]
398
- end
399
-
400
- # input:
401
- # observe attr.name do |value|
402
- # ...
403
- # end
404
- #
405
- # output:
406
- # attr.$observe('name') do |value|
407
- # ...
408
- # end
409
- def ng_observe(node)
410
- if @ngContext == :controller and @ngScope
411
- call = node.children[0]
412
- expression = call.children[2]
413
- call = s(:send, expression.children[0], :$observe,
414
- s(:sym, expression.children[1]))
415
- process node.updated nil, [call, *node.children[1..-1]]
416
- else
417
- node.updated nil, process_all(node.children)
418
- end
419
- end
420
-
421
- # convert ivar assignments in controllers to $scope
422
- def on_ivasgn(node)
423
- if @ngContext == :controller
424
- if node.children.length == 1
425
- process s(:attr, s(:gvar, :$scope),
426
- "#{node.children.first.to_s[1..-1]}")
427
- else
428
- process s(:send, s(:gvar, :$scope),
429
- "#{node.children.first.to_s[1..-1]}=", node.children.last)
430
- end
431
- else
432
- super
433
- end
434
- end
435
-
436
- # convert cvar assignments in controllers to self
437
- def on_cvasgn(node)
438
- if @ngContext == :controller
439
- if node.children.length == 1
440
- process s(:attr, s(:self), "#{node.children.first.to_s[2..-1]}")
441
- else
442
- process s(:send, s(:self), "#{node.children.first.to_s[2..-1]}=",
443
- node.children.last)
444
- end
445
- else
446
- super
447
- end
448
- end
449
-
450
- NG_METHOD_MAP = {
451
- :apply! => [:$rootScope, :$apply],
452
- :apply => [:$scope, :$apply],
453
- :broadcast! => [:$rootScope, :$broadcast],
454
- :broadcast => [:$scope, :$broadcast],
455
- :digest! => [:$rootScope, :$digest],
456
- :digest => [:$scope, :$digest],
457
- :emit => [:$scope, :$emit],
458
- :evalAsync! => [:$rootScope, :$evalAsync],
459
- :evalAsync => [:$scope, :$evalAsync],
460
- :eval! => [:$rootScope, :$eval],
461
- :eval => [:$scope, :$eval],
462
- :filter => [nil, :$filter],
463
- :parent => [:$scope, :$parent],
464
- }
465
-
466
- def on_send(node)
467
- if @ngContext == :controller
468
- if node.children[0..1] == [nil, :interpolate] and @ngScope
469
- @ngClassUses << :$interpolate
470
- if node.children.length > 3 and node.children[3].type == :nil
471
- return process node.updated nil, [nil, :$interpolate,
472
- node.children[2]]
473
- else
474
- return process s(:send, s(:send, nil, :$interpolate,
475
- *node.children[2..-1]), nil, @ngScope)
476
- end
477
-
478
- elsif node.children[0..1] == [nil, :compile] and @ngScope
479
-
480
- @ngClassUses << :$compile
481
- if node.children.length > 3 and node.children.last.type == :nil
482
- return process node.updated nil, [nil, :$compile,
483
- *node.children[2..-2]]
484
- else
485
- return process s(:send, s(:send, nil, :$compile,
486
- *node.children[2..-1]), nil, @ngScope)
487
- end
488
- end
489
-
490
- # map well known method names to the appropriate service
491
- scope, method = NG_METHOD_MAP[node.children[1]]
492
-
493
- return super unless node.children.first == nil and method
494
-
495
- scope = s(:gvar, scope) if scope
496
- process s(:gvar, method) unless scope
497
-
498
- process node.updated nil, [scope, method, *node.children[2..-1]]
499
-
500
- elsif @ngContext == :module and node.children[0]
501
- return super unless @ngModule.include? node
502
- child = node
503
- while child and child.type == :send
504
- child = child.children[0]
505
- end
506
-
507
- # singleton configuration syntax
508
- return super unless child and (child.type == :gvar or
509
- (child.type == :const and child.children[0] == nil))
510
-
511
- service = child.children.last
512
- s(:send, @ngApp, :config, s(:array, s(:str, service.to_s), s(:block,
513
- s(:send, nil, :proc), s(:args, s(:arg, service)), node)))
514
-
515
- else
516
- super
517
- end
518
- end
519
-
520
- # convert instance method definitions in controllers to $scope
521
- def on_pair(node)
522
- if @ngContext == :directive and node.children[0] == s(:sym, :link)
523
- begin
524
- ngScope = @ngScope
525
- if node.children[1].type == :block
526
- args = node.children[1].children[1]
527
- if args.children.length > 0
528
- @ngScope = s(:lvar, args.children[0].children[0])
529
- @ngContext = :controller
530
- end
531
- end
532
- super
533
- ensure
534
- @ngScope = ngScope
535
- @ngContext = :directive
536
- end
537
- else
538
- super
539
- end
540
- end
541
-
542
- # convert instance method definitions in controllers to $scope
543
- def on_def(node)
544
- if @ngContext == :controller
545
- if node.is_method?
546
- process s(:defs, s(:gvar, :$scope), *node.children)
547
- else
548
- process s(:defp, s(:gvar, :$scope), *node.children)
549
- end
550
- else
551
- super
552
- end
553
- end
554
-
555
- def on_gvar(node)
556
- return @ngScope if node.children.first == :$scope and @ngScope
557
-
558
- if @ngClassUses
559
- @ngClassUses << node.children.first
560
- end
561
-
562
- super
563
- end
564
-
565
- BUILTINS = [ :Array, :Boolean, :Date, :Error, :Function, :Infinity, :JSON,
566
- :Math, :NaN, :Number, :Object, :RegExp, :Regexp, :String ]
567
-
568
- def on_const(node)
569
- if @ngClassUses and not node.children.first
570
- unless BUILTINS.include? node.children.last
571
- @ngClassUses << node.children.last
572
- end
573
- end
574
-
575
- super
576
- end
577
-
578
- def extract_uses(block)
579
- # find the block
580
- while block.length == 1 and block.first and block.first.type == :begin
581
- block.push(*block.shift.children)
582
- end
583
-
584
- # find use class method calls
585
- uses = block.find_all do |node|
586
- node and node.type == :send and node.children[0..1] == [nil, :use]
587
- end
588
-
589
- # convert use calls into dependencies
590
- depends = []
591
- uses.each do |use|
592
- use.children[2..-1].each do |node|
593
- depends << node if [:str, :sym].include? node.type
594
- end
595
- block.delete use
596
- end
597
-
598
- depends
599
- end
600
- end
601
-
602
- DEFAULTS.push AngularRB
603
- end
604
- end
@@ -1,20 +0,0 @@
1
- require 'ruby2js'
2
-
3
- module Ruby2JS
4
- module Filter
5
- module Strict
6
- include SEXP
7
-
8
- def process(node)
9
- if @strict
10
- super
11
- else
12
- @strict = true
13
- s(:begin, s(:str, 'use strict'), super(node))
14
- end
15
- end
16
- end
17
-
18
- DEFAULTS.push Strict
19
- end
20
- end