Compare commits

..

21 Commits
2.2.0 ... 2.2.4

Author SHA1 Message Date
Geoffrey Booth
e5aa758dda 2.2.4 (#5025)
* Update changelog for 2.2.4

* Bump version to 2.2.4; update output
2018-03-29 20:00:45 -07:00
zdenko
001f97ac39 Fix #5013: return statement as an expression (#5014)
* fix #5013

* disallow statement in the expression
2018-03-17 23:08:43 -07:00
Robert de Forest
ce66a499de Make node --harmony bin/cake test pass on Node 9 (#5012)
* Make `node --harmony bin/cake test` pass on Node 9

Make classMaker() explicitly return an object

* Update Travis and AppVeyor to use --harmony and v9
2018-03-17 23:02:40 -07:00
zdenko
0268505119 Optimize 'for-range-by' loop when 'by' is literal number (#5016)
* optimize 'for-range-by' loop when 'by' is literal number

* small fix
2018-03-15 08:02:13 -07:00
Robert de Forest
5a43b2d7c5 simplified test file skipping (#4996) (#5003)
simplified test file skipping (#4996)
2018-03-12 19:03:44 -07:00
Geoffrey Booth
820942c3d0 2.2.3 (#5010)
* Bump version to 2.2.3; update packages

* Update output

* Update changelog
2018-03-11 13:48:14 -07:00
zdenko
1869f3121d Fix: destructuring assignment with an empty array in object (#5000)
* destructuring assignment with empty array in object

* improvements
2018-03-10 07:39:35 -08:00
zdenko
4c0363fb7c Fix #5004: incorrect compiled code when a destructuring array contains accessors (#5005) 2018-03-07 15:57:31 -08:00
Geoffrey Booth
746b0c7cc6 Code of Conduct (#4992)
* Code of Conduct

* Email address
2018-02-26 22:18:13 -08:00
Geoffrey Booth
b2fe7772c5 Pull request template (#4994) 2018-02-26 17:50:25 -08:00
Geoffrey Booth
23479eb486 Create issue template (#4993) 2018-02-26 17:50:14 -08:00
Geoffrey Booth
63b8543d73 Update output 2018-02-25 01:09:52 -08:00
zdenko
7542a75ff8 get/set example (#4990) 2018-02-25 00:18:57 -08:00
Joseph Lin
0875039d52 [update] copyright year to 2018 (#4988) 2018-02-24 23:40:11 -08:00
Geoffrey Booth
e0833c29ce 2.2.2 (#4986)
* Changelog for 2.2.2

* Bump version to 2.2.2

* Bump dependencies

* Update output
2018-02-22 00:31:14 -08:00
zdenko
72ab6feb2f Fix #4889: for...range loop condition (#4891)
* fix #4889

* test

* move test from 'control_flow' to 'ranges'

* More range tests
2018-02-20 00:46:20 -08:00
zdenko
eb7009268d fix #4898 (#4899) 2018-02-17 16:57:49 -08:00
zdenko
571e9df335 fix #4874 (#4888) 2018-02-08 21:11:11 -08:00
Geoffrey Booth
a73f66bc11 2.2.1 (#4885)
* 2.2.1 changelog

* Bump version to 2.2.1 and update output
2018-02-06 22:28:15 -08:00
zdenko
ba094126e2 Fix #4882: Range not declaring var for the "i" (#4883)
* fix #4882

* test
2018-02-04 13:33:08 -08:00
zdenko
794f65fbd7 Fix #4878: Compile error when using destructuring with a splat or expansion in an array (#4879)
* fix #4878

* improvements

* test

* refactor
2018-02-03 13:35:41 -08:00
41 changed files with 3225 additions and 1839 deletions

View File

@@ -3,6 +3,7 @@ language: node_js
node_js:
- 6
- 8
- 9
cache:
directories:
@@ -14,5 +15,6 @@ script:
- node ./bin/cake build:full
- node ./bin/cake build:browser
- node ./bin/cake test
- node --harmony ./bin/cake test
- node ./bin/cake test:browser
- node ./bin/cake test:integrations

46
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at maintainers@coffeescript.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@@ -425,12 +425,6 @@ runTests = (CoffeeScript) ->
catch err
onFail description, fn, err
global.supportsAsync = try
new Function('async () => {}')()
yes
catch
no
helpers.extend global, require './test/support/helpers'
# When all the tests have run, collect and print errors.
@@ -448,10 +442,18 @@ runTests = (CoffeeScript) ->
console.log " #{source}" if source
return
# 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'
# Run every test in the `test` folder, recording failures, except for files
# were skipping because the features to be tested are unsupported in the
# current Node runtime.
testFilesToSkip = []
skipUnless = (featureDetect, filenames) ->
unless (try new Function featureDetect)
testFilesToSkip = testFilesToSkip.concat filenames
skipUnless 'async () => {}', ['async.coffee', 'async_iterators.coffee']
skipUnless 'async function* generator() { yield 42; }', ['async_iterators.coffee']
skipUnless 'var a = 2 ** 2; a **= 3', ['exponentiation.coffee']
files = fs.readdirSync('test').filter (filename) ->
filename not in testFilesToSkip
startTime = Date.now()
for file in files when helpers.isCoffee file

62
ISSUE_TEMPLATE.md Normal file
View File

@@ -0,0 +1,62 @@
<!---
Thanks for filing an issue 😄! Before you submit, please read the following:
Search open/closed issues before submitting since someone might have asked the same thing before!
Our issues history stretches back to 2009, so the odds are good that your topic has come up.
If you have a support request or question please use Stack Overflow:
https://stackoverflow.com/questions/tagged/coffeescript
Issues on GitHub are only related to problems of the CoffeeScript compiler itself and we cannot answer
support questions here.
-->
Choose one: is this a bug report or feature request?
<!---
Provide a general summary of the issue in the title above.
For bugs, please also preface your title with “Bug:”. For feature requests, please preface your title
with “Proposal:”. Once your issue is reviewed, a maintainer will edit the title to refer to the part
of the codebase most relevant to the issue (if applicable).
If your request is that CoffeeScript support a new feature recently arrived to JavaScript, please note
that we generally only add features that have reached Stage 4 in the specification (in other words,
the syntax is finalized and the feature is approved to be part of the next ES release). You can still
open an issue, but it will likely be tagged with “[Awaiting Stage 4]” until the relevant ES feature is
approved for release. See http://coffeescript.org/#contributing
There are also a handful of JavaScript features that CoffeeScript intentionally does not support.
Please do not open issues regarding these. Theyre listed in http://coffeescript.org/#unsupported
-->
### Input Code
<!--- If you're describing a bug, please let us know which sample code reproduces your problem. -->
<!--- If you have link from http://coffeescript.org/#try or a standalone repo please include that! -->
```coffee
your (code) => here
```
### Expected Behavior
<!--- If youre describing a bug, tell us what should happen. -->
<!--- If youre suggesting a change/improvement, tell us how it should work. -->
### Current Behavior
<!--- If describing a bug, tell us what happens instead of the expected behavior. -->
<!--- If suggesting a change/improvement, explain the difference from current behavior. -->
### Possible Solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
<!--- or ideas how to implement the addition or change. -->
### Context
<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world. -->
### Environment
<!--- For bugs, please let us know what version of CoffeeScript youre running: `coffee -v`. -->
<!--- If you think it might be relevant, please also let us know your version of Node. -->
* CoffeeScript version:
* Node.js version:

View File

@@ -1,4 +1,4 @@
Copyright (c) 2009-2017 Jeremy Ashkenas
Copyright (c) 2009-2018 Jeremy Ashkenas
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation

22
PULL_REQUEST_TEMPLATE.md Normal file
View File

@@ -0,0 +1,22 @@
<!--
Before making a PR please make sure to read our contributing guidelines:
http://coffeescript.org/#contributing
For issue references: Add a comma-separated list of a
[closing word](https://help.github.com/articles/closing-issues-via-commit-messages/) followed by
the ticket number fixed by the PR. It should be underlined in the preview if done correctly.
All new features require tests. All but the most trivial bug fixes should also have new or updated tests.
Ensure that all new code you add to the compiler can be run in the minimum version of Node listed in
`package.json`. New tests can require newer Node runtimes, but you may need to ensure that such tests
only run in supported runtimes; see `Cakefile` for examples of how to filter out certain tests in
runtimes that dont support them.
Please follow the code style of the rest of the CoffeeScript codebase. Write comments in complete
sentences using Markdown, as the comments become the [annotated source](http://coffeescript.org/#annotated-source).
For tests proving a bug is fixed, please mention the issue number in the test description (see examples
in the codebase).
Describe your changes below in as much detail as possible.
-->

View File

@@ -2,6 +2,7 @@ environment:
matrix:
- nodejs_version: '6'
- nodejs_version: '8'
- nodejs_version: '9'
- nodejs_version: '' # Installs latest.
install:
@@ -19,6 +20,7 @@ test_script:
- node ./bin/cake build:full
- node ./bin/cake build:browser
- node ./bin/cake test
- node --harmony ./bin/cake test
- node ./bin/cake test:browser
- node ./bin/cake test:integrations

View File

@@ -920,10 +920,10 @@ can close multiple indents, so we need to know how far in we happen to be.</p>
indent = match[<span class="hljs-number">0</span>]
prev = @prev()
backslash = prev? <span class="hljs-keyword">and</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'\\'</span>
backslash = prev?[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'\\'</span>
@seenFor = <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> backslash <span class="hljs-keyword">and</span> @seenFor
@seenImport = <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> @importSpecifierList
@seenExport = <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> @exportSpecifierList
@seenImport = <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> (backslash <span class="hljs-keyword">and</span> @seenImport) <span class="hljs-keyword">or</span> @importSpecifierList
@seenExport = <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> (backslash <span class="hljs-keyword">and</span> @seenExport) <span class="hljs-keyword">or</span> @exportSpecifierList
size = indent.length - <span class="hljs-number">1</span> - indent.lastIndexOf <span class="hljs-string">'\n'</span>
noNewlines = @unfinished()
@@ -944,7 +944,7 @@ can close multiple indents, so we need to know how far in we happen to be.</p>
<span class="hljs-keyword">if</span> size &gt; @indent
<span class="hljs-keyword">if</span> noNewlines
@indebt = size - @indent
@indebt = size - @indent <span class="hljs-keyword">unless</span> backslash
@suppressNewlines()
<span class="hljs-keyword">return</span> indent.length
<span class="hljs-keyword">unless</span> @tokens.length

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -646,7 +646,7 @@ div.CodeMirror-cursor {
<section id="overview">
<p><strong>CoffeeScript is a little language that compiles into JavaScript.</strong> Underneath that awkward Java-esque patina, JavaScript has always had a gorgeous heart. CoffeeScript is an attempt to expose the good parts of JavaScript in a simple way.</p>
<p>The golden rule of CoffeeScript is: <em>“Its just JavaScript.”</em> The code compiles one-to-one into the equivalent JS, and there is no interpretation at runtime. You can use any existing JavaScript library seamlessly from CoffeeScript (and vice-versa). The compiled output is readable, pretty-printed, and tends to run as fast or faster than the equivalent handwritten JavaScript.</p>
<p><strong>Latest Version:</strong> <a href="https://github.com/jashkenas/coffeescript/tarball/2.2.0">2.2.0</a></p>
<p><strong>Latest Version:</strong> <a href="https://github.com/jashkenas/coffeescript/tarball/2.2.4">2.2.4</a></p>
<blockquote class="uneditable-code-block"><pre><code class="language-bash"><span class="comment"># Install locally for a project:</span>
npm install --save-dev coffeescript
@@ -3504,7 +3504,7 @@ say = function(text) {
countdown = async function(seconds) {
var i, j, ref;
for (i = j = ref = seconds; undefined !== 0 && (ref <= 1 ? ref <= j && j <= 1 : ref >= j && j >= 1); i = ref <= 1 ? ++j : --j) {
for (i = j = ref = seconds; (ref <= 1 ? j <= 1 : j >= 1); i = ref <= 1 ? ++j : --j) {
say(i);
await sleep(1000); // wait one second
}
@@ -3530,7 +3530,7 @@ countdown(3);
<span class="cm-variable">countdown</span> <span class="cm-operator">=</span> <span class="cm-keyword">async</span> <span class="cm-keyword">function</span>(<span class="cm-def">seconds</span>) {
<span class="cm-keyword">var</span> <span class="cm-def">i</span>, <span class="cm-def">j</span>, <span class="cm-def">ref</span>;
<span class="cm-keyword">for</span> (<span class="cm-variable-2">i</span> <span class="cm-operator">=</span> <span class="cm-variable-2">j</span> <span class="cm-operator">=</span> <span class="cm-variable-2">ref</span> <span class="cm-operator">=</span> <span class="cm-variable-2">seconds</span>; <span class="cm-atom">undefined</span> <span class="cm-operator">!==</span> <span class="cm-number">0</span> <span class="cm-operator">&amp;&amp;</span> (<span class="cm-variable-2">ref</span> <span class="cm-operator">&lt;=</span> <span class="cm-number">1</span> <span class="cm-operator">?</span> <span class="cm-variable-2">ref</span> <span class="cm-operator">&lt;=</span> <span class="cm-variable-2">j</span> <span class="cm-operator">&amp;&amp;</span> <span class="cm-variable-2">j</span> <span class="cm-operator">&lt;=</span> <span class="cm-number">1</span> : <span class="cm-variable-2">ref</span> <span class="cm-operator">>=</span> <span class="cm-variable-2">j</span> <span class="cm-operator">&amp;&amp;</span> <span class="cm-variable-2">j</span> <span class="cm-operator">>=</span> <span class="cm-number">1</span>); <span class="cm-variable-2">i</span> <span class="cm-operator">=</span> <span class="cm-variable-2">ref</span> <span class="cm-operator">&lt;=</span> <span class="cm-number">1</span> <span class="cm-operator">?</span> <span class="cm-operator">++</span><span class="cm-variable-2">j</span> : <span class="cm-operator">--</span><span class="cm-variable-2">j</span>) {
<span class="cm-keyword">for</span> (<span class="cm-variable-2">i</span> <span class="cm-operator">=</span> <span class="cm-variable-2">j</span> <span class="cm-operator">=</span> <span class="cm-variable-2">ref</span> <span class="cm-operator">=</span> <span class="cm-variable-2">seconds</span>; (<span class="cm-variable-2">ref</span> <span class="cm-operator">&lt;=</span> <span class="cm-number">1</span> <span class="cm-operator">?</span> <span class="cm-variable-2">j</span> <span class="cm-operator">&lt;=</span> <span class="cm-number">1</span> : <span class="cm-variable-2">j</span> <span class="cm-operator">>=</span> <span class="cm-number">1</span>); <span class="cm-variable-2">i</span> <span class="cm-operator">=</span> <span class="cm-variable-2">ref</span> <span class="cm-operator">&lt;=</span> <span class="cm-number">1</span> <span class="cm-operator">?</span> <span class="cm-operator">++</span><span class="cm-variable-2">j</span> : <span class="cm-operator">--</span><span class="cm-variable-2">j</span>) {
<span class="cm-variable">say</span>(<span class="cm-variable-2">i</span>);
<span class="cm-keyword">await</span> <span class="cm-variable">sleep</span>(<span class="cm-number">1000</span>); <span class="cm-comment">// wait one second</span>
}
@@ -4524,7 +4524,7 @@ renderStarRating = function({rating, maxStars}) {
{(function() {
var i, ref, results;
results = [];
for (wholeStar = i = 0, ref = Math.floor(rating); undefined !== 0 && (0 <= ref ? 0 <= i && i < ref : 0 >= i && i > ref); wholeStar = 0 <= ref ? ++i : --i) {
for (wholeStar = i = 0, ref = Math.floor(rating); (0 <= ref ? i < ref : i > ref); wholeStar = 0 <= ref ? ++i : --i) {
results.push(<Star className="wholeStar" key={wholeStar} />);
}
return results;
@@ -4533,7 +4533,7 @@ renderStarRating = function({rating, maxStars}) {
{(function() {
var i, ref, ref1, results;
results = [];
for (emptyStar = i = ref = Math.ceil(rating), ref1 = maxStars; undefined !== 0 && (ref <= ref1 ? ref <= i && i < ref1 : ref >= i && i > ref1); emptyStar = ref <= ref1 ? ++i : --i) {
for (emptyStar = i = ref = Math.ceil(rating), ref1 = maxStars; (ref <= ref1 ? i < ref1 : i > ref1); emptyStar = ref <= ref1 ? ++i : --i) {
results.push(<Star className="emptyStar" key={emptyStar} />);
}
return results;
@@ -4549,7 +4549,7 @@ renderStarRating = function({rating, maxStars}) {
<span class="cm-string-2">{(function() {</span>
<span class="cm-string-2">var i, ref, results;</span>
<span class="cm-string-2">results = [];</span>
<span class="cm-string-2">for (wholeStar = i = 0, ref = Math.floor(rating); undefined !== 0 &amp;&amp; (0 &lt;= ref ? 0 &lt;= i &amp;&amp; i &lt; ref : 0 >= i &amp;&amp; i > ref); wholeStar = 0 &lt;= ref ? ++i : --i) {</span>
<span class="cm-string-2">for (wholeStar = i = 0, ref = Math.floor(rating); (0 &lt;= ref ? i &lt; ref : i > ref); wholeStar = 0 &lt;= ref ? ++i : --i) {</span>
<span class="cm-string-2">results.push(&lt;Star className="wholeStar" key={wholeStar} />);</span>
<span class="cm-string-2">}</span>
<span class="cm-string-2">return results;</span>
@@ -4558,7 +4558,7 @@ renderStarRating = function({rating, maxStars}) {
<span class="cm-string-2">{(function() {</span>
<span class="cm-string-2">var i, ref, ref1, results;</span>
<span class="cm-string-2">results = [];</span>
<span class="cm-string-2">for (emptyStar = i = ref = Math.ceil(rating), ref1 = maxStars; undefined !== 0 &amp;&amp; (ref &lt;= ref1 ? ref &lt;= i &amp;&amp; i &lt; ref1 : ref >= i &amp;&amp; i > ref1); emptyStar = ref &lt;= ref1 ? ++i : --i) {</span>
<span class="cm-string-2">for (emptyStar = i = ref = Math.ceil(rating), ref1 = maxStars; (ref &lt;= ref1 ? i &lt; ref1 : i > ref1); emptyStar = ref &lt;= ref1 ? ++i : --i) {</span>
<span class="cm-string-2">results.push(&lt;Star className="emptyStar" key={emptyStar} />);</span>
<span class="cm-string-2">}</span>
<span class="cm-string-2">return results;</span>
@@ -4790,7 +4790,7 @@ The CoffeeScript logo is available in SVG for use in presentations.</li>
</section>
<section id="annotated-source">
<h2>Annotated Source</h2>
<p>You can browse the CoffeeScript 2.2.0 source in readable, annotated form <a href="annotated-source/">here</a>. You can also jump directly to a particular source file:</p>
<p>You can browse the CoffeeScript 2.2.4 source in readable, annotated form <a href="annotated-source/">here</a>. You can also jump directly to a particular source file:</p>
<ul>
<li><a href="annotated-source/grammar.html">Grammar Rules — src/grammar</a></li>
<li><a href="annotated-source/lexer.html">Lexing Tokens — src/lexer</a></li>
@@ -4859,7 +4859,7 @@ Object.defineProperty screen, 'height',
get: ->
this.width / this.ratio
set: (val) ->
this.width = val / this.ratio
this.width = val * this.ratio
</textarea>
<pre class="placeholder-code"><span class="cm-variable">screen</span> <span class="cm-punctuation">=</span>
<span class="cm-indent"> </span><span class="cm-variable">width</span><span class="cm-punctuation">:</span> <span class="cm-number">1200</span>
@@ -4869,7 +4869,7 @@ Object.defineProperty screen, 'height',
<span class="cm-indent"> </span><span class="cm-variable">get</span><span class="cm-punctuation">:</span> <span class="cm-operator">-></span>
<span class="cm-keyword">this</span><span class="cm-punctuation">.</span><span class="cm-property">width</span> <span class="cm-operator">/</span> <span class="cm-keyword">this</span><span class="cm-punctuation">.</span><span class="cm-property">ratio</span>
<span class="cm-dedent"> </span><span class="cm-variable">set</span><span class="cm-punctuation">:</span> <span class="cm-punctuation">(</span><span class="cm-variable">val</span><span class="cm-punctuation">)</span> <span class="cm-operator">-></span>
<span class="cm-keyword">this</span><span class="cm-punctuation">.</span><span class="cm-property">width</span> <span class="cm-punctuation">=</span> <span class="cm-variable">val</span> <span class="cm-operator">/</span> <span class="cm-keyword">this</span><span class="cm-punctuation">.</span><span class="cm-property">ratio</span>
<span class="cm-keyword">this</span><span class="cm-punctuation">.</span><span class="cm-property">width</span> <span class="cm-punctuation">=</span> <span class="cm-variable">val</span> <span class="cm-operator">*</span> <span class="cm-keyword">this</span><span class="cm-punctuation">.</span><span class="cm-property">ratio</span>
</pre>
</div>
<div class="col-md-6 javascript-output-column">
@@ -4885,7 +4885,7 @@ Object.defineProperty(screen, 'height', {
return this.width / this.ratio;
},
set: function(val) {
return this.width = val / this.ratio;
return this.width = val * this.ratio;
}
});
</textarea>
@@ -4901,7 +4901,7 @@ Object.defineProperty(screen, 'height', {
<span class="cm-keyword">return</span> <span class="cm-keyword">this</span>.<span class="cm-property">width</span> <span class="cm-operator">/</span> <span class="cm-keyword">this</span>.<span class="cm-property">ratio</span>;
},
<span class="cm-property">set</span>: <span class="cm-keyword">function</span>(<span class="cm-def">val</span>) {
<span class="cm-keyword">return</span> <span class="cm-keyword">this</span>.<span class="cm-property">width</span> <span class="cm-operator">=</span> <span class="cm-variable-2">val</span> <span class="cm-operator">/</span> <span class="cm-keyword">this</span>.<span class="cm-property">ratio</span>;
<span class="cm-keyword">return</span> <span class="cm-keyword">this</span>.<span class="cm-property">width</span> <span class="cm-operator">=</span> <span class="cm-variable-2">val</span> <span class="cm-operator">*</span> <span class="cm-keyword">this</span>.<span class="cm-property">ratio</span>;
}
});
</pre>
@@ -5467,6 +5467,38 @@ x = <span class="number">2</span> + <span class="number">2</span>
</section>
<section id="changelog">
<h2>Changelog</h2>
<div class="anchor" id="2.2.4"></div>
<h2 class="header">
<a href="https://github.com/jashkenas/coffeescript/compare/2.2.3...2.2.4">2.2.4</a>
<span class="timestamp"> &mdash; <time datetime="2018-03-29">March 29, 2018</time></span>
</h2><ul>
<li>When the <code>by</code> value in a <code>for</code> loop is a literal number, e.g. <code>for x in [2..1] by -1</code>, fewer checks are necessary to determine if the loop is in range.</li>
<li>Bugfix for regression in 2.2.0 where a statement inside parentheses, e.g. <code>(fn(); break) while condition</code>, was compiling. Pure statements like <code>break</code> or <code>return</code> cannot turn a parenthesized block into an expression, and should throw an error.</li>
</ul>
<div class="anchor" id="2.2.3"></div>
<h2 class="header">
<a href="https://github.com/jashkenas/coffeescript/compare/2.2.2...2.2.3">2.2.3</a>
<span class="timestamp"> &mdash; <time datetime="2018-03-11">March 11, 2018</time></span>
</h2><ul>
<li>Bugfix for object destructuring with an empty array as a keys value: <code>{ key: [] } = obj</code>.</li>
<li>Bugfix for array destructuring onto targets attached to <code>this</code>: <code>[ @most... , @penultimate, @last ] = arr</code>.</li>
</ul>
<div class="anchor" id="2.2.2"></div>
<h2 class="header">
<a href="https://github.com/jashkenas/coffeescript/compare/2.2.1...2.2.2">2.2.2</a>
<span class="timestamp"> &mdash; <time datetime="2018-02-21">February 21, 2018</time></span>
</h2><ul>
<li>Bugfix for regression in 2.2.0 where a range with a <code>by</code> (step) value that increments or decrements in the opposite direction as the range was returning an array containing the first value of the range, whereas it should be returning an empty array. In other words, <code>x for x in [2..1] by 1</code> should equal <code>[]</code>, not <code>[2]</code> (because the step value is positive 1, counting up, whereas the range goes from 2 to 1, counting down).</li>
<li>Bugfixes for allowing backslashes in <code>import</code> and <code>export</code> statements and lines that trigger the start of an indented block, like an <code>if</code> statement.</li>
</ul>
<div class="anchor" id="2.2.1"></div>
<h2 class="header">
<a href="https://github.com/jashkenas/coffeescript/compare/2.2.0...2.2.1">2.2.1</a>
<span class="timestamp"> &mdash; <time datetime="2018-02-06">February 6, 2018</time></span>
</h2><ul>
<li>Bugfix for regression in 2.2.0 involving an error thrown by the compiler in certain cases when using destructuring with a splat or expansion in an array.</li>
<li>Bugfix for regression in 2.2.0 where in certain cases a range iterator variable was declared in the global scope.</li>
</ul>
<div class="anchor" id="2.2.0"></div>
<h2 class="header">
<a href="https://github.com/jashkenas/coffeescript/compare/2.1.1...2.2.0">2.2.0</a>

View File

@@ -1573,13 +1573,101 @@ test "#4673: complex destructured object spread variables", ->
{{g}...} = g: 1
eq g, 1
test "#4878: Compile error when using destructuring with a splat or expansion in an array", ->
arr = ['a', 'b', 'c', 'd']
f1 = (list) ->
[first, ..., last] = list
f2 = (list) ->
[first..., last] = list
f3 = (list) ->
([first, ...] = list); first
f4 = (list) ->
([first, rest...] = list); rest
arrayEq f1(arr), arr
arrayEq f2(arr), arr
arrayEq f3(arr), 'a'
arrayEq f4(arr), ['b', 'c', 'd']
foo = (list) ->
ret =
if list?.length > 0
[first, ..., last] = list
[first, last]
else
[]
arrayEq foo(arr), ['a', 'd']
bar = (list) ->
ret =
if list?.length > 0
[first, rest...] = list
[first, rest]
else
[]
arrayEq bar(arr), ['a', ['b', 'c', 'd']]
test "destructuring assignment with an empty array in object", ->
obj =
a1: [1, 2]
b1: 3
{a1:[], b1} = obj
eq 'undefined', typeof a1
eq b1, 3
obj =
a2:
b2: [1, 2]
c2: 3
{a2: {b2:[]}, c2} = obj
eq 'undefined', typeof b2
eq c2, 3
test "#5004: array destructuring with accessors", ->
obj =
arr: ['a', 'b', 'c', 'd']
list: {}
f1: ->
[@first, @rest...] = @arr
f2: ->
[@second, @third..., @last] = @rest
f3: ->
[@list.a, @list.middle..., @list.d] = @arr
obj.f1()
eq obj.first, 'a'
arrayEq obj.rest, ['b', 'c', 'd']
obj.f2()
eq obj.second, 'b'
arrayEq obj.third, ['c']
eq obj.last, 'd'
obj.f3()
eq obj.list.a, 'a'
arrayEq obj.list.middle, ['b', 'c']
eq obj.list.d, 'd'
[obj.list.middle..., d] = obj.arr
eq d, 'd'
arrayEq obj.list.middle, ['a', 'b', 'c']
</script>
<script type="text/x-coffeescript" class="test" id="async">
# 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
# But runtimes that dont support the `await` keyword will throw an error just
# from parsing this file, even without executing it, even if we put
# `return unless try new Function 'async () => {}'` at the top of this file.
# Therefore we need to prevent runtimes which will choke on such code from
# parsing it, which is handled in `Cakefile`.
@@ -2067,6 +2155,7 @@ test "classes with value'd constructors", ->
inner = ++counter
->
@value = inner
@
class One
constructor: classMaker()
@@ -6721,37 +6810,6 @@ test "#3921: `switch`", ->
else "none"
eq "five", c
# Issue #3441: Parentheses wrapping expression throw invalid error in `then` clause
test "#3441: `StatementLiteral` in parentheses", ->
i = 0
r1 = ((i++; break) while i < 10)
arrayEq r1, []
i = 0
r2 = ((i++; continue) while i < 10)
arrayEq r2, []
i = 0
r4 = while i < 10 then (i++; break)
arrayEq r4, []
i = 0
r5 = while i < 10 then (i++; continue)
arrayEq r5, []
arr = [0..9]
r6 = ((a; break) for a in arr)
arrayEq r6, []
r7 = ((a; continue) for a in arr)
arrayEq r7, []
r8 = for a in arr then (a; break)
arrayEq r8, []
r9 = for a in arr then (a; continue)
arrayEq r9, []
# Issue #3909: backslash to break line in `for` loops throw syntax error
test "#3909: backslash `for own ... of`", ->
@@ -6897,6 +6955,59 @@ test "#4871: `else if` no longer output together ", ->
}
'''
test "#4898: Lexer: backslash line continuation is inconsistent", ->
if ( \
false \
or \
true \
)
a = 42
eq a, 42
if ( \
false \
or \
true \
)
b = 42
eq b, 42
if ( \
false \
or \
true \
)
c = 42
eq c, 42
if \
false \
or \
true
d = 42
eq d, 42
if \
false or \
true
e = 42
eq e, 42
if \
false or \
true \
then \
f = 42 \
else
f = 24
eq f, 42
</script>
<script type="text/x-coffeescript" class="test" id="csx">
# We usually do not check the actual JS output from the compiler, but since
@@ -8654,6 +8765,42 @@ test "#4097: `yield return` as an expression", ->
^^^^^^^^^^^^
'''
test "#5013: `await return` as an expression", ->
assertErrorFormat '''
-> (await return)
''', '''
[stdin]:1:5: error: cannot use a pure statement in an expression
-> (await return)
^^^^^^^^^^^^
'''
test "#5013: `return` as an expression", ->
assertErrorFormat '''
-> (return)
''', '''
[stdin]:1:5: error: cannot use a pure statement in an expression
-> (return)
^^^^^^
'''
test "#5013: `break` as an expression", ->
assertErrorFormat '''
(b = 1; break) for b in a
''', '''
[stdin]:1:9: error: cannot use a pure statement in an expression
(b = 1; break) for b in a
^^^^^
'''
test "#5013: `continue` as an expression", ->
assertErrorFormat '''
(b = 1; continue) for b in a
''', '''
[stdin]:1:9: error: cannot use a pure statement in an expression
(b = 1; continue) for b in a
^^^^^^^^
'''
test "`&&=` and `||=` with a space in-between", ->
assertErrorFormat '''
a = 0
@@ -14329,6 +14476,73 @@ test "#4491: import- and export-specific lexing should stop after import/export
from('foo');
"""
# Issue #4874: Backslash not supported in import or export statements
test "#4874: backslash `import`", ->
eqJS """
import foo \
from 'lib'
foo a
""",
"""
import foo from 'lib';
foo(a);
"""
eqJS """
import \
foo \
from \
'lib'
foo a
""",
"""
import foo from 'lib';
foo(a);
"""
eqJS """
import \
utilityBelt \
, {
each
} from \
'underscore'
""",
"""
import utilityBelt, {
each
} from 'underscore';
"""
test "#4874: backslash `export`", ->
eqJS """
export \
* \
from \
'underscore'
""",
"""
export * from 'underscore';
"""
eqJS """
export \
{ max, min } \
from \
'underscore'
""",
"""
export {
max,
min
} from 'underscore';
"""
</script>
<script type="text/x-coffeescript" class="test" id="numbers">
# Number Literals
@@ -16107,43 +16321,43 @@ test "#2047: Infinite loop possible when `for` loop with `range` uses variables"
testData = [
[1, 5, 1, [1..5]]
[1, 5, -1, [1]]
[1, 5, -1, []]
[1, 5, up, [1..5]]
[1, 5, down, [1]]
[1, 5, down, []]
[a, 5, 1, [1..5]]
[a, 5, -1, [1]]
[a, 5, -1, []]
[a, 5, up, [1..5]]
[a, 5, down, [1]]
[a, 5, down, []]
[1, b, 1, [1..5]]
[1, b, -1, [1]]
[1, b, -1, []]
[1, b, up, [1..5]]
[1, b, down, [1]]
[1, b, down, []]
[a, b, 1, [1..5]]
[a, b, -1, [1]]
[a, b, -1, []]
[a, b, up, [1..5]]
[a, b, down, [1]]
[a, b, down, []]
[5, 1, 1, [5]]
[5, 1, 1, []]
[5, 1, -1, [5..1]]
[5, 1, up, [5]]
[5, 1, up, []]
[5, 1, down, [5..1]]
[5, a, 1, [5]]
[5, a, 1, []]
[5, a, -1, [5..1]]
[5, a, up, [5]]
[5, a, up, []]
[5, a, down, [5..1]]
[b, 1, 1, [5]]
[b, 1, 1, []]
[b, 1, -1, [5..1]]
[b, 1, up, [5]]
[b, 1, up, []]
[b, 1, down, [5..1]]
[b, a, 1, [5]]
[b, a, 1, []]
[b, a, -1, [5..1]]
[b, a, up, [5]]
[b, a, up, []]
[b, a, down, [5..1]]
]
@@ -16159,10 +16373,10 @@ test "#2047: from, to and step as variables", ->
arrayEq r, [1..5]
r = (x for x in [a..b] by down)
arrayEq r, [1]
arrayEq r, []
r = (x for x in [b..a] by up)
arrayEq r, [5]
arrayEq r, []
r = (x for x in [b..a] by down)
arrayEq r, [5..1]
@@ -16173,6 +16387,53 @@ test "#2047: from, to and step as variables", ->
r = (x for x in [b..a] by step)
arrayEq r, []
test "#4884: Range not declaring var for the 'i'", ->
'use strict'
[0..21].forEach (idx) ->
idx + 1
eq global.i, undefined
test "#4889: `for` loop unexpected behavior", ->
n = 1
result = []
for i in [0..n]
result.push i
for j in [(i+1)..n]
result.push j
arrayEq result, [0,1,1,2,1]
test "#4889: `for` loop unexpected behavior with `by 1` on second loop", ->
n = 1
result = []
for i in [0..n]
result.push i
for j in [(i+1)..n] by 1
result.push j
arrayEq result, [0,1,1]
test "countdown example from docs", ->
countdown = (num for num in [10..1])
arrayEq countdown, [10,9,8,7,6,5,4,3,2,1]
test "counting up when the range goes down returns an empty array", ->
countdown = (num for num in [10..1] by 1)
arrayEq countdown, []
test "counting down when the range goes up returns an empty array", ->
countup = (num for num in [1..10] by -1)
arrayEq countup, []
test "counting down by too much returns just the first value", ->
countdown = (num for num in [10..1] by -100)
arrayEq countdown, [10]
test "counting up by too much returns just the first value", ->
countup = (num for num in [1..10] by 100)
arrayEq countup, [1]
</script>
<script type="text/x-coffeescript" class="test" id="regexps">
# Regular Expression Literals
@@ -16632,7 +16893,7 @@ testRepl "keeps running after runtime error", (input, output) ->
eq 'undefined', output.lastWrite()
testRepl "#4604: wraps an async function", (input, output) ->
return unless global.supportsAsync
return unless try new Function 'async () => {}' # Feature detect support for async functions.
input.emitLine 'await new Promise (resolve) -> setTimeout (-> resolve 33), 10'
setTimeout ->
eq '33', output.lastWrite()

View File

@@ -6,4 +6,4 @@ Object.defineProperty screen, 'height',
get: ->
this.width / this.ratio
set: (val) ->
this.width = val / this.ratio
this.width = val * this.ratio

View File

@@ -1,5 +1,29 @@
## Changelog
```
releaseHeader('2018-03-29', '2.2.4', '2.2.3')
```
* When the `by` value in a `for` loop is a literal number, e.g. `for x in [2..1] by -1`, fewer checks are necessary to determine if the loop is in range.
* Bugfix for regression in 2.2.0 where a statement inside parentheses, e.g. `(fn(); break) while condition`, was compiling. Pure statements like `break` or `return` cannot turn a parenthesized block into an expression, and should throw an error.
```
releaseHeader('2018-03-11', '2.2.3', '2.2.2')
```
* Bugfix for object destructuring with an empty array as a keys value: `{ key: [] } = obj`.
* Bugfix for array destructuring onto targets attached to `this`: `[ @most... , @penultimate, @last ] = arr`.
```
releaseHeader('2018-02-21', '2.2.2', '2.2.1')
```
* Bugfix for regression in 2.2.0 where a range with a `by` (step) value that increments or decrements in the opposite direction as the range was returning an array containing the first value of the range, whereas it should be returning an empty array. In other words, `x for x in [2..1] by 1` should equal `[]`, not `[2]` (because the step value is positive 1, counting up, whereas the range goes from 2 to 1, counting down).
* Bugfixes for allowing backslashes in `import` and `export` statements and lines that trigger the start of an indented block, like an `if` statement.
```
releaseHeader('2018-02-06', '2.2.1', '2.2.0')
```
* Bugfix for regression in 2.2.0 involving an error thrown by the compiler in certain cases when using destructuring with a splat or expansion in an array.
* Bugfix for regression in 2.2.0 where in certain cases a range iterator variable was declared in the global scope.
```
releaseHeader('2018-02-01', '2.2.0', '2.1.1')
```

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.4
(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.2.0
// Generated by CoffeeScript 2.2.4
(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,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.4
(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

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.4
(function() {
// The `coffee` utility. Handles command-line compilation of CoffeeScript
// into various forms: saved into `.js` files or printed to stdout

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.4
(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

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.4
(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.2.0
// Generated by CoffeeScript 2.2.4
(function() {
// Node.js Implementation
var CoffeeScript, ext, fs, helpers, i, len, path, ref, universalCompile, vm,

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.4
(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,
@@ -593,14 +593,14 @@
}
indent = match[0];
prev = this.prev();
backslash = (prev != null) && prev[0] === '\\';
backslash = (prev != null ? prev[0] : void 0) === '\\';
if (!(backslash && this.seenFor)) {
this.seenFor = false;
}
if (!this.importSpecifierList) {
if (!((backslash && this.seenImport) || this.importSpecifierList)) {
this.seenImport = false;
}
if (!this.exportSpecifierList) {
if (!((backslash && this.seenExport) || this.exportSpecifierList)) {
this.seenExport = false;
}
size = indent.length - 1 - indent.lastIndexOf('\n');
@@ -629,7 +629,9 @@
}
if (size > this.indent) {
if (noNewlines) {
this.indebt = size - this.indent;
if (!backslash) {
this.indebt = size - this.indent;
}
this.suppressNewlines();
return indent.length;
}

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.4
(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),
@@ -1267,15 +1267,6 @@
if (!props && base instanceof Value) {
return base;
}
if (base instanceof Parens && base.contains(function(n) {
return n instanceof StatementLiteral;
})) {
// When `Parens` block includes a `StatementLiteral` (e.g. `(b; break) for a in arr`),
// it won't compile since `Parens` (`(b; break)`) is compiled as `Value` and
// pure statement (`break`) can't be used in an expression.
// For this reasons, we return `Block` instead of `Parens`.
return base.unwrap();
}
this.base = base;
this.properties = props || [];
if (tag) {
@@ -2031,7 +2022,7 @@
// When compiled normally, the range returns the contents of the *for loop*
// needed to iterate over the values in the range. Used by comprehensions.
compileNode(o) {
var cond, condPart, from, gt, idx, idxName, known, lowerBound, lt, namedIndex, stepCond, stepPart, to, upperBound, varPart;
var cond, condPart, from, gt, idx, idxName, known, lowerBound, lt, namedIndex, ref1, ref2, stepCond, stepNotZero, stepPart, to, upperBound, varPart;
if (!this.fromVar) {
this.compileVariables(o);
}
@@ -2043,7 +2034,7 @@
idx = del(o, 'index');
idxName = del(o, 'name');
namedIndex = idxName && idxName !== idx;
varPart = `${idx} = ${this.fromC}`;
varPart = known && !namedIndex ? `var ${idx} = ${this.fromC}` : `${idx} = ${this.fromC}`;
if (this.toC !== this.toVar) {
varPart += `, ${this.toC}`;
}
@@ -2054,12 +2045,11 @@
// Generate the condition.
[from, to] = [this.fromNum, this.toNum];
// Always check if the `step` isn't zero to avoid the infinite loop.
stepCond = this.stepNum ? `${this.stepNum} !== 0` : `${this.stepVar} !== 0`;
condPart = known ? this.step == null ? from <= to ? `${lt} ${to}` : `${gt} ${ // from < to
to}` : (lowerBound = `${from} <= ${idx} && ${lt} ${// from > to
to}`, upperBound = `${from} >= ${idx} && ${gt} ${to}`, from <= to ? `${stepCond} && ${lowerBound}` : `${stepCond} && ${// from < to
upperBound}`) : (lowerBound = `${this.fromVar} <= ${idx} && ${lt} ${// from > to
this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `${stepCond} && (${this.fromVar} <= ${this.toVar} ? ${lowerBound} : ${upperBound})`);
stepNotZero = `${(ref1 = this.stepNum) != null ? ref1 : this.stepVar} !== 0`;
stepCond = `${(ref2 = this.stepNum) != null ? ref2 : this.stepVar} > 0`;
lowerBound = `${lt} ${(known ? to : this.toVar)}`;
upperBound = `${gt} ${(known ? to : this.toVar)}`;
condPart = this.step != null ? (this.stepNum != null) && this.stepNum !== 0 ? this.stepNum > 0 ? `${lowerBound}` : `${upperBound}` : `${stepNotZero} && (${stepCond} ? ${lowerBound} : ${upperBound})` : known ? `${(from <= to ? lt : gt)} ${to}` : `(${this.fromVar} <= ${this.toVar} ? ${lowerBound} : ${upperBound})`;
cond = this.stepVar ? `${this.stepVar} > 0` : `${this.fromVar} <= ${this.toVar}`;
// Generate the step.
stepPart = this.stepVar ? `${idx} += ${this.stepVar}` : known ? namedIndex ? from <= to ? `++${idx}` : `--${idx}` : from <= to ? `${idx}++` : `${idx}--` : namedIndex ? `${cond} ? ++${idx} : --${idx}` : `${cond} ? ${idx}++ : ${idx}--`;
@@ -2180,7 +2170,7 @@ this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `
}
isAssignable() {
var j, len1, message, prop, ref1;
var j, len1, message, prop, ref1, ref2;
ref1 = this.properties;
for (j = 0, len1 = ref1.length; j < len1; j++) {
prop = ref1[j];
@@ -2189,7 +2179,7 @@ this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `
if (message) {
prop.error(message);
}
if (prop instanceof Assign && prop.context === 'object') {
if (prop instanceof Assign && prop.context === 'object' && !(((ref2 = prop.value) != null ? ref2.base : void 0) instanceof Arr)) {
prop = prop.value;
}
if (!prop.isAssignable()) {
@@ -3575,8 +3565,8 @@ this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `
// Sort 'splatsAndExpans' so we can show error at first disallowed token.
objects[splatsAndExpans.sort()[1]].error("multiple splats/expansions are disallowed in an assignment");
}
isSplat = splats.length;
isExpans = expans.length;
isSplat = (splats != null ? splats.length : void 0) > 0;
isExpans = (expans != null ? expans.length : void 0) > 0;
isObject = this.variable.isObject();
isArray = this.variable.isArray();
vvar = value.compileToFragments(o, LEVEL_LIST);
@@ -3594,7 +3584,10 @@ this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `
slicer = function(type) {
return function(vvar, start, end = false) {
var args, slice;
args = [new IdentifierLiteral(vvar), new NumberLiteral(start)];
if (!(vvar instanceof Value)) {
vvar = new IdentifierLiteral(vvar);
}
args = [vvar, new NumberLiteral(start)];
if (end) {
args.push(new NumberLiteral(end));
}
@@ -3648,7 +3641,7 @@ this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `
};
// "Complex" `objects` are processed in a loop.
// Examples: [a, b, {c, r...}, d], [a, ..., {b, r...}, c, d]
loopObjects = (objs, vvarTxt) => {
loopObjects = (objs, vvar, vvarTxt) => {
var acc, idx, j, len1, message, objSpreads, results, vval;
objSpreads = hasObjSpreads(objs);
results = [];
@@ -3707,7 +3700,7 @@ this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `
return results;
};
// "Simple" `objects` can be split and compiled to arrays, [a, b, c] = arr, [a, b, c...] = arr
assignObjects = (objs, vvarTxt) => {
assignObjects = (objs, vvar, vvarTxt) => {
var vval;
vvar = new Value(new Arr(objs, true));
vval = vvarTxt instanceof Value ? vvarTxt : new Value(new Literal(vvarTxt));
@@ -3716,11 +3709,11 @@ this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `
subpattern: true
}).compileToFragments(o, LEVEL_LIST));
};
processObjects = function(objs, vvarTxt) {
processObjects = function(objs, vvar, vvarTxt) {
if (complexObjects(objs)) {
return loopObjects(objs, vvarTxt);
return loopObjects(objs, vvar, vvarTxt);
} else {
return assignObjects(objs, vvarTxt);
return assignObjects(objs, vvar, vvarTxt);
}
};
// In case there is `Splat` or `Expansion` in `objects`,
@@ -3739,14 +3732,14 @@ this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `
leftObjs = objects.slice(0, expIdx + (isSplat ? 1 : 0));
rightObjs = objects.slice(expIdx + 1);
if (leftObjs.length !== 0) {
processObjects(leftObjs, vvarText);
processObjects(leftObjs, vvar, vvarText);
}
if (rightObjs.length !== 0) {
// Slice or splice `objects`.
refExp = (function() {
switch (false) {
case !isSplat:
return compSplice(objects[expIdx].unwrapAll().value, rightObjs.length * -1);
return compSplice(new Value(objects[expIdx].name), rightObjs.length * -1);
case !isExpans:
return compSlice(vvarText, rightObjs.length * -1);
}
@@ -3756,11 +3749,11 @@ this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `
refExp = o.scope.freeVariable('ref');
assigns.push([this.makeCode(refExp + ' = '), ...restVar.compileToFragments(o, LEVEL_LIST)]);
}
processObjects(rightObjs, refExp);
processObjects(rightObjs, vvar, refExp);
}
} else {
// There is no `Splat` or `Expansion` in `objects`.
processObjects(objects, vvarText);
processObjects(objects, vvar, vvarText);
}
if (!(top || this.subpattern)) {
assigns.push(vvar);

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.4
(function() {
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments, repeat,
splice = [].splice;

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.4
(function() {
var CoffeeScript, Module, binary, child_process, ext, findExtension, fork, getRootModule, helpers, i, len, loadFile, path, ref;

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.4
(function() {
var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, replDefaults, runInContext, sawSIGINT, transpile, updateSyntaxError, vm;

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.4
(function() {
// The CoffeeScript language has a good deal of optional syntax, implicit syntax,
// and shorthand syntax. This can greatly complicate a grammar and bloat
@@ -218,7 +218,7 @@
indexOfTag(i, ...pattern) {
var fuzz, j, k, ref, ref1;
fuzz = 0;
for (j = k = 0, ref = pattern.length; undefined !== 0 && (0 <= ref ? 0 <= k && k < ref : 0 >= k && k > ref); j = 0 <= ref ? ++k : --k) {
for (j = k = 0, ref = pattern.length; (0 <= ref ? k < ref : k > ref); j = 0 <= ref ? ++k : --k) {
if (pattern[j] == null) {
continue;
}

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.4
(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.2.0
// Generated by CoffeeScript 2.2.4
(function() {
// Source maps allow JavaScript runtimes to match running JavaScript back to
// the original source code that corresponds to it. This can be minified

2766
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@
"compiler"
],
"author": "Jeremy Ashkenas",
"version": "2.2.0",
"version": "2.2.4",
"license": "MIT",
"engines": {
"node": ">=6"
@@ -43,13 +43,13 @@
"babel-preset-babili": "~0.1.4",
"babel-preset-env": "~1.6.1",
"babel-preset-minify": "^0.3.0",
"codemirror": "^5.32.0",
"codemirror": "^5.35.0",
"docco": "~0.8.0",
"highlight.js": "~9.12.0",
"jison": ">=0.4.18",
"markdown-it": "~8.4.0",
"markdown-it": "~8.4.1",
"underscore": "~1.8.3",
"webpack": "~3.10.0"
"webpack": "~4.1.1"
},
"dependencies": {}
}

View File

@@ -454,10 +454,10 @@ exports.Lexer = class Lexer
indent = match[0]
prev = @prev()
backslash = prev? and prev[0] is '\\'
backslash = prev?[0] is '\\'
@seenFor = no unless backslash and @seenFor
@seenImport = no unless @importSpecifierList
@seenExport = no unless @exportSpecifierList
@seenImport = no unless (backslash and @seenImport) or @importSpecifierList
@seenExport = no unless (backslash and @seenExport) or @exportSpecifierList
size = indent.length - 1 - indent.lastIndexOf '\n'
noNewlines = @unfinished()
@@ -478,7 +478,7 @@ exports.Lexer = class Lexer
if size > @indent
if noNewlines
@indebt = size - @indent
@indebt = size - @indent unless backslash
@suppressNewlines()
return indent.length
unless @tokens.length

View File

@@ -863,11 +863,6 @@ exports.Value = class Value extends Base
constructor: (base, props, tag, isDefaultValue = no) ->
super()
return base if not props and base instanceof Value
# When `Parens` block includes a `StatementLiteral` (e.g. `(b; break) for a in arr`),
# it won't compile since `Parens` (`(b; break)`) is compiled as `Value` and
# pure statement (`break`) can't be used in an expression.
# For this reasons, we return `Block` instead of `Parens`.
return base.unwrap() if base instanceof Parens and base.contains (n) -> n instanceof StatementLiteral
@base = base
@properties = props or []
@[tag] = yes if tag
@@ -1353,7 +1348,11 @@ exports.Range = class Range extends Base
idx = del o, 'index'
idxName = del o, 'name'
namedIndex = idxName and idxName isnt idx
varPart = "#{idx} = #{@fromC}"
varPart =
if known and not namedIndex
"var #{idx} = #{@fromC}"
else
"#{idx} = #{@fromC}"
varPart += ", #{@toC}" if @toC isnt @toVar
varPart += ", #{@step}" if @step isnt @stepVar
[lt, gt] = ["#{idx} <#{@equals}", "#{idx} >#{@equals}"]
@@ -1361,23 +1360,21 @@ exports.Range = class Range extends Base
# Generate the condition.
[from, to] = [@fromNum, @toNum]
# Always check if the `step` isn't zero to avoid the infinite loop.
stepCond = if @stepNum then "#{@stepNum} !== 0" else "#{@stepVar} !== 0"
stepNotZero = "#{ @stepNum ? @stepVar } !== 0"
stepCond = "#{ @stepNum ? @stepVar } > 0"
lowerBound = "#{lt} #{ if known then to else @toVar }"
upperBound = "#{gt} #{ if known then to else @toVar }"
condPart =
if known
unless @step?
if from <= to then "#{lt} #{to}" else "#{gt} #{to}"
if @step?
if @stepNum? and @stepNum isnt 0
if @stepNum > 0 then "#{lowerBound}" else "#{upperBound}"
else
# from < to
lowerBound = "#{from} <= #{idx} && #{lt} #{to}"
# from > to
upperBound = "#{from} >= #{idx} && #{gt} #{to}"
if from <= to then "#{stepCond} && #{lowerBound}" else "#{stepCond} && #{upperBound}"
"#{stepNotZero} && (#{stepCond} ? #{lowerBound} : #{upperBound})"
else
# from < to
lowerBound = "#{@fromVar} <= #{idx} && #{lt} #{@toVar}"
# from > to
upperBound = "#{@fromVar} >= #{idx} && #{gt} #{@toVar}"
"#{stepCond} && (#{@fromVar} <= #{@toVar} ? #{lowerBound} : #{upperBound})"
if known
"#{ if from <= to then lt else gt } #{to}"
else
"(#{@fromVar} <= #{@toVar} ? #{lowerBound} : #{upperBound})"
cond = if @stepVar then "#{@stepVar} > 0" else "#{@fromVar} <= #{@toVar}"
@@ -1478,7 +1475,9 @@ exports.Obj = class Obj extends Base
message = isUnassignable prop.unwrapAll().value
prop.error message if message
prop = prop.value if prop instanceof Assign and prop.context is 'object'
prop = prop.value if prop instanceof Assign and
prop.context is 'object' and
prop.value?.base not instanceof Arr
return no unless prop.isAssignable()
yes
@@ -2408,8 +2407,8 @@ exports.Assign = class Assign extends Base
# Sort 'splatsAndExpans' so we can show error at first disallowed token.
objects[splatsAndExpans.sort()[1]].error "multiple splats/expansions are disallowed in an assignment"
isSplat = splats.length
isExpans = expans.length
isSplat = splats?.length > 0
isExpans = expans?.length > 0
isObject = @variable.isObject()
isArray = @variable.isArray()
@@ -2427,7 +2426,8 @@ exports.Assign = class Assign extends Base
vvarText = ref
slicer = (type) -> (vvar, start, end = no) ->
args = [new IdentifierLiteral(vvar), new NumberLiteral(start)]
vvar = new IdentifierLiteral vvar unless vvar instanceof Value
args = [vvar, new NumberLiteral(start)]
args.push new NumberLiteral end if end
slice = new Value (new IdentifierLiteral utility type, o), [new Access new PropertyName 'call']
new Value new Call slice, args
@@ -2458,7 +2458,7 @@ exports.Assign = class Assign extends Base
# "Complex" `objects` are processed in a loop.
# Examples: [a, b, {c, r...}, d], [a, ..., {b, r...}, c, d]
loopObjects = (objs, vvarTxt) =>
loopObjects = (objs, vvar, vvarTxt) =>
objSpreads = hasObjSpreads objs
for obj, i in objs
# `Elision` can be skipped.
@@ -2488,16 +2488,16 @@ exports.Assign = class Assign extends Base
assigns.push new Assign(vvar, vval, null, param: @param, subpattern: yes).compileToFragments o, LEVEL_LIST
# "Simple" `objects` can be split and compiled to arrays, [a, b, c] = arr, [a, b, c...] = arr
assignObjects = (objs, vvarTxt) =>
assignObjects = (objs, vvar, vvarTxt) =>
vvar = new Value new Arr(objs, yes)
vval = if vvarTxt instanceof Value then vvarTxt else new Value new Literal(vvarTxt)
assigns.push new Assign(vvar, vval, null, param: @param, subpattern: yes).compileToFragments o, LEVEL_LIST
processObjects = (objs, vvarTxt) ->
processObjects = (objs, vvar, vvarTxt) ->
if complexObjects objs
loopObjects objs, vvarTxt
loopObjects objs, vvar, vvarTxt
else
assignObjects objs, vvarTxt
assignObjects objs, vvar, vvarTxt
# In case there is `Splat` or `Expansion` in `objects`,
# we can split array in two simple subarrays.
@@ -2514,20 +2514,20 @@ exports.Assign = class Assign extends Base
expIdx = splatsAndExpans[0]
leftObjs = objects.slice 0, expIdx + (if isSplat then 1 else 0)
rightObjs = objects.slice expIdx + 1
processObjects leftObjs, vvarText if leftObjs.length isnt 0
processObjects leftObjs, vvar, vvarText if leftObjs.length isnt 0
if rightObjs.length isnt 0
# Slice or splice `objects`.
refExp = switch
when isSplat then compSplice objects[expIdx].unwrapAll().value, rightObjs.length * -1
when isSplat then compSplice new Value(objects[expIdx].name), rightObjs.length * -1
when isExpans then compSlice vvarText, rightObjs.length * -1
if complexObjects rightObjs
restVar = refExp
refExp = o.scope.freeVariable 'ref'
assigns.push [@makeCode(refExp + ' = '), restVar.compileToFragments(o, LEVEL_LIST)...]
processObjects rightObjs, refExp
processObjects rightObjs, vvar, refExp
else
# There is no `Splat` or `Expansion` in `objects`.
processObjects objects, vvarText
processObjects objects, vvar, vvarText
assigns.push vvar unless top or @subpattern
fragments = @joinFragmentArrays assigns, ', '
if o.level < LEVEL_LIST then fragments else @wrapInParentheses fragments

View File

@@ -945,3 +945,90 @@ test "#4673: complex destructured object spread variables", ->
{{g}...} = g: 1
eq g, 1
test "#4878: Compile error when using destructuring with a splat or expansion in an array", ->
arr = ['a', 'b', 'c', 'd']
f1 = (list) ->
[first, ..., last] = list
f2 = (list) ->
[first..., last] = list
f3 = (list) ->
([first, ...] = list); first
f4 = (list) ->
([first, rest...] = list); rest
arrayEq f1(arr), arr
arrayEq f2(arr), arr
arrayEq f3(arr), 'a'
arrayEq f4(arr), ['b', 'c', 'd']
foo = (list) ->
ret =
if list?.length > 0
[first, ..., last] = list
[first, last]
else
[]
arrayEq foo(arr), ['a', 'd']
bar = (list) ->
ret =
if list?.length > 0
[first, rest...] = list
[first, rest]
else
[]
arrayEq bar(arr), ['a', ['b', 'c', 'd']]
test "destructuring assignment with an empty array in object", ->
obj =
a1: [1, 2]
b1: 3
{a1:[], b1} = obj
eq 'undefined', typeof a1
eq b1, 3
obj =
a2:
b2: [1, 2]
c2: 3
{a2: {b2:[]}, c2} = obj
eq 'undefined', typeof b2
eq c2, 3
test "#5004: array destructuring with accessors", ->
obj =
arr: ['a', 'b', 'c', 'd']
list: {}
f1: ->
[@first, @rest...] = @arr
f2: ->
[@second, @third..., @last] = @rest
f3: ->
[@list.a, @list.middle..., @list.d] = @arr
obj.f1()
eq obj.first, 'a'
arrayEq obj.rest, ['b', 'c', 'd']
obj.f2()
eq obj.second, 'b'
arrayEq obj.third, ['c']
eq obj.last, 'd'
obj.f3()
eq obj.list.a, 'a'
arrayEq obj.list.middle, ['b', 'c']
eq obj.list.d, 'd'
[obj.list.middle..., d] = obj.arr
eq d, 'd'
arrayEq obj.list.middle, ['a', 'b', 'c']

View File

@@ -1,8 +1,9 @@
# 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
# But runtimes that dont support the `await` keyword will throw an error just
# from parsing this file, even without executing it, even if we put
# `return unless try new Function 'async () => {}'` at the top of this file.
# Therefore we need to prevent runtimes which will choke on such code from
# parsing it, which is handled in `Cakefile`.

View File

@@ -266,6 +266,7 @@ test "classes with value'd constructors", ->
inner = ++counter
->
@value = inner
@
class One
constructor: classMaker()

View File

@@ -1112,37 +1112,6 @@ test "#3921: `switch`", ->
else "none"
eq "five", c
# Issue #3441: Parentheses wrapping expression throw invalid error in `then` clause
test "#3441: `StatementLiteral` in parentheses", ->
i = 0
r1 = ((i++; break) while i < 10)
arrayEq r1, []
i = 0
r2 = ((i++; continue) while i < 10)
arrayEq r2, []
i = 0
r4 = while i < 10 then (i++; break)
arrayEq r4, []
i = 0
r5 = while i < 10 then (i++; continue)
arrayEq r5, []
arr = [0..9]
r6 = ((a; break) for a in arr)
arrayEq r6, []
r7 = ((a; continue) for a in arr)
arrayEq r7, []
r8 = for a in arr then (a; break)
arrayEq r8, []
r9 = for a in arr then (a; continue)
arrayEq r9, []
# Issue #3909: backslash to break line in `for` loops throw syntax error
test "#3909: backslash `for own ... of`", ->
@@ -1287,3 +1256,56 @@ test "#4871: `else if` no longer output together ", ->
2;
}
'''
test "#4898: Lexer: backslash line continuation is inconsistent", ->
if ( \
false \
or \
true \
)
a = 42
eq a, 42
if ( \
false \
or \
true \
)
b = 42
eq b, 42
if ( \
false \
or \
true \
)
c = 42
eq c, 42
if \
false \
or \
true
d = 42
eq d, 42
if \
false or \
true
e = 42
eq e, 42
if \
false or \
true \
then \
f = 42 \
else
f = 24
eq f, 42

View File

@@ -962,6 +962,42 @@ test "#4097: `yield return` as an expression", ->
^^^^^^^^^^^^
'''
test "#5013: `await return` as an expression", ->
assertErrorFormat '''
-> (await return)
''', '''
[stdin]:1:5: error: cannot use a pure statement in an expression
-> (await return)
^^^^^^^^^^^^
'''
test "#5013: `return` as an expression", ->
assertErrorFormat '''
-> (return)
''', '''
[stdin]:1:5: error: cannot use a pure statement in an expression
-> (return)
^^^^^^
'''
test "#5013: `break` as an expression", ->
assertErrorFormat '''
(b = 1; break) for b in a
''', '''
[stdin]:1:9: error: cannot use a pure statement in an expression
(b = 1; break) for b in a
^^^^^
'''
test "#5013: `continue` as an expression", ->
assertErrorFormat '''
(b = 1; continue) for b in a
''', '''
[stdin]:1:9: error: cannot use a pure statement in an expression
(b = 1; continue) for b in a
^^^^^^^^
'''
test "`&&=` and `||=` with a space in-between", ->
assertErrorFormat '''
a = 0

View File

@@ -853,3 +853,70 @@ test "#4491: import- and export-specific lexing should stop after import/export
from('foo');
"""
# Issue #4874: Backslash not supported in import or export statements
test "#4874: backslash `import`", ->
eqJS """
import foo \
from 'lib'
foo a
""",
"""
import foo from 'lib';
foo(a);
"""
eqJS """
import \
foo \
from \
'lib'
foo a
""",
"""
import foo from 'lib';
foo(a);
"""
eqJS """
import \
utilityBelt \
, {
each
} from \
'underscore'
""",
"""
import utilityBelt, {
each
} from 'underscore';
"""
test "#4874: backslash `export`", ->
eqJS """
export \
* \
from \
'underscore'
""",
"""
export * from 'underscore';
"""
eqJS """
export \
{ max, min } \
from \
'underscore'
""",
"""
export {
max,
min
} from 'underscore';
"""

View File

@@ -130,43 +130,43 @@ test "#2047: Infinite loop possible when `for` loop with `range` uses variables"
testData = [
[1, 5, 1, [1..5]]
[1, 5, -1, [1]]
[1, 5, -1, []]
[1, 5, up, [1..5]]
[1, 5, down, [1]]
[1, 5, down, []]
[a, 5, 1, [1..5]]
[a, 5, -1, [1]]
[a, 5, -1, []]
[a, 5, up, [1..5]]
[a, 5, down, [1]]
[a, 5, down, []]
[1, b, 1, [1..5]]
[1, b, -1, [1]]
[1, b, -1, []]
[1, b, up, [1..5]]
[1, b, down, [1]]
[1, b, down, []]
[a, b, 1, [1..5]]
[a, b, -1, [1]]
[a, b, -1, []]
[a, b, up, [1..5]]
[a, b, down, [1]]
[a, b, down, []]
[5, 1, 1, [5]]
[5, 1, 1, []]
[5, 1, -1, [5..1]]
[5, 1, up, [5]]
[5, 1, up, []]
[5, 1, down, [5..1]]
[5, a, 1, [5]]
[5, a, 1, []]
[5, a, -1, [5..1]]
[5, a, up, [5]]
[5, a, up, []]
[5, a, down, [5..1]]
[b, 1, 1, [5]]
[b, 1, 1, []]
[b, 1, -1, [5..1]]
[b, 1, up, [5]]
[b, 1, up, []]
[b, 1, down, [5..1]]
[b, a, 1, [5]]
[b, a, 1, []]
[b, a, -1, [5..1]]
[b, a, up, [5]]
[b, a, up, []]
[b, a, down, [5..1]]
]
@@ -182,10 +182,10 @@ test "#2047: from, to and step as variables", ->
arrayEq r, [1..5]
r = (x for x in [a..b] by down)
arrayEq r, [1]
arrayEq r, []
r = (x for x in [b..a] by up)
arrayEq r, [5]
arrayEq r, []
r = (x for x in [b..a] by down)
arrayEq r, [5..1]
@@ -195,3 +195,50 @@ test "#2047: from, to and step as variables", ->
step = 0
r = (x for x in [b..a] by step)
arrayEq r, []
test "#4884: Range not declaring var for the 'i'", ->
'use strict'
[0..21].forEach (idx) ->
idx + 1
eq global.i, undefined
test "#4889: `for` loop unexpected behavior", ->
n = 1
result = []
for i in [0..n]
result.push i
for j in [(i+1)..n]
result.push j
arrayEq result, [0,1,1,2,1]
test "#4889: `for` loop unexpected behavior with `by 1` on second loop", ->
n = 1
result = []
for i in [0..n]
result.push i
for j in [(i+1)..n] by 1
result.push j
arrayEq result, [0,1,1]
test "countdown example from docs", ->
countdown = (num for num in [10..1])
arrayEq countdown, [10,9,8,7,6,5,4,3,2,1]
test "counting up when the range goes down returns an empty array", ->
countdown = (num for num in [10..1] by 1)
arrayEq countdown, []
test "counting down when the range goes up returns an empty array", ->
countup = (num for num in [1..10] by -1)
arrayEq countup, []
test "counting down by too much returns just the first value", ->
countdown = (num for num in [10..1] by -100)
arrayEq countdown, [10]
test "counting up by too much returns just the first value", ->
countup = (num for num in [1..10] by 100)
arrayEq countup, [1]

View File

@@ -124,7 +124,7 @@ testRepl "keeps running after runtime error", (input, output) ->
eq 'undefined', output.lastWrite()
testRepl "#4604: wraps an async function", (input, output) ->
return unless global.supportsAsync
return unless try new Function 'async () => {}' # Feature detect support for async functions.
input.emitLine 'await new Promise (resolve) -> setTimeout (-> resolve 33), 10'
setTimeout ->
eq '33', output.lastWrite()