sources = {}diff --git a/docs/v1/annotated-source/coffee-script.html b/docs/v1/annotated-source/coffee-script.html index 9c498ae5c0..99a4d22ab0 100644 --- a/docs/v1/annotated-source/coffee-script.html +++ b/docs/v1/annotated-source/coffee-script.html @@ -249,34 +249,88 @@
For each compiled file, save its source in memory in case we need to
+recompile it later. We might need to recompile if the first compilation
+didn’t create a source map (faster) but something went wrong and we need
+a stack trace. Assuming that most of the time, code isn’t throwing
+exceptions, it’s probably more efficient to compile twice only when we
+need a stack trace, rather than always generating a source map even when
+it’s not likely to be used. Save in form of filename: (source)
sources = {}Also save source maps if generated, in form of filename: (source map).
sourceMaps = {}Compile CoffeeScript code to JavaScript, using the Coffee/Jison compiler.
-If options.sourceMap is specified, then options.filename must also be specified. All
-options that can be passed to SourceMap#generate may also be passed here.
If options.sourceMap is specified, then options.filename must also be
+specified. All options that can be passed to SourceMap#generate may also
+be passed here.
This returns a javascript string, unless options.sourceMap is passed,
in which case this returns a {js, v3SourceMap, sourceMap}
-object, where sourceMap is a sourcemap.coffee#SourceMap object, handy for doing programatic
-lookups.
exports.compile = compile = withPrettyErrors (code, options) ->
{merge, extend} = helpers
- options = extend {}, options
- generateSourceMap = options.sourceMap or options.inlineMap
+ options = extend {}, optionsAlways generate a source map if no filename is passed in, since without a
+a filename we have no way to retrieve this source later in the event that
+we need to recompile it to get a source map for prepareStackTrace.
generateSourceMap = options.sourceMap or options.inlineMap or not options.filename?
+ filename = options.filename or '<anonymous>'
+
+ sources[filename] = code
+ map = new SourceMap if generateSourceMap
tokens = lexer.tokenize code, optionsPass a list of referenced variables, so that generated variables won’t get the same name.
@@ -290,13 +344,13 @@Check for import or export; if found, force bare mode
+Check for import or export; if found, force bare mode.
Update the sourcemap with data from each fragment
+Update the sourcemap with data from each fragment.
Do not include empty, whitespace, or semicolon-only fragments.
@@ -358,11 +412,11 @@Copy the code from each fragment into the final JavaScript.
@@ -376,6 +430,7 @@Tokenize a string of CoffeeScript code, and return the array of tokens.
@@ -411,11 +466,11 @@Parse a string of CoffeeScript code or an array of lexed tokens, and
return the AST. You can then compile it by calling .compile() on the root,
@@ -432,11 +487,11 @@
Compile and execute a string of CoffeeScript (on the server), correctly
setting __filename, __dirname, and relative require().
mainModule.filename = process.argv[1] =
- if options.filename then fs.realpathSync(options.filename) else '.'Clear the module cache.
@@ -480,17 +535,17 @@ dir = if options.filename
+ dir = if options.filename?
path.dirname fs.realpathSync options.filename
else
fs.realpathSync '.'
@@ -499,11 +554,11 @@ coffee-script.coffee
-
+
Compile.
@@ -518,11 +573,11 @@ coffee-script.coffee
-
+
Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
The CoffeeScript REPL uses this to run the input.
@@ -552,11 +607,11 @@ coffee-script.coffee
-
+
define module/require only if they chose not to specify their own
@@ -573,11 +628,11 @@ coffee-script.coffee
-
+
use the same hack node currently uses for their own REPL
@@ -599,11 +654,11 @@ coffee-script.coffee
-
+
Throw error with deprecation warning when depending upon implicit require.extensions registration
@@ -617,8 +672,22 @@ coffee-script.coffee
"""
exports._compileFile = (filename, sourceMap = no, inlineMap = no) ->
- raw = fs.readFileSync filename, 'utf8'
- stripped = if raw.charCodeAt(0) is 0xFEFF then raw.substring 1 else raw
+ raw = fs.readFileSync filename, 'utf8'
+
+
+
+
+
+
+
+
+ ¶
+
+ Strip the Unicode byte order mark, if this file begins with one.
+
+
+
+ stripped = if raw.charCodeAt(0) is 0xFEFF then raw.substring 1 else raw
try
answer = compile stripped, {
@@ -631,11 +700,11 @@ coffee-script.coffee
-
+
As the filename and code of a dynamically loaded file will be different
from the original file compiled with CoffeeScript.run, add that
@@ -650,11 +719,11 @@
coffee-script.coffee
-
+
Instantiate a Lexer for our use here.
@@ -665,11 +734,11 @@ coffee-script.coffee
-
+
The real Lexer produces a generic stream of tokens. This object provides a
thin wrapper around it, compatible with the Jison API. We can then pass it
@@ -697,11 +766,11 @@
coffee-script.coffee
-
+
Make all the AST nodes visible to the parser.
@@ -712,11 +781,11 @@ coffee-script.coffee
-
+
Override Jison’s default error handling function.
@@ -727,11 +796,11 @@ coffee-script.coffee
-
+
Disregard Jison’s message, it contains redundant line number information.
Disregard the token, we take its value directly from the lexer in case
@@ -755,11 +824,11 @@
coffee-script.coffee
-
+
The second argument has a loc property, which should have the location
data for this token. Unfortunately, Jison seems to send an outdated loc
@@ -772,6 +841,140 @@
coffee-script.coffee
+
+
+
+
+
+ ¶
+
+ Based on http://v8.googlecode.com/svn/branches/bleeding_edge/src/messages.js
+Modified to handle sourceMap
+
+
+
+ formatSourcePosition = (frame, getSourceMapping) ->
+ filename = undefined
+ fileLocation = ''
+
+ if frame.isNative()
+ fileLocation = "native"
+ else
+ if frame.isEval()
+ filename = frame.getScriptNameOrSourceURL()
+ fileLocation = "#{frame.getEvalOrigin()}, " unless filename
+ else
+ filename = frame.getFileName()
+
+ filename or= "<anonymous>"
+
+ line = frame.getLineNumber()
+ column = frame.getColumnNumber()
+
+
+
+
+
+
+
+
+ ¶
+
+ Check for a sourceMap position
+
+
+
+ source = getSourceMapping filename, line, column
+ fileLocation =
+ if source
+ "#{filename}:#{source[0]}:#{source[1]}"
+ else
+ "#{filename}:#{line}:#{column}"
+
+ functionName = frame.getFunctionName()
+ isConstructor = frame.isConstructor()
+ isMethodCall = not (frame.isToplevel() or isConstructor)
+
+ if isMethodCall
+ methodName = frame.getMethodName()
+ typeName = frame.getTypeName()
+
+ if functionName
+ tp = as = ''
+ if typeName and functionName.indexOf typeName
+ tp = "#{typeName}."
+ if methodName and functionName.indexOf(".#{methodName}") isnt functionName.length - methodName.length - 1
+ as = " [as #{methodName}]"
+
+ "#{tp}#{functionName}#{as} (#{fileLocation})"
+ else
+ "#{typeName}.#{methodName or '<anonymous>'} (#{fileLocation})"
+ else if isConstructor
+ "new #{functionName or '<anonymous>'} (#{fileLocation})"
+ else if functionName
+ "#{functionName} (#{fileLocation})"
+ else
+ fileLocation
+
+getSourceMap = (filename) ->
+ if sourceMaps[filename]?
+ sourceMaps[filename]
+
+
+
+
+
+
+
+
+ ¶
+
+ CoffeeScript compiled in a browser may get compiled with options.filename
+of <anonymous>, but the browser may request the stack trace with the
+filename of the script file.
+
+
+
+ else if sourceMaps['<anonymous>']?
+ sourceMaps['<anonymous>']
+ else if sources[filename]?
+ answer = compile sources[filename],
+ filename: filename
+ sourceMap: yes
+ answer.sourceMap
+ else
+ null
+
+
+
+
+
+
+
+
+ ¶
+
+ Based on michaelficarra/CoffeeScriptRedux
+NodeJS / V8 have no support for transforming positions in stack traces using
+sourceMap, so we must monkey-patch Error to display CoffeeScript source
+positions.
+
+
+
+ Error.prepareStackTrace = (err, stack) ->
+ getSourceMapping = (filename, line, column) ->
+ sourceMap = getSourceMap filename
+ answer = sourceMap.sourceLocation [line - 1, column - 1] if sourceMap?
+ if answer? then [answer[0] + 1, answer[1] + 1] else null
+
+ frames = for frame in stack
+ break if frame.getFunction() is exports.run
+ " at #{formatSourcePosition frame, getSourceMapping}"
+
+ "#{err.toString()}\n#{frames.join '\n'}\n"
+
+
+