<!DOCTYPE html> <html> <head> <title>coffee-script.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <ul id="jump_to"> <li> <a class="large" href="javascript:void(0);">Jump To …</a> <a class="small" href="javascript:void(0);">+</a> <div id="jump_wrapper"> <div id="jump_page_wrapper"> <div id="jump_page"> <a class="source" href="browser.html"> browser.coffee </a> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="register.html"> register.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.litcoffee </a> <a class="source" href="sourcemap.html"> sourcemap.litcoffee </a> </div> </div> </li> </ul> <ul class="sections"> <li id="title"> <div class="annotation"> <h1>coffee-script.coffee</h1> </div> </li> <li id="section-1"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-1">¶</a> </div> <p>CoffeeScript can be used both on the server, as a command-line compiler based on Node.js/V8, or to run CoffeeScript directly in the browser. This module contains the main entry functions for tokenizing, parsing, and compiling source CoffeeScript into JavaScript.</p> </div> <div class="content"><div class='highlight'><pre> fs = <span class="hljs-built_in">require</span> <span class="hljs-string">'fs'</span> vm = <span class="hljs-built_in">require</span> <span class="hljs-string">'vm'</span> path = <span class="hljs-built_in">require</span> <span class="hljs-string">'path'</span> {Lexer} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./lexer'</span> {parser} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./parser'</span> helpers = <span class="hljs-built_in">require</span> <span class="hljs-string">'./helpers'</span> SourceMap = <span class="hljs-built_in">require</span> <span class="hljs-string">'./sourcemap'</span></pre></div></div> </li> <li id="section-2"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-2">¶</a> </div> <p>The current CoffeeScript version number.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.VERSION = <span class="hljs-string">'1.10.0'</span> <span class="hljs-built_in">exports</span>.FILE_EXTENSIONS = [<span class="hljs-string">'.coffee'</span>, <span class="hljs-string">'.litcoffee'</span>, <span class="hljs-string">'.coffee.md'</span>]</pre></div></div> </li> <li id="section-3"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-3">¶</a> </div> <p>Expose helpers for testing.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.helpers = helpers</pre></div></div> </li> <li id="section-4"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Function wrapper to add source file information to SyntaxErrors thrown by the lexer/parser/compiler.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">withPrettyErrors</span> = <span class="hljs-params">(fn)</span> -></span> <span class="hljs-function"><span class="hljs-params">(code, options = {})</span> -></span> <span class="hljs-keyword">try</span> fn.call @, code, options <span class="hljs-keyword">catch</span> err <span class="hljs-keyword">throw</span> err <span class="hljs-keyword">if</span> <span class="hljs-keyword">typeof</span> code <span class="hljs-keyword">isnt</span> <span class="hljs-string">'string'</span> <span class="hljs-comment"># Support `CoffeeScript.nodes(tokens)`.</span> <span class="hljs-keyword">throw</span> helpers.updateSyntaxError err, code, options.filename</pre></div></div> </li> <li id="section-5"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Compile CoffeeScript code to JavaScript, using the Coffee/Jison compiler.</p> <p>If <code>options.sourceMap</code> is specified, then <code>options.filename</code> must also be specified. All options that can be passed to <code>SourceMap#generate</code> may also be passed here.</p> <p>This returns a javascript string, unless <code>options.sourceMap</code> is passed, in which case this returns a <code>{js, v3SourceMap, sourceMap}</code> object, where sourceMap is a sourcemap.coffee#SourceMap object, handy for doing programatic lookups.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.compile = compile = withPrettyErrors <span class="hljs-function"><span class="hljs-params">(code, options)</span> -></span> {merge, extend} = helpers options = extend {}, options <span class="hljs-keyword">if</span> options.sourceMap map = <span class="hljs-keyword">new</span> SourceMap tokens = lexer.tokenize code, options</pre></div></div> </li> <li id="section-6"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-6">¶</a> </div> <p>Pass a list of referenced variables, so that generated variables won’t get the same name.</p> </div> <div class="content"><div class='highlight'><pre> options.referencedVars = ( token[<span class="hljs-number">1</span>] <span class="hljs-keyword">for</span> token <span class="hljs-keyword">in</span> tokens <span class="hljs-keyword">when</span> token.variable ) fragments = parser.parse(tokens).compileToFragments options currentLine = <span class="hljs-number">0</span> currentLine += <span class="hljs-number">1</span> <span class="hljs-keyword">if</span> options.header currentLine += <span class="hljs-number">1</span> <span class="hljs-keyword">if</span> options.shiftLine currentColumn = <span class="hljs-number">0</span> js = <span class="hljs-string">""</span> <span class="hljs-keyword">for</span> fragment <span class="hljs-keyword">in</span> fragments</pre></div></div> </li> <li id="section-7"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-7">¶</a> </div> <p>Update the sourcemap with data from each fragment</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> options.sourceMap</pre></div></div> </li> <li id="section-8"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-8">¶</a> </div> <p>Do not include empty, whitespace, or semicolon-only fragments.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> fragment.locationData <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> <span class="hljs-regexp">/^[;\s]*$/</span>.test fragment.code map.add( [fragment.locationData.first_line, fragment.locationData.first_column] [currentLine, currentColumn] {<span class="hljs-attribute">noReplace</span>: <span class="hljs-literal">true</span>}) newLines = helpers.count fragment.code, <span class="hljs-string">"\n"</span> currentLine += newLines <span class="hljs-keyword">if</span> newLines currentColumn = fragment.code.length - (fragment.code.lastIndexOf(<span class="hljs-string">"\n"</span>) + <span class="hljs-number">1</span>) <span class="hljs-keyword">else</span> currentColumn += fragment.code.length</pre></div></div> </li> <li id="section-9"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-9">¶</a> </div> <p>Copy the code from each fragment into the final JavaScript.</p> </div> <div class="content"><div class='highlight'><pre> js += fragment.code <span class="hljs-keyword">if</span> options.header header = <span class="hljs-string">"Generated by CoffeeScript <span class="hljs-subst">#{<span class="hljs-property">@VERSION</span>}</span>"</span> js = <span class="hljs-string">"// <span class="hljs-subst">#{header}</span>\n<span class="hljs-subst">#{js}</span>"</span> <span class="hljs-keyword">if</span> options.sourceMap answer = {js} answer.sourceMap = map answer.v3SourceMap = map.generate(options, code) answer <span class="hljs-keyword">else</span> js</pre></div></div> </li> <li id="section-10"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Tokenize a string of CoffeeScript code, and return the array of tokens.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.tokens = withPrettyErrors <span class="hljs-function"><span class="hljs-params">(code, options)</span> -></span> lexer.tokenize code, options</pre></div></div> </li> <li id="section-11"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-11">¶</a> </div> <p>Parse a string of CoffeeScript code or an array of lexed tokens, and return the AST. You can then compile it by calling <code>.compile()</code> on the root, or traverse it by using <code>.traverseChildren()</code> with a callback.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.nodes = withPrettyErrors <span class="hljs-function"><span class="hljs-params">(source, options)</span> -></span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">typeof</span> source <span class="hljs-keyword">is</span> <span class="hljs-string">'string'</span> parser.parse lexer.tokenize source, options <span class="hljs-keyword">else</span> parser.parse source</pre></div></div> </li> <li id="section-12"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Compile and execute a string of CoffeeScript (on the server), correctly setting <code>__filename</code>, <code>__dirname</code>, and relative <code>require()</code>.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.<span class="hljs-function"><span class="hljs-title">run</span> = <span class="hljs-params">(code, options = {})</span> -></span> mainModule = <span class="hljs-built_in">require</span>.main</pre></div></div> </li> <li id="section-13"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-13">¶</a> </div> <p>Set the filename.</p> </div> <div class="content"><div class='highlight'><pre> mainModule.filename = process.argv[<span class="hljs-number">1</span>] = <span class="hljs-keyword">if</span> options.filename <span class="hljs-keyword">then</span> fs.realpathSync(options.filename) <span class="hljs-keyword">else</span> <span class="hljs-string">'.'</span></pre></div></div> </li> <li id="section-14"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-14">¶</a> </div> <p>Clear the module cache.</p> </div> <div class="content"><div class='highlight'><pre> mainModule.moduleCache <span class="hljs-keyword">and</span>= {}</pre></div></div> </li> <li id="section-15"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-15">¶</a> </div> <p>Assign paths for node_modules loading</p> </div> <div class="content"><div class='highlight'><pre> dir = <span class="hljs-keyword">if</span> options.filename path.dirname fs.realpathSync options.filename <span class="hljs-keyword">else</span> fs.realpathSync <span class="hljs-string">'.'</span> mainModule.paths = <span class="hljs-built_in">require</span>(<span class="hljs-string">'module'</span>)._nodeModulePaths dir</pre></div></div> </li> <li id="section-16"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-16">¶</a> </div> <p>Compile.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> helpers.isCoffee(mainModule.filename) <span class="hljs-keyword">or</span> <span class="hljs-built_in">require</span>.extensions answer = compile code, options code = answer.js ? answer mainModule._compile code, mainModule.filename</pre></div></div> </li> <li id="section-17"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-17">¶</a> </div> <p>Compile and evaluate a string of CoffeeScript (in a Node.js-like environment). The CoffeeScript REPL uses this to run the input.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.<span class="hljs-function"><span class="hljs-title">eval</span> = <span class="hljs-params">(code, options = {})</span> -></span> <span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> code = code.trim() createContext = vm.Script.createContext ? vm.createContext isContext = vm.isContext ? <span class="hljs-function"><span class="hljs-params">(ctx)</span> -></span> options.sandbox <span class="hljs-keyword">instanceof</span> createContext().constructor <span class="hljs-keyword">if</span> createContext <span class="hljs-keyword">if</span> options.sandbox? <span class="hljs-keyword">if</span> isContext options.sandbox sandbox = options.sandbox <span class="hljs-keyword">else</span> sandbox = createContext() sandbox[k] = v <span class="hljs-keyword">for</span> own k, v <span class="hljs-keyword">of</span> options.sandbox sandbox.<span class="hljs-built_in">global</span> = sandbox.root = sandbox.GLOBAL = sandbox <span class="hljs-keyword">else</span> sandbox = <span class="hljs-built_in">global</span> sandbox.__filename = options.filename || <span class="hljs-string">'eval'</span> sandbox.__dirname = path.dirname sandbox.__filename</pre></div></div> </li> <li id="section-18"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-18">¶</a> </div> <p>define module/require only if they chose not to specify their own</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">unless</span> sandbox <span class="hljs-keyword">isnt</span> <span class="hljs-built_in">global</span> <span class="hljs-keyword">or</span> sandbox.<span class="hljs-built_in">module</span> <span class="hljs-keyword">or</span> sandbox.<span class="hljs-built_in">require</span> Module = <span class="hljs-built_in">require</span> <span class="hljs-string">'module'</span> sandbox.<span class="hljs-built_in">module</span> = _module = <span class="hljs-keyword">new</span> Module(options.modulename || <span class="hljs-string">'eval'</span>) sandbox.<span class="hljs-built_in">require</span> = <span class="hljs-function"><span class="hljs-title">_require</span> = <span class="hljs-params">(path)</span> -></span> Module._load path, _module, <span class="hljs-literal">true</span> _module.filename = sandbox.__filename <span class="hljs-keyword">for</span> r <span class="hljs-keyword">in</span> Object.getOwnPropertyNames <span class="hljs-built_in">require</span> <span class="hljs-keyword">when</span> r <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'paths'</span>, <span class="hljs-string">'arguments'</span>, <span class="hljs-string">'caller'</span>] _require[r] = <span class="hljs-built_in">require</span>[r]</pre></div></div> </li> <li id="section-19"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-19">¶</a> </div> <p>use the same hack node currently uses for their own REPL</p> </div> <div class="content"><div class='highlight'><pre> _require.paths = _module.paths = Module._nodeModulePaths process.cwd() _require.<span class="hljs-function"><span class="hljs-title">resolve</span> = <span class="hljs-params">(request)</span> -></span> Module._resolveFilename request, _module o = {} o[k] = v <span class="hljs-keyword">for</span> own k, v <span class="hljs-keyword">of</span> options o.bare = <span class="hljs-literal">on</span> <span class="hljs-comment"># ensure return value</span> js = compile code, o <span class="hljs-keyword">if</span> sandbox <span class="hljs-keyword">is</span> <span class="hljs-built_in">global</span> vm.runInThisContext js <span class="hljs-keyword">else</span> vm.runInContext js, sandbox <span class="hljs-built_in">exports</span>.<span class="hljs-function"><span class="hljs-title">register</span> = -></span> <span class="hljs-built_in">require</span> <span class="hljs-string">'./register'</span></pre></div></div> </li> <li id="section-20"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-20">¶</a> </div> <p>Throw error with deprecation warning when depending upon implicit <code>require.extensions</code> registration</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-keyword">if</span> <span class="hljs-built_in">require</span>.extensions <span class="hljs-keyword">for</span> ext <span class="hljs-keyword">in</span> <span class="hljs-property">@FILE_EXTENSIONS</span> <span class="hljs-built_in">require</span>.extensions[ext] ?=<span class="hljs-function"> -></span> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Error <span class="hljs-string">""" Use CoffeeScript.register() or require the coffee-script/register module to require <span class="hljs-subst">#{ext}</span> files. """</span> <span class="hljs-built_in">exports</span>.<span class="hljs-function"><span class="hljs-title">_compileFile</span> = <span class="hljs-params">(filename, sourceMap = <span class="hljs-literal">no</span>)</span> -></span> raw = fs.readFileSync filename, <span class="hljs-string">'utf8'</span> stripped = <span class="hljs-keyword">if</span> raw.charCodeAt(<span class="hljs-number">0</span>) <span class="hljs-keyword">is</span> <span class="hljs-number">0xFEFF</span> <span class="hljs-keyword">then</span> raw.substring <span class="hljs-number">1</span> <span class="hljs-keyword">else</span> raw <span class="hljs-keyword">try</span> answer = compile(stripped, {filename, sourceMap, <span class="hljs-attribute">literate</span>: helpers.isLiterate filename}) <span class="hljs-keyword">catch</span> err</pre></div></div> </li> <li id="section-21"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-21">¶</a> </div> <p>As the filename and code of a dynamically loaded file will be different from the original file compiled with CoffeeScript.run, add that information to error so it can be pretty-printed later.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">throw</span> helpers.updateSyntaxError err, stripped, filename answer</pre></div></div> </li> <li id="section-22"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-22">¶</a> </div> <p>Instantiate a Lexer for our use here.</p> </div> <div class="content"><div class='highlight'><pre>lexer = <span class="hljs-keyword">new</span> Lexer</pre></div></div> </li> <li id="section-23"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-23">¶</a> </div> <p>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 directly as a “Jison lexer”.</p> </div> <div class="content"><div class='highlight'><pre>parser.lexer = <span class="hljs-attribute">lex</span>:<span class="hljs-function"> -></span> token = parser.tokens[<span class="hljs-property">@pos</span>++] <span class="hljs-keyword">if</span> token [tag, <span class="hljs-property">@yytext</span>, <span class="hljs-property">@yylloc</span>] = token parser.errorToken = token.origin <span class="hljs-keyword">or</span> token <span class="hljs-property">@yylineno</span> = <span class="hljs-property">@yylloc</span>.first_line <span class="hljs-keyword">else</span> tag = <span class="hljs-string">''</span> tag <span class="hljs-attribute">setInput</span>: <span class="hljs-function"><span class="hljs-params">(tokens)</span> -></span> parser.tokens = tokens <span class="hljs-property">@pos</span> = <span class="hljs-number">0</span> <span class="hljs-attribute">upcomingInput</span>:<span class="hljs-function"> -></span> <span class="hljs-string">""</span></pre></div></div> </li> <li id="section-24"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-24">¶</a> </div> <p>Make all the AST nodes visible to the parser.</p> </div> <div class="content"><div class='highlight'><pre>parser.yy = <span class="hljs-built_in">require</span> <span class="hljs-string">'./nodes'</span></pre></div></div> </li> <li id="section-25"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-25">¶</a> </div> <p>Override Jison’s default error handling function.</p> </div> <div class="content"><div class='highlight'><pre>parser.yy.<span class="hljs-function"><span class="hljs-title">parseError</span> = <span class="hljs-params">(message, {token})</span> -></span></pre></div></div> </li> <li id="section-26"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-26">¶</a> </div> <p>Disregard Jison’s message, it contains redundant line numer information. Disregard the token, we take its value directly from the lexer in case the error is caused by a generated token which might refer to its origin.</p> </div> <div class="content"><div class='highlight'><pre> {errorToken, tokens} = parser [errorTag, errorText, errorLoc] = errorToken errorText = <span class="hljs-keyword">switch</span> <span class="hljs-keyword">when</span> errorToken <span class="hljs-keyword">is</span> tokens[tokens.length - <span class="hljs-number">1</span>] <span class="hljs-string">'end of input'</span> <span class="hljs-keyword">when</span> errorTag <span class="hljs-keyword">in</span> [<span class="hljs-string">'INDENT'</span>, <span class="hljs-string">'OUTDENT'</span>] <span class="hljs-string">'indentation'</span> <span class="hljs-keyword">when</span> errorTag <span class="hljs-keyword">in</span> [<span class="hljs-string">'IDENTIFIER'</span>, <span class="hljs-string">'NUMBER'</span>, <span class="hljs-string">'STRING'</span>, <span class="hljs-string">'STRING_START'</span>, <span class="hljs-string">'REGEX'</span>, <span class="hljs-string">'REGEX_START'</span>] errorTag.replace(<span class="hljs-regexp">/_START$/</span>, <span class="hljs-string">''</span>).toLowerCase() <span class="hljs-keyword">else</span> helpers.nameWhitespaceCharacter errorText</pre></div></div> </li> <li id="section-27"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-27">¶</a> </div> <p>The second argument has a <code>loc</code> property, which should have the location data for this token. Unfortunately, Jison seems to send an outdated <code>loc</code> (from the previous token), so we take the location information directly from the lexer.</p> </div> <div class="content"><div class='highlight'><pre> helpers.throwSyntaxError <span class="hljs-string">"unexpected <span class="hljs-subst">#{errorText}</span>"</span>, errorLoc</pre></div></div> </li> <li id="section-28"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-28">¶</a> </div> <p>Based on <a href="http://v8.googlecode.com/svn/branches/bleeding_edge/src/messages.js">http://v8.googlecode.com/svn/branches/bleeding_edge/src/messages.js</a> Modified to handle sourceMap</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">formatSourcePosition</span> = <span class="hljs-params">(frame, getSourceMapping)</span> -></span> fileName = <span class="hljs-literal">undefined</span> fileLocation = <span class="hljs-string">''</span> <span class="hljs-keyword">if</span> frame.isNative() fileLocation = <span class="hljs-string">"native"</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> frame.isEval() fileName = frame.getScriptNameOrSourceURL() fileLocation = <span class="hljs-string">"<span class="hljs-subst">#{frame.getEvalOrigin()}</span>, "</span> <span class="hljs-keyword">unless</span> fileName <span class="hljs-keyword">else</span> fileName = frame.getFileName() fileName <span class="hljs-keyword">or</span>= <span class="hljs-string">"<anonymous>"</span> line = frame.getLineNumber() column = frame.getColumnNumber()</pre></div></div> </li> <li id="section-29"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-29">¶</a> </div> <p>Check for a sourceMap position</p> </div> <div class="content"><div class='highlight'><pre> source = getSourceMapping fileName, line, column fileLocation = <span class="hljs-keyword">if</span> source <span class="hljs-string">"<span class="hljs-subst">#{fileName}</span>:<span class="hljs-subst">#{source[<span class="hljs-number">0</span>]}</span>:<span class="hljs-subst">#{source[<span class="hljs-number">1</span>]}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{fileName}</span>:<span class="hljs-subst">#{line}</span>:<span class="hljs-subst">#{column}</span>"</span> functionName = frame.getFunctionName() isConstructor = frame.isConstructor() isMethodCall = <span class="hljs-keyword">not</span> (frame.isToplevel() <span class="hljs-keyword">or</span> isConstructor) <span class="hljs-keyword">if</span> isMethodCall methodName = frame.getMethodName() typeName = frame.getTypeName() <span class="hljs-keyword">if</span> functionName tp = as = <span class="hljs-string">''</span> <span class="hljs-keyword">if</span> typeName <span class="hljs-keyword">and</span> functionName.indexOf typeName tp = <span class="hljs-string">"<span class="hljs-subst">#{typeName}</span>."</span> <span class="hljs-keyword">if</span> methodName <span class="hljs-keyword">and</span> functionName.indexOf(<span class="hljs-string">".<span class="hljs-subst">#{methodName}</span>"</span>) <span class="hljs-keyword">isnt</span> functionName.length - methodName.length - <span class="hljs-number">1</span> as = <span class="hljs-string">" [as <span class="hljs-subst">#{methodName}</span>]"</span> <span class="hljs-string">"<span class="hljs-subst">#{tp}</span><span class="hljs-subst">#{functionName}</span><span class="hljs-subst">#{as}</span> (<span class="hljs-subst">#{fileLocation}</span>)"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{typeName}</span>.<span class="hljs-subst">#{methodName <span class="hljs-keyword">or</span> <span class="hljs-string">'<anonymous>'</span>}</span> (<span class="hljs-subst">#{fileLocation}</span>)"</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> isConstructor <span class="hljs-string">"new <span class="hljs-subst">#{functionName <span class="hljs-keyword">or</span> <span class="hljs-string">'<anonymous>'</span>}</span> (<span class="hljs-subst">#{fileLocation}</span>)"</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> functionName <span class="hljs-string">"<span class="hljs-subst">#{functionName}</span> (<span class="hljs-subst">#{fileLocation}</span>)"</span> <span class="hljs-keyword">else</span> fileLocation</pre></div></div> </li> <li id="section-30"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-30">¶</a> </div> <p>Map of filenames -> sourceMap object.</p> </div> <div class="content"><div class='highlight'><pre>sourceMaps = {}</pre></div></div> </li> <li id="section-31"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-31">¶</a> </div> <p>Generates the source map for a coffee file and stores it in the local cache variable.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">getSourceMap</span> = <span class="hljs-params">(filename)</span> -></span> <span class="hljs-keyword">return</span> sourceMaps[filename] <span class="hljs-keyword">if</span> sourceMaps[filename] <span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> path?.extname(filename) <span class="hljs-keyword">in</span> <span class="hljs-built_in">exports</span>.FILE_EXTENSIONS answer = <span class="hljs-built_in">exports</span>._compileFile filename, <span class="hljs-literal">true</span> sourceMaps[filename] = answer.sourceMap</pre></div></div> </li> <li id="section-32"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-32">¶</a> </div> <p>Based on <a href="http://goo.gl/ZTx1p">michaelficarra/CoffeeScriptRedux</a> NodeJS / V8 have no support for transforming positions in stack traces using sourceMap, so we must monkey-patch Error to display CoffeeScript source positions.</p> </div> <div class="content"><div class='highlight'><pre>Error.<span class="hljs-function"><span class="hljs-title">prepareStackTrace</span> = <span class="hljs-params">(err, stack)</span> -></span> <span class="hljs-function"><span class="hljs-title">getSourceMapping</span> = <span class="hljs-params">(filename, line, column)</span> -></span> sourceMap = getSourceMap filename answer = sourceMap.sourceLocation [line - <span class="hljs-number">1</span>, column - <span class="hljs-number">1</span>] <span class="hljs-keyword">if</span> sourceMap <span class="hljs-keyword">if</span> answer <span class="hljs-keyword">then</span> [answer[<span class="hljs-number">0</span>] + <span class="hljs-number">1</span>, answer[<span class="hljs-number">1</span>] + <span class="hljs-number">1</span>] <span class="hljs-keyword">else</span> <span class="hljs-literal">null</span> frames = <span class="hljs-keyword">for</span> frame <span class="hljs-keyword">in</span> stack <span class="hljs-keyword">break</span> <span class="hljs-keyword">if</span> frame.getFunction() <span class="hljs-keyword">is</span> <span class="hljs-built_in">exports</span>.run <span class="hljs-string">" at <span class="hljs-subst">#{formatSourcePosition frame, getSourceMapping}</span>"</span> <span class="hljs-string">"<span class="hljs-subst">#{err.toString()}</span>\n<span class="hljs-subst">#{frames.join <span class="hljs-string">'\n'</span>}</span>\n"</span></pre></div></div> </li> </ul> </div> </body> </html>