mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-13 16:57:54 -05:00
Compare commits
35 Commits
2.0.0-beta
...
2.0.0-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df9d4a2343 | ||
|
|
9e043bbae7 | ||
|
|
671486989f | ||
|
|
4a4f752204 | ||
|
|
b20e52da99 | ||
|
|
5525b2ba01 | ||
|
|
fe5ff39ca2 | ||
|
|
906bedf93a | ||
|
|
6f961a20dd | ||
|
|
e54b8a1009 | ||
|
|
d7d69a4a18 | ||
|
|
eb38dba5d6 | ||
|
|
9ff82fe17b | ||
|
|
5713b7eb6c | ||
|
|
7c627f9dfd | ||
|
|
c81e2d4767 | ||
|
|
3dd458267b | ||
|
|
892c4699dd | ||
|
|
40c351135a | ||
|
|
a3b08e1bef | ||
|
|
44a27c6204 | ||
|
|
c212e6e9ab | ||
|
|
5a709ed4a8 | ||
|
|
2491d3286d | ||
|
|
1a6477adec | ||
|
|
2149c3561b | ||
|
|
232041db2a | ||
|
|
4623bf5bba | ||
|
|
2664c2c108 | ||
|
|
f9367bacf1 | ||
|
|
aef54aeaf7 | ||
|
|
eff160eeb7 | ||
|
|
911c21f7be | ||
|
|
52795587ec | ||
|
|
3a6ffa6a85 |
62
Cakefile
62
Cakefile
@@ -341,11 +341,15 @@ task 'doc:source:watch', 'watch and continually rebuild the annotated source doc
|
||||
|
||||
|
||||
task 'release', 'build and test the CoffeeScript source, and build the documentation', ->
|
||||
invoke 'build:full'
|
||||
invoke 'build:browser:full'
|
||||
invoke 'doc:site'
|
||||
invoke 'doc:test'
|
||||
invoke 'doc:source'
|
||||
execSync '''
|
||||
cake build:full
|
||||
cake build:browser
|
||||
cake test:browser
|
||||
cake test:integrations
|
||||
cake doc:site
|
||||
cake doc:test
|
||||
cake doc:source''', stdio: 'inherit'
|
||||
|
||||
|
||||
task 'bench', 'quick benchmark of compilation time', ->
|
||||
{Rewriter} = require './lib/coffeescript/rewriter'
|
||||
@@ -372,7 +376,6 @@ task 'bench', 'quick benchmark of compilation time', ->
|
||||
# Run the CoffeeScript test suite.
|
||||
runTests = (CoffeeScript) ->
|
||||
CoffeeScript.register() unless global.testingBrowser
|
||||
startTime = Date.now()
|
||||
|
||||
# These are attached to `global` so that they’re accessible from within
|
||||
# `test/async.coffee`, which has an async-capable version of
|
||||
@@ -392,18 +395,35 @@ runTests = (CoffeeScript) ->
|
||||
global.yellow = yellow
|
||||
global.reset = reset
|
||||
|
||||
asyncTests = []
|
||||
onFail = (description, fn, err) ->
|
||||
failures.push
|
||||
filename: global.currentFile
|
||||
error: err
|
||||
description: description
|
||||
source: fn.toString() if fn.toString?
|
||||
|
||||
# Our test helper function for delimiting different test cases.
|
||||
global.test = (description, fn) ->
|
||||
try
|
||||
fn.test = {description, currentFile}
|
||||
fn.call(fn)
|
||||
++passedTests
|
||||
catch e
|
||||
failures.push
|
||||
filename: currentFile
|
||||
error: e
|
||||
description: description if description?
|
||||
source: fn.toString() if fn.toString?
|
||||
result = fn.call(fn)
|
||||
if result instanceof Promise # An async test.
|
||||
asyncTests.push result
|
||||
result.then ->
|
||||
passedTests++
|
||||
.catch (err) ->
|
||||
onFail description, fn, err
|
||||
else
|
||||
passedTests++
|
||||
catch err
|
||||
onFail description, fn, err
|
||||
|
||||
global.supportsAsync = try
|
||||
new Function('async () => {}')()
|
||||
yes
|
||||
catch
|
||||
no
|
||||
|
||||
helpers.extend global, require './test/support/helpers'
|
||||
|
||||
@@ -424,7 +444,10 @@ runTests = (CoffeeScript) ->
|
||||
|
||||
# Run every test in the `test` folder, recording failures.
|
||||
files = fs.readdirSync 'test'
|
||||
unless global.supportsAsync # Except for async tests, if async isn’t supported.
|
||||
files = files.filter (filename) -> filename isnt 'async.coffee'
|
||||
|
||||
startTime = Date.now()
|
||||
for file in files when helpers.isCoffee file
|
||||
literate = helpers.isLiterate file
|
||||
currentFile = filename = path.join 'test', file
|
||||
@@ -433,12 +456,13 @@ runTests = (CoffeeScript) ->
|
||||
CoffeeScript.run code.toString(), {filename, literate}
|
||||
catch error
|
||||
failures.push {filename, error}
|
||||
return !failures.length
|
||||
|
||||
Promise.all(asyncTests).then ->
|
||||
Promise.reject() if failures.length isnt 0
|
||||
|
||||
|
||||
task 'test', 'run the CoffeeScript language test suite', ->
|
||||
testResults = runTests CoffeeScript
|
||||
process.exit 1 unless testResults
|
||||
runTests(CoffeeScript).catch -> process.exit 1
|
||||
|
||||
|
||||
task 'test:browser', 'run the test suite against the merged browser script', ->
|
||||
@@ -446,8 +470,8 @@ task 'test:browser', 'run the test suite against the merged browser script', ->
|
||||
result = {}
|
||||
global.testingBrowser = yes
|
||||
(-> eval source).call result
|
||||
testResults = runTests result.CoffeeScript
|
||||
process.exit 1 unless testResults
|
||||
runTests(CoffeeScript).catch -> process.exit 1
|
||||
|
||||
|
||||
task 'test:integrations', 'test the module integrated with other libraries and environments', ->
|
||||
# Tools like Webpack and Browserify generate builds intended for a browser
|
||||
|
||||
@@ -159,7 +159,7 @@ evaluated from <code>lib/coffeescript</code>.</p>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>exports.VERSION = packageJson.version
|
||||
|
||||
exports.FILE_EXTENSIONS = [<span class="hljs-string">'.coffee'</span>, <span class="hljs-string">'.litcoffee'</span>, <span class="hljs-string">'.coffee.md'</span>]</pre></div></div>
|
||||
exports.FILE_EXTENSIONS = 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>
|
||||
|
||||
@@ -252,7 +252,7 @@ didn’t create a source map (faster) but something went wrong and we need
|
||||
a stack trace. Assuming that most of the time, code isn’t throwing
|
||||
exceptions, it’s probably more efficient to compile twice only when we
|
||||
need a stack trace, rather than always generating a source map even when
|
||||
it’s not likely to be used. Save in form of <code>filename</code>: <code>(source)</code></p>
|
||||
it’s not likely to be used. Save in form of <code>filename</code>: [<code>(source)</code>]</p>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -267,7 +267,7 @@ it’s not likely to be used. Save in form of <code>filename</code>: <code>(sour
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-9">¶</a>
|
||||
</div>
|
||||
<p>Also save source maps if generated, in form of <code>filename</code>: <code>(source map)</code>.</p>
|
||||
<p>Also save source maps if generated, in form of <code>(source)</code>: [<code>(source map)</code>].</p>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -317,7 +317,8 @@ we need to recompile it to get a source map for <code>prepareStackTrace</code>.<
|
||||
|
||||
checkShebangLine filename, code
|
||||
|
||||
sources[filename] = code
|
||||
sources[filename] ?= []
|
||||
sources[filename].push code
|
||||
map = <span class="hljs-keyword">new</span> SourceMap <span class="hljs-keyword">if</span> generateSourceMap
|
||||
|
||||
tokens = lexer.tokenize code, options</pre></div></div>
|
||||
@@ -428,8 +429,9 @@ the same name.</p>
|
||||
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> generateSourceMap
|
||||
v3SourceMap = map.generate(options, code)
|
||||
sourceMaps[filename] = map
|
||||
v3SourceMap = map.generate options, code
|
||||
sourceMaps[filename] ?= []
|
||||
sourceMaps[filename].push map
|
||||
|
||||
<span class="hljs-keyword">if</span> options.inlineMap
|
||||
encoded = base64encode JSON.stringify v3SourceMap
|
||||
@@ -701,9 +703,7 @@ Modified to handle sourceMap</p>
|
||||
<span class="hljs-keyword">else</span>
|
||||
fileLocation
|
||||
<span class="hljs-function">
|
||||
<span class="hljs-title">getSourceMap</span> = <span class="hljs-params">(filename)</span> -></span>
|
||||
<span class="hljs-keyword">if</span> sourceMaps[filename]?
|
||||
sourceMaps[filename]</pre></div></div>
|
||||
<span class="hljs-title">getSourceMap</span> = <span class="hljs-params">(filename, line, column)</span> -></span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -714,22 +714,15 @@ Modified to handle sourceMap</p>
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-28">¶</a>
|
||||
</div>
|
||||
<p>CoffeeScript compiled in a browser may get compiled with <code>options.filename</code>
|
||||
of <code><anonymous></code>, but the browser may request the stack trace with the
|
||||
filename of the script file.</p>
|
||||
<p>Skip files that we didn’t compile, like Node system files that appear in
|
||||
the stack trace, as they never have source maps.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> sourceMaps[<span class="hljs-string">'<anonymous>'</span>]?
|
||||
sourceMaps[<span class="hljs-string">'<anonymous>'</span>]
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> sources[filename]?
|
||||
answer = compile sources[filename],
|
||||
filename: filename
|
||||
sourceMap: <span class="hljs-literal">yes</span>
|
||||
literate: helpers.isLiterate filename
|
||||
answer.sourceMap
|
||||
<span class="hljs-keyword">else</span>
|
||||
<span class="hljs-literal">null</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">unless</span> filename <span class="hljs-keyword">is</span> <span class="hljs-string">'<anonymous>'</span> <span class="hljs-keyword">or</span> filename.slice(filename.lastIndexOf(<span class="hljs-string">'.'</span>)) <span class="hljs-keyword">in</span> FILE_EXTENSIONS
|
||||
|
||||
<span class="hljs-keyword">if</span> filename <span class="hljs-keyword">isnt</span> <span class="hljs-string">'<anonymous>'</span> <span class="hljs-keyword">and</span> sourceMaps[filename]?
|
||||
<span class="hljs-keyword">return</span> sourceMaps[filename][sourceMaps[filename].length - <span class="hljs-number">1</span>]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -740,6 +733,73 @@ filename of the script file.</p>
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-29">¶</a>
|
||||
</div>
|
||||
<p>CoffeeScript compiled in a browser or via <code>CoffeeScript.compile</code> or <code>.run</code>
|
||||
may get compiled with <code>options.filename</code> that’s missing, which becomes
|
||||
<code><anonymous></code>; but the runtime might request the stack trace with the
|
||||
filename of the script file. See if we have a source map cached under
|
||||
<code><anonymous></code> that matches the error.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> sourceMaps[<span class="hljs-string">'<anonymous>'</span>]?</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-30">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-30">¶</a>
|
||||
</div>
|
||||
<p>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. <code>frame.getFunction().toString()</code> doesn’t always work,
|
||||
and it’s not foolproof either.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span> map <span class="hljs-keyword">in</span> sourceMaps[<span class="hljs-string">'<anonymous>'</span>] <span class="hljs-keyword">by</span> <span class="hljs-number">-1</span>
|
||||
sourceLocation = map.sourceLocation [line - <span class="hljs-number">1</span>, column - <span class="hljs-number">1</span>]
|
||||
<span class="hljs-keyword">return</span> map <span class="hljs-keyword">if</span> sourceLocation?[<span class="hljs-number">0</span>]? <span class="hljs-keyword">and</span> sourceLocation[<span class="hljs-number">1</span>]?</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-31">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-31">¶</a>
|
||||
</div>
|
||||
<p>If all else fails, recompile this source to get a source map. We need the
|
||||
previous section (for <code><anonymous></code>) despite this option, because after it
|
||||
gets compiled we will still need to look it up from
|
||||
<code>sourceMaps['<anonymous>']</code> 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.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> sources[filename]?
|
||||
answer = compile sources[filename][sources[filename].length - <span class="hljs-number">1</span>],
|
||||
filename: filename
|
||||
sourceMap: <span class="hljs-literal">yes</span>
|
||||
literate: helpers.isLiterate filename
|
||||
answer.sourceMap
|
||||
<span class="hljs-keyword">else</span>
|
||||
<span class="hljs-literal">null</span></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
|
||||
@@ -749,7 +809,7 @@ positions.</p>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>Error.prepareStackTrace = <span class="hljs-function"><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
|
||||
sourceMap = getSourceMap filename, line, column
|
||||
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>
|
||||
|
||||
|
||||
@@ -199,25 +199,25 @@ useWinPathSep = path.sep <span class="hljs-keyword">is</span> <span class="hljs
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>SWITCHES = [
|
||||
[<span class="hljs-string">'-b'</span>, <span class="hljs-string">'--bare'</span>, <span class="hljs-string">'compile without a top-level function wrapper'</span>]
|
||||
[<span class="hljs-string">'-c'</span>, <span class="hljs-string">'--compile'</span>, <span class="hljs-string">'compile to JavaScript and save as .js files'</span>]
|
||||
[<span class="hljs-string">'-e'</span>, <span class="hljs-string">'--eval'</span>, <span class="hljs-string">'pass a string from the command line as input'</span>]
|
||||
[<span class="hljs-string">'-h'</span>, <span class="hljs-string">'--help'</span>, <span class="hljs-string">'display this help message'</span>]
|
||||
[<span class="hljs-string">'-i'</span>, <span class="hljs-string">'--interactive'</span>, <span class="hljs-string">'run an interactive CoffeeScript REPL'</span>]
|
||||
[<span class="hljs-string">'-j'</span>, <span class="hljs-string">'--join [FILE]'</span>, <span class="hljs-string">'concatenate the source CoffeeScript before compiling'</span>]
|
||||
[<span class="hljs-string">'-m'</span>, <span class="hljs-string">'--map'</span>, <span class="hljs-string">'generate source map and save as .js.map files'</span>]
|
||||
[<span class="hljs-string">'-M'</span>, <span class="hljs-string">'--inline-map'</span>, <span class="hljs-string">'generate source map and include it directly in output'</span>]
|
||||
[<span class="hljs-string">'-n'</span>, <span class="hljs-string">'--nodes'</span>, <span class="hljs-string">'print out the parse tree that the parser produces'</span>]
|
||||
[ <span class="hljs-string">'--nodejs [ARGS]'</span>, <span class="hljs-string">'pass options directly to the "node" binary'</span>]
|
||||
[ <span class="hljs-string">'--no-header'</span>, <span class="hljs-string">'suppress the "Generated by" header'</span>]
|
||||
[<span class="hljs-string">'-o'</span>, <span class="hljs-string">'--output [DIR]'</span>, <span class="hljs-string">'set the output directory for compiled JavaScript'</span>]
|
||||
[<span class="hljs-string">'-p'</span>, <span class="hljs-string">'--print'</span>, <span class="hljs-string">'print out the compiled JavaScript'</span>]
|
||||
[<span class="hljs-string">'-b'</span>, <span class="hljs-string">'--bare'</span>, <span class="hljs-string">'compile without a top-level function wrapper'</span>]
|
||||
[<span class="hljs-string">'-c'</span>, <span class="hljs-string">'--compile'</span>, <span class="hljs-string">'compile to JavaScript and save as .js files'</span>]
|
||||
[<span class="hljs-string">'-e'</span>, <span class="hljs-string">'--eval'</span>, <span class="hljs-string">'pass a string from the command line as input'</span>]
|
||||
[<span class="hljs-string">'-h'</span>, <span class="hljs-string">'--help'</span>, <span class="hljs-string">'display this help message'</span>]
|
||||
[<span class="hljs-string">'-i'</span>, <span class="hljs-string">'--interactive'</span>, <span class="hljs-string">'run an interactive CoffeeScript REPL'</span>]
|
||||
[<span class="hljs-string">'-j'</span>, <span class="hljs-string">'--join [FILE]'</span>, <span class="hljs-string">'concatenate the source CoffeeScript before compiling'</span>]
|
||||
[<span class="hljs-string">'-m'</span>, <span class="hljs-string">'--map'</span>, <span class="hljs-string">'generate source map and save as .js.map files'</span>]
|
||||
[<span class="hljs-string">'-M'</span>, <span class="hljs-string">'--inline-map'</span>, <span class="hljs-string">'generate source map and include it directly in output'</span>]
|
||||
[<span class="hljs-string">'-n'</span>, <span class="hljs-string">'--nodes'</span>, <span class="hljs-string">'print out the parse tree that the parser produces'</span>]
|
||||
[ <span class="hljs-string">'--nodejs [ARGS]'</span>, <span class="hljs-string">'pass options directly to the "node" binary'</span>]
|
||||
[ <span class="hljs-string">'--no-header'</span>, <span class="hljs-string">'suppress the "Generated by" header'</span>]
|
||||
[<span class="hljs-string">'-o'</span>, <span class="hljs-string">'--output [PATH]'</span>, <span class="hljs-string">'set the output path or path/filename for compiled JavaScript'</span>]
|
||||
[<span class="hljs-string">'-p'</span>, <span class="hljs-string">'--print'</span>, <span class="hljs-string">'print out the compiled JavaScript'</span>]
|
||||
[<span class="hljs-string">'-r'</span>, <span class="hljs-string">'--require [MODULE*]'</span>, <span class="hljs-string">'require the given module before eval or REPL'</span>]
|
||||
[<span class="hljs-string">'-s'</span>, <span class="hljs-string">'--stdio'</span>, <span class="hljs-string">'listen for and compile scripts over stdio'</span>]
|
||||
[<span class="hljs-string">'-l'</span>, <span class="hljs-string">'--literate'</span>, <span class="hljs-string">'treat stdio as literate style coffeescript'</span>]
|
||||
[<span class="hljs-string">'-t'</span>, <span class="hljs-string">'--tokens'</span>, <span class="hljs-string">'print out the tokens that the lexer/rewriter produce'</span>]
|
||||
[<span class="hljs-string">'-v'</span>, <span class="hljs-string">'--version'</span>, <span class="hljs-string">'display the version number'</span>]
|
||||
[<span class="hljs-string">'-w'</span>, <span class="hljs-string">'--watch'</span>, <span class="hljs-string">'watch scripts for changes and rerun commands'</span>]
|
||||
[<span class="hljs-string">'-s'</span>, <span class="hljs-string">'--stdio'</span>, <span class="hljs-string">'listen for and compile scripts over stdio'</span>]
|
||||
[<span class="hljs-string">'-l'</span>, <span class="hljs-string">'--literate'</span>, <span class="hljs-string">'treat stdio as literate style coffeescript'</span>]
|
||||
[<span class="hljs-string">'-t'</span>, <span class="hljs-string">'--tokens'</span>, <span class="hljs-string">'print out the tokens that the lexer/rewriter produce'</span>]
|
||||
[<span class="hljs-string">'-v'</span>, <span class="hljs-string">'--version'</span>, <span class="hljs-string">'display the version number'</span>]
|
||||
[<span class="hljs-string">'-w'</span>, <span class="hljs-string">'--watch'</span>, <span class="hljs-string">'watch scripts for changes and rerun commands'</span>]
|
||||
]</pre></div></div>
|
||||
|
||||
</li>
|
||||
@@ -305,7 +305,45 @@ Many flags cause us to divert before compiling anything. Flags passed after
|
||||
process.argv = process.argv[<span class="hljs-number">0.</span><span class="hljs-number">.1</span>].concat literals
|
||||
process.argv[<span class="hljs-number">0</span>] = <span class="hljs-string">'coffee'</span>
|
||||
|
||||
opts.output = path.resolve opts.output <span class="hljs-keyword">if</span> opts.output
|
||||
<span class="hljs-keyword">if</span> opts.output
|
||||
outputBasename = path.basename opts.output
|
||||
<span class="hljs-keyword">if</span> <span class="hljs-string">'.'</span> <span class="hljs-keyword">in</span> outputBasename <span class="hljs-keyword">and</span>
|
||||
outputBasename <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'.'</span>, <span class="hljs-string">'..'</span>] <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> helpers.ends(opts.output, path.sep)</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-9">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-9">¶</a>
|
||||
</div>
|
||||
<p>An output filename was specified, e.g. <code>/dist/scripts.js</code>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> opts.outputFilename = outputBasename
|
||||
opts.outputPath = path.resolve path.dirname opts.output
|
||||
<span class="hljs-keyword">else</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-10">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-10">¶</a>
|
||||
</div>
|
||||
<p>An output path was specified, e.g. <code>/dist</code>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> opts.outputFilename = <span class="hljs-literal">null</span>
|
||||
opts.outputPath = path.resolve opts.output
|
||||
|
||||
<span class="hljs-keyword">if</span> opts.join
|
||||
opts.join = path.resolve opts.join
|
||||
<span class="hljs-built_in">console</span>.error <span class="hljs-string">'''
|
||||
@@ -328,19 +366,19 @@ Many flags cause us to divert before compiling anything. Flags passed after
|
||||
<span class="hljs-function">
|
||||
<span class="hljs-title">makePrelude</span> = <span class="hljs-params">(requires)</span> -></span>
|
||||
requires.map (<span class="hljs-built_in">module</span>) ->
|
||||
[_, name, <span class="hljs-built_in">module</span>] = match <span class="hljs-keyword">if</span> match = <span class="hljs-built_in">module</span>.match(<span class="hljs-regexp">/^(.*)=(.*)$/</span>)
|
||||
name ||= helpers.baseFileName <span class="hljs-built_in">module</span>, <span class="hljs-literal">yes</span>, useWinPathSep
|
||||
<span class="hljs-string">"<span class="hljs-subst">#{name}</span> = require('<span class="hljs-subst">#{<span class="hljs-built_in">module</span>}</span>')"</span>
|
||||
[full, name, <span class="hljs-built_in">module</span>] = match <span class="hljs-keyword">if</span> match = <span class="hljs-built_in">module</span>.match(<span class="hljs-regexp">/^(.*)=(.*)$/</span>)
|
||||
name <span class="hljs-keyword">or</span>= helpers.baseFileName <span class="hljs-built_in">module</span>, <span class="hljs-literal">yes</span>, useWinPathSep
|
||||
<span class="hljs-string">"global['<span class="hljs-subst">#{name}</span>'] = require('<span class="hljs-subst">#{<span class="hljs-built_in">module</span>}</span>')"</span>
|
||||
.join <span class="hljs-string">';'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-9">
|
||||
<li id="section-11">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-9">¶</a>
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
</div>
|
||||
<p>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.</p>
|
||||
code = fs.readFileSync source
|
||||
<span class="hljs-keyword">catch</span> err
|
||||
<span class="hljs-keyword">if</span> err.code <span class="hljs-keyword">is</span> <span class="hljs-string">'ENOENT'</span> <span class="hljs-keyword">then</span> <span class="hljs-keyword">return</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">throw</span> err
|
||||
compileScript(source, code.toString(), base)
|
||||
compileScript source, code.toString(), base
|
||||
<span class="hljs-keyword">else</span>
|
||||
notSources[source] = <span class="hljs-literal">yes</span>
|
||||
<span class="hljs-function">
|
||||
@@ -399,53 +437,56 @@ extension source files in it and all subdirectories.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-10">
|
||||
<li id="section-12">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-10">¶</a>
|
||||
<a class="pilcrow" href="#section-12">¶</a>
|
||||
</div>
|
||||
<p>Compile a single source script, containing the given code, according to the
|
||||
requested options. If evaluating the script directly sets <code>__filename</code>,
|
||||
requested options. If evaluating the script directly, set <code>__filename</code>,
|
||||
<code>__dirname</code> and <code>module.filename</code> to be correct relative to the script’s path.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">compileScript</span> = <span class="hljs-params">(file, input, base = <span class="hljs-literal">null</span>)</span> -></span>
|
||||
o = opts
|
||||
options = compileOptions file, base
|
||||
<span class="hljs-keyword">try</span>
|
||||
t = task = {file, input, options}
|
||||
task = {file, input, options}
|
||||
CoffeeScript.emit <span class="hljs-string">'compile'</span>, task
|
||||
<span class="hljs-keyword">if</span> o.tokens
|
||||
printTokens CoffeeScript.tokens t.input, t.options
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> o.nodes
|
||||
printLine CoffeeScript.nodes(t.input, t.options).toString().trim()
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> o.run
|
||||
<span class="hljs-keyword">if</span> opts.tokens
|
||||
printTokens CoffeeScript.tokens task.input, task.options
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> opts.nodes
|
||||
printLine CoffeeScript.nodes(task.input, task.options).toString().trim()
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> opts.run
|
||||
CoffeeScript.register()
|
||||
CoffeeScript.eval opts.prelude, t.options <span class="hljs-keyword">if</span> opts.prelude
|
||||
CoffeeScript.run t.input, t.options
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> o.join <span class="hljs-keyword">and</span> t.file <span class="hljs-keyword">isnt</span> o.join
|
||||
t.input = helpers.invertLiterate t.input <span class="hljs-keyword">if</span> helpers.isLiterate file
|
||||
sourceCode[sources.indexOf(t.file)] = t.input
|
||||
CoffeeScript.eval opts.prelude, task.options <span class="hljs-keyword">if</span> opts.prelude
|
||||
CoffeeScript.run task.input, task.options
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> opts.join <span class="hljs-keyword">and</span> task.file <span class="hljs-keyword">isnt</span> opts.join
|
||||
task.input = helpers.invertLiterate task.input <span class="hljs-keyword">if</span> helpers.isLiterate file
|
||||
sourceCode[sources.indexOf(task.file)] = task.input
|
||||
compileJoin()
|
||||
<span class="hljs-keyword">else</span>
|
||||
compiled = CoffeeScript.compile t.input, t.options
|
||||
t.output = compiled
|
||||
<span class="hljs-keyword">if</span> o.map
|
||||
t.output = compiled.js
|
||||
t.sourceMap = compiled.v3SourceMap
|
||||
compiled = CoffeeScript.compile task.input, task.options
|
||||
task.output = compiled
|
||||
<span class="hljs-keyword">if</span> opts.map
|
||||
task.output = compiled.js
|
||||
task.sourceMap = compiled.v3SourceMap
|
||||
|
||||
CoffeeScript.emit <span class="hljs-string">'success'</span>, task
|
||||
<span class="hljs-keyword">if</span> o.<span class="hljs-built_in">print</span>
|
||||
printLine t.output.trim()
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> o.compile <span class="hljs-keyword">or</span> o.map
|
||||
writeJs base, t.file, t.output, options.jsPath, t.sourceMap
|
||||
<span class="hljs-keyword">if</span> opts.<span class="hljs-built_in">print</span>
|
||||
printLine task.output.trim()
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> opts.compile <span class="hljs-keyword">or</span> opts.map
|
||||
saveTo = <span class="hljs-keyword">if</span> opts.outputFilename <span class="hljs-keyword">and</span> sources.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span>
|
||||
path.join opts.outputPath, opts.outputFilename
|
||||
<span class="hljs-keyword">else</span>
|
||||
options.jsPath
|
||||
writeJs base, task.file, task.output, saveTo, task.sourceMap
|
||||
<span class="hljs-keyword">catch</span> err
|
||||
CoffeeScript.emit <span class="hljs-string">'failure'</span>, err, task
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> CoffeeScript.listeners(<span class="hljs-string">'failure'</span>).length
|
||||
message = err?.stack <span class="hljs-keyword">or</span> <span class="hljs-string">"<span class="hljs-subst">#{err}</span>"</span>
|
||||
<span class="hljs-keyword">if</span> o.watch
|
||||
<span class="hljs-keyword">if</span> opts.watch
|
||||
printLine message + <span class="hljs-string">'\x07'</span>
|
||||
<span class="hljs-keyword">else</span>
|
||||
printWarn message
|
||||
@@ -454,11 +495,11 @@ requested options. If evaluating the script directly sets <code>__filename</code
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-11">
|
||||
<li id="section-13">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
<a class="pilcrow" href="#section-13">¶</a>
|
||||
</div>
|
||||
<p>Attach the appropriate listeners to compile scripts incoming over <strong>stdin</strong>,
|
||||
and write them back to <strong>stdout</strong>.</p>
|
||||
@@ -476,11 +517,11 @@ and write them back to <strong>stdout</strong>.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-12">
|
||||
<li id="section-14">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-12">¶</a>
|
||||
<a class="pilcrow" href="#section-14">¶</a>
|
||||
</div>
|
||||
<p>If all of the source files are done being read, concatenate and compile
|
||||
them together.</p>
|
||||
@@ -498,11 +539,11 @@ them together.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-13">
|
||||
<li id="section-15">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-13">¶</a>
|
||||
<a class="pilcrow" href="#section-15">¶</a>
|
||||
</div>
|
||||
<p>Watch a source CoffeeScript file using <code>fs.watch</code>, recompiling it every
|
||||
time the file is updated. May be used in combination with other options,
|
||||
@@ -558,11 +599,11 @@ such as <code>--print</code>.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-14">
|
||||
<li id="section-16">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-14">¶</a>
|
||||
<a class="pilcrow" href="#section-16">¶</a>
|
||||
</div>
|
||||
<p>Watch a directory of files for new additions.</p>
|
||||
|
||||
@@ -609,11 +650,11 @@ such as <code>--print</code>.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-15">
|
||||
<li id="section-17">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-15">¶</a>
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
</div>
|
||||
<p>Remove a file from our source list, and source code cache. Optionally remove
|
||||
the compiled JS version as well.</p>
|
||||
@@ -638,11 +679,11 @@ the compiled JS version as well.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-16">
|
||||
<li id="section-18">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-16">¶</a>
|
||||
<a class="pilcrow" href="#section-18">¶</a>
|
||||
</div>
|
||||
<p>Get the corresponding output JavaScript path for a source file.</p>
|
||||
|
||||
@@ -651,22 +692,22 @@ the compiled JS version as well.</p>
|
||||
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">outputPath</span> = <span class="hljs-params">(source, base, extension=<span class="hljs-string">".js"</span>)</span> -></span>
|
||||
basename = helpers.baseFileName source, <span class="hljs-literal">yes</span>, useWinPathSep
|
||||
srcDir = path.dirname source
|
||||
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> opts.output
|
||||
dir = srcDir
|
||||
dir = <span class="hljs-keyword">unless</span> opts.outputPath
|
||||
srcDir
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> source <span class="hljs-keyword">is</span> base
|
||||
dir = opts.output
|
||||
opts.outputPath
|
||||
<span class="hljs-keyword">else</span>
|
||||
dir = path.join opts.output, path.relative base, srcDir
|
||||
path.join opts.outputPath, path.relative base, srcDir
|
||||
path.join dir, basename + extension</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-17">
|
||||
<li id="section-19">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
<a class="pilcrow" href="#section-19">¶</a>
|
||||
</div>
|
||||
<p>Recursively mkdir, like <code>mkdir -p</code>.</p>
|
||||
|
||||
@@ -688,11 +729,11 @@ the compiled JS version as well.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-18">
|
||||
<li id="section-20">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-18">¶</a>
|
||||
<a class="pilcrow" href="#section-20">¶</a>
|
||||
</div>
|
||||
<p>Write out a JavaScript source file with the compiled code. By default, files
|
||||
are written out in <code>cwd</code> as <code>.js</code> files with the same name, but the output
|
||||
@@ -726,11 +767,11 @@ same directory as the <code>.js</code> file.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-19">
|
||||
<li id="section-21">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-19">¶</a>
|
||||
<a class="pilcrow" href="#section-21">¶</a>
|
||||
</div>
|
||||
<p>Convenience for cleaner setTimeouts.</p>
|
||||
|
||||
@@ -741,11 +782,11 @@ same directory as the <code>.js</code> file.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-20">
|
||||
<li id="section-22">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-20">¶</a>
|
||||
<a class="pilcrow" href="#section-22">¶</a>
|
||||
</div>
|
||||
<p>When watching scripts, it’s useful to log changes with the timestamp.</p>
|
||||
|
||||
@@ -757,11 +798,11 @@ same directory as the <code>.js</code> file.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-21">
|
||||
<li id="section-23">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-21">¶</a>
|
||||
<a class="pilcrow" href="#section-23">¶</a>
|
||||
</div>
|
||||
<p>Pretty-print a stream of tokens, sans location data.</p>
|
||||
|
||||
@@ -777,11 +818,11 @@ same directory as the <code>.js</code> file.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-22">
|
||||
<li id="section-24">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-22">¶</a>
|
||||
<a class="pilcrow" href="#section-24">¶</a>
|
||||
</div>
|
||||
<p>Use the <a href="optparse.html">OptionParser module</a> to extract all options from
|
||||
<code>process.argv</code> that are specified in <code>SWITCHES</code>.</p>
|
||||
@@ -797,11 +838,11 @@ same directory as the <code>.js</code> file.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-23">
|
||||
<li id="section-25">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-23">¶</a>
|
||||
<a class="pilcrow" href="#section-25">¶</a>
|
||||
</div>
|
||||
<p>The compile-time options to pass to the CoffeeScript compiler.</p>
|
||||
|
||||
@@ -837,11 +878,11 @@ same directory as the <code>.js</code> file.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-24">
|
||||
<li id="section-26">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-24">¶</a>
|
||||
<a class="pilcrow" href="#section-26">¶</a>
|
||||
</div>
|
||||
<p>Start up a new Node.js instance with the arguments in <code>--nodejs</code> passed to
|
||||
the <code>node</code> binary, preserving the other options.</p>
|
||||
@@ -864,11 +905,11 @@ the <code>node</code> binary, preserving the other options.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-25">
|
||||
<li id="section-27">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-25">¶</a>
|
||||
<a class="pilcrow" href="#section-27">¶</a>
|
||||
</div>
|
||||
<p>Print the <code>--help</code> usage message and exit. Deprecated switches are not
|
||||
shown.</p>
|
||||
@@ -881,11 +922,11 @@ shown.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-26">
|
||||
<li id="section-28">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-26">¶</a>
|
||||
<a class="pilcrow" href="#section-28">¶</a>
|
||||
</div>
|
||||
<p>Print the <code>--version</code> message and exit.</p>
|
||||
|
||||
|
||||
@@ -788,6 +788,7 @@ that hoovers up the remaining arguments.</p>
|
||||
<div class="content"><div class='highlight'><pre> SimpleAssignable: [
|
||||
o <span class="hljs-string">'Identifier'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Value $<span class="hljs-number">1</span>
|
||||
o <span class="hljs-string">'Value Accessor'</span>, <span class="hljs-function">-></span> $<span class="hljs-number">1.</span>add $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'Code Accessor'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Value($<span class="hljs-number">1</span>).add $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'ThisProperty'</span>
|
||||
]</pre></div></div>
|
||||
|
||||
|
||||
@@ -395,7 +395,7 @@ though <code>is</code> means <code>===</code> otherwise.</p>
|
||||
<span class="hljs-keyword">return</span> id.length
|
||||
<span class="hljs-keyword">if</span> id <span class="hljs-keyword">is</span> <span class="hljs-string">'do'</span> <span class="hljs-keyword">and</span> regExSuper = <span class="hljs-regexp">/^(\s*super)(?!\(\))/</span>.exec @chunk[<span class="hljs-number">3.</span>..]
|
||||
@token <span class="hljs-string">'SUPER'</span>, <span class="hljs-string">'super'</span>
|
||||
@token <span class="hljs-string">'CALL_START'</span>, <span class="hljs-string">'('</span>
|
||||
@token <span class="hljs-string">'CALL_START'</span>, <span class="hljs-string">'('</span>
|
||||
@token <span class="hljs-string">'CALL_END'</span>, <span class="hljs-string">')'</span>
|
||||
[input, sup] = regExSuper
|
||||
<span class="hljs-keyword">return</span> sup.length + <span class="hljs-number">3</span>
|
||||
@@ -1000,7 +1000,7 @@ inwards past several recorded indents. Sets new @indent value.</p>
|
||||
@token <span class="hljs-string">'OUTDENT'</span>, moveOut, <span class="hljs-number">0</span>, outdentLength
|
||||
moveOut -= dent
|
||||
@outdebt -= moveOut <span class="hljs-keyword">if</span> dent
|
||||
@tokens.pop() <span class="hljs-keyword">while</span> @value() <span class="hljs-keyword">is</span> <span class="hljs-string">';'</span>
|
||||
@suppressSemicolons()
|
||||
|
||||
@token <span class="hljs-string">'TERMINATOR'</span>, <span class="hljs-string">'\n'</span>, outdentLength, <span class="hljs-number">0</span> <span class="hljs-keyword">unless</span> @tag() <span class="hljs-keyword">is</span> <span class="hljs-string">'TERMINATOR'</span> <span class="hljs-keyword">or</span> noNewlines
|
||||
@indent = decreasedIndent
|
||||
@@ -1042,7 +1042,7 @@ as being “spaced”, because there are some cases where it makes a difference.
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> newlineToken: <span class="hljs-function"><span class="hljs-params">(offset)</span> -></span>
|
||||
@tokens.pop() <span class="hljs-keyword">while</span> @value() <span class="hljs-keyword">is</span> <span class="hljs-string">';'</span>
|
||||
@suppressSemicolons()
|
||||
@token <span class="hljs-string">'TERMINATOR'</span>, <span class="hljs-string">'\n'</span>, offset, <span class="hljs-number">0</span> <span class="hljs-keyword">unless</span> @tag() <span class="hljs-keyword">is</span> <span class="hljs-string">'TERMINATOR'</span>
|
||||
<span class="hljs-keyword">this</span></pre></div></div>
|
||||
|
||||
@@ -1278,9 +1278,10 @@ parentheses that indicate a method call from regular parentheses, and so on.</p>
|
||||
@exportSpecifierList = <span class="hljs-literal">no</span>
|
||||
|
||||
<span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-string">';'</span>
|
||||
@error <span class="hljs-string">'unexpected ;'</span> <span class="hljs-keyword">if</span> prev?[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> [<span class="hljs-string">'='</span>, UNFINISHED...]
|
||||
@seenFor = @seenImport = @seenExport = <span class="hljs-literal">no</span>
|
||||
tag = <span class="hljs-string">'TERMINATOR'</span>
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-string">'*'</span> <span class="hljs-keyword">and</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'EXPORT'</span>
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-string">'*'</span> <span class="hljs-keyword">and</span> prev?[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'EXPORT'</span>
|
||||
tag = <span class="hljs-string">'EXPORT_ALL'</span>
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">in</span> MATH <span class="hljs-keyword">then</span> tag = <span class="hljs-string">'MATH'</span>
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">in</span> COMPARE <span class="hljs-keyword">then</span> tag = <span class="hljs-string">'COMPARE'</span>
|
||||
@@ -1289,11 +1290,12 @@ parentheses that indicate a method call from regular parentheses, and so on.</p>
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">in</span> UNARY_MATH <span class="hljs-keyword">then</span> tag = <span class="hljs-string">'UNARY_MATH'</span>
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">in</span> SHIFT <span class="hljs-keyword">then</span> tag = <span class="hljs-string">'SHIFT'</span>
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-string">'?'</span> <span class="hljs-keyword">and</span> prev?.spaced <span class="hljs-keyword">then</span> tag = <span class="hljs-string">'BIN?'</span>
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> prev <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> prev.spaced
|
||||
<span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-string">'('</span> <span class="hljs-keyword">and</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> CALLABLE
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> prev
|
||||
<span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-string">'('</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> prev.spaced <span class="hljs-keyword">and</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> CALLABLE
|
||||
prev[<span class="hljs-number">0</span>] = <span class="hljs-string">'FUNC_EXIST'</span> <span class="hljs-keyword">if</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'?'</span>
|
||||
tag = <span class="hljs-string">'CALL_START'</span>
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-string">'['</span> <span class="hljs-keyword">and</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> INDEXABLE
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-string">'['</span> <span class="hljs-keyword">and</span> ((prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> INDEXABLE <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> prev.spaced) <span class="hljs-keyword">or</span>
|
||||
(prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'::'</span>)) <span class="hljs-comment"># `.prototype` can’t be a method you can call.</span>
|
||||
tag = <span class="hljs-string">'INDEX_START'</span>
|
||||
<span class="hljs-keyword">switch</span> prev[<span class="hljs-number">0</span>]
|
||||
<span class="hljs-keyword">when</span> <span class="hljs-string">'?'</span> <span class="hljs-keyword">then</span> prev[<span class="hljs-number">0</span>] = <span class="hljs-string">'INDEX_SOAK'</span>
|
||||
@@ -1590,7 +1592,8 @@ of <code>'NEOSTRING'</code>s are converted using <code>fn</code> and tur
|
||||
<span class="hljs-keyword">for</span> token, i <span class="hljs-keyword">in</span> tokens
|
||||
[tag, value] = token
|
||||
<span class="hljs-keyword">switch</span> tag
|
||||
<span class="hljs-keyword">when</span> <span class="hljs-string">'TOKENS'</span></pre></div></div>
|
||||
<span class="hljs-keyword">when</span> <span class="hljs-string">'TOKENS'</span>
|
||||
<span class="hljs-keyword">if</span> value.length <span class="hljs-keyword">is</span> <span class="hljs-number">2</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -1605,7 +1608,7 @@ of <code>'NEOSTRING'</code>s are converted using <code>fn</code> and tur
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">continue</span> <span class="hljs-keyword">if</span> value.length <span class="hljs-keyword">is</span> <span class="hljs-number">2</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">continue</span> <span class="hljs-keyword">unless</span> value[<span class="hljs-number">0</span>].comments <span class="hljs-keyword">or</span> value[<span class="hljs-number">1</span>].comments</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -1616,6 +1619,59 @@ of <code>'NEOSTRING'</code>s are converted using <code>fn</code> and tur
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-57">¶</a>
|
||||
</div>
|
||||
<p>There are comments (and nothing else) in this interpolation.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @csxDepth <span class="hljs-keyword">is</span> <span class="hljs-number">0</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-58">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-58">¶</a>
|
||||
</div>
|
||||
<p>This is an interpolated string, not a CSX tag; and for whatever
|
||||
reason <code>`a${/*test*/}b` </code> is invalid JS. So compile to
|
||||
<code>`a${/*test*/''}b` </code> instead.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> placeholderToken = @makeToken <span class="hljs-string">'STRING'</span>, <span class="hljs-string">"''"</span>
|
||||
<span class="hljs-keyword">else</span>
|
||||
placeholderToken = @makeToken <span class="hljs-string">'JS'</span>, <span class="hljs-string">''</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-59">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-59">¶</a>
|
||||
</div>
|
||||
<p>Use the same location data as the first parenthesis.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> placeholderToken[<span class="hljs-number">2</span>] = value[<span class="hljs-number">0</span>][<span class="hljs-number">2</span>]
|
||||
<span class="hljs-keyword">for</span> val <span class="hljs-keyword">in</span> value <span class="hljs-keyword">when</span> val.comments
|
||||
placeholderToken.comments ?= []
|
||||
placeholderToken.comments.push val.comments...
|
||||
value.splice <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, placeholderToken</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-60">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-60">¶</a>
|
||||
</div>
|
||||
<p>Push all the tokens in the fake <code>'TOKENS'</code> token. These already have
|
||||
sane location data.</p>
|
||||
|
||||
@@ -1628,11 +1684,11 @@ sane location data.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-58">
|
||||
<li id="section-61">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-58">¶</a>
|
||||
<a class="pilcrow" href="#section-61">¶</a>
|
||||
</div>
|
||||
<p>Convert <code>'NEOSTRING'</code> into <code>'STRING'</code>.</p>
|
||||
|
||||
@@ -1643,11 +1699,11 @@ sane location data.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-59">
|
||||
<li id="section-62">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-59">¶</a>
|
||||
<a class="pilcrow" href="#section-62">¶</a>
|
||||
</div>
|
||||
<p>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.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-60">
|
||||
<li id="section-63">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-60">¶</a>
|
||||
<a class="pilcrow" href="#section-63">¶</a>
|
||||
</div>
|
||||
<p>However, there is one case where we can optimize away a starting
|
||||
empty string.</p>
|
||||
@@ -1686,11 +1742,11 @@ empty string.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-61">
|
||||
<li id="section-64">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-61">¶</a>
|
||||
<a class="pilcrow" href="#section-64">¶</a>
|
||||
</div>
|
||||
<p>Create a 0-length “+” token.</p>
|
||||
|
||||
@@ -1723,11 +1779,11 @@ empty string.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-62">
|
||||
<li id="section-65">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-62">¶</a>
|
||||
<a class="pilcrow" href="#section-65">¶</a>
|
||||
</div>
|
||||
<p>Pairs up a closing token, ensuring that all listed pairs of tokens are
|
||||
correctly balanced throughout the course of the token stream.</p>
|
||||
@@ -1742,11 +1798,11 @@ correctly balanced throughout the course of the token stream.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-63">
|
||||
<li id="section-66">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-63">¶</a>
|
||||
<a class="pilcrow" href="#section-66">¶</a>
|
||||
</div>
|
||||
<p>Auto-close <code>INDENT</code> to support syntax like this:</p>
|
||||
<pre><code>el.click(<span class="hljs-function"><span class="hljs-params">(event)</span> -></span>
|
||||
@@ -1762,11 +1818,11 @@ correctly balanced throughout the course of the token stream.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-64">
|
||||
<li id="section-67">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-64">¶</a>
|
||||
<a class="pilcrow" href="#section-67">¶</a>
|
||||
</div>
|
||||
<h2 id="helpers">Helpers</h2>
|
||||
|
||||
@@ -1775,11 +1831,11 @@ correctly balanced throughout the course of the token stream.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-65">
|
||||
<li id="section-68">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-65">¶</a>
|
||||
<a class="pilcrow" href="#section-68">¶</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1787,11 +1843,11 @@ correctly balanced throughout the course of the token stream.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-66">
|
||||
<li id="section-69">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-66">¶</a>
|
||||
<a class="pilcrow" href="#section-69">¶</a>
|
||||
</div>
|
||||
<p>Returns the line and column number from an offset into the current chunk.</p>
|
||||
<p><code>offset</code> is a number of characters into <code>@chunk</code>.</p>
|
||||
@@ -1821,11 +1877,11 @@ correctly balanced throughout the course of the token stream.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-67">
|
||||
<li id="section-70">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-67">¶</a>
|
||||
<a class="pilcrow" href="#section-70">¶</a>
|
||||
</div>
|
||||
<p>Same as <code>token</code>, except this just returns the token without adding it
|
||||
to the results.</p>
|
||||
@@ -1840,11 +1896,11 @@ to the results.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-68">
|
||||
<li id="section-71">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-68">¶</a>
|
||||
<a class="pilcrow" href="#section-71">¶</a>
|
||||
</div>
|
||||
<p>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.</p>
|
||||
@@ -1862,11 +1918,11 @@ so if last_column == first_column, then we’re looking at a character of length
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-69">
|
||||
<li id="section-72">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-69">¶</a>
|
||||
<a class="pilcrow" href="#section-72">¶</a>
|
||||
</div>
|
||||
<p>Add a token to the results.
|
||||
<code>offset</code> is the offset into the current <code>@chunk</code> where the token starts.
|
||||
@@ -1885,11 +1941,11 @@ not specified, the length of <code>value</code> will be used.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-70">
|
||||
<li id="section-73">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-70">¶</a>
|
||||
<a class="pilcrow" href="#section-73">¶</a>
|
||||
</div>
|
||||
<p>Peek at the last tag in the token stream.</p>
|
||||
|
||||
@@ -1902,11 +1958,11 @@ not specified, the length of <code>value</code> will be used.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-71">
|
||||
<li id="section-74">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-71">¶</a>
|
||||
<a class="pilcrow" href="#section-74">¶</a>
|
||||
</div>
|
||||
<p>Peek at the last value in the token stream.</p>
|
||||
|
||||
@@ -1919,11 +1975,11 @@ not specified, the length of <code>value</code> will be used.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-72">
|
||||
<li id="section-75">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-72">¶</a>
|
||||
<a class="pilcrow" href="#section-75">¶</a>
|
||||
</div>
|
||||
<p>Get the previous token in the token stream.</p>
|
||||
|
||||
@@ -1935,11 +1991,11 @@ not specified, the length of <code>value</code> will be used.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-73">
|
||||
<li id="section-76">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-73">¶</a>
|
||||
<a class="pilcrow" href="#section-76">¶</a>
|
||||
</div>
|
||||
<p>Are we in the midst of an unfinished expression?</p>
|
||||
|
||||
@@ -1967,11 +2023,11 @@ not specified, the length of <code>value</code> will be used.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-74">
|
||||
<li id="section-77">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-74">¶</a>
|
||||
<a class="pilcrow" href="#section-77">¶</a>
|
||||
</div>
|
||||
<p>surrogate pair</p>
|
||||
|
||||
@@ -1984,11 +2040,11 @@ not specified, the length of <code>value</code> will be used.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-75">
|
||||
<li id="section-78">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-75">¶</a>
|
||||
<a class="pilcrow" href="#section-78">¶</a>
|
||||
</div>
|
||||
<p>Replace <code>\u{...}</code> with <code>\uxxxx[\uxxxx]</code> in regexes without <code>u</code> flag</p>
|
||||
|
||||
@@ -2011,11 +2067,11 @@ not specified, the length of <code>value</code> will be used.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-76">
|
||||
<li id="section-79">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-76">¶</a>
|
||||
<a class="pilcrow" href="#section-79">¶</a>
|
||||
</div>
|
||||
<p>Validates escapes in strings and regexes.</p>
|
||||
|
||||
@@ -2043,11 +2099,11 @@ not specified, the length of <code>value</code> will be used.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-77">
|
||||
<li id="section-80">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-77">¶</a>
|
||||
<a class="pilcrow" href="#section-80">¶</a>
|
||||
</div>
|
||||
<p>Constructs a string or regex by escaping certain characters.</p>
|
||||
|
||||
@@ -2067,11 +2123,11 @@ not specified, the length of <code>value</code> will be used.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-78">
|
||||
<li id="section-81">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-78">¶</a>
|
||||
<a class="pilcrow" href="#section-81">¶</a>
|
||||
</div>
|
||||
<p>Ignore escaped backslashes.</p>
|
||||
|
||||
@@ -2085,16 +2141,21 @@ not specified, the length of <code>value</code> will be used.</p>
|
||||
<span class="hljs-keyword">when</span> ls <span class="hljs-keyword">then</span> <span class="hljs-string">'\\u2028'</span>
|
||||
<span class="hljs-keyword">when</span> ps <span class="hljs-keyword">then</span> <span class="hljs-string">'\\u2029'</span>
|
||||
<span class="hljs-keyword">when</span> other <span class="hljs-keyword">then</span> (<span class="hljs-keyword">if</span> options.double <span class="hljs-keyword">then</span> <span class="hljs-string">"\\<span class="hljs-subst">#{other}</span>"</span> <span class="hljs-keyword">else</span> other)
|
||||
<span class="hljs-string">"<span class="hljs-subst">#{options.delimiter}</span><span class="hljs-subst">#{body}</span><span class="hljs-subst">#{options.delimiter}</span>"</span></pre></div></div>
|
||||
<span class="hljs-string">"<span class="hljs-subst">#{options.delimiter}</span><span class="hljs-subst">#{body}</span><span class="hljs-subst">#{options.delimiter}</span>"</span>
|
||||
|
||||
suppressSemicolons: <span class="hljs-function">-></span>
|
||||
<span class="hljs-keyword">while</span> @value() <span class="hljs-keyword">is</span> <span class="hljs-string">';'</span>
|
||||
@tokens.pop()
|
||||
@error <span class="hljs-string">'unexpected ;'</span> <span class="hljs-keyword">if</span> @prev()?[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> [<span class="hljs-string">'='</span>, UNFINISHED...]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-79">
|
||||
<li id="section-82">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-79">¶</a>
|
||||
<a class="pilcrow" href="#section-82">¶</a>
|
||||
</div>
|
||||
<p>Throws an error at either a given offset from the current chunk or at the
|
||||
location of a token (<code>token[2]</code>).</p>
|
||||
@@ -2113,11 +2174,11 @@ location of a token (<code>token[2]</code>).</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-80">
|
||||
<li id="section-83">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-80">¶</a>
|
||||
<a class="pilcrow" href="#section-83">¶</a>
|
||||
</div>
|
||||
<h2 id="helper-functions">Helper functions</h2>
|
||||
|
||||
@@ -2126,11 +2187,11 @@ location of a token (<code>token[2]</code>).</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-81">
|
||||
<li id="section-84">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-81">¶</a>
|
||||
<a class="pilcrow" href="#section-84">¶</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -2151,11 +2212,11 @@ exports.isUnassignable = isUnassignable</pre></div></div>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-82">
|
||||
<li id="section-85">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-82">¶</a>
|
||||
<a class="pilcrow" href="#section-85">¶</a>
|
||||
</div>
|
||||
<p><code>from</code> isn’t a CoffeeScript keyword, but it behaves like one in <code>import</code> and
|
||||
<code>export</code> statements (handled above) and in the declaration line of a <code>for</code>
|
||||
@@ -2170,11 +2231,11 @@ loop. Try to detect when <code>from</code> is a variable identifier and when it
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-83">
|
||||
<li id="section-86">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-83">¶</a>
|
||||
<a class="pilcrow" href="#section-86">¶</a>
|
||||
</div>
|
||||
<p><code>for i from from</code>, <code>for from from iterable</code></p>
|
||||
|
||||
@@ -2187,11 +2248,11 @@ loop. Try to detect when <code>from</code> is a variable identifier and when it
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-84">
|
||||
<li id="section-87">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-84">¶</a>
|
||||
<a class="pilcrow" href="#section-87">¶</a>
|
||||
</div>
|
||||
<p><code>for i from iterable</code></p>
|
||||
|
||||
@@ -2202,11 +2263,11 @@ loop. Try to detect when <code>from</code> is a variable identifier and when it
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-85">
|
||||
<li id="section-88">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-85">¶</a>
|
||||
<a class="pilcrow" href="#section-88">¶</a>
|
||||
</div>
|
||||
<p><code>for from…</code></p>
|
||||
|
||||
@@ -2218,11 +2279,11 @@ loop. Try to detect when <code>from</code> is a variable identifier and when it
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-86">
|
||||
<li id="section-89">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-86">¶</a>
|
||||
<a class="pilcrow" href="#section-89">¶</a>
|
||||
</div>
|
||||
<p><code>for {from}…</code>, <code>for [from]…</code>, <code>for {a, from}…</code>, <code>for {a: from}…</code></p>
|
||||
|
||||
@@ -2236,11 +2297,11 @@ loop. Try to detect when <code>from</code> is a variable identifier and when it
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-87">
|
||||
<li id="section-90">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-87">¶</a>
|
||||
<a class="pilcrow" href="#section-90">¶</a>
|
||||
</div>
|
||||
<h2 id="constants">Constants</h2>
|
||||
|
||||
@@ -2249,11 +2310,11 @@ loop. Try to detect when <code>from</code> is a variable identifier and when it
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-88">
|
||||
<li id="section-91">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-88">¶</a>
|
||||
<a class="pilcrow" href="#section-91">¶</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -2261,11 +2322,11 @@ loop. Try to detect when <code>from</code> is a variable identifier and when it
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-89">
|
||||
<li id="section-92">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-89">¶</a>
|
||||
<a class="pilcrow" href="#section-92">¶</a>
|
||||
</div>
|
||||
<p>Keywords that CoffeeScript shares in common with JavaScript.</p>
|
||||
|
||||
@@ -2283,11 +2344,11 @@ loop. Try to detect when <code>from</code> is a variable identifier and when it
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-90">
|
||||
<li id="section-93">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-90">¶</a>
|
||||
<a class="pilcrow" href="#section-93">¶</a>
|
||||
</div>
|
||||
<p>CoffeeScript-only keywords.</p>
|
||||
|
||||
@@ -2315,11 +2376,11 @@ COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat COFFEE_ALIASES</pre></div></div>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-91">
|
||||
<li id="section-94">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-91">¶</a>
|
||||
<a class="pilcrow" href="#section-94">¶</a>
|
||||
</div>
|
||||
<p>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 = [<span class="hljs-string">'arguments'</span>, <span class="
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-92">
|
||||
<li id="section-95">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-92">¶</a>
|
||||
<a class="pilcrow" href="#section-95">¶</a>
|
||||
</div>
|
||||
<p>The superset of both JavaScript keywords and reserved words, none of which may
|
||||
be used as identifiers or properties.</p>
|
||||
@@ -2354,11 +2415,11 @@ be used as identifiers or properties.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-93">
|
||||
<li id="section-96">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-93">¶</a>
|
||||
<a class="pilcrow" href="#section-96">¶</a>
|
||||
</div>
|
||||
<p>The character code of the nasty Microsoft madness otherwise known as the BOM.</p>
|
||||
|
||||
@@ -2369,11 +2430,11 @@ be used as identifiers or properties.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-94">
|
||||
<li id="section-97">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-94">¶</a>
|
||||
<a class="pilcrow" href="#section-97">¶</a>
|
||||
</div>
|
||||
<p>Token matching regexes.</p>
|
||||
|
||||
@@ -2427,11 +2488,11 @@ HERE_JSTOKEN = <span class="hljs-regexp">///^ ``` ((?: [^`\\] | \\[\s\S] | `
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-95">
|
||||
<li id="section-98">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-95">¶</a>
|
||||
<a class="pilcrow" href="#section-98">¶</a>
|
||||
</div>
|
||||
<p>String-matching-regexes.</p>
|
||||
|
||||
@@ -2465,11 +2526,11 @@ HEREDOC_INDENT = <span class="hljs-regexp">/\n+([^\n\S]*)(?=\S)/g</span></pr
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-96">
|
||||
<li id="section-99">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-96">¶</a>
|
||||
<a class="pilcrow" href="#section-99">¶</a>
|
||||
</div>
|
||||
<p>Regex-matching-regexes.</p>
|
||||
|
||||
@@ -2503,11 +2564,11 @@ POSSIBLY_DIVISION = <span class="hljs-regexp">/// ^ /=?\s ///</span></pre></di
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-97">
|
||||
<li id="section-100">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-97">¶</a>
|
||||
<a class="pilcrow" href="#section-100">¶</a>
|
||||
</div>
|
||||
<p>Other regexes.</p>
|
||||
|
||||
@@ -2550,11 +2611,11 @@ TRAILING_SPACES = <span class="hljs-regexp">/\s+$/</span></pre></div></div>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-98">
|
||||
<li id="section-101">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-98">¶</a>
|
||||
<a class="pilcrow" href="#section-101">¶</a>
|
||||
</div>
|
||||
<p>Compound assignment tokens.</p>
|
||||
|
||||
@@ -2568,11 +2629,11 @@ TRAILING_SPACES = <span class="hljs-regexp">/\s+$/</span></pre></div></div>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-99">
|
||||
<li id="section-102">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-99">¶</a>
|
||||
<a class="pilcrow" href="#section-102">¶</a>
|
||||
</div>
|
||||
<p>Unary tokens.</p>
|
||||
|
||||
@@ -2585,11 +2646,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-100">
|
||||
<li id="section-103">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-100">¶</a>
|
||||
<a class="pilcrow" href="#section-103">¶</a>
|
||||
</div>
|
||||
<p>Bit-shifting tokens.</p>
|
||||
|
||||
@@ -2600,11 +2661,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-101">
|
||||
<li id="section-104">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-101">¶</a>
|
||||
<a class="pilcrow" href="#section-104">¶</a>
|
||||
</div>
|
||||
<p>Comparison tokens.</p>
|
||||
|
||||
@@ -2615,11 +2676,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-102">
|
||||
<li id="section-105">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-102">¶</a>
|
||||
<a class="pilcrow" href="#section-105">¶</a>
|
||||
</div>
|
||||
<p>Mathematical tokens.</p>
|
||||
|
||||
@@ -2630,11 +2691,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-103">
|
||||
<li id="section-106">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-103">¶</a>
|
||||
<a class="pilcrow" href="#section-106">¶</a>
|
||||
</div>
|
||||
<p>Relational tokens that are negatable with <code>not</code> prefix.</p>
|
||||
|
||||
@@ -2645,11 +2706,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-104">
|
||||
<li id="section-107">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-104">¶</a>
|
||||
<a class="pilcrow" href="#section-107">¶</a>
|
||||
</div>
|
||||
<p>Boolean tokens.</p>
|
||||
|
||||
@@ -2660,11 +2721,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-105">
|
||||
<li id="section-108">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-105">¶</a>
|
||||
<a class="pilcrow" href="#section-108">¶</a>
|
||||
</div>
|
||||
<p>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 [
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-106">
|
||||
<li id="section-109">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-106">¶</a>
|
||||
<a class="pilcrow" href="#section-109">¶</a>
|
||||
</div>
|
||||
<p>Tokens which can be the left-hand side of a less-than comparison, i.e. <code>a<b</code>.</p>
|
||||
|
||||
@@ -2696,11 +2757,11 @@ INDEXABLE = CALLABLE.concat [
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-107">
|
||||
<li id="section-110">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-107">¶</a>
|
||||
<a class="pilcrow" href="#section-110">¶</a>
|
||||
</div>
|
||||
<p>Tokens which a regular expression will never immediately follow (except spaced
|
||||
CALLABLEs in some cases), but which a division operator can.</p>
|
||||
@@ -2713,11 +2774,11 @@ CALLABLEs in some cases), but which a division operator can.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-108">
|
||||
<li id="section-111">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-108">¶</a>
|
||||
<a class="pilcrow" href="#section-111">¶</a>
|
||||
</div>
|
||||
<p>Tokens that, when immediately preceding a <code>WHEN</code>, indicate that the <code>WHEN</code>
|
||||
occurs at the start of a line. We disambiguate these from trailing whens to
|
||||
@@ -2730,11 +2791,11 @@ avoid an ambiguity in the grammar.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-109">
|
||||
<li id="section-112">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-109">¶</a>
|
||||
<a class="pilcrow" href="#section-112">¶</a>
|
||||
</div>
|
||||
<p>Additional indent in front of these is ignored.</p>
|
||||
|
||||
@@ -2745,11 +2806,11 @@ avoid an ambiguity in the grammar.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-110">
|
||||
<li id="section-113">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-110">¶</a>
|
||||
<a class="pilcrow" href="#section-113">¶</a>
|
||||
</div>
|
||||
<p>Tokens that, when appearing at the end of a line, suppress a following TERMINATOR/INDENT token</p>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
0
docs/v2/annotated-source/public/fonts/roboto-black.eot
Executable file → Normal file
0
docs/v2/annotated-source/public/fonts/roboto-black.eot
Executable file → Normal file
0
docs/v2/annotated-source/public/fonts/roboto-black.ttf
Executable file → Normal file
0
docs/v2/annotated-source/public/fonts/roboto-black.ttf
Executable file → Normal file
0
docs/v2/annotated-source/public/fonts/roboto-black.woff
Executable file → Normal file
0
docs/v2/annotated-source/public/fonts/roboto-black.woff
Executable file → Normal file
@@ -306,9 +306,9 @@ Unwrap that too.</p>
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> isAsync
|
||||
result = <span class="hljs-keyword">await</span> result
|
||||
cb <span class="hljs-literal">null</span>, result <span class="hljs-keyword">unless</span> sawSIGINT
|
||||
sawSIGINT = <span class="hljs-literal">false</span>
|
||||
result.<span class="hljs-keyword">then</span> (resolvedResult) ->
|
||||
cb <span class="hljs-literal">null</span>, resolvedResult <span class="hljs-keyword">unless</span> sawSIGINT
|
||||
sawSIGINT = <span class="hljs-literal">no</span>
|
||||
<span class="hljs-keyword">else</span>
|
||||
cb <span class="hljs-literal">null</span>, result
|
||||
<span class="hljs-keyword">catch</span> err</pre></div></div>
|
||||
|
||||
@@ -234,6 +234,7 @@ output the token stream after it has been rewritten by this file.</p>
|
||||
@normalizeLines()
|
||||
@tagPostfixConditionals()
|
||||
@addImplicitBracesAndParens()
|
||||
@addParensToChainedDoIife()
|
||||
@rescueStowawayComments()
|
||||
@addLocationDataToGeneratedTokens()
|
||||
@enforceValidCSXAttributes()
|
||||
@@ -694,7 +695,8 @@ Added support for spread dots on the left side: f …a</p>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (tag <span class="hljs-keyword">in</span> IMPLICIT_FUNC <span class="hljs-keyword">and</span> token.spaced <span class="hljs-keyword">or</span>
|
||||
tag <span class="hljs-keyword">is</span> <span class="hljs-string">'?'</span> <span class="hljs-keyword">and</span> i > <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> tokens[i - <span class="hljs-number">1</span>].spaced) <span class="hljs-keyword">and</span>
|
||||
(nextTag <span class="hljs-keyword">in</span> IMPLICIT_CALL <span class="hljs-keyword">or</span> nextTag <span class="hljs-keyword">is</span> <span class="hljs-string">'...'</span> <span class="hljs-keyword">or</span>
|
||||
(nextTag <span class="hljs-keyword">in</span> IMPLICIT_CALL <span class="hljs-keyword">or</span>
|
||||
(nextTag <span class="hljs-keyword">is</span> <span class="hljs-string">'...'</span> <span class="hljs-keyword">and</span> @tag(i + <span class="hljs-number">2</span>) <span class="hljs-keyword">in</span> IMPLICIT_CALL <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @findTagsBackwards(i, [<span class="hljs-string">'INDEX_START'</span>, <span class="hljs-string">'['</span>])) <span class="hljs-keyword">or</span>
|
||||
nextTag <span class="hljs-keyword">in</span> IMPLICIT_UNSPACED_CALL <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> nextToken.spaced <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> nextToken.newLine)
|
||||
tag = token[<span class="hljs-number">0</span>] = <span class="hljs-string">'FUNC_EXIST'</span> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'?'</span>
|
||||
@@ -767,7 +769,7 @@ that creates grammatical ambiguities.</p>
|
||||
<span class="hljs-keyword">when</span> @tag(i - <span class="hljs-number">2</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'@'</span> <span class="hljs-keyword">then</span> i - <span class="hljs-number">2</span>
|
||||
<span class="hljs-keyword">else</span> i - <span class="hljs-number">1</span>
|
||||
|
||||
startsLine = s <span class="hljs-keyword">is</span> <span class="hljs-number">0</span> <span class="hljs-keyword">or</span> @tag(s - <span class="hljs-number">1</span>) <span class="hljs-keyword">in</span> LINEBREAKS <span class="hljs-keyword">or</span> tokens[s - <span class="hljs-number">1</span>].newLine</pre></div></div>
|
||||
startsLine = s <= <span class="hljs-number">0</span> <span class="hljs-keyword">or</span> @tag(s - <span class="hljs-number">1</span>) <span class="hljs-keyword">in</span> LINEBREAKS <span class="hljs-keyword">or</span> tokens[s - <span class="hljs-number">1</span>].newLine</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -1197,6 +1199,42 @@ location corresponding to the last “real” token under the node.</p>
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-48">¶</a>
|
||||
</div>
|
||||
<p>Add parens around a <code>do</code> IIFE followed by a chained <code>.</code> so that the
|
||||
chaining applies to the executed function rather than the function
|
||||
object (see #3736)</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> addParensToChainedDoIife: <span class="hljs-function">-></span>
|
||||
<span class="hljs-function"> <span class="hljs-title">condition</span> = <span class="hljs-params">(token, i)</span> -></span>
|
||||
@tag(i - <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'OUTDENT'</span>
|
||||
<span class="hljs-function"> <span class="hljs-title">action</span> = <span class="hljs-params">(token, i)</span> -></span>
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> token[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> CALL_CLOSERS
|
||||
@tokens.splice doIndex, <span class="hljs-number">0</span>, generate <span class="hljs-string">'('</span>, <span class="hljs-string">'('</span>, @tokens[doIndex]
|
||||
@tokens.splice i + <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, generate <span class="hljs-string">')'</span>, <span class="hljs-string">')'</span>, @tokens[i]
|
||||
doIndex = <span class="hljs-literal">null</span>
|
||||
@scanTokens (token, i, tokens) ->
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">1</span> <span class="hljs-keyword">unless</span> token[<span class="hljs-number">1</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'do'</span>
|
||||
doIndex = i
|
||||
glyphIndex = i + <span class="hljs-number">1</span>
|
||||
<span class="hljs-keyword">if</span> @tag(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'PARAM_START'</span>
|
||||
glyphIndex = <span class="hljs-literal">null</span>
|
||||
@detectEnd i + <span class="hljs-number">1</span>,
|
||||
<span class="hljs-function"><span class="hljs-params">(token, i)</span> -></span> @tag(i - <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'PARAM_END'</span>
|
||||
(token, i) -> glyphIndex = i
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">1</span> <span class="hljs-keyword">unless</span> glyphIndex? <span class="hljs-keyword">and</span> @tag(glyphIndex) <span class="hljs-keyword">in</span> [<span class="hljs-string">'->'</span>, <span class="hljs-string">'=>'</span>] <span class="hljs-keyword">and</span> @tag(glyphIndex + <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'INDENT'</span>
|
||||
@detectEnd glyphIndex + <span class="hljs-number">1</span>, condition, action
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">2</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-49">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-49">¶</a>
|
||||
</div>
|
||||
<p>Because our grammar is LALR(1), it can’t handle some single-line
|
||||
expressions that lack ending delimiters. The <strong>Rewriter</strong> adds the implicit
|
||||
blocks, so it doesn’t need to. To keep the grammar clean and tidy, trailing
|
||||
@@ -1250,11 +1288,11 @@ blocks are added.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-49">
|
||||
<li id="section-50">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-49">¶</a>
|
||||
<a class="pilcrow" href="#section-50">¶</a>
|
||||
</div>
|
||||
<p>Tag postfix conditionals as such, so that we can parse them with a
|
||||
different precedence.</p>
|
||||
@@ -1282,11 +1320,11 @@ different precedence.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-50">
|
||||
<li id="section-51">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-50">¶</a>
|
||||
<a class="pilcrow" href="#section-51">¶</a>
|
||||
</div>
|
||||
<p>Generate the indentation tokens, based on another token on the same line.</p>
|
||||
|
||||
@@ -1307,11 +1345,11 @@ different precedence.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-51">
|
||||
<li id="section-52">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-51">¶</a>
|
||||
<a class="pilcrow" href="#section-52">¶</a>
|
||||
</div>
|
||||
<p>Look up a tag by token index.</p>
|
||||
|
||||
@@ -1322,26 +1360,14 @@ different precedence.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-52">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-52">¶</a>
|
||||
</div>
|
||||
<h2 id="constants">Constants</h2>
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-53">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-53">¶</a>
|
||||
</div>
|
||||
|
||||
<h2 id="constants">Constants</h2>
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
@@ -1353,6 +1379,18 @@ different precedence.</p>
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-54">¶</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-55">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-55">¶</a>
|
||||
</div>
|
||||
<p>List of the token pairs that must be balanced.</p>
|
||||
|
||||
</div>
|
||||
@@ -1372,11 +1410,11 @@ different precedence.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-55">
|
||||
<li id="section-56">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-55">¶</a>
|
||||
<a class="pilcrow" href="#section-56">¶</a>
|
||||
</div>
|
||||
<p>The inverse mappings of <code>BALANCED_PAIRS</code> we’re trying to fix up, so we can
|
||||
look things up from either end.</p>
|
||||
@@ -1388,11 +1426,11 @@ look things up from either end.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-56">
|
||||
<li id="section-57">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-56">¶</a>
|
||||
<a class="pilcrow" href="#section-57">¶</a>
|
||||
</div>
|
||||
<p>The tokens that signal the start/end of a balanced pair.</p>
|
||||
|
||||
@@ -1408,11 +1446,11 @@ EXPRESSION_END = []
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-57">
|
||||
<li id="section-58">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-57">¶</a>
|
||||
<a class="pilcrow" href="#section-58">¶</a>
|
||||
</div>
|
||||
<p>Tokens that indicate the close of a clause of an expression.</p>
|
||||
|
||||
@@ -1423,11 +1461,11 @@ EXPRESSION_END = []
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-58">
|
||||
<li id="section-59">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-58">¶</a>
|
||||
<a class="pilcrow" href="#section-59">¶</a>
|
||||
</div>
|
||||
<p>Tokens that, if followed by an <code>IMPLICIT_CALL</code>, indicate a function invocation.</p>
|
||||
|
||||
@@ -1438,11 +1476,11 @@ EXPRESSION_END = []
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-59">
|
||||
<li id="section-60">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-59">¶</a>
|
||||
<a class="pilcrow" href="#section-60">¶</a>
|
||||
</div>
|
||||
<p>If preceded by an <code>IMPLICIT_FUNC</code>, indicates a function invocation.</p>
|
||||
|
||||
@@ -1462,11 +1500,11 @@ IMPLICIT_UNSPACED_CALL = [<span class="hljs-string">'+'</span>, <span class="hlj
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-60">
|
||||
<li id="section-61">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-60">¶</a>
|
||||
<a class="pilcrow" href="#section-61">¶</a>
|
||||
</div>
|
||||
<p>Tokens that always mark the end of an implicit call for single-liners.</p>
|
||||
|
||||
@@ -1478,11 +1516,11 @@ IMPLICIT_UNSPACED_CALL = [<span class="hljs-string">'+'</span>, <span class="hlj
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-61">
|
||||
<li id="section-62">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-61">¶</a>
|
||||
<a class="pilcrow" href="#section-62">¶</a>
|
||||
</div>
|
||||
<p>Single-line flavors of block expressions that have unclosed endings.
|
||||
The grammar can’t disambiguate them, so we insert the implicit indentation.</p>
|
||||
@@ -1495,11 +1533,11 @@ SINGLE_CLOSERS = [<span class="hljs-string">'TERMINATOR'</span>, <span class="
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-62">
|
||||
<li id="section-63">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-62">¶</a>
|
||||
<a class="pilcrow" href="#section-63">¶</a>
|
||||
</div>
|
||||
<p>Tokens that end a line.</p>
|
||||
|
||||
@@ -1510,11 +1548,11 @@ SINGLE_CLOSERS = [<span class="hljs-string">'TERMINATOR'</span>, <span class="
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-63">
|
||||
<li id="section-64">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-63">¶</a>
|
||||
<a class="pilcrow" href="#section-64">¶</a>
|
||||
</div>
|
||||
<p>Tokens that close open calls when they follow a newline.</p>
|
||||
|
||||
@@ -1525,11 +1563,11 @@ SINGLE_CLOSERS = [<span class="hljs-string">'TERMINATOR'</span>, <span class="
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-64">
|
||||
<li id="section-65">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-64">¶</a>
|
||||
<a class="pilcrow" href="#section-65">¶</a>
|
||||
</div>
|
||||
<p>Tokens that prevent a subsequent indent from ending implicit calls/objects</p>
|
||||
|
||||
@@ -1540,11 +1578,11 @@ SINGLE_CLOSERS = [<span class="hljs-string">'TERMINATOR'</span>, <span class="
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-65">
|
||||
<li id="section-66">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-65">¶</a>
|
||||
<a class="pilcrow" href="#section-66">¶</a>
|
||||
</div>
|
||||
<p>Tokens that are swallowed up by the parser, never leading to code generation.
|
||||
You can spot these in <code>grammar.coffee</code> because the <code>o</code> function second
|
||||
|
||||
@@ -370,11 +370,18 @@ column for the current line:</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> v3 =
|
||||
<div class="content"><div class='highlight'><pre> sources = <span class="hljs-keyword">if</span> options.sourceFiles
|
||||
options.sourceFiles
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> options.filename
|
||||
[options.filename]
|
||||
<span class="hljs-keyword">else</span>
|
||||
[<span class="hljs-string">'<anonymous>'</span>]
|
||||
|
||||
v3 =
|
||||
version: <span class="hljs-number">3</span>
|
||||
file: options.generatedFile <span class="hljs-keyword">or</span> <span class="hljs-string">''</span>
|
||||
sourceRoot: options.sourceRoot <span class="hljs-keyword">or</span> <span class="hljs-string">''</span>
|
||||
sources: options.sourceFiles <span class="hljs-keyword">or</span> [<span class="hljs-string">''</span>]
|
||||
sources: sources
|
||||
names: []
|
||||
mappings: buffer
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,10 @@
|
||||
# Eat lunch.
|
||||
eat = (food) -> "#{food} eaten."
|
||||
eat food for food in ['toast', 'cheese', 'wine']
|
||||
|
||||
# Fine five course dining.
|
||||
courses = ['greens', 'caviar', 'truffles', 'roast', 'cake']
|
||||
menu = (i, dish) -> "Menu Item #{i}: #{dish}"
|
||||
menu i + 1, dish for dish, i in courses
|
||||
|
||||
# Health conscious meal.
|
||||
|
||||
@@ -2,5 +2,5 @@ $ 'body'
|
||||
.click (e) ->
|
||||
$ '.box'
|
||||
.fadeIn 'fast'
|
||||
.addClass '.active'
|
||||
.addClass 'show'
|
||||
.css 'background', 'white'
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
## Changelog
|
||||
|
||||
```
|
||||
releaseHeader('2017-09-02', '2.0.0-beta5', '2.0.0-beta4')
|
||||
```
|
||||
|
||||
* Node 6 is now supported, and we will try to maintain that as the minimum required version for CoffeeScript 2 via the `coffee` command or Node API. Older versions of Node, or non-evergreen browsers, can compile via the [browser compiler](./browser-compiler/coffeescript.js).
|
||||
* The command line `--output` flag now allows you to specify an output filename, not just an output folder.
|
||||
* The command line `--require` flag now properly handles filenames or module names that are invalid identifiers (like an NPM module with a hyphen in the name).
|
||||
* `Object.assign`, output when object destructuring is used, is polyfilled using the same polyfill that Babel outputs. This means that polyfills shouldn’t be required unless support for Internet Explorer 8 or below is desired (or your own code uses a feature that requires a polyfill). See [ES2015+ Output](#es2015plus-output).
|
||||
* A string or JSX interpolation that contains only a comment (`"a#{### comment ###}b"` or `<div>{### comment ###}</div>`) is now output (`` `a${/* comment */}b` ``)
|
||||
* Interpolated strings (ES2015 template literals) that contain quotation marks no longer have the quotation marks escaped: `` `say "${message}"` ``
|
||||
* It is now possible to chain after a function literal (for example, to define a function and then call `.call` on it).
|
||||
* The results of the async tests are included in the output when you run `cake test`.
|
||||
* Bugfixes for object destructuring; expansions in function parameters; generated reference variables in function parameters; chained functions after `do`; splats after existential operator soaks in arrays (`[a?.b...]`); trailing `if` with splat in arrays or function parameters (`[a if b...]`); attempting to `throw` an `if`, `for`, `switch`, `while` or other invalid construct.
|
||||
* Bugfixes for syntactical edge cases: semicolons after `=` and other “mid-expression” tokens; spaces after `::`; and scripts that begin with `:` or `*`.
|
||||
* Bugfixes for source maps generated via the Node API; and stack trace line numbers when compiling CoffeeScript via the Node API from within a `.coffee` file.
|
||||
|
||||
```
|
||||
releaseHeader('2017-08-03', '2.0.0-beta4', '2.0.0-beta3')
|
||||
```
|
||||
|
||||
@@ -11,3 +11,5 @@ npm install --global coffeescript@next
|
||||
npm install --save-dev coffeescript@next babel-cli babel-preset-env
|
||||
coffee --print *.coffee | babel --presets env > app.js
|
||||
```
|
||||
|
||||
Note that [babel-preset-env](https://babeljs.io/docs/plugins/preset-env/) doesn’t automatically supply polyfills for your code. CoffeeScript itself will output [`Array.indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) if you use the `in` operator, or destructuring or spread/rest syntax; and [`Function.bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) if you use a bound (`=>`) method in a class. Both are supported in Internet Explorer 9+ and all more recent browsers, but you will need to supply polyfills if you need to support Internet Explorer 8 or below and are using features that would cause these methods to be output, or in your own code are using similarly modern methods. One option is [`babel-polyfill`](https://babeljs.io/docs/usage/polyfill/), though there are many [other](https://hackernoon.com/polyfills-everything-you-ever-wanted-to-know-or-maybe-a-bit-less-7c8de164e423) [strategies](https://philipwalton.com/articles/loading-polyfills-only-when-needed/).
|
||||
|
||||
@@ -20,6 +20,6 @@ The `compile` method has the signature `compile(code, options)` where `code` is
|
||||
|
||||
* `options.sourceMap`, boolean: if true, a source map will be generated; and instead of returning a string, `compile` will return an object of the form `{js, v3SourceMap, sourceMap}`.
|
||||
* `options.inlineMap`, boolean: if true, output the source map as a base64-encoded string in a comment at the bottom.
|
||||
* `options.filename`, string: the filename to use for the source map.
|
||||
* `options.filename`, string: the filename to use for the source map. It can include a path (relative or absolute).
|
||||
* `options.bare`, boolean: if true, output without the [top-level function safety wrapper](#lexical-scope).
|
||||
* `options.header`, boolean: if true, output the `Generated by CoffeeScript` header.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Overview
|
||||
|
||||
_CoffeeScript on the <span class="hidden-md-up">top</span><span class="hidden-sm-down">left</span>, compiled JavaScript output on the <span class="hidden-md-up">bottom</span><span class="hidden-sm-down">right</span>. The CoffeeScript is editable!_
|
||||
_CoffeeScript on the <span class="d-md-none">top</span><span class="d-none d-md-inline">left</span>, compiled JavaScript output on the <span class="d-md-none">bottom</span><span class="d-none d-md-inline">right</span>. The CoffeeScript is editable!_
|
||||
|
||||
```
|
||||
codeFor('overview', 'cubes', false)
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
Newcomers to CoffeeScript often wonder how to generate the JavaScript `function foo() {}`, as opposed to the `foo = function() {}` that CoffeeScript produces. The first form is a [function declaration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function), and the second is a [function expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function). As stated above, in CoffeeScript [everything is an expression](#expressions), so naturally we favor the expression form. Supporting only one variant helps avoid confusing bugs that can arise from the [subtle differences between the two forms](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function#Function_declaration_hoisting).
|
||||
|
||||
Technically, `foo = function() {}` is creating an anonymous function that gets assigned to a variable named `foo`. Some very early versions of CoffeeScript named this function, e.g. `foo = function foo() {}`, but this was dropped because of compatibility issues with Internet Explorer. For a while this annoyed people, as these functions would be unnamed in stack traces; but modern JavaScript runtimes [infer the names of such anonymous functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name) from the names of the variables to which they’re assigned. Given that this is the case, and given that not all functions in function expressions can be named (for example, the functions in `first.fn = ->; second.fn = ->` can’t both be named `fn`) it’s simplest to just preserve the current behavior.
|
||||
Technically, `foo = function() {}` is creating an anonymous function that gets assigned to a variable named `foo`. Some very early versions of CoffeeScript named this function, e.g. `foo = function foo() {}`, but this was dropped because of compatibility issues with Internet Explorer. For a while this annoyed people, as these functions would be unnamed in stack traces; but modern JavaScript runtimes [infer the names of such anonymous functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name) from the names of the variables to which they’re assigned. Given that this is the case, it’s simplest to just preserve the current behavior.
|
||||
|
||||
@@ -52,16 +52,27 @@ say = (msg, className) ->
|
||||
stdout.appendChild div
|
||||
msg
|
||||
|
||||
asyncTests = []
|
||||
onFail = (description, fn, err) ->
|
||||
failures.push
|
||||
error: err
|
||||
description: description
|
||||
source: fn.toString() if fn.toString?
|
||||
|
||||
@test = (description, fn) ->
|
||||
++total
|
||||
try
|
||||
fn.call(fn)
|
||||
++passedTests
|
||||
catch error
|
||||
failures.push
|
||||
error: error
|
||||
description: description
|
||||
source: fn.toString() if fn.toString?
|
||||
result = fn.call(fn)
|
||||
if result instanceof Promise # An async test.
|
||||
asyncTests.push result
|
||||
result.then ->
|
||||
passedTests++
|
||||
.catch (err) ->
|
||||
onFail description, fn, err
|
||||
else
|
||||
passedTests++
|
||||
catch err
|
||||
onFail description, fn, err
|
||||
|
||||
@failures =
|
||||
push: (failure) -> # Match function called by regular tests
|
||||
@@ -74,11 +85,11 @@ say = (msg, className) ->
|
||||
@ok = (good, msg = 'Error') ->
|
||||
throw Error msg unless good
|
||||
|
||||
# Polyfill Node assert's fail
|
||||
# Polyfill Node assert’s fail
|
||||
@fail = ->
|
||||
ok no
|
||||
|
||||
# Polyfill Node assert's deepEqual with Underscore's isEqual
|
||||
# Polyfill Node assert’s deepEqual with Underscore’s isEqual
|
||||
@deepEqual = (a, b) ->
|
||||
ok _.isEqual(a, b), "Expected #{JSON.stringify a} to deep equal #{JSON.stringify b}"
|
||||
|
||||
@@ -114,11 +125,14 @@ for test in document.getElementsByClassName 'test'
|
||||
CoffeeScript.run test.innerHTML, options
|
||||
|
||||
# Finish up
|
||||
yay = passedTests is total and not failedTests
|
||||
sec = (new Date - start) / 1000
|
||||
msg = "passed #{passedTests} tests in #{sec.toFixed 2} seconds"
|
||||
msg = "failed #{total - passedTests} tests and #{msg}" unless yay
|
||||
say msg, (if yay then 'good' else 'bad')
|
||||
done = ->
|
||||
yay = passedTests is total and not failedTests
|
||||
sec = (new Date - start) / 1000
|
||||
msg = "passed #{passedTests} tests in #{sec.toFixed 2} seconds"
|
||||
msg = "failed #{total - passedTests} tests and #{msg}" unless yay
|
||||
say msg, (if yay then 'good' else 'bad')
|
||||
|
||||
Promise.all(asyncTests).then(done).catch(done)
|
||||
</script>
|
||||
|
||||
<%= tests %>
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
<nav class="sidebar sidebar-offcanvas col-xs-12 col-lg-3 bg-ribbed-light">
|
||||
<%= include('sidebar.html') %>
|
||||
</nav>
|
||||
<main class="main col-xs-12 col-lg-9 offset-lg-3">
|
||||
<main class="main col-lg-9 ml-auto">
|
||||
|
||||
<header class="title-logo hidden-md-down">
|
||||
<header class="title-logo d-none d-lg-block">
|
||||
<%= include('documentation/images/logo.svg') %>
|
||||
</header>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</div>
|
||||
<% if (run) { %>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 text-xs-right">
|
||||
<div class="col text-right">
|
||||
<button type="button" class="btn btn-primary" data-action="run-code-example" data-example="<%= file %>" data-run="<%= escape(run) %>"><% if (run === true) { %>▶<% } else { %><small>▶</small> <%= run.replace(/"/g, '"') %><% } %></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
$(document).ready ->
|
||||
# Mobile navigation
|
||||
toggleSidebar = ->
|
||||
$('.menu-button, .row-offcanvas').toggleClass 'active'
|
||||
$('.navbar-toggler, .row-offcanvas').toggleClass 'show'
|
||||
|
||||
$('[data-toggle="offcanvas"]').click toggleSidebar
|
||||
|
||||
$('[data-action="sidebar-nav"]').click (event) ->
|
||||
if $('.menu-button').is(':visible')
|
||||
if $('.navbar-toggler').is(':visible')
|
||||
event.preventDefault()
|
||||
toggleSidebar()
|
||||
setTimeout ->
|
||||
@@ -20,12 +20,12 @@ $(document).ready ->
|
||||
offset: Math.round $('main').css('padding-top').replace('px', '')
|
||||
|
||||
initializeScrollspyFromHash = (hash) ->
|
||||
$(".nav-link.active[href!='#{hash}']").removeClass 'active'
|
||||
$("#contents a.active[href!='#{hash}']").removeClass 'show'
|
||||
|
||||
$(window).on 'activate.bs.scrollspy', (event, target) -> # Why `window`? https://github.com/twbs/bootstrap/issues/20086
|
||||
# We only want one active link in the nav
|
||||
$(".nav-link.active[href!='#{target.relatedTarget}']").removeClass 'active'
|
||||
$target = $(".nav-link[href='#{target.relatedTarget}']")
|
||||
$("#contents a.active[href!='#{target.relatedTarget}']").removeClass 'show'
|
||||
$target = $("#contents a[href='#{target.relatedTarget}']")
|
||||
# Update the browser address bar on scroll or navigation
|
||||
window.history.pushState {}, $target.text(), $target.prop('href')
|
||||
|
||||
@@ -58,7 +58,7 @@ $(document).ready ->
|
||||
lastCompilationStartTime = Date.now()
|
||||
try
|
||||
coffee = editor.getValue()
|
||||
if index is 0 and $('#try').hasClass('active') # If this is the editor in Try CoffeeScript and it’s still visible
|
||||
if index is 0 and $('#try').hasClass('show') # If this is the editor in Try CoffeeScript and it’s still visible
|
||||
# Update the hash with the current code
|
||||
link = "try:#{encodeURIComponent coffee}"
|
||||
window.history.pushState {}, 'CoffeeScript', "#{location.href.split('#')[0]}##{link}"
|
||||
@@ -107,9 +107,9 @@ $(document).ready ->
|
||||
if coffee?
|
||||
editors[0].setValue coffee
|
||||
catch exception
|
||||
$('#try, #try-link').toggleClass 'active'
|
||||
$('#try, #try-link').toggleClass 'show'
|
||||
closeTry = ->
|
||||
$('#try, #try-link').removeClass 'active'
|
||||
$('#try, #try-link').removeClass 'show'
|
||||
|
||||
$('[data-toggle="try"]').click toggleTry
|
||||
$('[data-close="try"]').click closeTry
|
||||
@@ -124,5 +124,6 @@ $(document).ready ->
|
||||
toggleTry()
|
||||
else
|
||||
initializeScrollspyFromHash window.location.hash
|
||||
# Initializing the code editors might’ve thrown off our vertical scroll position
|
||||
document.getElementById(window.location.hash.slice(1)).scrollIntoView()
|
||||
if window.location.hash.length > 1
|
||||
# Initializing the code editors might’ve thrown off our vertical scroll position
|
||||
document.getElementById(window.location.hash.slice(1).replace(/try:.*/, '')).scrollIntoView()
|
||||
|
||||
@@ -27,7 +27,12 @@ a:focus, a:hover, a:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.bg-inverse {
|
||||
button:focus, .navbar-dark .navbar-toggler:focus {
|
||||
outline: none;
|
||||
border: thin solid rgba(248, 243, 240, 0.3);
|
||||
}
|
||||
|
||||
.bg-dark {
|
||||
background-color: #3e2723 !important;
|
||||
}
|
||||
|
||||
@@ -44,92 +49,35 @@ a:focus, a:hover, a:active {
|
||||
/*
|
||||
* Header
|
||||
*/
|
||||
.navbar-fixed-top {
|
||||
.site-navbar {
|
||||
height: 3.5rem;
|
||||
font-family: Lato;
|
||||
font-weight: 400;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
height: 2em;
|
||||
margin-right: 2em;
|
||||
height: 2.2em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.navbar-dark path {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
.navbar-nav {
|
||||
font-family: Lato;
|
||||
font-weight: 400;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.navbar-nav .nav-link {
|
||||
padding-left: 0.6em;
|
||||
padding-right: 0.6em;
|
||||
.navbar-nav .nav-item {
|
||||
margin-left: 0.6em;
|
||||
margin-right: 0.6em;
|
||||
border-radius: 0.4em;
|
||||
}
|
||||
.navbar-nav .nav-link:hover,
|
||||
.navbar-nav .nav-link:active,
|
||||
.navbar-nav .nav-link.active {
|
||||
.navbar-nav .nav-item:hover,
|
||||
.navbar-nav .nav-item:active,
|
||||
.navbar-nav .nav-item.show {
|
||||
background-color: #4e342e;
|
||||
}
|
||||
|
||||
/* Adapted from https://codepen.io/GeoffreyBooth/pen/QGzwYK */
|
||||
.navbar-menu-button,
|
||||
.navbar-menu-button:focus {
|
||||
float: right;
|
||||
width: 2.3em;
|
||||
padding: 0;
|
||||
margin-top: 0.25em;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
}
|
||||
.menu-button {
|
||||
width: 2em;
|
||||
height: 1.5em;
|
||||
position: relative;
|
||||
transform: rotate(0deg);
|
||||
transition: .25s ease-in-out;
|
||||
cursor: pointer;
|
||||
}
|
||||
.menu-button span {
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 4px;
|
||||
width: 100%;
|
||||
background: #efebe9;
|
||||
border-radius: 4px;
|
||||
opacity: 1;
|
||||
left: 0;
|
||||
transform: rotate(0deg);
|
||||
transition: .25s ease-in-out;
|
||||
}
|
||||
.menu-button span:nth-child(1) {
|
||||
top: 0;
|
||||
}
|
||||
.menu-button span:nth-child(2),
|
||||
.menu-button span:nth-child(3) {
|
||||
top: 0.7em;
|
||||
}
|
||||
.menu-button span:nth-child(4) {
|
||||
top: 1.4em;
|
||||
}
|
||||
.menu-button.active span:nth-child(1) {
|
||||
top: 0.7em;
|
||||
width: 0%;
|
||||
left: 50%;
|
||||
}
|
||||
.menu-button.active span:nth-child(2) {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.menu-button.active span:nth-child(3) {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
.menu-button.active span:nth-child(4) {
|
||||
top: 0.7em;
|
||||
width: 0%;
|
||||
left: 50%;
|
||||
.navbar-toggler {
|
||||
transition: all 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
|
||||
@@ -152,40 +100,44 @@ a:focus, a:hover, a:active {
|
||||
/* Scrollable contents if viewport is shorter than content */
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 0.5em 0 0.5em 0.3em;
|
||||
font-family: 'Alegreya Sans';
|
||||
font-weight: 400;
|
||||
font-size: 1.2em;
|
||||
line-height: 2;
|
||||
align-items: normal;
|
||||
}
|
||||
.sidebar .contents::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
@media screen and (max-width: 991px) {
|
||||
.sidebar .contents {
|
||||
position: fixed;
|
||||
height: calc(100% - 3.5rem);
|
||||
padding: 1em 1.6em;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 992px) {
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
}
|
||||
.sidebar .contents {
|
||||
padding: 1.3em;
|
||||
}
|
||||
.sidebar .contents::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar .nav-link.active,
|
||||
.sidebar .nav-link.active a:hover,
|
||||
.sidebar .nav-link.active a:focus {
|
||||
font-weight: 800;
|
||||
.contents-column {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nav .nav {
|
||||
.contents .nav .nav {
|
||||
margin-left: 1em;
|
||||
font-size: 0.9em;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.contents .nav-link {
|
||||
padding: 0.2em 0.7em;
|
||||
}
|
||||
|
||||
.contents .nav-link.active,
|
||||
.contents .nav-link.active a:hover,
|
||||
.contents .nav-link.active a:focus {
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
|
||||
@@ -209,7 +161,7 @@ a:focus, a:hover, a:active {
|
||||
.row-offcanvas-left .sidebar-offcanvas {
|
||||
left: -100%;
|
||||
}
|
||||
.row-offcanvas-left.active {
|
||||
.row-offcanvas-left.show {
|
||||
left: calc(100% + 30px)
|
||||
}
|
||||
}
|
||||
@@ -218,7 +170,7 @@ a:focus, a:hover, a:active {
|
||||
left: calc(-66.667% - 15px);
|
||||
width: 66.667%;
|
||||
}
|
||||
.row-offcanvas-left.active {
|
||||
.row-offcanvas-left.show {
|
||||
left: calc(66.667% + 30px);
|
||||
}
|
||||
.row-offcanvas-left .sidebar-offcanvas .contents {
|
||||
@@ -251,8 +203,19 @@ a:focus, a:hover, a:active {
|
||||
|
||||
.main p, .main li, .main td, .main th {
|
||||
font-family: Lato;
|
||||
font-size: 1.3rem;
|
||||
font-weight: 300;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
.main blockquote {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.main p, .main li, .main td, .main th {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
.main blockquote {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
}
|
||||
.main td {
|
||||
vertical-align: top;
|
||||
@@ -268,9 +231,6 @@ a:focus, a:hover, a:active {
|
||||
.main a:focus, .main a:hover, .main a:active {
|
||||
border-bottom: 2px solid rgba(56, 142, 60, 0.2);
|
||||
}
|
||||
.main blockquote {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
.main blockquote pre {
|
||||
background-color: #f8f3f0;
|
||||
color: #2f2625;
|
||||
@@ -308,8 +268,11 @@ code, button {
|
||||
font-family: 'Roboto Mono';
|
||||
font-weight: 400;
|
||||
}
|
||||
code {
|
||||
code, a > code {
|
||||
background-color: #f8f3f0;
|
||||
padding: 0.2rem 0.4rem;
|
||||
}
|
||||
code {
|
||||
color: #2f2625;
|
||||
}
|
||||
|
||||
@@ -355,7 +318,18 @@ textarea {
|
||||
font-family: 'Roboto Mono';
|
||||
font-weight: 400;
|
||||
line-height: 1.25;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.CodeMirror {
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.CodeMirror-code:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.javascript-output-column .CodeMirror-cursor {
|
||||
/* https://github.com/codemirror/CodeMirror/issues/2568 */
|
||||
display: none;
|
||||
@@ -373,7 +347,7 @@ textarea {
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease-in-out;
|
||||
}
|
||||
.try-coffeescript.active {
|
||||
.try-coffeescript.show {
|
||||
opacity: 1;
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
<nav class="navbar navbar-dark navbar-fixed-top bg-inverse bg-ribbed-dark">
|
||||
<nav class="navbar navbar-expand-lg fixed-top navbar-dark bg-dark bg-ribbed-dark site-navbar">
|
||||
<a class="navbar-brand" href="#" data-close="try"><%= include('documentation/images/logo.svg') %></a>
|
||||
<nav class="nav navbar-nav float-xs-left hidden-md-down">
|
||||
<a href="#try" id="try-link" class="nav-item nav-link" data-toggle="try">Try CoffeeScript</a>
|
||||
<a href="#language" class="nav-item nav-link" data-close="try">Language Reference</a>
|
||||
<a href="#resources" class="nav-item nav-link" data-close="try">Resources</a>
|
||||
<a href="http://github.com/jashkenas/coffeescript/" class="nav-item nav-link" data-close="try">GitHub</a>
|
||||
</nav>
|
||||
<button type="button" class="navbar-menu-button hidden-lg-up" data-toggle="offcanvas" aria-label="Toggle sidebar">
|
||||
<div class="menu-button">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
<button class="navbar-toggler" type="button" data-toggle="offcanvas" data-close="try" aria-label="Toggle sidebar">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<nav class="collapse navbar-collapse">
|
||||
<ul class="navbar-nav mr-auto d-none d-lg-flex">
|
||||
<a href="#try" id="try-link" class="nav-item nav-link" data-toggle="try">Try CoffeeScript</a>
|
||||
<a href="#language" class="nav-item nav-link" data-close="try">Language Reference</a>
|
||||
<a href="#resources" class="nav-item nav-link" data-close="try">Resources</a>
|
||||
<a href="http://github.com/jashkenas/coffeescript/" class="nav-item nav-link" data-close="try">GitHub
|
||||
</a>
|
||||
</nav>
|
||||
</nav>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha384-3ceskX3iaEnIogmQchP8opvBy3Mi7Ce34nWjpBIwVTHfGYWQS9jwHDVRnpKKHJg7" crossorigin="anonymous"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js" integrity="sha384-xBuQ/xzmlsLoJpyjoggmTEz8OWUFM0/RC5BsqQBDX2v5cMvDHcMakNTNrHIW2I5f" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
window.Tether = {}; // Remove if we want to use Bootstrap tooltips
|
||||
window.Popper = {}; // Remove if we want to use Bootstrap tooltips
|
||||
</script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/js/bootstrap.min.js" integrity="sha384-BLiI7JTZm+JWlgKa0M0kGRpJbF2J8q+qreVrKBC47e3K6BW78kGLrCkeRX6I9RoK" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/g/codemirror@4.5.0(codemirror.min.js+mode/coffeescript/coffeescript.js+addon/lint/coffeescript-lint.js+mode/javascript/javascript.js)" crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/combine/npm/codemirror@5.29.0/lib/codemirror.js,npm/codemirror@5.29.0/mode/coffeescript/coffeescript.js,npm/codemirror@5.29.0/addon/lint/coffeescript-lint.js,npm/codemirror@5.29.0/mode/javascript/javascript.js"></script>
|
||||
|
||||
<script src="browser-compiler/coffeescript.js"></script>
|
||||
<script type="text/coffeescript">
|
||||
|
||||
@@ -1,200 +1,78 @@
|
||||
<nav class="contents" id="contents">
|
||||
<ul class="nav">
|
||||
<li class="nav-item">
|
||||
<a href="#top" class="nav-link" data-action="sidebar-nav">Overview</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#coffeescript-2" class="nav-link" data-action="sidebar-nav">CoffeeScript 2</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#installation" class="nav-link" data-action="sidebar-nav">Installation</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#usage" class="nav-link" data-action="sidebar-nav">Usage</a>
|
||||
<ul class="nav">
|
||||
<li class="nav-item">
|
||||
<a href="#cli" class="nav-link" data-action="sidebar-nav">Command Line</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#es2015plus-output" class="nav-link" data-action="sidebar-nav">ES2015+ Output</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#nodejs-usage" class="nav-link" data-action="sidebar-nav">Node.js</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#language" class="nav-link" data-action="sidebar-nav">Language Reference</a>
|
||||
<ul class="nav">
|
||||
<li class="nav-item">
|
||||
<a href="#functions" class="nav-link" data-action="sidebar-nav">Functions</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#strings" class="nav-link" data-action="sidebar-nav">Strings</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#objects-and-arrays" class="nav-link" data-action="sidebar-nav">Objects and Arrays</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#comments" class="nav-link" data-action="sidebar-nav">Comments</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#lexical-scope" class="nav-link" data-action="sidebar-nav">Lexical Scoping and Variable Safety</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#conditionals" class="nav-link" data-action="sidebar-nav">If, Else, Unless, and Conditional Assignment</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#splats" class="nav-link" data-action="sidebar-nav">Splats, or Rest Parameters/Spread Syntax</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#loops" class="nav-link" data-action="sidebar-nav">Loops and Comprehensions</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#slices" class="nav-link" data-action="sidebar-nav">Array Slicing and Splicing</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#expressions" class="nav-link" data-action="sidebar-nav">Everything is an Expression</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#operators" class="nav-link" data-action="sidebar-nav">Operators and Aliases</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#existential-operator" class="nav-link" data-action="sidebar-nav">Existential Operator</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#destructuring" class="nav-link" data-action="sidebar-nav">Destructuring Assignment</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#chaining" class="nav-link" data-action="sidebar-nav">Chaining Function Calls</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#fat-arrow" class="nav-link" data-action="sidebar-nav">Bound (Fat Arrow) Functions</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#generators" class="nav-link" data-action="sidebar-nav">Generator Functions</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#async-functions" class="nav-link" data-action="sidebar-nav">Async Functions</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#classes" class="nav-link" data-action="sidebar-nav">Classes</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#prototypal-inheritance" class="nav-link" data-action="sidebar-nav">Prototypal Inheritance</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#switch" class="nav-link" data-action="sidebar-nav">Switch and Try/Catch</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#comparisons" class="nav-link" data-action="sidebar-nav">Chained Comparisons</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#regexes" class="nav-link" data-action="sidebar-nav">Block Regular Expressions</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#tagged-template-literals" class="nav-link" data-action="sidebar-nav">Tagged Template Literals</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#modules" class="nav-link" data-action="sidebar-nav">Modules</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#embedded" class="nav-link" data-action="sidebar-nav">Embedded JavaScript</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#jsx" class="nav-link" data-action="sidebar-nav">JSX</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#type-annotations" class="nav-link" data-action="sidebar-nav">Type Annotations</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#literate" class="nav-link" data-action="sidebar-nav">Literate CoffeeScript</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#source-maps" class="nav-link" data-action="sidebar-nav">Source Maps</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#cake" class="nav-link" data-action="sidebar-nav">Cake, and Cakefiles</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#scripts" class="nav-link" data-action="sidebar-nav"><code>"text/coffeescript"</code> Script Tags</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="test.html" class="nav-link" data-action="sidebar-nav">Browser-Based Tests</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#resources" class="nav-link" data-action="sidebar-nav">Resources</a>
|
||||
<ul class="nav">
|
||||
<li class="nav-item">
|
||||
<a href="#books" class="nav-link" data-action="sidebar-nav">Books</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#screencasts" class="nav-link" data-action="sidebar-nav">Screencasts</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#examples" class="nav-link" data-action="sidebar-nav">Examples</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#chat" class="nav-link" data-action="sidebar-nav">Chat</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#annotated-source" class="nav-link" data-action="sidebar-nav">Annotated Source</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#contributing" class="nav-link" data-action="sidebar-nav">Contributing</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#unsupported" class="nav-link" data-action="sidebar-nav">Unsupported ECMAScript Features</a>
|
||||
<ul class="nav">
|
||||
<li class="nav-item">
|
||||
<a href="#unsupported-let-const" class="nav-link" data-action="sidebar-nav"><code>let</code> and <code>const</code></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#unsupported-named-functions" class="nav-link" data-action="sidebar-nav">Named Functions and Function Declarations</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#unsupported-get-set" class="nav-link" data-action="sidebar-nav"><code>get</code> and <code>set</code> Shorthand Syntax</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#breaking-changes" class="nav-link" data-action="sidebar-nav">Breaking Changes From 1.x</a>
|
||||
<ul class="nav">
|
||||
<li class="nav-item">
|
||||
<a href="#breaking-change-fat-arrow" class="nav-link" data-action="sidebar-nav">Bound (Fat Arrow) Functions</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#breaking-changes-default-values" class="nav-link" data-action="sidebar-nav">Default Values</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#breaking-changes-bound-generator-functions" class="nav-link" data-action="sidebar-nav">Bound Generator Functions</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#breaking-changes-classes" class="nav-link" data-action="sidebar-nav">Classes</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#breaking-changes-super-extends" class="nav-link" data-action="sidebar-nav"><code>super</code> and <code>extends</code></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#breaking-changes-jsx-and-the-less-than-and-greater-than-operators" class="nav-link" data-action="sidebar-nav">JSX and the <code><</code> and <code>></code> Operators</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#breaking-changes-literate-coffeescript" class="nav-link" data-action="sidebar-nav">Literate CoffeeScript Parsing</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#breaking-changes-argument-parsing-and-shebang-lines" class="nav-link" data-action="sidebar-nav">Argument Parsing and <code>#!</code> Lines</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#changelog" class="nav-link" data-action="sidebar-nav">Changelog</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/v1/" class="nav-link" data-action="sidebar-nav">Version 1.x Documentation</a>
|
||||
</li>
|
||||
</ul>
|
||||
<nav id="contents" class="navbar contents">
|
||||
<nav class="nav flex-column contents-column">
|
||||
<a href="#try" class="nav-link d-md-none" data-action="sidebar-nav" data-toggle="try">Try CoffeeScript</a>
|
||||
<a href="#top" class="nav-link" data-action="sidebar-nav">Overview</a>
|
||||
<a href="#coffeescript-2" class="nav-link" data-action="sidebar-nav">CoffeeScript 2</a>
|
||||
<a href="#installation" class="nav-link" data-action="sidebar-nav">Installation</a>
|
||||
<a href="#usage" class="nav-link" data-action="sidebar-nav">Usage</a>
|
||||
<nav class="nav flex-column">
|
||||
<a href="#cli" class="nav-link" data-action="sidebar-nav">Command Line</a>
|
||||
<a href="#es2015plus-output" class="nav-link" data-action="sidebar-nav">ES2015+ Output</a>
|
||||
<a href="#nodejs-usage" class="nav-link" data-action="sidebar-nav">Node.js</a>
|
||||
</nav>
|
||||
<a href="#language" class="nav-link" data-action="sidebar-nav">Language Reference</a>
|
||||
<nav class="nav flex-column">
|
||||
<a href="#functions" class="nav-link" data-action="sidebar-nav">Functions</a>
|
||||
<a href="#strings" class="nav-link" data-action="sidebar-nav">Strings</a>
|
||||
<a href="#objects-and-arrays" class="nav-link" data-action="sidebar-nav">Objects and Arrays</a>
|
||||
<a href="#comments" class="nav-link" data-action="sidebar-nav">Comments</a>
|
||||
<a href="#lexical-scope" class="nav-link" data-action="sidebar-nav">Lexical Scoping and Variable Safety</a>
|
||||
<a href="#conditionals" class="nav-link" data-action="sidebar-nav">If, Else, Unless, and Conditional Assignment</a>
|
||||
<a href="#splats" class="nav-link" data-action="sidebar-nav">Splats, or Rest Parameters/Spread Syntax</a>
|
||||
<a href="#loops" class="nav-link" data-action="sidebar-nav">Loops and Comprehensions</a>
|
||||
<a href="#slices" class="nav-link" data-action="sidebar-nav">Array Slicing and Splicing</a>
|
||||
<a href="#expressions" class="nav-link" data-action="sidebar-nav">Everything is an Expression</a>
|
||||
<a href="#operators" class="nav-link" data-action="sidebar-nav">Operators and Aliases</a>
|
||||
<a href="#existential-operator" class="nav-link" data-action="sidebar-nav">Existential Operator</a>
|
||||
<a href="#destructuring" class="nav-link" data-action="sidebar-nav">Destructuring Assignment</a>
|
||||
<a href="#chaining" class="nav-link" data-action="sidebar-nav">Chaining Function Calls</a>
|
||||
<a href="#fat-arrow" class="nav-link" data-action="sidebar-nav">Bound (Fat Arrow) Functions</a>
|
||||
<a href="#generators" class="nav-link" data-action="sidebar-nav">Generator Functions</a>
|
||||
<a href="#async-functions" class="nav-link" data-action="sidebar-nav">Async Functions</a>
|
||||
<a href="#classes" class="nav-link" data-action="sidebar-nav">Classes</a>
|
||||
<a href="#prototypal-inheritance" class="nav-link" data-action="sidebar-nav">Prototypal Inheritance</a>
|
||||
<a href="#switch" class="nav-link" data-action="sidebar-nav">Switch and Try/Catch</a>
|
||||
<a href="#comparisons" class="nav-link" data-action="sidebar-nav">Chained Comparisons</a>
|
||||
<a href="#regexes" class="nav-link" data-action="sidebar-nav">Block Regular Expressions</a>
|
||||
<a href="#tagged-template-literals" class="nav-link" data-action="sidebar-nav">Tagged Template Literals</a>
|
||||
<a href="#modules" class="nav-link" data-action="sidebar-nav">Modules</a>
|
||||
<a href="#embedded" class="nav-link" data-action="sidebar-nav">Embedded JavaScript</a>
|
||||
<a href="#jsx" class="nav-link" data-action="sidebar-nav">JSX</a>
|
||||
</nav>
|
||||
<a href="#type-annotations" class="nav-link" data-action="sidebar-nav">Type Annotations</a>
|
||||
<a href="#literate" class="nav-link" data-action="sidebar-nav">Literate CoffeeScript</a>
|
||||
<a href="#source-maps" class="nav-link" data-action="sidebar-nav">Source Maps</a>
|
||||
<a href="#cake" class="nav-link" data-action="sidebar-nav">Cake, and Cakefiles</a>
|
||||
<a href="#scripts" class="nav-link" data-action="sidebar-nav"><code>"text/coffeescript"</code> Script Tags</a>
|
||||
<a href="test.html" class="nav-link" data-action="sidebar-nav">Browser-Based Tests</a>
|
||||
<a href="#resources" class="nav-link" data-action="sidebar-nav">Resources</a>
|
||||
<nav class="nav flex-column">
|
||||
<a href="#books" class="nav-link" data-action="sidebar-nav">Books</a>
|
||||
<a href="#screencasts" class="nav-link" data-action="sidebar-nav">Screencasts</a>
|
||||
<a href="#examples" class="nav-link" data-action="sidebar-nav">Examples</a>
|
||||
<a href="#chat" class="nav-link" data-action="sidebar-nav">Chat</a>
|
||||
<a href="#annotated-source" class="nav-link" data-action="sidebar-nav">Annotated Source</a>
|
||||
<a href="#contributing" class="nav-link" data-action="sidebar-nav">Contributing</a>
|
||||
</nav>
|
||||
<a href="http://github.com/jashkenas/coffeescript/" class="nav-item nav-link d-md-none" data-action="sidebar-nav">GitHub</a>
|
||||
<a href="#unsupported" class="nav-link" data-action="sidebar-nav">Unsupported ECMAScript Features</a>
|
||||
<nav class="nav flex-column">
|
||||
<a href="#unsupported-let-const" class="nav-link" data-action="sidebar-nav"><code>let</code> and <code>const</code></a>
|
||||
<a href="#unsupported-named-functions" class="nav-link" data-action="sidebar-nav">Named Functions and Function Declarations</a>
|
||||
<a href="#unsupported-get-set" class="nav-link" data-action="sidebar-nav"><code>get</code> and <code>set</code> Shorthand Syntax</a>
|
||||
</nav>
|
||||
<a href="#breaking-changes" class="nav-link" data-action="sidebar-nav">Breaking Changes From 1.x</a>
|
||||
<nav class="nav flex-column">
|
||||
<a href="#breaking-change-fat-arrow" class="nav-link" data-action="sidebar-nav">Bound (Fat Arrow) Functions</a>
|
||||
<a href="#breaking-changes-default-values" class="nav-link" data-action="sidebar-nav">Default Values</a>
|
||||
<a href="#breaking-changes-bound-generator-functions" class="nav-link" data-action="sidebar-nav">Bound Generator Functions</a>
|
||||
<a href="#breaking-changes-classes" class="nav-link" data-action="sidebar-nav">Classes</a>
|
||||
<a href="#breaking-changes-super-extends" class="nav-link" data-action="sidebar-nav"><code>super</code> and <code>extends</code></a>
|
||||
<a href="#breaking-changes-jsx-and-the-less-than-and-greater-than-operators" class="nav-link" data-action="sidebar-nav">JSX and the <code><</code> and <code>></code> Operators</a>
|
||||
<a href="#breaking-changes-literate-coffeescript" class="nav-link" data-action="sidebar-nav">Literate CoffeeScript Parsing</a>
|
||||
<a href="#breaking-changes-argument-parsing-and-shebang-lines" class="nav-link" data-action="sidebar-nav">Argument Parsing and <code>#!</code> Lines</a>
|
||||
</nav>
|
||||
<a href="#changelog" class="nav-link" data-action="sidebar-nav">Changelog</a>
|
||||
<a href="/v1/" class="nav-link" data-action="sidebar-nav">Version 1.x Documentation</a>
|
||||
</nav>
|
||||
</nav>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/css/bootstrap.min.css" integrity="sha384-AysaV+vQoT3kOAXZkl02PThvDr8HYKPZhNT5h/CXfBThSRXQ6jW5DO2ekP5ViFdi" crossorigin="anonymous">
|
||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
|
||||
<!-- The CoffeeScript logo font is Google’s Galada -->
|
||||
<link href="https://fonts.googleapis.com/css?family=Alegreya+Sans:400,800|Lato:300,300i,400,700|Roboto+Mono:400,400i" rel="stylesheet" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/codemirror/4.5.0/codemirror.css" crossorigin="anonymous">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 text-xs-right try-buttons">
|
||||
<div class="col text-right try-buttons">
|
||||
<button type="button" class="btn btn-primary" data-action="run-code-example" data-example="try-coffeescript" data-run="true">▶</button> 
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0-beta4
|
||||
// Generated by CoffeeScript 2.0.0-beta5
|
||||
(function() {
|
||||
// This **Browser** compatibility layer extends core CoffeeScript functions
|
||||
// to make things work smoothly when compiling code directly in the browser.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0-beta4
|
||||
// Generated by CoffeeScript 2.0.0-beta5
|
||||
(function() {
|
||||
// `cake` is a simplified version of [Make](http://www.gnu.org/software/make/)
|
||||
// ([Rake](http://rake.rubyforge.org/), [Jake](https://github.com/280north/jake))
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// Generated by CoffeeScript 2.0.0-beta4
|
||||
// Generated by CoffeeScript 2.0.0-beta5
|
||||
(function() {
|
||||
// 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.
|
||||
var Lexer, SourceMap, base64encode, checkShebangLine, compile, formatSourcePosition, getSourceMap, helpers, lexer, packageJson, parser, sourceMaps, sources, withPrettyErrors;
|
||||
var FILE_EXTENSIONS, Lexer, SourceMap, base64encode, checkShebangLine, compile, formatSourcePosition, getSourceMap, helpers, lexer, packageJson, parser, sourceMaps, sources, withPrettyErrors,
|
||||
indexOf = [].indexOf;
|
||||
|
||||
({Lexer} = require('./lexer'));
|
||||
|
||||
@@ -21,7 +22,7 @@
|
||||
// The current CoffeeScript version number.
|
||||
exports.VERSION = packageJson.version;
|
||||
|
||||
exports.FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md'];
|
||||
exports.FILE_EXTENSIONS = FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md'];
|
||||
|
||||
// Expose helpers for testing.
|
||||
exports.helpers = helpers;
|
||||
@@ -67,10 +68,10 @@
|
||||
// a stack trace. Assuming that most of the time, code isn’t throwing
|
||||
// exceptions, it’s probably more efficient to compile twice only when we
|
||||
// need a stack trace, rather than always generating a source map even when
|
||||
// it’s not likely to be used. Save in form of `filename`: `(source)`
|
||||
// it’s not likely to be used. Save in form of `filename`: [`(source)`]
|
||||
sources = {};
|
||||
|
||||
// Also save source maps if generated, in form of `filename`: `(source map)`.
|
||||
// Also save source maps if generated, in form of `(source)`: [`(source map)`].
|
||||
sourceMaps = {};
|
||||
|
||||
// Compile CoffeeScript code to JavaScript, using the Coffee/Jison compiler.
|
||||
@@ -93,7 +94,10 @@
|
||||
generateSourceMap = options.sourceMap || options.inlineMap || (options.filename == null);
|
||||
filename = options.filename || '<anonymous>';
|
||||
checkShebangLine(filename, code);
|
||||
sources[filename] = code;
|
||||
if (sources[filename] == null) {
|
||||
sources[filename] = [];
|
||||
}
|
||||
sources[filename].push(code);
|
||||
if (generateSourceMap) {
|
||||
map = new SourceMap;
|
||||
}
|
||||
@@ -158,7 +162,10 @@
|
||||
}
|
||||
if (generateSourceMap) {
|
||||
v3SourceMap = map.generate(options, code);
|
||||
sourceMaps[filename] = map;
|
||||
if (sourceMaps[filename] == null) {
|
||||
sourceMaps[filename] = [];
|
||||
}
|
||||
sourceMaps[filename].push(map);
|
||||
}
|
||||
if (options.inlineMap) {
|
||||
encoded = base64encode(JSON.stringify(v3SourceMap));
|
||||
@@ -311,17 +318,43 @@
|
||||
}
|
||||
};
|
||||
|
||||
getSourceMap = function(filename) {
|
||||
var answer;
|
||||
if (sourceMaps[filename] != null) {
|
||||
return sourceMaps[filename];
|
||||
// CoffeeScript compiled in a browser may get compiled with `options.filename`
|
||||
// of `<anonymous>`, but the browser may request the stack trace with the
|
||||
// filename of the script file.
|
||||
getSourceMap = function(filename, line, column) {
|
||||
var answer, i, map, ref, ref1, sourceLocation;
|
||||
if (!(filename === '<anonymous>' || (ref = filename.slice(filename.lastIndexOf('.')), indexOf.call(FILE_EXTENSIONS, ref) >= 0))) {
|
||||
// Skip files that we didn’t compile, like Node system files that appear in
|
||||
// the stack trace, as they never have source maps.
|
||||
return null;
|
||||
}
|
||||
if (filename !== '<anonymous>' && (sourceMaps[filename] != null)) {
|
||||
return sourceMaps[filename][sourceMaps[filename].length - 1];
|
||||
// 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>'] != null) {
|
||||
return sourceMaps['<anonymous>'];
|
||||
} else if (sources[filename] != null) {
|
||||
answer = compile(sources[filename], {
|
||||
ref1 = 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 (i = ref1.length - 1; i >= 0; i += -1) {
|
||||
map = ref1[i];
|
||||
sourceLocation = map.sourceLocation([line - 1, column - 1]);
|
||||
if (((sourceLocation != null ? sourceLocation[0] : void 0) != null) && (sourceLocation[1] != null)) {
|
||||
return map;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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] != null) {
|
||||
answer = compile(sources[filename][sources[filename].length - 1], {
|
||||
filename: filename,
|
||||
sourceMap: true,
|
||||
literate: helpers.isLiterate(filename)
|
||||
@@ -340,7 +373,7 @@
|
||||
var frame, frames, getSourceMapping;
|
||||
getSourceMapping = function(filename, line, column) {
|
||||
var answer, sourceMap;
|
||||
sourceMap = getSourceMap(filename);
|
||||
sourceMap = getSourceMap(filename, line, column);
|
||||
if (sourceMap != null) {
|
||||
answer = sourceMap.sourceLocation([line - 1, column - 1]);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0-beta4
|
||||
// Generated by CoffeeScript 2.0.0-beta5
|
||||
(function() {
|
||||
// The `coffee` utility. Handles command-line compilation of CoffeeScript
|
||||
// into various forms: saved into `.js` files or printed to stdout
|
||||
@@ -45,7 +45,7 @@
|
||||
BANNER = 'Usage: coffee [options] path/to/script.coffee [args]\n\nIf called without options, `coffee` will run your script.';
|
||||
|
||||
// The list of all the valid option flags that `coffee` knows how to handle.
|
||||
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'], ['-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']];
|
||||
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 [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']];
|
||||
|
||||
// Top-level objects shared by all the functions.
|
||||
opts = {};
|
||||
@@ -68,7 +68,7 @@
|
||||
// Many flags cause us to divert before compiling anything. Flags passed after
|
||||
// `--` will be passed verbatim to your script as arguments in `process.argv`
|
||||
exports.run = function() {
|
||||
var err, i, len, literals, ref, replCliOpts, results, source;
|
||||
var err, i, len, literals, outputBasename, ref, replCliOpts, results, source;
|
||||
optionParser = buildCSOptionParser();
|
||||
try {
|
||||
parseOptions();
|
||||
@@ -117,7 +117,16 @@
|
||||
process.argv = process.argv.slice(0, 2).concat(literals);
|
||||
process.argv[0] = 'coffee';
|
||||
if (opts.output) {
|
||||
opts.output = path.resolve(opts.output);
|
||||
outputBasename = path.basename(opts.output);
|
||||
if (indexOf.call(outputBasename, '.') >= 0 && (outputBasename !== '.' && outputBasename !== '..') && !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);
|
||||
@@ -135,12 +144,12 @@
|
||||
|
||||
makePrelude = function(requires) {
|
||||
return requires.map(function(module) {
|
||||
var _, match, name;
|
||||
var full, match, name;
|
||||
if (match = module.match(/^(.*)=(.*)$/)) {
|
||||
[_, name, module] = match;
|
||||
[full, name, module] = match;
|
||||
}
|
||||
name || (name = helpers.baseFileName(module, true, useWinPathSep));
|
||||
return `${name} = require('${module}')`;
|
||||
return `global['${name}'] = require('${module}')`;
|
||||
}).join(';');
|
||||
};
|
||||
|
||||
@@ -235,43 +244,43 @@
|
||||
};
|
||||
|
||||
// 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 = function(file, input, base = null) {
|
||||
var compiled, err, message, o, options, t, task;
|
||||
o = opts;
|
||||
var compiled, err, message, options, saveTo, task;
|
||||
options = compileOptions(file, base);
|
||||
try {
|
||||
t = task = {file, input, options};
|
||||
task = {file, input, options};
|
||||
CoffeeScript.emit('compile', task);
|
||||
if (o.tokens) {
|
||||
return printTokens(CoffeeScript.tokens(t.input, t.options));
|
||||
} else if (o.nodes) {
|
||||
return printLine(CoffeeScript.nodes(t.input, t.options).toString().trim());
|
||||
} else if (o.run) {
|
||||
if (opts.tokens) {
|
||||
return printTokens(CoffeeScript.tokens(task.input, task.options));
|
||||
} else if (opts.nodes) {
|
||||
return printLine(CoffeeScript.nodes(task.input, task.options).toString().trim());
|
||||
} else if (opts.run) {
|
||||
CoffeeScript.register();
|
||||
if (opts.prelude) {
|
||||
CoffeeScript.eval(opts.prelude, t.options);
|
||||
CoffeeScript.eval(opts.prelude, task.options);
|
||||
}
|
||||
return CoffeeScript.run(t.input, t.options);
|
||||
} else if (o.join && t.file !== o.join) {
|
||||
return CoffeeScript.run(task.input, task.options);
|
||||
} else if (opts.join && task.file !== opts.join) {
|
||||
if (helpers.isLiterate(file)) {
|
||||
t.input = helpers.invertLiterate(t.input);
|
||||
task.input = helpers.invertLiterate(task.input);
|
||||
}
|
||||
sourceCode[sources.indexOf(t.file)] = t.input;
|
||||
sourceCode[sources.indexOf(task.file)] = task.input;
|
||||
return 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) {
|
||||
return printLine(t.output.trim());
|
||||
} else if (o.compile || o.map) {
|
||||
return writeJs(base, t.file, t.output, options.jsPath, t.sourceMap);
|
||||
if (opts.print) {
|
||||
return printLine(task.output.trim());
|
||||
} else if (opts.compile || opts.map) {
|
||||
saveTo = opts.outputFilename && sources.length === 1 ? path.join(opts.outputPath, opts.outputFilename) : options.jsPath;
|
||||
return writeJs(base, task.file, task.output, saveTo, task.sourceMap);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -281,7 +290,7 @@
|
||||
return;
|
||||
}
|
||||
message = (err != null ? err.stack : void 0) || `${err}`;
|
||||
if (o.watch) {
|
||||
if (opts.watch) {
|
||||
return printLine(message + '\x07');
|
||||
} else {
|
||||
printWarn(message);
|
||||
@@ -486,13 +495,7 @@
|
||||
var basename, dir, srcDir;
|
||||
basename = helpers.baseFileName(source, true, useWinPathSep);
|
||||
srcDir = path.dirname(source);
|
||||
if (!opts.output) {
|
||||
dir = srcDir;
|
||||
} else if (source === base) {
|
||||
dir = opts.output;
|
||||
} else {
|
||||
dir = path.join(opts.output, path.relative(base, srcDir));
|
||||
}
|
||||
dir = !opts.outputPath ? srcDir : source === base ? opts.outputPath : path.join(opts.outputPath, path.relative(base, srcDir));
|
||||
return path.join(dir, basename + extension);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0-beta4
|
||||
// Generated by CoffeeScript 2.0.0-beta5
|
||||
(function() {
|
||||
// The CoffeeScript parser is generated by [Jison](https://github.com/zaach/jison)
|
||||
// from this grammar file. Jison is a bottom-up parser generator, similar in
|
||||
@@ -487,6 +487,10 @@
|
||||
function() {
|
||||
return $1.add($2);
|
||||
}),
|
||||
o('Code Accessor',
|
||||
function() {
|
||||
return new Value($1).add($2);
|
||||
}),
|
||||
o('ThisProperty')
|
||||
],
|
||||
// Everything that can be assigned to.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0-beta4
|
||||
// Generated by CoffeeScript 2.0.0-beta5
|
||||
(function() {
|
||||
// This file contains the common helper functions that we'd like to share among
|
||||
// the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0-beta4
|
||||
// Generated by CoffeeScript 2.0.0-beta5
|
||||
(function() {
|
||||
// Node.js Implementation
|
||||
var CoffeeScript, compile, ext, fn, fs, helpers, i, len, path, ref, vm,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0-beta4
|
||||
// Generated by CoffeeScript 2.0.0-beta5
|
||||
(function() {
|
||||
// The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt
|
||||
// matches against the beginning of the source code. When a match is found,
|
||||
@@ -672,9 +672,7 @@
|
||||
if (dent) {
|
||||
this.outdebt -= moveOut;
|
||||
}
|
||||
while (this.value() === ';') {
|
||||
this.tokens.pop();
|
||||
}
|
||||
this.suppressSemicolons();
|
||||
if (!(this.tag() === 'TERMINATOR' || noNewlines)) {
|
||||
this.token('TERMINATOR', '\n', outdentLength, 0);
|
||||
}
|
||||
@@ -703,9 +701,7 @@
|
||||
|
||||
// Generate a newline token. Consecutive newlines get merged together.
|
||||
newlineToken(offset) {
|
||||
while (this.value() === ';') {
|
||||
this.tokens.pop();
|
||||
}
|
||||
this.suppressSemicolons();
|
||||
if (this.tag() !== 'TERMINATOR') {
|
||||
this.token('TERMINATOR', '\n', offset, 0);
|
||||
}
|
||||
@@ -844,7 +840,7 @@
|
||||
// here. `;` and newlines are both treated as a `TERMINATOR`, we distinguish
|
||||
// parentheses that indicate a method call from regular parentheses, and so on.
|
||||
literalToken() {
|
||||
var match, message, origin, prev, ref, ref1, ref2, ref3, skipToken, tag, token, value;
|
||||
var match, message, origin, prev, ref, ref1, ref2, ref3, ref4, skipToken, tag, token, value;
|
||||
if (match = OPERATOR.exec(this.chunk)) {
|
||||
[value] = match;
|
||||
if (CODE.test(value)) {
|
||||
@@ -884,9 +880,12 @@
|
||||
this.exportSpecifierList = false;
|
||||
}
|
||||
if (value === ';') {
|
||||
if (ref2 = prev != null ? prev[0] : void 0, indexOf.call(['=', ...UNFINISHED], ref2) >= 0) {
|
||||
this.error('unexpected ;');
|
||||
}
|
||||
this.seenFor = this.seenImport = this.seenExport = false;
|
||||
tag = 'TERMINATOR';
|
||||
} else if (value === '*' && prev[0] === 'EXPORT') {
|
||||
} else if (value === '*' && (prev != null ? prev[0] : void 0) === 'EXPORT') {
|
||||
tag = 'EXPORT_ALL';
|
||||
} else if (indexOf.call(MATH, value) >= 0) {
|
||||
tag = 'MATH';
|
||||
@@ -902,13 +901,13 @@
|
||||
tag = 'SHIFT';
|
||||
} else if (value === '?' && (prev != null ? prev.spaced : void 0)) {
|
||||
tag = 'BIN?';
|
||||
} else if (prev && !prev.spaced) {
|
||||
if (value === '(' && (ref2 = prev[0], indexOf.call(CALLABLE, ref2) >= 0)) {
|
||||
} else if (prev) {
|
||||
if (value === '(' && !prev.spaced && (ref3 = prev[0], indexOf.call(CALLABLE, ref3) >= 0)) {
|
||||
if (prev[0] === '?') {
|
||||
prev[0] = 'FUNC_EXIST';
|
||||
}
|
||||
tag = 'CALL_START';
|
||||
} else if (value === '[' && (ref3 = prev[0], indexOf.call(INDEXABLE, ref3) >= 0)) {
|
||||
} else if (value === '[' && (((ref4 = prev[0], indexOf.call(INDEXABLE, ref4) >= 0) && !prev.spaced) || (prev[0] === '::'))) { // `.prototype` can’t be a method you can call.
|
||||
tag = 'INDEX_START';
|
||||
switch (prev[0]) {
|
||||
case '?':
|
||||
@@ -1089,7 +1088,7 @@
|
||||
// of `'NEOSTRING'`s are converted using `fn` and turned into strings using
|
||||
// `options` first.
|
||||
mergeInterpolationTokens(tokens, options, fn) {
|
||||
var converted, firstEmptyStringIndex, firstIndex, i, j, lastToken, len, locationToken, lparen, plusToken, rparen, tag, token, tokensToPush, value;
|
||||
var converted, firstEmptyStringIndex, firstIndex, i, j, k, lastToken, len, len1, locationToken, lparen, placeholderToken, plusToken, rparen, tag, token, tokensToPush, val, value;
|
||||
if (tokens.length > 1) {
|
||||
lparen = this.token('STRING_START', '(', 0, 0);
|
||||
}
|
||||
@@ -1100,8 +1099,32 @@
|
||||
switch (tag) {
|
||||
case 'TOKENS':
|
||||
if (value.length === 2) {
|
||||
// Optimize out empty interpolations (an empty pair of parentheses).
|
||||
continue;
|
||||
if (!(value[0].comments || value[1].comments)) {
|
||||
// Optimize out empty interpolations (an empty pair of parentheses).
|
||||
continue;
|
||||
}
|
||||
// There are comments (and nothing else) in this interpolation.
|
||||
if (this.csxDepth === 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 = this.makeToken('STRING', "''");
|
||||
} else {
|
||||
placeholderToken = this.makeToken('JS', '');
|
||||
}
|
||||
// Use the same location data as the first parenthesis.
|
||||
placeholderToken[2] = value[0][2];
|
||||
for (k = 0, len1 = value.length; k < len1; k++) {
|
||||
val = value[k];
|
||||
if (!val.comments) {
|
||||
continue;
|
||||
}
|
||||
if (placeholderToken.comments == null) {
|
||||
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.
|
||||
@@ -1383,6 +1406,20 @@
|
||||
return `${options.delimiter}${body}${options.delimiter}`;
|
||||
}
|
||||
|
||||
suppressSemicolons() {
|
||||
var ref, ref1, results;
|
||||
results = [];
|
||||
while (this.value() === ';') {
|
||||
this.tokens.pop();
|
||||
if (ref = (ref1 = this.prev()) != null ? ref1[0] : void 0, indexOf.call(['=', ...UNFINISHED], ref) >= 0) {
|
||||
results.push(this.error('unexpected ;'));
|
||||
} else {
|
||||
results.push(void 0);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
// Throws an error at either a given offset from the current chunk or at the
|
||||
// location of a token (`token[2]`).
|
||||
error(message, options = {}) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0-beta4
|
||||
// Generated by CoffeeScript 2.0.0-beta5
|
||||
(function() {
|
||||
// `nodes.coffee` contains all of the node classes for the syntax tree. Most
|
||||
// nodes are created as the result of actions in the [grammar](grammar.html),
|
||||
@@ -145,6 +145,10 @@
|
||||
return fragments;
|
||||
}
|
||||
|
||||
compileToFragmentsWithoutComments(o, lvl) {
|
||||
return this.compileWithoutComments(o, lvl, 'compileToFragments');
|
||||
}
|
||||
|
||||
// Statements converted into expressions via closure-wrapping share a scope
|
||||
// object with their parent closure, to preserve the expected lexical scope.
|
||||
compileClosure(o) {
|
||||
@@ -1043,17 +1047,19 @@
|
||||
exports.StringLiteral = StringLiteral = class StringLiteral extends Literal {
|
||||
compileNode(o) {
|
||||
var res;
|
||||
return res = this.csx ? [this.makeCode(this.unquote(true))] : super.compileNode();
|
||||
return res = this.csx ? [this.makeCode(this.unquote(true, true))] : super.compileNode();
|
||||
}
|
||||
|
||||
unquote(literal) {
|
||||
unquote(doubleQuote = false, newLine = false) {
|
||||
var unquoted;
|
||||
unquoted = this.value.slice(1, -1);
|
||||
if (literal) {
|
||||
return unquoted.replace(/\\n/g, '\n').replace(/\\"/g, '"');
|
||||
} else {
|
||||
return unquoted;
|
||||
if (doubleQuote) {
|
||||
unquoted = unquoted.replace(/\\"/g, '"');
|
||||
}
|
||||
if (newLine) {
|
||||
unquoted = unquoted.replace(/\\n/g, '\n');
|
||||
}
|
||||
return unquoted;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -1402,7 +1408,7 @@
|
||||
}
|
||||
for (j = 0, len1 = props.length; j < len1; j++) {
|
||||
prop = props[j];
|
||||
fragments.push(...prop.compileToFragments(o));
|
||||
fragments.push(...(prop.compileToFragments(o)));
|
||||
}
|
||||
return fragments;
|
||||
}
|
||||
@@ -1462,12 +1468,12 @@
|
||||
exports.HereComment = HereComment = class HereComment extends Base {
|
||||
constructor({
|
||||
content: content1,
|
||||
newLine: newLine,
|
||||
newLine: newLine1,
|
||||
unshift: unshift
|
||||
}) {
|
||||
super();
|
||||
this.content = content1;
|
||||
this.newLine = newLine;
|
||||
this.newLine = newLine1;
|
||||
this.unshift = unshift;
|
||||
}
|
||||
|
||||
@@ -1509,12 +1515,12 @@
|
||||
exports.LineComment = LineComment = class LineComment extends Base {
|
||||
constructor({
|
||||
content: content1,
|
||||
newLine: newLine,
|
||||
newLine: newLine1,
|
||||
unshift: unshift
|
||||
}) {
|
||||
super();
|
||||
this.content = content1;
|
||||
this.newLine = newLine;
|
||||
this.newLine = newLine1;
|
||||
this.unshift = unshift;
|
||||
}
|
||||
|
||||
@@ -1603,7 +1609,7 @@
|
||||
}
|
||||
rite = new Call(rite, this.args);
|
||||
rite.isNew = this.isNew;
|
||||
left = new Literal(`typeof ${left.compile(o)} === \"function\"`);
|
||||
left = new Literal(`typeof ${left.compile(o)} === "function"`);
|
||||
return new If(left, new Value(rite), {
|
||||
soak: true
|
||||
});
|
||||
@@ -1655,7 +1661,7 @@
|
||||
if (argIndex) {
|
||||
compiledArgs.push(this.makeCode(", "));
|
||||
}
|
||||
compiledArgs.push(...arg.compileToFragments(o, LEVEL_LIST));
|
||||
compiledArgs.push(...(arg.compileToFragments(o, LEVEL_LIST)));
|
||||
}
|
||||
fragments = [];
|
||||
if (this.isNew) {
|
||||
@@ -2236,7 +2242,7 @@
|
||||
// Object spread properties. https://github.com/tc39/proposal-object-rest-spread/blob/master/Spread.md
|
||||
// `obj2 = {a: 1, obj..., c: 3, d: 4}` → `obj2 = Object.assign({}, {a: 1}, obj, {c: 3, d: 4})`
|
||||
compileSpread(o) {
|
||||
var addSlice, j, len1, prop, propSlices, props, slices, splatSlice;
|
||||
var _extends, addSlice, j, len1, prop, propSlices, props, slices, splatSlice;
|
||||
props = this.properties;
|
||||
// Store object spreads.
|
||||
splatSlice = [];
|
||||
@@ -2265,7 +2271,8 @@
|
||||
if (!(slices[0] instanceof Obj)) {
|
||||
slices.unshift(new Obj);
|
||||
}
|
||||
return (new Call(new Literal('Object.assign'), slices)).compileToFragments(o);
|
||||
_extends = new Value(new Literal(utility('_extends', o)));
|
||||
return (new Call(_extends, slices)).compileToFragments(o);
|
||||
}
|
||||
|
||||
compileCSXAttributes(o) {
|
||||
@@ -3138,7 +3145,7 @@
|
||||
// we've been assigned to, for correct internal references. If the variable
|
||||
// has not been seen yet within the current scope, declare it.
|
||||
compileNode(o) {
|
||||
var answer, compiledName, isValue, j, name, properties, prototype, ref1, ref2, ref3, ref4, ref5, val, varBase;
|
||||
var answer, compiledName, isValue, j, name, objDestructAnswer, properties, prototype, ref1, ref2, ref3, ref4, ref5, val, varBase;
|
||||
isValue = this.variable instanceof Value;
|
||||
if (isValue) {
|
||||
// When compiling `@variable`, remember if it is part of a function parameter.
|
||||
@@ -3159,7 +3166,10 @@
|
||||
return node instanceof Obj && node.hasSplat();
|
||||
})) {
|
||||
// Object destructuring. Can be removed once ES proposal hits Stage 4.
|
||||
return this.compileObjectDestruct(o);
|
||||
objDestructAnswer = this.compileObjectDestruct(o);
|
||||
}
|
||||
if (objDestructAnswer) {
|
||||
return objDestructAnswer;
|
||||
}
|
||||
}
|
||||
if (this.variable.isSplice()) {
|
||||
@@ -3230,7 +3240,7 @@
|
||||
// Check object destructuring variable for rest elements;
|
||||
// can be removed once ES proposal hits Stage 4.
|
||||
compileObjectDestruct(o) {
|
||||
var fragments, getPropKey, getPropName, j, len1, restElement, restElements, result, setScopeVar, traverseRest, value, valueRef;
|
||||
var fragments, getPropKey, getPropName, j, len1, restElement, restElements, result, setScopeVar, traverseRest, value, valueRef, valueRefTemp;
|
||||
// Per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Assignment_without_declaration,
|
||||
// if we’re destructuring without declaring, the destructuring assignment
|
||||
// must be wrapped in parentheses: `({a, b} = obj)`. Helper function
|
||||
@@ -3284,11 +3294,19 @@
|
||||
var base1, index, j, len1, nestedProperties, nestedSource, nestedSourceDefault, p, prop, restElements, restIndex;
|
||||
restElements = [];
|
||||
restIndex = void 0;
|
||||
if (source.properties == null) {
|
||||
source = new Value(source);
|
||||
}
|
||||
for (index = j = 0, len1 = properties.length; j < len1; index = ++j) {
|
||||
prop = properties[index];
|
||||
nestedSourceDefault = nestedSource = nestedProperties = null;
|
||||
setScopeVar(prop.unwrap());
|
||||
if (prop instanceof Assign) {
|
||||
if (typeof (base1 = prop.value).isObject === "function" ? base1.isObject() : void 0) {
|
||||
if (prop.context !== 'object') {
|
||||
// prop is `k = {...} `
|
||||
continue;
|
||||
}
|
||||
// prop is `k: {...}`
|
||||
nestedProperties = prop.value.base.properties;
|
||||
} else if (prop.value instanceof Assign && prop.value.variable.isObject()) {
|
||||
@@ -3331,10 +3349,20 @@
|
||||
}
|
||||
return restElements;
|
||||
};
|
||||
// Cache the value for reuse with rest elements
|
||||
[this.value, valueRef] = this.value.cache(o);
|
||||
// Cache the value for reuse with rest elements.
|
||||
if (this.value.shouldCache()) {
|
||||
valueRefTemp = new IdentifierLiteral(o.scope.freeVariable('ref', {
|
||||
reserve: false
|
||||
}));
|
||||
} else {
|
||||
valueRefTemp = this.value.base;
|
||||
}
|
||||
// Find all rest elements.
|
||||
restElements = traverseRest(this.variable.base.properties, valueRef);
|
||||
restElements = traverseRest(this.variable.base.properties, valueRefTemp);
|
||||
if (!(restElements && restElements.length > 0)) {
|
||||
return false;
|
||||
}
|
||||
[this.value, valueRef] = this.value.cache(o);
|
||||
result = new Block([this]);
|
||||
for (j = 0, len1 = restElements.length; j < len1; j++) {
|
||||
restElement = restElements[j];
|
||||
@@ -3536,7 +3564,7 @@
|
||||
[left, right] = this.variable.cacheReference(o);
|
||||
// Disallow conditional assignment of undefined variables.
|
||||
if (!left.properties.length && left.base instanceof Literal && !(left.base instanceof ThisLiteral) && !o.scope.check(left.base.value)) {
|
||||
this.variable.error(`the variable \"${left.base.value}\" can't be assigned with ${this.context} because it has not been declared before`);
|
||||
this.variable.error(`the variable "${left.base.value}" can't be assigned with ${this.context} because it has not been declared before`);
|
||||
}
|
||||
if (indexOf.call(this.context, "?") >= 0) {
|
||||
o.isExistentialEquals = true;
|
||||
@@ -3671,7 +3699,7 @@
|
||||
// parameters after the splat, they are declared via expressions in the
|
||||
// function body.
|
||||
compileNode(o) {
|
||||
var answer, body, boundMethodCheck, comment, condition, exprs, haveBodyParam, haveSplatParam, i, ifTrue, j, k, l, len1, len2, len3, m, methodScope, modifiers, name, param, paramNames, paramToAddToScope, params, paramsAfterSplat, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, salvagedComments, signature, splatParamName, thisAssignments, wasEmpty;
|
||||
var answer, body, boundMethodCheck, comment, condition, exprs, generatedVariables, haveBodyParam, haveSplatParam, i, ifTrue, j, k, l, len1, len2, len3, m, methodScope, modifiers, name, param, paramNames, paramToAddToScope, params, paramsAfterSplat, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, scopeVariablesCount, signature, splatParamName, thisAssignments, wasEmpty;
|
||||
if (this.ctor) {
|
||||
if (this.isAsync) {
|
||||
this.name.error('Class constructor may not be async');
|
||||
@@ -3823,14 +3851,7 @@
|
||||
// compilation, so that they get output the “real” time this param
|
||||
// is compiled.
|
||||
paramToAddToScope = param.value != null ? param : ref;
|
||||
if ((ref5 = paramToAddToScope.name) != null ? ref5.comments : void 0) {
|
||||
salvagedComments = paramToAddToScope.name.comments;
|
||||
delete paramToAddToScope.name.comments;
|
||||
}
|
||||
o.scope.parameter(fragmentsToText(paramToAddToScope.compileToFragments(o)));
|
||||
if (salvagedComments) {
|
||||
paramToAddToScope.name.comments = salvagedComments;
|
||||
}
|
||||
o.scope.parameter(fragmentsToText(paramToAddToScope.compileToFragmentsWithoutComments(o)));
|
||||
}
|
||||
params.push(ref);
|
||||
} else {
|
||||
@@ -3843,7 +3864,7 @@
|
||||
ifTrue = new Assign(new Value(param.name), param.value);
|
||||
exprs.push(new If(condition, ifTrue));
|
||||
}
|
||||
if (((ref6 = param.name) != null ? ref6.value : void 0) != null) {
|
||||
if (((ref5 = param.name) != null ? ref5.value : void 0) != null) {
|
||||
// Add this parameter to the scope, since it wouldn’t have been added
|
||||
// yet since it was skipped earlier.
|
||||
o.scope.add(param.name.value, 'var', true);
|
||||
@@ -3857,7 +3878,7 @@
|
||||
// Create a destructured assignment, e.g. `[a, b, c] = [args..., b, c]`
|
||||
exprs.unshift(new Assign(new Value(new Arr([
|
||||
new Splat(new IdentifierLiteral(splatParamName)),
|
||||
...(function() {
|
||||
...((function() {
|
||||
var k, len2, results;
|
||||
results = [];
|
||||
for (k = 0, len2 = paramsAfterSplat.length; k < len2; k++) {
|
||||
@@ -3865,7 +3886,7 @@
|
||||
results.push(param.asReference(o));
|
||||
}
|
||||
return results;
|
||||
})()
|
||||
})())
|
||||
])), new Value(new IdentifierLiteral(splatParamName))));
|
||||
}
|
||||
// Add new expressions to the function body
|
||||
@@ -3903,14 +3924,22 @@
|
||||
if (haveSplatParam && i === params.length - 1) {
|
||||
signature.push(this.makeCode('...'));
|
||||
}
|
||||
// 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 !== o.scope.variables.length) {
|
||||
generatedVariables = o.scope.variables.splice(scopeVariablesCount);
|
||||
o.scope.parent.variables.push(...generatedVariables);
|
||||
}
|
||||
}
|
||||
signature.push(this.makeCode(')'));
|
||||
// Block comments between `)` and `->`/`=>` get output between `)` and `{`.
|
||||
if (((ref7 = this.funcGlyph) != null ? ref7.comments : void 0) != null) {
|
||||
ref8 = this.funcGlyph.comments;
|
||||
for (l = 0, len3 = ref8.length; l < len3; l++) {
|
||||
comment = ref8[l];
|
||||
if (((ref6 = this.funcGlyph) != null ? ref6.comments : void 0) != null) {
|
||||
ref7 = this.funcGlyph.comments;
|
||||
for (l = 0, len3 = ref7.length; l < len3; l++) {
|
||||
comment = ref7[l];
|
||||
comment.unshift = false;
|
||||
}
|
||||
this.compileCommentFragments(o, this.funcGlyph, signature);
|
||||
@@ -4068,6 +4097,10 @@
|
||||
return this.name.compileToFragments(o, LEVEL_LIST);
|
||||
}
|
||||
|
||||
compileToFragmentsWithoutComments(o) {
|
||||
return this.name.compileToFragmentsWithoutComments(o, LEVEL_LIST);
|
||||
}
|
||||
|
||||
asReference(o) {
|
||||
var name, node;
|
||||
if (this.reference) {
|
||||
@@ -4184,21 +4217,21 @@
|
||||
// or as part of a destructuring assignment.
|
||||
exports.Splat = Splat = (function() {
|
||||
class Splat extends Base {
|
||||
isAssignable() {
|
||||
return this.name.isAssignable() && (!this.name.isAtomic || this.name.isAtomic());
|
||||
}
|
||||
|
||||
constructor(name) {
|
||||
super();
|
||||
this.name = name.compile ? name : new Literal(name);
|
||||
}
|
||||
|
||||
isAssignable() {
|
||||
return this.name.isAssignable() && (!this.name.isAtomic || this.name.isAtomic());
|
||||
}
|
||||
|
||||
assigns(name) {
|
||||
return this.name.assigns(name);
|
||||
}
|
||||
|
||||
compileToFragments(o) {
|
||||
return [this.makeCode('...'), ...this.name.compileToFragments(o)];
|
||||
compileNode(o) {
|
||||
return [this.makeCode('...'), ...this.name.compileToFragments(o, LEVEL_OP)];
|
||||
}
|
||||
|
||||
unwrap() {
|
||||
@@ -4765,7 +4798,7 @@
|
||||
|
||||
compileNode(o) {
|
||||
var fragments;
|
||||
fragments = this.expression.compileToFragments(o);
|
||||
fragments = this.expression.compileToFragments(o, LEVEL_LIST);
|
||||
unshiftAfterComments(fragments, this.makeCode('throw '));
|
||||
fragments.unshift(this.makeCode(this.tab));
|
||||
fragments.push(this.makeCode(';'));
|
||||
@@ -4833,7 +4866,7 @@
|
||||
code = this.expression.compile(o, LEVEL_OP);
|
||||
if (this.expression.unwrap() instanceof IdentifierLiteral && !o.scope.check(code)) {
|
||||
[cmp, cnj] = this.negated ? ['===', '||'] : ['!==', '&&'];
|
||||
code = `typeof ${code} ${cmp} \"undefined\"` + (this.comparisonTarget !== 'undefined' ? ` ${cnj} ${code} ${cmp} ${this.comparisonTarget}` : '');
|
||||
code = `typeof ${code} ${cmp} "undefined"` + (this.comparisonTarget !== 'undefined' ? ` ${cnj} ${code} ${cmp} ${this.comparisonTarget}` : '');
|
||||
} else {
|
||||
// We explicity want to use loose equality (`==`) when comparing against `null`,
|
||||
// so that an existence check roughly corresponds to a check for truthiness.
|
||||
@@ -4980,7 +5013,7 @@
|
||||
for (j = 0, len1 = elements.length; j < len1; j++) {
|
||||
element = elements[j];
|
||||
if (element instanceof StringLiteral) {
|
||||
element.value = element.unquote(this.csx);
|
||||
element.value = element.unquote(true, this.csx);
|
||||
if (!this.csx) {
|
||||
// Backticks and `${` inside template literals must be escaped.
|
||||
element.value = element.value.replace(/(\\*)(`|\$\{)/g, function(match, backslashes, toBeEscaped) {
|
||||
@@ -5349,7 +5382,7 @@
|
||||
fragments.push(cond.makeCode(idt2 + 'break;\n'));
|
||||
}
|
||||
if (this.otherwise && this.otherwise.expressions.length) {
|
||||
fragments.push(this.makeCode(idt1 + "default:\n"), ...this.otherwise.compileToFragments(o, LEVEL_TOP), this.makeCode("\n"));
|
||||
fragments.push(this.makeCode(idt1 + "default:\n"), ...(this.otherwise.compileToFragments(o, LEVEL_TOP)), this.makeCode("\n"));
|
||||
}
|
||||
fragments.push(this.makeCode(this.tab + '}'));
|
||||
return fragments;
|
||||
@@ -5514,6 +5547,9 @@
|
||||
boundMethodCheck: function() {
|
||||
return "function(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new Error('Bound instance method accessed before binding'); } }";
|
||||
},
|
||||
_extends: function() {
|
||||
return "Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }";
|
||||
},
|
||||
// Shortcuts to speed up the lookup time for native functions.
|
||||
hasProp: function() {
|
||||
return '{}.hasOwnProperty';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0-beta4
|
||||
// Generated by CoffeeScript 2.0.0-beta5
|
||||
(function() {
|
||||
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments, repeat,
|
||||
slice = [].slice;
|
||||
|
||||
309
lib/coffeescript/parser.js
Executable file → Normal file
309
lib/coffeescript/parser.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0-beta4
|
||||
// Generated by CoffeeScript 2.0.0-beta5
|
||||
(function() {
|
||||
var CoffeeScript, Module, binary, child_process, ext, findExtension, fork, helpers, i, len, loadFile, path, ref;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0-beta4
|
||||
// Generated by CoffeeScript 2.0.0-beta5
|
||||
(function() {
|
||||
var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, replDefaults, runInContext, sawSIGINT, updateSyntaxError, vm;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
}
|
||||
})(),
|
||||
historyMaxInputSize: 10240,
|
||||
eval: async function(input, context, filename, cb) {
|
||||
eval: function(input, context, filename, cb) {
|
||||
var Assign, Block, Call, Code, Literal, Value, ast, err, isAsync, js, referencedVars, result, token, tokens;
|
||||
// XXX: multiline hack.
|
||||
input = input.replace(/\uFF00/g, '\n');
|
||||
@@ -71,10 +71,11 @@
|
||||
result = runInContext(js, context, filename);
|
||||
// Await an async result, if necessary
|
||||
if (isAsync) {
|
||||
result = (await result);
|
||||
if (!sawSIGINT) {
|
||||
cb(null, result);
|
||||
}
|
||||
result.then(function(resolvedResult) {
|
||||
if (!sawSIGINT) {
|
||||
return cb(null, resolvedResult);
|
||||
}
|
||||
});
|
||||
return sawSIGINT = false;
|
||||
} else {
|
||||
return cb(null, result);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0-beta4
|
||||
// Generated by CoffeeScript 2.0.0-beta5
|
||||
(function() {
|
||||
// The CoffeeScript language has a good deal of optional syntax, implicit syntax,
|
||||
// and shorthand syntax. This can greatly complicate a grammar and bloat
|
||||
@@ -86,6 +86,7 @@
|
||||
this.normalizeLines();
|
||||
this.tagPostfixConditionals();
|
||||
this.addImplicitBracesAndParens();
|
||||
this.addParensToChainedDoIife();
|
||||
this.rescueStowawayComments();
|
||||
this.addLocationDataToGeneratedTokens();
|
||||
this.enforceValidCSXAttributes();
|
||||
@@ -280,7 +281,7 @@
|
||||
stack = [];
|
||||
start = null;
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var endImplicitCall, endImplicitObject, forward, implicitObjectContinues, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, isImplicit, isImplicitCall, isImplicitObject, k, newLine, nextTag, nextToken, offset, prevTag, prevToken, ref, s, sameLine, stackIdx, stackItem, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag;
|
||||
var endImplicitCall, endImplicitObject, forward, implicitObjectContinues, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, isImplicit, isImplicitCall, isImplicitObject, k, newLine, nextTag, nextToken, offset, prevTag, prevToken, ref, ref1, s, sameLine, stackIdx, stackItem, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag;
|
||||
[tag] = token;
|
||||
[prevTag] = prevToken = i > 0 ? tokens[i - 1] : [];
|
||||
[nextTag] = nextToken = i < tokens.length - 1 ? tokens[i + 1] : [];
|
||||
@@ -422,7 +423,7 @@
|
||||
// Recognize standard implicit calls like
|
||||
// f a, f() b, f? c, h[0] d etc.
|
||||
// Added support for spread dots on the left side: f ...a
|
||||
if ((indexOf.call(IMPLICIT_FUNC, tag) >= 0 && token.spaced || tag === '?' && i > 0 && !tokens[i - 1].spaced) && (indexOf.call(IMPLICIT_CALL, nextTag) >= 0 || nextTag === '...' || indexOf.call(IMPLICIT_UNSPACED_CALL, nextTag) >= 0 && !nextToken.spaced && !nextToken.newLine)) {
|
||||
if ((indexOf.call(IMPLICIT_FUNC, tag) >= 0 && token.spaced || tag === '?' && i > 0 && !tokens[i - 1].spaced) && (indexOf.call(IMPLICIT_CALL, nextTag) >= 0 || (nextTag === '...' && (ref = this.tag(i + 2), indexOf.call(IMPLICIT_CALL, ref) >= 0) && !this.findTagsBackwards(i, ['INDEX_START', '['])) || indexOf.call(IMPLICIT_UNSPACED_CALL, nextTag) >= 0 && !nextToken.spaced && !nextToken.newLine)) {
|
||||
if (tag === '?') {
|
||||
tag = token[0] = 'FUNC_EXIST';
|
||||
}
|
||||
@@ -456,9 +457,9 @@
|
||||
if (tag === ':') {
|
||||
// Go back to the (implicit) start of the object.
|
||||
s = (function() {
|
||||
var ref;
|
||||
var ref1;
|
||||
switch (false) {
|
||||
case ref = this.tag(i - 1), indexOf.call(EXPRESSION_END, ref) < 0:
|
||||
case ref1 = this.tag(i - 1), indexOf.call(EXPRESSION_END, ref1) < 0:
|
||||
return start[1];
|
||||
case this.tag(i - 2) !== '@':
|
||||
return i - 2;
|
||||
@@ -466,7 +467,7 @@
|
||||
return i - 1;
|
||||
}
|
||||
}).call(this);
|
||||
startsLine = s === 0 || (ref = this.tag(s - 1), indexOf.call(LINEBREAKS, ref) >= 0) || tokens[s - 1].newLine;
|
||||
startsLine = s <= 0 || (ref1 = this.tag(s - 1), indexOf.call(LINEBREAKS, ref1) >= 0) || tokens[s - 1].newLine;
|
||||
// Are we just continuing an already declared object?
|
||||
if (stackTop()) {
|
||||
[stackTag, stackIdx] = stackTop();
|
||||
@@ -734,6 +735,46 @@
|
||||
});
|
||||
}
|
||||
|
||||
// Add parens around a `do` IIFE followed by a chained `.` so that the
|
||||
// chaining applies to the executed function rather than the function
|
||||
// object (see #3736)
|
||||
addParensToChainedDoIife() {
|
||||
var action, condition, doIndex;
|
||||
condition = function(token, i) {
|
||||
return this.tag(i - 1) === 'OUTDENT';
|
||||
};
|
||||
action = function(token, i) {
|
||||
var ref;
|
||||
if (ref = token[0], indexOf.call(CALL_CLOSERS, ref) < 0) {
|
||||
return;
|
||||
}
|
||||
this.tokens.splice(doIndex, 0, generate('(', '(', this.tokens[doIndex]));
|
||||
return this.tokens.splice(i + 1, 0, generate(')', ')', this.tokens[i]));
|
||||
};
|
||||
doIndex = null;
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var glyphIndex, ref;
|
||||
if (token[1] !== 'do') {
|
||||
return 1;
|
||||
}
|
||||
doIndex = i;
|
||||
glyphIndex = i + 1;
|
||||
if (this.tag(i + 1) === 'PARAM_START') {
|
||||
glyphIndex = null;
|
||||
this.detectEnd(i + 1, function(token, i) {
|
||||
return this.tag(i - 1) === 'PARAM_END';
|
||||
}, function(token, i) {
|
||||
return glyphIndex = i;
|
||||
});
|
||||
}
|
||||
if (!((glyphIndex != null) && ((ref = this.tag(glyphIndex)) === '->' || ref === '=>') && this.tag(glyphIndex + 1) === 'INDENT')) {
|
||||
return 1;
|
||||
}
|
||||
this.detectEnd(glyphIndex + 1, condition, action);
|
||||
return 2;
|
||||
});
|
||||
}
|
||||
|
||||
// Because our grammar is LALR(1), it can’t handle some single-line
|
||||
// expressions that lack ending delimiters. The **Rewriter** adds the implicit
|
||||
// blocks, so it doesn’t need to. To keep the grammar clean and tidy, trailing
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0-beta4
|
||||
// Generated by CoffeeScript 2.0.0-beta5
|
||||
(function() {
|
||||
// The **Scope** class regulates lexical scoping within CoffeeScript. As you
|
||||
// generate code, you create a tree of scopes in the same shape as the nested
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0-beta4
|
||||
// Generated by CoffeeScript 2.0.0-beta5
|
||||
(function() {
|
||||
// Source maps allow JavaScript runtimes to match running JavaScript back to
|
||||
// the original source code that corresponds to it. This can be minified
|
||||
@@ -93,7 +93,7 @@
|
||||
// map. Also, `options.sourceFiles` and `options.generatedFile` may be passed to
|
||||
// set "sources" and "file", respectively.
|
||||
generate(options = {}, code = null) {
|
||||
var buffer, i, j, lastColumn, lastSourceColumn, lastSourceLine, len, len1, lineMap, lineNumber, mapping, needComma, ref, ref1, v3, writingline;
|
||||
var buffer, i, j, lastColumn, lastSourceColumn, lastSourceLine, len, len1, lineMap, lineNumber, mapping, needComma, ref, ref1, sources, v3, writingline;
|
||||
writingline = 0;
|
||||
lastColumn = 0;
|
||||
lastSourceLine = 0;
|
||||
@@ -141,11 +141,12 @@
|
||||
}
|
||||
}
|
||||
// Produce the canonical JSON object format for a "v3" source map.
|
||||
sources = options.sourceFiles ? options.sourceFiles : options.filename ? [options.filename] : ['<anonymous>'];
|
||||
v3 = {
|
||||
version: 3,
|
||||
file: options.generatedFile || '',
|
||||
sourceRoot: options.sourceRoot || '',
|
||||
sources: options.sourceFiles || [''],
|
||||
sources: sources,
|
||||
names: [],
|
||||
mappings: buffer
|
||||
};
|
||||
|
||||
779
package-lock.json
generated
779
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@@ -8,10 +8,10 @@
|
||||
"compiler"
|
||||
],
|
||||
"author": "Jeremy Ashkenas",
|
||||
"version": "2.0.0-beta4",
|
||||
"version": "2.0.0-beta5",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=7.6.0"
|
||||
"node": ">=6"
|
||||
},
|
||||
"directories": {
|
||||
"lib": "./lib/coffeescript"
|
||||
@@ -39,16 +39,16 @@
|
||||
"url": "git://github.com/jashkenas/coffeescript.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "~6.25.0",
|
||||
"babel-core": "~6.26.0",
|
||||
"babel-preset-babili": "~0.1.4",
|
||||
"babel-preset-env": "~1.6.0",
|
||||
"babili": "^0.1.4",
|
||||
"docco": "~0.7.0",
|
||||
"highlight.js": "~9.12.0",
|
||||
"jison": ">=0.4.17",
|
||||
"markdown-it": "~8.3.1",
|
||||
"markdown-it": "~8.4.0",
|
||||
"underscore": "~1.8.3",
|
||||
"webpack": "~3.2.0"
|
||||
"webpack": "~3.5.5"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ packageJson = require '../../package.json'
|
||||
# The current CoffeeScript version number.
|
||||
exports.VERSION = packageJson.version
|
||||
|
||||
exports.FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md']
|
||||
exports.FILE_EXTENSIONS = FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md']
|
||||
|
||||
# Expose helpers for testing.
|
||||
exports.helpers = helpers
|
||||
@@ -49,9 +49,9 @@ withPrettyErrors = (fn) ->
|
||||
# a stack trace. Assuming that most of the time, code isn’t throwing
|
||||
# exceptions, it’s probably more efficient to compile twice only when we
|
||||
# need a stack trace, rather than always generating a source map even when
|
||||
# it’s not likely to be used. Save in form of `filename`: `(source)`
|
||||
# it’s not likely to be used. Save in form of `filename`: [`(source)`]
|
||||
sources = {}
|
||||
# Also save source maps if generated, in form of `filename`: `(source map)`.
|
||||
# Also save source maps if generated, in form of `(source)`: [`(source map)`].
|
||||
sourceMaps = {}
|
||||
|
||||
# Compile CoffeeScript code to JavaScript, using the Coffee/Jison compiler.
|
||||
@@ -75,7 +75,8 @@ exports.compile = compile = withPrettyErrors (code, options) ->
|
||||
|
||||
checkShebangLine filename, code
|
||||
|
||||
sources[filename] = code
|
||||
sources[filename] ?= []
|
||||
sources[filename].push code
|
||||
map = new SourceMap if generateSourceMap
|
||||
|
||||
tokens = lexer.tokenize code, options
|
||||
@@ -124,8 +125,9 @@ exports.compile = compile = withPrettyErrors (code, options) ->
|
||||
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
|
||||
@@ -264,16 +266,36 @@ formatSourcePosition = (frame, getSourceMapping) ->
|
||||
else
|
||||
fileLocation
|
||||
|
||||
getSourceMap = (filename) ->
|
||||
if sourceMaps[filename]?
|
||||
sourceMaps[filename]
|
||||
# CoffeeScript compiled in a browser may get compiled with `options.filename`
|
||||
# of `<anonymous>`, but the browser may request the stack trace with the
|
||||
# filename of the script file.
|
||||
getSourceMap = (filename, line, column) ->
|
||||
# Skip files that we didn’t compile, like Node system files that appear in
|
||||
# the stack trace, as they never have source maps.
|
||||
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]
|
||||
# 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>']?
|
||||
sourceMaps['<anonymous>']
|
||||
else if sources[filename]?
|
||||
answer = compile sources[filename],
|
||||
# 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
|
||||
@@ -287,7 +309,7 @@ getSourceMap = (filename) ->
|
||||
# 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
|
||||
|
||||
|
||||
@@ -32,25 +32,25 @@ BANNER = '''
|
||||
|
||||
# The list of all the valid option flags that `coffee` knows how to handle.
|
||||
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']
|
||||
]
|
||||
|
||||
# Top-level objects shared by all the functions.
|
||||
@@ -102,7 +102,19 @@ exports.run = ->
|
||||
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 '''
|
||||
@@ -125,9 +137,9 @@ exports.run = ->
|
||||
|
||||
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
|
||||
@@ -167,7 +179,7 @@ compilePath = (source, topLevel, base) ->
|
||||
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
|
||||
|
||||
@@ -182,43 +194,46 @@ findDirectoryIndex = (source) ->
|
||||
process.exit 1
|
||||
|
||||
# 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
|
||||
@@ -352,12 +367,12 @@ silentUnlink = (path) ->
|
||||
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`.
|
||||
|
||||
@@ -316,6 +316,7 @@ grammar =
|
||||
SimpleAssignable: [
|
||||
o 'Identifier', -> new Value $1
|
||||
o 'Value Accessor', -> $1.add $2
|
||||
o 'Code Accessor', -> new Value($1).add $2
|
||||
o 'ThisProperty'
|
||||
]
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ exports.Lexer = class Lexer
|
||||
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
|
||||
@@ -509,7 +509,7 @@ exports.Lexer = class Lexer
|
||||
@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
|
||||
@@ -527,7 +527,7 @@ exports.Lexer = class Lexer
|
||||
|
||||
# Generate a newline token. Consecutive newlines get merged together.
|
||||
newlineToken: (offset) ->
|
||||
@tokens.pop() while @value() is ';'
|
||||
@suppressSemicolons()
|
||||
@token 'TERMINATOR', '\n', offset, 0 unless @tag() is 'TERMINATOR'
|
||||
this
|
||||
|
||||
@@ -662,9 +662,10 @@ exports.Lexer = class Lexer
|
||||
@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'
|
||||
@@ -673,11 +674,12 @@ exports.Lexer = class Lexer
|
||||
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'
|
||||
@@ -820,8 +822,23 @@ exports.Lexer = class Lexer
|
||||
[tag, value] = token
|
||||
switch tag
|
||||
when 'TOKENS'
|
||||
# Optimize out empty interpolations (an empty pair of parentheses).
|
||||
continue if value.length is 2
|
||||
if value.length is 2
|
||||
# Optimize out empty interpolations (an empty pair of parentheses).
|
||||
continue unless value[0].comments or value[1].comments
|
||||
# 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.
|
||||
locationToken = value[0]
|
||||
@@ -1037,6 +1054,11 @@ exports.Lexer = class Lexer
|
||||
when other then (if options.double then "\\#{other}" else other)
|
||||
"#{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]`).
|
||||
error: (message, options = {}) ->
|
||||
|
||||
@@ -107,6 +107,9 @@ exports.Base = class Base
|
||||
@compileCommentFragments o, node, fragments
|
||||
fragments
|
||||
|
||||
compileToFragmentsWithoutComments: (o, lvl) ->
|
||||
@compileWithoutComments o, lvl, 'compileToFragments'
|
||||
|
||||
# Statements converted into expressions via closure-wrapping share a scope
|
||||
# object with their parent closure, to preserve the expected lexical scope.
|
||||
compileClosure: (o) ->
|
||||
@@ -732,15 +735,13 @@ exports.NaNLiteral = class NaNLiteral extends NumberLiteral
|
||||
|
||||
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
|
||||
|
||||
@@ -1529,7 +1530,8 @@ exports.Obj = class Obj extends Base
|
||||
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
|
||||
@@ -2119,8 +2121,9 @@ exports.Assign = class Assign extends Base
|
||||
@variable.base.lhs = yes
|
||||
return @compileDestructuring o unless @variable.isAssignable()
|
||||
# Object destructuring. Can be removed once ES proposal hits Stage 4.
|
||||
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 ['||=', '&&=', '?=']
|
||||
@@ -2213,12 +2216,16 @@ exports.Assign = class Assign extends Base
|
||||
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
|
||||
# prop is `k: expr`, we need to check `expr` for nested splats
|
||||
if prop.value.isObject?()
|
||||
# prop is `k = {...} `
|
||||
continue unless prop.context is 'object'
|
||||
# prop is `k: {...}`
|
||||
nestedProperties = prop.value.base.properties
|
||||
else if prop.value instanceof Assign and prop.value.variable.isObject()
|
||||
@@ -2244,13 +2251,19 @@ exports.Assign = class Assign extends Base
|
||||
|
||||
restElements
|
||||
|
||||
# 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
|
||||
@@ -2626,11 +2639,7 @@ exports.Code = class Code extends Base
|
||||
# compilation, so that they get output the “real” time this param
|
||||
# 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
|
||||
@@ -2675,7 +2684,14 @@ exports.Code = class Code extends Base
|
||||
for param, i in params
|
||||
signature.push @makeCode ', ' if i isnt 0
|
||||
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 `{`.
|
||||
if @funcGlyph?.comments?
|
||||
@@ -2774,6 +2790,9 @@ exports.Param = class Param extends Base
|
||||
compileToFragments: (o) ->
|
||||
@name.compileToFragments o, LEVEL_LIST
|
||||
|
||||
compileToFragmentsWithoutComments: (o) ->
|
||||
@name.compileToFragmentsWithoutComments o, LEVEL_LIST
|
||||
|
||||
asReference: (o) ->
|
||||
return @reference if @reference
|
||||
node = @name
|
||||
@@ -2850,22 +2869,20 @@ exports.Param = class Param extends Base
|
||||
# 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())
|
||||
|
||||
constructor: (name) ->
|
||||
super()
|
||||
@name = if name.compile then name else new Literal name
|
||||
|
||||
assigns: (name) ->
|
||||
@name.assigns name
|
||||
|
||||
compileToFragments: (o) ->
|
||||
[ @makeCode('...')
|
||||
@name.compileToFragments(o)... ]
|
||||
compileNode: (o) ->
|
||||
[@makeCode('...'), @name.compileToFragments(o, LEVEL_OP)...]
|
||||
|
||||
unwrap: -> @name
|
||||
|
||||
@@ -3246,7 +3263,7 @@ exports.Throw = class Throw extends Base
|
||||
makeReturn: THIS
|
||||
|
||||
compileNode: (o) ->
|
||||
fragments = @expression.compileToFragments o
|
||||
fragments = @expression.compileToFragments o, LEVEL_LIST
|
||||
unshiftAfterComments fragments, @makeCode 'throw '
|
||||
fragments.unshift @makeCode @tab
|
||||
fragments.push @makeCode ';'
|
||||
@@ -3384,7 +3401,7 @@ exports.StringWithInterpolations = class StringWithInterpolations extends Base
|
||||
fragments.push @makeCode '`' unless @csx
|
||||
for element in elements
|
||||
if element instanceof StringLiteral
|
||||
element.value = element.unquote @csx
|
||||
element.value = element.unquote yes, @csx
|
||||
unless @csx
|
||||
# Backticks and `${` inside template literals must be escaped.
|
||||
element.value = element.value.replace /(\\*)(`|\$\{)/g, (match, backslashes, toBeEscaped) ->
|
||||
@@ -3712,6 +3729,19 @@ UTILITIES =
|
||||
}
|
||||
}
|
||||
"
|
||||
_extends: -> "
|
||||
Object.assign || function (target) {
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
var source = arguments[i];
|
||||
for (var key in source) {
|
||||
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
"
|
||||
|
||||
# Shortcuts to speed up the lookup time for native functions.
|
||||
hasProp: -> '{}.hasOwnProperty'
|
||||
|
||||
@@ -44,9 +44,9 @@ replDefaults =
|
||||
result = runInContext js, context, filename
|
||||
# Await an async result, if necessary
|
||||
if isAsync
|
||||
result = await result
|
||||
cb null, result unless sawSIGINT
|
||||
sawSIGINT = false
|
||||
result.then (resolvedResult) ->
|
||||
cb null, resolvedResult unless sawSIGINT
|
||||
sawSIGINT = no
|
||||
else
|
||||
cb null, result
|
||||
catch err
|
||||
|
||||
@@ -53,6 +53,7 @@ exports.Rewriter = class Rewriter
|
||||
@normalizeLines()
|
||||
@tagPostfixConditionals()
|
||||
@addImplicitBracesAndParens()
|
||||
@addParensToChainedDoIife()
|
||||
@rescueStowawayComments()
|
||||
@addLocationDataToGeneratedTokens()
|
||||
@enforceValidCSXAttributes()
|
||||
@@ -267,7 +268,8 @@ exports.Rewriter = class Rewriter
|
||||
# Added support for spread dots on the left side: f ...a
|
||||
if (tag in IMPLICIT_FUNC and token.spaced or
|
||||
tag is '?' and i > 0 and not tokens[i - 1].spaced) and
|
||||
(nextTag in IMPLICIT_CALL or nextTag is '...' or
|
||||
(nextTag in IMPLICIT_CALL or
|
||||
(nextTag is '...' and @tag(i + 2) in IMPLICIT_CALL and not @findTagsBackwards(i, ['INDEX_START', '['])) or
|
||||
nextTag in IMPLICIT_UNSPACED_CALL and
|
||||
not nextToken.spaced and not nextToken.newLine)
|
||||
tag = token[0] = 'FUNC_EXIST' if tag is '?'
|
||||
@@ -308,7 +310,7 @@ exports.Rewriter = class Rewriter
|
||||
when @tag(i - 2) is '@' then i - 2
|
||||
else i - 1
|
||||
|
||||
startsLine = s is 0 or @tag(s - 1) in LINEBREAKS or tokens[s - 1].newLine
|
||||
startsLine = s <= 0 or @tag(s - 1) in LINEBREAKS or tokens[s - 1].newLine
|
||||
# Are we just continuing an already declared object?
|
||||
if stackTop()
|
||||
[stackTag, stackIdx] = stackTop()
|
||||
@@ -511,6 +513,30 @@ exports.Rewriter = class Rewriter
|
||||
last_column: prevLocationData.last_column
|
||||
return 1
|
||||
|
||||
# Add parens around a `do` IIFE followed by a chained `.` so that the
|
||||
# chaining applies to the executed function rather than the function
|
||||
# object (see #3736)
|
||||
addParensToChainedDoIife: ->
|
||||
condition = (token, i) ->
|
||||
@tag(i - 1) is 'OUTDENT'
|
||||
action = (token, i) ->
|
||||
return unless token[0] in CALL_CLOSERS
|
||||
@tokens.splice doIndex, 0, generate '(', '(', @tokens[doIndex]
|
||||
@tokens.splice i + 1, 0, generate ')', ')', @tokens[i]
|
||||
doIndex = null
|
||||
@scanTokens (token, i, tokens) ->
|
||||
return 1 unless token[1] is 'do'
|
||||
doIndex = i
|
||||
glyphIndex = i + 1
|
||||
if @tag(i + 1) is 'PARAM_START'
|
||||
glyphIndex = null
|
||||
@detectEnd i + 1,
|
||||
(token, i) -> @tag(i - 1) is 'PARAM_END'
|
||||
(token, i) -> glyphIndex = i
|
||||
return 1 unless glyphIndex? and @tag(glyphIndex) in ['->', '=>'] and @tag(glyphIndex + 1) is 'INDENT'
|
||||
@detectEnd glyphIndex + 1, condition, action
|
||||
return 2
|
||||
|
||||
# Because our grammar is LALR(1), it can’t handle some single-line
|
||||
# expressions that lack ending delimiters. The **Rewriter** adds the implicit
|
||||
# blocks, so it doesn’t need to. To keep the grammar clean and tidy, trailing
|
||||
|
||||
@@ -118,11 +118,18 @@ The starting column in the original source, relative to the previous column.
|
||||
|
||||
Produce the canonical JSON object format for a "v3" source map.
|
||||
|
||||
sources = if options.sourceFiles
|
||||
options.sourceFiles
|
||||
else if options.filename
|
||||
[options.filename]
|
||||
else
|
||||
['<anonymous>']
|
||||
|
||||
v3 =
|
||||
version: 3
|
||||
file: options.generatedFile or ''
|
||||
sourceRoot: options.sourceRoot or ''
|
||||
sources: options.sourceFiles or ['']
|
||||
sources: sources
|
||||
names: []
|
||||
mappings: buffer
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ If called without options, `coffee` will run your script.
|
||||
-n, --nodes print out the parse tree that the parser produces
|
||||
--nodejs pass options directly to the "node" binary
|
||||
--no-header suppress the "Generated by" header
|
||||
-o, --output set the output directory for compiled JavaScript
|
||||
-o, --output set the output path or path/filename for compiled JavaScript
|
||||
-p, --print print out the compiled JavaScript
|
||||
-r, --require require the given module before eval or REPL
|
||||
-s, --stdio listen for and compile scripts over stdio
|
||||
|
||||
@@ -38,7 +38,6 @@ test "array splat expansions with assignments", ->
|
||||
|
||||
|
||||
test "mixed shorthand objects in array lists", ->
|
||||
|
||||
arr = [
|
||||
a:1
|
||||
'b'
|
||||
@@ -58,7 +57,6 @@ test "mixed shorthand objects in array lists", ->
|
||||
eq arr[2].b, 1
|
||||
eq arr[3], 'b'
|
||||
|
||||
|
||||
test "array splats with nested arrays", ->
|
||||
nonce = {}
|
||||
a = [nonce]
|
||||
@@ -70,6 +68,54 @@ test "array splats with nested arrays", ->
|
||||
list = [1, 2, a...]
|
||||
arrayEq list, [1, 2, [nonce]]
|
||||
|
||||
test "#4260: splat after existential operator soak", ->
|
||||
a = {b: [3]}
|
||||
foo = (a) -> [a]
|
||||
arrayEq [a?.b...], [3]
|
||||
arrayEq [c?.b ? []...], []
|
||||
arrayEq [...a?.b], [3]
|
||||
arrayEq [...c?.b ? []], []
|
||||
arrayEq foo(a?.b...), [3]
|
||||
arrayEq foo(...a?.b), [3]
|
||||
arrayEq foo(c?.b ? []...), [undefined]
|
||||
arrayEq foo(...c?.b ? []), [undefined]
|
||||
e = yes
|
||||
f = null
|
||||
arrayEq [(a if e)?.b...], [3]
|
||||
arrayEq [(a if f)?.b ? []...], []
|
||||
arrayEq [...(a if e)?.b], [3]
|
||||
arrayEq [...(a if f)?.b ? []], []
|
||||
arrayEq foo((a if e)?.b...), [3]
|
||||
arrayEq foo(...(a if e)?.b), [3]
|
||||
arrayEq foo((a if f)?.b ? []...), [undefined]
|
||||
arrayEq foo(...(a if f)?.b ? []), [undefined]
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
arrayEq [... a?.b], [3]
|
||||
arrayEq [... c?.b ? []], []
|
||||
arrayEq [a?.b ...], [3]
|
||||
arrayEq [(a if e)?.b ...], [3]
|
||||
arrayEq foo(a?.b ...), [3]
|
||||
arrayEq foo(... a?.b), [3]
|
||||
|
||||
test "#1349: trailing if after splat", ->
|
||||
a = [3]
|
||||
b = yes
|
||||
c = null
|
||||
foo = (a) -> [a]
|
||||
arrayEq [a if b...], [3]
|
||||
arrayEq [(a if c) ? []...], []
|
||||
arrayEq [...a if b], [3]
|
||||
arrayEq [...(a if c) ? []], []
|
||||
arrayEq foo((a if b)...), [3]
|
||||
arrayEq foo(...(a if b)), [3]
|
||||
arrayEq foo((a if c) ? []...), [undefined]
|
||||
arrayEq foo(...(a if c) ? []), [undefined]
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
arrayEq [... a if b], [3]
|
||||
arrayEq [a if b ...], [3]
|
||||
|
||||
test "#1274: `[] = a()` compiles to `false` instead of `a()`", ->
|
||||
a = false
|
||||
fn = -> a = true
|
||||
|
||||
@@ -185,6 +185,12 @@ test "destructuring assignment with splats", ->
|
||||
arrayEq [b,c,d], y
|
||||
eq e, z
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
[x,y ...,z] = [a,b,c,d,e]
|
||||
eq a, x
|
||||
arrayEq [b,c,d], y
|
||||
eq e, z
|
||||
|
||||
test "deep destructuring assignment with splats", ->
|
||||
a={}; b={}; c={}; d={}; e={}; f={}; g={}; h={}; i={}
|
||||
[u, [v, w..., x], y..., z] = [a, [b, c, d, e], f, g, h, i]
|
||||
@@ -229,6 +235,11 @@ test "destructuring assignment with objects and splats", ->
|
||||
eq a, y
|
||||
arrayEq [b,c,d], z
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
{a: b: [y, z ...]} = obj
|
||||
eq a, y
|
||||
arrayEq [b,c,d], z
|
||||
|
||||
test "destructuring assignment against an expression", ->
|
||||
a={}; b={}
|
||||
[y, z] = if true then [a, b] else [b, a]
|
||||
@@ -263,6 +274,15 @@ test "destructuring assignment with splats and default values", ->
|
||||
eq b, 1
|
||||
deepEqual d, {}
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
{
|
||||
a: {b} = c
|
||||
d ...
|
||||
} = obj
|
||||
|
||||
eq b, 1
|
||||
deepEqual d, {}
|
||||
|
||||
test "destructuring assignment with splat with default value", ->
|
||||
obj = {}
|
||||
c = {val: 1}
|
||||
@@ -276,6 +296,41 @@ test "destructuring assignment with multiple splats in different objects", ->
|
||||
deepEqual a, val: 1
|
||||
deepEqual b, val: 2
|
||||
|
||||
o = {
|
||||
props: {
|
||||
p: {
|
||||
n: 1
|
||||
m: 5
|
||||
}
|
||||
s: 6
|
||||
}
|
||||
}
|
||||
{p: {m, q..., t = {obj...}}, r...} = o.props
|
||||
eq m, o.props.p.m
|
||||
deepEqual r, s: 6
|
||||
deepEqual q, n: 1
|
||||
deepEqual t, obj
|
||||
|
||||
@props = o.props
|
||||
{p: {m}, r...} = @props
|
||||
eq m, @props.p.m
|
||||
deepEqual r, s: 6
|
||||
|
||||
{p: {m}, r...} = {o.props..., p:{m:9}}
|
||||
eq m, 9
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
{
|
||||
a: {
|
||||
a ...
|
||||
}
|
||||
b: {
|
||||
b ...
|
||||
}
|
||||
} = obj
|
||||
deepEqual a, val: 1
|
||||
deepEqual b, val: 2
|
||||
|
||||
test "destructuring assignment with dynamic keys and splats", ->
|
||||
i = 0
|
||||
foo = -> ++i
|
||||
@@ -299,6 +354,15 @@ test "destructuring assignment with objects and splats: Babel tests", ->
|
||||
n = { x, y, z... }
|
||||
deepEqual n, { x: 1, y: 2, a: 3, b: 4 }
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
{ x, y, z ... } = { x: 1, y: 2, a: 3, b: 4 }
|
||||
eq x, 1
|
||||
eq y, 2
|
||||
deepEqual z, { a: 3, b: 4 }
|
||||
|
||||
n = { x, y, z ... }
|
||||
deepEqual n, { x: 1, y: 2, a: 3, b: 4 }
|
||||
|
||||
test "deep destructuring assignment with objects: ES2015", ->
|
||||
a1={}; b1={}; c1={}; d1={}
|
||||
obj = {
|
||||
@@ -320,6 +384,13 @@ test "deep destructuring assignment with objects: ES2015", ->
|
||||
eq bb, b1
|
||||
eq r2.b2, obj.b2
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
{a: w, b: {c: {d: {b1: bb, r1 ...}}}, r2 ...} = obj
|
||||
eq r1.e, c1
|
||||
eq r2.b, undefined
|
||||
eq bb, b1
|
||||
eq r2.b2, obj.b2
|
||||
|
||||
test "deep destructuring assignment with defaults: ES2015", ->
|
||||
obj =
|
||||
b: { c: 1, baz: 'qux' }
|
||||
@@ -343,16 +414,55 @@ test "deep destructuring assignment with defaults: ES2015", ->
|
||||
eq hello, 'world'
|
||||
deepEqual h, some: 'prop'
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
{
|
||||
a ...
|
||||
b: {
|
||||
c,
|
||||
d ...
|
||||
}
|
||||
e: {
|
||||
f: hello
|
||||
g: {
|
||||
h ...
|
||||
} = i
|
||||
} = j
|
||||
} = obj
|
||||
|
||||
deepEqual a, foo: 'bar'
|
||||
eq c, 1
|
||||
deepEqual d, baz: 'qux'
|
||||
eq hello, 'world'
|
||||
deepEqual h, some: 'prop'
|
||||
|
||||
test "object spread properties: ES2015", ->
|
||||
obj = {a: 1, b: 2, c: 3, d: 4, e: 5}
|
||||
obj2 = {obj..., c:9}
|
||||
eq obj2.c, 9
|
||||
eq obj.a, obj2.a
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
obj2 = {
|
||||
obj ...
|
||||
c:9
|
||||
}
|
||||
eq obj2.c, 9
|
||||
eq obj.a, obj2.a
|
||||
|
||||
obj2 = {obj..., a: 8, c: 9, obj...}
|
||||
eq obj2.c, 3
|
||||
eq obj.a, obj2.a
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
obj2 = {
|
||||
obj ...
|
||||
a: 8
|
||||
c: 9
|
||||
obj ...
|
||||
}
|
||||
eq obj2.c, 3
|
||||
eq obj.a, obj2.a
|
||||
|
||||
obj3 = {obj..., b: 7, g: {obj2..., c: 1}}
|
||||
eq obj3.g.c, 1
|
||||
eq obj3.b, 7
|
||||
@@ -370,10 +480,42 @@ test "object spread properties: ES2015", ->
|
||||
eq obj4.f.g, 5
|
||||
deepEqual obj4.f, obj.c.f
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
(({
|
||||
a
|
||||
b
|
||||
r ...
|
||||
}) ->
|
||||
eq 1, a
|
||||
deepEqual r, {c: 3, d: 44, e: 55}
|
||||
) {
|
||||
obj2 ...
|
||||
d: 44
|
||||
e: 55
|
||||
}
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
obj4 = {
|
||||
a: 10
|
||||
obj.c ...
|
||||
}
|
||||
eq obj4.a, 10
|
||||
eq obj4.d, 3
|
||||
eq obj4.f.g, 5
|
||||
deepEqual obj4.f, obj.c.f
|
||||
|
||||
obj5 = {obj..., ((k) -> {b: k})(99)...}
|
||||
eq obj5.b, 99
|
||||
deepEqual obj5.c, obj.c
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
obj5 = {
|
||||
obj ...
|
||||
((k) -> {b: k})(99) ...
|
||||
}
|
||||
eq obj5.b, 99
|
||||
deepEqual obj5.c, obj.c
|
||||
|
||||
fn = -> {c: {d: 33, e: 44, f: {g: 55}}}
|
||||
obj6 = {obj..., fn()...}
|
||||
eq obj6.c.d, 33
|
||||
@@ -382,7 +524,16 @@ test "object spread properties: ES2015", ->
|
||||
obj7 = {obj..., fn()..., {c: {d: 55, e: 66, f: {77}}}...}
|
||||
eq obj7.c.d, 55
|
||||
deepEqual obj6.c, {d: 33, e: 44, f: {g: 55}}
|
||||
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
obj7 = {
|
||||
obj ...
|
||||
fn() ...
|
||||
{c: {d: 55, e: 66, f: {77}}} ...
|
||||
}
|
||||
eq obj7.c.d, 55
|
||||
deepEqual obj6.c, {d: 33, e: 44, f: {g: 55}}
|
||||
|
||||
obj =
|
||||
a:
|
||||
b:
|
||||
@@ -746,3 +897,21 @@ test "#4566: destructuring with nested default values", ->
|
||||
|
||||
{e: {f = 5} = {}} = {}
|
||||
eq 5, f
|
||||
|
||||
test "#4674: _extends utility for object spreads 1", ->
|
||||
eqJS(
|
||||
"{a, b..., c..., d}"
|
||||
"""
|
||||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
||||
|
||||
_extends({a}, b, c, {d});
|
||||
"""
|
||||
)
|
||||
|
||||
test "#4674: _extends utility for object spreads 2", ->
|
||||
_extends = -> 3
|
||||
a = b: 1
|
||||
c = d: 2
|
||||
e = {a..., c...}
|
||||
eq e.b, 1
|
||||
eq e.d, 2
|
||||
|
||||
@@ -1,28 +1,15 @@
|
||||
# Functions that contain the `await` keyword will compile into async
|
||||
# functions, which currently only Node 7+ in harmony mode can even
|
||||
# evaluate, much less run. Therefore we need to prevent runtimes
|
||||
# which will choke on such code from even loading it. This file is
|
||||
# only loaded by async-capable environments, so we redefine `test`
|
||||
# here even though it is based on `test` defined in `Cakefile`.
|
||||
# It replaces `test` for this file, and adds to the tracked
|
||||
# `passedTests` and `failures` arrays which are global objects.
|
||||
test = (description, fn) ->
|
||||
try
|
||||
fn.test = {description, currentFile}
|
||||
await fn.call(fn)
|
||||
++passedTests
|
||||
catch e
|
||||
failures.push
|
||||
filename: currentFile
|
||||
error: e
|
||||
description: description if description?
|
||||
source: fn.toString() if fn.toString?
|
||||
# Functions that contain the `await` keyword will compile into async functions,
|
||||
# supported by Node 7.6+, Chrome 55+, Firefox 52+, Safari 10.1+ and Edge.
|
||||
# But runtimes that don’t support the `await` keyword will throw an error,
|
||||
# even if we put `return unless global.supportsAsync` at the top of this file.
|
||||
# Therefore we need to prevent runtimes which will choke on such code from even
|
||||
# parsing it, which is handled in `Cakefile`.
|
||||
|
||||
|
||||
# always fulfills
|
||||
# This is always fulfilled.
|
||||
winning = (val) -> Promise.resolve val
|
||||
|
||||
# always is rejected
|
||||
# This is always rejected.
|
||||
failing = (val) -> Promise.reject new Error val
|
||||
|
||||
|
||||
|
||||
@@ -721,6 +721,26 @@ test "Empty lines between comments are preserved", ->
|
||||
3;
|
||||
}'''
|
||||
|
||||
test "Block comment in an interpolated string", ->
|
||||
eqJS '"a#{### Comment ###}b"', "`a${/* Comment */''}b`;"
|
||||
eqJS '"a#{### 1 ###}b#{### 2 ###}c"', "`a${/* 1 */''}b${/* 2 */''}c`;"
|
||||
|
||||
test "#4629: Block comment in CSX interpolation", ->
|
||||
eqJS '<div>{### Comment ###}</div>', '<div>{/* Comment */}</div>;'
|
||||
eqJS '''
|
||||
<div>
|
||||
{###
|
||||
Multiline
|
||||
Comment
|
||||
###}
|
||||
</div>''', '''
|
||||
<div>
|
||||
{/*
|
||||
Multiline
|
||||
Comment
|
||||
*/}
|
||||
</div>;'''
|
||||
|
||||
test "Line comment in an interpolated string", ->
|
||||
eqJS '''
|
||||
"a#{# Comment
|
||||
|
||||
@@ -75,7 +75,7 @@ if require?
|
||||
finally
|
||||
fs.unlinkSync tempFile
|
||||
|
||||
test "#3890 Error.prepareStackTrace doesn't throw an error if a compiled file is deleted", ->
|
||||
test "#3890: Error.prepareStackTrace doesn't throw an error if a compiled file is deleted", ->
|
||||
# Adapted from https://github.com/atom/coffee-cash/blob/master/spec/coffee-cash-spec.coffee
|
||||
filePath = path.join os.tmpdir(), 'PrepareStackTraceTestFile.coffee'
|
||||
fs.writeFileSync filePath, "module.exports = -> throw new Error('hello world')"
|
||||
@@ -90,7 +90,10 @@ if require?
|
||||
doesNotThrow(-> error.stack)
|
||||
notEqual error.stack.toString().indexOf(filePath), -1
|
||||
|
||||
test "#4418 stack traces for compiled files reference the correct line number", ->
|
||||
test "#4418: stack traces for compiled files reference the correct line number", ->
|
||||
# The browser is already compiling other anonymous scripts (the tests)
|
||||
# which will conflict.
|
||||
return if global.testingBrowser
|
||||
filePath = path.join os.tmpdir(), 'StackTraceLineNumberTestFile.coffee'
|
||||
fileContents = """
|
||||
testCompiledFileStackTraceLineNumber = ->
|
||||
@@ -111,15 +114,18 @@ if require?
|
||||
eq /StackTraceLineNumberTestFile.coffee:(\d)/.exec(error.stack.toString())[1], '3'
|
||||
|
||||
|
||||
test "#4418 stack traces for compiled strings reference the correct line number", ->
|
||||
test "#4418: stack traces for compiled strings reference the correct line number", ->
|
||||
# The browser is already compiling other anonymous scripts (the tests)
|
||||
# which will conflict.
|
||||
return if global.testingBrowser
|
||||
try
|
||||
CoffeeScript.run """
|
||||
CoffeeScript.run '''
|
||||
testCompiledStringStackTraceLineNumber = ->
|
||||
# `a` on the next line is undefined and should throw a ReferenceError
|
||||
console.log a if true
|
||||
|
||||
do testCompiledStringStackTraceLineNumber
|
||||
"""
|
||||
'''
|
||||
catch error
|
||||
|
||||
# Make sure the line number reported is line 3 (the original Coffee source)
|
||||
@@ -127,6 +133,26 @@ test "#4418 stack traces for compiled strings reference the correct line number"
|
||||
eq /testCompiledStringStackTraceLineNumber.*:(\d):/.exec(error.stack.toString())[1], '3'
|
||||
|
||||
|
||||
test "#4558: compiling a string inside a script doesn’t screw up stack trace line number", ->
|
||||
# The browser is already compiling other anonymous scripts (the tests)
|
||||
# which will conflict.
|
||||
return if global.testingBrowser
|
||||
try
|
||||
CoffeeScript.run '''
|
||||
testCompilingInsideAScriptDoesntScrewUpStackTraceLineNumber = ->
|
||||
if require?
|
||||
CoffeeScript = require './lib/coffeescript'
|
||||
CoffeeScript.compile ''
|
||||
throw new Error 'Some Error'
|
||||
|
||||
do testCompilingInsideAScriptDoesntScrewUpStackTraceLineNumber
|
||||
'''
|
||||
catch error
|
||||
|
||||
# Make sure the line number reported is line 5 (the original Coffee source)
|
||||
# and not line 10 (the generated JavaScript).
|
||||
eq /testCompilingInsideAScriptDoesntScrewUpStackTraceLineNumber.*:(\d):/.exec(error.stack.toString())[1], '5'
|
||||
|
||||
test "#1096: unexpected generated tokens", ->
|
||||
# Implicit ends
|
||||
assertErrorFormat 'a:, b', '''
|
||||
@@ -1742,3 +1768,12 @@ test "#3199: error message for throw indented comprehension", ->
|
||||
x for x in [1, 2, 3]
|
||||
^
|
||||
'''
|
||||
|
||||
test "#3098: suppressed newline should be unsuppressed by semicolon", ->
|
||||
assertErrorFormat '''
|
||||
a = ; 5
|
||||
''', '''
|
||||
[stdin]:1:5: error: unexpected ;
|
||||
a = ; 5
|
||||
^
|
||||
'''
|
||||
|
||||
@@ -89,10 +89,8 @@ test "try/catch with empty catch as last statement in a function body", ->
|
||||
catch err
|
||||
eq nonce, fn()
|
||||
|
||||
|
||||
# Catch leads to broken scoping: #1595
|
||||
|
||||
test "try/catch with a reused variable name.", ->
|
||||
test "#1595: try/catch with a reused variable name", ->
|
||||
# `catch` shouldn’t lead to broken scoping.
|
||||
do ->
|
||||
try
|
||||
inner = 5
|
||||
@@ -100,11 +98,7 @@ test "try/catch with a reused variable name.", ->
|
||||
# nothing
|
||||
eq typeof inner, 'undefined'
|
||||
|
||||
|
||||
# Allowed to destructure exceptions: #2580
|
||||
|
||||
test "try/catch with destructuring the exception object", ->
|
||||
|
||||
test "#2580: try/catch with destructuring the exception object", ->
|
||||
result = try
|
||||
missing.object
|
||||
catch {message}
|
||||
@@ -112,8 +106,6 @@ test "try/catch with destructuring the exception object", ->
|
||||
|
||||
eq message, 'missing is not defined'
|
||||
|
||||
|
||||
|
||||
test "Try catch finally as implicit arguments", ->
|
||||
first = (x) -> x
|
||||
|
||||
@@ -130,8 +122,8 @@ test "Try catch finally as implicit arguments", ->
|
||||
catch e
|
||||
eq bar, yes
|
||||
|
||||
# Catch Should Not Require Param: #2900
|
||||
test "parameter-less catch clause", ->
|
||||
test "#2900: parameter-less catch clause", ->
|
||||
# `catch` should not require a parameter.
|
||||
try
|
||||
throw new Error 'failed'
|
||||
catch
|
||||
@@ -140,3 +132,53 @@ test "parameter-less catch clause", ->
|
||||
try throw new Error 'failed' catch finally ok true
|
||||
|
||||
ok try throw new Error 'failed' catch then true
|
||||
|
||||
test "#3709: throwing an if statement", ->
|
||||
# `throw if` should return a closure around the `if` block, so that the
|
||||
# output is valid JavaScript.
|
||||
try
|
||||
throw if no
|
||||
new Error 'drat!'
|
||||
else
|
||||
new Error 'no escape!'
|
||||
catch err
|
||||
eq err.message, 'no escape!'
|
||||
|
||||
try
|
||||
throw if yes then new Error 'huh?' else null
|
||||
catch err
|
||||
eq err.message, 'huh?'
|
||||
|
||||
test "#3709: throwing a switch statement", ->
|
||||
i = 3
|
||||
try
|
||||
throw switch i
|
||||
when 2
|
||||
new Error 'not this one'
|
||||
when 3
|
||||
new Error 'oh no!'
|
||||
catch err
|
||||
eq err.message, 'oh no!'
|
||||
|
||||
test "#3709: throwing a for loop", ->
|
||||
# `throw for` should return a closure around the `for` block, so that the
|
||||
# output is valid JavaScript.
|
||||
try
|
||||
throw for i in [0..3]
|
||||
i * 2
|
||||
catch err
|
||||
arrayEq err, [0, 2, 4, 6]
|
||||
|
||||
test "#3709: throwing a while loop", ->
|
||||
i = 0
|
||||
try
|
||||
throw while i < 3
|
||||
i++
|
||||
catch err
|
||||
eq i, 3
|
||||
|
||||
test "#3789: throwing a throw", ->
|
||||
try
|
||||
throw throw throw new Error 'whoa!'
|
||||
catch err
|
||||
eq err.message, 'whoa!'
|
||||
|
||||
@@ -87,6 +87,9 @@ doesNotThrow -> CoffeeScript.compile """
|
||||
a?[b..c]
|
||||
"""
|
||||
|
||||
test "#1768: space between `::` and index is ignored", ->
|
||||
eq 'function', typeof String:: ['toString']
|
||||
|
||||
# Array Literals
|
||||
|
||||
test "indented array literals don't trigger whitespace rewriting", ->
|
||||
@@ -407,3 +410,41 @@ test "#3199: throw multiline implicit object", ->
|
||||
type: 'a'
|
||||
msg: 'b'
|
||||
eq undefined, y
|
||||
|
||||
test "#4576: multiple row function chaining", ->
|
||||
->
|
||||
eq @a, 3
|
||||
.call a: 3
|
||||
|
||||
test "#4576: function chaining on separate rows", ->
|
||||
do ->
|
||||
Promise
|
||||
.resolve()
|
||||
.then ->
|
||||
yes
|
||||
.then ok
|
||||
|
||||
test "#3736: chaining after do IIFE", ->
|
||||
eq 3,
|
||||
do ->
|
||||
a: 3
|
||||
.a
|
||||
|
||||
eq 3,
|
||||
do (b = (c) -> c) -> a: 3
|
||||
?.a
|
||||
|
||||
b = 3
|
||||
eq 3,
|
||||
do (
|
||||
b
|
||||
{d} = {}
|
||||
) ->
|
||||
a: b
|
||||
.a
|
||||
|
||||
# preserve existing chaining behavior for non-IIFE `do`
|
||||
b = c: -> 4
|
||||
eq 4,
|
||||
do b
|
||||
.c
|
||||
|
||||
@@ -347,12 +347,26 @@ test "passing splats to functions", ->
|
||||
arrayEq [2..6], others
|
||||
eq 7, last
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
arrayEq [0..4], id id [0..4] ...
|
||||
fn = (a, b, c ..., d) -> [a, b, c, d]
|
||||
range = [0..3]
|
||||
[first, second, others, last] = fn range ..., 4, [5 ... 8] ...
|
||||
eq 0, first
|
||||
eq 1, second
|
||||
arrayEq [2..6], others
|
||||
eq 7, last
|
||||
|
||||
test "splat variables are local to the function", ->
|
||||
outer = "x"
|
||||
clobber = (avar, outer...) -> outer
|
||||
clobber "foo", "bar"
|
||||
eq "x", outer
|
||||
|
||||
test "Issue 4631: left and right spread dots with preceding space", ->
|
||||
a = []
|
||||
f = (a) -> a
|
||||
eq yes, (f ...a) is (f ... a) is (f a...) is (f a ...) is f(a...) is f(...a) is f(a ...) is f(... a)
|
||||
|
||||
test "Issue 894: Splatting against constructor-chained functions.", ->
|
||||
|
||||
@@ -387,6 +401,16 @@ test "splats with super() within classes.", ->
|
||||
super nums...
|
||||
ok (new Child).meth().join(' ') is '3 2 1'
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
class Parent
|
||||
meth: (args ...) ->
|
||||
args
|
||||
class Child extends Parent
|
||||
meth: ->
|
||||
nums = [3, 2, 1]
|
||||
super nums ...
|
||||
ok (new Child).meth().join(' ') is '3 2 1'
|
||||
|
||||
|
||||
test "#1011: passing a splat to a method of a number", ->
|
||||
eq '1011', 11.toString [2]...
|
||||
@@ -394,12 +418,21 @@ test "#1011: passing a splat to a method of a number", ->
|
||||
eq '1011', 69.0.toString [4]...
|
||||
eq '1011', (131.0).toString [5]...
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
eq '1011', 11.toString [2] ...
|
||||
eq '1011', (31).toString [3] ...
|
||||
eq '1011', 69.0.toString [4] ...
|
||||
eq '1011', (131.0).toString [5] ...
|
||||
|
||||
test "splats and the `new` operator: functions that return `null` should construct their instance", ->
|
||||
args = []
|
||||
child = new (constructor = -> null) args...
|
||||
ok child instanceof constructor
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
child = new (constructor = -> null) args ...
|
||||
ok child instanceof constructor
|
||||
|
||||
test "splats and the `new` operator: functions that return functions should construct their return value", ->
|
||||
args = []
|
||||
fn = ->
|
||||
|
||||
@@ -110,6 +110,12 @@ test "splats", ->
|
||||
arrayEq [0, 1], (((splat..., _, _1) -> splat) 0, 1, 2, 3)
|
||||
arrayEq [2], (((_, _1, splat..., _2) -> splat) 0, 1, 2, 3)
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
arrayEq [0, 1, 2], (((splat ...) -> splat) 0, 1, 2)
|
||||
arrayEq [2, 3], (((_, _1, splat ...) -> splat) 0, 1, 2, 3)
|
||||
arrayEq [0, 1], (((splat ..., _, _1) -> splat) 0, 1, 2, 3)
|
||||
arrayEq [2], (((_, _1, splat ..., _2) -> splat) 0, 1, 2, 3)
|
||||
|
||||
test "destructured splatted parameters", ->
|
||||
arr = [0,1,2]
|
||||
splatArray = ([a...]) -> a
|
||||
@@ -117,6 +123,10 @@ test "destructured splatted parameters", ->
|
||||
arrayEq splatArray(arr), arr
|
||||
arrayEq splatArrayRest(arr,0,1,2), arr
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
splatArray = ([a ...]) -> a
|
||||
splatArrayRest = ([a ...],b ...) -> arrayEq(a,b); b
|
||||
|
||||
test "@-parameters: automatically assign an argument's value to a property of the context", ->
|
||||
nonce = {}
|
||||
|
||||
@@ -127,10 +137,18 @@ test "@-parameters: automatically assign an argument's value to a property of th
|
||||
((splat..., @prop) ->).apply context = {}, [0, 0, nonce]
|
||||
eq nonce, context.prop
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
((splat ..., @prop) ->).apply context = {}, [0, 0, nonce]
|
||||
eq nonce, context.prop
|
||||
|
||||
# Allow the argument itself to be a splat
|
||||
((@prop...) ->).call context = {}, 0, nonce, 0
|
||||
eq nonce, context.prop[1]
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
((@prop ...) ->).call context = {}, 0, nonce, 0
|
||||
eq nonce, context.prop[1]
|
||||
|
||||
# The argument should not be able to be referenced normally
|
||||
code = '((@prop) -> prop).call {}'
|
||||
doesNotThrow -> CoffeeScript.compile code
|
||||
@@ -149,12 +167,26 @@ test "@-parameters and splats with constructors", ->
|
||||
eq a, obj.first
|
||||
eq b, obj.last
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
class Klass
|
||||
constructor: (@first, splat ..., @last) ->
|
||||
|
||||
obj = new Klass a, 0, 0, b
|
||||
eq a, obj.first
|
||||
eq b, obj.last
|
||||
|
||||
test "destructuring in function definition", ->
|
||||
(([{a: [b], c}]...) ->
|
||||
eq 1, b
|
||||
eq 2, c
|
||||
) {a: [1], c: 2}
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
(([{a: [b], c}] ...) ->
|
||||
eq 1, b
|
||||
eq 2, c
|
||||
) {a: [1], c: 2}
|
||||
|
||||
context = {}
|
||||
(([{a: [b, c = 2], @d, e = 4}]...) ->
|
||||
eq 1, b
|
||||
@@ -198,6 +230,17 @@ test "rest element destructuring in function definition", ->
|
||||
deepEqual r, {c: 3, d: 4, e: 5}
|
||||
) {a:1, b:2, c:3, d:4, e:5}, 9
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
(({
|
||||
a: p
|
||||
b
|
||||
r ...
|
||||
}, q) ->
|
||||
eq p, 1
|
||||
eq q, 9
|
||||
deepEqual r, {c: 3, d: 4, e: 5}
|
||||
) {a:1, b:2, c:3, d:4, e:5}, 9
|
||||
|
||||
a1={}; b1={}; c1={}; d1={}
|
||||
obj1 = {
|
||||
a: a1
|
||||
@@ -256,6 +299,10 @@ test "#4005: `([a = {}]..., b) ->` weirdness", ->
|
||||
fn = ([a = {}]..., b) -> [a, b]
|
||||
deepEqual fn(5), [{}, 5]
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
fn = ([a = {}] ..., b) -> [a, b]
|
||||
deepEqual fn(5), [{}, 5]
|
||||
|
||||
test "default values", ->
|
||||
nonceA = {}
|
||||
nonceB = {}
|
||||
@@ -299,6 +346,14 @@ test "default values with splatted arguments", ->
|
||||
eq 1, withSplats(1,1,1)
|
||||
eq 2, withSplats(1,1,1,1)
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
withSplats = (a = 2, b ..., c = 3, d = 5) -> a * (b.length + 1) * c * d
|
||||
eq 30, withSplats()
|
||||
eq 15, withSplats(1)
|
||||
eq 5, withSplats(1,1)
|
||||
eq 1, withSplats(1,1,1)
|
||||
eq 2, withSplats(1,1,1,1)
|
||||
|
||||
test "#156: parameter lists with expansion", ->
|
||||
expandArguments = (first, ..., lastButOne, last) ->
|
||||
eq 1, first
|
||||
@@ -328,6 +383,12 @@ test "variable definitions and splat", ->
|
||||
eq 0, a
|
||||
eq 0, b
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
f = (a, middle ..., b) -> [a, middle, b]
|
||||
arrayEq [1, [2, 3, 4], 5], f 1, 2, 3, 4, 5
|
||||
eq 0, a
|
||||
eq 0, b
|
||||
|
||||
test "default values with function calls", ->
|
||||
doesNotThrow -> CoffeeScript.compile "(x = f()) ->"
|
||||
|
||||
@@ -354,6 +415,12 @@ test "reserved keyword at-splat", ->
|
||||
eq 1, a
|
||||
eq 2, b
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
f = (@case ...) -> @case
|
||||
[a, b] = f(1, 2)
|
||||
eq 1, a
|
||||
eq 2, b
|
||||
|
||||
test "#1574: Destructuring and a parameter named _arg", ->
|
||||
f = ({a, b}, _arg, _arg1) -> [a, b, _arg, _arg1]
|
||||
arrayEq [1, 2, 3, 4], f a: 1, b: 2, 3, 4
|
||||
@@ -471,3 +538,14 @@ test "#3845/#3446: chain after function glyph", ->
|
||||
doThing()
|
||||
.then (@result) =>
|
||||
.catch handleError
|
||||
|
||||
test "#4413: expressions in function parameters that create generated variables have those variables declared correctly", ->
|
||||
'use strict'
|
||||
# We’re in strict mode because we want an error to be thrown if the generated
|
||||
# variable (`ref`) is assigned before being declared.
|
||||
foo = -> null
|
||||
bar = -> 33
|
||||
f = (a = foo() ? bar()) -> a
|
||||
g = (a = foo() ? bar()) -> a + 1
|
||||
eq f(), 33
|
||||
eq g(), 34
|
||||
|
||||
@@ -28,6 +28,19 @@ test "basic exclusive ranges", ->
|
||||
arrayEq [], [0...0]
|
||||
arrayEq [], [-1...-1]
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
arrayEq [1, 2, 3] , [1 ... 4]
|
||||
arrayEq [0, 1, 2] , [0 ... 3]
|
||||
arrayEq [0, 1] , [0 ... 2]
|
||||
arrayEq [0] , [0 ... 1]
|
||||
arrayEq [-1] , [-1 ... 0]
|
||||
arrayEq [-1, 0] , [-1 ... 1]
|
||||
arrayEq [-1, 0, 1], [-1 ... 2]
|
||||
|
||||
arrayEq [], [1 ... 1]
|
||||
arrayEq [], [0 ... 0]
|
||||
arrayEq [], [-1 ... -1]
|
||||
|
||||
test "downward ranges", ->
|
||||
arrayEq shared, [9..0].reverse()
|
||||
arrayEq [5, 4, 3, 2] , [5..2]
|
||||
@@ -66,6 +79,9 @@ test "ranges with expressions as endpoints", ->
|
||||
arrayEq [2, 3, 4, 5, 6], [(a+1)..2*b]
|
||||
arrayEq [2, 3, 4, 5] , [(a+1)...2*b]
|
||||
|
||||
# Should not trigger implicit call, e.g. rest ... => rest(...)
|
||||
arrayEq [2, 3, 4, 5] , [(a+1) ... 2*b]
|
||||
|
||||
test "large ranges are generated with looping constructs", ->
|
||||
down = [99..0]
|
||||
eq 100, (len = down.length)
|
||||
|
||||
@@ -115,6 +115,13 @@ testRepl "keeps running after runtime error", (input, output) ->
|
||||
input.emitLine 'a'
|
||||
eq 'undefined', output.lastWrite()
|
||||
|
||||
testRepl "#4604: wraps an async function", (input, output) ->
|
||||
return unless global.supportsAsync
|
||||
input.emitLine 'await new Promise (resolve) -> setTimeout (-> resolve 33), 10'
|
||||
setTimeout ->
|
||||
eq '33', output.lastWrite()
|
||||
, 20
|
||||
|
||||
process.on 'exit', ->
|
||||
try
|
||||
fs.unlinkSync historyFile
|
||||
|
||||
@@ -64,6 +64,18 @@ test "#1722: operator precedence in unbounded slice compilation", ->
|
||||
test "#2349: inclusive slicing to numeric strings", ->
|
||||
arrayEq [0, 1], [0..10][.."1"]
|
||||
|
||||
test "#4631: slicing with space before and/or after the dots", ->
|
||||
a = (s) -> s
|
||||
b = [4, 5, 6]
|
||||
c = [7, 8, 9]
|
||||
arrayEq [2, 3, 4], shared[2 ... 5]
|
||||
arrayEq [3, 4, 5], shared[3... 6]
|
||||
arrayEq [4, 5, 6], shared[4 ...7]
|
||||
arrayEq shared[(a b...)...(a c...)] , shared[(a ...b)...(a ...c)]
|
||||
arrayEq shared[(a b...) ... (a c...)], shared[(a ...b) ... (a ...c)]
|
||||
arrayEq shared[(a b...)... (a c...)] , shared[(a ...b)... (a ...c)]
|
||||
arrayEq shared[(a b...) ...(a c...)] , shared[(a ...b) ...(a ...c)]
|
||||
|
||||
|
||||
# Splicing
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@ return if global.testingBrowser
|
||||
SourceMap = require '../src/sourcemap'
|
||||
|
||||
vlqEncodedValues = [
|
||||
[1, "C"],
|
||||
[-1, "D"],
|
||||
[2, "E"],
|
||||
[-2, "F"],
|
||||
[0, "A"],
|
||||
[16, "gB"],
|
||||
[948, "o7B"]
|
||||
[1, 'C'],
|
||||
[-1, 'D'],
|
||||
[2, 'E'],
|
||||
[-2, 'F'],
|
||||
[0, 'A'],
|
||||
[16, 'gB'],
|
||||
[948, 'o7B']
|
||||
]
|
||||
|
||||
test "encodeVlq tests", ->
|
||||
@@ -25,27 +25,27 @@ test "SourceMap tests", ->
|
||||
map.add [3, 0], [3, 4]
|
||||
|
||||
testWithFilenames = map.generate {
|
||||
sourceRoot: ""
|
||||
sourceFiles: ["source.coffee"]
|
||||
generatedFile: "source.js"
|
||||
sourceRoot: ''
|
||||
sourceFiles: ['source.coffee']
|
||||
generatedFile: 'source.js'
|
||||
}
|
||||
|
||||
deepEqual testWithFilenames, {
|
||||
version: 3
|
||||
file: "source.js"
|
||||
sourceRoot: ""
|
||||
sources: ["source.coffee"]
|
||||
file: 'source.js'
|
||||
sourceRoot: ''
|
||||
sources: ['source.coffee']
|
||||
names: []
|
||||
mappings: "AAAA;;IACK,GAAC,CAAG;IAET"
|
||||
mappings: 'AAAA;;IACK,GAAC,CAAG;IAET'
|
||||
}
|
||||
|
||||
deepEqual map.generate(), {
|
||||
version: 3
|
||||
file: ""
|
||||
sourceRoot: ""
|
||||
sources: [""]
|
||||
file: ''
|
||||
sourceRoot: ''
|
||||
sources: ['<anonymous>']
|
||||
names: []
|
||||
mappings: "AAAA;;IACK,GAAC,CAAG;IAET"
|
||||
mappings: 'AAAA;;IACK,GAAC,CAAG;IAET'
|
||||
}
|
||||
|
||||
# Look up a generated column - should get back the original source position.
|
||||
@@ -53,3 +53,13 @@ test "SourceMap tests", ->
|
||||
|
||||
# Look up a point further along on the same line - should get back the same source position.
|
||||
arrayEq map.sourceLocation([2,10]), [1,9]
|
||||
|
||||
test "#3075: v3 source map fields", ->
|
||||
{ js, v3SourceMap, sourceMap } = CoffeeScript.compile 'console.log Date.now()',
|
||||
filename: 'tempus_fugit.coffee'
|
||||
sourceMap: yes
|
||||
sourceRoot: './www_root/coffee/'
|
||||
|
||||
v3SourceMap = JSON.parse v3SourceMap
|
||||
arrayEq v3SourceMap.sources, ['tempus_fugit.coffee']
|
||||
eq v3SourceMap.sourceRoot, './www_root/coffee/'
|
||||
|
||||
@@ -29,7 +29,7 @@ exports.eq = (a, b, msg) ->
|
||||
"Expected #{reset}#{a}#{red} to equal #{reset}#{b}#{red}"
|
||||
|
||||
exports.arrayEq = (a, b, msg) ->
|
||||
ok arrayEgal(a,b), msg or
|
||||
ok arrayEgal(a, b), msg or
|
||||
"Expected #{reset}#{a}#{red} to deep equal #{reset}#{b}#{red}"
|
||||
|
||||
exports.eqJS = (input, expectedOutput, msg) ->
|
||||
|
||||
Reference in New Issue
Block a user