Compare commits

..

35 Commits

Author SHA1 Message Date
Geoffrey Booth
df9d4a2343 [CS2] 2.0.0-beta5 (#4682)
* Upgrade docs to Bootstrap 4 beta, including refactoring styles; upgrade docs jQuery and CodeMirror

* Better style the docs for mobile, including Try CoffeeScript

* Fix #4642, erroneous statement about named functions

* Update packages

* 2.0.0-beta5
2017-09-02 12:48:38 -07:00
Geoffrey Booth
9e043bbae7 [CS2] Fix async tests (#4680)
* Get `coffee` command working again in Node 6, by converting the ‘await’ wrapper in the REPL to use a Promise instead of the ‘await’ keyword; add tests for REPL ‘await’ wrapper, including test to skip async tests if the runtime doesn’t support them

* Fix async tests: now if a test function is a Promise (which an `await` function is), we add it to an array of async test functions and wait for them all to resolve before finishing the test run, so that if any async tests fail we see those failures in the output

* Code review

* Unnecessary

* Let's support Node 6+ if we can

* Simplify the returned promise

* Simplify async check
2017-09-01 12:26:47 -07:00
Geoffrey Booth
671486989f [CS2] Don’t require async/await support to run coffee (#4679)
* Get `coffee` command working again in Node 6, by converting the ‘await’ wrapper in the REPL to use a Promise instead of the ‘await’ keyword; add tests for REPL ‘await’ wrapper, including test to skip async tests if the runtime doesn’t support them

* Code review

* Let's support Node 6+ if we can
2017-09-01 12:19:15 -07:00
Geoffrey Booth
4a4f752204 Fix #3098: Suppressed newline should be unsuppressed by semicolon (#4669) 2017-09-01 07:09:36 -07:00
Julian Rosse
b20e52da99 [CS2] use _extends utility instead of Object.assign() for object spreads (#4675)
* _extends utility instead of Object.assign()

* eqJS test for _extends

* Test that a user-defined function named `_extends` doesn’t conflict with our utility function

* IE8 polyfill note in docs
2017-09-01 07:09:16 -07:00
Chris Connelly
5525b2ba01 Merge pull request #4652 from GeoffreyBooth/bug-fix-4651
[CS2] Fix #4651: object spread destructuring bug
2017-09-01 13:10:49 +01:00
Geoffrey Booth
fe5ff39ca2 [CS2] Fix v3 source map (#4671)
* Per discussion in #3075: if `sourceFiles` is unspecified, but `filename` is, use `filename`; output null instead of an empty string for `sources` or `sourceRoot`

* Update source map tests to reflect that now we return null instead of empty strings; check generated sources array

* Update source map documentation; still leave more obscure options undocumented

* Follow the TypeScript compiler’s example regarding v3SourceMap, but output empty strings instead of made-up filenames

* Have `sources` default to ‘<anonymous>’
2017-09-01 01:06:45 -07:00
Geoffrey Booth
906bedf93a Fix #1768: Ignore space after :: (#4670) 2017-08-30 22:43:17 -07:00
Julian Rosse
6f961a20dd [CS2] Refine #4666: add parens to chained do IIFE with params (#4672)
* add parens to chained do iife [Fixes #3736]

* remove debug code

* fixes from code review

* handle iife with params

* add test w/ destructured param from code review
2017-08-30 22:42:50 -07:00
Julian Rosse
e54b8a1009 [CS2] add parens to chained do IIFE (#4666)
* add parens to chained do iife [Fixes #3736]

* remove debug code

* fixes from code review
2017-08-29 14:17:56 -07:00
Geoffrey Booth
d7d69a4a18 Fix #4576: Allow accessing a property of a function literal (like .call) via chaining syntax (#4665) 2017-08-28 13:16:22 -07:00
Geoffrey Booth
eb38dba5d6 Only unescape newlines for CSX; updated compiled output 2017-08-27 21:37:21 -07:00
Geoffrey Booth
9ff82fe17b Fix #4589: Unquote all interpolated strings, not just CSX ones, so that quotation marks are not unnecessarily escaped in backtick-delimited strings/template literals (#4660) 2017-08-27 15:16:31 -07:00
zdenko
5713b7eb6c [CS2] Fix #4260 and #1349: Splat error with soak properties or expressions (#4644)
* fix splat error with soak properties or expressions

* Add test based on #4260

* Add test based on #1349

* tests for the leading splat variant

* test for spaced prefix ...

* fixed 'if' statement in parens

* fixed replacing 'void 0' with '[]'

* remove 'void 0' replacement; add Splat::compileNode

* Use LEVEL_OP; follow style better
2017-08-27 15:11:14 -07:00
Geoffrey Booth
7c627f9dfd [CS2] Fix #3709, #3789: ‘throw’ an ‘if’, ‘for’, ‘switch’, ‘while’ (#4664)
* Fix #3709: throwing an if, for, switch or while should throw the returned value of the statement/loop

* Fix #3789: don’t throw a throw (unless it’s in a closure)

* LEVEL_LIST works better than a list of node types
2017-08-25 11:11:10 -07:00
Geoffrey Booth
c81e2d4767 Fix #4575: Check for the previous token’s existence before comparing against it (#4663) 2017-08-24 00:05:26 -07:00
Geoffrey Booth
3dd458267b [CS2] Fix #2870: Allow specifying output filename (#4661)
* Fix #2870: If --output ends with a filename, and the input is a file and not a path, save as the desired filename

* If an output path ends in a slash, force saving into an output folder even if that folder name would contain a period (e.g. /scripts.js/); if output filename is only periods, treat it as a path

* Restrict exceptions
2017-08-24 00:03:57 -07:00
Geoffrey Booth
892c4699dd Fix #4578: Never look back past the start of the token stream (#4662) 2017-08-24 00:02:57 -07:00
Geoffrey Booth
40c351135a [CS2] Fix #4629: interpolations (whether in strings or CSX tags) with only comments (#4659)
* Fix #4629: interpolations (whether in strings or CSX tags) that contain nothing but comments should not be optimized out

* Template literals need an expression inside their interpolations, so if we only have a comment to put in there, toss in an empty string as well
2017-08-23 23:34:59 -07:00
Geoffrey Booth
a3b08e1bef [CS2] Fix #4209: --require for filenames that are invalid identifiers (#4658)
* When using --require, check that the variable we’re creating from the required file/module is a valid identifier name before assigning to it; fixes #4209

* We don’t need no stinkin’ regex
2017-08-23 06:51:14 -07:00
Geoffrey Booth
44a27c6204 Fix #4558: Stack trace line numbers for scripts that compile CoffeeScript (#4645)
* Don't throw an error in the console when loading a try: URL

* Handle the possibility of compiling multiple scripts with the same filename, or multiple anonymous scripts

* Fix #4558: Much more robust caching of sources and source maps, more careful lookup of source maps especially for CoffeeScript code compiled within a Coffee script (. . . within a Coffee script, etc.)

* Reimplement `cake release` to just use the shell to avoid the issues plaguing that command (something to do with module caching perhaps)
2017-08-23 06:50:46 -07:00
Zdenko Vujasinovic
c212e6e9ab refactor 2017-08-22 21:19:56 +02:00
Zdenko Vujasinovic
5a709ed4a8 improve variable declaration 2017-08-22 10:48:12 +02:00
Zdenko Vujasinovic
2491d3286d fix assign in nested properties
fix assign in nested properties
2017-08-21 21:16:28 +02:00
Julian Rosse
1a6477adec resolve merge conflicts 2017-08-21 10:39:46 -04:00
Julian Rosse
2149c3561b ensure Value; breaking test for {a={b...}} = c 2017-08-21 10:34:33 -04:00
Zdenko Vujasinovic
232041db2a fixed issue with nested properties 2017-08-21 16:22:17 +02:00
Ben Drechsel
4623bf5bba Docs: Define functions used in loop examples (#4653)
* Cherrypick changes from messy branch

* Reorder function defs
2017-08-18 17:15:52 -07:00
Zdenko Vujasinovic
2664c2c108 small fix 2017-08-18 08:51:11 +02:00
Zdenko Vujasinovic
f9367bacf1 fix object spread destructuring bug: #4651 2017-08-18 04:06:37 +02:00
zdenko
aef54aeaf7 [CS2] Fix #4631: Expansion that becomes rest parameter causes runtime error (#4634)
* expansion-rest bug fix

* tests; improved implicit call recognition with dots on the left in the `rewriter`

* whitespace cleanup

* more tests
2017-08-17 13:13:52 -07:00
Chris Connelly
eff160eeb7 Merge pull request #4640 from GeoffreyBooth/generated-variables-in-function-parameters
[CS2] Fix #4413: Generated variables in function parameters
2017-08-15 14:19:21 +01:00
Geoffrey Booth
911c21f7be Update test to prove that there's no collision in generated variables 2017-08-14 03:06:38 +00:00
Geoffrey Booth
52795587ec If compiling a function parameter creates any generated variables (e.g. ref), shift the declarations for those variables into the parent scope; fixes #4413 2017-08-14 03:00:01 +00:00
Geoffrey Booth
3a6ffa6a85 Clean up function parameter compilation to get name for scope 2017-08-14 02:42:01 +00:00
73 changed files with 3780 additions and 2106 deletions

View File

@@ -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 theyre 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 isnt 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

View File

@@ -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 @@ didnt create a source map (faster) but something went wrong and we need
a stack trace. Assuming that most of the time, code isnt throwing
exceptions, its probably more efficient to compile twice only when we
need a stack trace, rather than always generating a source map even when
its not likely to be used. Save in form of <code>filename</code>: <code>(source)</code></p>
its not likely to be used. Save in form of <code>filename</code>: [<code>(source)</code>]</p>
</div>
@@ -267,7 +267,7 @@ its not likely to be used. Save in form of <code>filename</code>: <code>(sour
<div class="pilwrap ">
<a class="pilcrow" href="#section-9">&#182;</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> -&gt;</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> -&gt;</span></pre></div></div>
</li>
@@ -714,22 +714,15 @@ Modified to handle sourceMap</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-28">&#182;</a>
</div>
<p>CoffeeScript compiled in a browser may get compiled with <code>options.filename</code>
of <code>&lt;anonymous&gt;</code>, but the browser may request the stack trace with the
filename of the script file.</p>
<p>Skip files that we didnt 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">'&lt;anonymous&gt;'</span>]?
sourceMaps[<span class="hljs-string">'&lt;anonymous&gt;'</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">'&lt;anonymous&gt;'</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">'&lt;anonymous&gt;'</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">&#182;</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> thats missing, which becomes
<code>&lt;anonymous&gt;</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>&lt;anonymous&gt;</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">'&lt;anonymous&gt;'</span>]?</pre></div></div>
</li>
<li id="section-30">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-30">&#182;</a>
</div>
<p>Work backwards from the most recent anonymous source maps, until we find
one that works. This isnt 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> doesnt always work,
and its 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">'&lt;anonymous&gt;'</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">&#182;</a>
</div>
<p>If all else fails, recompile this source to get a source map. We need the
previous section (for <code>&lt;anonymous&gt;</code>) despite this option, because after it
gets compiled we will still need to look it up from
<code>sourceMaps[&#39;&lt;anonymous&gt;&#39;]</code> in order to find and return it. Thats 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">&#182;</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> -&gt;</span>
<span class="hljs-function"> <span class="hljs-title">getSourceMapping</span> = <span class="hljs-params">(filename, line, column)</span> -&gt;</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>

View File

@@ -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">&#182;</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">&#182;</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> -&gt;</span>
requires.map (<span class="hljs-built_in">module</span>) -&gt;
[_, 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">&#182;</a>
<a class="pilcrow" href="#section-11">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-12">&#182;</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 scripts 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> -&gt;</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">&#182;</a>
<a class="pilcrow" href="#section-13">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-14">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-15">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-16">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-17">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-18">&#182;</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> -&gt;</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">&#182;</a>
<a class="pilcrow" href="#section-19">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-20">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-21">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-22">&#182;</a>
</div>
<p>When watching scripts, its 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">&#182;</a>
<a class="pilcrow" href="#section-23">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-24">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-25">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-26">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-27">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-28">&#182;</a>
</div>
<p>Print the <code>--version</code> message and exit.</p>

View File

@@ -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">-&gt;</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">-&gt;</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">-&gt;</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>

View File

@@ -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> -&gt;</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` cant 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>&#39;NEOSTRING&#39;</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>&#39;NEOSTRING&#39;</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>&#39;NEOSTRING&#39;</code>s are converted using <code>fn</code> and tur
<div class="pilwrap ">
<a class="pilcrow" href="#section-57">&#182;</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">&#182;</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*/&#39;&#39;}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">&#182;</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">&#182;</a>
</div>
<p>Push all the tokens in the fake <code>&#39;TOKENS&#39;</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">&#182;</a>
<a class="pilcrow" href="#section-61">&#182;</a>
</div>
<p>Convert <code>&#39;NEOSTRING&#39;</code> into <code>&#39;STRING&#39;</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">&#182;</a>
<a class="pilcrow" href="#section-62">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-63">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-64">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-65">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-66">&#182;</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> -&gt;</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">&#182;</a>
<a class="pilcrow" href="#section-67">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-68">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-69">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-70">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-71">&#182;</a>
</div>
<p>Use length - 1 for the final offset - were supplying the last_line and the last_column,
so if last_column == first_column, then were looking at a character of length 1.</p>
@@ -1862,11 +1918,11 @@ so if last_column == first_column, then were 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">&#182;</a>
<a class="pilcrow" href="#section-72">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-73">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-74">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-75">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-76">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-77">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-78">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-79">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-80">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-81">&#182;</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">-&gt;</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">&#182;</a>
<a class="pilcrow" href="#section-82">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-83">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-84">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-85">&#182;</a>
</div>
<p><code>from</code> isnt 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">&#182;</a>
<a class="pilcrow" href="#section-86">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-87">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-88">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-89">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-90">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-91">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-92">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-93">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-94">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-95">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-96">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-97">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-98">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-99">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-100">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-101">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-102">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-103">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-104">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-105">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-106">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-107">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-108">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-109">&#182;</a>
</div>
<p>Tokens which can be the left-hand side of a less-than comparison, i.e. <code>a&lt;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">&#182;</a>
<a class="pilcrow" href="#section-110">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-111">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-112">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-113">&#182;</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
View File

0
docs/v2/annotated-source/public/fonts/roboto-black.ttf Executable file → Normal file
View File

View File

View 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) -&gt;
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>

View File

@@ -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 &gt; <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 &lt;= <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">&#182;</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">-&gt;</span>
<span class="hljs-function"> <span class="hljs-title">condition</span> = <span class="hljs-params">(token, i)</span> -&gt;</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> -&gt;</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) -&gt;
<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> -&gt;</span> @tag(i - <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'PARAM_END'</span>
(token, i) -&gt; 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">'-&gt;'</span>, <span class="hljs-string">'=&gt;'</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">&#182;</a>
</div>
<p>Because our grammar is LALR(1), it cant handle some single-line
expressions that lack ending delimiters. The <strong>Rewriter</strong> adds the implicit
blocks, so it doesnt 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">&#182;</a>
<a class="pilcrow" href="#section-50">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-51">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-52">&#182;</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">&#182;</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">&#182;</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">&#182;</a>
</div>
</div>
</li>
<li id="section-55">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-55">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-56">&#182;</a>
</div>
<p>The inverse mappings of <code>BALANCED_PAIRS</code> were 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">&#182;</a>
<a class="pilcrow" href="#section-57">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-58">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-59">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-60">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-61">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-62">&#182;</a>
</div>
<p>Single-line flavors of block expressions that have unclosed endings.
The grammar cant 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">&#182;</a>
<a class="pilcrow" href="#section-63">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-64">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-65">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-66">&#182;</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

View File

@@ -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">'&lt;anonymous&gt;'</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

View File

@@ -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.

View File

@@ -2,5 +2,5 @@ $ 'body'
.click (e) ->
$ '.box'
.fadeIn 'fast'
.addClass '.active'
.addClass 'show'
.css 'background', 'white'

View File

@@ -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 shouldnt 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')
```

View File

@@ -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/) doesnt 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/).

View File

@@ -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.

View File

@@ -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)

View File

@@ -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 theyre 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 = ->` cant both be named `fn`) its 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 theyre assigned. Given that this is the case, its simplest to just preserve the current behavior.

View File

@@ -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 asserts fail
@fail = ->
ok no
# Polyfill Node assert's deepEqual with Underscore's isEqual
# Polyfill Node asserts deepEqual with Underscores 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 %>

View File

@@ -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>

View File

@@ -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>&ensp;<%= run.replace(/"/g, '&quot;') %><% } %></button>
</div>
</div>

View File

@@ -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 its still visible
if index is 0 and $('#try').hasClass('show') # If this is the editor in Try CoffeeScript and its 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 mightve thrown off our vertical scroll position
document.getElementById(window.location.hash.slice(1)).scrollIntoView()
if window.location.hash.length > 1
# Initializing the code editors mightve thrown off our vertical scroll position
document.getElementById(window.location.hash.slice(1).replace(/try:.*/, '')).scrollIntoView()

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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">

View File

@@ -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>&lt;</code> and <code>&gt;</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>&lt;</code> and <code>&gt;</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>

View File

@@ -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 Googles 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">

View File

@@ -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>&emsp;
</div>
</div>

View File

@@ -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.

View File

@@ -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))

View File

@@ -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 isnt throwing
// exceptions, its probably more efficient to compile twice only when we
// need a stack trace, rather than always generating a source map even when
// its not likely to be used. Save in form of `filename`: `(source)`
// its 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 didnt 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` thats 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 isnt 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()` doesnt always work,
// and its 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. Thats 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]);
}

View File

@@ -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);
};

View File

@@ -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.

View File

@@ -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

View File

@@ -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,

View File

@@ -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` cant 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 = {}) {

View File

@@ -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 were 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 wouldnt 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 cant 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';

View File

@@ -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

File diff suppressed because one or more lines are too long

View File

@@ -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;

View File

@@ -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);

View File

@@ -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 cant handle some single-line
// expressions that lack ending delimiters. The **Rewriter** adds the implicit
// blocks, so it doesnt need to. To keep the grammar clean and tidy, trailing

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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": {}
}

View File

@@ -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 isnt throwing
# exceptions, its probably more efficient to compile twice only when we
# need a stack trace, rather than always generating a source map even when
# its not likely to be used. Save in form of `filename`: `(source)`
# its 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 didnt 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` thats 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 isnt 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()` doesnt always work,
# and its 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. Thats 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

View File

@@ -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`.

View File

@@ -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'
]

View File

@@ -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` cant 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 = {}) ->

View File

@@ -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 cant 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'

View File

@@ -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

View File

@@ -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 cant handle some single-line
# expressions that lack ending delimiters. The **Rewriter** adds the implicit
# blocks, so it doesnt need to. To keep the grammar clean and tidy, trailing

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 dont 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

View File

@@ -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

View File

@@ -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 doesnt 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
^
'''

View File

@@ -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` shouldnt 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!'

View File

@@ -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

View File

@@ -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 = ->

View File

@@ -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'
# Were 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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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/'

View File

@@ -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) ->