Diff
checker
Texte
Texte
Images
Documents
Excel
Dossiers
Legal
Enterprise
Application de bureau
Prix
Se connecter
Télécharger Diffchecker Desktop
Comparer le texte
Trouver la différence entre deux fichiers texte
Outils
Historique
Éditeur live
Cacher identiques
Sans retour à la ligne
Vue
Divisé
Unifié
Niveau de précision
Intelligent
Mot
Caractère
Coloration syntaxique
Choisir la syntaxe
Ignorer
Transformer le texte
Aller au premier écart
Modifier l'entrée
Diffchecker Desktop
La façon la plus sécurisée d'utiliser Diffchecker. Obtenez l'application Diffchecker Desktop : vos diffs ne quittent jamais votre ordinateur !
Obtenir Desktop
Untitled diff
Créé
il y a 9 ans
Le diff n'expire jamais
Effacer
Exporter
Partager
Expliquer
16 suppressions
Lignes
Total
Supprimé
Caractères
Total
Supprimé
Pour continuer à utiliser cette fonctionnalité, passez à
Diff
checker
Pro
Voir les prix
362 lignes
Copier tout
35 ajouts
Lignes
Total
Ajouté
Caractères
Total
Ajouté
Pour continuer à utiliser cette fonctionnalité, passez à
Diff
checker
Pro
Voir les prix
378 lignes
Copier tout
# CoffeeScript can be used both on the server, as a command-line compiler based
# 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
# on Node.js/V8, or to run CoffeeScript directly in the browser. This module
# contains the main entry functions for tokenizing, parsing, and compiling
# contains the main entry functions for tokenizing, parsing, and compiling
# source CoffeeScript into JavaScript.
# source CoffeeScript into JavaScript.
fs = require 'fs'
fs = require 'fs'
vm = require 'vm'
vm = require 'vm'
path = require 'path'
path = require 'path'
{Lexer} = require './lexer'
{Lexer} = require './lexer'
{parser} = require './parser'
{parser} = require './parser'
helpers = require './helpers'
helpers = require './helpers'
SourceMap = require './sourcemap'
SourceMap = require './sourcemap'
Copier
Copié
Copier
Copié
# Require `package.json`, which is two levels above this file, as this file is
# evaluated from `lib/coffee-script`.
packageJson = require '../../package.json'
# The current CoffeeScript version number.
# The current CoffeeScript version number.
Copier
Copié
Copier
Copié
exports.VERSION =
'1.12.1'
exports.VERSION =
packageJson.version
exports.FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md']
exports.FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md']
# Expose helpers for testing.
# Expose helpers for testing.
exports.helpers = helpers
exports.helpers = helpers
# Function that allows for btoa in both nodejs and the browser.
# Function that allows for btoa in both nodejs and the browser.
base64encode = (src) -> switch
base64encode = (src) -> switch
when typeof Buffer is 'function'
when typeof Buffer is 'function'
new Buffer(src).toString('base64')
new Buffer(src).toString('base64')
when typeof btoa is 'function'
when typeof btoa is 'function'
# The contents of a `<script>` block are encoded via UTF-16, so if any extended
# The contents of a `<script>` block are encoded via UTF-16, so if any extended
# characters are used in the block, btoa will fail as it maxes out at UTF-8.
# characters are used in the block, btoa will fail as it maxes out at UTF-8.
# See https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_Unicode_Problem
# See https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_Unicode_Problem
# for the gory details, and for the solution implemented here.
# for the gory details, and for the solution implemented here.
btoa encodeURIComponent(src).replace /%([0-9A-F]{2})/g, (match, p1) ->
btoa encodeURIComponent(src).replace /%([0-9A-F]{2})/g, (match, p1) ->
String.fromCharCode '0x' + p1
String.fromCharCode '0x' + p1
else
else
throw new Error('Unable to base64 encode inline sourcemap.')
throw new Error('Unable to base64 encode inline sourcemap.')
# Function wrapper to add source file information to SyntaxErrors thrown by the
# Function wrapper to add source file information to SyntaxErrors thrown by the
# lexer/parser/compiler.
# lexer/parser/compiler.
withPrettyErrors = (fn) ->
withPrettyErrors = (fn) ->
(code, options = {}) ->
(code, options = {}) ->
try
try
fn.call @, code, options
fn.call @, code, options
catch err
catch err
throw err if typeof code isnt 'string' # Support `CoffeeScript.nodes(tokens)`.
throw err if typeof code isnt 'string' # Support `CoffeeScript.nodes(tokens)`.
throw helpers.updateSyntaxError err, code, options.filename
throw helpers.updateSyntaxError err, code, options.filename
# Compile CoffeeScript code to JavaScript, using the Coffee/Jison compiler.
# Compile CoffeeScript code to JavaScript, using the Coffee/Jison compiler.
#
#
# If `options.sourceMap` is specified, then `options.filename` must also be specified. All
# 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.
# options that can be passed to `SourceMap#generate` may also be passed here.
#
#
# This returns a javascript string, unless `options.sourceMap` is passed,
# This returns a javascript string, unless `options.sourceMap` is passed,
# in which case this returns a `{js, v3SourceMap, sourceMap}`
# in which case this returns a `{js, v3SourceMap, sourceMap}`
# object, where sourceMap is a sourcemap.coffee#SourceMap object, handy for doing programatic
# object, where sourceMap is a sourcemap.coffee#SourceMap object, handy for doing programatic
# lookups.
# lookups.
exports.compile = compile = withPrettyErrors (code, options) ->
exports.compile = compile = withPrettyErrors (code, options) ->
{merge, extend} = helpers
{merge, extend} = helpers
options = extend {}, options
options = extend {}, options
generateSourceMap = options.sourceMap or options.inlineMap
generateSourceMap = options.sourceMap or options.inlineMap
if generateSourceMap
if generateSourceMap
map = new SourceMap
map = new SourceMap
tokens = lexer.tokenize code, options
tokens = lexer.tokenize code, options
# Pass a list of referenced variables, so that generated variables won't get
# Pass a list of referenced variables, so that generated variables won't get
# the same name.
# the same name.
options.referencedVars = (
options.referencedVars = (
token[1] for token in tokens when token[0] is 'IDENTIFIER'
token[1] for token in tokens when token[0] is 'IDENTIFIER'
)
)
# Check for import or export; if found, force bare mode
# Check for import or export; if found, force bare mode
unless options.bare? and options.bare is yes
unless options.bare? and options.bare is yes
for token in tokens
for token in tokens
if token[0] in ['IMPORT', 'EXPORT']
if token[0] in ['IMPORT', 'EXPORT']
options.bare = yes
options.bare = yes
break
break
fragments = parser.parse(tokens).compileToFragments options
fragments = parser.parse(tokens).compileToFragments options
currentLine = 0
currentLine = 0
currentLine += 1 if options.header
currentLine += 1 if options.header
currentLine += 1 if options.shiftLine
currentLine += 1 if options.shiftLine
currentColumn = 0
currentColumn = 0
js = ""
js = ""
for fragment in fragments
for fragment in fragments
# Update the sourcemap with data from each fragment
# Update the sourcemap with data from each fragment
if generateSourceMap
if generateSourceMap
# Do not include empty, whitespace, or semicolon-only fragments.
# Do not include empty, whitespace, or semicolon-only fragments.
if fragment.locationData and not /^[;\s]*$/.test fragment.code
if fragment.locationData and not /^[;\s]*$/.test fragment.code
map.add(
map.add(
[fragment.locationData.first_line, fragment.locationData.first_column]
[fragment.locationData.first_line, fragment.locationData.first_column]
[currentLine, currentColumn]
[currentLine, currentColumn]
{noReplace: true})
{noReplace: true})
newLines = helpers.count fragment.code, "\n"
newLines = helpers.count fragment.code, "\n"
currentLine += newLines
currentLine += newLines
if newLines
if newLines
currentColumn = fragment.code.length - (fragment.code.lastIndexOf("\n") + 1)
currentColumn = fragment.code.length - (fragment.code.lastIndexOf("\n") + 1)
else
else
currentColumn += fragment.code.length
currentColumn += fragment.code.length
# Copy the code from each fragment into the final JavaScript.
# Copy the code from each fragment into the final JavaScript.
js += fragment.code
js += fragment.code
if options.header
if options.header
header = "Generated by CoffeeScript #{@VERSION}"
header = "Generated by CoffeeScript #{@VERSION}"
js = "// #{header}\n#{js}"
js = "// #{header}\n#{js}"
if generateSourceMap
if generateSourceMap
v3SourceMap = map.generate(options, code)
v3SourceMap = map.generate(options, code)
if options.inlineMap
if options.inlineMap
encoded = base64encode JSON.stringify v3SourceMap
encoded = base64encode JSON.stringify v3SourceMap
sourceMapDataURI = "//# sourceMappingURL=data:application/json;base64,#{encoded}"
sourceMapDataURI = "//# sourceMappingURL=data:application/json;base64,#{encoded}"
sourceURL = "//# sourceURL=#{options.filename ? 'coffeescript'}"
sourceURL = "//# sourceURL=#{options.filename ? 'coffeescript'}"
js = "#{js}\n#{sourceMapDataURI}\n#{sourceURL}"
js = "#{js}\n#{sourceMapDataURI}\n#{sourceURL}"
if options.sourceMap
if options.sourceMap
{
{
js
js
sourceMap: map
sourceMap: map
v3SourceMap: JSON.stringify v3SourceMap, null, 2
v3SourceMap: JSON.stringify v3SourceMap, null, 2
}
}
else
else
js
js
# Tokenize a string of CoffeeScript code, and return the array of tokens.
# Tokenize a string of CoffeeScript code, and return the array of tokens.
exports.tokens = withPrettyErrors (code, options) ->
exports.tokens = withPrettyErrors (code, options) ->
lexer.tokenize code, options
lexer.tokenize code, options
# Parse a string of CoffeeScript code or an array of lexed tokens, and
# 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,
# return the AST. You can then compile it by calling `.compile()` on the root,
# or traverse it by using `.traverseChildren()` with a callback.
# or traverse it by using `.traverseChildren()` with a callback.
exports.nodes = withPrettyErrors (source, options) ->
exports.nodes = withPrettyErrors (source, options) ->
if typeof source is 'string'
if typeof source is 'string'
parser.parse lexer.tokenize source, options
parser.parse lexer.tokenize source, options
else
else
parser.parse source
parser.parse source
# Compile and execute a string of CoffeeScript (on the server), correctly
# Compile and execute a string of CoffeeScript (on the server), correctly
# setting `__filename`, `__dirname`, and relative `require()`.
# setting `__filename`, `__dirname`, and relative `require()`.
exports.run = (code, options = {}) ->
exports.run = (code, options = {}) ->
mainModule = require.main
mainModule = require.main
# Set the filename.
# Set the filename.
mainModule.filename = process.argv[1] =
mainModule.filename = process.argv[1] =
if options.filename then fs.realpathSync(options.filename) else '.'
if options.filename then fs.realpathSync(options.filename) else '.'
# Clear the module cache.
# Clear the module cache.
mainModule.moduleCache and= {}
mainModule.moduleCache and= {}
# Assign paths for node_modules loading
# Assign paths for node_modules loading
dir = if options.filename
dir = if options.filename
path.dirname fs.realpathSync options.filename
path.dirname fs.realpathSync options.filename
else
else
fs.realpathSync '.'
fs.realpathSync '.'
mainModule.paths = require('module')._nodeModulePaths dir
mainModule.paths = require('module')._nodeModulePaths dir
# Compile.
# Compile.
if not helpers.isCoffee(mainModule.filename) or require.extensions
if not helpers.isCoffee(mainModule.filename) or require.extensions
answer = compile code, options
answer = compile code, options
code = answer.js ? answer
code = answer.js ? answer
mainModule._compile code, mainModule.filename
mainModule._compile code, mainModule.filename
# Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
# Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
# The CoffeeScript REPL uses this to run the input.
# The CoffeeScript REPL uses this to run the input.
exports.eval = (code, options = {}) ->
exports.eval = (code, options = {}) ->
return unless code = code.trim()
return unless code = code.trim()
createContext = vm.Script.createContext ? vm.createContext
createContext = vm.Script.createContext ? vm.createContext
isContext = vm.isContext ? (ctx) ->
isContext = vm.isContext ? (ctx) ->
options.sandbox instanceof createContext().constructor
options.sandbox instanceof createContext().constructor
if createContext
if createContext
if options.sandbox?
if options.sandbox?
if isContext options.sandbox
if isContext options.sandbox
sandbox = options.sandbox
sandbox = options.sandbox
else
else
sandbox = createContext()
sandbox = createContext()
sandbox[k] = v for own k, v of options.sandbox
sandbox[k] = v for own k, v of options.sandbox
sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox
sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox
else
else
sandbox = global
sandbox = global
sandbox.__filename = options.filename || 'eval'
sandbox.__filename = options.filename || 'eval'
sandbox.__dirname = path.dirname sandbox.__filename
sandbox.__dirname = path.dirname sandbox.__filename
# define module/require only if they chose not to specify their own
# define module/require only if they chose not to specify their own
unless sandbox isnt global or sandbox.module or sandbox.require
unless sandbox isnt global or sandbox.module or sandbox.require
Module = require 'module'
Module = require 'module'
sandbox.module = _module = new Module(options.modulename || 'eval')
sandbox.module = _module = new Module(options.modulename || 'eval')
sandbox.require = _require = (path) -> Module._load path, _module, true
sandbox.require = _require = (path) -> Module._load path, _module, true
_module.filename = sandbox.__filename
_module.filename = sandbox.__filename
for r in Object.getOwnPropertyNames require when r not in ['paths', 'arguments', 'caller']
for r in Object.getOwnPropertyNames require when r not in ['paths', 'arguments', 'caller']
_require[r] = require[r]
_require[r] = require[r]
# use the same hack node currently uses for their own REPL
# use the same hack node currently uses for their own REPL
_require.paths = _module.paths = Module._nodeModulePaths process.cwd()
_require.paths = _module.paths = Module._nodeModulePaths process.cwd()
_require.resolve = (request) -> Module._resolveFilename request, _module
_require.resolve = (request) -> Module._resolveFilename request, _module
o = {}
o = {}
o[k] = v for own k, v of options
o[k] = v for own k, v of options
o.bare = on # ensure return value
o.bare = on # ensure return value
js = compile code, o
js = compile code, o
if sandbox is global
if sandbox is global
vm.runInThisContext js
vm.runInThisContext js
else
else
vm.runInContext js, sandbox
vm.runInContext js, sandbox
exports.register = -> require './register'
exports.register = -> require './register'
# Throw error with deprecation warning when depending upon implicit `require.extensions` registration
# Throw error with deprecation warning when depending upon implicit `require.extensions` registration
if require.extensions
if require.extensions
for ext in @FILE_EXTENSIONS then do (ext) ->
for ext in @FILE_EXTENSIONS then do (ext) ->
require.extensions[ext] ?= ->
require.extensions[ext] ?= ->
throw new Error """
throw new Error """
Use CoffeeScript.register() or require the coffee-script/register module to require #{ext} files.
Use CoffeeScript.register() or require the coffee-script/register module to require #{ext} files.
"""
"""
Copier
Copié
Copier
Copié
# 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.
compiledFiles = {}
exports._compileFile = (filename, sourceMap = no, inlineMap = no) ->
exports._compileFile = (filename, sourceMap = no, inlineMap = no) ->
raw = fs.readFileSync filename, 'utf8'
raw = fs.readFileSync filename, 'utf8'
Copier
Copié
Copier
Copié
# 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
stripped = if raw.charCodeAt(0) is 0xFEFF then raw.substring 1 else raw
Copier
Copié
Copier
Copié
compiledFiles[filename] = stripped
compileCode stripped, filename, sourceMap, inlineMap
Copier
Copié
Copier
Copié
compileCode = (code, filename, sourceMap = no, inlineMap = no) ->
try
try
Copier
Copié
Copier
Copié
answer = compile
stripped
, {
answer = compile
code
, {
filename, sourceMap, inlineMap
filename, sourceMap, inlineMap
sourceFiles: [filename]
sourceFiles: [filename]
literate: helpers.isLiterate filename
literate: helpers.isLiterate filename
}
}
catch err
catch err
# As the filename and code of a dynamically loaded file will be different
# As the filename and code of a dynamically loaded file will be different
# from the original file compiled with CoffeeScript.run, add that
# from the original file compiled with CoffeeScript.run, add that
# information to error so it can be pretty-printed later.
# information to error so it can be pretty-printed later.
Copier
Copié
Copier
Copié
throw helpers.updateSyntaxError err,
stripped
, filename
throw helpers.updateSyntaxError err,
code
, filename
answer
answer
# Instantiate a Lexer for our use here.
# Instantiate a Lexer for our use here.
lexer = new Lexer
lexer = new Lexer
# The real Lexer produces a generic stream of tokens. This object provides a
# 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
# thin wrapper around it, compatible with the Jison API. We can then pass it
# directly as a "Jison lexer".
# directly as a "Jison lexer".
parser.lexer =
parser.lexer =
lex: ->
lex: ->
token = parser.tokens[@pos++]
token = parser.tokens[@pos++]
if token
if token
[tag, @yytext, @yylloc] = token
[tag, @yytext, @yylloc] = token
parser.errorToken = token.origin or token
parser.errorToken = token.origin or token
@yylineno = @yylloc.first_line
@yylineno = @yylloc.first_line
else
else
tag = ''
tag = ''
tag
tag
setInput: (tokens) ->
setInput: (tokens) ->
parser.tokens = tokens
parser.tokens = tokens
@pos = 0
@pos = 0
upcomingInput: ->
upcomingInput: ->
""
""
# Make all the AST nodes visible to the parser.
# Make all the AST nodes visible to the parser.
parser.yy = require './nodes'
parser.yy = require './nodes'
# Override Jison's default error handling function.
# Override Jison's default error handling function.
parser.yy.parseError = (message, {token}) ->
parser.yy.parseError = (message, {token}) ->
# Disregard Jison's message, it contains redundant line number information.
# Disregard Jison's message, it contains redundant line number information.
# Disregard the token, we take its value directly from the lexer in case
# 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.
# the error is caused by a generated token which might refer to its origin.
{errorToken, tokens} = parser
{errorToken, tokens} = parser
[errorTag, errorText, errorLoc] = errorToken
[errorTag, errorText, errorLoc] = errorToken
errorText = switch
errorText = switch
when errorToken is tokens[tokens.length - 1]
when errorToken is tokens[tokens.length - 1]
'end of input'
'end of input'
when errorTag in ['INDENT', 'OUTDENT']
when errorTag in ['INDENT', 'OUTDENT']
'indentation'
'indentation'
when errorTag in ['IDENTIFIER', 'NUMBER', 'INFINITY', 'STRING', 'STRING_START', 'REGEX', 'REGEX_START']
when errorTag in ['IDENTIFIER', 'NUMBER', 'INFINITY', 'STRING', 'STRING_START', 'REGEX', 'REGEX_START']
errorTag.replace(/_START$/, '').toLowerCase()
errorTag.replace(/_START$/, '').toLowerCase()
else
else
helpers.nameWhitespaceCharacter errorText
helpers.nameWhitespaceCharacter errorText
# The second argument has a `loc` property, which should have the location
# The second argument has a `loc` property, which should have the location
# data for this token. Unfortunately, Jison seems to send an outdated `loc`
# data for this token. Unfortunately, Jison seems to send an outdated `loc`
# (from the previous token), so we take the location information directly
# (from the previous token), so we take the location information directly
# from the lexer.
# from the lexer.
helpers.throwSyntaxError "unexpected #{errorText}", errorLoc
helpers.throwSyntaxError "unexpected #{errorText}", errorLoc
# Based on http://v8.googlecode.com/svn/branches/bleeding_edge/src/messages.js
# Based on http://v8.googlecode.com/svn/branches/bleeding_edge/src/messages.js
# Modified to handle sourceMap
# Modified to handle sourceMap
formatSourcePosition = (frame, getSourceMapping) ->
formatSourcePosition = (frame, getSourceMapping) ->
fileName = undefined
fileName = undefined
fileLocation = ''
fileLocation = ''
if frame.isNative()
if frame.isNative()
fileLocation = "native"
fileLocation = "native"
else
else
if frame.isEval()
if frame.isEval()
fileName = frame.getScriptNameOrSourceURL()
fileName = frame.getScriptNameOrSourceURL()
fileLocation = "#{frame.getEvalOrigin()}, " unless fileName
fileLocation = "#{frame.getEvalOrigin()}, " unless fileName
else
else
fileName = frame.getFileName()
fileName = frame.getFileName()
fileName or= "<anonymous>"
fileName or= "<anonymous>"
line = frame.getLineNumber()
line = frame.getLineNumber()
column = frame.getColumnNumber()
column = frame.getColumnNumber()
# Check for a sourceMap position
# Check for a sourceMap position
source = getSourceMapping fileName, line, column
source = getSourceMapping fileName, line, column
fileLocation =
fileLocation =
if source
if source
"#{fileName}:#{source[0]}:#{source[1]}"
"#{fileName}:#{source[0]}:#{source[1]}"
else
else
"#{fileName}:#{line}:#{column}"
"#{fileName}:#{line}:#{column}"
functionName = frame.getFunctionName()
functionName = frame.getFunctionName()
isConstructor = frame.isConstructor()
isConstructor = frame.isConstructor()
isMethodCall = not (frame.isToplevel() or isConstructor)
isMethodCall = not (frame.isToplevel() or isConstructor)
if isMethodCall
if isMethodCall
methodName = frame.getMethodName()
methodName = frame.getMethodName()
typeName = frame.getTypeName()
typeName = frame.getTypeName()
if functionName
if functionName
tp = as = ''
tp = as = ''
if typeName and functionName.indexOf typeName
if typeName and functionName.indexOf typeName
tp = "#{typeName}."
tp = "#{typeName}."
if methodName and functionName.indexOf(".#{methodName}") isnt functionName.length - methodName.length - 1
if methodName and functionName.indexOf(".#{methodName}") isnt functionName.length - methodName.length - 1
as = " [as #{methodName}]"
as = " [as #{methodName}]"
"#{tp}#{functionName}#{as} (#{fileLocation})"
"#{tp}#{functionName}#{as} (#{fileLocation})"
else
else
"#{typeName}.#{methodName or '<anonymous>'} (#{fileLocation})"
"#{typeName}.#{methodName or '<anonymous>'} (#{fileLocation})"
else if isConstructor
else if isConstructor
"new #{functionName or '<anonymous>'} (#{fileLocation})"
"new #{functionName or '<anonymous>'} (#{fileLocation})"
else if functionName
else if functionName
"#{functionName} (#{fileLocation})"
"#{functionName} (#{fileLocation})"
else
else
fileLocation
fileLocation
Copier
Copié
Copier
Copié
# Map of filenames
->
sourceMap object
.
# Map of filenames
:
sourceMap object
s
.
sourceMaps = {}
sourceMaps = {}
Copier
Copié
Copier
Copié
# Generates the source map for a coffee file and stores it in the local cache variable.
# Generates the source map for a coffee file and stores it in the local cache variable.
getSourceMap = (filename) ->
getSourceMap = (filename) ->
Copier
Copié
Copier
Copié
return
sourceMaps[filename]
if
sourceMaps[filename]
if
sourceMaps[filename]
?
for ext in exports.FILE_EXTENSIONS
sourceMaps[filename]
if
helpers.ends
filename
, ext
else
if
compiledFiles[
filename
]?
answer =
exports._
compile
File
filename,
true
answer =
compileCode
compile
d
File
s[filename],
filename,
yes, no
return
sourceMaps[filename] = answer.sourceMap
sourceMaps[filename] = answer.sourceMap
return
null
else
null
# Based on [michaelficarra/CoffeeScriptRedux](http://goo.gl/ZTx1p)
# Based on [michaelficarra/CoffeeScriptRedux](http://goo.gl/ZTx1p)
# NodeJS / V8 have no support for transforming positions in stack traces using
# NodeJS / V8 have no support for transforming positions in stack traces using
# sourceMap, so we must monkey-patch Error to display CoffeeScript source
# sourceMap, so we must monkey-patch Error to display CoffeeScript source
# positions.
# positions.
Error.prepareStackTrace = (err, stack) ->
Error.prepareStackTrace = (err, stack) ->
getSourceMapping = (filename, line, column) ->
getSourceMapping = (filename, line, column) ->
sourceMap = getSourceMap filename
sourceMap = getSourceMap filename
answer = sourceMap.sourceLocation [line - 1, column - 1] if sourceMap
answer = sourceMap.sourceLocation [line - 1, column - 1] if sourceMap
if answer then [answer[0] + 1, answer[1] + 1] else null
if answer then [answer[0] + 1, answer[1] + 1] else null
frames = for frame in stack
frames = for frame in stack
break if frame.getFunction() is exports.run
break if frame.getFunction() is exports.run
Copier
Copié
Copier
Copié
"
at #{formatSourcePosition frame, getSourceMapping}"
"
at #{formatSourcePosition frame, getSourceMapping}"
"#{err.toString()}\n#{frames.join '\n'}\n"
"#{err.toString()}\n#{frames.join '\n'}\n"
Copier
Copié
Copier
Copié
Différences enregistrées
Texte d'origine
Ouvrir un fichier
# 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. fs = require 'fs' vm = require 'vm' path = require 'path' {Lexer} = require './lexer' {parser} = require './parser' helpers = require './helpers' SourceMap = require './sourcemap' # The current CoffeeScript version number. exports.VERSION = '1.12.1' exports.FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md'] # Expose helpers for testing. exports.helpers = helpers # Function that allows for btoa in both nodejs and the browser. base64encode = (src) -> switch when typeof Buffer is 'function' new Buffer(src).toString('base64') when typeof btoa is 'function' # The contents of a `<script>` block are encoded via UTF-16, so if any extended # characters are used in the block, btoa will fail as it maxes out at UTF-8. # See https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_Unicode_Problem # for the gory details, and for the solution implemented here. btoa encodeURIComponent(src).replace /%([0-9A-F]{2})/g, (match, p1) -> String.fromCharCode '0x' + p1 else throw new Error('Unable to base64 encode inline sourcemap.') # Function wrapper to add source file information to SyntaxErrors thrown by the # lexer/parser/compiler. withPrettyErrors = (fn) -> (code, options = {}) -> try fn.call @, code, options catch err throw err if typeof code isnt 'string' # Support `CoffeeScript.nodes(tokens)`. throw helpers.updateSyntaxError err, code, options.filename # 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. # # 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 if generateSourceMap map = new SourceMap tokens = lexer.tokenize code, options # Pass a list of referenced variables, so that generated variables won't get # the same name. options.referencedVars = ( token[1] for token in tokens when token[0] is 'IDENTIFIER' ) # Check for import or export; if found, force bare mode unless options.bare? and options.bare is yes for token in tokens if token[0] in ['IMPORT', 'EXPORT'] options.bare = yes break fragments = parser.parse(tokens).compileToFragments options currentLine = 0 currentLine += 1 if options.header currentLine += 1 if options.shiftLine currentColumn = 0 js = "" for fragment in fragments # Update the sourcemap with data from each fragment if generateSourceMap # Do not include empty, whitespace, or semicolon-only fragments. if fragment.locationData and not /^[;\s]*$/.test fragment.code map.add( [fragment.locationData.first_line, fragment.locationData.first_column] [currentLine, currentColumn] {noReplace: true}) newLines = helpers.count fragment.code, "\n" currentLine += newLines if newLines currentColumn = fragment.code.length - (fragment.code.lastIndexOf("\n") + 1) else currentColumn += fragment.code.length # Copy the code from each fragment into the final JavaScript. js += fragment.code if options.header header = "Generated by CoffeeScript #{@VERSION}" js = "// #{header}\n#{js}" if generateSourceMap v3SourceMap = map.generate(options, code) if options.inlineMap encoded = base64encode JSON.stringify v3SourceMap sourceMapDataURI = "//# sourceMappingURL=data:application/json;base64,#{encoded}" sourceURL = "//# sourceURL=#{options.filename ? 'coffeescript'}" js = "#{js}\n#{sourceMapDataURI}\n#{sourceURL}" if options.sourceMap { js sourceMap: map v3SourceMap: JSON.stringify v3SourceMap, null, 2 } else js # Tokenize a string of CoffeeScript code, and return the array of tokens. exports.tokens = withPrettyErrors (code, options) -> lexer.tokenize code, options # 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, # or traverse it by using `.traverseChildren()` with a callback. exports.nodes = withPrettyErrors (source, options) -> if typeof source is 'string' parser.parse lexer.tokenize source, options else parser.parse source # Compile and execute a string of CoffeeScript (on the server), correctly # setting `__filename`, `__dirname`, and relative `require()`. exports.run = (code, options = {}) -> mainModule = require.main # Set the filename. mainModule.filename = process.argv[1] = if options.filename then fs.realpathSync(options.filename) else '.' # Clear the module cache. mainModule.moduleCache and= {} # Assign paths for node_modules loading dir = if options.filename path.dirname fs.realpathSync options.filename else fs.realpathSync '.' mainModule.paths = require('module')._nodeModulePaths dir # Compile. if not helpers.isCoffee(mainModule.filename) or require.extensions answer = compile code, options code = answer.js ? answer mainModule._compile code, mainModule.filename # Compile and evaluate a string of CoffeeScript (in a Node.js-like environment). # The CoffeeScript REPL uses this to run the input. exports.eval = (code, options = {}) -> return unless code = code.trim() createContext = vm.Script.createContext ? vm.createContext isContext = vm.isContext ? (ctx) -> options.sandbox instanceof createContext().constructor if createContext if options.sandbox? if isContext options.sandbox sandbox = options.sandbox else sandbox = createContext() sandbox[k] = v for own k, v of options.sandbox sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox else sandbox = global sandbox.__filename = options.filename || 'eval' sandbox.__dirname = path.dirname sandbox.__filename # define module/require only if they chose not to specify their own unless sandbox isnt global or sandbox.module or sandbox.require Module = require 'module' sandbox.module = _module = new Module(options.modulename || 'eval') sandbox.require = _require = (path) -> Module._load path, _module, true _module.filename = sandbox.__filename for r in Object.getOwnPropertyNames require when r not in ['paths', 'arguments', 'caller'] _require[r] = require[r] # use the same hack node currently uses for their own REPL _require.paths = _module.paths = Module._nodeModulePaths process.cwd() _require.resolve = (request) -> Module._resolveFilename request, _module o = {} o[k] = v for own k, v of options o.bare = on # ensure return value js = compile code, o if sandbox is global vm.runInThisContext js else vm.runInContext js, sandbox exports.register = -> require './register' # Throw error with deprecation warning when depending upon implicit `require.extensions` registration if require.extensions for ext in @FILE_EXTENSIONS then do (ext) -> require.extensions[ext] ?= -> throw new Error """ Use CoffeeScript.register() or require the coffee-script/register module to require #{ext} files. """ 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 try answer = compile stripped, { filename, sourceMap, inlineMap sourceFiles: [filename] literate: helpers.isLiterate filename } catch err # 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. throw helpers.updateSyntaxError err, stripped, filename answer # Instantiate a Lexer for our use here. lexer = new Lexer # 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". parser.lexer = lex: -> token = parser.tokens[@pos++] if token [tag, @yytext, @yylloc] = token parser.errorToken = token.origin or token @yylineno = @yylloc.first_line else tag = '' tag setInput: (tokens) -> parser.tokens = tokens @pos = 0 upcomingInput: -> "" # Make all the AST nodes visible to the parser. parser.yy = require './nodes' # Override Jison's default error handling function. parser.yy.parseError = (message, {token}) -> # Disregard Jison's message, it contains redundant line number 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. {errorToken, tokens} = parser [errorTag, errorText, errorLoc] = errorToken errorText = switch when errorToken is tokens[tokens.length - 1] 'end of input' when errorTag in ['INDENT', 'OUTDENT'] 'indentation' when errorTag in ['IDENTIFIER', 'NUMBER', 'INFINITY', 'STRING', 'STRING_START', 'REGEX', 'REGEX_START'] errorTag.replace(/_START$/, '').toLowerCase() else helpers.nameWhitespaceCharacter errorText # The second argument has a `loc` property, which should have the location # data for this token. Unfortunately, Jison seems to send an outdated `loc` # (from the previous token), so we take the location information directly # from the lexer. helpers.throwSyntaxError "unexpected #{errorText}", errorLoc # 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 # Map of filenames -> sourceMap object. sourceMaps = {} # Generates the source map for a coffee file and stores it in the local cache variable. getSourceMap = (filename) -> return sourceMaps[filename] if sourceMaps[filename] for ext in exports.FILE_EXTENSIONS if helpers.ends filename, ext answer = exports._compileFile filename, true return sourceMaps[filename] = answer.sourceMap return null # Based on [michaelficarra/CoffeeScriptRedux](http://goo.gl/ZTx1p) # 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"
Texte modifié
Ouvrir un fichier
# 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. fs = require 'fs' vm = require 'vm' path = require 'path' {Lexer} = require './lexer' {parser} = require './parser' helpers = require './helpers' SourceMap = require './sourcemap' # Require `package.json`, which is two levels above this file, as this file is # evaluated from `lib/coffee-script`. packageJson = require '../../package.json' # The current CoffeeScript version number. exports.VERSION = packageJson.version exports.FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md'] # Expose helpers for testing. exports.helpers = helpers # Function that allows for btoa in both nodejs and the browser. base64encode = (src) -> switch when typeof Buffer is 'function' new Buffer(src).toString('base64') when typeof btoa is 'function' # The contents of a `<script>` block are encoded via UTF-16, so if any extended # characters are used in the block, btoa will fail as it maxes out at UTF-8. # See https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_Unicode_Problem # for the gory details, and for the solution implemented here. btoa encodeURIComponent(src).replace /%([0-9A-F]{2})/g, (match, p1) -> String.fromCharCode '0x' + p1 else throw new Error('Unable to base64 encode inline sourcemap.') # Function wrapper to add source file information to SyntaxErrors thrown by the # lexer/parser/compiler. withPrettyErrors = (fn) -> (code, options = {}) -> try fn.call @, code, options catch err throw err if typeof code isnt 'string' # Support `CoffeeScript.nodes(tokens)`. throw helpers.updateSyntaxError err, code, options.filename # 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. # # 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 if generateSourceMap map = new SourceMap tokens = lexer.tokenize code, options # Pass a list of referenced variables, so that generated variables won't get # the same name. options.referencedVars = ( token[1] for token in tokens when token[0] is 'IDENTIFIER' ) # Check for import or export; if found, force bare mode unless options.bare? and options.bare is yes for token in tokens if token[0] in ['IMPORT', 'EXPORT'] options.bare = yes break fragments = parser.parse(tokens).compileToFragments options currentLine = 0 currentLine += 1 if options.header currentLine += 1 if options.shiftLine currentColumn = 0 js = "" for fragment in fragments # Update the sourcemap with data from each fragment if generateSourceMap # Do not include empty, whitespace, or semicolon-only fragments. if fragment.locationData and not /^[;\s]*$/.test fragment.code map.add( [fragment.locationData.first_line, fragment.locationData.first_column] [currentLine, currentColumn] {noReplace: true}) newLines = helpers.count fragment.code, "\n" currentLine += newLines if newLines currentColumn = fragment.code.length - (fragment.code.lastIndexOf("\n") + 1) else currentColumn += fragment.code.length # Copy the code from each fragment into the final JavaScript. js += fragment.code if options.header header = "Generated by CoffeeScript #{@VERSION}" js = "// #{header}\n#{js}" if generateSourceMap v3SourceMap = map.generate(options, code) if options.inlineMap encoded = base64encode JSON.stringify v3SourceMap sourceMapDataURI = "//# sourceMappingURL=data:application/json;base64,#{encoded}" sourceURL = "//# sourceURL=#{options.filename ? 'coffeescript'}" js = "#{js}\n#{sourceMapDataURI}\n#{sourceURL}" if options.sourceMap { js sourceMap: map v3SourceMap: JSON.stringify v3SourceMap, null, 2 } else js # Tokenize a string of CoffeeScript code, and return the array of tokens. exports.tokens = withPrettyErrors (code, options) -> lexer.tokenize code, options # 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, # or traverse it by using `.traverseChildren()` with a callback. exports.nodes = withPrettyErrors (source, options) -> if typeof source is 'string' parser.parse lexer.tokenize source, options else parser.parse source # Compile and execute a string of CoffeeScript (on the server), correctly # setting `__filename`, `__dirname`, and relative `require()`. exports.run = (code, options = {}) -> mainModule = require.main # Set the filename. mainModule.filename = process.argv[1] = if options.filename then fs.realpathSync(options.filename) else '.' # Clear the module cache. mainModule.moduleCache and= {} # Assign paths for node_modules loading dir = if options.filename path.dirname fs.realpathSync options.filename else fs.realpathSync '.' mainModule.paths = require('module')._nodeModulePaths dir # Compile. if not helpers.isCoffee(mainModule.filename) or require.extensions answer = compile code, options code = answer.js ? answer mainModule._compile code, mainModule.filename # Compile and evaluate a string of CoffeeScript (in a Node.js-like environment). # The CoffeeScript REPL uses this to run the input. exports.eval = (code, options = {}) -> return unless code = code.trim() createContext = vm.Script.createContext ? vm.createContext isContext = vm.isContext ? (ctx) -> options.sandbox instanceof createContext().constructor if createContext if options.sandbox? if isContext options.sandbox sandbox = options.sandbox else sandbox = createContext() sandbox[k] = v for own k, v of options.sandbox sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox else sandbox = global sandbox.__filename = options.filename || 'eval' sandbox.__dirname = path.dirname sandbox.__filename # define module/require only if they chose not to specify their own unless sandbox isnt global or sandbox.module or sandbox.require Module = require 'module' sandbox.module = _module = new Module(options.modulename || 'eval') sandbox.require = _require = (path) -> Module._load path, _module, true _module.filename = sandbox.__filename for r in Object.getOwnPropertyNames require when r not in ['paths', 'arguments', 'caller'] _require[r] = require[r] # use the same hack node currently uses for their own REPL _require.paths = _module.paths = Module._nodeModulePaths process.cwd() _require.resolve = (request) -> Module._resolveFilename request, _module o = {} o[k] = v for own k, v of options o.bare = on # ensure return value js = compile code, o if sandbox is global vm.runInThisContext js else vm.runInContext js, sandbox exports.register = -> require './register' # Throw error with deprecation warning when depending upon implicit `require.extensions` registration if require.extensions for ext in @FILE_EXTENSIONS then do (ext) -> require.extensions[ext] ?= -> throw new Error """ Use CoffeeScript.register() or require the coffee-script/register module to require #{ext} files. """ # 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. compiledFiles = {} exports._compileFile = (filename, sourceMap = no, inlineMap = no) -> 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 compiledFiles[filename] = stripped compileCode stripped, filename, sourceMap, inlineMap compileCode = (code, filename, sourceMap = no, inlineMap = no) -> try answer = compile code, { filename, sourceMap, inlineMap sourceFiles: [filename] literate: helpers.isLiterate filename } catch err # 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. throw helpers.updateSyntaxError err, code, filename answer # Instantiate a Lexer for our use here. lexer = new Lexer # 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". parser.lexer = lex: -> token = parser.tokens[@pos++] if token [tag, @yytext, @yylloc] = token parser.errorToken = token.origin or token @yylineno = @yylloc.first_line else tag = '' tag setInput: (tokens) -> parser.tokens = tokens @pos = 0 upcomingInput: -> "" # Make all the AST nodes visible to the parser. parser.yy = require './nodes' # Override Jison's default error handling function. parser.yy.parseError = (message, {token}) -> # Disregard Jison's message, it contains redundant line number 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. {errorToken, tokens} = parser [errorTag, errorText, errorLoc] = errorToken errorText = switch when errorToken is tokens[tokens.length - 1] 'end of input' when errorTag in ['INDENT', 'OUTDENT'] 'indentation' when errorTag in ['IDENTIFIER', 'NUMBER', 'INFINITY', 'STRING', 'STRING_START', 'REGEX', 'REGEX_START'] errorTag.replace(/_START$/, '').toLowerCase() else helpers.nameWhitespaceCharacter errorText # The second argument has a `loc` property, which should have the location # data for this token. Unfortunately, Jison seems to send an outdated `loc` # (from the previous token), so we take the location information directly # from the lexer. helpers.throwSyntaxError "unexpected #{errorText}", errorLoc # 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 # Map of filenames: sourceMap objects. sourceMaps = {} # Generates the source map for a coffee file and stores it in the local cache variable. getSourceMap = (filename) -> if sourceMaps[filename]? sourceMaps[filename] else if compiledFiles[filename]? answer = compileCode compiledFiles[filename], filename, yes, no sourceMaps[filename] = answer.sourceMap else null # Based on [michaelficarra/CoffeeScriptRedux](http://goo.gl/ZTx1p) # 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"
Trouver la différence