@@ -1,29 +1,9 @@
# config/initializers/source_maps.rb
if Rails . env . development?
require 'open3'
module CoffeeScript
class SourceMapError < StandardError ; end ;
class << self
def map_dir
return @map_dir if @map_dir
# Make the directory the maps are served from
@map_dir = Rails . root . join ( "public/source_maps" )
@map_dir . mkpath
@map_dir
end
def check_coffeescript_version
version = `coffee --version`
unless version . match ( /(\d +)\. \d +\. / ) [ 1 ] . to_i >= 2
raise "You must have coffeescript version 2.0.0-dev or higher to use source maps - see http://ryanflorence.com/2012/coffeescript-source-maps/"
end
end
def compile script , options
script = script . read if script . respond_to? ( :read )
@@ -32,59 +12,32 @@ def compile script, options
else
options [ :bare ] = false
end
check_coffeescript_version
compile_with_source_map script , options
end
def compile_with_source_map script , options
flags = %w( --js )
flags << "--bare" if options [ :bare ]
javascript , stderr , status = Open3 . capture3 ( "coffee #{ flags . join ( ' ' ) } " , stdin_data : script )
# adding source mapss option. (source maps option requires filename option.)
options [ :sourceMap ] = true
options [ :filename ] = options [ :pathname ] . basename . to_s
raise SourceMapError , stderr unless status . success?
ret = Source . context . call ( "CoffeeScript.compile" , script , options )
source_map_comment = generate_source_map options [ :pathname ] , script if options [ :pathname ]
map_dir = Rails . root . join ( "public/source_maps" )
map_dir . mkpath
return javascript << source_map_comment
basename = options [ :pathname ] . basename ( '.coffee' )
map_file = map_dir . join "#{ basename } .map"
coffee_file = map_dir . join "#{ basename } .coffee"
# patch the generated source map with the otherwise missing filename
source_map = JSON . load ( ret [ "v3SourceMap" ] )
source_map [ "sources" ] [ 0 ] = options [ :filename ]
rescue SourceMapError => e
message = e . message . lines . first . chomp . gsub ( '"' , '\"' )
relative_path_name = options [ :pathname ] . to_s . gsub ( Rails . root . to_s , '' ) if options [ :pathname ]
relative_path_name ||= '<unknown path>'
%Q{throw Error("Coffeescript compile error: #{ relative_path_name } : #{ message } ")}
end
def generate_source_map pathname , script
basename = pathname . basename ( '.coffee' )
coffee_file = map_dir . join ( "#{ basename } .coffee" )
coffee_file . open ( 'w' ) { |f | f . puts script }
map_file . open ( 'w' ) { |f | f . puts source_map . to_json }
# This command actually generates the source map, and saves it to a file
source_map , status = nil
Dir . chdir Rails . root . join ( 'public/source_maps' ) . to_s do
source_map , stderr , status = Open3 . capture3 ( "coffee --source-map -i #{ pathname . basename } " )
end
comment = "//@ sourceMappingURL=/source_maps/#{ map_file . basename } \n "
return comment + ret [ "js" ]
raise SourceMapError , "Error while generating source map for file #{ pathname } : #{ stderr } " unless status . success?
# I couldn't figure out how to control the 'file' and 'sources' values in the output,
# so parse the map to JSON and rewrite these to ones that will work here
data = JSON . parse ( source_map )
data [ 'file' ] = pathname . basename . to_s . gsub ( /\. coffee/ , '' )
data [ 'sources' ] = [ pathname . basename . to_s ]
map_file = map_dir . join "#{ basename } .map"
map_file . open ( 'w' ) { |f | f . puts data . to_json }
Rails . logger . info "Compiled source map #{ map_file } "
return "\n //@ sourceMappingURL=/source_maps/#{ map_file . basename } \n "
end
end
end
@@ -96,8 +49,8 @@ def generate_source_map pathname, script
module Tilt
class CoffeeScriptTemplate < Template
def evaluate ( scope , locals , &block )
@output ||= CoffeeScript . compile ( data , options . merge ( pathname : scope . pathname ) )
@output ||= CoffeeScript . compile ( data , options . merge ( :pathname => scope . pathname ) )
end
end
end
end
end