lib/execjs/external_runtime.rb in execjs-2.3.0 vs lib/execjs/external_runtime.rb in execjs-2.4.0

- old
+ new

@@ -22,16 +22,16 @@ end end def exec(source, options = {}) source = encode(source) - source = "#{@source}\n#{source}" if @source + source = "#{@source}\n#{source}" if @source != "" source = @runtime.compile_source(source) tmpfile = write_to_tempfile(source) begin - extract_result(@runtime.exec_runtime(tmpfile.path)) + extract_result(@runtime.exec_runtime(tmpfile.path), tmpfile.path) ensure File.unlink(tmpfile) end end @@ -55,18 +55,29 @@ tmpfile.write(contents) tmpfile.close tmpfile end - def extract_result(output) - status, value = output.empty? ? [] : ::JSON.parse(output, create_additions: false) + def extract_result(output, filename) + status, value, stack = output.empty? ? [] : ::JSON.parse(output, create_additions: false) if status == "ok" value - elsif value =~ /SyntaxError:/ - raise RuntimeError, value else - raise ProgramError, value + stack ||= "" + real_filename = File.realpath(filename) + stack = stack.split("\n").map do |line| + line.sub(" at ", "") + .sub(real_filename, "(execjs)") + .sub(filename, "(execjs)") + .strip + end + stack.reject! { |line| ["eval code", "eval@[native code]"].include?(line) } + stack.shift unless stack[0].to_s.include?("(execjs)") + error_class = value =~ /SyntaxError:/ ? RuntimeError : ProgramError + error = error_class.new(value) + error.set_backtrace(stack + caller) + raise error end end end attr_reader :name @@ -156,11 +167,11 @@ end if $?.success? output else - raise RuntimeError, output + raise exec_runtime_error(output) end end def shell_escape(*args) # see http://technet.microsoft.com/en-us/library/cc723564.aspx#XSLTsection123121120120 @@ -179,11 +190,11 @@ io.close if $?.success? output else - raise RuntimeError, output + raise exec_runtime_error(output) end end else def exec_runtime(filename) io = IO.popen(binary.split(' ') << filename, @popen_options.merge({err: [:child, :out]})) @@ -191,15 +202,24 @@ io.close if $?.success? output else - raise RuntimeError, output + raise exec_runtime_error(output) end end end # Internally exposed for Context. public :exec_runtime + + def exec_runtime_error(output) + error = RuntimeError.new(output) + lines = output.split("\n") + lineno = lines[0][/:(\d+)$/, 1] if lines[0] + lineno ||= 1 + error.set_backtrace(["(execjs):#{lineno}"] + caller) + error + end def which(command) Array(command).find do |name| name, args = name.split(/\s+/, 2) path = locate_executable(name)