ruby2js 3.5.2 → 4.0.1
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 +47 -13
- data/lib/ruby2js/converter.rb +9 -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/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/opasgn.rb +8 -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/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 +104 -106
- 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 +192 -57
- data/lib/ruby2js/filter/require.rb +102 -11
- data/lib/ruby2js/filter/return.rb +13 -1
- data/lib/ruby2js/filter/stimulus.rb +185 -0
- data/lib/ruby2js/jsx.rb +309 -0
- data/lib/ruby2js/namespace.rb +75 -0
- data/lib/ruby2js/rails.rb +15 -9
- data/lib/ruby2js/serializer.rb +3 -1
- data/lib/ruby2js/version.rb +3 -3
- data/ruby2js.gemspec +2 -2
- metadata +17 -9
- data/lib/ruby2js/filter/esm_migration.rb +0 -72
- data/lib/ruby2js/filter/fast-deep-equal.rb +0 -23
| @@ -1,17 +1,19 @@ | |
| 1 1 | 
             
            require 'ruby2js'
         | 
| 2 2 |  | 
| 3 | 
            +
            # Convert Wunderbar syntax to JSX
         | 
| 4 | 
            +
             | 
| 3 5 | 
             
            module Ruby2JS
         | 
| 4 6 | 
             
              module Filter
         | 
| 5 | 
            -
                module  | 
| 7 | 
            +
                module JSX
         | 
| 6 8 | 
             
                  include SEXP
         | 
| 7 9 |  | 
| 8 10 | 
             
                  def on_send(node)
         | 
| 9 | 
            -
                    target, method, * | 
| 11 | 
            +
                    target, method, *args = node.children
         | 
| 10 12 |  | 
| 11 13 | 
             
                    if target == s(:const, nil, :Wunderbar)
         | 
| 12 14 | 
             
                      if [:debug, :info, :warn, :error, :fatal].include? method
         | 
| 13 15 | 
             
                        method = :error if method == :fatal
         | 
