Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

193 lines (163 sloc) 5.83 kB
require 'digest/sha2'
module Barista
class Compiler
UNAVAILABLE_MESSAGE = "No method of compiling coffee-script is currently available. Please see the ExecJS page (https://github.com/sstephenson/execjs) for details on how to set one up."
# TODO: Deprecate.
class << self
def js_path
CoffeeScript::Source.path
end
def js_path=(value)
CoffeeScript::Source.path = value
end
def bin_path
execjs_runtime_call :binary
end
def bin_path=(path)
execjs_runtime_call :binary=, path
end
def execjs_runtime_call(method, *args)
runtime = ExecJS.runtime
if runtime.respond_to?(method, true)
runtime.send method, *args
else
nil
end
end
def available?
ExecJS.runtime and ExecJS.runtime.available?
end
def check_availability!(silence = false)
available = available?
if !available && Barista.exception_on_error? && !silence
raise CompilerUnavailableError, UNAVAILABLE_MESSAGE
end
available
end
def compile(content, options = {})
self.new(content, options).to_js
end
def autocompile_file(file, force = false, silence_error = false)
# Expand the path from the framework.
origin_path, framework = Framework.full_path_for(file)
return if origin_path.nil?
destination_path = framework.output_path_for(file)
# read file directly if auto_compile is disabled
if !Barista.auto_compile?
if File.exist?(destination_path)
return File.read(destination_path)
else
return nil
end
end
return File.read(destination_path) unless dirty?(origin_path, destination_path) || force
# Ensure we have a coffeescript compiler available.
if !check_availability!(silence_error)
Barista.debug UNAVAILABLE_MESSAGE
return nil
end
Barista.debug "Compiling #{file} from framework '#{framework.name}'"
compiler = new(origin_path, :silence_error => silence_error, :output_path => destination_path)
content = compiler.to_js
compiler.save
content
end
def compile_as(file, type)
origin_path, framework = Framework.full_path_for(file)
return if origin_path.nil?
if type == :coffeescript
return File.read(origin_path), File.mtime(origin_path)
else
return autocompile_file(file), Time.now
end
end
def dirty?(from, to)
File.exist?(from) && (!File.exist?(to) || File.mtime(to) < File.mtime(from))
end
def setup_default_error_logger
Barista.on_compilation_error do |where, message|
if Barista.verbose?
Barista.debug "There was an error compiling coffeescript from #{where}:"
message.each_line { |line| Barista.debug line.rstrip }
end
end
end
end
def initialize(context, options = {})
@compiled = false
@options = options
setup_compiler_context context
end
def compile!
location = @options.fetch(:origin, 'inline')
@compiled_content = compile(@context, location)
@compiled_content = preamble(location) + @compiled_content if location != 'inline' && Barista.add_preamble?
@compiled = true
end
def to_js
compile! unless defined?(@compiled) && @compiled
@compiled_content
end
def copyable?(location)
location != 'inline' && File.extname(location) == '.js'
end
def compile(script, where = 'inline')
if copyable?(where)
out = script
else
Barista.invoke_hook :before_compilation, where
out = CoffeeScript.compile script, :bare => Barista.bare?
Barista.invoke_hook :compiled, where
end
out
rescue ExecJS::Error => e
Barista.invoke_hook :compilation_failed, where, e.message
if Barista.exception_on_error? && !@options[:silence]
if e.is_a?(ExecJS::ProgramError)
where_within_app = where.sub(/#{Regexp.escape(Barista.app_root.to_s)}\/?/, '')
raise CompilationError, "Error: In #{where_within_app}, #{e.message}"
else
raise CompilationError, "CoffeeScript encountered an error compiling #{where}: #{e.message}"
end
end
compilation_error_for where, e.message
end
def save(path = @options[:output_path])
return false unless path.is_a?(String) && !to_js.nil?
FileUtils.mkdir_p File.dirname(path)
File.open(path, "w+") { |f| f.write @compiled_content }
true
rescue Errno::EACCES
false
end
protected
def preamble(location)
inner_message = copyable?(location) ? "copied" : "compiled"
if Barista.preamble
Barista.preamble.call(location)
else
"/* DO NOT MODIFY. This file was #{inner_message} #{Time.now.httpdate} from\n * #{location.strip}\n */\n\n"
end
end
def compilation_error_for(location, message)
details = "Compilation of '#{location}' failed:\n#{message}"
Barista.verbose? ? "alert(#{details.to_json});" : nil
end
def setup_compiler_context(context)
if context.respond_to?(:read)
@context = context.read
@type = :string
default_path = context.respond_to?(:path) ? context.path : 'inline'
@options[:origin] ||= default_path
elsif !context.include?("\n") && File.exist?(context)
@context = File.read(context)
@type = :file
@options[:origin] ||= context
else
@context = context.to_s
@type = :string
@options[:origin] ||= 'inline'
end
end
end
end
Jump to Line
Something went wrong with that request. Please try again.