exports.VERSION = packageJson.version
-exports.FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md']
From df9d4a23432c05a004fa7d06a62917e7daa765f9 Mon Sep 17 00:00:00 2001
From: Geoffrey Booth lib/coffeescript
.
exports.VERSION = packageJson.version
-exports.FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md']
filename
: (source)
+it’s not likely to be used. Save in form of filename
: [(source)
]
@@ -267,7 +267,7 @@ it’s not likely to be used. Save in form of filename
: (sour
- Also save source maps if generated, in form of filename
: (source map)
.
+ Also save source maps if generated, in form of (source)
: [(source map)
].
@@ -317,7 +317,8 @@ we need to recompile it to get a source map for prepareStackTrace
.<
checkShebangLine filename, code
- sources[filename] = code
+ sources[filename] ?= []
+ sources[filename].push code
map = new SourceMap if generateSourceMap
tokens = lexer.tokenize code, options
@@ -428,8 +429,9 @@ the same name.
js = "// #{header}\n#{js}"
if generateSourceMap
- v3SourceMap = map.generate(options, code)
- sourceMaps[filename] = map
+ v3SourceMap = map.generate options, code
+ sourceMaps[filename] ?= []
+ sourceMaps[filename].push map
if options.inlineMap
encoded = base64encode JSON.stringify v3SourceMap
@@ -701,9 +703,7 @@ Modified to handle sourceMap
else
fileLocation
-getSourceMap = (filename) ->
- if sourceMaps[filename]?
- sourceMaps[filename]
+getSourceMap = (filename, line, column) ->
@@ -714,22 +714,15 @@ Modified to handle sourceMap
- 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.
+ Skip files that we didn’t compile, like Node system files that appear in
+the stack trace, as they never have source maps.
- else if sourceMaps['<anonymous>']?
- sourceMaps['<anonymous>']
- else if sources[filename]?
- answer = compile sources[filename],
- filename: filename
- sourceMap: yes
- literate: helpers.isLiterate filename
- answer.sourceMap
- else
- null
+ return null unless filename is '<anonymous>' or filename.slice(filename.lastIndexOf('.')) in FILE_EXTENSIONS
+
+ if filename isnt '<anonymous>' and sourceMaps[filename]?
+ return sourceMaps[filename][sourceMaps[filename].length - 1]
@@ -740,6 +733,73 @@ filename of the script file.
+ CoffeeScript compiled in a browser or via CoffeeScript.compile
or .run
+may get compiled with options.filename
that’s missing, which becomes
+<anonymous>
; but the runtime might request the stack trace with the
+filename of the script file. See if we have a source map cached under
+<anonymous>
that matches the error.
+
+
+
+ else if sourceMaps['<anonymous>']?
+
+
+
+
+
+
+
+
+ ¶
+
+ Work backwards from the most recent anonymous source maps, until we find
+one that works. This isn’t foolproof; there is a chance that multiple
+source maps will have line/column pairs that match. But we have no other
+way to match them. frame.getFunction().toString()
doesn’t always work,
+and it’s not foolproof either.
+
+
+
+ for map in sourceMaps['<anonymous>'] by -1
+ sourceLocation = map.sourceLocation [line - 1, column - 1]
+ return map if sourceLocation?[0]? and sourceLocation[1]?
+
+
+
+
+
+
+
+
+ ¶
+
+ If all else fails, recompile this source to get a source map. We need the
+previous section (for <anonymous>
) despite this option, because after it
+gets compiled we will still need to look it up from
+sourceMaps['<anonymous>']
in order to find and return it. That’s why we
+start searching from the end in the previous block, because most of the
+time the source map we want is the last one.
+
+
+
+ if sources[filename]?
+ answer = compile sources[filename][sources[filename].length - 1],
+ filename: filename
+ sourceMap: yes
+ literate: helpers.isLiterate filename
+ 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
@@ -749,7 +809,7 @@ positions.
Error.prepareStackTrace = (err, stack) ->
getSourceMapping = (filename, line, column) ->
- sourceMap = getSourceMap filename
+ sourceMap = getSourceMap filename, line, column
answer = sourceMap.sourceLocation [line - 1, column - 1] if sourceMap?
if answer? then [answer[0] + 1, answer[1] + 1] else null
diff --git a/docs/v2/annotated-source/command.html b/docs/v2/annotated-source/command.html
index 2d047c48..6e0c69be 100644
--- a/docs/v2/annotated-source/command.html
+++ b/docs/v2/annotated-source/command.html
@@ -199,25 +199,25 @@ useWinPathSep = path.sep is SWITCHES = [
- ['-b', '--bare', 'compile without a top-level function wrapper']
- ['-c', '--compile', 'compile to JavaScript and save as .js files']
- ['-e', '--eval', 'pass a string from the command line as input']
- ['-h', '--help', 'display this help message']
- ['-i', '--interactive', 'run an interactive CoffeeScript REPL']
- ['-j', '--join [FILE]', 'concatenate the source CoffeeScript before compiling']
- ['-m', '--map', 'generate source map and save as .js.map files']
- ['-M', '--inline-map', 'generate source map and include it directly in output']
- ['-n', '--nodes', 'print out the parse tree that the parser produces']
- [ '--nodejs [ARGS]', 'pass options directly to the "node" binary']
- [ '--no-header', 'suppress the "Generated by" header']
- ['-o', '--output [DIR]', 'set the output directory for compiled JavaScript']
- ['-p', '--print', 'print out the compiled JavaScript']
+ ['-b', '--bare', 'compile without a top-level function wrapper']
+ ['-c', '--compile', 'compile to JavaScript and save as .js files']
+ ['-e', '--eval', 'pass a string from the command line as input']
+ ['-h', '--help', 'display this help message']
+ ['-i', '--interactive', 'run an interactive CoffeeScript REPL']
+ ['-j', '--join [FILE]', 'concatenate the source CoffeeScript before compiling']
+ ['-m', '--map', 'generate source map and save as .js.map files']
+ ['-M', '--inline-map', 'generate source map and include it directly in output']
+ ['-n', '--nodes', 'print out the parse tree that the parser produces']
+ [ '--nodejs [ARGS]', 'pass options directly to the "node" binary']
+ [ '--no-header', 'suppress the "Generated by" header']
+ ['-o', '--output [PATH]', 'set the output path or path/filename for compiled JavaScript']
+ ['-p', '--print', 'print out the compiled JavaScript']
['-r', '--require [MODULE*]', 'require the given module before eval or REPL']
- ['-s', '--stdio', 'listen for and compile scripts over stdio']
- ['-l', '--literate', 'treat stdio as literate style coffeescript']
- ['-t', '--tokens', 'print out the tokens that the lexer/rewriter produce']
- ['-v', '--version', 'display the version number']
- ['-w', '--watch', 'watch scripts for changes and rerun commands']
+ ['-s', '--stdio', 'listen for and compile scripts over stdio']
+ ['-l', '--literate', 'treat stdio as literate style coffeescript']
+ ['-t', '--tokens', 'print out the tokens that the lexer/rewriter produce']
+ ['-v', '--version', 'display the version number']
+ ['-w', '--watch', 'watch scripts for changes and rerun commands']
]
@@ -305,7 +305,45 @@ Many flags cause us to divert before compiling anything. Flags passed after
process.argv = process.argv[0..1].concat literals
process.argv[0] = 'coffee'
- opts.output = path.resolve opts.output if opts.output
+ if opts.output
+ outputBasename = path.basename opts.output
+ if '.' in outputBasename and
+ outputBasename not in ['.', '..'] and
+ not helpers.ends(opts.output, path.sep)
+
+
+
+
+
+
+
+
+ ¶
+
+ An output filename was specified, e.g. /dist/scripts.js
.
+
+
+
+ opts.outputFilename = outputBasename
+ opts.outputPath = path.resolve path.dirname opts.output
+ else
+
+
+
+
+
+
+
+
+ ¶
+
+ An output path was specified, e.g. /dist
.
+
+
+
+ opts.outputFilename = null
+ opts.outputPath = path.resolve opts.output
+
if opts.join
opts.join = path.resolve opts.join
console.error '''
@@ -328,19 +366,19 @@ Many flags cause us to divert before compiling anything. Flags passed after
makePrelude = (requires) ->
requires.map (module) ->
- [_, name, module] = match if match = module.match(/^(.*)=(.*)$/)
- name ||= helpers.baseFileName module, yes, useWinPathSep
- "#{name} = require('#{module}')"
+ [full, name, module] = match if match = module.match(/^(.*)=(.*)$/)
+ name or= helpers.baseFileName module, yes, useWinPathSep
+ "global['#{name}'] = require('#{module}')"
.join ';'
-
+
Compile a path, which could be a script or a directory. If a directory
is passed, recursively compile all ‘.coffee’, ‘.litcoffee’, and ‘.coffee.md’
@@ -382,7 +420,7 @@ extension source files in it and all subdirectories.
code = fs.readFileSync source
catch err
if err.code is 'ENOENT' then return else throw err
- compileScript(source, code.toString(), base)
+ compileScript source, code.toString(), base
else
notSources[source] = yes
@@ -399,53 +437,56 @@ extension source files in it and all subdirectories.
-
+
Compile a single source script, containing the given code, according to the
-requested options. If evaluating the script directly sets __filename
,
+requested options. If evaluating the script directly, set __filename
,
__dirname
and module.filename
to be correct relative to the script’s path.
compileScript = (file, input, base = null) ->
- o = opts
options = compileOptions file, base
try
- t = task = {file, input, options}
+ task = {file, input, options}
CoffeeScript.emit 'compile', task
- if o.tokens
- printTokens CoffeeScript.tokens t.input, t.options
- else if o.nodes
- printLine CoffeeScript.nodes(t.input, t.options).toString().trim()
- else if o.run
+ if opts.tokens
+ printTokens CoffeeScript.tokens task.input, task.options
+ else if opts.nodes
+ printLine CoffeeScript.nodes(task.input, task.options).toString().trim()
+ else if opts.run
CoffeeScript.register()
- CoffeeScript.eval opts.prelude, t.options if opts.prelude
- CoffeeScript.run t.input, t.options
- else if o.join and t.file isnt o.join
- t.input = helpers.invertLiterate t.input if helpers.isLiterate file
- sourceCode[sources.indexOf(t.file)] = t.input
+ CoffeeScript.eval opts.prelude, task.options if opts.prelude
+ CoffeeScript.run task.input, task.options
+ else if opts.join and task.file isnt opts.join
+ task.input = helpers.invertLiterate task.input if helpers.isLiterate file
+ sourceCode[sources.indexOf(task.file)] = task.input
compileJoin()
else
- compiled = CoffeeScript.compile t.input, t.options
- t.output = compiled
- if o.map
- t.output = compiled.js
- t.sourceMap = compiled.v3SourceMap
+ compiled = CoffeeScript.compile task.input, task.options
+ task.output = compiled
+ if opts.map
+ task.output = compiled.js
+ task.sourceMap = compiled.v3SourceMap
CoffeeScript.emit 'success', task
- if o.print
- printLine t.output.trim()
- else if o.compile or o.map
- writeJs base, t.file, t.output, options.jsPath, t.sourceMap
+ if opts.print
+ printLine task.output.trim()
+ else if opts.compile or opts.map
+ saveTo = if opts.outputFilename and sources.length is 1
+ path.join opts.outputPath, opts.outputFilename
+ else
+ options.jsPath
+ writeJs base, task.file, task.output, saveTo, task.sourceMap
catch err
CoffeeScript.emit 'failure', err, task
return if CoffeeScript.listeners('failure').length
message = err?.stack or "#{err}"
- if o.watch
+ if opts.watch
printLine message + '\x07'
else
printWarn message
@@ -454,11 +495,11 @@ requested options. If evaluating the script directly sets __filename
-
+
Attach the appropriate listeners to compile scripts incoming over stdin,
and write them back to stdout.
@@ -476,11 +517,11 @@ and write them back to stdout.
-
+
If all of the source files are done being read, concatenate and compile
them together.
@@ -498,11 +539,11 @@ them together.
-
+
Watch a source CoffeeScript file using fs.watch
, recompiling it every
time the file is updated. May be used in combination with other options,
@@ -558,11 +599,11 @@ such as --print
.
-
+
Watch a directory of files for new additions.
@@ -609,11 +650,11 @@ such as --print
.
-
+
Remove a file from our source list, and source code cache. Optionally remove
the compiled JS version as well.
@@ -638,11 +679,11 @@ the compiled JS version as well.
-
+
Get the corresponding output JavaScript path for a source file.
@@ -651,22 +692,22 @@ the compiled JS version as well.
outputPath = (source, base, extension=".js") ->
basename = helpers.baseFileName source, yes, useWinPathSep
srcDir = path.dirname source
- if not opts.output
- dir = srcDir
+ dir = unless opts.outputPath
+ srcDir
else if source is base
- dir = opts.output
+ opts.outputPath
else
- dir = path.join opts.output, path.relative base, srcDir
+ path.join opts.outputPath, path.relative base, srcDir
path.join dir, basename + extension
-
+
Recursively mkdir, like mkdir -p
.
@@ -688,11 +729,11 @@ the compiled JS version as well.
-
+
Write out a JavaScript source file with the compiled code. By default, files
are written out in cwd
as .js
files with the same name, but the output
@@ -726,11 +767,11 @@ same directory as the .js
file.
-
+
Convenience for cleaner setTimeouts.
@@ -741,11 +782,11 @@ same directory as the .js
file.
-
+
When watching scripts, it’s useful to log changes with the timestamp.
@@ -757,11 +798,11 @@ same directory as the .js
file.
-
+
Pretty-print a stream of tokens, sans location data.
@@ -777,11 +818,11 @@ same directory as the .js
file.
-
+
Use the OptionParser module to extract all options from
process.argv
that are specified in SWITCHES
.
@@ -797,11 +838,11 @@ same directory as the .js
file.
-
+
The compile-time options to pass to the CoffeeScript compiler.
@@ -837,11 +878,11 @@ same directory as the .js
file.
-
+
Start up a new Node.js instance with the arguments in --nodejs
passed to
the node
binary, preserving the other options.
@@ -864,11 +905,11 @@ the node
binary, preserving the other options.
-
+
Print the --help
usage message and exit. Deprecated switches are not
shown.
@@ -881,11 +922,11 @@ shown.
-
+
Print the --version
message and exit.
diff --git a/docs/v2/annotated-source/grammar.html b/docs/v2/annotated-source/grammar.html
index 8867d22e..7d0bafd0 100644
--- a/docs/v2/annotated-source/grammar.html
+++ b/docs/v2/annotated-source/grammar.html
@@ -788,6 +788,7 @@ that hoovers up the remaining arguments.
SimpleAssignable: [
o 'Identifier', -> new Value $1
o 'Value Accessor', -> $1.add $2
+ o 'Code Accessor', -> new Value($1).add $2
o 'ThisProperty'
]
diff --git a/docs/v2/annotated-source/lexer.html b/docs/v2/annotated-source/lexer.html
index 2fe6eb2b..9d83c6db 100644
--- a/docs/v2/annotated-source/lexer.html
+++ b/docs/v2/annotated-source/lexer.html
@@ -395,7 +395,7 @@ though is
means ===
otherwise.
return id.length
if id is 'do' and regExSuper = /^(\s*super)(?!\(\))/.exec @chunk[3...]
@token 'SUPER', 'super'
- @token 'CALL_START', '('
+ @token 'CALL_START', '('
@token 'CALL_END', ')'
[input, sup] = regExSuper
return sup.length + 3
@@ -1000,7 +1000,7 @@ inwards past several recorded indents. Sets new @indent value.
@token 'OUTDENT', moveOut, 0, outdentLength
moveOut -= dent
@outdebt -= moveOut if dent
- @tokens.pop() while @value() is ';'
+ @suppressSemicolons()
@token 'TERMINATOR', '\n', outdentLength, 0 unless @tag() is 'TERMINATOR' or noNewlines
@indent = decreasedIndent
@@ -1042,7 +1042,7 @@ as being “spaced”, because there are some cases where it makes a difference.
newlineToken: (offset) ->
- @tokens.pop() while @value() is ';'
+ @suppressSemicolons()
@token 'TERMINATOR', '\n', offset, 0 unless @tag() is 'TERMINATOR'
this
@@ -1278,9 +1278,10 @@ parentheses that indicate a method call from regular parentheses, and so on.
@exportSpecifierList = no
if value is ';'
+ @error 'unexpected ;' if prev?[0] in ['=', UNFINISHED...]
@seenFor = @seenImport = @seenExport = no
tag = 'TERMINATOR'
- else if value is '*' and prev[0] is 'EXPORT'
+ else if value is '*' and prev?[0] is 'EXPORT'
tag = 'EXPORT_ALL'
else if value in MATH then tag = 'MATH'
else if value in COMPARE then tag = 'COMPARE'
@@ -1289,11 +1290,12 @@ parentheses that indicate a method call from regular parentheses, and so on.
else if value in UNARY_MATH then tag = 'UNARY_MATH'
else if value in SHIFT then tag = 'SHIFT'
else if value is '?' and prev?.spaced then tag = 'BIN?'
- else if prev and not prev.spaced
- if value is '(' and prev[0] in CALLABLE
+ else if prev
+ if value is '(' and not prev.spaced and prev[0] in CALLABLE
prev[0] = 'FUNC_EXIST' if prev[0] is '?'
tag = 'CALL_START'
- else if value is '[' and prev[0] in INDEXABLE
+ else if value is '[' and ((prev[0] in INDEXABLE and not prev.spaced) or
+ (prev[0] is '::')) # `.prototype` can’t be a method you can call.
tag = 'INDEX_START'
switch prev[0]
when '?' then prev[0] = 'INDEX_SOAK'
@@ -1590,7 +1592,8 @@ of 'NEOSTRING'
s are converted using fn
and tur
for token, i in tokens
[tag, value] = token
switch tag
- when 'TOKENS'
+ when 'TOKENS'
+ if value.length is 2
@@ -1605,7 +1608,7 @@ of 'NEOSTRING'
s are converted using fn
and tur
- continue if value.length is 2
+ continue unless value[0].comments or value[1].comments
@@ -1616,6 +1619,59 @@ of 'NEOSTRING'
s are converted using fn
and tur
+ There are comments (and nothing else) in this interpolation.
+
+
+
+ if @csxDepth is 0
+
+
+
+
+
+
+
+
+ ¶
+
+ This is an interpolated string, not a CSX tag; and for whatever
+reason `a${/*test*/}b`
is invalid JS. So compile to
+`a${/*test*/''}b`
instead.
+
+
+
+ placeholderToken = @makeToken 'STRING', "''"
+ else
+ placeholderToken = @makeToken 'JS', ''
+
+
+
+
+
+
+
+
+ ¶
+
+ Use the same location data as the first parenthesis.
+
+
+
+ placeholderToken[2] = value[0][2]
+ for val in value when val.comments
+ placeholderToken.comments ?= []
+ placeholderToken.comments.push val.comments...
+ value.splice 1, 0, placeholderToken
+
+
+
+
+
+
+
+
+ ¶
+
Push all the tokens in the fake 'TOKENS'
token. These already have
sane location data.
@@ -1628,11 +1684,11 @@ sane location data.
-
+
Convert 'NEOSTRING'
into 'STRING'
.
@@ -1643,11 +1699,11 @@ sane location data.
-
+
Optimize out empty strings. We ensure that the tokens stream always
starts with a string token, though, to make sure that the result
@@ -1664,11 +1720,11 @@ really is a string.
-
+
However, there is one case where we can optimize away a starting
empty string.
@@ -1686,11 +1742,11 @@ empty string.
-
+
Create a 0-length “+” token.
@@ -1723,11 +1779,11 @@ empty string.
-
+
Pairs up a closing token, ensuring that all listed pairs of tokens are
correctly balanced throughout the course of the token stream.
@@ -1742,11 +1798,11 @@ correctly balanced throughout the course of the token stream.
-
+
Auto-close INDENT
to support syntax like this:
el.click((event) ->
@@ -1762,11 +1818,11 @@ correctly balanced throughout the course of the token stream.
-
+
Helpers
@@ -1775,11 +1831,11 @@ correctly balanced throughout the course of the token stream.
-
+
@@ -1787,11 +1843,11 @@ correctly balanced throughout the course of the token stream.
-
+
Returns the line and column number from an offset into the current chunk.
offset
is a number of characters into @chunk
.
@@ -1821,11 +1877,11 @@ correctly balanced throughout the course of the token stream.
-
+
Same as token
, except this just returns the token without adding it
to the results.
@@ -1840,11 +1896,11 @@ to the results.
-
+
Use length - 1 for the final offset - we’re supplying the last_line and the last_column,
so if last_column == first_column, then we’re looking at a character of length 1.
@@ -1862,11 +1918,11 @@ so if last_column == first_column, then we’re looking at a character of length
-
+
Add a token to the results.
offset
is the offset into the current @chunk
where the token starts.
@@ -1885,11 +1941,11 @@ not specified, the length of value
will be used.
-
+
Peek at the last tag in the token stream.
@@ -1902,11 +1958,11 @@ not specified, the length of value
will be used.
-
+
Peek at the last value in the token stream.
@@ -1919,11 +1975,11 @@ not specified, the length of value
will be used.
-
+
Get the previous token in the token stream.
@@ -1935,11 +1991,11 @@ not specified, the length of value
will be used.
-
+
Are we in the midst of an unfinished expression?
@@ -1967,11 +2023,11 @@ not specified, the length of value
will be used.
-
+
surrogate pair
@@ -1984,11 +2040,11 @@ not specified, the length of value
will be used.
-
+
Replace \u{...}
with \uxxxx[\uxxxx]
in regexes without u
flag
@@ -2011,11 +2067,11 @@ not specified, the length of value
will be used.
-
+
Validates escapes in strings and regexes.
@@ -2043,11 +2099,11 @@ not specified, the length of value
will be used.
-
+
Constructs a string or regex by escaping certain characters.
@@ -2067,11 +2123,11 @@ not specified, the length of value
will be used.
-
+
+ "#{options.delimiter}#{body}#{options.delimiter}"
+
+ suppressSemicolons: ->
+ while @value() is ';'
+ @tokens.pop()
+ @error 'unexpected ;' if @prev()?[0] in ['=', UNFINISHED...]
-
+
Throws an error at either a given offset from the current chunk or at the
location of a token (token[2]
).
@@ -2113,11 +2174,11 @@ location of a token (token[2]
).
-
+
-
+
from
isn’t a CoffeeScript keyword, but it behaves like one in import
and
export
statements (handled above) and in the declaration line of a for
@@ -2170,11 +2231,11 @@ loop. Try to detect when from
is a variable identifier and when it
-
+
for i from from
, for from from iterable
@@ -2187,11 +2248,11 @@ loop. Try to detect when from
is a variable identifier and when it
-
+
for i from iterable
@@ -2202,11 +2263,11 @@ loop. Try to detect when from
is a variable identifier and when it
-
+
for from…
@@ -2218,11 +2279,11 @@ loop. Try to detect when from
is a variable identifier and when it
-
+
for {from}…
, for [from]…
, for {a, from}…
, for {a: from}…
@@ -2236,11 +2297,11 @@ loop. Try to detect when from
is a variable identifier and when it
-
+
Constants
@@ -2249,11 +2310,11 @@ loop. Try to detect when from
is a variable identifier and when it
-
+
@@ -2261,11 +2322,11 @@ loop. Try to detect when from
is a variable identifier and when it
-
+
-
+
The list of keywords that are reserved by JavaScript, but not used, or are
used by CoffeeScript internally. We throw an error when these are encountered,
@@ -2338,11 +2399,11 @@ STRICT_PROSCRIBED = ['arguments',
+
The superset of both JavaScript keywords and reserved words, none of which may
be used as identifiers or properties.
@@ -2354,11 +2415,11 @@ be used as identifiers or properties.
-
+
The character code of the nasty Microsoft madness otherwise known as the BOM.
@@ -2369,11 +2430,11 @@ be used as identifiers or properties.
-
+
Token matching regexes.
@@ -2427,11 +2488,11 @@ HERE_JSTOKEN = ///^ ``` ((?: [^`\\] | \\[\s\S] | `
-
+
String-matching-regexes.
@@ -2465,11 +2526,11 @@ HEREDOC_INDENT = /\n+([^\n\S]*)(?=\S)/g
-
+
-
+
-
+
Unary tokens.
@@ -2585,11 +2646,11 @@ UNARY_MATH = ['!', '~
-
+
Bit-shifting tokens.
@@ -2600,11 +2661,11 @@ UNARY_MATH = ['!', '~
-
+
Comparison tokens.
@@ -2615,11 +2676,11 @@ UNARY_MATH = ['!', '~
-
+
Mathematical tokens.
@@ -2630,11 +2691,11 @@ UNARY_MATH = ['!', '~
-
+
Relational tokens that are negatable with not
prefix.
@@ -2645,11 +2706,11 @@ UNARY_MATH = ['!', '~
-
+
Boolean tokens.
@@ -2660,11 +2721,11 @@ UNARY_MATH = ['!', '~
-
+
Tokens which could legitimately be invoked or indexed. An opening
parentheses or bracket following these tokens will be recorded as the start
@@ -2681,11 +2742,11 @@ INDEXABLE = CALLABLE.concat [
-
+
Tokens which can be the left-hand side of a less-than comparison, i.e. a<b
.
@@ -2696,11 +2757,11 @@ INDEXABLE = CALLABLE.concat [
-
+
Tokens which a regular expression will never immediately follow (except spaced
CALLABLEs in some cases), but which a division operator can.
@@ -2713,11 +2774,11 @@ CALLABLEs in some cases), but which a division operator can.
-
+
Tokens that, when immediately preceding a WHEN
, indicate that the WHEN
occurs at the start of a line. We disambiguate these from trailing whens to
@@ -2730,11 +2791,11 @@ avoid an ambiguity in the grammar.
-
+
Additional indent in front of these is ignored.
@@ -2745,11 +2806,11 @@ avoid an ambiguity in the grammar.
-
+
Tokens that, when appearing at the end of a line, suppress a following TERMINATOR/INDENT token
diff --git a/docs/v2/annotated-source/nodes.html b/docs/v2/annotated-source/nodes.html
index 41d7f4fb..a0571876 100644
--- a/docs/v2/annotated-source/nodes.html
+++ b/docs/v2/annotated-source/nodes.html
@@ -356,7 +356,10 @@ return results).
else
node.compileClosure o
@compileCommentFragments o, node, fragments
- fragments
+ fragments
+
+ compileToFragmentsWithoutComments: (o, lvl) ->
+ @compileWithoutComments o, lvl, 'compileToFragments'
@@ -1715,15 +1718,13 @@ exports.NaNLiteral = class
exports.StringLiteral = class StringLiteral extends Literal
compileNode: (o) ->
- res = if @csx then [@makeCode @unquote yes] else super()
+ res = if @csx then [@makeCode @unquote(yes, yes)] else super()
- unquote: (literal) ->
+ unquote: (doubleQuote = no, newLine = no) ->
unquoted = @value[1...-1]
- if literal
- unquoted.replace /\\n/g, '\n'
- .replace /\\"/g, '"'
- else
- unquoted
+ unquoted = unquoted.replace /\\"/g, '"' if doubleQuote
+ unquoted = unquoted.replace /\\n/g, '\n' if newLine
+ unquoted
exports.RegexLiteral = class RegexLiteral extends Literal
@@ -3288,7 +3289,8 @@ are too.
propSlices.push prop
addSlice()
slices.unshift new Obj unless slices[0] instanceof Obj
- (new Call new Literal('Object.assign'), slices).compileToFragments o
+ _extends = new Value new Literal utility '_extends', o
+ (new Call _extends, slices).compileToFragments o
compileCSXAttributes: (o) ->
props = @properties
@@ -4209,8 +4211,9 @@ destructured variables.
- return @compileObjectDestruct(o) if @variable.isObject() and @variable.contains (node) ->
+ objDestructAnswer = @compileObjectDestruct(o) if @variable.isObject() and @variable.contains (node) ->
node instanceof Obj and node.hasSplat()
+ return objDestructAnswer if objDestructAnswer
return @compileSplice o if @variable.isSplice()
return @compileConditional o if @context in ['||=', '&&=', '?=']
@@ -4389,8 +4392,10 @@ e.g. {[properties...]} = source
.
traverseRest = (properties, source) =>
restElements = []
restIndex = undefined
+ source = new Value source unless source.properties?
for prop, index in properties
+ nestedSourceDefault = nestedSource = nestedProperties = null
setScopeVar prop.unwrap()
if prop instanceof Assign
@@ -4418,6 +4423,21 @@ e.g. {[properties...]} = source
.
+ prop is k = {...}
+
+
+
+ continue unless prop.context is 'object'
+
+
+
+
+
+
+
+
+ ¶
+
prop is k: {...}
@@ -4428,11 +4448,11 @@ e.g. {[properties...]} = source
.
-
+
prop is k: {...} = default
@@ -4458,11 +4478,11 @@ e.g. {[properties...]} = source
.
-
+
Remove rest element from the properties after iteration
@@ -4475,34 +4495,40 @@ e.g. {[properties...]} = source
.
-
-
-
-
- ¶
-
- Cache the value for reuse with rest elements
-
-
-
- [@value, valueRef] = @value.cache o
-
-
-
-
+ Cache the value for reuse with rest elements.
+
+
+
+ if @value.shouldCache()
+ valueRefTemp = new IdentifierLiteral o.scope.freeVariable 'ref', reserve: false
+ else
+ valueRefTemp = @value.base
+
+
+
+
+
+
+
+
+ ¶
+
Find all rest elements.
- restElements = traverseRest @variable.base.properties, valueRef
+ restElements = traverseRest @variable.base.properties, valueRefTemp
+ return no unless restElements and restElements.length > 0
+ [@value, valueRef] = @value.cache o
result = new Block [@]
+
for restElement in restElements
value = new Call new Value(new Literal utility 'objectWithoutKeys', o), [restElement.source, restElement.excludeProps]
result.push new Assign restElement.name, value
@@ -4513,11 +4539,11 @@ e.g. {[properties...]} = source
.
-
+
Remove leading tab and trailing semicolon
@@ -4531,11 +4557,11 @@ e.g. {[properties...]} = source
.
-
+
Brief implementation of recursive pattern matching, when assigning array or
object literals to a value. Peeks at their properties to assign inner names.
@@ -4551,11 +4577,11 @@ object literals to a value. Peeks at their properties to assign inner names.
-
+
Special-case for {} = a
and [] = a
(empty patterns).
Compile to simply a
.
@@ -4570,11 +4596,11 @@ Compile to simply a
.
-
+
Disallow [...] = a
for some reason. (Could be equivalent to [] = a
?)
@@ -4588,11 +4614,11 @@ Compile to simply a
.
-
+
Special case for when there’s only one thing destructured off of
something. {a} = b
, [a] = b
, {a: b} = c
@@ -4604,11 +4630,11 @@ something. {a} = b
, [a] = b
, {a: b} = c
-
+
Pick the property straight off the value when there’s just one to pick
(no need to cache the value into a variable).
@@ -4621,11 +4647,11 @@ something. {a} = b
, [a] = b
, {a: b} = c
-
+
A regular object pattern-match.
@@ -4644,11 +4670,11 @@ something. {a} = b
, [a] = b
, {a: b} = c
-
+
A shorthand {a, b, @c} = val
pattern-match.
@@ -4663,11 +4689,11 @@ something. {a} = b
, [a] = b
, {a: b} = c
-
+
A regular array pattern-match.
@@ -4692,11 +4718,11 @@ something. {a} = b
, [a] = b
, {a: b} = c
-
+
At this point, there are several things to destructure. So the fn()
in
{a, b} = fn()
must be cached, for example. Make vvar into a simple
@@ -4713,11 +4739,11 @@ variable if it isn’t already.
-
+
And here comes the big loop that handles all of these cases:
[a, b] = c
@@ -4766,11 +4792,11 @@ etc.
-
+
A regular object pattern-match.
@@ -4789,11 +4815,11 @@ etc.
-
+
A shorthand {a, b, @c} = val
pattern-match.
@@ -4808,11 +4834,11 @@ etc.
-
+
A regular array pattern-match.
@@ -4837,11 +4863,11 @@ etc.
-
+
When compiling a conditional assignment, take care to ensure that the
operands are only evaluated once, even though we have to reference them
@@ -4855,11 +4881,11 @@ more than once.
-
+
Disallow conditional assignment of undefined variables.
@@ -4878,11 +4904,11 @@ more than once.
-
+
Convert special math assignment operators like a **= b
to the equivalent
extended form a = a ** b
and then compiles that.
@@ -4896,11 +4922,11 @@ extended form a = a ** b
and then compiles that.
-
+
Compile the assignment from an array splice literal, using JavaScript’s
Array#splice
method.
@@ -4937,11 +4963,11 @@ extended form a = a ** b
and then compiles that.
-
+
FuncGlyph
@@ -4955,11 +4981,11 @@ exports.FuncGlyph = class
-
+
Code
@@ -4968,11 +4994,11 @@ exports.FuncGlyph = class
-
+
A function definition. This is the only node that creates a new Scope.
When for the purposes of walking the contents of a function body, the Code
@@ -5010,11 +5036,11 @@ has no children – they’re within the inner scope.
-
+
Compilation creates a new scope unless explicitly asked to share with the
outer scope. Handles splat parameters in the parameter list by setting
@@ -5049,11 +5075,11 @@ function body.
-
+
Check for duplicate parameters and separate this
assignments.
@@ -5073,11 +5099,11 @@ function body.
-
+
Parse the parameters, adding them to the list of parameters to put in the
function definition; and dealing with splats or expansions, including
@@ -5095,11 +5121,11 @@ any non-idempotent parameters are evaluated in the correct order.
-
+
Was ...
used with this parameter? (Only one such parameter is allowed
per function.) Splat/expansion parameters cannot have default values,
@@ -5119,11 +5145,11 @@ so we need not worry about that.
-
+
Splat arrays are treated oddly by ES; deal with them the legacy
way in the function body. TODO: Should this be handled in the
@@ -5148,11 +5174,11 @@ function parameter list, and if so, how?
-
+
Parse all other parameters; if a splat paramater has not yet been
encountered, add these other parameters to the list to be output in
@@ -5168,11 +5194,11 @@ the function definition.
-
+
This parameter cannot be declared or assigned in the parameter
list. So put a reference in the parameter list and add a statement
@@ -5191,11 +5217,11 @@ to the function body assigning it, e.g.
-
+
If this parameter comes before the splat or expansion, it will go
in the function definition parameter list.
@@ -5207,11 +5233,11 @@ in the function definition parameter list.
-
+
If this parameter has a default value, and it hasn’t already been
set by the shouldCache()
block above, define it as a statement in
@@ -5231,11 +5257,11 @@ so we can’t define its default value in the parameter list.
-
+
Add this parameter’s reference(s) to the function scope.
@@ -5246,11 +5272,11 @@ so we can’t define its default value in the parameter list.
-
+
This parameter is destructured.
@@ -5263,11 +5289,11 @@ so we can’t define its default value in the parameter list.
-
+
Compile foo({a, b...}) ->
to foo(arg) -> {a, b...} = arg
.
Can be removed once ES proposal hits Stage 4.
@@ -5283,11 +5309,11 @@ Can be removed once ES proposal hits Stage 4.
-
+
Compile foo({a, b...} = {}) ->
to foo(arg = {}) -> {a, b...} = arg
.
@@ -5300,11 +5326,11 @@ Can be removed once ES proposal hits Stage 4.
-
+
This compilation of the parameter is only to get its name to add
to the scope name tracking; since the compilation output here
@@ -5315,11 +5341,7 @@ is compiled.
paramToAddToScope = if param.value? then param else ref
- if paramToAddToScope.name?.comments
- salvagedComments = paramToAddToScope.name.comments
- delete paramToAddToScope.name.comments
- o.scope.parameter fragmentsToText paramToAddToScope.compileToFragments o
- paramToAddToScope.name.comments = salvagedComments if salvagedComments
+ o.scope.parameter fragmentsToText paramToAddToScope.compileToFragmentsWithoutComments o
params.push ref
else
paramsAfterSplat.push param
@@ -5327,11 +5349,11 @@ is compiled.
-
+
If this parameter had a default value, since it’s no longer in the
function parameter list we need to assign its default value
@@ -5347,11 +5369,11 @@ function parameter list we need to assign its default value
-
+
Add this parameter to the scope, since it wouldn’t have been added
yet since it was skipped earlier.
@@ -5363,11 +5385,11 @@ yet since it was skipped earlier.
-
+
If there were parameters after the splat or expansion parameter, those
parameters need to be assigned in the body of the function.
@@ -5379,11 +5401,11 @@ parameters need to be assigned in the body of the function.
-
+
Create a destructured assignment, e.g. [a, b, c] = [args..., b, c]
@@ -5396,11 +5418,11 @@ parameters need to be assigned in the body of the function.
-
+
Add new expressions to the function body
@@ -5417,11 +5439,11 @@ parameters need to be assigned in the body of the function.
-
+
Assemble the output
@@ -5438,18 +5460,38 @@ parameters need to be assigned in the body of the function.
signature = [@makeCode '(']
for param, i in params
signature.push @makeCode ', ' if i isnt 0
- signature.push @makeCode '...' if haveSplatParam and i is params.length - 1
+ signature.push @makeCode '...' if haveSplatParam and i is params.length - 1
+
+
+
+
+
+
+
+
+ ¶
+
+ Compile this parameter, but if any generated variables get created
+(e.g. ref
), shift those into the parent scope since we can’t put a
+var
line inside a function parameter list.
+
+
+
+ scopeVariablesCount = o.scope.variables.length
signature.push param.compileToFragments(o)...
+ if scopeVariablesCount isnt o.scope.variables.length
+ generatedVariables = o.scope.variables.splice scopeVariablesCount
+ o.scope.parent.variables.push generatedVariables...
signature.push @makeCode ')'
-
+
Block comments between )
and ->
/=>
get output between )
and {
.
@@ -5464,11 +5506,11 @@ parameters need to be assigned in the body of the function.
-
+
We need to compile the body before method names to ensure super
references are handled.
@@ -5499,11 +5541,11 @@ references are handled.
-
+
Short-circuit traverseChildren
method to prevent it from crossing scope
boundaries unless crossScope
is true
.
@@ -5516,11 +5558,11 @@ boundaries unless crossScope
is true
.
-
+
Short-circuit replaceInContext
method to prevent it from crossing context boundaries. Bound
functions have the same context.
@@ -5553,11 +5595,11 @@ functions have the same context.
-
+
Find all super calls in the given context node
Returns true
if iterator
is called
@@ -5577,11 +5619,11 @@ Returns true
if iterator
is called
-
+
super
has the same target in bound (arrow) functions, so check them too
@@ -5594,11 +5636,11 @@ Returns true
if iterator
is called
-
+
Param
@@ -5607,11 +5649,11 @@ Returns true
if iterator
is called
-
+
A parameter in a function definition. Beyond a typical JavaScript parameter,
these parameters can also attach themselves to the context of the function,
@@ -5634,6 +5676,9 @@ as well as be a splat, gathering up a group of parameters into an array.
compileToFragments: (o) ->
@name.compileToFragments o, LEVEL_LIST
+ compileToFragmentsWithoutComments: (o) ->
+ @name.compileToFragmentsWithoutComments o, LEVEL_LIST
+
asReference: (o) ->
return @reference if @reference
node = @name
@@ -5653,11 +5698,11 @@ as well as be a splat, gathering up a group of parameters into an array.
-
+
Iterates the name or names of a Param
.
In a sense, a destructured parameter represents multiple JS parameters. This
@@ -5674,11 +5719,11 @@ to that name.
-
+
- simple literals
foo
@@ -5691,11 +5736,11 @@ to that name.
- -
+
-
- at-params
@foo
@@ -5709,11 +5754,11 @@ to that name.
- -
+
-
- destructured parameter with default value
@@ -5727,11 +5772,11 @@ to that name.
- -
+
-
- assignments within destructured parameters
{foo:bar}
@@ -5744,11 +5789,11 @@ to that name.
- -
+
-
… possibly with a default value
@@ -5763,11 +5808,11 @@ to that name.
- -
+
-
- splats within destructured parameters
[xs...]
@@ -5783,11 +5828,11 @@ to that name.
- -
+
-
- destructured parameters within destructured parameters
[{a}]
@@ -5801,11 +5846,11 @@ to that name.
- -
+
-
- at-params within destructured parameters
{@foo}
@@ -5819,11 +5864,11 @@ to that name.
- -
+
-
- simple destructured parameters {foo}
@@ -5839,11 +5884,11 @@ to that name.
- -
+
-
Rename a param by replacing the given AST node for a name with a new node.
This needs to ensure that the the source for object destructuring does not change.
@@ -5865,60 +5910,13 @@ This needs to ensure that the the source for object destructuring does not chang
- -
-
-
-
- ¶
-
-
Splat
-
-
-
-
-
-
- -
-
-
-
- ¶
-
-
A splat, either as a parameter to a function, an argument to a call,
-or as part of a destructuring assignment.
-
-
-
- exports.Splat = class Splat extends Base
-
- children: ['name']
-
- isAssignable: ->
- @name.isAssignable() and (not @name.isAtomic or @name.isAtomic())
-
- constructor: (name) ->
- super()
- @name = if name.compile then name else new Literal name
-
- assigns: (name) ->
- @name.assigns name
-
- compileToFragments: (o) ->
- [ @makeCode('...')
- @name.compileToFragments(o)... ]
-
- unwrap: -> @name
-
-
-
-
-
@@ -5931,6 +5929,51 @@ or as part of a destructuring assignment.
+
A splat, either as a parameter to a function, an argument to a call,
+or as part of a destructuring assignment.
+
+
+
+ exports.Splat = class Splat extends Base
+ constructor: (name) ->
+ super()
+ @name = if name.compile then name else new Literal name
+
+ children: ['name']
+
+ isAssignable: ->
+ @name.isAssignable() and (not @name.isAtomic or @name.isAtomic())
+
+ assigns: (name) ->
+ @name.assigns name
+
+ compileNode: (o) ->
+ [@makeCode('...'), @name.compileToFragments(o, LEVEL_OP)...]
+
+ unwrap: -> @name
+
+
+
+
+ -
+
+
+
+ ¶
+
+
Expansion
+
+
+
+
+
+
+ -
+
+
+
+ ¶
+
Used to skip values inside an array destructuring (pattern matching) or
parameter list.
@@ -5951,11 +5994,11 @@ parameter list.
- -
+
-
While
@@ -5964,11 +6007,11 @@ parameter list.
- -
+
-
A while loop, the only sort of low-level loop exposed by CoffeeScript. From
it, all other loops can be manufactured. Useful in cases where you need more
@@ -6007,11 +6050,11 @@ flexibility or more speed than a comprehension can provide.
- -
+
-
The main difference from a JavaScript while is that the CoffeeScript
while can be used as a part of a larger expression – while loops may
@@ -6044,11 +6087,11 @@ return an array containing the computed result of each iteration.
- -
+
-