| 14 | 
            -
                        return node.updated(nil, [s(:const, nil, :console), method, * | 
| 16 | 
            +
                        return node.updated(nil, [s(:const, nil, :console), method, *args])
         | 
| 15 17 | 
             
                      end
         | 
| 16 18 | 
             
                    end
         | 
| 17 19 |  | 
| @@ -27,7 +29,17 @@ module Ruby2JS | |
| 27 29 | 
             
                    end
         | 
| 28 30 |  | 
| 29 31 | 
             
                    if target == nil and method.to_s.start_with? "_"
         | 
| 30 | 
            -
                      S(:xnode,  | 
| 32 | 
            +
                      S(:xnode, method.to_s[1..-1], *stack, *process_all(args))
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                    elsif method == :createElement and target == s(:const, nil, :React)
         | 
| 35 | 
            +
                      if args.first.type == :str and \
         | 
| 36 | 
            +
                        (args.length == 1 or %i(nil hash).include? args[1].type)
         | 
| 37 | 
            +
                        attrs = (args[1]&.type != :nil && args[1]) || s(:hash)
         | 
| 38 | 
            +
                        S(:xnode, args[0].children.first, attrs, *process_all(args[2..-1]))
         | 
| 39 | 
            +
                      else
         | 
| 40 | 
            +
                        super
         | 
| 41 | 
            +
                      end
         | 
| 42 | 
            +
             | 
| 31 43 | 
             
                    else
         | 
| 32 44 | 
             
                      super
         | 
| 33 45 | 
             
                    end
         | 
| @@ -42,8 +54,18 @@ module Ruby2JS | |
| 42 54 |  | 
| 43 55 | 
             
                    if target == nil and method.to_s.start_with? "_"
         | 
| 44 56 | 
             
                      if args.children.empty?
         | 
| 45 | 
            -
                         | 
| 46 | 
            -
             | 
| 57 | 
            +
                        if method == :_
         | 
| 58 | 
            +
                          # Fragment
         | 
| 59 | 
            +
                          if send.children.length == 2
         | 
| 60 | 
            +
                            process send.updated(:xnode, ['', *process_all(block)])
         | 
| 61 | 
            +
                          else
         | 
| 62 | 
            +
                            process s(:xnode, 'React.Fragment', *send.children[2..-1],
         | 
| 63 | 
            +
                              *process_all(block))
         | 
| 64 | 
            +
                          end
         | 
| 65 | 
            +
                        else
         | 
| 66 | 
            +
                          # append block as a standalone proc
         | 
| 67 | 
            +
                          process send.updated(nil, [*send.children, *process_all(block)])
         | 
| 68 | 
            +
                        end
         | 
| 47 69 | 
             
                      else
         | 
| 48 70 | 
             
                        # iterate over Enumerable arguments if there are args present
         | 
| 49 71 | 
             
                        send = send.children
         | 
| @@ -58,6 +80,6 @@ module Ruby2JS | |
| 58 80 | 
             
                  end
         | 
| 59 81 | 
             
                end
         | 
| 60 82 |  | 
| 61 | 
            -
                DEFAULTS.push  | 
| 83 | 
            +
                DEFAULTS.push JSX
         | 
| 62 84 | 
             
              end
         | 
| 63 85 | 
             
            end
         | 
    
        data/lib/ruby2js/filter/node.rb
    CHANGED
    
    | @@ -14,6 +14,10 @@ module Ruby2JS | |
| 14 14 |  | 
| 15 15 | 
             
                  IMPORT_FS = s(:import, ['fs'], s(:attr, nil, :fs))
         | 
| 16 16 |  | 
| 17 | 
            +
                  IMPORT_OS = s(:import, ['os'], s(:attr, nil, :os))
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  IMPORT_PATH = s(:import, ['path'], s(:attr, nil, :path))
         | 
| 20 | 
            +
             | 
| 17 21 | 
             
                  SETUP_ARGV = s(:lvasgn, :ARGV, s(:send, s(:attr, 
         | 
| 18 22 | 
             
                      s(:attr, nil, :process), :argv), :slice, s(:int, 2)))
         | 
| 19 23 |  | 
| @@ -31,11 +35,11 @@ module Ruby2JS | |
| 31 35 | 
             
                        prepend_list << IMPORT_CHILD_PROCESS
         | 
| 32 36 |  | 
| 33 37 | 
             
                        if args.length == 1
         | 
| 34 | 
            -
                           | 
| 38 | 
            +
                          S(:send, s(:attr, nil, :child_process), :execSync,
         | 
| 35 39 | 
             
                          process(args.first),
         | 
| 36 40 | 
             
                          s(:hash, s(:pair, s(:sym, :stdio), s(:str, 'inherit'))))
         | 
| 37 41 | 
             
                        else
         | 
| 38 | 
            -
                           | 
| 42 | 
            +
                          S(:send, s(:attr, nil, :child_process), :execFileSync,
         | 
| 39 43 | 
             
                          process(args.first), s(:array, *process_all(args[1..-1])),
         | 
| 40 44 | 
             
                          s(:hash, s(:pair, s(:sym, :stdio), s(:str, 'inherit'))))
         | 
| 41 45 | 
             
                        end
         | 
| @@ -57,7 +61,7 @@ module Ruby2JS | |
| 57 61 | 
             
                    then
         | 
| 58 62 | 
             
                      if method == :read and args.length == 1
         | 
| 59 63 | 
             
                        prepend_list << IMPORT_FS
         | 
| 60 | 
            -
                         | 
| 64 | 
            +
                        S(:send, s(:attr, nil, :fs), :readFileSync, *process_all(args),
         | 
| 61 65 | 
             
                          s(:str, 'utf8'))
         | 
| 62 66 |  | 
| 63 67 | 
             
                      elsif method == :write and args.length == 2
         | 
| @@ -111,15 +115,15 @@ module Ruby2JS | |
| 111 115 |  | 
| 112 116 | 
             
                      elsif method == :symlink and args.length == 2
         | 
| 113 117 | 
             
                        prepend_list << IMPORT_FS
         | 
| 114 | 
            -
                         | 
| 118 | 
            +
                        S(:send, s(:attr, nil, :fs), :symlinkSync, *process_all(args))
         | 
| 115 119 |  | 
| 116 120 | 
             
                      elsif method == :truncate and args.length == 2
         | 
| 117 121 | 
             
                        prepend_list << IMPORT_FS
         | 
| 118 | 
            -
                         | 
| 122 | 
            +
                        S(:send, s(:attr, nil, :fs), :truncateSync, *process_all(args))
         | 
| 119 123 |  | 
| 120 124 | 
             
                      elsif [:stat, :lstat].include? method and args.length == 1
         | 
| 121 125 | 
             
                        prepend_list << IMPORT_FS
         | 
| 122 | 
            -
                         | 
| 126 | 
            +
                        S(:send, s(:attr, nil, :fs), method.to_s + 'Sync',
         | 
| 123 127 | 
             
                          process(args.first))
         | 
| 124 128 |  | 
| 125 129 | 
             
                      elsif method == :unlink and args.length == 1
         | 
| @@ -128,6 +132,29 @@ module Ruby2JS | |
| 128 132 | 
             
                          S(:send, s(:attr, nil, :fs), :unlinkSync, process(file))
         | 
| 129 133 | 
             
                        })
         | 
| 130 134 |  | 
| 135 | 
            +
                      elsif target.children.last == :File
         | 
| 136 | 
            +
                        if method == :absolute_path
         | 
| 137 | 
            +
                          prepend_list << IMPORT_PATH
         | 
| 138 | 
            +
                          S(:send, s(:attr, nil, :path), :resolve,
         | 
| 139 | 
            +
                            *process_all(args.reverse))
         | 
| 140 | 
            +
                        elsif method == :absolute_path?
         | 
| 141 | 
            +
                          prepend_list << IMPORT_PATH
         | 
| 142 | 
            +
                          S(:send, s(:attr, nil, :path), :isAbsolute, *process_all(args))
         | 
| 143 | 
            +
                        elsif method == :basename
         | 
| 144 | 
            +
                          prepend_list << IMPORT_PATH
         | 
| 145 | 
            +
                          S(:send, s(:attr, nil, :path), :basename, *process_all(args))
         | 
| 146 | 
            +
                        elsif method == :dirname
         | 
| 147 | 
            +
                          prepend_list << IMPORT_PATH
         | 
| 148 | 
            +
                          S(:send, s(:attr, nil, :path), :dirname, *process_all(args))
         | 
| 149 | 
            +
                        elsif method == :extname
         | 
| 150 | 
            +
                          prepend_list << IMPORT_PATH
         | 
| 151 | 
            +
                          S(:send, s(:attr, nil, :path), :extname, *process_all(args))
         | 
| 152 | 
            +
                        elsif method == :join
         | 
| 153 | 
            +
                          prepend_list << IMPORT_PATH
         | 
| 154 | 
            +
                          S(:send, s(:attr, nil, :path), :join, *process_all(args))
         | 
| 155 | 
            +
                        else
         | 
| 156 | 
            +
                          super
         | 
| 157 | 
            +
                        end
         | 
| 131 158 | 
             
                      else
         | 
| 132 159 | 
             
                        super
         | 
| 133 160 | 
             
                      end
         | 
| @@ -163,7 +190,7 @@ module Ruby2JS | |
| 163 190 | 
             
                        S(:send, s(:attr, nil, :process), :chdir, *process_all(args))
         | 
| 164 191 |  | 
| 165 192 | 
             
                      elsif method == :pwd and args.length == 0
         | 
| 166 | 
            -
                         | 
| 193 | 
            +
                        S(:send!, s(:attr, nil, :process), :cwd)
         | 
| 167 194 |  | 
| 168 195 | 
             
                      elsif method == :rmdir and args.length == 1
         | 
| 169 196 | 
             
                        prepend_list << IMPORT_FS
         | 
| @@ -173,11 +200,11 @@ module Ruby2JS | |
| 173 200 |  | 
| 174 201 | 
             
                      elsif method == :ln and args.length == 2
         | 
| 175 202 | 
             
                        prepend_list << IMPORT_FS
         | 
| 176 | 
            -
                         | 
| 203 | 
            +
                        S(:send, s(:attr, nil, :fs), :linkSync, *process_all(args))
         | 
| 177 204 |  | 
| 178 205 | 
             
                      elsif method == :ln_s and args.length == 2
         | 
| 179 206 | 
             
                        prepend_list << IMPORT_FS
         | 
| 180 | 
            -
                         | 
| 207 | 
            +
                        S(:send, s(:attr, nil, :fs), :symlinkSync, *process_all(args))
         | 
| 181 208 |  | 
| 182 209 | 
             
                      elsif method == :rm and args.length == 1
         | 
| 183 210 | 
             
                        prepend_list << IMPORT_FS
         | 
| @@ -224,16 +251,16 @@ module Ruby2JS | |
| 224 251 | 
             
                      if method == :chdir and args.length == 1
         | 
| 225 252 | 
             
                        S(:send, s(:attr, nil, :process), :chdir, *process_all(args))
         | 
| 226 253 | 
             
                      elsif method == :pwd and args.length == 0
         | 
| 227 | 
            -
                         | 
| 254 | 
            +
                        S(:send!, s(:attr, nil, :process), :cwd)
         | 
| 228 255 | 
             
                      elsif method == :entries
         | 
| 229 256 | 
             
                        prepend_list << IMPORT_FS
         | 
| 230 | 
            -
                         | 
| 257 | 
            +
                        S(:send, s(:attr, nil, :fs), :readdirSync, *process_all(args))
         | 
| 231 258 | 
             
                      elsif method == :mkdir and args.length == 1
         | 
| 232 259 | 
             
                        prepend_list << IMPORT_FS
         | 
| 233 | 
            -
                         | 
| 260 | 
            +
                        S(:send, s(:attr, nil, :fs), :mkdirSync, process(args.first))
         | 
| 234 261 | 
             
                      elsif method == :rmdir and args.length == 1
         | 
| 235 262 | 
             
                        prepend_list << IMPORT_FS
         | 
| 236 | 
            -
                         | 
| 263 | 
            +
                        S(:send, s(:attr, nil, :fs), :rmdirSync, process(args.first))
         | 
| 237 264 | 
             
                      elsif method == :mktmpdir and args.length <=1
         | 
| 238 265 | 
             
                        prepend_list << IMPORT_FS
         | 
| 239 266 | 
             
                        if args.length == 0
         | 
| @@ -244,7 +271,14 @@ module Ruby2JS | |
| 244 271 | 
             
                          prefix = args.first
         | 
| 245 272 | 
             
                        end
         | 
| 246 273 |  | 
| 247 | 
            -
                         | 
| 274 | 
            +
                        S(:send, s(:attr, nil, :fs), :mkdtempSync, process(prefix))
         | 
| 275 | 
            +
                      elsif method == :home and args.length == 0
         | 
| 276 | 
            +
                        prepend_list << IMPORT_OS
         | 
| 277 | 
            +
                        S(:send!, s(:attr, nil, :os), :homedir)
         | 
| 278 | 
            +
                      elsif method == :tmpdir and args.length == 0
         | 
| 279 | 
            +
                        prepend_list << IMPORT_OS
         | 
| 280 | 
            +
                        S(:send!, s(:attr, nil, :os), :tmpdir)
         | 
| 281 | 
            +
             | 
| 248 282 | 
             
                      else
         | 
| 249 283 | 
             
                        super
         | 
| 250 284 | 
             
                      end
         | 
| @@ -285,6 +319,16 @@ module Ruby2JS | |
| 285 319 | 
             
                      S(:attr, s(:attr, nil, :process), :stdout)
         | 
| 286 320 | 
             
                    elsif node.children == [nil, :STDERR]
         | 
| 287 321 | 
             
                      S(:attr, s(:attr, nil, :process), :stderr)
         | 
| 322 | 
            +
                    elsif node.children.first == s(:const, nil, :File)
         | 
| 323 | 
            +
                      if node.children.last == :SEPARATOR
         | 
| 324 | 
            +
                        prepend_list << IMPORT_PATH
         | 
| 325 | 
            +
                        S(:attr, s(:attr, nil, :path), :sep)
         | 
| 326 | 
            +
                      elsif node.children.last == :PATH_SEPARATOR
         | 
| 327 | 
            +
                        prepend_list << IMPORT_PATH
         | 
| 328 | 
            +
                        S(:attr, s(:attr, nil, :path), :delimiter)
         | 
| 329 | 
            +
                      else
         | 
| 330 | 
            +
                        super
         | 
| 331 | 
            +
                      end
         | 
| 288 332 | 
             
                    else
         | 
| 289 333 | 
             
                      super
         | 
| 290 334 | 
             
                    end
         | 
| @@ -47,40 +47,40 @@ module Ruby2JS | |
| 47 47 | 
             
                      method == :at and 
         | 
| 48 48 | 
             
                      args.length == 1 and args.first.type == :str
         | 
| 49 49 | 
             
                    then
         | 
| 50 | 
            -
                      S(:send, target, :querySelector, process(args.first))
         | 
| 50 | 
            +
                      S(:send, process(target), :querySelector, process(args.first))
         | 
| 51 51 |  | 
| 52 52 | 
             
                    elsif \
         | 
| 53 53 | 
             
                      method == :search and 
         | 
| 54 54 | 
             
                      args.length == 1 and args.first.type == :str
         | 
| 55 55 | 
             
                    then
         | 
| 56 | 
            -
                      S(:send, target, :querySelectorAll, process(args.first))
         | 
| 56 | 
            +
                      S(:send, process(target), :querySelectorAll, process(args.first))
         | 
| 57 57 |  | 
| 58 58 | 
             
                    elsif method === :parent and args.length == 0
         | 
| 59 | 
            -
                      S(:attr, target, :parentNode)
         | 
| 59 | 
            +
                      S(:attr, process(target), :parentNode)
         | 
| 60 60 |  | 
| 61 61 | 
             
                    elsif method === :name and args.length == 0
         | 
| 62 | 
            -
                      S(:attr, target, :nodeName)
         | 
| 62 | 
            +
                      S(:attr, process(target), :nodeName)
         | 
| 63 63 |  | 
| 64 64 | 
             
                    elsif [:text, :content].include? method and args.length == 0
         | 
| 65 | 
            -
                      S(:attr, target, :textContent)
         | 
| 65 | 
            +
                      S(:attr, process(target), :textContent)
         | 
| 66 66 |  | 
| 67 67 | 
             
                    elsif method == :content= and args.length == 1
         | 
| 68 | 
            -
                      S(:send, target, :textContent=, *process_all(args))
         | 
| 68 | 
            +
                      S(:send, process(target), :textContent=, *process_all(args))
         | 
| 69 69 |  | 
| 70 70 | 
             
                    elsif method === :inner_html and args.length == 0
         | 
| 71 | 
            -
                      S(:attr, target, :innerHTML)
         | 
| 71 | 
            +
                      S(:attr, process(target), :innerHTML)
         | 
| 72 72 |  | 
| 73 73 | 
             
                    elsif method == :inner_html= and args.length == 1
         | 
| 74 | 
            -
                      S(:send, target, :innerHTML=, *process_all(args))
         | 
| 74 | 
            +
                      S(:send, process(target), :innerHTML=, *process_all(args))
         | 
| 75 75 |  | 
| 76 76 | 
             
                    elsif method === :to_html and args.length == 0
         | 
| 77 | 
            -
                      S(:attr, target, :outerHTML)
         | 
| 77 | 
            +
                      S(:attr, process(target), :outerHTML)
         | 
| 78 78 |  | 
| 79 79 | 
             
                    elsif \
         | 
| 80 80 | 
             
                      [:attr, :get_attribute].include? method and 
         | 
| 81 81 | 
             
                      args.length == 1 and args.first.type == :str
         | 
| 82 82 | 
             
                    then
         | 
| 83 | 
            -
                      S(:send, target, :getAttribute, process(args.first))
         | 
| 83 | 
            +
                      S(:send, process(target), :getAttribute, process(args.first))
         | 
| 84 84 |  | 
| 85 85 | 
             
                    elsif \
         | 
| 86 86 | 
             
                      [:key?, :has_attribute].include? method and 
         | 
| @@ -154,14 +154,14 @@ module Ruby2JS | |
| 154 154 | 
             
                      [:add_next_sibling, :next=, :after].include? method and
         | 
| 155 155 | 
             
                      args.length == 1
         | 
| 156 156 | 
             
                    then
         | 
| 157 | 
            -
                      S(:send, s(:attr, target, :parentNode), :insertBefore,
         | 
| 157 | 
            +
                      S(:send, s(:attr, process(target), :parentNode), :insertBefore,
         | 
| 158 158 | 
             
                        process(args.first), s(:attr, target, :nextSibling))
         | 
| 159 159 |  | 
| 160 160 | 
             
                    elsif \
         | 
| 161 161 | 
             
                      [:add_previous_sibling, :previous=, :before].include? method and
         | 
| 162 162 | 
             
                      args.length == 1
         | 
| 163 163 | 
             
                    then
         | 
| 164 | 
            -
                      S(:send, s(:attr, target, :parentNode), :insertBefore,
         | 
| 164 | 
            +
                      S(:send, s(:attr, process(target), :parentNode), :insertBefore,
         | 
| 165 165 | 
             
                        process(args.first), target)
         | 
| 166 166 |  | 
| 167 167 | 
             
                    elsif method == :prepend_child and args.length == 1
         | 
    
        data/lib/ruby2js/filter/react.rb
    CHANGED
    
    | @@ -17,30 +17,39 @@ | |
| 17 17 | 
             
            #  * ~"x" becomes document.querySelector("x")
         | 
| 18 18 | 
             
            #
         | 
| 19 19 | 
             
            require 'ruby2js'
         | 
| 20 | 
            +
            require 'ruby2js/jsx'
         | 
| 20 21 |  | 
| 21 22 | 
             
            module Ruby2JS
         | 
| 22 23 | 
             
              module Filter
         | 
| 23 24 | 
             
                module React
         | 
| 24 25 | 
             
                  include SEXP
         | 
| 26 | 
            +
                  extend  SEXP
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  REACT_IMPORTS = {
         | 
| 29 | 
            +
                    React: s(:import, ['React'], s(:attr, nil, :React)),
         | 
| 30 | 
            +
                    ReactDOM: s(:import, ['ReactDOM'], s(:attr, nil, :ReactDOM))
         | 
| 31 | 
            +
                  }
         | 
| 25 32 |  | 
| 26 33 | 
             
                  # the following command can be used to generate ReactAttrs:
         | 
| 27 34 | 
             
                  # 
         | 
| 28 35 | 
             
                  #   ruby -r ruby2js/filter/react -e "Ruby2JS::Filter::React.genAttrs"
         | 
| 29 36 | 
             
                  #
         | 
| 30 37 | 
             
                  def self.genAttrs
         | 
| 31 | 
            -
                     | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 38 | 
            +
                    unless RUBY_ENGINE == 'opal'
         | 
| 39 | 
            +
                      require 'nokogumbo'
         | 
| 40 | 
            +
                      page = 'https://facebook.github.io/react/docs/tags-and-attributes.html'
         | 
| 41 | 
            +
                      doc = Nokogiri::HTML5.get(page)
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                      # delete contents of page prior to the list of supported attributes
         | 
| 44 | 
            +
                      attrs = doc.at('a[name=supported-attributes]')
         | 
| 45 | 
            +
                      attrs = attrs.parent while attrs and not attrs.name.start_with? 'h'
         | 
| 46 | 
            +
                      attrs.previous_sibling.remove while attrs and attrs.previous_sibling
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                      # extract attribute names with uppercase chars from code and format
         | 
| 49 | 
            +
                      attrs = doc.search('code').map(&:text).join(' ')
         | 
| 50 | 
            +
                      attrs = attrs.split(/\s+/).grep(/[A-Z]/).sort.uniq.join(' ')
         | 
| 51 | 
            +
                      puts "ReactAttrs = %w(#{attrs})".gsub(/(.{1,72})(\s+|\Z)/, "\\1\n")
         | 
| 52 | 
            +
                    end
         | 
| 44 53 | 
             
                  end
         | 
| 45 54 |  | 
| 46 55 | 
             
                  # list of react attributes that require special processing
         | 
| @@ -60,8 +69,13 @@ module Ruby2JS | |
| 60 69 | 
             
                  xlinkActuate xlinkArcrole xlinkHref xlinkRole xlinkShow xlinkTitle
         | 
| 61 70 | 
             
                  xlinkType xmlBase xmlLang xmlSpace)
         | 
| 62 71 |  | 
| 72 | 
            +
                  ReactLifecycle = %w(render componentDidMount shouldComponentUpdate
         | 
| 73 | 
            +
                  getShapshotBeforeUpdate componentDidUpdate componentWillUnmount
         | 
| 74 | 
            +
                  componentDidCatch)
         | 
| 75 | 
            +
             | 
| 63 76 | 
             
                  ReactAttrMap = Hash[ReactAttrs.map {|name| [name.downcase, name]}]
         | 
| 64 77 | 
             
                  ReactAttrMap['for'] = 'htmlFor'
         | 
| 78 | 
            +
                  ReactFragment = :'_React.Fragment'
         | 
| 65 79 |  | 
| 66 80 | 
             
                  def initialize(*args)
         | 
| 67 81 | 
             
                    @react = nil
         | 
| @@ -71,6 +85,7 @@ module Ruby2JS | |
| 71 85 | 
             
                    @react_props = []
         | 
| 72 86 | 
             
                    @react_methods = []
         | 
| 73 87 | 
             
                    @react_filter_functions = false
         | 
| 88 | 
            +
                    @react_imports = false
         | 
| 74 89 | 
             
                    @jsx = false
         | 
| 75 90 | 
             
                    super
         | 
| 76 91 | 
             
                  end
         | 
| @@ -88,8 +103,17 @@ module Ruby2JS | |
| 88 103 | 
             
                    end
         | 
| 89 104 |  | 
| 90 105 | 
             
                    if \
         | 
| 91 | 
            -
                      defined? Ruby2JS::Filter:: | 
| 92 | 
            -
                      filters.include? Ruby2JS::Filter:: | 
| 106 | 
            +
                      (defined? Ruby2JS::Filter::ESM and
         | 
| 107 | 
            +
                      filters.include? Ruby2JS::Filter::ESM) or
         | 
| 108 | 
            +
                      (defined? Ruby2JS::Filter::CJS and
         | 
| 109 | 
            +
                      filters.include? Ruby2JS::Filter::CJS)
         | 
| 110 | 
            +
                    then
         | 
| 111 | 
            +
                      @react_imports = true
         | 
| 112 | 
            +
                    end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                    if \
         | 
| 115 | 
            +
                      defined? Ruby2JS::Filter::JSX and
         | 
| 116 | 
            +
                      filters.include? Ruby2JS::Filter::JSX
         | 
| 93 117 | 
             
                    then
         | 
| 94 118 | 
             
                      @jsx = true
         | 
| 95 119 | 
             
                    end
         | 
| @@ -106,8 +130,11 @@ module Ruby2JS | |
| 106 130 | 
             
                    return super unless cname.children.first == nil
         | 
| 107 131 | 
             
                    return super unless inheritance == s(:const, nil, :React) or
         | 
| 108 132 | 
             
                      inheritance == s(:const, nil, :Vue) or
         | 
| 133 | 
            +
                      inheritance == s(:const, s(:const, nil, :React), :Component) or
         | 
| 109 134 | 
             
                      inheritance == s(:send, s(:const, nil, :React), :Component)
         | 
| 110 135 |  | 
| 136 | 
            +
                    prepend_list << REACT_IMPORTS[:React] if @react_imports
         | 
| 137 | 
            +
             | 
| 111 138 | 
             
                    # traverse down to actual list of class statements
         | 
| 112 139 | 
             
                    if body.length == 1
         | 
| 113 140 | 
             
                      if not body.first
         | 
| @@ -156,24 +183,46 @@ module Ruby2JS | |
| 156 183 | 
             
                        end
         | 
| 157 184 | 
             
                      end
         | 
| 158 185 |  | 
| 159 | 
            -
             | 
| 186 | 
            +
                      # collect instance methods (including getters and setters)
         | 
| 160 187 | 
             
                      @react_props = []
         | 
| 161 188 | 
             
                      @react_methods = []
         | 
| 162 | 
            -
             | 
| 163 | 
            -
             | 
| 164 | 
            -
             | 
| 165 | 
            -
             | 
| 166 | 
            -
             | 
| 167 | 
            -
             | 
| 168 | 
            -
             | 
| 169 | 
            -
             | 
| 170 | 
            -
             | 
| 171 | 
            -
             | 
| 172 | 
            -
             | 
| 173 | 
            -
             | 
| 174 | 
            -
             | 
| 175 | 
            -
             | 
| 176 | 
            -
             | 
| 189 | 
            +
                      body.each do |statement|
         | 
| 190 | 
            +
                        if statement.type == :def
         | 
| 191 | 
            +
                          method = statement.children.first
         | 
| 192 | 
            +
                          unless method == :initialize
         | 
| 193 | 
            +
                            if method.to_s.end_with? '='
         | 
| 194 | 
            +
                              method = method.to_s[0..-2].to_sym
         | 
| 195 | 
            +
                              @react_props << method unless @react_props.include? method
         | 
| 196 | 
            +
                            elsif statement.is_method?
         | 
| 197 | 
            +
                              @react_methods << method unless @react_methods.include? method
         | 
| 198 | 
            +
                            else
         | 
| 199 | 
            +
                              @react_props << method unless @react_props.include? method
         | 
| 200 | 
            +
                            end
         | 
| 201 | 
            +
                          end
         | 
| 202 | 
            +
                        end
         | 
| 203 | 
            +
                      end
         | 
| 204 | 
            +
             | 
| 205 | 
            +
                      # determine which instance methods need binding
         | 
| 206 | 
            +
                      needs_binding = []
         | 
| 207 | 
            +
                      scan_events = lambda do |list|
         | 
| 208 | 
            +
                        list.each do |node|
         | 
| 209 | 
            +
                          next unless Parser::AST::Node === node
         | 
| 210 | 
            +
                          node = process node if node.type == :xstr
         | 
| 211 | 
            +
                          if node.type == :hash
         | 
| 212 | 
            +
                            node.children.each do |pair|
         | 
| 213 | 
            +
                              value = pair.children.last
         | 
| 214 | 
            +
                              if value.type == :send and \
         | 
| 215 | 
            +
                                @react_methods.include? value.children[1] and \
         | 
| 216 | 
            +
                                [nil, s(:self), s(:send, nil, :this)].include? value.children[0]
         | 
| 217 | 
            +
             | 
| 218 | 
            +
                                needs_binding << value.children[1]
         | 
| 219 | 
            +
                              end
         | 
| 220 | 
            +
                            end
         | 
| 221 | 
            +
                          end
         | 
| 222 | 
            +
                          scan_events[node.children]
         | 
| 223 | 
            +
                        end
         | 
| 224 | 
            +
                      end
         | 
| 225 | 
            +
                      scan_events[body] unless es2015
         | 
| 177 226 |  | 
| 178 227 | 
             
                      # append statics (if any)
         | 
| 179 228 | 
             
                      unless statics.empty?
         | 
| @@ -181,9 +230,9 @@ module Ruby2JS | |
| 181 230 | 
             
                      end
         | 
| 182 231 |  | 
| 183 232 | 
             
                      # create a default getInitialState method if there is no such method
         | 
| 184 | 
            -
                      # and there are references to instance variables | 
| 233 | 
            +
                      # and there are either references to instance variables or there are
         | 
| 234 | 
            +
                      # methods that need to be bound.
         | 
| 185 235 | 
             
                      if \
         | 
| 186 | 
            -
                        not es2015 and
         | 
| 187 236 | 
             
                        not body.any? do |child|
         | 
| 188 237 | 
             
                          child.type == :def and
         | 
| 189 238 | 
             
                          [:getInitialState, :initialize].include? child.children.first
         | 
| @@ -191,9 +240,11 @@ module Ruby2JS | |
| 191 240 | 
             
                      then
         | 
| 192 241 | 
             
                        @reactIvars = {pre: [], post: [], asgn: [], ref: [], cond: []}
         | 
| 193 242 | 
             
                        react_walk(node)
         | 
| 194 | 
            -
                         | 
| 243 | 
            +
                        if not es2015 and not @reactIvars.values.flatten.empty?
         | 
| 195 244 | 
             
                          body = [s(:def, :getInitialState, s(:args),
         | 
| 196 245 | 
             
                            s(:return, s(:hash))), *body]
         | 
| 246 | 
            +
                        elsif not needs_binding.empty? or not @reactIvars.values.flatten.empty?
         | 
| 247 | 
            +
                          body = [s(:def, :initialize, s(:args)), *body]
         | 
| 197 248 | 
             
                        end
         | 
| 198 249 | 
             
                      end
         | 
| 199 250 |  | 
| @@ -221,9 +272,22 @@ module Ruby2JS | |
| 221 272 | 
             
                            end
         | 
| 222 273 | 
             
                          end
         | 
| 223 274 |  | 
| 275 | 
            +
                          # add props argument if there is a reference to a prop
         | 
| 276 | 
            +
                          if args.children.length == 0
         | 
| 277 | 
            +
                            has_cvar = lambda {|list|
         | 
| 278 | 
            +
                              list.any? {|node|
         | 
| 279 | 
            +
                                next unless Parser::AST::Node === node
         | 
| 280 | 
            +
                                return true if node.type == :cvar
         | 
| 281 | 
            +
                                has_cvar.call(node.children)
         | 
| 282 | 
            +
                              }
         | 
| 283 | 
            +
                            }
         | 
| 284 | 
            +
                            args = s(:args, s(:arg, 'prop$')) if has_cvar[block]
         | 
| 285 | 
            +
                          end
         | 
| 286 | 
            +
             | 
| 224 287 | 
             
                          # peel off the initial set of instance variable assignment stmts
         | 
| 225 288 | 
             
                          assigns = []
         | 
| 226 289 | 
             
                          block = block.dup
         | 
| 290 | 
            +
                          block.shift if block.first == s(:zsuper)
         | 
| 227 291 | 
             
                          while not block.empty? and block.first.type == :ivasgn
         | 
| 228 292 | 
             
                            node = block.shift
         | 
| 229 293 | 
             
                            vars = [node.children.first]
         | 
| @@ -240,9 +304,15 @@ module Ruby2JS | |
| 240 304 | 
             
                          state = s(:hash, *assigns.map {|anode| s(:pair, s(:str,
         | 
| 241 305 | 
             
                            anode.children.first.to_s[1..-1]), anode.children.last)})
         | 
| 242 306 |  | 
| 307 | 
            +
                          # bind methods as needed
         | 
| 308 | 
            +
                          needs_binding.each do |method|
         | 
| 309 | 
            +
                            block.push(s(:send, s(:self), "#{method}=",
         | 
| 310 | 
            +
                              s(:send, s(:attr, s(:self), method), :bind, s(:self))))
         | 
| 311 | 
            +
                          end
         | 
| 312 | 
            +
             | 
| 243 313 | 
             
                          # modify block to build and/or return state
         | 
| 244 314 | 
             
                          if mname == :initialize
         | 
| 245 | 
            -
                            block.unshift(s(:send, s(:self), :state=, state))
         | 
| 315 | 
            +
                            block.unshift(s(:zsuper), s(:send, s(:self), :state=, state))
         | 
| 246 316 | 
             
                          elsif block.empty?
         | 
| 247 317 | 
             
                            block = [s(:return, state)]
         | 
| 248 318 | 
             
                          else
         | 
| @@ -250,10 +320,10 @@ module Ruby2JS | |
| 250 320 | 
             
                            block.push(s(:return, s(:attr, s(:self), :state)))
         | 
| 251 321 | 
             
                          end
         | 
| 252 322 |  | 
| 253 | 
            -
                        elsif mname == :render
         | 
| 323 | 
            +
                        elsif mname == :render and not react_wunderbar_free(block, true)
         | 
| 254 324 | 
             
                          if \
         | 
| 255 325 | 
             
                             block.length != 1 or not block.last or
         | 
| 256 | 
            -
                            not [ | 
| 326 | 
            +
                            not %i[send block xstr].include? block.last.type
         | 
| 257 327 | 
             
                          then
         | 
| 258 328 | 
             
                            if @jsx
         | 
| 259 329 | 
             
                              while block.length == 1 and block.first.type == :begin
         | 
| @@ -271,9 +341,9 @@ module Ruby2JS | |
| 271 341 | 
             
                              block = [*prolog, s(:return,
         | 
| 272 342 | 
             
                                s(:xnode, '', *process_all(block)))]
         | 
| 273 343 | 
             
                            else
         | 
| 274 | 
            -
                              # wrap multi-line blocks with a  | 
| 344 | 
            +
                              # wrap multi-line blocks with a React Fragment
         | 
| 275 345 | 
             
                              block = [s(:return,
         | 
| 276 | 
            -
                                s(:block, s(:send, nil,  | 
| 346 | 
            +
                                s(:block, s(:send, nil, ReactFragment), s(:args), *block))]
         | 
| 277 347 | 
             
                            end
         | 
| 278 348 | 
             
                          end
         | 
| 279 349 |  | 
| @@ -300,7 +370,10 @@ module Ruby2JS | |
| 300 370 | 
             
                        end
         | 
| 301 371 |  | 
| 302 372 | 
             
                        if es2015
         | 
| 303 | 
            -
                          pairs <<  | 
| 373 | 
            +
                          pairs << child.updated(
         | 
| 374 | 
            +
                            ReactLifecycle.include?(mname.to_s) ? :defm : :def, 
         | 
| 375 | 
            +
                            [mname, args, process(s(type, *block))]
         | 
| 376 | 
            +
                          )
         | 
| 304 377 | 
             
                        else
         | 
| 305 378 | 
             
                          pairs << s(:pair, s(:sym, mname), child.updated(:block,
         | 
| 306 379 | 
             
                            [s(:send, nil, :proc), args, process(s(type, *block))]))
         | 
| @@ -369,8 +442,12 @@ module Ruby2JS | |
| 369 442 | 
             
                      # enable React filtering within React class method calls or
         | 
| 370 443 | 
             
                      # React component calls
         | 
| 371 444 | 
             
                      if \
         | 
| 372 | 
            -
                        node.children.first == s(:const, nil, :React)
         | 
| 445 | 
            +
                        node.children.first == s(:const, nil, :React) or
         | 
| 446 | 
            +
                        node.children.first == s(:const, nil, :ReactDOM)
         | 
| 373 447 | 
             
                      then
         | 
| 448 | 
            +
                        if @react_imports
         | 
| 449 | 
            +
                          prepend_list << REACT_IMPORTS[node.children.first.children.last]
         | 
| 450 | 
            +
                        end
         | 
| 374 451 |  | 
| 375 452 | 
             
                        begin
         | 
| 376 453 | 
             
                          react, @react = @react, true
         | 
| @@ -429,6 +506,10 @@ module Ruby2JS | |
| 429 506 | 
             
                          # :block arguments are inserted by on_block logic below
         | 
| 430 507 | 
             
                          block = child
         | 
| 431 508 |  | 
| 509 | 
            +
                        elsif child.type == :splat
         | 
| 510 | 
            +
                          # arrays need not be expanded
         | 
| 511 | 
            +
                          text = child.children.first
         | 
| 512 | 
            +
             | 
| 432 513 | 
             
                        else
         | 
| 433 514 | 
             
                          # everything else added as text
         | 
| 434 515 | 
             
                          text = child
         | 
| @@ -586,6 +667,9 @@ module Ruby2JS | |
| 586 667 | 
             
                          next true if arg.children[1] == :createElement and
         | 
| 587 668 | 
             
                            arg.children[0] == s(:const, nil, :Vue)
         | 
| 588 669 |  | 
| 670 | 
            +
                          # JSX
         | 
| 671 | 
            +
                          next true if arg.type == :xstr
         | 
| 672 | 
            +
             | 
| 589 673 | 
             
                          # wunderbar style call
         | 
| 590 674 | 
             
                          arg = arg.children.first if arg.type == :block
         | 
| 591 675 | 
             
                          while arg.type == :send and arg.children.first != nil
         | 
| @@ -598,7 +682,19 @@ module Ruby2JS | |
| 598 682 | 
             
                          if simple
         | 
| 599 683 | 
             
                            # in the normal case, process each argument
         | 
| 600 684 | 
             
                            reactApply, @reactApply = @reactApply, false
         | 
| 601 | 
            -
                             | 
| 685 | 
            +
                            args.each do |arg|
         | 
| 686 | 
            +
                              arg = process(arg)
         | 
| 687 | 
            +
                              if arg.type == :send and 
         | 
| 688 | 
            +
                                arg.children[0] == s(:const, nil, :React) and
         | 
| 689 | 
            +
                                arg.children[1] == :createElement and
         | 
| 690 | 
            +
                                arg.children[2] == s(:const, nil, "React.Fragment") and
         | 
| 691 | 
            +
                                arg.children[3] == s(:nil) 
         | 
| 692 | 
            +
                              then
         | 
| 693 | 
            +
                                params += arg.children[4..-1]
         | 
| 694 | 
            +
                              else
         | 
| 695 | 
            +
                                params << arg
         | 
| 696 | 
            +
                              end
         | 
| 697 | 
            +
                            end
         | 
| 602 698 | 
             
                          else
         | 
| 603 699 | 
             
                            reactApply, @reactApply = @reactApply, true
         | 
| 604 700 |  | 
| @@ -860,7 +956,15 @@ module Ruby2JS | |
| 860 956 | 
             
                    end
         | 
| 861 957 |  | 
| 862 958 | 
             
                    # wunderbar style calls
         | 
| 863 | 
            -
                    if  | 
| 959 | 
            +
                    if child.children[0] == nil and child.children[1] == :_ and \
         | 
| 960 | 
            +
                      node.children[1].children.empty? and !@jsx
         | 
| 961 | 
            +
             | 
| 962 | 
            +
                      block = s(:block, s(:send, nil, :proc), s(:args),
         | 
| 963 | 
            +
                        *node.children[2..-1])
         | 
| 964 | 
            +
                      return on_send node.children.first.updated(:send,
         | 
| 965 | 
            +
                        [nil, ReactFragment, block])
         | 
| 966 | 
            +
             | 
| 967 | 
            +
                    elsif !@jsx and child.children[0] == nil and child.children[1] =~ /^_\w/
         | 
| 864 968 | 
             
                      if node.children[1].children.empty?
         | 
| 865 969 | 
             
                        # append block as a standalone proc
         | 
| 866 970 | 
             
                        block = s(:block, s(:send, nil, :proc), s(:args),
         | 
| @@ -871,9 +975,18 @@ module Ruby2JS | |
| 871 975 | 
             
                        # iterate over Enumerable arguments if there are args present
         | 
| 872 976 | 
             
                        send = node.children.first.children
         | 
| 873 977 | 
             
                        return super if send.length < 3
         | 
| 874 | 
            -
                         | 
| 875 | 
            -
                           | 
| 876 | 
            -
                           | 
| 978 | 
            +
                        if node.children.length == 3 and
         | 
| 979 | 
            +
                          node.children.last.respond_to? :type and
         | 
| 980 | 
            +
                          node.children.last.type == :send
         | 
| 981 | 
            +
             | 
| 982 | 
            +
                          return process s(:send, *send[0..1], *send[3..-1],
         | 
| 983 | 
            +
                            s(:splat, s(:block, s(:send, send[2], :map),
         | 
| 984 | 
            +
                            node.children[1], s(:return, node.children[2]))))
         | 
| 985 | 
            +
                        else
         | 
| 986 | 
            +
                          return process s(:block, s(:send, *send[0..1], *send[3..-1]),
         | 
| 987 | 
            +
                            s(:args), s(:block, s(:send, send[2], :forEach),
         | 
| 988 | 
            +
                            *node.children[1..-1]))
         | 
| 989 | 
            +
                        end
         | 
| 877 990 | 
             
                      end
         | 
| 878 991 | 
             
                    end
         | 
| 879 992 |  | 
| @@ -885,6 +998,13 @@ module Ruby2JS | |
| 885 998 | 
             
                    end
         | 
| 886 999 | 
             
                  end
         | 
| 887 1000 |  | 
| 1001 | 
            +
                  def on_lvasgn(node)
         | 
| 1002 | 
            +
                    return super unless @reactClass
         | 
| 1003 | 
            +
                    return super unless @react_props.include? node.children.first
         | 
| 1004 | 
            +
                    node.updated(:send, [s(:self), "#{node.children.first}=",
         | 
| 1005 | 
            +
                      node.children.last])
         | 
| 1006 | 
            +
                  end
         | 
| 1007 | 
            +
             | 
| 888 1008 | 
             
                  # convert global variables to refs
         | 
| 889 1009 | 
             
                  def on_gvar(node)
         | 
| 890 1010 | 
             
                    return super unless @reactClass
         | 
| @@ -993,7 +1113,7 @@ module Ruby2JS | |
| 993 1113 | 
             
                  end
         | 
| 994 1114 |  | 
| 995 1115 | 
             
                  # is this a "wunderbar" style call or createElement?
         | 
| 996 | 
            -
                  def react_element?(node)
         | 
| 1116 | 
            +
                  def react_element?(node, wunderbar_only=false)
         | 
| 997 1117 | 
             
                    return false unless node
         | 
| 998 1118 |  | 
| 999 1119 | 
             
                    forEach = [:forEach]
         | 
| @@ -1001,15 +1121,17 @@ module Ruby2JS | |
| 1001 1121 |  | 
| 1002 1122 | 
             
                    return true if node.type == :block and
         | 
| 1003 1123 | 
             
                      forEach.include? node.children.first.children.last and 
         | 
| 1004 | 
            -
                      react_element?(node.children.last)
         | 
| 1124 | 
            +
                      react_element?(node.children.last, wunderbar_only)
         | 
| 1005 1125 |  | 
| 1006 | 
            -
                     | 
| 1007 | 
            -
             | 
| 1008 | 
            -
                      node.children[ | 
| 1126 | 
            +
                    unless wunderbar_only
         | 
| 1127 | 
            +
                      # explicit call to React.createElement
         | 
| 1128 | 
            +
                      return true if node.children[1] == :createElement and
         | 
| 1129 | 
            +
                        node.children[0] == s(:const, nil, :React)
         | 
| 1009 1130 |  | 
| 1010 | 
            -
             | 
| 1011 | 
            -
             | 
| 1012 | 
            -
             | 
| 1131 | 
            +
                      # explicit call to Vue.createElement
         | 
| 1132 | 
            +
                      return true if node.children[1] == :createElement and
         | 
| 1133 | 
            +
                        node.children[0] == s(:const, nil, :Vue)
         | 
| 1134 | 
            +
                    end
         | 
| 1013 1135 |  | 
| 1014 1136 | 
             
                    # wunderbar style call
         | 
| 1015 1137 | 
             
                    node = node.children.first if node.type == :block
         | 
| @@ -1021,13 +1143,14 @@ module Ruby2JS | |
| 1021 1143 |  | 
| 1022 1144 | 
             
                  # ensure that there are no "wunderbar" or "createElement" calls in
         | 
| 1023 1145 | 
             
                  # a set of statements.
         | 
| 1024 | 
            -
                  def react_wunderbar_free(nodes)
         | 
| 1146 | 
            +
                  def react_wunderbar_free(nodes, wunderbar_only=false)
         | 
| 1025 1147 | 
             
                    nodes.each do |node|
         | 
| 1026 1148 | 
             
                      if Parser::AST::Node === node
         | 
| 1027 | 
            -
                        return false if  | 
| 1149 | 
            +
                        return false if node.type == :xstr
         | 
| 1150 | 
            +
                        return false if react_element?(node, wunderbar_only)
         | 
| 1028 1151 |  | 
| 1029 1152 | 
             
                        # recurse
         | 
| 1030 | 
            -
                        return false unless react_wunderbar_free(node.children)
         | 
| 1153 | 
            +
                        return false unless react_wunderbar_free(node.children, wunderbar_only)
         | 
| 1031 1154 | 
             
                      end
         | 
| 1032 1155 | 
             
                    end
         | 
| 1033 1156 |  | 
| @@ -1181,6 +1304,18 @@ module Ruby2JS | |
| 1181 1304 |  | 
| 1182 1305 | 
             
                    block
         | 
| 1183 1306 | 
             
                  end
         | 
| 1307 | 
            +
             | 
| 1308 | 
            +
                  def on_xstr(node)
         | 
| 1309 | 
            +
                   loc = node.loc
         | 
| 1310 | 
            +
                   return super unless loc
         | 
| 1311 | 
            +
                   source = loc.begin.source_buffer.source
         | 
| 1312 | 
            +
                   source = source[loc.begin.end_pos...loc.end.begin_pos].strip
         | 
| 1313 | 
            +
                   return super unless @reactClass or source.start_with? '<'
         | 
| 1314 | 
            +
                   source = Ruby2JS.jsx2_rb(source)
         | 
| 1315 | 
            +
                   ast =  Ruby2JS.parse(source).first
         | 
| 1316 | 
            +
                   ast = s(:block, s(:send, nil, :_), s(:args), ast) if ast.type == :begin
         | 
| 1317 | 
            +
                   process ast
         | 
| 1318 | 
            +
                  end
         | 
| 1184 1319 | 
             
                end
         | 
| 1185 1320 |  | 
| 1186 1321 | 
             
                DEFAULTS.push React
         |