lib/boojs.rb in boojs-0.0.20 vs lib/boojs.rb in boojs-0.0.21

- old
+ new

@@ -1,35 +1,72 @@ require 'tempfile' require 'securerandom' require 'greenletters' require "net/http" require "uri" +require "open3" +require 'therubyracer' module BooJS def self.verify str - phantom = Phantomjs.path - #Create tmp file tmp = Tempfile.new(SecureRandom.hex) - tmp.puts %{ - phantom.onError = function(msg, trace) { - console.log("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"); - console.log("PhantomJS Error"); - console.log("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"); - console.log(msg); - trace.forEach(function(t) { - console.log(t.file + ': line ' + t.line ); - }) - console.log("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"); - phantom.exit(1); + path = tmp.path + tmp.close! + File.open path, "w" do |f| + f.puts %{ + phantom.onError = function(msg, trace) { + console.log("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"); + console.log("PhantomJS Error"); + console.log("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"); + console.log(msg); + trace.forEach(function(t) { + console.log(t.file + ': line ' + t.line ); + }) + console.log("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"); + phantom.exit(1); + } } - } - tmp.puts str - tmp.puts "phantom.exit(0)" - tmp.close + f.puts str + f.puts "phantom.exit(0)" + end - system("phantomjs #{tmp.path} 2>&1") or raise "Verifying failed" + begin + #Do we have a syntax error? + @syntax_error = false + Timeout.timeout(8) do + Open3.popen3 "#{$phantomjs_path} #{path}" do |_, out, err, _| + begin + loop do + rr, ww = select([out, err], []); e = rr[0] + + #PhantomJS wrote to stderr + r = e.readline + if r =~ /SyntaxError/ + @syntax_error = true + raise "syntax_error" #Break out + end + end + ensure + Process.kill 9, p.pid + end + end + end + rescue => e + end + + #PhantomJS does not support syntax checking, so we use V8 to do that + return 0 unless @syntax_error + begin + ctx = V8::Context.new + ctx.load path + rescue V8::Error => e + matches = e.message.match(/.*? at (?<path>.*?):(?<line>.*?):.*?$/) + dump_lines matches[:path], matches[:line].to_i, 10 + end + + return 1 end #Optionally, accept code to inject and a command to run #If the command is nil, this is not executed as a oneshot def self.pipe(str=nil, cmd=nil, will_timeout=false) @@ -129,28 +166,28 @@ # 3| console.log("hello world"); # 4| console.log("hello world again"]; <-------- [optional msg] # 5| var x = 4; # 6| var y = 3; # ----------------------------------------------- - def dump_lines fn, center_num, n_expand, msg=nil + def self.dump_lines fn, center_num, n_expand, msg=nil f = File.open(fn) range = (center_num-n_expand)..(center_num+n_expand) - puts "------------------------------------------------------------" - puts "#{File.basename(fn)}:#{center_num}" - puts "------------------------------------------------------------" + $stderr.puts "------------------------------------------------------------" + $stderr.puts "#{File.basename(fn)}:#{center_num}" + $stderr.puts "------------------------------------------------------------" f.each_line.with_index do |line, index| line.strip! if range.include? index if index == center_num - puts "#{index}| #{line} <------ " + (msg ? "[#{msg}]" : "") + $stderr.puts "#{index}| #{line} <------ " + (msg ? "[#{msg}]" : "") else - puts "#{index}| #{line}" + $stderr.puts "#{index}| #{line}" end end end - puts "------------------------------------------------------------" + $stderr.puts "------------------------------------------------------------" end end #You can not use stdin readLine from PhantomJS because it blocks. This is a workaround where #commands are queued via the built-in server and then evaluated asynchronously via setInterval. @@ -177,10 +214,10 @@ if (__async_stdin_queue.length == 0) { return; } var str = __async_stdin_queue.pop() - eval(str); + eval.call(window, str); } setInterval(__async_stdin_dequeue, 50); } end end