mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-13 08:47:55 -05:00
Compare commits
97 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8061ecf0e2 | ||
|
|
6df8f5ff17 | ||
|
|
776e7e5328 | ||
|
|
871079b25c | ||
|
|
be2b24310f | ||
|
|
1f9cd4eaf7 | ||
|
|
47c491ffa1 | ||
|
|
195a46ab77 | ||
|
|
e5aa758dda | ||
|
|
001f97ac39 | ||
|
|
ce66a499de | ||
|
|
0268505119 | ||
|
|
5a43b2d7c5 | ||
|
|
820942c3d0 | ||
|
|
1869f3121d | ||
|
|
4c0363fb7c | ||
|
|
746b0c7cc6 | ||
|
|
b2fe7772c5 | ||
|
|
23479eb486 | ||
|
|
63b8543d73 | ||
|
|
7542a75ff8 | ||
|
|
0875039d52 | ||
|
|
e0833c29ce | ||
|
|
72ab6feb2f | ||
|
|
eb7009268d | ||
|
|
571e9df335 | ||
|
|
a73f66bc11 | ||
|
|
ba094126e2 | ||
|
|
794f65fbd7 | ||
|
|
0490eb9a3a | ||
|
|
9e80f6fa67 | ||
|
|
fc5ab1afa3 | ||
|
|
0aa77f157a | ||
|
|
1849f0db76 | ||
|
|
d86597dbad | ||
|
|
bf91781888 | ||
|
|
dcd6de9a77 | ||
|
|
70b510bcb7 | ||
|
|
84d596d534 | ||
|
|
c804087ec9 | ||
|
|
74bd537d6c | ||
|
|
0217ed5505 | ||
|
|
e53307b46b | ||
|
|
c8c8c167d1 | ||
|
|
c1283ead45 | ||
|
|
3ade25a32c | ||
|
|
7ea3ea92f3 | ||
|
|
a70f1a082e | ||
|
|
2ccbb6b91a | ||
|
|
e348026073 | ||
|
|
7c6f3788ca | ||
|
|
12fcbfc654 | ||
|
|
38f5963b85 | ||
|
|
ffbe51e374 | ||
|
|
926cb8463c | ||
|
|
b1286752b9 | ||
|
|
5eb9dded52 | ||
|
|
7f5ab7eb0d | ||
|
|
5bc85b8f6d | ||
|
|
81d1b511f0 | ||
|
|
2dc3f6c87a | ||
|
|
04959162c6 | ||
|
|
f14c7ffa3f | ||
|
|
64b8dd486a | ||
|
|
7864acabc3 | ||
|
|
9812d28748 | ||
|
|
555c22af58 | ||
|
|
3f4b03bcff | ||
|
|
a706a64a6d | ||
|
|
637fe305a6 | ||
|
|
bd824c73dd | ||
|
|
cbc695b831 | ||
|
|
f3375e798c | ||
|
|
e2308093e4 | ||
|
|
0dc4755920 | ||
|
|
6faa7f2b35 | ||
|
|
063c2d1f56 | ||
|
|
4d4e47bfb2 | ||
|
|
22fb31e317 | ||
|
|
a2037e799f | ||
|
|
694e69d872 | ||
|
|
bb2871fdde | ||
|
|
08e00331dd | ||
|
|
0b0a9ef2c4 | ||
|
|
9df1457c55 | ||
|
|
22f92f23ae | ||
|
|
cd516b954f | ||
|
|
27eff5ca77 | ||
|
|
5cbd25f5d4 | ||
|
|
eb127923a7 | ||
|
|
42da56deb1 | ||
|
|
81260bff7d | ||
|
|
35f784bcdf | ||
|
|
c17b6b8863 | ||
|
|
1965996933 | ||
|
|
a67dfae985 | ||
|
|
1cb733989c |
@@ -3,6 +3,7 @@ language: node_js
|
||||
node_js:
|
||||
- 6
|
||||
- 8
|
||||
- 10
|
||||
|
||||
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
46
CODE_OF_CONDUCT.md
Normal 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/
|
||||
@@ -6,4 +6,9 @@
|
||||
|
||||
* Use the same coding style as the rest of the [codebase](https://github.com/jashkenas/coffeescript/tree/master/src). If you’re just getting started with CoffeeScript, there’s a nice [style guide](https://github.com/polarmobile/coffeescript-style-guide).
|
||||
|
||||
* In your pull request, do not add documentation to `index.html` or re-build the minified `coffeescript.js` file. We’ll do those things before cutting a new release. You _should,_ however, commit the updated compiled JavaScript files in `lib`.
|
||||
* In your pull request, do not add documentation to `index.html` or re-build the minified `coffeescript.js` file. We’ll do those things before cutting a new release. You _should,_ however, commit the updated compiled JavaScript files in `lib`.
|
||||
|
||||
* To get started, read the guides in the wiki:
|
||||
* [Hacking on the CoffeeScript Compiler](https://github.com/jashkenas/coffeescript/wiki/%5BHowTo%5D-Hacking-on-the-CoffeeScript-Compiler)
|
||||
* [How parsing works](https://github.com/jashkenas/coffeescript/wiki/%5BHowTo%5D-How-parsing-works)
|
||||
* [Update the docs](https://github.com/jashkenas/coffeescript/wiki/%5BHowTo%5D-Update-the-docs)
|
||||
|
||||
26
Cakefile
26
Cakefile
@@ -332,7 +332,7 @@ task 'doc:test:watch', 'watch and continually rebuild the browser-based tests',
|
||||
|
||||
buildAnnotatedSource = (watch = no) ->
|
||||
do generateAnnotatedSource = ->
|
||||
exec "node_modules/docco/bin/docco src/*.*coffee --output docs/v#{majorVersion}/annotated-source", (err) -> throw err if err
|
||||
exec "cd src && ../node_modules/docco/bin/docco *.*coffee --output ../docs/v#{majorVersion}/annotated-source", (err) -> throw err if err
|
||||
log 'generated', green, "annotated source in docs/v#{majorVersion}/annotated-source/"
|
||||
|
||||
if watch
|
||||
@@ -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,20 @@ 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 isn’t supported.
|
||||
files = files.filter (filename) -> filename isnt 'async.coffee'
|
||||
# Run every test in the `test` folder, recording failures, except for files
|
||||
# we’re 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']
|
||||
skipUnless 'var {...a} = {}', ['object_rest_spread.coffee']
|
||||
skipUnless '/foo.bar/s.test("foo\tbar")', ['regex_dotall.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
62
ISSUE_TEMPLATE.md
Normal 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. They’re 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 you’re describing a bug, tell us what should happen. -->
|
||||
<!--- If you’re 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 you’re running: `coffee -v`. -->
|
||||
<!--- If you think it might be relevant, please also let us know your version of Node. -->
|
||||
|
||||
* CoffeeScript version:
|
||||
* Node.js version:
|
||||
2
LICENSE
2
LICENSE
@@ -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
22
PULL_REQUEST_TEMPLATE.md
Normal 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 don’t 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.
|
||||
-->
|
||||
49
README.md
49
README.md
@@ -1,22 +1,27 @@
|
||||
{
|
||||
} } {
|
||||
{ { } }
|
||||
} }{ {
|
||||
{ }{ } } _____ __ __
|
||||
{ }{ }{ { } / ____| / _|/ _|
|
||||
.- { { } { }} -. | | ___ | |_| |_ ___ ___
|
||||
( { } { } { } } ) | | / _ \| _| _/ _ \/ _ \
|
||||
|`-..________ ..-'| | |___| (_) | | | || __/ __/
|
||||
| | \_____\___/|_| |_| \___|\___|
|
||||
| ;--.
|
||||
| (__ \ _____ _ _
|
||||
| | ) ) / ____| (_) | |
|
||||
| |/ / | (___ ___ _ __ _ _ __ | |_
|
||||
| ( / \___ \ / __| '__| | '_ \| __|
|
||||
| |/ ____) | (__| | | | |_) | |_
|
||||
| | |_____/ \___|_| |_| .__/ \__|
|
||||
`-.._________..-' | |
|
||||
|_|
|
||||
@@@@@@@ @@@@ @@@@@
|
||||
@@@@@@@@@@ @@@ @@@ {
|
||||
@@@@ @@ @@@ @@@ } } {
|
||||
@@@@ @@@@@@@ @@@ @@@ @@@@@@ @@@@@@ { { } }
|
||||
@@@@ @@@ @@ @@@@@ @@@@@@ @@@ @@ @@@@ @@ } }{ {
|
||||
@@@@ @@@@ @@ @@@ @@@ @@@ @@@ @@@ @@@ { }{ } }
|
||||
@@@@ @@@@ @@ @@@ @@@ @@@@@@@@ @@@@@@@@ { }{ }{ { }
|
||||
@@@@@ @@@@ @@ @@@ @@@ @@@ @@@ { { } { } { } }
|
||||
@@@@@@@@@@ @@@@@@@@ @@@ @@@ @@@@@@@@ @@@@@@@@ { } { } { }
|
||||
@@@@@ @@@ @@@ @@@@@ @@@@@ @@@@@@ { } { } @@@@@@@
|
||||
@@@ @@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@@@ @@@ @@@ @@ @@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@ @@ @@@ @@@@ @@ @@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@ @@@ @@ @@@@ @@@ @@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@@ @@@@@ @@ @@ @@@ @@@@@@@ @@@@@ @@@ @@@@@@@@@@@@@@@@@@
|
||||
@@@@@ @@@ @@@ @@@@@@@@ @@@@ @@@@ @@@@@@@ @@@ @@@@@@@@@@@@@@@@
|
||||
@@@@@ @@@ @@@@ @@@@ @@@ @@@ @@@ @@@@@@@@@@@@@@
|
||||
@@@@@ @@@@ @@@@ @@@@ @@@@ @@@@ @@@@ @@@@
|
||||
@@@ @@@@ @@@ @@@@ @@@@ @@@ @@@@ @@@@
|
||||
@@@ @@@@ @@@@ @@@@ @@@@ @@@@ @@@@ @@@@
|
||||
@@@@@@@@@ @@@@@@ @@@@ @@@@ @@@@@@@@@ @@@@
|
||||
@@@ @@@@
|
||||
@@@
|
||||
@@@
|
||||
|
||||
CoffeeScript is a little language that compiles into JavaScript.
|
||||
|
||||
@@ -25,11 +30,13 @@ CoffeeScript is a little language that compiles into JavaScript.
|
||||
Once you have Node.js installed:
|
||||
|
||||
```shell
|
||||
# Install locally for a project:
|
||||
npm install --save-dev coffeescript
|
||||
|
||||
# Install globally to execute .coffee files anywhere:
|
||||
npm install --global coffeescript
|
||||
```
|
||||
|
||||
Leave off the `--global` if you don’t wish to install globally.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Execute a script:
|
||||
|
||||
29
appveyor.yml
Normal file
29
appveyor.yml
Normal file
@@ -0,0 +1,29 @@
|
||||
environment:
|
||||
matrix:
|
||||
- nodejs_version: '6'
|
||||
- nodejs_version: '8'
|
||||
- nodejs_version: '10'
|
||||
- nodejs_version: '' # Installs latest.
|
||||
|
||||
install:
|
||||
- ps: Install-Product node $env:nodejs_version
|
||||
- node --version
|
||||
- npm --version
|
||||
- npm install
|
||||
|
||||
cache:
|
||||
- node_modules
|
||||
|
||||
test_script:
|
||||
- node ./bin/cake build:except-parser
|
||||
- node ./bin/cake build:parser
|
||||
- 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
|
||||
|
||||
build: off
|
||||
|
||||
version: "{build}"
|
||||
7
bin/cake
7
bin/cake
@@ -1,5 +1,12 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
try {
|
||||
new Function('var {a} = {a: 1}')();
|
||||
} catch (error) {
|
||||
console.error('Your JavaScript runtime does not support some features used by the cake command. Please use Node 6 or later.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
try {
|
||||
new Function('var {a} = {a: 1}')();
|
||||
} catch (error) {
|
||||
console.error('Your JavaScript runtime does not support some features used by the coffee command. Please use Node 6 or later.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
|
||||
|
||||
@@ -480,7 +480,9 @@ is run via the CLI or Node API.</p>
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> transpiler = options.transpile.transpile
|
||||
<span class="hljs-keyword">delete</span> options.transpile.transpile</pre></div></div>
|
||||
<span class="hljs-keyword">delete</span> options.transpile.transpile
|
||||
|
||||
transpilerOptions = Object.assign {}, options.transpile</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -497,9 +499,9 @@ and it will return an <em>updated</em> v3 source map object in its output.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> v3SourceMap <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> options.transpile.inputSourceMap?
|
||||
options.transpile.inputSourceMap = v3SourceMap
|
||||
transpilerOutput = transpiler js, options.transpile
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> v3SourceMap <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> transpilerOptions.inputSourceMap?
|
||||
transpilerOptions.inputSourceMap = v3SourceMap
|
||||
transpilerOutput = transpiler js, transpilerOptions
|
||||
js = transpilerOutput.code
|
||||
<span class="hljs-keyword">if</span> v3SourceMap <span class="hljs-keyword">and</span> transpilerOutput.map
|
||||
v3SourceMap = transpilerOutput.map
|
||||
|
||||
@@ -295,6 +295,7 @@ Many flags cause us to divert before compiling anything. Flags passed after
|
||||
<div class="content"><div class='highlight'><pre> replCliOpts = useGlobal: <span class="hljs-literal">yes</span>
|
||||
opts.prelude = makePrelude opts.<span class="hljs-built_in">require</span> <span class="hljs-keyword">if</span> opts.<span class="hljs-built_in">require</span>
|
||||
replCliOpts.prelude = opts.prelude
|
||||
replCliOpts.transpile = opts.transpile
|
||||
<span class="hljs-keyword">return</span> forkNode() <span class="hljs-keyword">if</span> opts.nodejs
|
||||
<span class="hljs-keyword">return</span> usage() <span class="hljs-keyword">if</span> opts.help
|
||||
<span class="hljs-keyword">return</span> version() <span class="hljs-keyword">if</span> opts.version
|
||||
@@ -508,6 +509,9 @@ and write them back to <strong>stdout</strong>.</p>
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">compileStdio</span> = -></span>
|
||||
<span class="hljs-keyword">if</span> opts.map
|
||||
<span class="hljs-built_in">console</span>.error <span class="hljs-string">'--stdio and --map cannot be used together'</span>
|
||||
process.exit <span class="hljs-number">1</span>
|
||||
buffers = []
|
||||
stdin = process.openStdin()
|
||||
stdin.<span class="hljs-literal">on</span> <span class="hljs-string">'data'</span>, <span class="hljs-function"><span class="hljs-params">(buffer)</span> -></span>
|
||||
@@ -745,7 +749,7 @@ same directory as the <code>.js</code> file.</p>
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">writeJs</span> = <span class="hljs-params">(base, sourcePath, js, jsPath, generatedSourceMap = <span class="hljs-literal">null</span>)</span> -></span>
|
||||
sourceMapPath = outputPath sourcePath, base, <span class="hljs-string">".js.map"</span>
|
||||
sourceMapPath = <span class="hljs-string">"<span class="hljs-subst">#{jsPath}</span>.map"</span>
|
||||
jsDir = path.dirname jsPath
|
||||
<span class="hljs-function"> <span class="hljs-title">compile</span> = -></span>
|
||||
<span class="hljs-keyword">if</span> opts.compile
|
||||
@@ -862,19 +866,17 @@ same directory as the <code>.js</code> file.</p>
|
||||
<a class="pilcrow" href="#section-26">¶</a>
|
||||
</div>
|
||||
<p>The user has requested that the CoffeeScript compiler also transpile
|
||||
via Babel. We use Babel as an <code>optionalDependency</code>; see
|
||||
<a href="https://docs.npmjs.com/files/package.json#optionaldependencies">https://docs.npmjs.com/files/package.json#optionaldependencies</a>.</p>
|
||||
via Babel. We don’t include Babel as a dependency because we want to
|
||||
avoid dependencies in general, and most users probably won’t be relying
|
||||
on us to transpile for them; we assume most users will probably either
|
||||
run CoffeeScript’s output without transpilation (modern Node or evergreen
|
||||
browsers) or use a proper build chain like Gulp or Webpack.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">try</span>
|
||||
<span class="hljs-built_in">require</span> <span class="hljs-string">'babel-core'</span>
|
||||
<span class="hljs-keyword">catch</span>
|
||||
<span class="hljs-built_in">console</span>.error <span class="hljs-string">'''
|
||||
To use --transpile, you must have Babel installed and configured.
|
||||
See http://coffeescript.org/#transpilation
|
||||
'''</span>
|
||||
process.exit <span class="hljs-number">1</span></pre></div></div>
|
||||
<span class="hljs-keyword">catch</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -885,14 +887,28 @@ via Babel. We use Babel as an <code>optionalDependency</code>; see
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-27">¶</a>
|
||||
</div>
|
||||
<p>We’re giving Babel only a string, not a filename or path to a file, so
|
||||
it doesn’t know where to search to find a <code>.babelrc</code> file or a <code>babel</code>
|
||||
key in a <code>package.json</code>. So if <code>opts.transpile</code> is an object, use that
|
||||
as Babel’s options; otherwise figure out what the options should be.</p>
|
||||
<p>Give appropriate instructions depending on whether <code>coffee</code> was run
|
||||
locally or globally.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">unless</span> <span class="hljs-keyword">typeof</span> opts.transpile <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> <span class="hljs-built_in">require</span>.resolve(<span class="hljs-string">'.'</span>).indexOf(process.cwd()) <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
|
||||
<span class="hljs-built_in">console</span>.error <span class="hljs-string">'''
|
||||
To use --transpile, you must have babel-core installed:
|
||||
npm install --save-dev babel-core
|
||||
And you must save options to configure Babel in one of the places it looks to find its options.
|
||||
See http://coffeescript.org/#transpilation
|
||||
'''</span>
|
||||
<span class="hljs-keyword">else</span>
|
||||
<span class="hljs-built_in">console</span>.error <span class="hljs-string">'''
|
||||
To use --transpile with globally-installed CoffeeScript, you must have babel-core installed globally:
|
||||
npm install --global babel-core
|
||||
And you must save options to configure Babel in one of the places it looks to find its options, relative to the file being compiled or to the current folder.
|
||||
See http://coffeescript.org/#transpilation
|
||||
'''</span>
|
||||
process.exit <span class="hljs-number">1</span>
|
||||
|
||||
opts.transpile = {} <span class="hljs-keyword">unless</span> <span class="hljs-keyword">typeof</span> opts.transpile <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -903,46 +919,14 @@ as Babel’s options; otherwise figure out what the options should be.</p>
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-28">¶</a>
|
||||
</div>
|
||||
<p>Find the options based on the path to the file being compiled.</p>
|
||||
<p>Pass a reference to Babel into the compiler, so that the transpile option
|
||||
is available for the CLI. We need to do this so that tools like Webpack
|
||||
can <code>require('coffeescript')</code> and build correctly, without trying to
|
||||
require Babel.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">cantFindOptions</span> = -></span>
|
||||
<span class="hljs-built_in">console</span>.error <span class="hljs-string">'''
|
||||
To use the transpile option, there must be a .babelrc file
|
||||
(or a package.json file with a "babel" key) in the path of the file
|
||||
to be compiled, or in the path of the current working directory.
|
||||
If you are compiling a string via the Node API, the transpile option
|
||||
must be an object with the options to pass to Babel.
|
||||
See http://coffeescript.org/#transpilation
|
||||
'''</span>
|
||||
process.exit <span class="hljs-number">1</span>
|
||||
|
||||
checkPath = <span class="hljs-keyword">if</span> filename
|
||||
path.dirname filename
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> base
|
||||
base
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> process?
|
||||
process.cwd()
|
||||
<span class="hljs-keyword">else</span>
|
||||
cantFindOptions()
|
||||
|
||||
<span class="hljs-keyword">loop</span>
|
||||
<span class="hljs-keyword">try</span>
|
||||
opts.transpile = JSON.parse fs.readFileSync path.join(checkPath, <span class="hljs-string">'.babelrc'</span>), <span class="hljs-string">'utf-8'</span>
|
||||
<span class="hljs-keyword">break</span>
|
||||
<span class="hljs-keyword">catch</span>
|
||||
<span class="hljs-keyword">try</span>
|
||||
packageJson = JSON.parse fs.readFileSync(path.join(checkPath, <span class="hljs-string">'package.json'</span>), <span class="hljs-string">'utf-8'</span>)
|
||||
<span class="hljs-keyword">if</span> packageJson.babel?
|
||||
opts.transpile = packageJson.babel
|
||||
<span class="hljs-keyword">break</span>
|
||||
|
||||
<span class="hljs-keyword">if</span> checkPath <span class="hljs-keyword">is</span> path.dirname checkPath <span class="hljs-comment"># We’ve reached the root.</span>
|
||||
cantFindOptions()
|
||||
<span class="hljs-keyword">break</span>
|
||||
<span class="hljs-keyword">else</span>
|
||||
checkPath = path.dirname checkPath</pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> opts.transpile.transpile = CoffeeScript.transpile</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -953,14 +937,15 @@ as Babel’s options; otherwise figure out what the options should be.</p>
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-29">¶</a>
|
||||
</div>
|
||||
<p>Pass a reference to Babel into the compiler, so that the transpile option
|
||||
is available for the CLI. We need to do this so that tools like Webpack
|
||||
can <code>require('coffeescript')</code> and build correctly, without trying to
|
||||
require Babel.</p>
|
||||
<p>Babel searches for its options (a <code>.babelrc</code> file, a <code>.babelrc.js</code> file,
|
||||
a <code>package.json</code> file with a <code>babel</code> key, etc.) relative to the path
|
||||
given to it in its <code>filename</code> option. Make sure we have a path to pass
|
||||
along.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> opts.transpile.transpile = CoffeeScript.transpile
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">unless</span> opts.transpile.filename
|
||||
opts.transpile.filename = filename <span class="hljs-keyword">or</span> path.resolve(base <span class="hljs-keyword">or</span> process.cwd(), <span class="hljs-string">'<anonymous>'</span>)
|
||||
<span class="hljs-keyword">else</span>
|
||||
opts.transpile = <span class="hljs-literal">no</span>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -274,6 +274,21 @@ setting <code>__filename</code>, <code>__dirname</code>, and relative <code>requ
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-10">¶</a>
|
||||
</div>
|
||||
<p>Save the options for compiling child imports.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> mainModule.options = options</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-11">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
</div>
|
||||
<p>Compile.</p>
|
||||
|
||||
</div>
|
||||
@@ -287,11 +302,11 @@ setting <code>__filename</code>, <code>__dirname</code>, and relative <code>requ
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-11">
|
||||
<li id="section-12">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
<a class="pilcrow" href="#section-12">¶</a>
|
||||
</div>
|
||||
<p>Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
|
||||
The CoffeeScript REPL uses this to run the input.</p>
|
||||
@@ -321,11 +336,11 @@ The CoffeeScript REPL uses this to run the input.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-12">
|
||||
<li id="section-13">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-12">¶</a>
|
||||
<a class="pilcrow" href="#section-13">¶</a>
|
||||
</div>
|
||||
<p>define module/require only if they chose not to specify their own</p>
|
||||
|
||||
@@ -342,11 +357,11 @@ The CoffeeScript REPL uses this to run the input.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-13">
|
||||
<li id="section-14">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-13">¶</a>
|
||||
<a class="pilcrow" href="#section-14">¶</a>
|
||||
</div>
|
||||
<p>use the same hack node currently uses for their own REPL</p>
|
||||
|
||||
@@ -368,11 +383,11 @@ CoffeeScript.register = <span class="hljs-function">-></span> <span class="hl
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-14">
|
||||
<li id="section-15">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-14">¶</a>
|
||||
<a class="pilcrow" href="#section-15">¶</a>
|
||||
</div>
|
||||
<p>Throw error with deprecation warning when depending upon implicit <code>require.extensions</code> registration</p>
|
||||
|
||||
@@ -385,41 +400,43 @@ CoffeeScript.register = <span class="hljs-function">-></span> <span class="hl
|
||||
Use CoffeeScript.register() or require the coffeescript/register module to require <span class="hljs-subst">#{ext}</span> files.
|
||||
"""</span>
|
||||
|
||||
CoffeeScript._compileFile = <span class="hljs-function"><span class="hljs-params">(filename, sourceMap = <span class="hljs-literal">no</span>, inlineMap = <span class="hljs-literal">no</span>)</span> -></span>
|
||||
CoffeeScript._compileFile = <span class="hljs-function"><span class="hljs-params">(filename, options = {})</span> -></span>
|
||||
raw = fs.readFileSync filename, <span class="hljs-string">'utf8'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-15">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-15">¶</a>
|
||||
</div>
|
||||
<p>Strip the Unicode byte order mark, if this file begins with one.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> stripped = <span class="hljs-keyword">if</span> raw.charCodeAt(<span class="hljs-number">0</span>) <span class="hljs-keyword">is</span> <span class="hljs-number">0xFEFF</span> <span class="hljs-keyword">then</span> raw.substring <span class="hljs-number">1</span> <span class="hljs-keyword">else</span> raw
|
||||
|
||||
<span class="hljs-keyword">try</span>
|
||||
answer = CoffeeScript.compile stripped, {
|
||||
filename, sourceMap, inlineMap
|
||||
sourceFiles: [filename]
|
||||
literate: helpers.isLiterate filename
|
||||
}
|
||||
<span class="hljs-keyword">catch</span> err</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-16">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-16">¶</a>
|
||||
</div>
|
||||
<p>Strip the Unicode byte order mark, if this file begins with one.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> stripped = <span class="hljs-keyword">if</span> raw.charCodeAt(<span class="hljs-number">0</span>) <span class="hljs-keyword">is</span> <span class="hljs-number">0xFEFF</span> <span class="hljs-keyword">then</span> raw.substring <span class="hljs-number">1</span> <span class="hljs-keyword">else</span> raw
|
||||
|
||||
options = Object.assign {}, options,
|
||||
filename: filename
|
||||
literate: helpers.isLiterate filename
|
||||
sourceFiles: [filename]
|
||||
inlineMap: <span class="hljs-literal">yes</span> <span class="hljs-comment"># Always generate a source map, so that stack traces line up.</span>
|
||||
|
||||
<span class="hljs-keyword">try</span>
|
||||
answer = CoffeeScript.compile stripped, options
|
||||
<span class="hljs-keyword">catch</span> err</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-17">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
</div>
|
||||
<p>As the filename and code of a dynamically loaded file will be different
|
||||
from the original file compiled with CoffeeScript.run, add that
|
||||
information to error so it can be pretty-printed later.</p>
|
||||
|
||||
@@ -372,7 +372,6 @@ though <code>is</code> means <code>===</code> otherwise.</p>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> idLength = id.length
|
||||
poppedToken = <span class="hljs-literal">undefined</span>
|
||||
|
||||
<span class="hljs-keyword">if</span> id <span class="hljs-keyword">is</span> <span class="hljs-string">'own'</span> <span class="hljs-keyword">and</span> @tag() <span class="hljs-keyword">is</span> <span class="hljs-string">'FOR'</span>
|
||||
@token <span class="hljs-string">'OWN'</span>, id
|
||||
<span class="hljs-keyword">return</span> id.length
|
||||
@@ -382,14 +381,21 @@ though <code>is</code> means <code>===</code> otherwise.</p>
|
||||
<span class="hljs-keyword">if</span> id <span class="hljs-keyword">is</span> <span class="hljs-string">'as'</span> <span class="hljs-keyword">and</span> @seenImport
|
||||
<span class="hljs-keyword">if</span> @value() <span class="hljs-keyword">is</span> <span class="hljs-string">'*'</span>
|
||||
@tokens[@tokens.length - <span class="hljs-number">1</span>][<span class="hljs-number">0</span>] = <span class="hljs-string">'IMPORT_ALL'</span>
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @value() <span class="hljs-keyword">in</span> COFFEE_KEYWORDS
|
||||
@tokens[@tokens.length - <span class="hljs-number">1</span>][<span class="hljs-number">0</span>] = <span class="hljs-string">'IDENTIFIER'</span>
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @value(<span class="hljs-literal">yes</span>) <span class="hljs-keyword">in</span> COFFEE_KEYWORDS
|
||||
prev = @prev()
|
||||
[prev[<span class="hljs-number">0</span>], prev[<span class="hljs-number">1</span>]] = [<span class="hljs-string">'IDENTIFIER'</span>, @value(<span class="hljs-literal">yes</span>)]
|
||||
<span class="hljs-keyword">if</span> @tag() <span class="hljs-keyword">in</span> [<span class="hljs-string">'DEFAULT'</span>, <span class="hljs-string">'IMPORT_ALL'</span>, <span class="hljs-string">'IDENTIFIER'</span>]
|
||||
@token <span class="hljs-string">'AS'</span>, id
|
||||
<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">'as'</span> <span class="hljs-keyword">and</span> @seenExport <span class="hljs-keyword">and</span> @tag() <span class="hljs-keyword">in</span> [<span class="hljs-string">'IDENTIFIER'</span>, <span class="hljs-string">'DEFAULT'</span>]
|
||||
@token <span class="hljs-string">'AS'</span>, id
|
||||
<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">'as'</span> <span class="hljs-keyword">and</span> @seenExport
|
||||
<span class="hljs-keyword">if</span> @tag() <span class="hljs-keyword">in</span> [<span class="hljs-string">'IDENTIFIER'</span>, <span class="hljs-string">'DEFAULT'</span>]
|
||||
@token <span class="hljs-string">'AS'</span>, id
|
||||
<span class="hljs-keyword">return</span> id.length
|
||||
<span class="hljs-keyword">if</span> @value(<span class="hljs-literal">yes</span>) <span class="hljs-keyword">in</span> COFFEE_KEYWORDS
|
||||
prev = @prev()
|
||||
[prev[<span class="hljs-number">0</span>], prev[<span class="hljs-number">1</span>]] = [<span class="hljs-string">'IDENTIFIER'</span>, @value(<span class="hljs-literal">yes</span>)]
|
||||
@token <span class="hljs-string">'AS'</span>, id
|
||||
<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">'default'</span> <span class="hljs-keyword">and</span> @seenExport <span class="hljs-keyword">and</span> @tag() <span class="hljs-keyword">in</span> [<span class="hljs-string">'EXPORT'</span>, <span class="hljs-string">'AS'</span>]
|
||||
@token <span class="hljs-string">'DEFAULT'</span>, id
|
||||
<span class="hljs-keyword">return</span> id.length
|
||||
@@ -455,18 +461,22 @@ what CoffeeScript would normally interpret as calls to functions named
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'PROPERTY'</span> <span class="hljs-keyword">and</span> prev
|
||||
<span class="hljs-keyword">if</span> prev.spaced <span class="hljs-keyword">and</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> CALLABLE <span class="hljs-keyword">and</span> <span class="hljs-regexp">/^[gs]et$/</span>.test(prev[<span class="hljs-number">1</span>])
|
||||
@error <span class="hljs-string">"'<span class="hljs-subst">#{prev[<span class="hljs-number">1</span>]}</span>' cannot be used as a keyword, or as a function call without parentheses"</span>, prev[<span class="hljs-number">2</span>]
|
||||
<span class="hljs-keyword">else</span>
|
||||
<span class="hljs-keyword">if</span> prev.spaced <span class="hljs-keyword">and</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> CALLABLE <span class="hljs-keyword">and</span> <span class="hljs-regexp">/^[gs]et$/</span>.test(prev[<span class="hljs-number">1</span>]) <span class="hljs-keyword">and</span>
|
||||
@tokens.length > <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> @tokens[@tokens.length - <span class="hljs-number">2</span>][<span class="hljs-number">0</span>] <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-string">'@'</span>]
|
||||
@error <span class="hljs-string">"'<span class="hljs-subst">#{prev[<span class="hljs-number">1</span>]}</span>' cannot be used as a keyword, or as a function call
|
||||
without parentheses"</span>, prev[<span class="hljs-number">2</span>]
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @tokens.length > <span class="hljs-number">2</span>
|
||||
prevprev = @tokens[@tokens.length - <span class="hljs-number">2</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>, <span class="hljs-string">'THIS'</span>] <span class="hljs-keyword">and</span> prevprev <span class="hljs-keyword">and</span> prevprev.spaced <span class="hljs-keyword">and</span> <span class="hljs-regexp">/^[gs]et$/</span>.test(prevprev[<span class="hljs-number">1</span>]) <span class="hljs-keyword">and</span>
|
||||
@tokens[@tokens.length - <span class="hljs-number">3</span>][<span class="hljs-number">0</span>] <span class="hljs-keyword">isnt</span> <span class="hljs-string">'.'</span>
|
||||
@error <span class="hljs-string">"'<span class="hljs-subst">#{prevprev[<span class="hljs-number">1</span>]}</span>' cannot be used as a keyword, or as a function call without parentheses"</span>, prevprev[<span class="hljs-number">2</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>, <span class="hljs-string">'THIS'</span>] <span class="hljs-keyword">and</span> prevprev <span class="hljs-keyword">and</span> prevprev.spaced <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-regexp">/^[gs]et$/</span>.test(prevprev[<span class="hljs-number">1</span>]) <span class="hljs-keyword">and</span>
|
||||
@tokens[@tokens.length - <span class="hljs-number">3</span>][<span class="hljs-number">0</span>] <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-string">'@'</span>]
|
||||
@error <span class="hljs-string">"'<span class="hljs-subst">#{prevprev[<span class="hljs-number">1</span>]}</span>' cannot be used as a keyword, or as a
|
||||
function call without parentheses"</span>, prevprev[<span class="hljs-number">2</span>]
|
||||
|
||||
<span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'IDENTIFIER'</span> <span class="hljs-keyword">and</span> id <span class="hljs-keyword">in</span> RESERVED
|
||||
@error <span class="hljs-string">"reserved word '<span class="hljs-subst">#{id}</span>'"</span>, length: id.length
|
||||
|
||||
<span class="hljs-keyword">unless</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'PROPERTY'</span>
|
||||
<span class="hljs-keyword">unless</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'PROPERTY'</span> <span class="hljs-keyword">or</span> @exportSpecifierList
|
||||
<span class="hljs-keyword">if</span> id <span class="hljs-keyword">in</span> COFFEE_ALIASES
|
||||
alias = id
|
||||
id = COFFEE_ALIAS_MAP[id]
|
||||
@@ -909,9 +919,11 @@ can close multiple indents, so we need to know how far in we happen to be.</p>
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span> <span class="hljs-keyword">unless</span> match = MULTI_DENT.exec chunk
|
||||
indent = match[<span class="hljs-number">0</span>]
|
||||
|
||||
@seenFor = <span class="hljs-literal">no</span>
|
||||
@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
|
||||
prev = @prev()
|
||||
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> (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()
|
||||
@@ -932,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 > @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
|
||||
@@ -1115,7 +1127,7 @@ comments that trail it.</p>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> prevChar = <span class="hljs-keyword">if</span> @tokens.length > <span class="hljs-number">0</span> <span class="hljs-keyword">then</span> @tokens[@tokens.length - <span class="hljs-number">1</span>][<span class="hljs-number">0</span>] <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>
|
||||
<span class="hljs-keyword">if</span> firstChar <span class="hljs-keyword">is</span> <span class="hljs-string">'<'</span>
|
||||
match = CSX_IDENTIFIER.exec @chunk[<span class="hljs-number">1.</span>..]
|
||||
match = CSX_IDENTIFIER.exec(@chunk[<span class="hljs-number">1.</span>..]) <span class="hljs-keyword">or</span> CSX_FRAGMENT_IDENTIFIER.exec(@chunk[<span class="hljs-number">1.</span>..])
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span> <span class="hljs-keyword">unless</span> match <span class="hljs-keyword">and</span> (
|
||||
@csxDepth > <span class="hljs-number">0</span> <span class="hljs-keyword">or</span></pre></div></div>
|
||||
|
||||
@@ -1181,8 +1193,8 @@ comments that trail it.</p>
|
||||
@matchWithInterpolations INSIDE_CSX, <span class="hljs-string">'>'</span>, <span class="hljs-string">'</'</span>, CSX_INTERPOLATION
|
||||
@mergeInterpolationTokens tokens, {delimiter: <span class="hljs-string">'"'</span>}, <span class="hljs-function"><span class="hljs-params">(value, i)</span> =></span>
|
||||
@formatString value, delimiter: <span class="hljs-string">'>'</span>
|
||||
match = CSX_IDENTIFIER.exec @chunk[end...]
|
||||
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> match <span class="hljs-keyword">or</span> match[<span class="hljs-number">0</span>] <span class="hljs-keyword">isnt</span> csxTag.name
|
||||
match = CSX_IDENTIFIER.exec(@chunk[end...]) <span class="hljs-keyword">or</span> CSX_FRAGMENT_IDENTIFIER.exec(@chunk[end...])
|
||||
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> match <span class="hljs-keyword">or</span> match[<span class="hljs-number">1</span>] <span class="hljs-keyword">isnt</span> csxTag.name
|
||||
@error <span class="hljs-string">"expected corresponding CSX closing tag for <span class="hljs-subst">#{csxTag.name}</span>"</span>,
|
||||
csxTag.origin[<span class="hljs-number">2</span>]
|
||||
afterTag = end + csxTag.name.length
|
||||
@@ -1635,8 +1647,8 @@ of <code>'NEOSTRING'</code>s are converted using <code>fn</code> and tur
|
||||
<a class="pilcrow" href="#section-58">¶</a>
|
||||
</div>
|
||||
<p>This is an interpolated string, not a CSX tag; and for whatever
|
||||
reason <code>`a${/*test*/}b` </code> is invalid JS. So compile to
|
||||
<code>`a${/*test*/''}b` </code> instead.</p>
|
||||
reason <code>`a${/*test*/}b`</code> is invalid JS. So compile to
|
||||
<code>`a${/*test*/''}b`</code> instead.</p>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1968,9 +1980,12 @@ not specified, the length of <code>value</code> will be used.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> value: <span class="hljs-function">-></span>
|
||||
<div class="content"><div class='highlight'><pre> value: <span class="hljs-function"><span class="hljs-params">(useOrigin = <span class="hljs-literal">no</span>)</span> -></span>
|
||||
[..., token] = @tokens
|
||||
token?[<span class="hljs-number">1</span>]</pre></div></div>
|
||||
<span class="hljs-keyword">if</span> useOrigin <span class="hljs-keyword">and</span> token?.origin?
|
||||
token.origin?[<span class="hljs-number">1</span>]
|
||||
<span class="hljs-keyword">else</span>
|
||||
token?[<span class="hljs-number">1</span>]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -2449,6 +2464,23 @@ be used as identifiers or properties.</p>
|
||||
CSX_IDENTIFIER = <span class="hljs-regexp">/// ^
|
||||
(?![\d<]) <span class="hljs-comment"># Must not start with `<`.</span>
|
||||
( (?: (?!\s)[\.\-$\w\x7f-\uffff] )+ ) <span class="hljs-comment"># Like `IDENTIFIER`, but includes `-`s and `.`s.</span>
|
||||
///</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-98">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-98">¶</a>
|
||||
</div>
|
||||
<p>Fragment: <></></p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>CSX_FRAGMENT_IDENTIFIER = <span class="hljs-regexp">/// ^
|
||||
()> <span class="hljs-comment"># Ends immediately with `>`.</span>
|
||||
///</span>
|
||||
|
||||
CSX_ATTRIBUTE = <span class="hljs-regexp">/// ^
|
||||
@@ -2488,11 +2520,11 @@ HERE_JSTOKEN = <span class="hljs-regexp">///^ ``` ((?: [^`\\] | \\[\s\S] | `
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-98">
|
||||
<li id="section-99">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-98">¶</a>
|
||||
<a class="pilcrow" href="#section-99">¶</a>
|
||||
</div>
|
||||
<p>String-matching-regexes.</p>
|
||||
|
||||
@@ -2526,11 +2558,11 @@ HEREDOC_INDENT = <span class="hljs-regexp">/\n+([^\n\S]*)(?=\S)/g</span></pr
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-99">
|
||||
<li id="section-100">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-99">¶</a>
|
||||
<a class="pilcrow" href="#section-100">¶</a>
|
||||
</div>
|
||||
<p>Regex-matching-regexes.</p>
|
||||
|
||||
@@ -2547,9 +2579,88 @@ HEREDOC_INDENT = <span class="hljs-regexp">/\n+([^\n\S]*)(?=\S)/g</span></pr
|
||||
///</span>
|
||||
|
||||
REGEX_FLAGS = <span class="hljs-regexp">/^\w*/</span>
|
||||
VALID_FLAGS = <span class="hljs-regexp">/^(?!.*(.).*\1)[imguy]*$/</span>
|
||||
VALID_FLAGS = <span class="hljs-regexp">/^(?!.*(.).*\1)[gimsuy]*$/</span>
|
||||
|
||||
HEREGEX = <span class="hljs-regexp">/// ^(?: [^\\/<span class="hljs-comment">#] | \\[\s\S] | /(?!//) | \#(?!\{) )* ///</span>
|
||||
HEREGEX = <span class="hljs-regexp">/// ^
|
||||
(?:
|
||||
</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-101">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-101">¶</a>
|
||||
</div>
|
||||
<p>Match any character, except those that need special handling below.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> [^\\/<span class="hljs-comment">#\s]</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-102">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-102">¶</a>
|
||||
</div>
|
||||
<p>Match <code>\</code> followed by any character.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> | \\[\s\S]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-103">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-103">¶</a>
|
||||
</div>
|
||||
<p>Match any <code>/</code> except <code>///</code>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> | <span class="hljs-regexp">/(?!/</span>/)</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-104">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-104">¶</a>
|
||||
</div>
|
||||
<p>Match <code>#</code> which is not part of interpolation, e.g. <code>#{}</code>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> | \<span class="hljs-comment">#(?!\{)</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-105">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-105">¶</a>
|
||||
</div>
|
||||
<p>Comments consume everything until the end of the line, including <code>///</code>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> | \s+(?:<span class="hljs-comment">#(?!\{).*)?</span>
|
||||
)*
|
||||
<span class="hljs-regexp">///
|
||||
|
||||
HEREGEX_OMIT = ///</span>
|
||||
((?:\\\\)+) <span class="hljs-comment"># Consume (and preserve) an even number of backslashes.</span>
|
||||
@@ -2564,11 +2675,11 @@ POSSIBLY_DIVISION = <span class="hljs-regexp">/// ^ /=?\s ///</span></pre></di
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-100">
|
||||
<li id="section-106">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-100">¶</a>
|
||||
<a class="pilcrow" href="#section-106">¶</a>
|
||||
</div>
|
||||
<p>Other regexes.</p>
|
||||
|
||||
@@ -2611,11 +2722,11 @@ TRAILING_SPACES = <span class="hljs-regexp">/\s+$/</span></pre></div></div>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-101">
|
||||
<li id="section-107">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-101">¶</a>
|
||||
<a class="pilcrow" href="#section-107">¶</a>
|
||||
</div>
|
||||
<p>Compound assignment tokens.</p>
|
||||
|
||||
@@ -2629,11 +2740,11 @@ TRAILING_SPACES = <span class="hljs-regexp">/\s+$/</span></pre></div></div>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-102">
|
||||
<li id="section-108">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-102">¶</a>
|
||||
<a class="pilcrow" href="#section-108">¶</a>
|
||||
</div>
|
||||
<p>Unary tokens.</p>
|
||||
|
||||
@@ -2646,11 +2757,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-103">
|
||||
<li id="section-109">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-103">¶</a>
|
||||
<a class="pilcrow" href="#section-109">¶</a>
|
||||
</div>
|
||||
<p>Bit-shifting tokens.</p>
|
||||
|
||||
@@ -2661,11 +2772,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-104">
|
||||
<li id="section-110">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-104">¶</a>
|
||||
<a class="pilcrow" href="#section-110">¶</a>
|
||||
</div>
|
||||
<p>Comparison tokens.</p>
|
||||
|
||||
@@ -2676,11 +2787,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-105">
|
||||
<li id="section-111">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-105">¶</a>
|
||||
<a class="pilcrow" href="#section-111">¶</a>
|
||||
</div>
|
||||
<p>Mathematical tokens.</p>
|
||||
|
||||
@@ -2691,11 +2802,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-106">
|
||||
<li id="section-112">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-106">¶</a>
|
||||
<a class="pilcrow" href="#section-112">¶</a>
|
||||
</div>
|
||||
<p>Relational tokens that are negatable with <code>not</code> prefix.</p>
|
||||
|
||||
@@ -2706,11 +2817,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-107">
|
||||
<li id="section-113">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-107">¶</a>
|
||||
<a class="pilcrow" href="#section-113">¶</a>
|
||||
</div>
|
||||
<p>Boolean tokens.</p>
|
||||
|
||||
@@ -2721,11 +2832,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-108">
|
||||
<li id="section-114">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-108">¶</a>
|
||||
<a class="pilcrow" href="#section-114">¶</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
|
||||
@@ -2742,11 +2853,11 @@ INDEXABLE = CALLABLE.concat [
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-109">
|
||||
<li id="section-115">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-109">¶</a>
|
||||
<a class="pilcrow" href="#section-115">¶</a>
|
||||
</div>
|
||||
<p>Tokens which can be the left-hand side of a less-than comparison, i.e. <code>a<b</code>.</p>
|
||||
|
||||
@@ -2757,11 +2868,11 @@ INDEXABLE = CALLABLE.concat [
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-110">
|
||||
<li id="section-116">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-110">¶</a>
|
||||
<a class="pilcrow" href="#section-116">¶</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>
|
||||
@@ -2774,11 +2885,11 @@ CALLABLEs in some cases), but which a division operator can.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-111">
|
||||
<li id="section-117">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-111">¶</a>
|
||||
<a class="pilcrow" href="#section-117">¶</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
|
||||
@@ -2791,11 +2902,11 @@ avoid an ambiguity in the grammar.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-112">
|
||||
<li id="section-118">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-112">¶</a>
|
||||
<a class="pilcrow" href="#section-118">¶</a>
|
||||
</div>
|
||||
<p>Additional indent in front of these is ignored.</p>
|
||||
|
||||
@@ -2806,11 +2917,11 @@ avoid an ambiguity in the grammar.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-113">
|
||||
<li id="section-119">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-113">¶</a>
|
||||
<a class="pilcrow" href="#section-119">¶</a>
|
||||
</div>
|
||||
<p>Tokens that, when appearing at the end of a line, suppress a following TERMINATOR/INDENT token</p>
|
||||
|
||||
@@ -2818,7 +2929,7 @@ avoid an ambiguity in the grammar.</p>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>UNFINISHED = [<span class="hljs-string">'\\'</span>, <span class="hljs-string">'.'</span>, <span class="hljs-string">'?.'</span>, <span class="hljs-string">'?::'</span>, <span class="hljs-string">'UNARY'</span>, <span class="hljs-string">'MATH'</span>, <span class="hljs-string">'UNARY_MATH'</span>, <span class="hljs-string">'+'</span>, <span class="hljs-string">'-'</span>,
|
||||
<span class="hljs-string">'**'</span>, <span class="hljs-string">'SHIFT'</span>, <span class="hljs-string">'RELATION'</span>, <span class="hljs-string">'COMPARE'</span>, <span class="hljs-string">'&'</span>, <span class="hljs-string">'^'</span>, <span class="hljs-string">'|'</span>, <span class="hljs-string">'&&'</span>, <span class="hljs-string">'||'</span>,
|
||||
<span class="hljs-string">'BIN?'</span>, <span class="hljs-string">'EXTENDS'</span>, <span class="hljs-string">'DEFAULT'</span>]</pre></div></div>
|
||||
<span class="hljs-string">'BIN?'</span>, <span class="hljs-string">'EXTENDS'</span>]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -137,7 +137,8 @@ path = <span class="hljs-built_in">require</span> <span class="hljs-str
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">loadFile</span> = <span class="hljs-params">(<span class="hljs-built_in">module</span>, filename)</span> -></span>
|
||||
answer = CoffeeScript._compileFile filename, <span class="hljs-literal">no</span>, <span class="hljs-literal">yes</span>
|
||||
options = <span class="hljs-built_in">module</span>.options <span class="hljs-keyword">or</span> getRootModule(<span class="hljs-built_in">module</span>).options
|
||||
answer = CoffeeScript._compileFile filename, options
|
||||
<span class="hljs-built_in">module</span>._compile answer, filename</pre></div></div>
|
||||
|
||||
</li>
|
||||
@@ -245,6 +246,22 @@ to fork both CoffeeScript files, and JavaScript files, directly.</p>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-8">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-8">¶</a>
|
||||
</div>
|
||||
<p>Utility function to find the <code>options</code> object attached to the topmost module.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">getRootModule</span> = <span class="hljs-params">(<span class="hljs-built_in">module</span>)</span> -></span>
|
||||
<span class="hljs-keyword">if</span> <span class="hljs-built_in">module</span>.parent <span class="hljs-keyword">then</span> getRootModule <span class="hljs-built_in">module</span>.parent <span class="hljs-keyword">else</span> <span class="hljs-built_in">module</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -126,6 +126,7 @@ CoffeeScript = <span class="hljs-built_in">require</span> <span class="hljs-stri
|
||||
{merge, updateSyntaxError} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./helpers'</span>
|
||||
|
||||
sawSIGINT = <span class="hljs-literal">no</span>
|
||||
transpile = <span class="hljs-literal">no</span>
|
||||
|
||||
replDefaults =
|
||||
prompt: <span class="hljs-string">'coffee> '</span>,
|
||||
@@ -223,11 +224,17 @@ Unwrap that too.</p>
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-7">¶</a>
|
||||
</div>
|
||||
<p>Collect referenced variable names just like in <code>CoffeeScript.compile</code>.</p>
|
||||
<p>Filter out tokens generated just to hold comments.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> referencedVars = (token[<span class="hljs-number">1</span>] <span class="hljs-keyword">for</span> token <span class="hljs-keyword">in</span> tokens <span class="hljs-keyword">when</span> token[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'IDENTIFIER'</span>)</pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> tokens.length >= <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> tokens[<span class="hljs-number">0</span>].generated <span class="hljs-keyword">and</span>
|
||||
tokens[<span class="hljs-number">0</span>].comments?.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> tokens[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">''</span> <span class="hljs-keyword">and</span>
|
||||
tokens[<span class="hljs-number">1</span>][<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'TERMINATOR'</span>
|
||||
tokens = tokens[<span class="hljs-number">2.</span>..]
|
||||
<span class="hljs-keyword">if</span> tokens.length >= <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> tokens[tokens.length - <span class="hljs-number">1</span>].generated <span class="hljs-keyword">and</span>
|
||||
tokens[tokens.length - <span class="hljs-number">1</span>].comments?.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> tokens[tokens.length - <span class="hljs-number">1</span>][<span class="hljs-number">1</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">''</span>
|
||||
tokens.pop()</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -238,11 +245,11 @@ Unwrap that too.</p>
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-8">¶</a>
|
||||
</div>
|
||||
<p>Generate the AST of the tokens.</p>
|
||||
<p>Collect referenced variable names just like in <code>CoffeeScript.compile</code>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> ast = CoffeeScript.nodes tokens</pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> referencedVars = (token[<span class="hljs-number">1</span>] <span class="hljs-keyword">for</span> token <span class="hljs-keyword">in</span> tokens <span class="hljs-keyword">when</span> token[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'IDENTIFIER'</span>)</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -253,11 +260,11 @@ Unwrap that too.</p>
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-9">¶</a>
|
||||
</div>
|
||||
<p>Add assignment to <code>__</code> variable to force the input to be an expression.</p>
|
||||
<p>Generate the AST of the tokens.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> ast = <span class="hljs-keyword">new</span> Block [<span class="hljs-keyword">new</span> Assign (<span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal <span class="hljs-string">'__'</span>), ast, <span class="hljs-string">'='</span>]</pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> ast = CoffeeScript.nodes tokens</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -268,12 +275,11 @@ Unwrap that too.</p>
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-10">¶</a>
|
||||
</div>
|
||||
<p>Wrap the expression in a closure to support top-level <code>await</code></p>
|
||||
<p>Add assignment to <code>__</code> variable to force the input to be an expression.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> ast = <span class="hljs-keyword">new</span> Code [], ast
|
||||
isAsync = ast.isAsync</pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> ast = <span class="hljs-keyword">new</span> Block [<span class="hljs-keyword">new</span> Assign (<span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal <span class="hljs-string">'__'</span>), ast, <span class="hljs-string">'='</span>]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -284,13 +290,12 @@ Unwrap that too.</p>
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
</div>
|
||||
<p>Invoke the wrapping closure</p>
|
||||
<p>Wrap the expression in a closure to support top-level <code>await</code>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> ast = <span class="hljs-keyword">new</span> Block [<span class="hljs-keyword">new</span> Call ast]
|
||||
js = ast.compile {bare: <span class="hljs-literal">yes</span>, locals: Object.keys(context), referencedVars, sharedScope: <span class="hljs-literal">yes</span>}
|
||||
result = runInContext js, context, filename</pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> ast = <span class="hljs-keyword">new</span> Code [], ast
|
||||
isAsync = ast.isAsync</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -301,7 +306,42 @@ Unwrap that too.</p>
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-12">¶</a>
|
||||
</div>
|
||||
<p>Await an async result, if necessary</p>
|
||||
<p>Invoke the wrapping closure.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> ast = <span class="hljs-keyword">new</span> Block [<span class="hljs-keyword">new</span> Call ast]
|
||||
js = ast.compile {bare: <span class="hljs-literal">yes</span>, locals: Object.keys(context), referencedVars, sharedScope: <span class="hljs-literal">yes</span>}
|
||||
<span class="hljs-keyword">if</span> transpile
|
||||
js = transpile.transpile(js, transpile.options).code</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-13">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-13">¶</a>
|
||||
</div>
|
||||
<p>Strip <code>"use strict"</code>, to avoid an exception on assigning to
|
||||
undeclared variable <code>__</code>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> js = js.replace <span class="hljs-regexp">/^"use strict"|^'use strict'/</span>, <span class="hljs-string">''</span>
|
||||
result = runInContext js, context, filename</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-14">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-14">¶</a>
|
||||
</div>
|
||||
<p>Await an async result, if necessary.</p>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -316,11 +356,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-13">
|
||||
<li id="section-15">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-13">¶</a>
|
||||
<a class="pilcrow" href="#section-15">¶</a>
|
||||
</div>
|
||||
<p>AST’s <code>compile</code> does not add source code information to syntax errors.</p>
|
||||
|
||||
@@ -341,11 +381,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-14">
|
||||
<li id="section-16">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-14">¶</a>
|
||||
<a class="pilcrow" href="#section-16">¶</a>
|
||||
</div>
|
||||
<p>Node 0.11.12 changed API, prompt is now _prompt.</p>
|
||||
|
||||
@@ -362,11 +402,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-15">
|
||||
<li id="section-17">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-15">¶</a>
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
</div>
|
||||
<p>Proxy node’s line listener</p>
|
||||
|
||||
@@ -387,11 +427,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-16">
|
||||
<li id="section-18">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-16">¶</a>
|
||||
<a class="pilcrow" href="#section-18">¶</a>
|
||||
</div>
|
||||
<p>Handle Ctrl-v</p>
|
||||
|
||||
@@ -404,11 +444,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-17">
|
||||
<li id="section-19">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
<a class="pilcrow" href="#section-19">¶</a>
|
||||
</div>
|
||||
<p>allow arbitrarily switching between modes any time before multiple lines are entered</p>
|
||||
|
||||
@@ -423,11 +463,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-18">
|
||||
<li id="section-20">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-18">¶</a>
|
||||
<a class="pilcrow" href="#section-20">¶</a>
|
||||
</div>
|
||||
<p>no-op unless the current line is empty</p>
|
||||
|
||||
@@ -438,11 +478,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-19">
|
||||
<li id="section-21">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-19">¶</a>
|
||||
<a class="pilcrow" href="#section-21">¶</a>
|
||||
</div>
|
||||
<p>eval, print, loop</p>
|
||||
|
||||
@@ -457,11 +497,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-20">
|
||||
<li id="section-22">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-20">¶</a>
|
||||
<a class="pilcrow" href="#section-22">¶</a>
|
||||
</div>
|
||||
<p>XXX: multiline hack</p>
|
||||
|
||||
@@ -479,11 +519,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-21">
|
||||
<li id="section-23">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-21">¶</a>
|
||||
<a class="pilcrow" href="#section-23">¶</a>
|
||||
</div>
|
||||
<p>Store and load command history from a file</p>
|
||||
|
||||
@@ -496,11 +536,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-22">
|
||||
<li id="section-24">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-22">¶</a>
|
||||
<a class="pilcrow" href="#section-24">¶</a>
|
||||
</div>
|
||||
<p>Get file info and at most maxSize of command history</p>
|
||||
|
||||
@@ -512,11 +552,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-23">
|
||||
<li id="section-25">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-23">¶</a>
|
||||
<a class="pilcrow" href="#section-25">¶</a>
|
||||
</div>
|
||||
<p>Read last <code>size</code> bytes from the file</p>
|
||||
|
||||
@@ -530,11 +570,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-24">
|
||||
<li id="section-26">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-24">¶</a>
|
||||
<a class="pilcrow" href="#section-26">¶</a>
|
||||
</div>
|
||||
<p>Set the history on the interpreter</p>
|
||||
|
||||
@@ -545,11 +585,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-25">
|
||||
<li id="section-27">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-25">¶</a>
|
||||
<a class="pilcrow" href="#section-27">¶</a>
|
||||
</div>
|
||||
<p>If the history file was truncated we should pop off a potential partial line</p>
|
||||
|
||||
@@ -560,11 +600,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-26">
|
||||
<li id="section-28">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-26">¶</a>
|
||||
<a class="pilcrow" href="#section-28">¶</a>
|
||||
</div>
|
||||
<p>Shift off the final blank newline</p>
|
||||
|
||||
@@ -582,11 +622,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-27">
|
||||
<li id="section-29">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-27">¶</a>
|
||||
<a class="pilcrow" href="#section-29">¶</a>
|
||||
</div>
|
||||
<p>Save the latest command in the file</p>
|
||||
|
||||
@@ -598,11 +638,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-28">
|
||||
<li id="section-30">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-28">¶</a>
|
||||
<a class="pilcrow" href="#section-30">¶</a>
|
||||
</div>
|
||||
<p>XXX: The SIGINT event from REPLServer is undocumented, so this is a bit fragile</p>
|
||||
|
||||
@@ -614,11 +654,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-29">
|
||||
<li id="section-31">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-29">¶</a>
|
||||
<a class="pilcrow" href="#section-31">¶</a>
|
||||
</div>
|
||||
<p>Add a command to show the history stack</p>
|
||||
|
||||
@@ -635,11 +675,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-30">
|
||||
<li id="section-32">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-30">¶</a>
|
||||
<a class="pilcrow" href="#section-32">¶</a>
|
||||
</div>
|
||||
<p>Node 0.11 changed API, a command such as ‘.help’ is now stored as ‘help’</p>
|
||||
|
||||
@@ -658,6 +698,44 @@ Unwrap that too.</p>
|
||||
|
||||
CoffeeScript.register()
|
||||
process.argv = [<span class="hljs-string">'coffee'</span>].concat process.argv[<span class="hljs-number">2.</span>.]
|
||||
<span class="hljs-keyword">if</span> opts.transpile
|
||||
<span class="hljs-keyword">try</span>
|
||||
transpile = {}
|
||||
transpile.transpile = <span class="hljs-built_in">require</span>(<span class="hljs-string">'babel-core'</span>).transform
|
||||
<span class="hljs-keyword">catch</span>
|
||||
<span class="hljs-built_in">console</span>.error <span class="hljs-string">'''
|
||||
To use --transpile with an interactive REPL, babel-core must be installed either in the current folder or globally:
|
||||
npm install --save-dev babel-core
|
||||
or
|
||||
npm install --global babel-core
|
||||
And you must save options to configure Babel in one of the places it looks to find its options.
|
||||
See http://coffeescript.org/#transpilation
|
||||
'''</span>
|
||||
process.exit <span class="hljs-number">1</span>
|
||||
transpile.options =
|
||||
filename: path.resolve process.cwd(), <span class="hljs-string">'<repl>'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-33">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-33">¶</a>
|
||||
</div>
|
||||
<p>Since the REPL compilation path is unique (in <code>eval</code> above), we need
|
||||
another way to get the <code>options</code> object attached to a module so that
|
||||
it knows later on whether it needs to be transpiled. In the case of
|
||||
the REPL, the only applicable option is <code>transpile</code>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> Module = <span class="hljs-built_in">require</span> <span class="hljs-string">'module'</span>
|
||||
originalModuleLoad = Module::load
|
||||
Module::load = <span class="hljs-function"><span class="hljs-params">(filename)</span> -></span>
|
||||
@options = transpile: transpile.options
|
||||
originalModuleLoad.call @, filename
|
||||
opts = merge replDefaults, opts
|
||||
repl = nodeREPL.start opts
|
||||
runInContext opts.prelude, repl.context, <span class="hljs-string">'prelude'</span> <span class="hljs-keyword">if</span> opts.prelude
|
||||
@@ -668,11 +746,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-31">
|
||||
<li id="section-34">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-31">¶</a>
|
||||
<a class="pilcrow" href="#section-34">¶</a>
|
||||
</div>
|
||||
<p>Adapt help inherited from the node REPL</p>
|
||||
|
||||
|
||||
@@ -676,7 +676,21 @@ class declaration or if-conditionals).</p>
|
||||
endImplicitObject()
|
||||
<span class="hljs-keyword">else</span>
|
||||
stack.pop()
|
||||
start = stack.pop()</pre></div></div>
|
||||
start = stack.pop()
|
||||
<span class="hljs-function">
|
||||
<span class="hljs-title">inControlFlow</span> = =></span>
|
||||
seenFor = @findTagsBackwards(i, [<span class="hljs-string">'FOR'</span>]) <span class="hljs-keyword">and</span> @findTagsBackwards(i, [<span class="hljs-string">'FORIN'</span>, <span class="hljs-string">'FOROF'</span>, <span class="hljs-string">'FORFROM'</span>])
|
||||
controlFlow = seenFor <span class="hljs-keyword">or</span> @findTagsBackwards i, [<span class="hljs-string">'WHILE'</span>, <span class="hljs-string">'UNTIL'</span>, <span class="hljs-string">'LOOP'</span>, <span class="hljs-string">'LEADING_WHEN'</span>]
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> controlFlow
|
||||
isFunc = <span class="hljs-literal">no</span>
|
||||
tagCurrentLine = token[<span class="hljs-number">2</span>].first_line
|
||||
@detectEnd i,
|
||||
<span class="hljs-function"><span class="hljs-params">(token, i)</span> -></span> token[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> LINEBREAKS
|
||||
(token, i) ->
|
||||
[prevTag, ,{first_line}] = tokens[i - <span class="hljs-number">1</span>] || []
|
||||
isFunc = tagCurrentLine <span class="hljs-keyword">is</span> first_line <span class="hljs-keyword">and</span> prevTag <span class="hljs-keyword">in</span> [<span class="hljs-string">'->'</span>, <span class="hljs-string">'=>'</span>]
|
||||
returnOnNegativeLevel: <span class="hljs-literal">yes</span>
|
||||
isFunc</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -698,7 +712,8 @@ Added support for spread dots on the left side: f …a</p>
|
||||
(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)
|
||||
<span class="hljs-keyword">not</span> nextToken.spaced <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> nextToken.newLine) <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> inControlFlow()
|
||||
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>
|
||||
startImplicitCall i + <span class="hljs-number">1</span>
|
||||
<span class="hljs-keyword">return</span> forward(<span class="hljs-number">2</span>)</pre></div></div>
|
||||
@@ -835,7 +850,9 @@ like e.g.:</p>
|
||||
stackItem[<span class="hljs-number">2</span>].sameLine = <span class="hljs-literal">no</span> <span class="hljs-keyword">if</span> isImplicitObject stackItem
|
||||
|
||||
newLine = prevTag <span class="hljs-keyword">is</span> <span class="hljs-string">'OUTDENT'</span> <span class="hljs-keyword">or</span> prevToken.newLine
|
||||
<span class="hljs-keyword">if</span> tag <span class="hljs-keyword">in</span> IMPLICIT_END <span class="hljs-keyword">or</span> tag <span class="hljs-keyword">in</span> CALL_CLOSERS <span class="hljs-keyword">and</span> newLine
|
||||
<span class="hljs-keyword">if</span> tag <span class="hljs-keyword">in</span> IMPLICIT_END <span class="hljs-keyword">or</span>
|
||||
(tag <span class="hljs-keyword">in</span> CALL_CLOSERS <span class="hljs-keyword">and</span> newLine) <span class="hljs-keyword">or</span>
|
||||
(tag <span class="hljs-keyword">in</span> [<span class="hljs-string">'..'</span>, <span class="hljs-string">'...'</span>] <span class="hljs-keyword">and</span> @findTagsBackwards(i, [<span class="hljs-string">"INDEX_START"</span>]))
|
||||
<span class="hljs-keyword">while</span> inImplicit()
|
||||
[stackTag, stackIdx, {sameLine, startsLine}] = stackTop()</pre></div></div>
|
||||
|
||||
@@ -852,7 +869,8 @@ like e.g.:</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> inImplicitCall() <span class="hljs-keyword">and</span> prevTag <span class="hljs-keyword">isnt</span> <span class="hljs-string">','</span>
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> inImplicitCall() <span class="hljs-keyword">and</span> prevTag <span class="hljs-keyword">isnt</span> <span class="hljs-string">','</span> <span class="hljs-keyword">or</span>
|
||||
(prevTag <span class="hljs-keyword">is</span> <span class="hljs-string">','</span> <span class="hljs-keyword">and</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'TERMINATOR'</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> nextTag?)
|
||||
endImplicitCall()</pre></div></div>
|
||||
|
||||
</li>
|
||||
@@ -916,7 +934,7 @@ e = <span class="hljs-number">2</span>
|
||||
</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">','</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @looksObjectish(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">and</span> inImplicitObject() <span class="hljs-keyword">and</span>
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">','</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @looksObjectish(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">and</span> inImplicitObject() <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> (@tag(i + <span class="hljs-number">2</span>) <span class="hljs-keyword">in</span> [<span class="hljs-string">'FOROF'</span>, <span class="hljs-string">'FORIN'</span>]) <span class="hljs-keyword">and</span>
|
||||
(nextTag <span class="hljs-keyword">isnt</span> <span class="hljs-string">'TERMINATOR'</span> <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> @looksObjectish(i + <span class="hljs-number">2</span>))</pre></div></div>
|
||||
|
||||
</li>
|
||||
@@ -1245,20 +1263,101 @@ blocks are added.</p>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> normalizeLines: <span class="hljs-function">-></span>
|
||||
starter = indent = outdent = <span class="hljs-literal">null</span>
|
||||
leading_switch_when = <span class="hljs-literal">null</span>
|
||||
leading_if_then = <span class="hljs-literal">null</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-50">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-50">¶</a>
|
||||
</div>
|
||||
<p>Count <code>THEN</code> tags</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> ifThens = []
|
||||
<span class="hljs-function">
|
||||
<span class="hljs-title">condition</span> = <span class="hljs-params">(token, i)</span> -></span>
|
||||
token[<span class="hljs-number">1</span>] <span class="hljs-keyword">isnt</span> <span class="hljs-string">';'</span> <span class="hljs-keyword">and</span> token[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> SINGLE_CLOSERS <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> (token[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'TERMINATOR'</span> <span class="hljs-keyword">and</span> @tag(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">in</span> EXPRESSION_CLOSE) <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> (token[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'ELSE'</span> <span class="hljs-keyword">and</span> starter <span class="hljs-keyword">isnt</span> <span class="hljs-string">'THEN'</span>) <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> (token[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'ELSE'</span> <span class="hljs-keyword">and</span>
|
||||
(starter <span class="hljs-keyword">isnt</span> <span class="hljs-string">'THEN'</span> <span class="hljs-keyword">or</span> (leading_if_then <span class="hljs-keyword">or</span> leading_switch_when))) <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> (token[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> [<span class="hljs-string">'CATCH'</span>, <span class="hljs-string">'FINALLY'</span>] <span class="hljs-keyword">and</span> starter <span class="hljs-keyword">in</span> [<span class="hljs-string">'->'</span>, <span class="hljs-string">'=>'</span>]) <span class="hljs-keyword">or</span>
|
||||
token[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> CALL_CLOSERS <span class="hljs-keyword">and</span>
|
||||
(@tokens[i - <span class="hljs-number">1</span>].newLine <span class="hljs-keyword">or</span> @tokens[i - <span class="hljs-number">1</span>][<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'OUTDENT'</span>)
|
||||
<span class="hljs-function">
|
||||
<span class="hljs-title">action</span> = <span class="hljs-params">(token, i)</span> -></span>
|
||||
ifThens.pop() <span class="hljs-keyword">if</span> token[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'ELSE'</span> <span class="hljs-keyword">and</span> starter <span class="hljs-keyword">is</span> <span class="hljs-string">'THEN'</span>
|
||||
@tokens.splice (<span class="hljs-keyword">if</span> @tag(i - <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">','</span> <span class="hljs-keyword">then</span> i - <span class="hljs-number">1</span> <span class="hljs-keyword">else</span> i), <span class="hljs-number">0</span>, outdent
|
||||
<span class="hljs-function">
|
||||
<span class="hljs-title">closeElseTag</span> = <span class="hljs-params">(tokens, i)</span> =></span>
|
||||
tlen = ifThens.length
|
||||
<span class="hljs-keyword">return</span> i <span class="hljs-keyword">unless</span> tlen > <span class="hljs-number">0</span>
|
||||
lastThen = ifThens.pop()
|
||||
[, outdentElse] = @indentation tokens[lastThen]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-51">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-51">¶</a>
|
||||
</div>
|
||||
<p>Insert <code>OUTDENT</code> to close inner <code>IF</code>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> outdentElse[<span class="hljs-number">1</span>] = tlen*<span class="hljs-number">2</span>
|
||||
tokens.splice(i, <span class="hljs-number">0</span>, outdentElse)</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-52">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-52">¶</a>
|
||||
</div>
|
||||
<p>Insert <code>OUTDENT</code> to close outer <code>IF</code>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> outdentElse[<span class="hljs-number">1</span>] = <span class="hljs-number">2</span>
|
||||
tokens.splice(i + <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, outdentElse)</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-53">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-53">¶</a>
|
||||
</div>
|
||||
<p>Remove outdents from the end.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> @detectEnd i + <span class="hljs-number">2</span>,
|
||||
<span class="hljs-function"><span class="hljs-params">(token, i)</span> -></span> token[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> [<span class="hljs-string">'OUTDENT'</span>, <span class="hljs-string">'TERMINATOR'</span>]
|
||||
(token, i) ->
|
||||
<span class="hljs-keyword">if</span> @tag(i) <span class="hljs-keyword">is</span> <span class="hljs-string">'OUTDENT'</span> <span class="hljs-keyword">and</span> @tag(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'OUTDENT'</span>
|
||||
tokens.splice i, <span class="hljs-number">2</span>
|
||||
i + <span class="hljs-number">2</span>
|
||||
|
||||
@scanTokens (token, i, tokens) ->
|
||||
[tag] = token
|
||||
conditionTag = tag <span class="hljs-keyword">in</span> [<span class="hljs-string">'->'</span>, <span class="hljs-string">'=>'</span>] <span class="hljs-keyword">and</span>
|
||||
@findTagsBackwards(i, [<span class="hljs-string">'IF'</span>, <span class="hljs-string">'WHILE'</span>, <span class="hljs-string">'FOR'</span>, <span class="hljs-string">'UNTIL'</span>, <span class="hljs-string">'SWITCH'</span>, <span class="hljs-string">'WHEN'</span>, <span class="hljs-string">'LEADING_WHEN'</span>, <span class="hljs-string">'['</span>, <span class="hljs-string">'INDEX_START'</span>]) <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> (@findTagsBackwards i, [<span class="hljs-string">'THEN'</span>, <span class="hljs-string">'..'</span>, <span class="hljs-string">'...'</span>])
|
||||
|
||||
<span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'TERMINATOR'</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">'ELSE'</span> <span class="hljs-keyword">and</span> @tag(i - <span class="hljs-number">1</span>) <span class="hljs-keyword">isnt</span> <span class="hljs-string">'OUTDENT'</span>
|
||||
tokens.splice i, <span class="hljs-number">1</span>, @indentation()...
|
||||
@@ -1275,10 +1374,31 @@ blocks are added.</p>
|
||||
tokens.splice i + <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, indent, outdent
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">1</span>
|
||||
<span class="hljs-keyword">if</span> tag <span class="hljs-keyword">in</span> SINGLE_LINERS <span class="hljs-keyword">and</span> @tag(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">isnt</span> <span class="hljs-string">'INDENT'</span> <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> (tag <span class="hljs-keyword">is</span> <span class="hljs-string">'ELSE'</span> <span class="hljs-keyword">and</span> @tag(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'IF'</span>)
|
||||
<span class="hljs-keyword">not</span> (tag <span class="hljs-keyword">is</span> <span class="hljs-string">'ELSE'</span> <span class="hljs-keyword">and</span> @tag(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'IF'</span>) <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> conditionTag
|
||||
starter = tag
|
||||
[indent, outdent] = @indentation tokens[i]
|
||||
indent.fromThen = <span class="hljs-literal">true</span> <span class="hljs-keyword">if</span> starter <span class="hljs-keyword">is</span> <span class="hljs-string">'THEN'</span>
|
||||
<span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'THEN'</span>
|
||||
leading_switch_when = @findTagsBackwards(i, [<span class="hljs-string">'LEADING_WHEN'</span>]) <span class="hljs-keyword">and</span> @tag(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'IF'</span>
|
||||
leading_if_then = @findTagsBackwards(i, [<span class="hljs-string">'IF'</span>]) <span class="hljs-keyword">and</span> @tag(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'IF'</span>
|
||||
ifThens.push i <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'THEN'</span> <span class="hljs-keyword">and</span> @findTagsBackwards(i, [<span class="hljs-string">'IF'</span>])</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-54">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-54">¶</a>
|
||||
</div>
|
||||
<p><code>ELSE</code> tag is not closed.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'ELSE'</span> <span class="hljs-keyword">and</span> @tag(i - <span class="hljs-number">1</span>) <span class="hljs-keyword">isnt</span> <span class="hljs-string">'OUTDENT'</span>
|
||||
i = closeElseTag tokens, i
|
||||
tokens.splice i + <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, indent
|
||||
@detectEnd i + <span class="hljs-number">2</span>, condition, action
|
||||
tokens.splice i, <span class="hljs-number">1</span> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'THEN'</span>
|
||||
@@ -1288,11 +1408,11 @@ blocks are added.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-50">
|
||||
<li id="section-55">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-50">¶</a>
|
||||
<a class="pilcrow" href="#section-55">¶</a>
|
||||
</div>
|
||||
<p>Tag postfix conditionals as such, so that we can parse them with a
|
||||
different precedence.</p>
|
||||
@@ -1320,11 +1440,11 @@ different precedence.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-51">
|
||||
<li id="section-56">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-51">¶</a>
|
||||
<a class="pilcrow" href="#section-56">¶</a>
|
||||
</div>
|
||||
<p>Generate the indentation tokens, based on another token on the same line.</p>
|
||||
|
||||
@@ -1345,11 +1465,11 @@ different precedence.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-52">
|
||||
<li id="section-57">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-52">¶</a>
|
||||
<a class="pilcrow" href="#section-57">¶</a>
|
||||
</div>
|
||||
<p>Look up a tag by token index.</p>
|
||||
|
||||
@@ -1360,11 +1480,11 @@ different precedence.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-53">
|
||||
<li id="section-58">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-53">¶</a>
|
||||
<a class="pilcrow" href="#section-58">¶</a>
|
||||
</div>
|
||||
<h2 id="constants">Constants</h2>
|
||||
|
||||
@@ -1373,11 +1493,11 @@ different precedence.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-54">
|
||||
<li id="section-59">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-54">¶</a>
|
||||
<a class="pilcrow" href="#section-59">¶</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1385,11 +1505,11 @@ different precedence.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-55">
|
||||
<li id="section-60">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-55">¶</a>
|
||||
<a class="pilcrow" href="#section-60">¶</a>
|
||||
</div>
|
||||
<p>List of the token pairs that must be balanced.</p>
|
||||
|
||||
@@ -1410,11 +1530,11 @@ different precedence.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-56">
|
||||
<li id="section-61">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-56">¶</a>
|
||||
<a class="pilcrow" href="#section-61">¶</a>
|
||||
</div>
|
||||
<p>The inverse mappings of <code>BALANCED_PAIRS</code> we’re trying to fix up, so we can
|
||||
look things up from either end.</p>
|
||||
@@ -1426,11 +1546,11 @@ look things up from either end.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-57">
|
||||
<li id="section-62">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-57">¶</a>
|
||||
<a class="pilcrow" href="#section-62">¶</a>
|
||||
</div>
|
||||
<p>The tokens that signal the start/end of a balanced pair.</p>
|
||||
|
||||
@@ -1446,11 +1566,11 @@ EXPRESSION_END = []
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-58">
|
||||
<li id="section-63">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-58">¶</a>
|
||||
<a class="pilcrow" href="#section-63">¶</a>
|
||||
</div>
|
||||
<p>Tokens that indicate the close of a clause of an expression.</p>
|
||||
|
||||
@@ -1461,11 +1581,11 @@ EXPRESSION_END = []
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-59">
|
||||
<li id="section-64">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-59">¶</a>
|
||||
<a class="pilcrow" href="#section-64">¶</a>
|
||||
</div>
|
||||
<p>Tokens that, if followed by an <code>IMPLICIT_CALL</code>, indicate a function invocation.</p>
|
||||
|
||||
@@ -1476,11 +1596,11 @@ EXPRESSION_END = []
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-60">
|
||||
<li id="section-65">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-60">¶</a>
|
||||
<a class="pilcrow" href="#section-65">¶</a>
|
||||
</div>
|
||||
<p>If preceded by an <code>IMPLICIT_FUNC</code>, indicates a function invocation.</p>
|
||||
|
||||
@@ -1500,11 +1620,11 @@ IMPLICIT_UNSPACED_CALL = [<span class="hljs-string">'+'</span>, <span class="hlj
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-61">
|
||||
<li id="section-66">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-61">¶</a>
|
||||
<a class="pilcrow" href="#section-66">¶</a>
|
||||
</div>
|
||||
<p>Tokens that always mark the end of an implicit call for single-liners.</p>
|
||||
|
||||
@@ -1516,11 +1636,11 @@ IMPLICIT_UNSPACED_CALL = [<span class="hljs-string">'+'</span>, <span class="hlj
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-62">
|
||||
<li id="section-67">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-62">¶</a>
|
||||
<a class="pilcrow" href="#section-67">¶</a>
|
||||
</div>
|
||||
<p>Single-line flavors of block expressions that have unclosed endings.
|
||||
The grammar can’t disambiguate them, so we insert the implicit indentation.</p>
|
||||
@@ -1533,11 +1653,11 @@ SINGLE_CLOSERS = [<span class="hljs-string">'TERMINATOR'</span>, <span class="
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-63">
|
||||
<li id="section-68">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-63">¶</a>
|
||||
<a class="pilcrow" href="#section-68">¶</a>
|
||||
</div>
|
||||
<p>Tokens that end a line.</p>
|
||||
|
||||
@@ -1548,11 +1668,11 @@ SINGLE_CLOSERS = [<span class="hljs-string">'TERMINATOR'</span>, <span class="
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-64">
|
||||
<li id="section-69">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-64">¶</a>
|
||||
<a class="pilcrow" href="#section-69">¶</a>
|
||||
</div>
|
||||
<p>Tokens that close open calls when they follow a newline.</p>
|
||||
|
||||
@@ -1563,11 +1683,11 @@ SINGLE_CLOSERS = [<span class="hljs-string">'TERMINATOR'</span>, <span class="
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-65">
|
||||
<li id="section-70">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-65">¶</a>
|
||||
<a class="pilcrow" href="#section-70">¶</a>
|
||||
</div>
|
||||
<p>Tokens that prevent a subsequent indent from ending implicit calls/objects</p>
|
||||
|
||||
@@ -1578,11 +1698,11 @@ SINGLE_CLOSERS = [<span class="hljs-string">'TERMINATOR'</span>, <span class="
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-66">
|
||||
<li id="section-71">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-66">¶</a>
|
||||
<a class="pilcrow" href="#section-71">¶</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
|
||||
@@ -1596,8 +1716,8 @@ the node that becomes <code>StringWithInterpolations</code>, and therefore
|
||||
<div class="content"><div class='highlight'><pre>DISCARDED = [<span class="hljs-string">'('</span>, <span class="hljs-string">')'</span>, <span class="hljs-string">'['</span>, <span class="hljs-string">']'</span>, <span class="hljs-string">'{'</span>, <span class="hljs-string">'}'</span>, <span class="hljs-string">'.'</span>, <span class="hljs-string">'..'</span>, <span class="hljs-string">'...'</span>, <span class="hljs-string">','</span>, <span class="hljs-string">'='</span>, <span class="hljs-string">'++'</span>, <span class="hljs-string">'--'</span>, <span class="hljs-string">'?'</span>,
|
||||
<span class="hljs-string">'AS'</span>, <span class="hljs-string">'AWAIT'</span>, <span class="hljs-string">'CALL_START'</span>, <span class="hljs-string">'CALL_END'</span>, <span class="hljs-string">'DEFAULT'</span>, <span class="hljs-string">'ELSE'</span>, <span class="hljs-string">'EXTENDS'</span>, <span class="hljs-string">'EXPORT'</span>,
|
||||
<span class="hljs-string">'FORIN'</span>, <span class="hljs-string">'FOROF'</span>, <span class="hljs-string">'FORFROM'</span>, <span class="hljs-string">'IMPORT'</span>, <span class="hljs-string">'INDENT'</span>, <span class="hljs-string">'INDEX_SOAK'</span>, <span class="hljs-string">'LEADING_WHEN'</span>,
|
||||
<span class="hljs-string">'OUTDENT'</span>, <span class="hljs-string">'PARAM_START'</span>, <span class="hljs-string">'PARAM_END'</span>, <span class="hljs-string">'REGEX_START'</span>, <span class="hljs-string">'REGEX_END'</span>, <span class="hljs-string">'RETURN'</span>,
|
||||
<span class="hljs-string">'STRING_END'</span>, <span class="hljs-string">'THROW'</span>, <span class="hljs-string">'UNARY'</span>, <span class="hljs-string">'YIELD'</span>
|
||||
<span class="hljs-string">'OUTDENT'</span>, <span class="hljs-string">'PARAM_END'</span>, <span class="hljs-string">'REGEX_START'</span>, <span class="hljs-string">'REGEX_END'</span>, <span class="hljs-string">'RETURN'</span>, <span class="hljs-string">'STRING_END'</span>, <span class="hljs-string">'THROW'</span>,
|
||||
<span class="hljs-string">'UNARY'</span>, <span class="hljs-string">'YIELD'</span>
|
||||
].concat IMPLICIT_UNSPACED_CALL.concat IMPLICIT_END.concat CALL_CLOSERS.concat CONTROL_IN_IMPLICIT</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -139,12 +139,14 @@ with external scopes.</p>
|
||||
as well as a reference to the <strong>Block</strong> node it belongs to, which is
|
||||
where it should declare its variables, a reference to the function that
|
||||
it belongs to, and a list of variables referenced in the source code
|
||||
and therefore should be avoided when generating variables.</p>
|
||||
and therefore should be avoided when generating variables. Also track comments
|
||||
that should be output as part of variable declarations.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> constructor: <span class="hljs-function"><span class="hljs-params">(@parent, @expressions, @method, @referencedVars)</span> -></span>
|
||||
@variables = [{name: <span class="hljs-string">'arguments'</span>, type: <span class="hljs-string">'arguments'</span>}]
|
||||
@comments = {}
|
||||
@positions = {}
|
||||
@utilities = {} <span class="hljs-keyword">unless</span> @parent</pre></div></div>
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
3076
docs/v2/test.html
3076
docs/v2/test.html
File diff suppressed because it is too large
Load Diff
4
documentation/examples/breaking_change_super_this.coffee
Normal file
4
documentation/examples/breaking_change_super_this.coffee
Normal file
@@ -0,0 +1,4 @@
|
||||
class B extends A
|
||||
constructor: (arg) ->
|
||||
super arg
|
||||
@arg = arg
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
# @flow
|
||||
|
||||
fn = (str ###: string ###, num ###: number ###) ###: string ### ->
|
||||
str + num
|
||||
###::
|
||||
type Obj = {
|
||||
num: number,
|
||||
};
|
||||
###
|
||||
|
||||
fn = (str ###: string ###, obj ###: Obj ###) ###: string ### ->
|
||||
str + obj.num
|
||||
|
||||
@@ -9,13 +9,6 @@ Class constructors can’t be invoked without `new`:
|
||||
# Throws a TypeError at runtime
|
||||
```
|
||||
|
||||
Derived (extended) class `constructor`s cannot use `this` before calling `super`:
|
||||
|
||||
```coffee
|
||||
class B extends A
|
||||
constructor: -> this # Throws a compiler error
|
||||
```
|
||||
|
||||
ES2015 classes don’t allow bound (fat arrow) methods. The CoffeeScript compiler goes through some contortions to preserve support for them, but one thing that can’t be accommodated is calling a bound method before it is bound:
|
||||
|
||||
```coffee
|
||||
|
||||
20
documentation/sections/breaking_changes_super_this.md
Normal file
20
documentation/sections/breaking_changes_super_this.md
Normal file
@@ -0,0 +1,20 @@
|
||||
### `super` and `this`
|
||||
|
||||
In the constructor of a derived class (a class that `extends` another class), `this` cannot be used before calling `super`:
|
||||
|
||||
```coffee
|
||||
class B extends A
|
||||
constructor: -> this # Throws a compiler error
|
||||
```
|
||||
This also means you cannot pass a reference to `this` as an argument to `super` in the constructor of a derived class:
|
||||
|
||||
```coffee
|
||||
class B extends A
|
||||
constructor: (@arg) ->
|
||||
super @arg # Throws a compiler error
|
||||
```
|
||||
This is a limitation of ES2015 classes. As a workaround, assign to `this` after the `super` call:
|
||||
|
||||
```
|
||||
codeFor('breaking_change_super_this')
|
||||
```
|
||||
@@ -1,7 +1,111 @@
|
||||
## Changelog
|
||||
|
||||
```
|
||||
releaseHeader('2017-09-17', '2.0.0', '2.0.0-beta5')
|
||||
releaseHeader('2018-04-29', '2.3.0', '2.2.4')
|
||||
```
|
||||
* This release adds support for all the new features and syntaxes in ES2018 that weren’t already possible in CoffeeScript. For all of the below features, make sure that you [transpile](#transpilation) unless you know that your target runtime(s) support each feature.
|
||||
* Asynchronous iterators are now supported. You can now `yield` an `await` call, e.g. `do -> until file.EOF then yield await file.readLine()`.
|
||||
* Object splats/destructuring, a.k.a. object rest/spread syntax, has been standardized as part of ES2018 and therefore this release removes the polyfill that had previously been supporting this syntax. Code like `{a, b, rest...} = obj` now outputs more or less just like it appears, rather than being converted into an `Object.assign` call. Note that there are [some subtle differences](https://developers.google.com/web/updates/2017/06/object-rest-spread) between the `Object.assign` polyfill and the native implementation.
|
||||
* The exponentiation operator, `**`, and exponentiation assignment operator `**=` are new to JavaScript in ES2018. Now code like `a ** 3` is output as it appears, rather than being converted into `Math.pow(a, 3)` as it was before.
|
||||
* The `s` (dotAll) flag is now supported in regular expressions.
|
||||
|
||||
```
|
||||
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 key’s 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')
|
||||
```
|
||||
* This release fixes *all* currently open bugs, dating as far back as 2014, 2012 and 2011.
|
||||
* **Potential breaking change:** An inline `if` or `switch` statement with an ambiguous `else`, such as `if no then if yes then alert 1 else alert 2`, now compiles where the `else` always corresponds to the closest open `then`. Previously the behavior of an ambiguous `else` was unpredictable. If your code has any `if … then` or `switch … then` statements with multiple `then`s (and one or more `else`s) the compiled output might be different now, unless you had resolved ambiguity via parentheses. We made this change because the previous behavior was inconsistent and basically a bug: depending on what grammar was where, for example if there was an inline function or something that implied a block, the `else` might bind to an earlier `then` rather than a later `then`. Now an `else` essentially closes a block opened by a `then`, similar to closing an open parenthesis.
|
||||
* When a required `then` is missing, the error more accurately points out the location of the mistake.
|
||||
* An error is thrown when the `coffee` command is run in an environment that doesn’t support some ES2015 JavaScript features that the CoffeeScript compiler itself requires. This can happen if CoffeeScript is installed in Node older than version 6.
|
||||
* Destructuring with a non-final splat/spread, e.g. `[open, contents..., close] = tag.split('')` is now output using ES2015 rest syntax.
|
||||
* Functions named `get` or `set` can be used without parentheses in more cases, including when attached to `this` or `@` or `?.`; or when the first argument is an implicit object, e.g. `@set key: 'val'`.
|
||||
* Statements such as `break` can now be used inside parentheses, e.g. `(doSomething(); break) while condition` or `(pick(key); break) for key of obj`.
|
||||
* Bugfix for assigning to a property attached to `this`/`@` in destructuring, e.g. `({@prop = yes, @otherProp = no}) ->`.
|
||||
* Bugfix for incorrect errors being thrown about calling `super` with a parameter attached to `this` when said parameter is in a lower scope, e.g. `class Child extends Parent then constructor: -> super(-> @prop)`.
|
||||
* Bugfix to prevent a possible infinite loop when a `for` loop is given a variable to step by, e.g. `for x in [1..3] by step` (as opposed to `by 0.5` or some other primitive numeric value).
|
||||
* Bugfix to no longer declare iterator variables twice when evaluating a range, e.g. `end = 3; fn [0..end]`.
|
||||
* Bugfix for incorrect scope of variables in chained calls, e.g. `start(x = 3).then(-> x = 4)`.
|
||||
* Bugfix for incorrect scope of variables in a function passed to `do`, e.g. `for [1..3] then masked = 10; do -> alert masked`.
|
||||
* Bugfix to no longer throw a syntax error for a trailing comma in a function call, e.g. `fn arg1, arg2,`.
|
||||
* Bugfix for an expression in a property access, e.g. `a[!b in c..]`.
|
||||
* Bugfix to allow a line continuation backslash (`\`) at any point in a `for` line.
|
||||
|
||||
```
|
||||
releaseHeader('2017-12-29', '2.1.1', '2.1.0')
|
||||
```
|
||||
|
||||
* Bugfix to set the correct context for executable class bodies. So in `class @B extends @A then @property = 1`, the `@` in `@property` now refers to the class, not the global object.
|
||||
* Bugfix where anonymous classes were getting created using the same automatic variable name. They now each receive unique names, so as not to override each other.
|
||||
|
||||
|
||||
```
|
||||
releaseHeader('2017-12-10', '2.1.0', '2.0.3')
|
||||
```
|
||||
|
||||
* Computed property keys in object literals are now supported: `obj = { ['key' + i]: 42 }`, or `obj = [Symbol.iterator]: -> yield i++`.
|
||||
* Skipping of array elements, a.k.a. elision, is now supported: `arr = [a, , b]`, or `[, protocol] = url.match /^(.*):\/\//`.
|
||||
* [JSX fragments syntax](https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html) is now supported.
|
||||
* Bugfix where `///` within a `#` line comment inside a `///` block regex was erroneously closing the regex, rather than being treated as part of the comment.
|
||||
* Bugfix for incorrect output for object rest destructuring inside array destructuring.
|
||||
|
||||
```
|
||||
releaseHeader('2017-11-26', '2.0.3', '2.0.2')
|
||||
```
|
||||
|
||||
* Bugfix for `export default` followed by an implicit object that contains an explicit object, for example `exportedMember: { obj... }`.
|
||||
* Bugfix for `key, val of obj` after an implicit object member, e.g. `foo: bar for key, val of obj`.
|
||||
* Bugfix for combining array and object destructuring, e.g. `[ ..., {a, b} ] = arr`.
|
||||
* Bugfix for an edge case where it was possible to create a bound (`=>`) generator function, which should throw an error as such functions aren’t allowed in ES2015.
|
||||
* Bugfix for source maps: `.map` files should always have the same base filename as the requested output filename. So `coffee --map --output foo.js test.coffee` should generate `foo.js` and `foo.js.map`.
|
||||
* Bugfix for incorrect source maps generated when using `--transpile` with `--map` for multiple input files.
|
||||
* Bugfix for comments at the beginning or end of input into the REPL (`coffee --interactive`).
|
||||
|
||||
```
|
||||
releaseHeader('2017-10-26', '2.0.2', '2.0.1')
|
||||
```
|
||||
* `--transpile` now also applies to `require`d or `import`ed CoffeeScript files.
|
||||
* `--transpile` can be used with the REPL: `coffee --interactive --transpile`.
|
||||
* Improvements to comments output that should now cover all of the [Flow comment-based syntax](https://flow.org/en/docs/types/comments/). Inline `###` comments near [variable](https://flow.org/en/docs/types/variables/) initial assignments are now output in the variable declaration statement, and `###` comments near a [class and method names](https://flow.org/en/docs/types/generics/) are now output where Flow expects them.
|
||||
* Importing CoffeeScript keywords is now allowed, so long as they’re aliased: `import { and as andFn } from 'lib'`. (You could also do `import lib from 'lib'` and then reference `lib.and`.)
|
||||
* Calls to functions named `get` and `set` no longer throw an error when given a bracketless object literal as an argument: `obj.set propertyName: propertyValue`.
|
||||
* In the constructor of a derived class (a class that `extends` another class), you cannot call `super` with an argument that references `this`: `class Child extends Parent then constructor: (@arg) -> super(@arg)`. This isn’t allowed in JavaScript, and now the CoffeeScript compiler will throw an error. Instead, assign to `this` after calling `super`: `(arg) -> super(arg); @arg = arg`.
|
||||
* Bugfix for incorrect output when backticked statements and hoisted expressions were both in the same class body. This allows a backticked line like `` `field = 3` ``, for people using the experimental [class fields](https://github.com/tc39/proposal-class-fields) syntax, in the same class along with traditional class body expressions like `prop: 3` that CoffeeScript outputs as part of the class prototype.
|
||||
* Bugfix for comments not output before a complex `?` operation, e.g. `@a ? b`.
|
||||
* All tests now pass in Windows.
|
||||
|
||||
```
|
||||
releaseHeader('2017-09-26', '2.0.1', '2.0.0')
|
||||
```
|
||||
|
||||
* `babel-core` is no longer listed in `package.json`, even as an `optionalDependency`, to avoid it being automatically installed for most users. If you wish to use `--transpile`, simply install `babel-core` manually. See [Transpilation](#transpilation).
|
||||
* `--transpile` now relies on Babel to find its options, i.e. the `.babelrc` file in the path of the file(s) being compiled. (Previously the CoffeeScript compiler was duplicating this logic, so nothing has changed from a user’s perspective.) This provides automatic support for additional ways to pass options to Babel in future versions, such as the `.babelrc.js` file coming in Babel 7.
|
||||
* Backticked expressions in a class body, outside any class methods, are now output in the JavaScript class body itself. This allows for passing through experimental JavaScript syntax like the [class fields proposal](https://github.com/tc39/proposal-class-fields), assuming your [transpiler supports it](https://babeljs.io/docs/plugins/transform-class-properties/).
|
||||
|
||||
```
|
||||
releaseHeader('2017-09-18', '2.0.0', '2.0.0-beta5')
|
||||
```
|
||||
|
||||
* Added `--transpile` flag or `transpile` Node API option to tell the CoffeeScript compiler to pipe its output through Babel before saving or returning it; see [Transpilation](#transpilation). Also changed the `-t` short flag to refer to `--transpile` instead of `--tokens`.
|
||||
@@ -184,7 +288,6 @@ releaseHeader('2016-09-24', '1.11.0', '1.10.0')
|
||||
* CoffeeScript now supports ES2015 [`import` and `export` syntax](#modules).
|
||||
* Added the `-M, --inline-map` flag to the compiler, allowing you embed the source map directly into the output JavaScript, rather than as a separate file.
|
||||
* A bunch of fixes for `yield`:
|
||||
|
||||
* `yield return` can no longer mistakenly be used as an expression.
|
||||
* `yield` now mirrors `return` in that it can be used stand-alone as well as with expressions. Where you previously wrote `yield undefined`, you may now write simply `yield`. However, this means also inheriting the same syntax limitations that `return` has, so these examples no longer compile:
|
||||
```
|
||||
@@ -195,7 +298,6 @@ releaseHeader('2016-09-24', '1.11.0', '1.10.0')
|
||||
yield
|
||||
2 * 3
|
||||
```
|
||||
|
||||
* The JavaScript output is a bit nicer, with unnecessary parentheses and spaces, double indentation and double semicolons around `yield` no longer present.
|
||||
* `&&=`, `||=`, `and=` and `or=` no longer accidentally allow a space before the equals sign.
|
||||
* Improved several error messages.
|
||||
@@ -203,7 +305,6 @@ releaseHeader('2016-09-24', '1.11.0', '1.10.0')
|
||||
* Bugfix for renamed destructured parameters with defaults. `({a: b = 1}) ->` no longer crashes the compiler.
|
||||
* Improved the internal representation of a CoffeeScript program. This is only noticeable to tools that use `CoffeeScript.tokens` or `CoffeeScript.nodes`. Such tools need to update to take account for changed or added tokens and nodes.
|
||||
* Several minor bug fixes, including:
|
||||
|
||||
* The caught error in `catch` blocks is no longer declared unnecessarily, and no longer mistakenly named `undefined` for `catch`-less `try` blocks.
|
||||
* Unassignable parameter destructuring no longer crashes the compiler.
|
||||
* Source maps are now used correctly for errors thrown from .coffee.md files.
|
||||
@@ -219,7 +320,6 @@ releaseHeader('2015-09-03', '1.10.0', '1.9.3')
|
||||
* CoffeeScript now supports ES2015-style destructuring defaults.
|
||||
* `(offsetHeight: height) ->` no longer compiles. That syntax was accidental and partly broken. Use `({offsetHeight: height}) ->` instead. Object destructuring always requires braces.
|
||||
* Several minor bug fixes, including:
|
||||
|
||||
* A bug where the REPL would sometimes report valid code as invalid, based on what you had typed earlier.
|
||||
* A problem with multiple JS contexts in the jest test framework.
|
||||
* An error in io.js where strict mode is set on internal modules.
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
### Compatibility
|
||||
|
||||
With the exception of [modules](#modules) (`import` and `export` statements) and [JSX](#jsx), all the modern JavaScript features that CoffeeScript supports can run natively in Node 7.6+, meaning that Node can run CoffeeScript’s output without any further processing required. You can [run the tests in your browser](test.html) to see if your browser can do the same. For older browsers or older versions of Node, however, [transpilation](#transpilation) is required.
|
||||
Most modern JavaScript features that CoffeeScript supports can run natively in Node 7.6+, meaning that Node can run CoffeeScript’s output without any further processing required. Here are some notable exceptions:
|
||||
|
||||
Support for modern JavaScript syntax is important to ensure compatibility with frameworks that assume modern features. Now that CoffeeScript compiles classes to the `class` keyword, it’s possible to `extend` a JavaScript class; that wasn’t possible in CoffeeScript 1. Parity in how language features work is also important on its own; CoffeeScript “is just JavaScript,” and so things like [function parameter default values](#breaking-changes-default-values) should behave the same in CoffeeScript as in JavaScript. Some such features behave slightly differently in JavaScript than they did in CoffeeScript 1; in such cases we are conforming with the JavaScript spec, and we’ve documented the differences as [breaking changes](#breaking-changes).
|
||||
* [Modules](#modules) and [JSX](#jsx) always require transpilation.
|
||||
* [Splats, a.k.a. object rest/spread syntax, for objects](http://coffeescript.org/#splats) are supported by Node 8.6+.
|
||||
* The [regular expression `s` (dotall) flag](https://github.com/tc39/proposal-regexp-dotall-flag) is supported by Node 9+.
|
||||
* [Async generator functions](https://github.com/tc39/proposal-async-iteration) are supported by Node 10+.
|
||||
|
||||
This list may be incomplete, and excludes versions of Node that support newer features behind flags; please refer to [node.green](http://node.green/) for full details. You can [run the tests in your browser](test.html) to see what your browser supports. It is your responsibility to ensure that your runtime supports the modern features you use; or that you [transpile](#transpilation) your code. When in doubt, transpile.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Bound (Fat Arrow) Functions
|
||||
|
||||
In JavaScript, the `this` keyword is dynamically scoped to mean the object that the current function is attached to. If you pass a function as a callback or attach it to a different object, the original value of `this` will be lost. If you’re not familiar with this behavior, [this Digital Web article](http://64.13.255.16/articles/scope_in_javascript/) gives a good overview of the quirks.
|
||||
In JavaScript, the `this` keyword is dynamically scoped to mean the object that the current function is attached to. If you pass a function as a callback or attach it to a different object, the original value of `this` will be lost. If you’re not familiar with this behavior, [this Digital Web article](https://web.archive.org/web/20150316122013/http://www.digital-web.com/articles/scope_in_javascript) gives a good overview of the quirks.
|
||||
|
||||
The fat arrow `=>` can be used to both define a function, and to bind it to the current value of `this`, right on the spot. This is helpful when using callback-based libraries like Prototype or jQuery, for creating iterator functions to pass to `each`, or event-handler functions to use with `on`. Functions created with the fat arrow are able to access properties of the `this` where they’re defined.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Installation
|
||||
|
||||
The command-line version of `coffee` is available as a [Node.js](https://nodejs.org/) utility. The [core compiler](/v<%= majorVersion %>/browser-compiler/coffeescript.js) however, does not depend on Node, and can be run in any JavaScript environment, or in the browser (see [Try CoffeeScript](#try)).
|
||||
The command-line version of `coffee` is available as a [Node.js](https://nodejs.org/) utility, requiring Node 6 or later. The [core compiler](/v<%= majorVersion %>/browser-compiler/coffeescript.js) however, does not depend on Node, and can be run in any JavaScript environment, or in the browser (see [Try CoffeeScript](#try)).
|
||||
|
||||
To install, first make sure you have a working copy of the latest stable version of [Node.js](https://nodejs.org/). You can then install CoffeeScript globally with [npm](https://www.npmjs.com/):
|
||||
|
||||
@@ -10,10 +10,12 @@ npm install --global coffeescript
|
||||
|
||||
This will make the `coffee` and `cake` commands available globally.
|
||||
|
||||
When you need CoffeeScript as a dependency of a project, within that project’s folder you can install it locally:
|
||||
If you are using CoffeeScript in a project, you should install it locally for that project so that the version of CoffeeScript is tracked as one of your project’s dependencies. Within that project’s folder:
|
||||
|
||||
```bash
|
||||
npm install --save-dev coffeescript
|
||||
```
|
||||
|
||||
The `coffee` and `cake` commands will first look in the current folder to see if CoffeeScript is installed locally, and use that version if so. This allows different versions of CoffeeScript to be installed globally and locally.
|
||||
|
||||
If you plan to use the `--transpile` option (see [Transpilation](#transpilation)) you will need to also install `babel-core` either globally or locally, depending on whether you are running a globally or locally installed version of CoffeeScript.
|
||||
@@ -5,5 +5,9 @@ The golden rule of CoffeeScript is: _“It’s just JavaScript.”_ The code com
|
||||
**Latest Version:** [<%= fullVersion %>](https://github.com/jashkenas/coffeescript/tarball/<%= fullVersion %>)
|
||||
|
||||
```bash
|
||||
npm install -g coffeescript
|
||||
# Install locally for a project:
|
||||
npm install --save-dev coffeescript
|
||||
|
||||
# Install globally to execute .coffee files anywhere:
|
||||
npm install --global coffeescript
|
||||
```
|
||||
|
||||
@@ -8,6 +8,6 @@ codeFor('modules')
|
||||
|
||||
<div id="modules-note" class="bookmark"></div>
|
||||
|
||||
Note that the CoffeeScript compiler **does not resolve modules**; writing an `import` or `export` statement in CoffeeScript will produce an `import` or `export` statement in the resulting output. It is your responsibility attach another transpiler, such as [Traceur Compiler](https://github.com/google/traceur-compiler), [Babel](http://babeljs.io/) or [Rollup](https://github.com/rollup/rollup), to convert this ES2015 syntax into code that will work in your target runtimes.
|
||||
Note that the CoffeeScript compiler **does not resolve modules**; writing an `import` or `export` statement in CoffeeScript will produce an `import` or `export` statement in the resulting output. It is your responsibility to [transpile](#transpilation) this ES2015 syntax into code that will work in your target runtimes.
|
||||
|
||||
Also note that any file with an `import` or `export` statement will be output without a [top-level function safety wrapper](#lexical-scope); in other words, importing or exporting modules will automatically trigger [bare](#usage) mode for that file. This is because per the ES2015 spec, `import` or `export` statements must occur at the topmost scope.
|
||||
|
||||
@@ -6,12 +6,6 @@ The CoffeeScript literals for objects and arrays look very similar to their Java
|
||||
codeFor('objects_and_arrays', 'song.join(" … ")')
|
||||
```
|
||||
|
||||
In JavaScript, you can’t use reserved words, like `class`, as properties of an object, without quoting them as strings. CoffeeScript notices reserved words used as keys in objects and quotes them for you, so you don’t have to worry about it (say, when using jQuery).
|
||||
|
||||
```
|
||||
codeFor('objects_reserved')
|
||||
```
|
||||
|
||||
CoffeeScript has a shortcut for creating objects when you want the key to be set with a variable of the same name.
|
||||
|
||||
```
|
||||
|
||||
@@ -18,7 +18,7 @@ You can use `in` to test for array presence, and `of` to test for JavaScript obj
|
||||
|
||||
In a `for` loop, `from` compiles to the [ES2015 `of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of). (Yes, it’s unfortunate; the CoffeeScript `of` predates the ES2015 `of`.)
|
||||
|
||||
To simplify math expressions, `**` can be used for exponentiation and `//` performs integer division. `%` works just like in JavaScript, while `%%` provides [“dividend dependent modulo”](https://en.wikipedia.org/wiki/Modulo_operation):
|
||||
To simplify math expressions, `**` can be used for exponentiation and `//` performs floor division. `%` works just like in JavaScript, while `%%` provides [“dividend dependent modulo”](https://en.wikipedia.org/wiki/Modulo_operation):
|
||||
|
||||
```
|
||||
codeFor('modulo')
|
||||
@@ -39,7 +39,7 @@ All together now:
|
||||
| `a in b` | `[].indexOf.call(b, a) >= 0` |
|
||||
| `a of b` | `a in b` |
|
||||
| `for a from b` | `for (a of b)` |
|
||||
| `a ** b` | `Math.pow(a, b)` |
|
||||
| `a ** b` | `a ** b` |
|
||||
| `a // b` | `Math.floor(a / b)` |
|
||||
| `a %% b` | `(a % b + b) % b` |
|
||||
|
||||
|
||||
@@ -11,5 +11,5 @@
|
||||
Perhaps your CoffeeScript-related question has been asked before. Check the FAQ first.
|
||||
* [JS2Coffee](http://js2.coffee/)<br>
|
||||
Is a very well done reverse JavaScript-to-CoffeeScript compiler. It’s not going to be perfect (infer what your JavaScript classes are, when you need bound functions, and so on…) — but it’s a great starting point for converting simple scripts.
|
||||
* [High-Rez Logo](https://github.com/jashkenas/coffeescript/tree/master/documentation/images)<br>
|
||||
* [High-Rez Logo](https://github.com/jashkenas/coffeescript/tree/master/documentation/site)<br>
|
||||
The CoffeeScript logo is available in SVG for use in presentations.
|
||||
|
||||
@@ -2,6 +2,4 @@
|
||||
|
||||
While it’s not recommended for serious use, CoffeeScripts may be included directly within the browser using `<script type="text/coffeescript">` tags. The source includes a compressed and minified version of the compiler ([Download current version here, 51k when gzipped](/v<%= majorVersion %>/browser-compiler/coffeescript.js)) as `docs/v<%= majorVersion %>/browser-compiler/coffeescript.js`. Include this file on a page with inline CoffeeScript tags, and it will compile and evaluate them in order.
|
||||
|
||||
In fact, the little bit of glue script that runs [Try CoffeeScript](#try), as well as the code examples and other interactive parts of this site, is implemented in just this way. View source and look at the bottom of the page to see the example. Including the script also gives you access to `CoffeeScript.compile()` so you can pop open your JavaScript console and try compiling some strings.
|
||||
|
||||
The usual caveats about CoffeeScript apply — your inline scripts will run within a closure wrapper, so if you want to expose global variables or functions, attach them to the `window` object.
|
||||
|
||||
@@ -22,4 +22,4 @@ codeFor('array_spread', 'all')
|
||||
codeFor('object_spread', 'JSON.stringify(currentUser)')
|
||||
```
|
||||
|
||||
In ECMAScript this is called [spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator), and has been supported for arrays since ES2015 but is [coming soon for objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator#Spread_in_object_literals). Until object spread syntax is officially supported, the CoffeeScript compiler outputs the same polyfill as [Babel’s rest spread transform](https://babeljs.io/docs/plugins/transform-object-rest-spread/); but once it is supported, we will revise the compiler’s output. Note that there are [very subtle differences](https://developers.google.com/web/updates/2017/06/object-rest-spread) between the polyfill and the current proposal.
|
||||
In ECMAScript this is called [spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator), and has been supported for arrays since ES2015 and objects since ES2018.
|
||||
@@ -1,6 +1,6 @@
|
||||
### Transpilation
|
||||
|
||||
CoffeeScript 2 generates JavaScript that uses the latest, modern syntax. Your runtime [might not support all of that syntax](#compatibility). If so, you need to _transpile_ the JavaScript. To make things a little easier, CoffeeScript has built-in support for the popular [Babel](http://babeljs.io/) transpiler.
|
||||
CoffeeScript 2 generates JavaScript that uses the latest, modern syntax. The runtime or browsers where you want your code to run [might not support all of that syntax](#compatibility). In that case, we want to convert modern JavaScript into older JavaScript that will run in older versions of Node or older browsers; for example, `{ a } = obj` into `a = obj.a`. This is done via transpilers like [Babel](http://babeljs.io/), [Bublé](https://buble.surge.sh/) or [Traceur Compiler](https://github.com/google/traceur-compiler).
|
||||
|
||||
#### Quickstart
|
||||
|
||||
@@ -12,29 +12,29 @@ echo '{ "presets": ["env"] }' > .babelrc
|
||||
coffee --compile --transpile --inline-map some-file.coffee
|
||||
```
|
||||
|
||||
#### About Transpilation
|
||||
#### Transpiling with the CoffeeScript compiler
|
||||
|
||||
Transpilation is the conversion of source code into equivalent but different source code. In our case, we want to convert modern JavaScript into older JavaScript that will run in older versions of Node or older browsers; for example, `{ a } = obj` into `a = obj.a`. This is done via transpilers like [Babel](http://babeljs.io/), [Bublé](https://buble.surge.sh/) or [Traceur Compiler](https://github.com/google/traceur-compiler).
|
||||
|
||||
CoffeeScript includes a `--transpile` option when used via the `coffee` command, or a `transpile` option when used via Node. To use either, [Babel](http://babeljs.io/) must be installed in your project:
|
||||
To make things easy, CoffeeScript has built-in support for the popular [Babel](http://babeljs.io/) transpiler. You can use it via the `--transpile` command-line option or the `transpile` Node API option. To use either, `babel-core` must be installed in your project:
|
||||
|
||||
```bash
|
||||
npm install --save-dev babel-core
|
||||
```
|
||||
|
||||
By default, Babel doesn’t do anything—it doesn’t make assumptions about what you want to transpile to. You might know that your code will run in Node 8, and so you want Babel to transpile modules and JSX and nothing else. Or you might want to support Internet Explorer 8, in which case Babel will transpile every feature introduced in ES2015 and later specs.
|
||||
|
||||
If you’re not sure what you need, a good starting point is [`babel-preset-env`](https://babeljs.io/docs/plugins/preset-env/):
|
||||
Or if you’re running the `coffee` command outside of a project folder, using a globally-installed `coffeescript` module, `babel-core` needs to be installed globally:
|
||||
|
||||
```bash
|
||||
npm install --save-dev babel-preset-env
|
||||
npm install --global babel-core
|
||||
```
|
||||
|
||||
See [Babel’s website to learn about presets and plugins](https://babeljs.io/docs/plugins/) and the multitude of options you have.
|
||||
By default, Babel doesn’t do anything—it doesn’t make assumptions about what you want to transpile to. You need to provide it with a configuration so that it knows what to do. One way to do this is by creating a [`.babelrc` file](https://babeljs.io/docs/usage/babelrc/) in the folder containing the files you’re compiling, or in any parent folder up the path above those files. (Babel supports [other ways](https://babeljs.io/docs/usage/babelrc/), too.) A minimal `.babelrc` file would be just `{ "presets": ["env"] }`. This implies that you have installed [`babel-preset-env`](https://babeljs.io/docs/plugins/preset-env/):
|
||||
|
||||
Simply installing `babel-preset-env` isn’t enough. You also need to define the configuration options that you want Babel to use. You can do this by creating a [`.babelrc` file](https://babeljs.io/docs/usage/babelrc/) in the folder containing the files you’re compiling, or in any parent folder up the path above those files. So if your project is in `~/app` and your files are in `~/app/src`, you can put `.babelrc` in either `~/app` or in `~/app/src`. You can also define the Babel options via a `babel` key in the `package.json` file for your project. A minimal `.babelrc` file (or `package.json` `babel` key) for use with `babel-preset-env` would be just `{ "presets": ["env"] }`.
|
||||
```bash
|
||||
npm install --save-dev babel-preset-env # Or --global for non-project-based usage
|
||||
```
|
||||
|
||||
Once you have `babel-core` and `babel-preset-env` (or other presets or plugins) installed, and a `.babelrc` file (or `package.json` `babel` key) in place, you can use `coffee --transpile` to pipe CoffeeScript’s output through Babel using the options you’ve saved.
|
||||
See [Babel’s website to learn about presets and plugins](https://babeljs.io/docs/plugins/) and the multitude of options you have. Another preset you might need is [`transform-react-jsx`](https://babeljs.io/docs/plugins/transform-react-jsx/) if you’re using JSX with React (JSX can also be used with other frameworks).
|
||||
|
||||
Once you have `babel-core` and `babel-preset-env` (or other presets or plugins) installed, and a `.babelrc` file (or other equivalent) in place, you can use `coffee --transpile` to pipe CoffeeScript’s output through Babel using the options you’ve saved.
|
||||
|
||||
If you’re using CoffeeScript via the [Node API](nodejs_usage), where you call `CoffeeScript.compile` with a string to be compiled and an `options` object, the `transpile` key of the `options` object should be the Babel options:
|
||||
|
||||
@@ -44,4 +44,6 @@ CoffeeScript.compile(code, {transpile: {presets: ['env']}})
|
||||
|
||||
You can also transpile CoffeeScript’s output without using the `transpile` option, for example as part of a build chain. This lets you use transpilers other than Babel, and it gives you greater control over the process. There are many great task runners for setting up JavaScript build chains, such as [Gulp](http://gulpjs.com/), [Webpack](https://webpack.github.io/), [Grunt](https://gruntjs.com/) and [Broccoli](http://broccolijs.com/).
|
||||
|
||||
Note that [babel-preset-env](https://babeljs.io/docs/plugins/preset-env/) doesn’t automatically supply [polyfills](https://developer.mozilla.org/en-US/docs/Glossary/Polyfill) 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. You’ll also need to supply polyfills if your own code uses these methods or another method added in recent versions of JavaScript. One polyfill 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/).
|
||||
#### Polyfills
|
||||
|
||||
Note that transpiling doesn’t automatically supply [polyfills](https://developer.mozilla.org/en-US/docs/Glossary/Polyfill) 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. You’ll also need to supply polyfills if your own code uses these methods or another method added in recent versions of JavaScript. One polyfill 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/).
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
### Why CoffeeScript When There’s ES6?
|
||||
|
||||
CoffeeScript introduced many new features to the JavaScript world, such as [`=>`](#fat-arrow) and [destructuring](#destructuring) and [classes](#classes). We are happy that ECMA has seen their utility and adopted them into ECMAScript.
|
||||
|
||||
CoffeeScript’s intent, however, was never to be a superset of JavaScript. One of the guiding principles of CoffeeScript has been _simplicity:_ not just removing JavaScript’s “bad parts,” but providing an elegant, concise syntax that eschews unnecessary punctuation whenever possible, to make code easier to read and reason about. This benefit of CoffeeScript remains, even in an ES2015+ world.
|
||||
@@ -3,13 +3,15 @@
|
||||
<%= include('try.html') %>
|
||||
|
||||
<div class="container-fluid" id="top">
|
||||
<div class="row flex-nowrap">
|
||||
<nav class="sidebar col-lg-3 bg-ribbed-light">
|
||||
<div class="row flex-nowrap main-row">
|
||||
<nav class="sidebar bg-ribbed-light">
|
||||
<%= include('sidebar.html') %>
|
||||
</nav>
|
||||
<main class="main col-lg-9 ml-auto">
|
||||
<header class="title-logo d-none d-lg-block">
|
||||
<%= include('logo.svg') %>
|
||||
<main class="main">
|
||||
<header class="d-none d-lg-block">
|
||||
<p class="title-logo">
|
||||
<%= include('logo.svg') %>
|
||||
</p>
|
||||
</header>
|
||||
<section id="overview">
|
||||
<%= htmlFor('introduction') %>
|
||||
@@ -20,9 +22,6 @@
|
||||
<section id="whats-new-in-coffeescript-2">
|
||||
<%= htmlFor('whats_new_in_coffeescript_2') %>
|
||||
</section>
|
||||
<section id="why-coffeescript">
|
||||
<%= htmlFor('why_coffeescript') %>
|
||||
</section>
|
||||
<section id="compatibility">
|
||||
<%= htmlFor('compatibility') %>
|
||||
</section>
|
||||
@@ -188,6 +187,9 @@
|
||||
<section id="breaking-changes-classes">
|
||||
<%= htmlFor('breaking_changes_classes') %>
|
||||
</section>
|
||||
<section id="breaking-changes-super-this">
|
||||
<%= htmlFor('breaking_changes_super_this') %>
|
||||
</section>
|
||||
<section id="breaking-changes-super-extends">
|
||||
<%= htmlFor('breaking_changes_super_extends') %>
|
||||
</section>
|
||||
|
||||
@@ -1,20 +1,41 @@
|
||||
/* Adapted from https://github.com/FarhadG/code-mirror-themes/blob/master/themes/twilight.css */
|
||||
/* Adapted from https://github.com/FarhadG/code-mirror-themes/blob/master/themes/twilight.css and https://github.com/codemirror/CodeMirror/blob/master/theme/twilight.css */
|
||||
|
||||
/* CodeMirror general styling */
|
||||
|
||||
.CodeMirror,
|
||||
.placeholder-code {
|
||||
/* https://codemirror.net/demo/resize.html */
|
||||
height: auto;
|
||||
background: transparent;
|
||||
font-family: 'Roboto Mono';
|
||||
font-weight: 400;
|
||||
line-height: 1.25;
|
||||
letter-spacing: 0.3px;
|
||||
color: #f8f8f8;
|
||||
/* Prevent mobile Safari from zooming in on our code editors; the code is 16px naturally, but somehow being explicit about it prevents the zooming */
|
||||
font-size: 16px;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.CodeMirror,
|
||||
.placeholder-code {
|
||||
font-size: 87.5%; /* Matching Bootstrap’s font size for code, which calculates to 14.4px */
|
||||
}
|
||||
}
|
||||
.CodeMirror-lines {
|
||||
padding: 0.5em 0;
|
||||
}
|
||||
.placeholder-code {
|
||||
padding: 0.5em 4px;
|
||||
margin-bottom: 1.3rem;
|
||||
margin-bottom: 1.37em;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.CodeMirror pre,
|
||||
pre.placeholder-code {
|
||||
line-height: 1.4em;
|
||||
}
|
||||
.CodeMirror-code:focus {
|
||||
outline: none;
|
||||
}
|
||||
div.CodeMirror-cursor {
|
||||
border-left: 3px solid #f8f8f8;
|
||||
}
|
||||
@@ -24,27 +45,18 @@ div.CodeMirror-cursor {
|
||||
.CodeMirror-selected {
|
||||
background: #ddf0ff33;
|
||||
}
|
||||
.cm-comment,
|
||||
.placeholder-code .comment {
|
||||
font-style: italic;
|
||||
color: #5f5a60;
|
||||
}
|
||||
|
||||
/* Syntax highlighting */
|
||||
|
||||
.cm-keyword,
|
||||
.placeholder-code .keyword {
|
||||
color: #cda869;
|
||||
}
|
||||
.cm-string,
|
||||
.placeholder-code .string {
|
||||
color: #8f9d6a;
|
||||
}
|
||||
.cm-property,
|
||||
.placeholder-code .attribute {
|
||||
color: #dad085;
|
||||
}
|
||||
.cm-atom {
|
||||
color: #dad085;
|
||||
}
|
||||
.cm-number,
|
||||
.cm-meta,
|
||||
.placeholder-code .number,
|
||||
.placeholder-code .built_in,
|
||||
.placeholder-code .builtin-name,
|
||||
@@ -55,6 +67,18 @@ div.CodeMirror-cursor {
|
||||
.placeholder-code .link {
|
||||
color: #dad085;
|
||||
}
|
||||
.cm-def {
|
||||
color: #f8f8f8;
|
||||
}
|
||||
span.cm-variable-2,
|
||||
span.cm-tag {
|
||||
color: #f8f8f8;
|
||||
}
|
||||
span.cm-variable-3,
|
||||
span.cm-def,
|
||||
span.cm-type {
|
||||
color: #f8f8f8;
|
||||
}
|
||||
.cm-operator,
|
||||
.placeholder-code .punctuation,
|
||||
.placeholder-code .symbol,
|
||||
@@ -63,9 +87,50 @@ div.CodeMirror-cursor {
|
||||
.placeholder-code .operator {
|
||||
color: #cda869;
|
||||
}
|
||||
.cm-comment,
|
||||
.placeholder-code .comment {
|
||||
font-style: italic;
|
||||
color: #5f5a60;
|
||||
}
|
||||
.cm-string,
|
||||
.cm-string-2,
|
||||
.placeholder-code .string {
|
||||
color: #8f9d6a;
|
||||
}
|
||||
.cm-property,
|
||||
.placeholder-code .attribute {
|
||||
color: #dad085;
|
||||
}
|
||||
.cm-builtin {
|
||||
color: #cda869;
|
||||
}
|
||||
.cm-tag {
|
||||
color: #997643;
|
||||
}
|
||||
.cm-attribute {
|
||||
color: #d6bb6d;
|
||||
}
|
||||
.cm-header {
|
||||
color: #FF6400;
|
||||
}
|
||||
.cm-hr {
|
||||
color: #AEAEAE;
|
||||
}
|
||||
.cm-link {
|
||||
color: #ad9361;
|
||||
font-style: italic;
|
||||
text-decoration: none;
|
||||
}
|
||||
.cm-error {
|
||||
border-bottom: 1px solid rgba(142, 22, 22, 0.67);
|
||||
}
|
||||
|
||||
/* Uneditable code blocks are inverted, so use darker versions of the above */
|
||||
|
||||
.uneditable-code-block code {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.uneditable-code-block .comment {
|
||||
font-style: italic;
|
||||
color: #837B85;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<% if (run) { %>
|
||||
<div class="row">
|
||||
<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) { include('play.svg') } else { %><small><%= include('play.svg') %></small><%= run.replace(/"/g, '"') %><% } %></button>
|
||||
<button type="button" class="btn btn-primary" data-action="run-code-example" data-example="<%= file %>" data-run="<%= escape(run) %>"><small><%= include('play.svg') %></small><%= run === true ? '' : run.replace(/"/g, '"') %></button>
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
unless window.location.origin # Polyfill `location.origin` for IE < 11
|
||||
window.location.origin = "#{window.location.protocol}//#{window.location.hostname}"
|
||||
|
||||
|
||||
# Initialize Google Analytics
|
||||
window.GA_TRACKING_ID = 'UA-106156830-1'
|
||||
window.dataLayer ?= []
|
||||
window.gtag = ->
|
||||
window.dataLayer.push arguments
|
||||
return
|
||||
window.gtag 'js', new Date()
|
||||
window.gtag 'config', window.GA_TRACKING_ID
|
||||
|
||||
|
||||
# Initialize the CoffeeScript docs interactions
|
||||
$(document).ready ->
|
||||
# Mobile navigation
|
||||
toggleSidebar = ->
|
||||
@@ -21,20 +33,20 @@ $(document).ready ->
|
||||
|
||||
# Initialize Scrollspy for sidebar navigation; https://getbootstrap.com/docs/4.0/components/scrollspy/
|
||||
# See also http://www.codingeverything.com/2014/02/BootstrapDocsSideBar.html and http://jsfiddle.net/KyleMit/v6zhz/
|
||||
$('body').scrollspy
|
||||
$('.main').scrollspy
|
||||
target: '#contents'
|
||||
offset: Math.round $('main').css('padding-top').replace('px', '')
|
||||
|
||||
initializeScrollspyFromHash = (hash) ->
|
||||
$("#contents a.active[href!='#{hash}']").removeClass 'show'
|
||||
|
||||
$(window).on 'activate.bs.scrollspy', (event, target) -> # Why `window`? https://github.com/twbs/bootstrap/issues/20086
|
||||
$('.main').on 'activate.bs.scrollspy', (event, target) ->
|
||||
# We only want one active link in the nav
|
||||
$("#contents a.active[href!='#{target.relatedTarget}']").removeClass 'show'
|
||||
$target = $("#contents a[href='#{target.relatedTarget}']")
|
||||
return if $target.prop('href') is "#{window.location.origin}/#try"
|
||||
# Update the browser address bar on scroll or navigation
|
||||
window.history.pushState {}, $target.text(), $target.prop('href')
|
||||
# Update the browser address bar on scroll, without adding to the history; clicking the sidebar links will automatically add to the history
|
||||
replaceState $target.prop('href')
|
||||
# Track this as a new pageview; we only want '/#hash', not 'http://coffeescript.org/#hash'
|
||||
gtag 'config', GA_TRACKING_ID,
|
||||
page_path: $target.prop('href').replace window.location.origin, ''
|
||||
@@ -74,9 +86,10 @@ $(document).ready ->
|
||||
try
|
||||
coffee = editor.getValue()
|
||||
if index is 0 and $('#try').hasClass('show') # If this is the editor in Try CoffeeScript and it’s still visible
|
||||
# Update the hash with the current code
|
||||
link = "try:#{encodeURIComponent coffee}"
|
||||
window.history.pushState {}, 'CoffeeScript', "#{location.href.split('#')[0]}##{link}"
|
||||
if $('#try').hasClass('show')
|
||||
# Update the hash with the current code
|
||||
link = "try:#{encodeURIComponent coffee}"
|
||||
replaceState "#{window.location.href.split('#')[0]}##{link}"
|
||||
# Save this to the user’s localStorage
|
||||
try
|
||||
if window.localStorage?
|
||||
@@ -135,32 +148,51 @@ $(document).ready ->
|
||||
event_category: 'engagement'
|
||||
event_label: $(@).closest('[data-example]').data('example')
|
||||
|
||||
# Try CoffeeScript
|
||||
previousHash = null
|
||||
toggleTry = (checkLocalStorage) ->
|
||||
$('#try, #try-link').toggleClass 'show'
|
||||
if $('#try').hasClass('show')
|
||||
previousHash = window.location.hash if window.location.hash
|
||||
initializeTryEditors() if $('#try .CodeMirror').length is 0
|
||||
if checkLocalStorage and window.localStorage?
|
||||
try
|
||||
coffee = window.localStorage.getItem 'tryCoffeeScriptCode'
|
||||
if coffee?
|
||||
editors[0].setValue coffee
|
||||
else
|
||||
replaceState '#try'
|
||||
catch exception
|
||||
replaceState '#try'
|
||||
else
|
||||
replaceState '#try'
|
||||
else
|
||||
if previousHash then replaceState(previousHash) else clearHash()
|
||||
closeTry = ->
|
||||
$('#try, #try-link').removeClass 'show'
|
||||
if previousHash then replaceState(previousHash) else clearHash()
|
||||
|
||||
$('[data-toggle="try"]').click (event) ->
|
||||
event.preventDefault()
|
||||
toggleTry yes
|
||||
$('[data-close="try"]').click closeTry
|
||||
|
||||
$('[data-action="scroll-to-top"]').click (event) ->
|
||||
return if $('#try').hasClass('show')
|
||||
$('.main')[0].scrollTop = 0
|
||||
setTimeout clearHash, 10
|
||||
|
||||
clearHash = ->
|
||||
window.history.pushState '', document.title, window.location.pathname
|
||||
window.history.replaceState {}, document.title, window.location.pathname
|
||||
|
||||
replaceState = (newURL) ->
|
||||
newURL = "#{window.location.pathname}#{newURL}" if newURL?.indexOf('#') is 0
|
||||
window.history.replaceState {}, document.title, (newURL or '')
|
||||
|
||||
$(window).on 'hashchange', ->
|
||||
# Get rid of dangling # in the address bar
|
||||
clearHash() if window.location.hash is ''
|
||||
|
||||
# Try CoffeeScript
|
||||
toggleTry = (checkLocalStorage = no) ->
|
||||
initializeTryEditors() if $('#try .CodeMirror').length is 0
|
||||
if checkLocalStorage and window.localStorage?
|
||||
try
|
||||
coffee = window.localStorage.getItem 'tryCoffeeScriptCode'
|
||||
if coffee?
|
||||
editors[0].setValue coffee
|
||||
catch exception
|
||||
$('#try, #try-link').toggleClass 'show'
|
||||
setTimeout clearHash, 200 unless $('#try').hasClass('show')
|
||||
closeTry = ->
|
||||
$('#try, #try-link').removeClass 'show'
|
||||
window.history.pushState '', document.title, window.location.pathname
|
||||
|
||||
$('[data-toggle="try"]').click toggleTry
|
||||
$('[data-close="try"]').click closeTry
|
||||
|
||||
|
||||
# Configure the initial state
|
||||
if window.location.hash?
|
||||
if window.location.hash is '#try'
|
||||
@@ -168,7 +200,7 @@ $(document).ready ->
|
||||
else if window.location.hash.indexOf('#try') is 0
|
||||
initializeTryEditors() if $('#try .CodeMirror').length is 0
|
||||
editors[0].setValue decodeURIComponent window.location.hash[5..]
|
||||
toggleTry()
|
||||
toggleTry no
|
||||
else if window.location.hash is ''
|
||||
clearHash()
|
||||
else
|
||||
|
||||
@@ -79,14 +79,18 @@ button:focus, .navbar-dark .navbar-toggler:focus {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Layout; based on https://codepen.io/Sphinxxxx/pen/WjwbEO
|
||||
*/
|
||||
.main-row {
|
||||
height: calc(100vh - 3.5rem);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sidebar
|
||||
*/
|
||||
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 3.5em;
|
||||
height: calc(100% - 3.5rem);
|
||||
/* Scrollable contents if viewport is shorter than content */
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
@@ -102,6 +106,9 @@ button:focus, .navbar-dark .navbar-toggler:focus {
|
||||
}
|
||||
@media screen and (max-width: 991px) {
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 3.5em;
|
||||
height: calc(100% - 3.5rem);
|
||||
left: -100%;
|
||||
transition: 0.25s left ease-in-out;
|
||||
}
|
||||
@@ -109,6 +116,11 @@ button:focus, .navbar-dark .navbar-toggler:focus {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.sidebar {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.contents {
|
||||
padding: 0.5em 0 0.5em 0.5em;
|
||||
@@ -139,10 +151,13 @@ button:focus, .navbar-dark .navbar-toggler:focus {
|
||||
*/
|
||||
|
||||
.main {
|
||||
max-width: 100%;
|
||||
padding: 1.3em;
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.main {
|
||||
flex: 1 1 auto;
|
||||
overflow: auto;
|
||||
padding-right: 2em;
|
||||
padding-left: 2em;
|
||||
}
|
||||
@@ -160,16 +175,17 @@ button:focus, .navbar-dark .navbar-toggler:focus {
|
||||
font-family: Lato;
|
||||
font-weight: 300;
|
||||
font-size: 1.1em;
|
||||
line-height: 1.7;
|
||||
}
|
||||
.main blockquote {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
.main li p, .main li li, .main li blockquote {
|
||||
font-size: 1em;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.main p, .main li, .main td, .main th {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
.main blockquote {
|
||||
font-size: 1.3em;
|
||||
.main p, .main li, .main td, .main th, .main blockquote {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
.main td {
|
||||
@@ -194,11 +210,18 @@ button:focus, .navbar-dark .navbar-toggler:focus {
|
||||
}
|
||||
|
||||
p, blockquote, table, .code-example {
|
||||
margin-bottom: 1.3rem;
|
||||
margin-bottom: 1.1em;
|
||||
}
|
||||
.main li {
|
||||
margin-bottom: 0.6em;
|
||||
}
|
||||
|
||||
td code {
|
||||
code, td code {
|
||||
white-space: nowrap;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
pre code {
|
||||
white-space: pre; /* We want newlines to be newlines in code blocks */
|
||||
}
|
||||
|
||||
h2, h3, h4 {
|
||||
@@ -213,10 +236,10 @@ h3, h4, h2 time {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.main section {
|
||||
/* Offset the anchor so that clicking on the sidebar links don’t hide the heading under the header bar */
|
||||
padding-top: 2.3rem;
|
||||
margin-top: -2.3rem;
|
||||
@media (min-width: 1200px) {
|
||||
.main > header, .main section > h2, .main section > h3, .main section > h4, .main section > p, .main section > blockquote, .main section > ul, .main section > table {
|
||||
max-width: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
code, button {
|
||||
@@ -225,7 +248,6 @@ code, button {
|
||||
}
|
||||
code, a > code {
|
||||
background-color: #f8f3f0;
|
||||
padding: 0.2rem 0.4rem;
|
||||
}
|
||||
code {
|
||||
color: #2f2625;
|
||||
@@ -233,7 +255,7 @@ code {
|
||||
|
||||
|
||||
/*
|
||||
* Code examples
|
||||
* Chrome around code examples; see code.css for the styling of the code blocks themselves
|
||||
*/
|
||||
|
||||
textarea {
|
||||
@@ -268,27 +290,7 @@ textarea {
|
||||
|
||||
.play-button {
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.CodeMirror,
|
||||
.placeholder-code {
|
||||
/* https://codemirror.net/demo/resize.html */
|
||||
height: auto;
|
||||
background: transparent;
|
||||
font-family: 'Roboto Mono';
|
||||
font-weight: 400;
|
||||
line-height: 1.25;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.CodeMirror,
|
||||
.placeholder-code {
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.CodeMirror-code:focus {
|
||||
outline: none;
|
||||
width: 1em;
|
||||
}
|
||||
|
||||
.javascript-output-column .CodeMirror-cursor {
|
||||
@@ -307,6 +309,8 @@ textarea {
|
||||
right: 0;
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease-in-out;
|
||||
z-index: -1001;
|
||||
background-color: #2f2625;
|
||||
}
|
||||
.try-coffeescript.show {
|
||||
opacity: 1;
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
<title>
|
||||
CoffeeScript Logo
|
||||
</title>
|
||||
<path d="M106 228.6c.5 2.3-.9 4.4-5 6.5-5.5-3.1-16.9-4.4-26.7-3.5-10.4.9-19.4 4.2-17.9 11.3 1.5 7.1 11.7 11 29.5 9.5 43.6-3.8 43.4-33.3 107.4-39 49.8-4.4 77.8 11 81.8 29.7 3.1 14.7-9.1 28.6-45.2 31.8-32 2.8-50.7-5.6-52.6-14.6-1-4.5 1.8-11.3 17.2-13.1 1.5 7 10.6 14.4 31.1 12.6 14.8-1.3 27.6-6.6 25.9-14.9-1.8-8.6-17.7-13.7-42.6-11.5-50.7 4.5-63.2 32.5-106.8 36.3-30.8 2.7-55.9-8.5-59.4-25.1-1.3-6.1-1.4-21 31.2-23.9 17.1-1.5 30.7 1.5 32.1 7.9zM-56.4 402.5c-14.3 18-20.4 38.8-19.2 59.2 1.2 20.4 11.4 37.1 26.9 50.2C-32 525-14 528.6 6.4 525c7.8-1.2 16.7-5.3 24.5-7.8-16.7 0-31-5.3-44.9-16.7-15.5-11.4-25.7-26.9-28.2-46.1-3.7-18 0-34.7 10.2-49 11.4-14.3 25.7-22 44.9-24.5 19.2-1.2 35.9 3.7 52.6 15.5-3.7-5.3-9-9-14.3-14.3-16.7-11.4-34.7-16.7-56.7-11.4-19.9 3.6-36.7 13.8-50.9 31.8zm223.6-96.3c-53.9 0-101.6-5.3-136.3-13.1-37.1-9-56.7-19.2-56.7-32.2 0-5.3 2.4-10.2 10.2-15.5-23.3 9-35.9 16.7-35.9 28.2 1.2 13.1 22 25.7 64.5 35.9 40 10.2 91.4 15.5 153 15.5 62.8 0 113-5.3 153-15.5 42.4-10.2 62.8-23.3 62.8-35.9 0-9-9-18-25.7-24.5 3.7 2.4 6.5 6.5 6.5 11.4 0 13.1-19.2 23.3-57.9 32.2-36 8.2-82.1 13.5-137.5 13.5zm153 35.9c-40 9-91.4 15.5-153 15.5-62.8 0-114.2-6.5-154.2-15.5-35.9-9-55.1-19.2-61.6-29.4 6.5 44.9 22 87.3 42.4 124.8 15.5 23.3 31 43.7 46.1 65.7 6.5 13.1 11.4 25.7 14.3 38.8 10.2 14.3 24.5 23.3 42.4 28.2 22 7.8 44.9 11.4 68.1 10.2h2.4c23.3 1.2 47.7-2.4 70.6-10.2 16.7-5.3 31-14.3 41.2-28.2h1.2c2.4-13.1 6.5-25.7 13.1-38.8 15.5-22 31-42.4 46.1-65.7 20.4-37.1 34.7-79.6 42.4-124.8-7.7 11.4-26.9 21.6-61.5 29.4z"/>
|
||||
<path d="M106 228.6c.5 2.3-.9 4.4-5 6.5-5.5-3.1-16.9-4.4-26.7-3.5-10.4.9-19.4 4.2-17.9 11.3 1.5 7.1 11.7 11 29.5 9.5 43.6-3.8 43.4-33.3 107.4-39 49.8-4.4 77.8 11 81.8 29.7 3.1 14.7-9.1 28.6-45.2 31.8-32 2.8-50.7-5.6-52.6-14.6-1-4.5 1.8-11.3 17.2-13.1 1.5 7 10.6 14.4 31.1 12.6 14.8-1.3 27.6-6.6 25.9-14.9-1.8-8.6-17.7-13.7-42.6-11.5-50.7 4.5-63.2 32.5-106.8 36.3-30.8 2.7-55.9-8.5-59.4-25.1-1.3-6.1-1.4-21 31.2-23.9 17.1-1.5 30.7 1.5 32.1 7.9zM-56.4 402.5c-14.3 18-20.4 38.8-19.2 59.2 1.2 20.4 11.4 37.1 26.9 50.2C-32 525-14 528.6 6.4 525c7.8-1.2 16.7-5.3 24.5-7.8-16.7 0-31-5.3-44.9-16.7-15.5-11.4-25.7-26.9-28.2-46.1-3.7-18 0-34.7 10.2-49 11.4-14.3 25.7-22 44.9-24.5 19.2-1.2 35.9 3.7 52.6 15.5-3.7-5.3-9-9-14.3-14.3-16.7-11.4-34.7-16.7-56.7-11.4-19.9 3.6-36.7 13.8-50.9 31.8zm223.6-96.3c-53.9 0-101.6-5.3-136.3-13.1-37.1-9-56.7-19.2-56.7-32.2 0-5.3 2.4-10.2 10.2-15.5-23.3 9-35.9 16.7-35.9 28.2 1.2 13.1 22 25.7 64.5 35.9 40 10.2 91.4 15.5 153 15.5 62.8 0 113-5.3 153-15.5 42.4-10.2 62.8-23.3 62.8-35.9 0-9-9-18-25.7-24.5 3.7 2.4 6.5 6.5 6.5 11.4 0 13.1-19.2 23.3-57.9 32.2-36 8.2-82.1 13.5-137.5 13.5zm153 35.9c-40 9-91.4 15.5-153 15.5-62.8 0-114.2-6.5-154.2-15.5-35.9-9-55.1-19.2-61.6-29.4 6.5 44.9 22 87.3 42.4 124.8 15.5 23.3 31 43.7 46.1 65.7 6.5 13.1 11.4 25.7 14.3 38.8 10.2 14.3 24.5 23.3 42.4 28.2 22 7.8 44.9 11.4 68.1 10.2h2.4c23.3 1.2 47.7-2.4 70.6-10.2 16.7-5.3 31-14.3 41.2-28.2h1.2c2.4-13.1 6.5-25.7 13.1-38.8 15.5-22 31-42.4 46.1-65.7 20.4-37.1 34.7-79.6 42.4-124.8-7.7 11.4-26.9 21.6-61.5 29.4z"></path>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -2,5 +2,5 @@
|
||||
<title>
|
||||
CoffeeScript Logo
|
||||
</title>
|
||||
<path d="M21.7 351.1c.1.6-.2 1.1-1.2 1.6-1.3-.7-4.1-1.1-6.4-.9-2.5.2-4.6 1-4.3 2.7.4 1.7 2.8 2.7 7.1 2.3 10.5-.9 10.4-8 25.8-9.4 12-1.1 18.7 2.6 19.6 7.1.7 3.5-2.2 6.9-10.9 7.6-7.7.7-12.2-1.4-12.6-3.5-.2-1.1.4-2.7 4.1-3.1.4 1.7 2.5 3.5 7.5 3 3.6-.3 6.6-1.6 6.2-3.6-.4-2.1-4.2-3.3-10.2-2.8-12.2 1.1-15.2 7.8-25.6 8.7-7.4.7-13.4-2-14.2-6-.3-1.5-.3-5 7.5-5.7 4-.3 7.2.4 7.6 2zm-39 41.8c-3.4 4.3-4.9 9.3-4.6 14.2.3 4.9 2.7 8.9 6.5 12 4 3.1 8.3 4 13.2 3.1 1.9-.3 4-1.3 5.9-1.9-4 0-7.4-1.3-10.8-4-3.7-2.7-6.2-6.5-6.8-11.1-.9-4.3 0-8.3 2.4-11.8 2.7-3.4 6.2-5.3 10.8-5.9 4.6-.3 8.6.9 12.6 3.7-.9-1.3-2.2-2.2-3.4-3.4-4-2.7-8.3-4-13.6-2.7-4.8 1-8.8 3.5-12.2 7.8zm53.6-23.1c-12.9 0-24.4-1.3-32.7-3.1-8.9-2.2-13.6-4.6-13.6-7.7 0-1.3.6-2.4 2.4-3.7-5.6 2.2-8.6 4-8.6 6.8.3 3.1 5.3 6.2 15.5 8.6 9.6 2.4 21.9 3.7 36.7 3.7 15.1 0 27.1-1.3 36.7-3.7 10.2-2.4 15.1-5.6 15.1-8.6 0-2.2-2.2-4.3-6.2-5.9.9.6 1.6 1.6 1.6 2.7 0 3.1-4.6 5.6-13.9 7.7-8.6 1.9-19.6 3.2-33 3.2zm36.8 8.6c-9.6 2.2-21.9 3.7-36.7 3.7-15.1 0-27.4-1.6-37-3.7-8.6-2.2-13.2-4.6-14.8-7.1 1.6 10.8 5.3 21 10.2 30 3.7 5.6 7.4 10.5 11.1 15.8 1.6 3.1 2.7 6.2 3.4 9.3 2.4 3.4 5.9 5.6 10.2 6.8 5.3 1.9 10.8 2.7 16.4 2.4h.6c5.6.3 11.5-.6 16.9-2.4 4-1.3 7.4-3.4 9.9-6.8h.3c.6-3.1 1.6-6.2 3.1-9.3 3.7-5.3 7.4-10.2 11.1-15.8 4.9-8.9 8.3-19.1 10.2-30-2 2.8-6.6 5.2-14.9 7.1zm106.2 30.1c-4.8 12.1-17.6 16.9-25.9 16.9-13.4 0-19.9-6-19.9-22.3 0-16.5 7.9-47.3 31.7-47.3 8.5 0 15.2 3.3 15.2 12.1 0 4.8-1.8 8.3-6.4 8.3-1.5 0-3.4-.4-5.2-2.4 2.2-1.1 4.2-4.9 4.2-8.3 0-2.9-1.5-5.6-5.6-5.6-10 0-18.9 23.9-18.9 42.4 0 8.3 2.2 14.2 10.9 14.2 7.1 0 13.5-3.4 17.7-9.1l2.2 1.1zm32.9-16.3c.4.2.7.2 1 .2 4.2 0 10.1-2.7 14-5.5l.8 2.4c-3.4 3.7-9.5 6.5-16.1 7.5-1.5 16.8-10.6 27.3-21.7 27.3-8.4 0-14.5-4-14.5-14.4 0-10.5 6.2-32.2 24.9-32.2 7.8.3 11.6 5.3 11.6 14.7zm-7.7 5c-1.9-.5-2.4-2-2.4-3.8 0-2.5 1.2-4.2 2.8-4.9-.2-3.8-1.1-5.3-3.4-5.3-6.5 0-12 16.6-12 25.6 0 6 1.2 7.3 4.6 7.3 4.2.1 8.9-8 10.4-18.9zm-6.6 39.7c0-8.3 7.1-11 15.8-13.6l10.9-51.9c2.7-13 10.6-15.5 16.5-15.5 4.1 0 8 2.2 9.7 5.7 3.6-4.6 8.4-5.7 12.4-5.7 5.6 0 10.8 3.9 10.8 9.8 0 1.5-.1 2.6-.3 3.7h-4.3c.1-.9.2-1.7.2-2.4 0-2.1-1.7-3.1-3.4-3.1-2 0-4.8 1.1-6.2 7.1l-1.7 7.4h9.1l-.8 3.6h-9l-10.3 49.1c-2.7 13-10.6 15.5-16.5 15.5-5.2 0-8.3-2.3-9.8-5.7-3.5 4.6-8.3 5.7-12.3 5.7-5.6.1-10.8-3.8-10.8-9.7zm9.1 1.8c1.9 0 4.2-1.8 5.4-7.1l1.1-5.3c-5.7 2-10.1 4.4-10.1 9.4 0 1.2 1.7 3 3.6 3zm21.7 0c1.9 0 4.2-1.8 5.4-7.1l2.2-10.4-9.4 1.8-1.8 8.3c-.5 2.1-1.1 4-1.8 5.6.9 1.3 3 1.8 5.4 1.8zm-1.4-18l9.4-1.7 7.7-36.8h-9l-8.1 38.5zm16.6-56.7c-2 0-4.8 1.1-6.2 7.1l-1.7 7.4h9l2.1-9.5c.2-.7.2-1.3.2-2 .1-2-1.5-3-3.4-3zm37.9 53c7.1 0 11.6-4 16.1-9.2h3.1c-5.2 8.3-12.9 16.8-25 16.8-8.5 0-14.2-4.2-14.2-14.5 0-10.5 5.9-32.3 24.6-32.3 8.1 0 10 4.2 10 8.7 0 10.5-10 18.5-20.9 19.2-.1 1.3-.2 2.5-.2 3.6 0 6.2 2.2 7.7 6.5 7.7zm5.3-34.4c-4.6 0-9.1 9.7-10.9 18.7 7-.5 13.2-7.4 13.2-15 0-2.2-.5-3.7-2.3-3.7zm28.6 33.4c3.4 0 7.8-2.3 10.8-4.8-2 10.4-8.4 13.4-15.8 13.4-8.4 0-14.1-4.2-14.1-14.5 0-10.5 5.9-32.3 24.6-32.3 8.1 0 10 4.2 10 8.7 0 10.6-10 18.5-20.9 19.2-.1.9-.2 2-.2 2.7 0 5.7 2.5 7.6 5.6 7.6zm6.2-33.4c-4.5 0-9.1 10.1-11 18.7 7.1-.4 13.3-7.3 13.3-15 0-2.2-.6-3.7-2.3-3.7zm51.3-6.7c-1.7 0-3-.6-4.2-1.9 2.4-1.5 4.1-4.8 4.1-7.8 0-3.1-1.8-6.1-6.8-6.1s-8.3 2.8-8.3 8.2c0 13.3 20.5 15.2 20.5 34.8 0 15.3-12.3 22.7-25.6 22.7-10.4 0-19.3-4.5-19.3-15.7 0-9.8 7-14.9 13.3-14.9 3.1 0 7.7 1.3 8 6-4.9 0-10.7 2.3-10.7 8.5 0 4.5 2.9 8.7 8.7 8.7 6.1 0 10.6-4.4 10.6-12 0-15.6-18.6-21.1-18.6-34.5 0-9.5 9.3-16.3 21-16.3 4.3 0 14.6.9 14.6 10.9.1 5.5-2.8 9.4-7.3 9.4zm36.2 10.3c0-2.3-.8-3.7-2.5-3.7-5.7 0-11.7 16.6-11.7 26.7 0 6.2 2.2 7.6 6.6 7.6 7.1 0 11.6-4 16.1-9.2h3.1c-5.2 8.3-12.9 16.8-25 16.8-8.5 0-14.2-4.2-14.2-14.5 0-10.6 6-32.3 24.5-32.3 8.1 0 10.1 4.2 10.1 8.3 0 4.4-2.2 6.7-4.8 6.7-1 0-2.1-.4-3.1-1.1.5-1.9.9-3.6.9-5.3zm27.7-7.6l-1.2 5.7c3.1-2.7 6.7-5.7 11-5.7 4.1 0 6.3 3.3 6.3 6.9 0 3.1-2.1 6.7-6.6 6.7-5.1 0-2.5-6-5.3-6-2.7 0-4.4 1.4-6.7 3.4l-7.2 34.6h-13.1l9.6-45.4 13.2-.2zm34.2 0l-6.6 30.9c-.3 1.2-.4 2.1-.4 2.9 0 2.5 1.2 3.3 3.7 3.3 3.5 0 6.9-3.4 8.1-8h3.8c-5.2 14.8-14.2 16.8-19.1 16.8-5.5 0-9.7-3.2-9.7-10.9 0-1.8.3-3.7.7-5.9l6.2-29.2 13.3.1zm-4.1-19.4c4 0 7.2 3.2 7.2 7.2s-3.2 7.1-7.2 7.1-7.1-3.1-7.1-7.1c-.1-4 3.2-7.2 7.1-7.2zm29.1 16l-1.5 6.9c2.6-2.3 6.1-3.9 10.7-3.9 6.2 0 11.1 3.5 11.1 14.4 0 12.2-4.7 32.1-22.3 32.1-4.5 0-6.8-1.6-7.7-3.2l-4.7 22.1-13.7 3.2 15.2-71.5 12.9-.1zm7.8 17c0-7-2.9-7.5-4.5-7.5-2 0-4.5 1.6-6.3 4.4l-5.4 25.5c.4 1 1.4 2.1 3.4 2.1 9.7 0 12.8-15.9 12.8-24.5zm27.8 17.3c-.3 1.1-.5 2.2-.5 3.1 0 1.9.7 3.2 3.1 3.2.7 0 1.7 0 2.4-.3-2.5 7.8-6.6 8.9-9.6 8.9-6.4 0-9.1-4.4-9.1-10.3 0-1.6.2-3.1.6-4.8l5.8-27.2h-3l.7-3.6h3L528 366l13.4-1.9s-1.4 6.2-3.1 14.4h5.5l-.7 3.6h-5.5l-5.7 27.4z"/>
|
||||
<path d="M21.7 351.1c.1.6-.2 1.1-1.2 1.6-1.3-.7-4.1-1.1-6.4-.9-2.5.2-4.6 1-4.3 2.7.4 1.7 2.8 2.7 7.1 2.3 10.5-.9 10.4-8 25.8-9.4 12-1.1 18.7 2.6 19.6 7.1.7 3.5-2.2 6.9-10.9 7.6-7.7.7-12.2-1.4-12.6-3.5-.2-1.1.4-2.7 4.1-3.1.4 1.7 2.5 3.5 7.5 3 3.6-.3 6.6-1.6 6.2-3.6-.4-2.1-4.2-3.3-10.2-2.8-12.2 1.1-15.2 7.8-25.6 8.7-7.4.7-13.4-2-14.2-6-.3-1.5-.3-5 7.5-5.7 4-.3 7.2.4 7.6 2zm-39 41.8c-3.4 4.3-4.9 9.3-4.6 14.2.3 4.9 2.7 8.9 6.5 12 4 3.1 8.3 4 13.2 3.1 1.9-.3 4-1.3 5.9-1.9-4 0-7.4-1.3-10.8-4-3.7-2.7-6.2-6.5-6.8-11.1-.9-4.3 0-8.3 2.4-11.8 2.7-3.4 6.2-5.3 10.8-5.9 4.6-.3 8.6.9 12.6 3.7-.9-1.3-2.2-2.2-3.4-3.4-4-2.7-8.3-4-13.6-2.7-4.8 1-8.8 3.5-12.2 7.8zm53.6-23.1c-12.9 0-24.4-1.3-32.7-3.1-8.9-2.2-13.6-4.6-13.6-7.7 0-1.3.6-2.4 2.4-3.7-5.6 2.2-8.6 4-8.6 6.8.3 3.1 5.3 6.2 15.5 8.6 9.6 2.4 21.9 3.7 36.7 3.7 15.1 0 27.1-1.3 36.7-3.7 10.2-2.4 15.1-5.6 15.1-8.6 0-2.2-2.2-4.3-6.2-5.9.9.6 1.6 1.6 1.6 2.7 0 3.1-4.6 5.6-13.9 7.7-8.6 1.9-19.6 3.2-33 3.2zm36.8 8.6c-9.6 2.2-21.9 3.7-36.7 3.7-15.1 0-27.4-1.6-37-3.7-8.6-2.2-13.2-4.6-14.8-7.1 1.6 10.8 5.3 21 10.2 30 3.7 5.6 7.4 10.5 11.1 15.8 1.6 3.1 2.7 6.2 3.4 9.3 2.4 3.4 5.9 5.6 10.2 6.8 5.3 1.9 10.8 2.7 16.4 2.4h.6c5.6.3 11.5-.6 16.9-2.4 4-1.3 7.4-3.4 9.9-6.8h.3c.6-3.1 1.6-6.2 3.1-9.3 3.7-5.3 7.4-10.2 11.1-15.8 4.9-8.9 8.3-19.1 10.2-30-2 2.8-6.6 5.2-14.9 7.1zm106.2 30.1c-4.8 12.1-17.6 16.9-25.9 16.9-13.4 0-19.9-6-19.9-22.3 0-16.5 7.9-47.3 31.7-47.3 8.5 0 15.2 3.3 15.2 12.1 0 4.8-1.8 8.3-6.4 8.3-1.5 0-3.4-.4-5.2-2.4 2.2-1.1 4.2-4.9 4.2-8.3 0-2.9-1.5-5.6-5.6-5.6-10 0-18.9 23.9-18.9 42.4 0 8.3 2.2 14.2 10.9 14.2 7.1 0 13.5-3.4 17.7-9.1l2.2 1.1zm32.9-16.3c.4.2.7.2 1 .2 4.2 0 10.1-2.7 14-5.5l.8 2.4c-3.4 3.7-9.5 6.5-16.1 7.5-1.5 16.8-10.6 27.3-21.7 27.3-8.4 0-14.5-4-14.5-14.4 0-10.5 6.2-32.2 24.9-32.2 7.8.3 11.6 5.3 11.6 14.7zm-7.7 5c-1.9-.5-2.4-2-2.4-3.8 0-2.5 1.2-4.2 2.8-4.9-.2-3.8-1.1-5.3-3.4-5.3-6.5 0-12 16.6-12 25.6 0 6 1.2 7.3 4.6 7.3 4.2.1 8.9-8 10.4-18.9zm-6.6 39.7c0-8.3 7.1-11 15.8-13.6l10.9-51.9c2.7-13 10.6-15.5 16.5-15.5 4.1 0 8 2.2 9.7 5.7 3.6-4.6 8.4-5.7 12.4-5.7 5.6 0 10.8 3.9 10.8 9.8 0 1.5-.1 2.6-.3 3.7h-4.3c.1-.9.2-1.7.2-2.4 0-2.1-1.7-3.1-3.4-3.1-2 0-4.8 1.1-6.2 7.1l-1.7 7.4h9.1l-.8 3.6h-9l-10.3 49.1c-2.7 13-10.6 15.5-16.5 15.5-5.2 0-8.3-2.3-9.8-5.7-3.5 4.6-8.3 5.7-12.3 5.7-5.6.1-10.8-3.8-10.8-9.7zm9.1 1.8c1.9 0 4.2-1.8 5.4-7.1l1.1-5.3c-5.7 2-10.1 4.4-10.1 9.4 0 1.2 1.7 3 3.6 3zm21.7 0c1.9 0 4.2-1.8 5.4-7.1l2.2-10.4-9.4 1.8-1.8 8.3c-.5 2.1-1.1 4-1.8 5.6.9 1.3 3 1.8 5.4 1.8zm-1.4-18l9.4-1.7 7.7-36.8h-9l-8.1 38.5zm16.6-56.7c-2 0-4.8 1.1-6.2 7.1l-1.7 7.4h9l2.1-9.5c.2-.7.2-1.3.2-2 .1-2-1.5-3-3.4-3zm37.9 53c7.1 0 11.6-4 16.1-9.2h3.1c-5.2 8.3-12.9 16.8-25 16.8-8.5 0-14.2-4.2-14.2-14.5 0-10.5 5.9-32.3 24.6-32.3 8.1 0 10 4.2 10 8.7 0 10.5-10 18.5-20.9 19.2-.1 1.3-.2 2.5-.2 3.6 0 6.2 2.2 7.7 6.5 7.7zm5.3-34.4c-4.6 0-9.1 9.7-10.9 18.7 7-.5 13.2-7.4 13.2-15 0-2.2-.5-3.7-2.3-3.7zm28.6 33.4c3.4 0 7.8-2.3 10.8-4.8-2 10.4-8.4 13.4-15.8 13.4-8.4 0-14.1-4.2-14.1-14.5 0-10.5 5.9-32.3 24.6-32.3 8.1 0 10 4.2 10 8.7 0 10.6-10 18.5-20.9 19.2-.1.9-.2 2-.2 2.7 0 5.7 2.5 7.6 5.6 7.6zm6.2-33.4c-4.5 0-9.1 10.1-11 18.7 7.1-.4 13.3-7.3 13.3-15 0-2.2-.6-3.7-2.3-3.7zm51.3-6.7c-1.7 0-3-.6-4.2-1.9 2.4-1.5 4.1-4.8 4.1-7.8 0-3.1-1.8-6.1-6.8-6.1s-8.3 2.8-8.3 8.2c0 13.3 20.5 15.2 20.5 34.8 0 15.3-12.3 22.7-25.6 22.7-10.4 0-19.3-4.5-19.3-15.7 0-9.8 7-14.9 13.3-14.9 3.1 0 7.7 1.3 8 6-4.9 0-10.7 2.3-10.7 8.5 0 4.5 2.9 8.7 8.7 8.7 6.1 0 10.6-4.4 10.6-12 0-15.6-18.6-21.1-18.6-34.5 0-9.5 9.3-16.3 21-16.3 4.3 0 14.6.9 14.6 10.9.1 5.5-2.8 9.4-7.3 9.4zm36.2 10.3c0-2.3-.8-3.7-2.5-3.7-5.7 0-11.7 16.6-11.7 26.7 0 6.2 2.2 7.6 6.6 7.6 7.1 0 11.6-4 16.1-9.2h3.1c-5.2 8.3-12.9 16.8-25 16.8-8.5 0-14.2-4.2-14.2-14.5 0-10.6 6-32.3 24.5-32.3 8.1 0 10.1 4.2 10.1 8.3 0 4.4-2.2 6.7-4.8 6.7-1 0-2.1-.4-3.1-1.1.5-1.9.9-3.6.9-5.3zm27.7-7.6l-1.2 5.7c3.1-2.7 6.7-5.7 11-5.7 4.1 0 6.3 3.3 6.3 6.9 0 3.1-2.1 6.7-6.6 6.7-5.1 0-2.5-6-5.3-6-2.7 0-4.4 1.4-6.7 3.4l-7.2 34.6h-13.1l9.6-45.4 13.2-.2zm34.2 0l-6.6 30.9c-.3 1.2-.4 2.1-.4 2.9 0 2.5 1.2 3.3 3.7 3.3 3.5 0 6.9-3.4 8.1-8h3.8c-5.2 14.8-14.2 16.8-19.1 16.8-5.5 0-9.7-3.2-9.7-10.9 0-1.8.3-3.7.7-5.9l6.2-29.2 13.3.1zm-4.1-19.4c4 0 7.2 3.2 7.2 7.2s-3.2 7.1-7.2 7.1-7.1-3.1-7.1-7.1c-.1-4 3.2-7.2 7.1-7.2zm29.1 16l-1.5 6.9c2.6-2.3 6.1-3.9 10.7-3.9 6.2 0 11.1 3.5 11.1 14.4 0 12.2-4.7 32.1-22.3 32.1-4.5 0-6.8-1.6-7.7-3.2l-4.7 22.1-13.7 3.2 15.2-71.5 12.9-.1zm7.8 17c0-7-2.9-7.5-4.5-7.5-2 0-4.5 1.6-6.3 4.4l-5.4 25.5c.4 1 1.4 2.1 3.4 2.1 9.7 0 12.8-15.9 12.8-24.5zm27.8 17.3c-.3 1.1-.5 2.2-.5 3.1 0 1.9.7 3.2 3.1 3.2.7 0 1.7 0 2.4-.3-2.5 7.8-6.6 8.9-9.6 8.9-6.4 0-9.1-4.4-9.1-10.3 0-1.6.2-3.1.6-4.8l5.8-27.2h-3l.7-3.6h3L528 366l13.4-1.9s-1.4 6.2-3.1 14.4h5.5l-.7 3.6h-5.5l-5.7 27.4z"></path>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
@@ -1,5 +1,5 @@
|
||||
<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('logo.svg') %></a>
|
||||
<a class="navbar-brand" href="#" data-close="try" data-action="scroll-to-top"><%= include('logo.svg') %></a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="offcanvas" data-close="try" aria-label="Toggle sidebar">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<svg class="play-button" viewBox="0 0 24 24">
|
||||
<path d="M2.56-0.01v24.02L21.44 11.98 2.56-0.01z"/>
|
||||
<path d="M2.56-0.01v24.02L21.44 11.98 2.56-0.01z"></path>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 107 B After Width: | Height: | Size: 112 B |
@@ -1,19 +1,9 @@
|
||||
<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.Popper = {}; // Remove if we want to use Bootstrap tooltips
|
||||
</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="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js" integrity="sha384-uefMccjFJAIv6A+rW+L4AHf99KvxDjWSu1z9VI8SKNVmz4sk7buKt/6v9KI65qnm" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/combine/npm/codemirror@5.37.0/lib/codemirror.js,npm/codemirror@5.37.0/mode/coffeescript/coffeescript.js,npm/codemirror@5.37.0/addon/lint/coffeescript-lint.js,npm/codemirror@5.37.0/mode/javascript/javascript.js"></script>
|
||||
|
||||
<script src="browser-compiler/coffeescript.js"></script>
|
||||
<script>
|
||||
<%= includeScript('docs.coffee') %>
|
||||
</script>
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-106156830-1"></script>
|
||||
<script>
|
||||
window.GA_TRACKING_ID = 'UA-106156830-1';
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments)};
|
||||
gtag('js', new Date());
|
||||
gtag('config', GA_TRACKING_ID);
|
||||
</script>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<a href="#coffeescript-2" class="nav-link" data-action="sidebar-nav">CoffeeScript 2</a>
|
||||
<nav class="nav flex-column">
|
||||
<a href="#whats-new-in-coffeescript-2" class="nav-link" data-action="sidebar-nav">What’s New in CoffeeScript 2</a>
|
||||
<a href="#why-coffeescript" class="nav-link" data-action="sidebar-nav">Why CoffeeScript When There’s ES6?</a>
|
||||
<a href="#compatibility" class="nav-link" data-action="sidebar-nav">Compatibility</a>
|
||||
</nav>
|
||||
<a href="#installation" class="nav-link" data-action="sidebar-nav">Installation</a>
|
||||
@@ -72,6 +71,7 @@
|
||||
<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-this" class="nav-link" data-action="sidebar-nav"><code>super</code> and <code>this</code></a>
|
||||
<a href="#breaking-changes-super-extends" class="nav-link" data-action="sidebar-nav"><code>super</code> and <code>extends</code></a>
|
||||
<a href="#breaking-changes-jsx-and-the-less-than-and-greater-than-operators" class="nav-link" data-action="sidebar-nav">JSX and the <code><</code> and <code>></code> Operators</a>
|
||||
<a href="#breaking-changes-literate-coffeescript" class="nav-link" data-action="sidebar-nav">Literate CoffeeScript Parsing</a>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
|
||||
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
|
||||
<!-- The CoffeeScript logo font is Google’s Galada -->
|
||||
<link href="https://fonts.googleapis.com/css?family=Alegreya+Sans:400,800|Lato:300,300i,400,700|Roboto+Mono:400,400i" rel="stylesheet" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/codemirror/4.5.0/codemirror.css" crossorigin="anonymous">
|
||||
<link href="https://cdn.jsdelivr.net/npm/codemirror@5.37.0/lib/codemirror.css" rel="stylesheet" crossorigin="anonymous">
|
||||
<style>
|
||||
<%= include('docs.css') %>
|
||||
<%= include('code.css') %>
|
||||
<%= include('docs.css') %>
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.3.0
|
||||
(function() {
|
||||
// This **Browser** compatibility layer extends core CoffeeScript functions
|
||||
// to make things work smoothly when compiling code directly in the browser.
|
||||
@@ -77,7 +77,7 @@
|
||||
// all script tags with a content-type of `text/coffeescript`.
|
||||
// This happens on page load.
|
||||
runScripts = function() {
|
||||
var coffees, coffeetypes, execute, fn, i, index, j, len, s, script, scripts;
|
||||
var coffees, coffeetypes, execute, i, index, j, len, s, script, scripts;
|
||||
scripts = window.document.getElementsByTagName('script');
|
||||
coffeetypes = ['text/coffeescript', 'text/literate-coffeescript'];
|
||||
coffees = (function() {
|
||||
@@ -101,32 +101,31 @@
|
||||
return execute();
|
||||
}
|
||||
};
|
||||
fn = function(script, i) {
|
||||
var options, source;
|
||||
options = {
|
||||
literate: script.type === coffeetypes[1]
|
||||
};
|
||||
source = script.src || script.getAttribute('data-src');
|
||||
if (source) {
|
||||
options.filename = source;
|
||||
return CoffeeScript.load(source, function(param) {
|
||||
coffees[i] = param;
|
||||
return execute();
|
||||
}, options, true);
|
||||
} else {
|
||||
// `options.filename` defines the filename the source map appears as
|
||||
// in Developer Tools. If a script tag has an `id`, use that as the
|
||||
// filename; otherwise use `coffeescript`, or `coffeescript1` etc.,
|
||||
// leaving the first one unnumbered for the common case that there’s
|
||||
// only one CoffeeScript script block to parse.
|
||||
options.filename = script.id && script.id !== '' ? script.id : `coffeescript${(i !== 0 ? i : '')}`;
|
||||
options.sourceFiles = ['embedded'];
|
||||
return coffees[i] = [script.innerHTML, options];
|
||||
}
|
||||
};
|
||||
for (i = j = 0, len = coffees.length; j < len; i = ++j) {
|
||||
script = coffees[i];
|
||||
fn(script, i);
|
||||
(function(script, i) {
|
||||
var options, source;
|
||||
options = {
|
||||
literate: script.type === coffeetypes[1]
|
||||
};
|
||||
source = script.src || script.getAttribute('data-src');
|
||||
if (source) {
|
||||
options.filename = source;
|
||||
return CoffeeScript.load(source, function(param) {
|
||||
coffees[i] = param;
|
||||
return execute();
|
||||
}, options, true);
|
||||
} else {
|
||||
// `options.filename` defines the filename the source map appears as
|
||||
// in Developer Tools. If a script tag has an `id`, use that as the
|
||||
// filename; otherwise use `coffeescript`, or `coffeescript1` etc.,
|
||||
// leaving the first one unnumbered for the common case that there’s
|
||||
// only one CoffeeScript script block to parse.
|
||||
options.filename = script.id && script.id !== '' ? script.id : `coffeescript${(i !== 0 ? i : '')}`;
|
||||
options.sourceFiles = ['embedded'];
|
||||
return coffees[i] = [script.innerHTML, options];
|
||||
}
|
||||
})(script, i);
|
||||
}
|
||||
return execute();
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.3.0
|
||||
(function() {
|
||||
// `cake` is a simplified version of [Make](http://www.gnu.org/software/make/)
|
||||
// ([Rake](http://rake.rubyforge.org/), [Jake](https://github.com/280north/jake))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.3.0
|
||||
(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
|
||||
@@ -85,7 +85,7 @@
|
||||
// object, where sourceMap is a sourcemap.coffee#SourceMap object, handy for
|
||||
// doing programmatic lookups.
|
||||
exports.compile = compile = withPrettyErrors(function(code, options = {}) {
|
||||
var currentColumn, currentLine, encoded, filename, fragment, fragments, generateSourceMap, header, i, j, js, len, len1, map, newLines, ref, ref1, sourceMapDataURI, sourceURL, token, tokens, transpiler, transpilerOutput, v3SourceMap;
|
||||
var currentColumn, currentLine, encoded, filename, fragment, fragments, generateSourceMap, header, i, j, js, len, len1, map, newLines, ref, ref1, sourceMapDataURI, sourceURL, token, tokens, transpiler, transpilerOptions, transpilerOutput, v3SourceMap;
|
||||
// Clone `options`, to avoid mutating the `options` object passed in.
|
||||
options = Object.assign({}, options);
|
||||
// Always generate a source map if no filename is passed in, since without a
|
||||
@@ -177,13 +177,14 @@
|
||||
// is run via the CLI or Node API.
|
||||
transpiler = options.transpile.transpile;
|
||||
delete options.transpile.transpile;
|
||||
transpilerOptions = Object.assign({}, options.transpile);
|
||||
// See https://github.com/babel/babel/issues/827#issuecomment-77573107:
|
||||
// Babel can take a v3 source map object as input in `inputSourceMap`
|
||||
// and it will return an *updated* v3 source map object in its output.
|
||||
if (v3SourceMap && (options.transpile.inputSourceMap == null)) {
|
||||
options.transpile.inputSourceMap = v3SourceMap;
|
||||
if (v3SourceMap && (transpilerOptions.inputSourceMap == null)) {
|
||||
transpilerOptions.inputSourceMap = v3SourceMap;
|
||||
}
|
||||
transpilerOutput = transpiler(js, options.transpile);
|
||||
transpilerOutput = transpiler(js, transpilerOptions);
|
||||
js = transpilerOutput.code;
|
||||
if (v3SourceMap && transpilerOutput.map) {
|
||||
v3SourceMap = transpilerOutput.map;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.3.0
|
||||
(function() {
|
||||
// The `coffee` utility. Handles command-line compilation of CoffeeScript
|
||||
// into various forms: saved into `.js` files or printed to stdout
|
||||
@@ -92,6 +92,7 @@
|
||||
opts.prelude = makePrelude(opts.require);
|
||||
}
|
||||
replCliOpts.prelude = opts.prelude;
|
||||
replCliOpts.transpile = opts.transpile;
|
||||
if (opts.nodejs) {
|
||||
return forkNode();
|
||||
}
|
||||
@@ -303,6 +304,10 @@
|
||||
// and write them back to **stdout**.
|
||||
compileStdio = function() {
|
||||
var buffers, stdin;
|
||||
if (opts.map) {
|
||||
console.error('--stdio and --map cannot be used together');
|
||||
process.exit(1);
|
||||
}
|
||||
buffers = [];
|
||||
stdin = process.openStdin();
|
||||
stdin.on('data', function(buffer) {
|
||||
@@ -529,7 +534,7 @@
|
||||
// same directory as the `.js` file.
|
||||
writeJs = function(base, sourcePath, js, jsPath, generatedSourceMap = null) {
|
||||
var compile, jsDir, sourceMapPath;
|
||||
sourceMapPath = outputPath(sourcePath, base, ".js.map");
|
||||
sourceMapPath = `${jsPath}.map`;
|
||||
jsDir = path.dirname(jsPath);
|
||||
compile = function() {
|
||||
if (opts.compile) {
|
||||
@@ -605,54 +610,41 @@
|
||||
|
||||
// The compile-time options to pass to the CoffeeScript compiler.
|
||||
compileOptions = function(filename, base) {
|
||||
var answer, cantFindOptions, checkPath, cwd, jsDir, jsPath, packageJson;
|
||||
var answer, cwd, jsDir, jsPath;
|
||||
if (opts.transpile) {
|
||||
try {
|
||||
// The user has requested that the CoffeeScript compiler also transpile
|
||||
// via Babel. We use Babel as an `optionalDependency`; see
|
||||
// https://docs.npmjs.com/files/package.json#optionaldependencies.
|
||||
// via Babel. We don’t include Babel as a dependency because we want to
|
||||
// avoid dependencies in general, and most users probably won’t be relying
|
||||
// on us to transpile for them; we assume most users will probably either
|
||||
// run CoffeeScript’s output without transpilation (modern Node or evergreen
|
||||
// browsers) or use a proper build chain like Gulp or Webpack.
|
||||
require('babel-core');
|
||||
} catch (error) {
|
||||
console.error('To use --transpile, you must have Babel installed and configured.\nSee http://coffeescript.org/#transpilation');
|
||||
// Give appropriate instructions depending on whether `coffee` was run
|
||||
// locally or globally.
|
||||
if (require.resolve('.').indexOf(process.cwd()) === 0) {
|
||||
console.error('To use --transpile, you must have babel-core installed:\n npm install --save-dev babel-core\nAnd you must save options to configure Babel in one of the places it looks to find its options.\nSee http://coffeescript.org/#transpilation');
|
||||
} else {
|
||||
console.error('To use --transpile with globally-installed CoffeeScript, you must have babel-core installed globally:\n npm install --global babel-core\nAnd you must save options to configure Babel in one of the places it looks to find its options, relative to the file being compiled or to the current folder.\nSee http://coffeescript.org/#transpilation');
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
// We’re giving Babel only a string, not a filename or path to a file, so
|
||||
// it doesn’t know where to search to find a `.babelrc` file or a `babel`
|
||||
// key in a `package.json`. So if `opts.transpile` is an object, use that
|
||||
// as Babel’s options; otherwise figure out what the options should be.
|
||||
if (typeof opts.transpile !== 'object') {
|
||||
// Find the options based on the path to the file being compiled.
|
||||
cantFindOptions = function() {
|
||||
console.error('To use the transpile option, there must be a .babelrc file\n(or a package.json file with a "babel" key) in the path of the file\nto be compiled, or in the path of the current working directory.\nIf you are compiling a string via the Node API, the transpile option\nmust be an object with the options to pass to Babel.\nSee http://coffeescript.org/#transpilation');
|
||||
return process.exit(1);
|
||||
};
|
||||
checkPath = filename ? path.dirname(filename) : base ? base : typeof process !== "undefined" && process !== null ? process.cwd() : cantFindOptions();
|
||||
while (true) {
|
||||
try {
|
||||
opts.transpile = JSON.parse(fs.readFileSync(path.join(checkPath, '.babelrc'), 'utf-8'));
|
||||
break;
|
||||
} catch (error) {
|
||||
try {
|
||||
packageJson = JSON.parse(fs.readFileSync(path.join(checkPath, 'package.json'), 'utf-8'));
|
||||
if (packageJson.babel != null) {
|
||||
opts.transpile = packageJson.babel;
|
||||
break;
|
||||
}
|
||||
} catch (error) {}
|
||||
}
|
||||
if (checkPath === path.dirname(checkPath)) { // We’ve reached the root.
|
||||
cantFindOptions();
|
||||
break;
|
||||
} else {
|
||||
checkPath = path.dirname(checkPath);
|
||||
}
|
||||
}
|
||||
opts.transpile = {};
|
||||
}
|
||||
// Pass a reference to Babel into the compiler, so that the transpile option
|
||||
// is available for the CLI. We need to do this so that tools like Webpack
|
||||
// can `require('coffeescript')` and build correctly, without trying to
|
||||
// require Babel.
|
||||
opts.transpile.transpile = CoffeeScript.transpile;
|
||||
// Babel searches for its options (a `.babelrc` file, a `.babelrc.js` file,
|
||||
// a `package.json` file with a `babel` key, etc.) relative to the path
|
||||
// given to it in its `filename` option. Make sure we have a path to pass
|
||||
// along.
|
||||
if (!opts.transpile.filename) {
|
||||
opts.transpile.filename = filename || path.resolve(base || process.cwd(), '<anonymous>');
|
||||
}
|
||||
} else {
|
||||
opts.transpile = false;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.3.0
|
||||
(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
|
||||
@@ -97,7 +97,7 @@
|
||||
// Block and statements, which make up a line in a body. YieldReturn is a
|
||||
// statement, but not included in Statement because that results in an ambiguous
|
||||
// grammar.
|
||||
Line: [o('Expression'), o('Statement'), o('FuncDirective')],
|
||||
Line: [o('Expression'), o('ExpressionLine'), o('Statement'), o('FuncDirective')],
|
||||
FuncDirective: [o('YieldReturn'), o('AwaitReturn')],
|
||||
// Pure statements which cannot be expressions.
|
||||
Statement: [
|
||||
@@ -114,6 +114,10 @@
|
||||
// is one. Blocks serve as the building blocks of many other rules, making
|
||||
// them somewhat circular.
|
||||
Expression: [o('Value'), o('Code'), o('Operation'), o('Assign'), o('If'), o('Try'), o('While'), o('For'), o('Switch'), o('Class'), o('Throw'), o('Yield')],
|
||||
// Expressions which are written in single line and would otherwise require being
|
||||
// wrapped in braces: E.g `a = b if do -> f a is 1`, `if f (a) -> a*2 then ...`,
|
||||
// `for x in do (obj) -> f obj when x > 8 then f x`
|
||||
ExpressionLine: [o('CodeLine'), o('IfLine'), o('OperationLine')],
|
||||
Yield: [
|
||||
o('YIELD',
|
||||
function() {
|
||||
@@ -283,7 +287,14 @@
|
||||
})
|
||||
],
|
||||
SimpleObjAssignable: [o('Identifier'), o('Property'), o('ThisProperty')],
|
||||
ObjAssignable: [o('SimpleObjAssignable'), o('AlphaNumeric')],
|
||||
ObjAssignable: [
|
||||
o('SimpleObjAssignable'),
|
||||
o('[ Expression ]',
|
||||
function() {
|
||||
return new Value(new ComputedPropertyName($2));
|
||||
}),
|
||||
o('AlphaNumeric')
|
||||
],
|
||||
// Object literal spread properties.
|
||||
ObjRestValue: [
|
||||
o('SimpleObjAssignable ...',
|
||||
@@ -389,7 +400,8 @@
|
||||
function() {
|
||||
return new Code($2,
|
||||
$5,
|
||||
$4);
|
||||
$4,
|
||||
LOC(1)(new Literal($1)));
|
||||
}),
|
||||
o('FuncGlyph Block',
|
||||
function() {
|
||||
@@ -398,6 +410,22 @@
|
||||
$1);
|
||||
})
|
||||
],
|
||||
// The Codeline is the **Code** node with **Line** instead of indented **Block**.
|
||||
CodeLine: [
|
||||
o('PARAM_START ParamList PARAM_END FuncGlyph Line',
|
||||
function() {
|
||||
return new Code($2,
|
||||
LOC(5)(Block.wrap([$5])),
|
||||
$4,
|
||||
LOC(1)(new Literal($1)));
|
||||
}),
|
||||
o('FuncGlyph Line',
|
||||
function() {
|
||||
return new Code([],
|
||||
LOC(2)(Block.wrap([$2])),
|
||||
$1);
|
||||
})
|
||||
],
|
||||
// CoffeeScript has two different symbols for functions. `->` is for ordinary
|
||||
// functions, and `=>` is for functions bound to the current value of *this*.
|
||||
FuncGlyph: [
|
||||
@@ -821,6 +849,10 @@
|
||||
function() {
|
||||
return new ExportDefaultDeclaration($3);
|
||||
}),
|
||||
o('EXPORT DEFAULT INDENT Object OUTDENT',
|
||||
function() {
|
||||
return new ExportDefaultDeclaration(new Value($4));
|
||||
}),
|
||||
o('EXPORT EXPORT_ALL FROM String',
|
||||
function() {
|
||||
return new ExportAllDeclaration(new Literal($2),
|
||||
@@ -949,9 +981,14 @@
|
||||
function() {
|
||||
return new Arr([]);
|
||||
}),
|
||||
o('[ ArgList OptComma ]',
|
||||
o('[ Elisions ]',
|
||||
function() {
|
||||
return new Arr($2);
|
||||
}),
|
||||
o('[ ArgElisionList OptElisions ]',
|
||||
function() {
|
||||
return new Arr([].concat($2,
|
||||
$3));
|
||||
})
|
||||
],
|
||||
// Inclusive and exclusive range dots.
|
||||
@@ -972,6 +1009,12 @@
|
||||
return new Range($2,
|
||||
$4,
|
||||
$3);
|
||||
}),
|
||||
o('[ ExpressionLine RangeDots Expression ]',
|
||||
function() {
|
||||
return new Range($2,
|
||||
$4,
|
||||
$3);
|
||||
})
|
||||
],
|
||||
// Array slice literals.
|
||||
@@ -988,6 +1031,18 @@
|
||||
null,
|
||||
$2);
|
||||
}),
|
||||
o('ExpressionLine RangeDots Expression',
|
||||
function() {
|
||||
return new Range($1,
|
||||
$3,
|
||||
$2);
|
||||
}),
|
||||
o('ExpressionLine RangeDots',
|
||||
function() {
|
||||
return new Range($1,
|
||||
null,
|
||||
$2);
|
||||
}),
|
||||
o('RangeDots Expression',
|
||||
function() {
|
||||
return new Range(null,
|
||||
@@ -1001,8 +1056,7 @@
|
||||
$1);
|
||||
})
|
||||
],
|
||||
// The **ArgList** is both the list of objects passed into a function call,
|
||||
// as well as the contents of an array literal
|
||||
// The **ArgList** is the list of objects passed into a function call
|
||||
// (i.e. comma-separated expressions). Newlines work as well.
|
||||
ArgList: [
|
||||
o('Arg',
|
||||
@@ -1029,21 +1083,88 @@
|
||||
// Valid arguments are Blocks or Splats.
|
||||
Arg: [
|
||||
o('Expression'),
|
||||
o('ExpressionLine'),
|
||||
o('Splat'),
|
||||
o('...',
|
||||
function() {
|
||||
return new Expansion;
|
||||
})
|
||||
],
|
||||
// The **ArgElisionList** is the list of objects, contents of an array literal
|
||||
// (i.e. comma-separated expressions and elisions). Newlines work as well.
|
||||
ArgElisionList: [
|
||||
o('ArgElision'),
|
||||
o('ArgElisionList , ArgElision',
|
||||
function() {
|
||||
return $1.concat($3);
|
||||
}),
|
||||
o('ArgElisionList OptElisions TERMINATOR ArgElision',
|
||||
function() {
|
||||
return $1.concat($2,
|
||||
$4);
|
||||
}),
|
||||
o('INDENT ArgElisionList OptElisions OUTDENT',
|
||||
function() {
|
||||
return $2.concat($3);
|
||||
}),
|
||||
o('ArgElisionList OptElisions INDENT ArgElisionList OptElisions OUTDENT',
|
||||
function() {
|
||||
return $1.concat($2,
|
||||
$4,
|
||||
$5);
|
||||
})
|
||||
],
|
||||
ArgElision: [
|
||||
o('Arg',
|
||||
function() {
|
||||
return [$1];
|
||||
}),
|
||||
o('Elisions Arg',
|
||||
function() {
|
||||
return $1.concat($2);
|
||||
})
|
||||
],
|
||||
OptElisions: [
|
||||
o('OptComma',
|
||||
function() {
|
||||
return [];
|
||||
}),
|
||||
o(', Elisions',
|
||||
function() {
|
||||
return [].concat($2);
|
||||
})
|
||||
],
|
||||
Elisions: [
|
||||
o('Elision',
|
||||
function() {
|
||||
return [$1];
|
||||
}),
|
||||
o('Elisions Elision',
|
||||
function() {
|
||||
return $1.concat($2);
|
||||
})
|
||||
],
|
||||
Elision: [
|
||||
o(',',
|
||||
function() {
|
||||
return new Elision;
|
||||
})
|
||||
],
|
||||
// Just simple, comma-separated, required arguments (no fancy syntax). We need
|
||||
// this to be separate from the **ArgList** for use in **Switch** blocks, where
|
||||
// having the newlines wouldn't make sense.
|
||||
SimpleArgs: [
|
||||
o('Expression'),
|
||||
o('ExpressionLine'),
|
||||
o('SimpleArgs , Expression',
|
||||
function() {
|
||||
return [].concat($1,
|
||||
$3);
|
||||
}),
|
||||
o('SimpleArgs , ExpressionLine',
|
||||
function() {
|
||||
return [].concat($1,
|
||||
$3);
|
||||
})
|
||||
],
|
||||
// The variants of *try/catch/finally* exception handling blocks.
|
||||
@@ -1117,6 +1238,34 @@
|
||||
})
|
||||
],
|
||||
// The condition portion of a while loop.
|
||||
WhileLineSource: [
|
||||
o('WHILE ExpressionLine',
|
||||
function() {
|
||||
return new While($2);
|
||||
}),
|
||||
o('WHILE ExpressionLine WHEN ExpressionLine',
|
||||
function() {
|
||||
return new While($2,
|
||||
{
|
||||
guard: $4
|
||||
});
|
||||
}),
|
||||
o('UNTIL ExpressionLine',
|
||||
function() {
|
||||
return new While($2,
|
||||
{
|
||||
invert: true
|
||||
});
|
||||
}),
|
||||
o('UNTIL ExpressionLine WHEN ExpressionLine',
|
||||
function() {
|
||||
return new While($2,
|
||||
{
|
||||
invert: true,
|
||||
guard: $4
|
||||
});
|
||||
})
|
||||
],
|
||||
WhileSource: [
|
||||
o('WHILE Expression',
|
||||
function() {
|
||||
@@ -1129,6 +1278,13 @@
|
||||
guard: $4
|
||||
});
|
||||
}),
|
||||
o('WHILE ExpressionLine WHEN Expression',
|
||||
function() {
|
||||
return new While($2,
|
||||
{
|
||||
guard: $4
|
||||
});
|
||||
}),
|
||||
o('UNTIL Expression',
|
||||
function() {
|
||||
return new While($2,
|
||||
@@ -1137,6 +1293,14 @@
|
||||
});
|
||||
}),
|
||||
o('UNTIL Expression WHEN Expression',
|
||||
function() {
|
||||
return new While($2,
|
||||
{
|
||||
invert: true,
|
||||
guard: $4
|
||||
});
|
||||
}),
|
||||
o('UNTIL ExpressionLine WHEN Expression',
|
||||
function() {
|
||||
return new While($2,
|
||||
{
|
||||
@@ -1152,6 +1316,10 @@
|
||||
function() {
|
||||
return $1.addBody($2);
|
||||
}),
|
||||
o('WhileLineSource Block',
|
||||
function() {
|
||||
return $1.addBody($2);
|
||||
}),
|
||||
o('Statement WhileSource',
|
||||
function() {
|
||||
return $2.addBody(LOC(1)(Block.wrap([$1])));
|
||||
@@ -1179,55 +1347,94 @@
|
||||
// Comprehensions can either be normal, with a block of expressions to execute,
|
||||
// or postfix, with a single expression.
|
||||
For: [
|
||||
o('Statement ForBody',
|
||||
o('Statement ForBody',
|
||||
function() {
|
||||
return new For($1,
|
||||
$2);
|
||||
return $2.addBody($1);
|
||||
}),
|
||||
o('Expression ForBody',
|
||||
o('Expression ForBody',
|
||||
function() {
|
||||
return new For($1,
|
||||
$2);
|
||||
return $2.addBody($1);
|
||||
}),
|
||||
o('ForBody Block',
|
||||
o('ForBody Block',
|
||||
function() {
|
||||
return new For($2,
|
||||
$1);
|
||||
return $1.addBody($2);
|
||||
}),
|
||||
o('ForLineBody Block',
|
||||
function() {
|
||||
return $1.addBody($2);
|
||||
})
|
||||
],
|
||||
ForBody: [
|
||||
o('FOR Range',
|
||||
function() {
|
||||
return {
|
||||
return new For([],
|
||||
{
|
||||
source: LOC(2)(new Value($2))
|
||||
};
|
||||
});
|
||||
}),
|
||||
o('FOR Range BY Expression',
|
||||
function() {
|
||||
return {
|
||||
return new For([],
|
||||
{
|
||||
source: LOC(2)(new Value($2)),
|
||||
step: $4
|
||||
};
|
||||
});
|
||||
}),
|
||||
o('ForStart ForSource',
|
||||
function() {
|
||||
$2.own = $1.own;
|
||||
$2.ownTag = $1.ownTag;
|
||||
$2.name = $1[0];
|
||||
$2.index = $1[1];
|
||||
return $2;
|
||||
return $1.addSource($2);
|
||||
})
|
||||
],
|
||||
ForLineBody: [
|
||||
o('FOR Range BY ExpressionLine',
|
||||
function() {
|
||||
return new For([],
|
||||
{
|
||||
source: LOC(2)(new Value($2)),
|
||||
step: $4
|
||||
});
|
||||
}),
|
||||
o('ForStart ForLineSource',
|
||||
function() {
|
||||
return $1.addSource($2);
|
||||
})
|
||||
],
|
||||
ForStart: [
|
||||
o('FOR ForVariables',
|
||||
function() {
|
||||
return $2;
|
||||
return new For([],
|
||||
{
|
||||
name: $2[0],
|
||||
index: $2[1]
|
||||
});
|
||||
}),
|
||||
o('FOR AWAIT ForVariables',
|
||||
function() {
|
||||
var index,
|
||||
name;
|
||||
[name,
|
||||
index] = $3;
|
||||
return new For([],
|
||||
{
|
||||
name,
|
||||
index,
|
||||
await: true,
|
||||
awaitTag: LOC(2)(new Literal($2))
|
||||
});
|
||||
}),
|
||||
o('FOR OWN ForVariables',
|
||||
function() {
|
||||
$3.own = true;
|
||||
$3.ownTag = LOC(2)(new Literal($2));
|
||||
return $3;
|
||||
var index,
|
||||
name;
|
||||
[name,
|
||||
index] = $3;
|
||||
return new For([],
|
||||
{
|
||||
name,
|
||||
index,
|
||||
own: true,
|
||||
ownTag: LOC(2)(new Literal($2))
|
||||
});
|
||||
})
|
||||
],
|
||||
// An array of all accepted values for a variable inside the loop.
|
||||
@@ -1282,6 +1489,13 @@
|
||||
guard: $4
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4
|
||||
};
|
||||
}),
|
||||
o('FOROF Expression WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
@@ -1290,6 +1504,14 @@
|
||||
object: true
|
||||
};
|
||||
}),
|
||||
o('FOROF ExpressionLine WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
object: true
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression BY Expression',
|
||||
function() {
|
||||
return {
|
||||
@@ -1297,6 +1519,13 @@
|
||||
step: $4
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine BY Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression WHEN Expression BY Expression',
|
||||
function() {
|
||||
return {
|
||||
@@ -1305,6 +1534,30 @@
|
||||
step: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine WHEN Expression BY Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
step: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression WHEN ExpressionLine BY Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
step: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine WHEN ExpressionLine BY Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
step: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression BY Expression WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
@@ -1313,6 +1566,30 @@
|
||||
guard: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine BY Expression WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4,
|
||||
guard: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression BY ExpressionLine WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4,
|
||||
guard: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine BY ExpressionLine WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4,
|
||||
guard: $6
|
||||
};
|
||||
}),
|
||||
o('FORFROM Expression',
|
||||
function() {
|
||||
return {
|
||||
@@ -1321,6 +1598,160 @@
|
||||
};
|
||||
}),
|
||||
o('FORFROM Expression WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
from: true
|
||||
};
|
||||
}),
|
||||
o('FORFROM ExpressionLine WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
from: true
|
||||
};
|
||||
})
|
||||
],
|
||||
ForLineSource: [
|
||||
o('FORIN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2
|
||||
};
|
||||
}),
|
||||
o('FOROF ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
object: true
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4
|
||||
};
|
||||
}),
|
||||
o('FOROF Expression WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
object: true
|
||||
};
|
||||
}),
|
||||
o('FOROF ExpressionLine WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
object: true
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression BY ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine BY ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression WHEN Expression BY ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
step: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine WHEN Expression BY ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
step: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression WHEN ExpressionLine BY ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
step: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine WHEN ExpressionLine BY ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
step: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression BY Expression WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4,
|
||||
guard: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine BY Expression WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4,
|
||||
guard: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression BY ExpressionLine WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4,
|
||||
guard: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine BY ExpressionLine WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4,
|
||||
guard: $6
|
||||
};
|
||||
}),
|
||||
o('FORFROM ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
from: true
|
||||
};
|
||||
}),
|
||||
o('FORFROM Expression WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
from: true
|
||||
};
|
||||
}),
|
||||
o('FORFROM ExpressionLine WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
@@ -1335,12 +1766,23 @@
|
||||
return new Switch($2,
|
||||
$4);
|
||||
}),
|
||||
o('SWITCH ExpressionLine INDENT Whens OUTDENT',
|
||||
function() {
|
||||
return new Switch($2,
|
||||
$4);
|
||||
}),
|
||||
o('SWITCH Expression INDENT Whens ELSE Block OUTDENT',
|
||||
function() {
|
||||
return new Switch($2,
|
||||
$4,
|
||||
$6);
|
||||
}),
|
||||
o('SWITCH ExpressionLine INDENT Whens ELSE Block OUTDENT',
|
||||
function() {
|
||||
return new Switch($2,
|
||||
$4,
|
||||
$6);
|
||||
}),
|
||||
o('SWITCH INDENT Whens OUTDENT',
|
||||
function() {
|
||||
return new Switch(null,
|
||||
@@ -1422,12 +1864,63 @@
|
||||
});
|
||||
})
|
||||
],
|
||||
IfBlockLine: [
|
||||
o('IF ExpressionLine Block',
|
||||
function() {
|
||||
return new If($2,
|
||||
$3,
|
||||
{
|
||||
type: $1
|
||||
});
|
||||
}),
|
||||
o('IfBlockLine ELSE IF ExpressionLine Block',
|
||||
function() {
|
||||
return $1.addElse(LOC(3,
|
||||
5)(new If($4,
|
||||
$5,
|
||||
{
|
||||
type: $3
|
||||
})));
|
||||
})
|
||||
],
|
||||
IfLine: [
|
||||
o('IfBlockLine'),
|
||||
o('IfBlockLine ELSE Block',
|
||||
function() {
|
||||
return $1.addElse($3);
|
||||
}),
|
||||
o('Statement POST_IF ExpressionLine',
|
||||
function() {
|
||||
return new If($3,
|
||||
LOC(1)(Block.wrap([$1])),
|
||||
{
|
||||
type: $2,
|
||||
statement: true
|
||||
});
|
||||
}),
|
||||
o('Expression POST_IF ExpressionLine',
|
||||
function() {
|
||||
return new If($3,
|
||||
LOC(1)(Block.wrap([$1])),
|
||||
{
|
||||
type: $2,
|
||||
statement: true
|
||||
});
|
||||
})
|
||||
],
|
||||
// Arithmetic and logical operators, working on one or more operands.
|
||||
// Here they are grouped by order of precedence. The actual precedence rules
|
||||
// are defined at the bottom of the page. It would be shorter if we could
|
||||
// combine most of these rules into a single generic *Operand OpSymbol Operand*
|
||||
// -type rule, but in order to make the precedence binding possible, separate
|
||||
// rules are necessary.
|
||||
OperationLine: [
|
||||
o('UNARY ExpressionLine',
|
||||
function() {
|
||||
return new Op($1,
|
||||
$2);
|
||||
})
|
||||
],
|
||||
Operation: [
|
||||
o('UNARY Expression',
|
||||
function() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.3.0
|
||||
(function() {
|
||||
// This file contains the common helper functions that we'd like to share among
|
||||
// the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.3.0
|
||||
(function() {
|
||||
// Node.js Implementation
|
||||
var CoffeeScript, ext, fn, fs, helpers, i, len, path, ref, universalCompile, vm,
|
||||
var CoffeeScript, ext, fs, helpers, i, len, path, ref, universalCompile, vm,
|
||||
hasProp = {}.hasOwnProperty;
|
||||
|
||||
CoffeeScript = require('./coffeescript');
|
||||
@@ -53,6 +53,8 @@
|
||||
// Assign paths for node_modules loading
|
||||
dir = options.filename != null ? path.dirname(fs.realpathSync(options.filename)) : fs.realpathSync('.');
|
||||
mainModule.paths = require('module')._nodeModulePaths(dir);
|
||||
// Save the options for compiling child imports.
|
||||
mainModule.options = options;
|
||||
// Compile.
|
||||
if (!helpers.isCoffee(mainModule.filename) || require.extensions) {
|
||||
answer = CoffeeScript.compile(code, options);
|
||||
@@ -135,31 +137,30 @@
|
||||
// Throw error with deprecation warning when depending upon implicit `require.extensions` registration
|
||||
if (require.extensions) {
|
||||
ref = CoffeeScript.FILE_EXTENSIONS;
|
||||
fn = function(ext) {
|
||||
var base;
|
||||
return (base = require.extensions)[ext] != null ? base[ext] : base[ext] = function() {
|
||||
throw new Error(`Use CoffeeScript.register() or require the coffeescript/register module to require ${ext} files.`);
|
||||
};
|
||||
};
|
||||
for (i = 0, len = ref.length; i < len; i++) {
|
||||
ext = ref[i];
|
||||
fn(ext);
|
||||
(function(ext) {
|
||||
var base;
|
||||
return (base = require.extensions)[ext] != null ? base[ext] : base[ext] = function() {
|
||||
throw new Error(`Use CoffeeScript.register() or require the coffeescript/register module to require ${ext} files.`);
|
||||
};
|
||||
})(ext);
|
||||
}
|
||||
}
|
||||
|
||||
CoffeeScript._compileFile = function(filename, sourceMap = false, inlineMap = false) {
|
||||
CoffeeScript._compileFile = function(filename, options = {}) {
|
||||
var answer, err, raw, stripped;
|
||||
raw = fs.readFileSync(filename, 'utf8');
|
||||
// Strip the Unicode byte order mark, if this file begins with one.
|
||||
stripped = raw.charCodeAt(0) === 0xFEFF ? raw.substring(1) : raw;
|
||||
options = Object.assign({}, options, {
|
||||
filename: filename,
|
||||
literate: helpers.isLiterate(filename),
|
||||
sourceFiles: [filename],
|
||||
inlineMap: true // Always generate a source map, so that stack traces line up.
|
||||
});
|
||||
try {
|
||||
answer = CoffeeScript.compile(stripped, {
|
||||
filename,
|
||||
sourceMap,
|
||||
inlineMap,
|
||||
sourceFiles: [filename],
|
||||
literate: helpers.isLiterate(filename)
|
||||
});
|
||||
answer = CoffeeScript.compile(stripped, options);
|
||||
} catch (error) {
|
||||
err = error;
|
||||
// As the filename and code of a dynamically loaded file will be different
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.3.0
|
||||
(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,
|
||||
@@ -10,8 +10,9 @@
|
||||
// where locationData is {first_line, first_column, last_line, last_column}, which is a
|
||||
// format that can be fed directly into [Jison](https://github.com/zaach/jison). These
|
||||
// are read by jison in the `parser.lexer` function defined in coffeescript.coffee.
|
||||
var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARABLE_LEFT_SIDE, COMPARE, COMPOUND_ASSIGN, CSX_ATTRIBUTE, CSX_IDENTIFIER, CSX_INTERPOLATION, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, HERE_JSTOKEN, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INSIDE_CSX, INVERSES, JSTOKEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, REGEX_INVALID_ESCAPE, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_INVALID_ESCAPE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, UNFINISHED, UNICODE_CODE_POINT_ESCAPE, VALID_FLAGS, WHITESPACE, attachCommentsToNode, compact, count, invertLiterate, isForFrom, isUnassignable, key, locationDataToString, merge, repeat, starts, throwSyntaxError,
|
||||
indexOf = [].indexOf;
|
||||
var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARABLE_LEFT_SIDE, COMPARE, COMPOUND_ASSIGN, CSX_ATTRIBUTE, CSX_FRAGMENT_IDENTIFIER, CSX_IDENTIFIER, CSX_INTERPOLATION, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, HERE_JSTOKEN, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INSIDE_CSX, INVERSES, JSTOKEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, REGEX_INVALID_ESCAPE, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_INVALID_ESCAPE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, UNFINISHED, UNICODE_CODE_POINT_ESCAPE, VALID_FLAGS, WHITESPACE, attachCommentsToNode, compact, count, invertLiterate, isForFrom, isUnassignable, key, locationDataToString, merge, repeat, starts, throwSyntaxError,
|
||||
indexOf = [].indexOf,
|
||||
slice = [].slice;
|
||||
|
||||
({Rewriter, INVERSES} = require('./rewriter'));
|
||||
|
||||
@@ -111,7 +112,7 @@
|
||||
// referenced as property names here, so you can still do `jQuery.is()` even
|
||||
// though `is` means `===` otherwise.
|
||||
identifierToken() {
|
||||
var alias, colon, colonOffset, colonToken, id, idLength, inCSXTag, input, match, poppedToken, prev, prevprev, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, regExSuper, regex, sup, tag, tagToken;
|
||||
var alias, colon, colonOffset, colonToken, id, idLength, inCSXTag, input, match, poppedToken, prev, prevprev, ref, ref1, ref10, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, regExSuper, regex, sup, tag, tagToken;
|
||||
inCSXTag = this.atCSXTag();
|
||||
regex = inCSXTag ? CSX_ATTRIBUTE : IDENTIFIER;
|
||||
if (!(match = regex.exec(this.chunk))) {
|
||||
@@ -132,19 +133,28 @@
|
||||
if (id === 'as' && this.seenImport) {
|
||||
if (this.value() === '*') {
|
||||
this.tokens[this.tokens.length - 1][0] = 'IMPORT_ALL';
|
||||
} else if (ref = this.value(), indexOf.call(COFFEE_KEYWORDS, ref) >= 0) {
|
||||
this.tokens[this.tokens.length - 1][0] = 'IDENTIFIER';
|
||||
} else if (ref = this.value(true), indexOf.call(COFFEE_KEYWORDS, ref) >= 0) {
|
||||
prev = this.prev();
|
||||
[prev[0], prev[1]] = ['IDENTIFIER', this.value(true)];
|
||||
}
|
||||
if ((ref1 = this.tag()) === 'DEFAULT' || ref1 === 'IMPORT_ALL' || ref1 === 'IDENTIFIER') {
|
||||
this.token('AS', id);
|
||||
return id.length;
|
||||
}
|
||||
}
|
||||
if (id === 'as' && this.seenExport && ((ref2 = this.tag()) === 'IDENTIFIER' || ref2 === 'DEFAULT')) {
|
||||
this.token('AS', id);
|
||||
return id.length;
|
||||
if (id === 'as' && this.seenExport) {
|
||||
if ((ref2 = this.tag()) === 'IDENTIFIER' || ref2 === 'DEFAULT') {
|
||||
this.token('AS', id);
|
||||
return id.length;
|
||||
}
|
||||
if (ref3 = this.value(true), indexOf.call(COFFEE_KEYWORDS, ref3) >= 0) {
|
||||
prev = this.prev();
|
||||
[prev[0], prev[1]] = ['IDENTIFIER', this.value(true)];
|
||||
this.token('AS', id);
|
||||
return id.length;
|
||||
}
|
||||
}
|
||||
if (id === 'default' && this.seenExport && ((ref3 = this.tag()) === 'EXPORT' || ref3 === 'AS')) {
|
||||
if (id === 'default' && this.seenExport && ((ref4 = this.tag()) === 'EXPORT' || ref4 === 'AS')) {
|
||||
this.token('DEFAULT', id);
|
||||
return id.length;
|
||||
}
|
||||
@@ -156,10 +166,10 @@
|
||||
return sup.length + 3;
|
||||
}
|
||||
prev = this.prev();
|
||||
tag = colon || (prev != null) && (((ref4 = prev[0]) === '.' || ref4 === '?.' || ref4 === '::' || ref4 === '?::') || !prev.spaced && prev[0] === '@') ? 'PROPERTY' : 'IDENTIFIER';
|
||||
tag = colon || (prev != null) && (((ref5 = prev[0]) === '.' || ref5 === '?.' || ref5 === '::' || ref5 === '?::') || !prev.spaced && prev[0] === '@') ? 'PROPERTY' : 'IDENTIFIER';
|
||||
if (tag === 'IDENTIFIER' && (indexOf.call(JS_KEYWORDS, id) >= 0 || indexOf.call(COFFEE_KEYWORDS, id) >= 0) && !(this.exportSpecifierList && indexOf.call(COFFEE_KEYWORDS, id) >= 0)) {
|
||||
tag = id.toUpperCase();
|
||||
if (tag === 'WHEN' && (ref5 = this.tag(), indexOf.call(LINE_BREAK, ref5) >= 0)) {
|
||||
if (tag === 'WHEN' && (ref6 = this.tag(), indexOf.call(LINE_BREAK, ref6) >= 0)) {
|
||||
tag = 'LEADING_WHEN';
|
||||
} else if (tag === 'FOR') {
|
||||
this.seenFor = true;
|
||||
@@ -190,11 +200,11 @@
|
||||
// what CoffeeScript would normally interpret as calls to functions named
|
||||
// `get` or `set`, i.e. `get({foo: function () {}})`.
|
||||
} else if (tag === 'PROPERTY' && prev) {
|
||||
if (prev.spaced && (ref6 = prev[0], indexOf.call(CALLABLE, ref6) >= 0) && /^[gs]et$/.test(prev[1])) {
|
||||
if (prev.spaced && (ref7 = prev[0], indexOf.call(CALLABLE, ref7) >= 0) && /^[gs]et$/.test(prev[1]) && this.tokens.length > 1 && ((ref8 = this.tokens[this.tokens.length - 2][0]) !== '.' && ref8 !== '?.' && ref8 !== '@')) {
|
||||
this.error(`'${prev[1]}' cannot be used as a keyword, or as a function call without parentheses`, prev[2]);
|
||||
} else {
|
||||
} else if (this.tokens.length > 2) {
|
||||
prevprev = this.tokens[this.tokens.length - 2];
|
||||
if (((ref7 = prev[0]) === '@' || ref7 === 'THIS') && prevprev && prevprev.spaced && /^[gs]et$/.test(prevprev[1]) && this.tokens[this.tokens.length - 3][0] !== '.') {
|
||||
if (((ref9 = prev[0]) === '@' || ref9 === 'THIS') && prevprev && prevprev.spaced && /^[gs]et$/.test(prevprev[1]) && ((ref10 = this.tokens[this.tokens.length - 3][0]) !== '.' && ref10 !== '?.' && ref10 !== '@')) {
|
||||
this.error(`'${prevprev[1]}' cannot be used as a keyword, or as a function call without parentheses`, prevprev[2]);
|
||||
}
|
||||
}
|
||||
@@ -204,7 +214,7 @@
|
||||
length: id.length
|
||||
});
|
||||
}
|
||||
if (tag !== 'PROPERTY') {
|
||||
if (!(tag === 'PROPERTY' || this.exportSpecifierList)) {
|
||||
if (indexOf.call(COFFEE_ALIASES, id) >= 0) {
|
||||
alias = id;
|
||||
id = COFFEE_ALIAS_MAP[id];
|
||||
@@ -577,16 +587,20 @@
|
||||
// Keeps track of the level of indentation, because a single outdent token
|
||||
// can close multiple indents, so we need to know how far in we happen to be.
|
||||
lineToken(chunk = this.chunk) {
|
||||
var diff, indent, match, minLiteralLength, newIndentLiteral, noNewlines, size;
|
||||
var backslash, diff, indent, match, minLiteralLength, newIndentLiteral, noNewlines, prev, size;
|
||||
if (!(match = MULTI_DENT.exec(chunk))) {
|
||||
return 0;
|
||||
}
|
||||
indent = match[0];
|
||||
this.seenFor = false;
|
||||
if (!this.importSpecifierList) {
|
||||
prev = this.prev();
|
||||
backslash = (prev != null ? prev[0] : void 0) === '\\';
|
||||
if (!(backslash && this.seenFor)) {
|
||||
this.seenFor = false;
|
||||
}
|
||||
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');
|
||||
@@ -615,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;
|
||||
}
|
||||
@@ -732,7 +748,7 @@
|
||||
// Check the previous token to detect if attribute is spread.
|
||||
prevChar = this.tokens.length > 0 ? this.tokens[this.tokens.length - 1][0] : '';
|
||||
if (firstChar === '<') {
|
||||
match = CSX_IDENTIFIER.exec(this.chunk.slice(1));
|
||||
match = CSX_IDENTIFIER.exec(this.chunk.slice(1)) || CSX_FRAGMENT_IDENTIFIER.exec(this.chunk.slice(1));
|
||||
// Not the right hand side of an unspaced comparison (i.e. `a<b`).
|
||||
if (!(match && (this.csxDepth > 0 || !(prev = this.prev()) || prev.spaced || (ref = prev[0], indexOf.call(COMPARABLE_LEFT_SIDE, ref) < 0)))) {
|
||||
return 0;
|
||||
@@ -784,8 +800,8 @@
|
||||
delimiter: '>'
|
||||
});
|
||||
});
|
||||
match = CSX_IDENTIFIER.exec(this.chunk.slice(end));
|
||||
if (!match || match[0] !== csxTag.name) {
|
||||
match = CSX_IDENTIFIER.exec(this.chunk.slice(end)) || CSX_FRAGMENT_IDENTIFIER.exec(this.chunk.slice(end));
|
||||
if (!match || match[1] !== csxTag.name) {
|
||||
this.error(`expected corresponding CSX closing tag for ${csxTag.name}`, csxTag.origin[2]);
|
||||
}
|
||||
afterTag = end + csxTag.name.length;
|
||||
@@ -1041,7 +1057,7 @@
|
||||
if (braceInterpolator) {
|
||||
// Turn the leading and trailing `{` and `}` into parentheses. Unnecessary
|
||||
// parentheses will be removed later.
|
||||
open = nested[0], close = nested[nested.length - 1];
|
||||
[open] = nested, [close] = slice.call(nested, -1);
|
||||
open[0] = open[1] = '(';
|
||||
close[0] = close[1] = ')';
|
||||
close.origin = ['', 'end of interpolation', close[2]];
|
||||
@@ -1066,7 +1082,7 @@
|
||||
length: delimiter.length
|
||||
});
|
||||
}
|
||||
firstToken = tokens[0], lastToken = tokens[tokens.length - 1];
|
||||
[firstToken] = tokens, [lastToken] = slice.call(tokens, -1);
|
||||
firstToken[2].first_column -= delimiter.length;
|
||||
if (lastToken[1].substr(-1) === '\n') {
|
||||
lastToken[2].last_line += 1;
|
||||
@@ -1167,7 +1183,7 @@
|
||||
this.tokens.push(...tokensToPush);
|
||||
}
|
||||
if (lparen) {
|
||||
lastToken = tokens[tokens.length - 1];
|
||||
[lastToken] = slice.call(tokens, -1);
|
||||
lparen.origin = [
|
||||
'STRING',
|
||||
null,
|
||||
@@ -1193,7 +1209,7 @@
|
||||
// correctly balanced throughout the course of the token stream.
|
||||
pair(tag) {
|
||||
var lastIndent, prev, ref, ref1, wanted;
|
||||
ref = this.ends, prev = ref[ref.length - 1];
|
||||
ref = this.ends, [prev] = slice.call(ref, -1);
|
||||
if (tag !== (wanted = prev != null ? prev.tag : void 0)) {
|
||||
if ('OUTDENT' !== wanted) {
|
||||
this.error(`unmatched ${tag}`);
|
||||
@@ -1203,7 +1219,7 @@
|
||||
// el.click((event) ->
|
||||
// el.hide())
|
||||
|
||||
ref1 = this.indents, lastIndent = ref1[ref1.length - 1];
|
||||
ref1 = this.indents, [lastIndent] = slice.call(ref1, -1);
|
||||
this.outdentToken(lastIndent, true);
|
||||
return this.pair(tag);
|
||||
}
|
||||
@@ -1229,7 +1245,7 @@
|
||||
lineCount = count(string, '\n');
|
||||
column = this.chunkColumn;
|
||||
if (lineCount > 0) {
|
||||
ref = string.split('\n'), lastLine = ref[ref.length - 1];
|
||||
ref = string.split('\n'), [lastLine] = slice.call(ref, -1);
|
||||
column = lastLine.length;
|
||||
} else {
|
||||
column += string.length;
|
||||
@@ -1270,15 +1286,19 @@
|
||||
// Peek at the last tag in the token stream.
|
||||
tag() {
|
||||
var ref, token;
|
||||
ref = this.tokens, token = ref[ref.length - 1];
|
||||
ref = this.tokens, [token] = slice.call(ref, -1);
|
||||
return token != null ? token[0] : void 0;
|
||||
}
|
||||
|
||||
// Peek at the last value in the token stream.
|
||||
value() {
|
||||
var ref, token;
|
||||
ref = this.tokens, token = ref[ref.length - 1];
|
||||
return token != null ? token[1] : void 0;
|
||||
value(useOrigin = false) {
|
||||
var ref, ref1, token;
|
||||
ref = this.tokens, [token] = slice.call(ref, -1);
|
||||
if (useOrigin && ((token != null ? token.origin : void 0) != null)) {
|
||||
return (ref1 = token.origin) != null ? ref1[1] : void 0;
|
||||
} else {
|
||||
return token != null ? token[1] : void 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the previous token in the token stream.
|
||||
@@ -1528,6 +1548,9 @@
|
||||
CSX_IDENTIFIER = /^(?![\d<])((?:(?!\s)[\.\-$\w\x7f-\uffff])+)/; // Must not start with `<`.
|
||||
// Like `IDENTIFIER`, but includes `-`s and `.`s.
|
||||
|
||||
// Fragment: <></>
|
||||
CSX_FRAGMENT_IDENTIFIER = /^()>/; // Ends immediately with `>`.
|
||||
|
||||
CSX_ATTRIBUTE = /^(?!\d)((?:(?!\s)[\-$\w\x7f-\uffff])+)([^\S]*=(?!=))?/; // Like `IDENTIFIER`, but includes `-`s.
|
||||
// Is this an attribute with a value?
|
||||
|
||||
@@ -1587,9 +1610,14 @@
|
||||
|
||||
REGEX_FLAGS = /^\w*/;
|
||||
|
||||
VALID_FLAGS = /^(?!.*(.).*\1)[imguy]*$/;
|
||||
VALID_FLAGS = /^(?!.*(.).*\1)[gimsuy]*$/;
|
||||
|
||||
HEREGEX = /^(?:[^\\\/#]|\\[\s\S]|\/(?!\/\/)|\#(?!\{))*/;
|
||||
// Match any character, except those that need special handling below.
|
||||
// Match `\` followed by any character.
|
||||
// Match any `/` except `///`.
|
||||
// Match `#` which is not part of interpolation, e.g. `#{}`.
|
||||
// Comments consume everything until the end of the line, including `///`.
|
||||
HEREGEX = /^(?:[^\\\/#\s]|\\[\s\S]|\/(?!\/\/)|\#(?!\{)|\s+(?:#(?!\{).*)?)*/;
|
||||
|
||||
HEREGEX_OMIT = /((?:\\\\)+)|\\(\s)|\s+(?:#.*)?/g; // Consume (and preserve) an even number of backslashes.
|
||||
// Preserve escaped whitespace.
|
||||
@@ -1672,6 +1700,6 @@
|
||||
INDENTABLE_CLOSERS = [')', '}', ']'];
|
||||
|
||||
// Tokens that, when appearing at the end of a line, suppress a following TERMINATOR/INDENT token
|
||||
UNFINISHED = ['\\', '.', '?.', '?::', 'UNARY', 'MATH', 'UNARY_MATH', '+', '-', '**', 'SHIFT', 'RELATION', 'COMPARE', '&', '^', '|', '&&', '||', 'BIN?', 'EXTENDS', 'DEFAULT'];
|
||||
UNFINISHED = ['\\', '.', '?.', '?::', 'UNARY', 'MATH', 'UNARY_MATH', '+', '-', '**', 'SHIFT', 'RELATION', 'COMPARE', '&', '^', '|', '&&', '||', 'BIN?', 'EXTENDS'];
|
||||
|
||||
}).call(this);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.3.0
|
||||
(function() {
|
||||
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments, repeat,
|
||||
slice = [].slice;
|
||||
splice = [].splice;
|
||||
|
||||
({repeat} = require('./helpers'));
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
// `--` argument after, because that will fail on Linux (see #3946).
|
||||
({rules, positional} = normalizeArguments(args, this.rules.flagDict));
|
||||
options = {};
|
||||
// The `argument` field is added to the rule instance non-destructively by
|
||||
// `normalizeArguments`.
|
||||
// The `argument` field is added to the rule instance non-destructively by
|
||||
// `normalizeArguments`.
|
||||
for (i = 0, len = rules.length; i < len; i++) {
|
||||
({hasArgument, argument, isList, name} = rules[i]);
|
||||
if (hasArgument) {
|
||||
@@ -157,7 +157,7 @@
|
||||
};
|
||||
|
||||
normalizeArguments = function(args, flagDict) {
|
||||
var arg, argIndex, flag, i, innerOpts, j, k, lastOpt, len, len1, multiFlags, multiOpts, needsArgOpt, positional, ref, rule, rules, singleRule, withArg;
|
||||
var arg, argIndex, flag, i, innerOpts, j, lastOpt, len, len1, multiFlags, multiOpts, needsArgOpt, positional, ref, rule, rules, singleRule, withArg;
|
||||
rules = [];
|
||||
positional = [];
|
||||
needsArgOpt = null;
|
||||
@@ -187,9 +187,9 @@
|
||||
return {rule, flag};
|
||||
});
|
||||
// Only the last flag in a multi-flag may have an argument.
|
||||
innerOpts = 2 <= multiOpts.length ? slice.call(multiOpts, 0, j = multiOpts.length - 1) : (j = 0, []), lastOpt = multiOpts[j++];
|
||||
for (k = 0, len1 = innerOpts.length; k < len1; k++) {
|
||||
({rule, flag} = innerOpts[k]);
|
||||
[...innerOpts] = multiOpts, [lastOpt] = splice.call(innerOpts, -1);
|
||||
for (j = 0, len1 = innerOpts.length; j < len1; j++) {
|
||||
({rule, flag} = innerOpts[j]);
|
||||
if (rule.hasArgument) {
|
||||
throw new Error(`cannot use option ${flag} in multi-flag ${arg} except as the last option, because it needs an argument`);
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.3.0
|
||||
(function() {
|
||||
var CoffeeScript, Module, binary, child_process, ext, findExtension, fork, helpers, i, len, loadFile, path, ref;
|
||||
var CoffeeScript, Module, binary, child_process, ext, findExtension, fork, getRootModule, helpers, i, len, loadFile, path, ref;
|
||||
|
||||
CoffeeScript = require('./');
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
|
||||
// Load and run a CoffeeScript file for Node, stripping any `BOM`s.
|
||||
loadFile = function(module, filename) {
|
||||
var answer;
|
||||
answer = CoffeeScript._compileFile(filename, false, true);
|
||||
var answer, options;
|
||||
options = module.options || getRootModule(module).options;
|
||||
answer = CoffeeScript._compileFile(filename, options);
|
||||
return module._compile(answer, filename);
|
||||
};
|
||||
|
||||
@@ -72,4 +73,13 @@
|
||||
};
|
||||
}
|
||||
|
||||
// Utility function to find the `options` object attached to the topmost module.
|
||||
getRootModule = function(module) {
|
||||
if (module.parent) {
|
||||
return getRootModule(module.parent);
|
||||
} else {
|
||||
return module;
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.3.0
|
||||
(function() {
|
||||
var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, replDefaults, runInContext, sawSIGINT, updateSyntaxError, vm;
|
||||
var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, replDefaults, runInContext, sawSIGINT, transpile, updateSyntaxError, vm;
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
sawSIGINT = false;
|
||||
|
||||
transpile = false;
|
||||
|
||||
replDefaults = {
|
||||
prompt: 'coffee> ',
|
||||
historyFile: (function() {
|
||||
@@ -27,7 +29,7 @@
|
||||
})(),
|
||||
historyMaxInputSize: 10240,
|
||||
eval: function(input, context, filename, cb) {
|
||||
var Assign, Block, Call, Code, Literal, Value, ast, err, isAsync, js, referencedVars, result, token, tokens;
|
||||
var Assign, Block, Call, Code, Literal, Value, ast, err, isAsync, js, ref, ref1, referencedVars, result, token, tokens;
|
||||
// XXX: multiline hack.
|
||||
input = input.replace(/\uFF00/g, '\n');
|
||||
// Node's REPL sends the input ending with a newline and then wrapped in
|
||||
@@ -41,6 +43,13 @@
|
||||
try {
|
||||
// Tokenize the clean input.
|
||||
tokens = CoffeeScript.tokens(input);
|
||||
// Filter out tokens generated just to hold comments.
|
||||
if (tokens.length >= 2 && tokens[0].generated && ((ref = tokens[0].comments) != null ? ref.length : void 0) !== 0 && tokens[0][1] === '' && tokens[1][0] === 'TERMINATOR') {
|
||||
tokens = tokens.slice(2);
|
||||
}
|
||||
if (tokens.length >= 1 && tokens[tokens.length - 1].generated && ((ref1 = tokens[tokens.length - 1].comments) != null ? ref1.length : void 0) !== 0 && tokens[tokens.length - 1][1] === '') {
|
||||
tokens.pop();
|
||||
}
|
||||
// Collect referenced variable names just like in `CoffeeScript.compile`.
|
||||
referencedVars = (function() {
|
||||
var i, len, results;
|
||||
@@ -57,10 +66,10 @@
|
||||
ast = CoffeeScript.nodes(tokens);
|
||||
// Add assignment to `__` variable to force the input to be an expression.
|
||||
ast = new Block([new Assign(new Value(new Literal('__')), ast, '=')]);
|
||||
// Wrap the expression in a closure to support top-level `await`
|
||||
// Wrap the expression in a closure to support top-level `await`.
|
||||
ast = new Code([], ast);
|
||||
isAsync = ast.isAsync;
|
||||
// Invoke the wrapping closure
|
||||
// Invoke the wrapping closure.
|
||||
ast = new Block([new Call(ast)]);
|
||||
js = ast.compile({
|
||||
bare: true,
|
||||
@@ -68,8 +77,14 @@
|
||||
referencedVars,
|
||||
sharedScope: true
|
||||
});
|
||||
if (transpile) {
|
||||
js = transpile.transpile(js, transpile.options).code;
|
||||
// Strip `"use strict"`, to avoid an exception on assigning to
|
||||
// undeclared variable `__`.
|
||||
js = js.replace(/^"use strict"|^'use strict'/, '');
|
||||
}
|
||||
result = runInContext(js, context, filename);
|
||||
// Await an async result, if necessary
|
||||
// Await an async result, if necessary.
|
||||
if (isAsync) {
|
||||
result.then(function(resolvedResult) {
|
||||
if (!sawSIGINT) {
|
||||
@@ -224,7 +239,7 @@
|
||||
|
||||
module.exports = {
|
||||
start: function(opts = {}) {
|
||||
var build, major, minor, repl;
|
||||
var Module, build, major, minor, originalModuleLoad, repl;
|
||||
[major, minor, build] = process.versions.node.split('.').map(function(n) {
|
||||
return parseInt(n, 10);
|
||||
});
|
||||
@@ -234,6 +249,30 @@
|
||||
}
|
||||
CoffeeScript.register();
|
||||
process.argv = ['coffee'].concat(process.argv.slice(2));
|
||||
if (opts.transpile) {
|
||||
try {
|
||||
transpile = {};
|
||||
transpile.transpile = require('babel-core').transform;
|
||||
} catch (error) {
|
||||
console.error('To use --transpile with an interactive REPL, babel-core must be installed either in the current folder or globally:\n npm install --save-dev babel-core\nor\n npm install --global babel-core\nAnd you must save options to configure Babel in one of the places it looks to find its options.\nSee http://coffeescript.org/#transpilation');
|
||||
process.exit(1);
|
||||
}
|
||||
transpile.options = {
|
||||
filename: path.resolve(process.cwd(), '<repl>')
|
||||
};
|
||||
// Since the REPL compilation path is unique (in `eval` above), we need
|
||||
// another way to get the `options` object attached to a module so that
|
||||
// it knows later on whether it needs to be transpiled. In the case of
|
||||
// the REPL, the only applicable option is `transpile`.
|
||||
Module = require('module');
|
||||
originalModuleLoad = Module.prototype.load;
|
||||
Module.prototype.load = function(filename) {
|
||||
this.options = {
|
||||
transpile: transpile.options
|
||||
};
|
||||
return originalModuleLoad.call(this, filename);
|
||||
};
|
||||
}
|
||||
opts = merge(replDefaults, opts);
|
||||
repl = nodeREPL.start(opts);
|
||||
if (opts.prelude) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.3.0
|
||||
(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; 0 <= ref ? k < ref : 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;
|
||||
}
|
||||
@@ -281,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, ref1, s, sameLine, stackIdx, stackItem, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag;
|
||||
var endImplicitCall, endImplicitObject, forward, implicitObjectContinues, inControlFlow, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, isImplicit, isImplicitCall, isImplicitObject, k, newLine, nextTag, nextToken, offset, prevTag, prevToken, ref, ref1, ref2, 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] : [];
|
||||
@@ -420,10 +420,31 @@
|
||||
}
|
||||
start = stack.pop();
|
||||
}
|
||||
inControlFlow = () => {
|
||||
var controlFlow, isFunc, seenFor, tagCurrentLine;
|
||||
seenFor = this.findTagsBackwards(i, ['FOR']) && this.findTagsBackwards(i, ['FORIN', 'FOROF', 'FORFROM']);
|
||||
controlFlow = seenFor || this.findTagsBackwards(i, ['WHILE', 'UNTIL', 'LOOP', 'LEADING_WHEN']);
|
||||
if (!controlFlow) {
|
||||
return false;
|
||||
}
|
||||
isFunc = false;
|
||||
tagCurrentLine = token[2].first_line;
|
||||
this.detectEnd(i, function(token, i) {
|
||||
var ref;
|
||||
return ref = token[0], indexOf.call(LINEBREAKS, ref) >= 0;
|
||||
}, function(token, i) {
|
||||
var first_line;
|
||||
[prevTag, , {first_line}] = tokens[i - 1] || [];
|
||||
return isFunc = tagCurrentLine === first_line && (prevTag === '->' || prevTag === '=>');
|
||||
}, {
|
||||
returnOnNegativeLevel: true
|
||||
});
|
||||
return isFunc;
|
||||
};
|
||||
// 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 === '...' && (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 ((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) && !inControlFlow()) {
|
||||
if (tag === '?') {
|
||||
tag = token[0] = 'FUNC_EXIST';
|
||||
}
|
||||
@@ -506,11 +527,11 @@
|
||||
}
|
||||
}
|
||||
newLine = prevTag === 'OUTDENT' || prevToken.newLine;
|
||||
if (indexOf.call(IMPLICIT_END, tag) >= 0 || indexOf.call(CALL_CLOSERS, tag) >= 0 && newLine) {
|
||||
if (indexOf.call(IMPLICIT_END, tag) >= 0 || (indexOf.call(CALL_CLOSERS, tag) >= 0 && newLine) || ((tag === '..' || tag === '...') && this.findTagsBackwards(i, ["INDEX_START"]))) {
|
||||
while (inImplicit()) {
|
||||
[stackTag, stackIdx, {sameLine, startsLine}] = stackTop();
|
||||
// Close implicit calls when reached end of argument list
|
||||
if (inImplicitCall() && prevTag !== ',') {
|
||||
if (inImplicitCall() && prevTag !== ',' || (prevTag === ',' && tag === 'TERMINATOR' && (nextTag == null))) {
|
||||
endImplicitCall();
|
||||
// Close implicit objects such as:
|
||||
// return a: 1, b: 2 unless true
|
||||
@@ -539,7 +560,7 @@
|
||||
|
||||
// f a, b: c, d: e, f, g: h: i, j
|
||||
|
||||
if (tag === ',' && !this.looksObjectish(i + 1) && inImplicitObject() && (nextTag !== 'TERMINATOR' || !this.looksObjectish(i + 2))) {
|
||||
if (tag === ',' && !this.looksObjectish(i + 1) && inImplicitObject() && !((ref2 = this.tag(i + 2)) === 'FOROF' || ref2 === 'FORIN') && (nextTag !== 'TERMINATOR' || !this.looksObjectish(i + 2))) {
|
||||
// When nextTag is OUTDENT the comma is insignificant and
|
||||
// should just be ignored so embed it in the implicit object.
|
||||
|
||||
@@ -781,18 +802,51 @@
|
||||
// newlines within expressions are removed and the indentation tokens of empty
|
||||
// blocks are added.
|
||||
normalizeLines() {
|
||||
var action, condition, indent, outdent, starter;
|
||||
var action, closeElseTag, condition, ifThens, indent, leading_if_then, leading_switch_when, outdent, starter;
|
||||
starter = indent = outdent = null;
|
||||
leading_switch_when = null;
|
||||
leading_if_then = null;
|
||||
// Count `THEN` tags
|
||||
ifThens = [];
|
||||
condition = function(token, i) {
|
||||
var ref, ref1, ref2, ref3;
|
||||
return token[1] !== ';' && (ref = token[0], indexOf.call(SINGLE_CLOSERS, ref) >= 0) && !(token[0] === 'TERMINATOR' && (ref1 = this.tag(i + 1), indexOf.call(EXPRESSION_CLOSE, ref1) >= 0)) && !(token[0] === 'ELSE' && starter !== 'THEN') && !(((ref2 = token[0]) === 'CATCH' || ref2 === 'FINALLY') && (starter === '->' || starter === '=>')) || (ref3 = token[0], indexOf.call(CALL_CLOSERS, ref3) >= 0) && (this.tokens[i - 1].newLine || this.tokens[i - 1][0] === 'OUTDENT');
|
||||
return token[1] !== ';' && (ref = token[0], indexOf.call(SINGLE_CLOSERS, ref) >= 0) && !(token[0] === 'TERMINATOR' && (ref1 = this.tag(i + 1), indexOf.call(EXPRESSION_CLOSE, ref1) >= 0)) && !(token[0] === 'ELSE' && (starter !== 'THEN' || (leading_if_then || leading_switch_when))) && !(((ref2 = token[0]) === 'CATCH' || ref2 === 'FINALLY') && (starter === '->' || starter === '=>')) || (ref3 = token[0], indexOf.call(CALL_CLOSERS, ref3) >= 0) && (this.tokens[i - 1].newLine || this.tokens[i - 1][0] === 'OUTDENT');
|
||||
};
|
||||
action = function(token, i) {
|
||||
if (token[0] === 'ELSE' && starter === 'THEN') {
|
||||
ifThens.pop();
|
||||
}
|
||||
return this.tokens.splice((this.tag(i - 1) === ',' ? i - 1 : i), 0, outdent);
|
||||
};
|
||||
closeElseTag = (tokens, i) => {
|
||||
var lastThen, outdentElse, tlen;
|
||||
tlen = ifThens.length;
|
||||
if (!(tlen > 0)) {
|
||||
return i;
|
||||
}
|
||||
lastThen = ifThens.pop();
|
||||
[, outdentElse] = this.indentation(tokens[lastThen]);
|
||||
// Insert `OUTDENT` to close inner `IF`.
|
||||
outdentElse[1] = tlen * 2;
|
||||
tokens.splice(i, 0, outdentElse);
|
||||
// Insert `OUTDENT` to close outer `IF`.
|
||||
outdentElse[1] = 2;
|
||||
tokens.splice(i + 1, 0, outdentElse);
|
||||
// Remove outdents from the end.
|
||||
this.detectEnd(i + 2, function(token, i) {
|
||||
var ref;
|
||||
return (ref = token[0]) === 'OUTDENT' || ref === 'TERMINATOR';
|
||||
}, function(token, i) {
|
||||
if (this.tag(i) === 'OUTDENT' && this.tag(i + 1) === 'OUTDENT') {
|
||||
return tokens.splice(i, 2);
|
||||
}
|
||||
});
|
||||
return i + 2;
|
||||
};
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var j, k, ref, ref1, tag;
|
||||
var conditionTag, j, k, ref, ref1, tag;
|
||||
[tag] = token;
|
||||
conditionTag = (tag === '->' || tag === '=>') && this.findTagsBackwards(i, ['IF', 'WHILE', 'FOR', 'UNTIL', 'SWITCH', 'WHEN', 'LEADING_WHEN', '[', 'INDEX_START']) && !(this.findTagsBackwards(i, ['THEN', '..', '...']));
|
||||
if (tag === 'TERMINATOR') {
|
||||
if (this.tag(i + 1) === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') {
|
||||
tokens.splice(i, 1, ...this.indentation());
|
||||
@@ -817,12 +871,23 @@
|
||||
tokens.splice(i + 1, 0, indent, outdent);
|
||||
return 1;
|
||||
}
|
||||
if (indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) {
|
||||
if (indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF') && !conditionTag) {
|
||||
starter = tag;
|
||||
[indent, outdent] = this.indentation(tokens[i]);
|
||||
if (starter === 'THEN') {
|
||||
indent.fromThen = true;
|
||||
}
|
||||
if (tag === 'THEN') {
|
||||
leading_switch_when = this.findTagsBackwards(i, ['LEADING_WHEN']) && this.tag(i + 1) === 'IF';
|
||||
leading_if_then = this.findTagsBackwards(i, ['IF']) && this.tag(i + 1) === 'IF';
|
||||
}
|
||||
if (tag === 'THEN' && this.findTagsBackwards(i, ['IF'])) {
|
||||
ifThens.push(i);
|
||||
}
|
||||
// `ELSE` tag is not closed.
|
||||
if (tag === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') {
|
||||
i = closeElseTag(tokens, i);
|
||||
}
|
||||
tokens.splice(i + 1, 0, indent);
|
||||
this.detectEnd(i + 2, condition, action);
|
||||
if (tag === 'THEN') {
|
||||
@@ -886,7 +951,7 @@
|
||||
|
||||
return Rewriter;
|
||||
|
||||
})();
|
||||
}).call(this);
|
||||
|
||||
// Constants
|
||||
// ---------
|
||||
@@ -944,6 +1009,6 @@
|
||||
// `STRING_START` isn’t on this list because its `locationData` matches that of
|
||||
// the node that becomes `StringWithInterpolations`, and therefore
|
||||
// `addDataToNode` attaches `STRING_START`’s tokens to that node.
|
||||
DISCARDED = ['(', ')', '[', ']', '{', '}', '.', '..', '...', ',', '=', '++', '--', '?', 'AS', 'AWAIT', 'CALL_START', 'CALL_END', 'DEFAULT', 'ELSE', 'EXTENDS', 'EXPORT', 'FORIN', 'FOROF', 'FORFROM', 'IMPORT', 'INDENT', 'INDEX_SOAK', 'LEADING_WHEN', 'OUTDENT', 'PARAM_START', 'PARAM_END', 'REGEX_START', 'REGEX_END', 'RETURN', 'STRING_END', 'THROW', 'UNARY', 'YIELD'].concat(IMPLICIT_UNSPACED_CALL.concat(IMPLICIT_END.concat(CALL_CLOSERS.concat(CONTROL_IN_IMPLICIT))));
|
||||
DISCARDED = ['(', ')', '[', ']', '{', '}', '.', '..', '...', ',', '=', '++', '--', '?', 'AS', 'AWAIT', 'CALL_START', 'CALL_END', 'DEFAULT', 'ELSE', 'EXTENDS', 'EXPORT', 'FORIN', 'FOROF', 'FORFROM', 'IMPORT', 'INDENT', 'INDEX_SOAK', 'LEADING_WHEN', 'OUTDENT', 'PARAM_END', 'REGEX_START', 'REGEX_END', 'RETURN', 'STRING_END', 'THROW', 'UNARY', 'YIELD'].concat(IMPLICIT_UNSPACED_CALL.concat(IMPLICIT_END.concat(CALL_CLOSERS.concat(CONTROL_IN_IMPLICIT))));
|
||||
|
||||
}).call(this);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.3.0
|
||||
(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
|
||||
@@ -14,7 +14,8 @@
|
||||
// as well as a reference to the **Block** node it belongs to, which is
|
||||
// where it should declare its variables, a reference to the function that
|
||||
// it belongs to, and a list of variables referenced in the source code
|
||||
// and therefore should be avoided when generating variables.
|
||||
// and therefore should be avoided when generating variables. Also track comments
|
||||
// that should be output as part of variable declarations.
|
||||
constructor(parent, expressions, method, referencedVars) {
|
||||
var ref, ref1;
|
||||
this.parent = parent;
|
||||
@@ -27,6 +28,7 @@
|
||||
type: 'arguments'
|
||||
}
|
||||
];
|
||||
this.comments = {};
|
||||
this.positions = {};
|
||||
if (!this.parent) {
|
||||
this.utilities = {};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.3.0
|
||||
(function() {
|
||||
// Source maps allow JavaScript runtimes to match running JavaScript back to
|
||||
// the original source code that corresponds to it. This can be minified
|
||||
@@ -47,18 +47,18 @@
|
||||
|
||||
};
|
||||
|
||||
// SourceMap
|
||||
// ---------
|
||||
|
||||
// Maps locations in a single generated JavaScript file back to locations in
|
||||
// the original CoffeeScript source file.
|
||||
|
||||
// This is intentionally agnostic towards how a source map might be represented on
|
||||
// disk. Once the compiler is ready to produce a "v3"-style source map, we can walk
|
||||
// through the arrays of line and column buffer to produce it.
|
||||
SourceMap = (function() {
|
||||
var BASE64_CHARS, VLQ_CONTINUATION_BIT, VLQ_SHIFT, VLQ_VALUE_MASK;
|
||||
|
||||
// SourceMap
|
||||
// ---------
|
||||
|
||||
// Maps locations in a single generated JavaScript file back to locations in
|
||||
// the original CoffeeScript source file.
|
||||
|
||||
// This is intentionally agnostic towards how a source map might be represented on
|
||||
// disk. Once the compiler is ready to produce a "v3"-style source map, we can walk
|
||||
// through the arrays of line and column buffer to produce it.
|
||||
class SourceMap {
|
||||
constructor() {
|
||||
this.lines = [];
|
||||
@@ -203,7 +203,7 @@
|
||||
|
||||
return SourceMap;
|
||||
|
||||
})();
|
||||
}).call(this);
|
||||
|
||||
// Our API for source maps is just the `SourceMap` class.
|
||||
module.exports = SourceMap;
|
||||
|
||||
4315
package-lock.json
generated
4315
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
21
package.json
21
package.json
@@ -8,7 +8,7 @@
|
||||
"compiler"
|
||||
],
|
||||
"author": "Jeremy Ashkenas",
|
||||
"version": "2.0.0",
|
||||
"version": "2.3.0",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
@@ -39,20 +39,17 @@
|
||||
"url": "git://github.com/jashkenas/coffeescript.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "~6.26.0",
|
||||
"babel-core": "~6.26.2",
|
||||
"babel-preset-babili": "~0.1.4",
|
||||
"babel-preset-env": "~1.6.0",
|
||||
"babel-preset-minify": "^0.2.0",
|
||||
"codemirror": "^5.29.0",
|
||||
"docco": "~0.7.0",
|
||||
"babel-preset-env": "~1.6.1",
|
||||
"babel-preset-minify": "^0.4.0",
|
||||
"codemirror": "^5.37.0",
|
||||
"docco": "~0.8.0",
|
||||
"highlight.js": "~9.12.0",
|
||||
"jison": ">=0.4.18",
|
||||
"markdown-it": "~8.4.0",
|
||||
"underscore": "~1.8.3",
|
||||
"webpack": "~3.6.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"babel-core": "^6"
|
||||
"markdown-it": "~8.4.1",
|
||||
"underscore": "~1.9.0",
|
||||
"webpack": "~4.6.0"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
|
||||
@@ -140,12 +140,14 @@ exports.compile = compile = withPrettyErrors (code, options = {}) ->
|
||||
transpiler = options.transpile.transpile
|
||||
delete options.transpile.transpile
|
||||
|
||||
transpilerOptions = Object.assign {}, options.transpile
|
||||
|
||||
# See https://github.com/babel/babel/issues/827#issuecomment-77573107:
|
||||
# Babel can take a v3 source map object as input in `inputSourceMap`
|
||||
# and it will return an *updated* v3 source map object in its output.
|
||||
if v3SourceMap and not options.transpile.inputSourceMap?
|
||||
options.transpile.inputSourceMap = v3SourceMap
|
||||
transpilerOutput = transpiler js, options.transpile
|
||||
if v3SourceMap and not transpilerOptions.inputSourceMap?
|
||||
transpilerOptions.inputSourceMap = v3SourceMap
|
||||
transpilerOutput = transpiler js, transpilerOptions
|
||||
js = transpilerOutput.code
|
||||
if v3SourceMap and transpilerOutput.map
|
||||
v3SourceMap = transpilerOutput.map
|
||||
|
||||
@@ -92,6 +92,7 @@ exports.run = ->
|
||||
replCliOpts = useGlobal: yes
|
||||
opts.prelude = makePrelude opts.require if opts.require
|
||||
replCliOpts.prelude = opts.prelude
|
||||
replCliOpts.transpile = opts.transpile
|
||||
return forkNode() if opts.nodejs
|
||||
return usage() if opts.help
|
||||
return version() if opts.version
|
||||
@@ -243,6 +244,9 @@ compileScript = (file, input, base = null) ->
|
||||
# Attach the appropriate listeners to compile scripts incoming over **stdin**,
|
||||
# and write them back to **stdout**.
|
||||
compileStdio = ->
|
||||
if opts.map
|
||||
console.error '--stdio and --map cannot be used together'
|
||||
process.exit 1
|
||||
buffers = []
|
||||
stdin = process.openStdin()
|
||||
stdin.on 'data', (buffer) ->
|
||||
@@ -397,7 +401,7 @@ mkdirp = (dir, fn) ->
|
||||
# If `generatedSourceMap` is provided, this will write a `.js.map` file into the
|
||||
# same directory as the `.js` file.
|
||||
writeJs = (base, sourcePath, js, jsPath, generatedSourceMap = null) ->
|
||||
sourceMapPath = outputPath sourcePath, base, ".js.map"
|
||||
sourceMapPath = "#{jsPath}.map"
|
||||
jsDir = path.dirname jsPath
|
||||
compile = ->
|
||||
if opts.compile
|
||||
@@ -444,65 +448,46 @@ parseOptions = ->
|
||||
compileOptions = (filename, base) ->
|
||||
if opts.transpile
|
||||
# The user has requested that the CoffeeScript compiler also transpile
|
||||
# via Babel. We use Babel as an `optionalDependency`; see
|
||||
# https://docs.npmjs.com/files/package.json#optionaldependencies.
|
||||
# via Babel. We don’t include Babel as a dependency because we want to
|
||||
# avoid dependencies in general, and most users probably won’t be relying
|
||||
# on us to transpile for them; we assume most users will probably either
|
||||
# run CoffeeScript’s output without transpilation (modern Node or evergreen
|
||||
# browsers) or use a proper build chain like Gulp or Webpack.
|
||||
try
|
||||
require 'babel-core'
|
||||
catch
|
||||
console.error '''
|
||||
To use --transpile, you must have Babel installed and configured.
|
||||
See http://coffeescript.org/#transpilation
|
||||
'''
|
||||
process.exit 1
|
||||
|
||||
# We’re giving Babel only a string, not a filename or path to a file, so
|
||||
# it doesn’t know where to search to find a `.babelrc` file or a `babel`
|
||||
# key in a `package.json`. So if `opts.transpile` is an object, use that
|
||||
# as Babel’s options; otherwise figure out what the options should be.
|
||||
unless typeof opts.transpile is 'object'
|
||||
# Find the options based on the path to the file being compiled.
|
||||
cantFindOptions = ->
|
||||
# Give appropriate instructions depending on whether `coffee` was run
|
||||
# locally or globally.
|
||||
if require.resolve('.').indexOf(process.cwd()) is 0
|
||||
console.error '''
|
||||
To use the transpile option, there must be a .babelrc file
|
||||
(or a package.json file with a "babel" key) in the path of the file
|
||||
to be compiled, or in the path of the current working directory.
|
||||
If you are compiling a string via the Node API, the transpile option
|
||||
must be an object with the options to pass to Babel.
|
||||
To use --transpile, you must have babel-core installed:
|
||||
npm install --save-dev babel-core
|
||||
And you must save options to configure Babel in one of the places it looks to find its options.
|
||||
See http://coffeescript.org/#transpilation
|
||||
'''
|
||||
process.exit 1
|
||||
|
||||
checkPath = if filename
|
||||
path.dirname filename
|
||||
else if base
|
||||
base
|
||||
else if process?
|
||||
process.cwd()
|
||||
else
|
||||
cantFindOptions()
|
||||
console.error '''
|
||||
To use --transpile with globally-installed CoffeeScript, you must have babel-core installed globally:
|
||||
npm install --global babel-core
|
||||
And you must save options to configure Babel in one of the places it looks to find its options, relative to the file being compiled or to the current folder.
|
||||
See http://coffeescript.org/#transpilation
|
||||
'''
|
||||
process.exit 1
|
||||
|
||||
loop
|
||||
try
|
||||
opts.transpile = JSON.parse fs.readFileSync path.join(checkPath, '.babelrc'), 'utf-8'
|
||||
break
|
||||
catch
|
||||
try
|
||||
packageJson = JSON.parse fs.readFileSync(path.join(checkPath, 'package.json'), 'utf-8')
|
||||
if packageJson.babel?
|
||||
opts.transpile = packageJson.babel
|
||||
break
|
||||
|
||||
if checkPath is path.dirname checkPath # We’ve reached the root.
|
||||
cantFindOptions()
|
||||
break
|
||||
else
|
||||
checkPath = path.dirname checkPath
|
||||
opts.transpile = {} unless typeof opts.transpile is 'object'
|
||||
|
||||
# Pass a reference to Babel into the compiler, so that the transpile option
|
||||
# is available for the CLI. We need to do this so that tools like Webpack
|
||||
# can `require('coffeescript')` and build correctly, without trying to
|
||||
# require Babel.
|
||||
opts.transpile.transpile = CoffeeScript.transpile
|
||||
|
||||
# Babel searches for its options (a `.babelrc` file, a `.babelrc.js` file,
|
||||
# a `package.json` file with a `babel` key, etc.) relative to the path
|
||||
# given to it in its `filename` option. Make sure we have a path to pass
|
||||
# along.
|
||||
unless opts.transpile.filename
|
||||
opts.transpile.filename = filename or path.resolve(base or process.cwd(), '<anonymous>')
|
||||
else
|
||||
opts.transpile = no
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ grammar =
|
||||
# grammar.
|
||||
Line: [
|
||||
o 'Expression'
|
||||
o 'ExpressionLine'
|
||||
o 'Statement'
|
||||
o 'FuncDirective'
|
||||
]
|
||||
@@ -125,6 +126,15 @@ grammar =
|
||||
o 'Yield'
|
||||
]
|
||||
|
||||
# Expressions which are written in single line and would otherwise require being
|
||||
# wrapped in braces: E.g `a = b if do -> f a is 1`, `if f (a) -> a*2 then ...`,
|
||||
# `for x in do (obj) -> f obj when x > 8 then f x`
|
||||
ExpressionLine: [
|
||||
o 'CodeLine'
|
||||
o 'IfLine'
|
||||
o 'OperationLine'
|
||||
]
|
||||
|
||||
Yield: [
|
||||
o 'YIELD', -> new Op $1, new Value new Literal ''
|
||||
o 'YIELD Expression', -> new Op $1, $2
|
||||
@@ -210,6 +220,7 @@ grammar =
|
||||
|
||||
ObjAssignable: [
|
||||
o 'SimpleObjAssignable'
|
||||
o '[ Expression ]', -> new Value new ComputedPropertyName $2
|
||||
o 'AlphaNumeric'
|
||||
]
|
||||
|
||||
@@ -262,10 +273,17 @@ grammar =
|
||||
# The **Code** node is the function literal. It's defined by an indented block
|
||||
# of **Block** preceded by a function arrow, with an optional parameter list.
|
||||
Code: [
|
||||
o 'PARAM_START ParamList PARAM_END FuncGlyph Block', -> new Code $2, $5, $4
|
||||
o 'PARAM_START ParamList PARAM_END FuncGlyph Block', -> new Code $2, $5, $4, LOC(1)(new Literal $1)
|
||||
o 'FuncGlyph Block', -> new Code [], $2, $1
|
||||
]
|
||||
|
||||
# The Codeline is the **Code** node with **Line** instead of indented **Block**.
|
||||
CodeLine: [
|
||||
o 'PARAM_START ParamList PARAM_END FuncGlyph Line', -> new Code $2, LOC(5)(Block.wrap [$5]), $4,
|
||||
LOC(1)(new Literal $1)
|
||||
o 'FuncGlyph Line', -> new Code [], LOC(2)(Block.wrap [$2]), $1
|
||||
]
|
||||
|
||||
# CoffeeScript has two different symbols for functions. `->` is for ordinary
|
||||
# functions, and `=>` is for functions bound to the current value of *this*.
|
||||
FuncGlyph: [
|
||||
@@ -439,6 +457,7 @@ grammar =
|
||||
o 'EXPORT Identifier = INDENT Expression OUTDENT', -> new ExportNamedDeclaration new Assign $2, $5, null,
|
||||
moduleDeclaration: 'export'
|
||||
o 'EXPORT DEFAULT Expression', -> new ExportDefaultDeclaration $3
|
||||
o 'EXPORT DEFAULT INDENT Object OUTDENT', -> new ExportDefaultDeclaration new Value $4
|
||||
o 'EXPORT EXPORT_ALL FROM String', -> new ExportAllDeclaration new Literal($2), $4
|
||||
o 'EXPORT { ExportSpecifierList OptComma } FROM String', -> new ExportNamedDeclaration new ExportSpecifierList($3), $7
|
||||
]
|
||||
@@ -492,7 +511,8 @@ grammar =
|
||||
# The array literal.
|
||||
Array: [
|
||||
o '[ ]', -> new Arr []
|
||||
o '[ ArgList OptComma ]', -> new Arr $2
|
||||
o '[ Elisions ]', -> new Arr $2
|
||||
o '[ ArgElisionList OptElisions ]', -> new Arr [].concat $2, $3
|
||||
]
|
||||
|
||||
# Inclusive and exclusive range dots.
|
||||
@@ -503,19 +523,21 @@ grammar =
|
||||
|
||||
# The CoffeeScript range literal.
|
||||
Range: [
|
||||
o '[ Expression RangeDots Expression ]', -> new Range $2, $4, $3
|
||||
o '[ Expression RangeDots Expression ]', -> new Range $2, $4, $3
|
||||
o '[ ExpressionLine RangeDots Expression ]', -> new Range $2, $4, $3
|
||||
]
|
||||
|
||||
# Array slice literals.
|
||||
Slice: [
|
||||
o 'Expression RangeDots Expression', -> new Range $1, $3, $2
|
||||
o 'Expression RangeDots', -> new Range $1, null, $2
|
||||
o 'ExpressionLine RangeDots Expression', -> new Range $1, $3, $2
|
||||
o 'ExpressionLine RangeDots', -> new Range $1, null, $2
|
||||
o 'RangeDots Expression', -> new Range null, $2, $1
|
||||
o 'RangeDots', -> new Range null, null, $1
|
||||
]
|
||||
|
||||
# The **ArgList** is both the list of objects passed into a function call,
|
||||
# as well as the contents of an array literal
|
||||
# The **ArgList** is the list of objects passed into a function call
|
||||
# (i.e. comma-separated expressions). Newlines work as well.
|
||||
ArgList: [
|
||||
o 'Arg', -> [$1]
|
||||
@@ -528,16 +550,48 @@ grammar =
|
||||
# Valid arguments are Blocks or Splats.
|
||||
Arg: [
|
||||
o 'Expression'
|
||||
o 'ExpressionLine'
|
||||
o 'Splat'
|
||||
o '...', -> new Expansion
|
||||
]
|
||||
|
||||
# The **ArgElisionList** is the list of objects, contents of an array literal
|
||||
# (i.e. comma-separated expressions and elisions). Newlines work as well.
|
||||
ArgElisionList: [
|
||||
o 'ArgElision'
|
||||
o 'ArgElisionList , ArgElision', -> $1.concat $3
|
||||
o 'ArgElisionList OptElisions TERMINATOR ArgElision', -> $1.concat $2, $4
|
||||
o 'INDENT ArgElisionList OptElisions OUTDENT', -> $2.concat $3
|
||||
o 'ArgElisionList OptElisions INDENT ArgElisionList OptElisions OUTDENT', -> $1.concat $2, $4, $5
|
||||
]
|
||||
|
||||
ArgElision: [
|
||||
o 'Arg', -> [$1]
|
||||
o 'Elisions Arg', -> $1.concat $2
|
||||
]
|
||||
|
||||
OptElisions: [
|
||||
o 'OptComma', -> []
|
||||
o ', Elisions', -> [].concat $2
|
||||
]
|
||||
|
||||
Elisions: [
|
||||
o 'Elision', -> [$1]
|
||||
o 'Elisions Elision', -> $1.concat $2
|
||||
]
|
||||
|
||||
Elision: [
|
||||
o ',', -> new Elision
|
||||
]
|
||||
|
||||
# Just simple, comma-separated, required arguments (no fancy syntax). We need
|
||||
# this to be separate from the **ArgList** for use in **Switch** blocks, where
|
||||
# having the newlines wouldn't make sense.
|
||||
SimpleArgs: [
|
||||
o 'Expression'
|
||||
o 'ExpressionLine'
|
||||
o 'SimpleArgs , Expression', -> [].concat $1, $3
|
||||
o 'SimpleArgs , ExpressionLine', -> [].concat $1, $3
|
||||
]
|
||||
|
||||
# The variants of *try/catch/finally* exception handling blocks.
|
||||
@@ -571,17 +625,27 @@ grammar =
|
||||
]
|
||||
|
||||
# The condition portion of a while loop.
|
||||
WhileLineSource: [
|
||||
o 'WHILE ExpressionLine', -> new While $2
|
||||
o 'WHILE ExpressionLine WHEN ExpressionLine', -> new While $2, guard: $4
|
||||
o 'UNTIL ExpressionLine', -> new While $2, invert: true
|
||||
o 'UNTIL ExpressionLine WHEN ExpressionLine', -> new While $2, invert: true, guard: $4
|
||||
]
|
||||
|
||||
WhileSource: [
|
||||
o 'WHILE Expression', -> new While $2
|
||||
o 'WHILE Expression WHEN Expression', -> new While $2, guard: $4
|
||||
o 'WHILE ExpressionLine WHEN Expression', -> new While $2, guard: $4
|
||||
o 'UNTIL Expression', -> new While $2, invert: true
|
||||
o 'UNTIL Expression WHEN Expression', -> new While $2, invert: true, guard: $4
|
||||
o 'UNTIL ExpressionLine WHEN Expression', -> new While $2, invert: true, guard: $4
|
||||
]
|
||||
|
||||
# The while loop can either be normal, with a block of expressions to execute,
|
||||
# or postfix, with a single expression. There is no do..while.
|
||||
While: [
|
||||
o 'WhileSource Block', -> $1.addBody $2
|
||||
o 'WhileLineSource Block', -> $1.addBody $2
|
||||
o 'Statement WhileSource', -> $2.addBody LOC(1) Block.wrap([$1])
|
||||
o 'Expression WhileSource', -> $2.addBody LOC(1) Block.wrap([$1])
|
||||
o 'Loop', -> $1
|
||||
@@ -596,20 +660,31 @@ grammar =
|
||||
# Comprehensions can either be normal, with a block of expressions to execute,
|
||||
# or postfix, with a single expression.
|
||||
For: [
|
||||
o 'Statement ForBody', -> new For $1, $2
|
||||
o 'Expression ForBody', -> new For $1, $2
|
||||
o 'ForBody Block', -> new For $2, $1
|
||||
o 'Statement ForBody', -> $2.addBody $1
|
||||
o 'Expression ForBody', -> $2.addBody $1
|
||||
o 'ForBody Block', -> $1.addBody $2
|
||||
o 'ForLineBody Block', -> $1.addBody $2
|
||||
]
|
||||
|
||||
ForBody: [
|
||||
o 'FOR Range', -> source: (LOC(2) new Value($2))
|
||||
o 'FOR Range BY Expression', -> source: (LOC(2) new Value($2)), step: $4
|
||||
o 'ForStart ForSource', -> $2.own = $1.own; $2.ownTag = $1.ownTag; $2.name = $1[0]; $2.index = $1[1]; $2
|
||||
o 'FOR Range', -> new For [], source: (LOC(2) new Value($2))
|
||||
o 'FOR Range BY Expression', -> new For [], source: (LOC(2) new Value($2)), step: $4
|
||||
o 'ForStart ForSource', -> $1.addSource $2
|
||||
]
|
||||
|
||||
ForLineBody: [
|
||||
o 'FOR Range BY ExpressionLine', -> new For [], source: (LOC(2) new Value($2)), step: $4
|
||||
o 'ForStart ForLineSource', -> $1.addSource $2
|
||||
]
|
||||
|
||||
ForStart: [
|
||||
o 'FOR ForVariables', -> $2
|
||||
o 'FOR OWN ForVariables', -> $3.own = yes; $3.ownTag = (LOC(2) new Literal($2)); $3
|
||||
o 'FOR ForVariables', -> new For [], name: $2[0], index: $2[1]
|
||||
o 'FOR AWAIT ForVariables', ->
|
||||
[name, index] = $3
|
||||
new For [], {name, index, await: yes, awaitTag: (LOC(2) new Literal($2))}
|
||||
o 'FOR OWN ForVariables', ->
|
||||
[name, index] = $3
|
||||
new For [], {name, index, own: yes, ownTag: (LOC(2) new Literal($2))}
|
||||
]
|
||||
|
||||
# An array of all accepted values for a variable inside the loop.
|
||||
@@ -633,22 +708,56 @@ grammar =
|
||||
# clause. If it's an array comprehension, you can also choose to step through
|
||||
# in fixed-size increments.
|
||||
ForSource: [
|
||||
o 'FORIN Expression', -> source: $2
|
||||
o 'FOROF Expression', -> source: $2, object: yes
|
||||
o 'FORIN Expression WHEN Expression', -> source: $2, guard: $4
|
||||
o 'FOROF Expression WHEN Expression', -> source: $2, guard: $4, object: yes
|
||||
o 'FORIN Expression BY Expression', -> source: $2, step: $4
|
||||
o 'FORIN Expression WHEN Expression BY Expression', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN Expression BY Expression WHEN Expression', -> source: $2, step: $4, guard: $6
|
||||
o 'FORFROM Expression', -> source: $2, from: yes
|
||||
o 'FORFROM Expression WHEN Expression', -> source: $2, guard: $4, from: yes
|
||||
o 'FORIN Expression', -> source: $2
|
||||
o 'FOROF Expression', -> source: $2, object: yes
|
||||
o 'FORIN Expression WHEN Expression', -> source: $2, guard: $4
|
||||
o 'FORIN ExpressionLine WHEN Expression', -> source: $2, guard: $4
|
||||
o 'FOROF Expression WHEN Expression', -> source: $2, guard: $4, object: yes
|
||||
o 'FOROF ExpressionLine WHEN Expression', -> source: $2, guard: $4, object: yes
|
||||
o 'FORIN Expression BY Expression', -> source: $2, step: $4
|
||||
o 'FORIN ExpressionLine BY Expression', -> source: $2, step: $4
|
||||
o 'FORIN Expression WHEN Expression BY Expression', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN ExpressionLine WHEN Expression BY Expression', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN Expression WHEN ExpressionLine BY Expression', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN ExpressionLine WHEN ExpressionLine BY Expression', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN Expression BY Expression WHEN Expression', -> source: $2, step: $4, guard: $6
|
||||
o 'FORIN ExpressionLine BY Expression WHEN Expression', -> source: $2, step: $4, guard: $6
|
||||
o 'FORIN Expression BY ExpressionLine WHEN Expression', -> source: $2, step: $4, guard: $6
|
||||
o 'FORIN ExpressionLine BY ExpressionLine WHEN Expression', -> source: $2, step: $4, guard: $6
|
||||
o 'FORFROM Expression', -> source: $2, from: yes
|
||||
o 'FORFROM Expression WHEN Expression', -> source: $2, guard: $4, from: yes
|
||||
o 'FORFROM ExpressionLine WHEN Expression', -> source: $2, guard: $4, from: yes
|
||||
]
|
||||
|
||||
ForLineSource: [
|
||||
o 'FORIN ExpressionLine', -> source: $2
|
||||
o 'FOROF ExpressionLine', -> source: $2, object: yes
|
||||
o 'FORIN Expression WHEN ExpressionLine', -> source: $2, guard: $4
|
||||
o 'FORIN ExpressionLine WHEN ExpressionLine', -> source: $2, guard: $4
|
||||
o 'FOROF Expression WHEN ExpressionLine', -> source: $2, guard: $4, object: yes
|
||||
o 'FOROF ExpressionLine WHEN ExpressionLine', -> source: $2, guard: $4, object: yes
|
||||
o 'FORIN Expression BY ExpressionLine', -> source: $2, step: $4
|
||||
o 'FORIN ExpressionLine BY ExpressionLine', -> source: $2, step: $4
|
||||
o 'FORIN Expression WHEN Expression BY ExpressionLine', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN ExpressionLine WHEN Expression BY ExpressionLine', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN Expression WHEN ExpressionLine BY ExpressionLine', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN ExpressionLine WHEN ExpressionLine BY ExpressionLine', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN Expression BY Expression WHEN ExpressionLine', -> source: $2, step: $4, guard: $6
|
||||
o 'FORIN ExpressionLine BY Expression WHEN ExpressionLine', -> source: $2, step: $4, guard: $6
|
||||
o 'FORIN Expression BY ExpressionLine WHEN ExpressionLine', -> source: $2, step: $4, guard: $6
|
||||
o 'FORIN ExpressionLine BY ExpressionLine WHEN ExpressionLine', -> source: $2, step: $4, guard: $6
|
||||
o 'FORFROM ExpressionLine', -> source: $2, from: yes
|
||||
o 'FORFROM Expression WHEN ExpressionLine', -> source: $2, guard: $4, from: yes
|
||||
o 'FORFROM ExpressionLine WHEN ExpressionLine', -> source: $2, guard: $4, from: yes
|
||||
]
|
||||
|
||||
Switch: [
|
||||
o 'SWITCH Expression INDENT Whens OUTDENT', -> new Switch $2, $4
|
||||
o 'SWITCH Expression INDENT Whens ELSE Block OUTDENT', -> new Switch $2, $4, $6
|
||||
o 'SWITCH INDENT Whens OUTDENT', -> new Switch null, $3
|
||||
o 'SWITCH INDENT Whens ELSE Block OUTDENT', -> new Switch null, $3, $5
|
||||
o 'SWITCH Expression INDENT Whens OUTDENT', -> new Switch $2, $4
|
||||
o 'SWITCH ExpressionLine INDENT Whens OUTDENT', -> new Switch $2, $4
|
||||
o 'SWITCH Expression INDENT Whens ELSE Block OUTDENT', -> new Switch $2, $4, $6
|
||||
o 'SWITCH ExpressionLine INDENT Whens ELSE Block OUTDENT', -> new Switch $2, $4, $6
|
||||
o 'SWITCH INDENT Whens OUTDENT', -> new Switch null, $3
|
||||
o 'SWITCH INDENT Whens ELSE Block OUTDENT', -> new Switch null, $3, $5
|
||||
]
|
||||
|
||||
Whens: [
|
||||
@@ -679,12 +788,28 @@ grammar =
|
||||
o 'Expression POST_IF Expression', -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, statement: true
|
||||
]
|
||||
|
||||
IfBlockLine: [
|
||||
o 'IF ExpressionLine Block', -> new If $2, $3, type: $1
|
||||
o 'IfBlockLine ELSE IF ExpressionLine Block', -> $1.addElse LOC(3,5) new If $4, $5, type: $3
|
||||
]
|
||||
|
||||
IfLine: [
|
||||
o 'IfBlockLine'
|
||||
o 'IfBlockLine ELSE Block', -> $1.addElse $3
|
||||
o 'Statement POST_IF ExpressionLine', -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, statement: true
|
||||
o 'Expression POST_IF ExpressionLine', -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, statement: true
|
||||
]
|
||||
|
||||
# Arithmetic and logical operators, working on one or more operands.
|
||||
# Here they are grouped by order of precedence. The actual precedence rules
|
||||
# are defined at the bottom of the page. It would be shorter if we could
|
||||
# combine most of these rules into a single generic *Operand OpSymbol Operand*
|
||||
# -type rule, but in order to make the precedence binding possible, separate
|
||||
# rules are necessary.
|
||||
OperationLine: [
|
||||
o 'UNARY ExpressionLine', -> new Op $1, $2
|
||||
]
|
||||
|
||||
Operation: [
|
||||
o 'UNARY Expression', -> new Op $1 , $2
|
||||
o 'UNARY_MATH Expression', -> new Op $1 , $2
|
||||
|
||||
@@ -46,6 +46,9 @@ CoffeeScript.run = (code, options = {}) ->
|
||||
fs.realpathSync '.'
|
||||
mainModule.paths = require('module')._nodeModulePaths dir
|
||||
|
||||
# Save the options for compiling child imports.
|
||||
mainModule.options = options
|
||||
|
||||
# Compile.
|
||||
if not helpers.isCoffee(mainModule.filename) or require.extensions
|
||||
answer = CoffeeScript.compile code, options
|
||||
@@ -104,17 +107,19 @@ if require.extensions
|
||||
Use CoffeeScript.register() or require the coffeescript/register module to require #{ext} files.
|
||||
"""
|
||||
|
||||
CoffeeScript._compileFile = (filename, sourceMap = no, inlineMap = no) ->
|
||||
CoffeeScript._compileFile = (filename, options = {}) ->
|
||||
raw = fs.readFileSync filename, 'utf8'
|
||||
# Strip the Unicode byte order mark, if this file begins with one.
|
||||
stripped = if raw.charCodeAt(0) is 0xFEFF then raw.substring 1 else raw
|
||||
|
||||
options = Object.assign {}, options,
|
||||
filename: filename
|
||||
literate: helpers.isLiterate filename
|
||||
sourceFiles: [filename]
|
||||
inlineMap: yes # Always generate a source map, so that stack traces line up.
|
||||
|
||||
try
|
||||
answer = CoffeeScript.compile stripped, {
|
||||
filename, sourceMap, inlineMap
|
||||
sourceFiles: [filename]
|
||||
literate: helpers.isLiterate filename
|
||||
}
|
||||
answer = CoffeeScript.compile stripped, options
|
||||
catch err
|
||||
# As the filename and code of a dynamically loaded file will be different
|
||||
# from the original file compiled with CoffeeScript.run, add that
|
||||
|
||||
@@ -116,7 +116,6 @@ exports.Lexer = class Lexer
|
||||
# Preserve length of id for location data
|
||||
idLength = id.length
|
||||
poppedToken = undefined
|
||||
|
||||
if id is 'own' and @tag() is 'FOR'
|
||||
@token 'OWN', id
|
||||
return id.length
|
||||
@@ -126,14 +125,21 @@ exports.Lexer = class Lexer
|
||||
if id is 'as' and @seenImport
|
||||
if @value() is '*'
|
||||
@tokens[@tokens.length - 1][0] = 'IMPORT_ALL'
|
||||
else if @value() in COFFEE_KEYWORDS
|
||||
@tokens[@tokens.length - 1][0] = 'IDENTIFIER'
|
||||
else if @value(yes) in COFFEE_KEYWORDS
|
||||
prev = @prev()
|
||||
[prev[0], prev[1]] = ['IDENTIFIER', @value(yes)]
|
||||
if @tag() in ['DEFAULT', 'IMPORT_ALL', 'IDENTIFIER']
|
||||
@token 'AS', id
|
||||
return id.length
|
||||
if id is 'as' and @seenExport and @tag() in ['IDENTIFIER', 'DEFAULT']
|
||||
@token 'AS', id
|
||||
return id.length
|
||||
if id is 'as' and @seenExport
|
||||
if @tag() in ['IDENTIFIER', 'DEFAULT']
|
||||
@token 'AS', id
|
||||
return id.length
|
||||
if @value(yes) in COFFEE_KEYWORDS
|
||||
prev = @prev()
|
||||
[prev[0], prev[1]] = ['IDENTIFIER', @value(yes)]
|
||||
@token 'AS', id
|
||||
return id.length
|
||||
if id is 'default' and @seenExport and @tag() in ['EXPORT', 'AS']
|
||||
@token 'DEFAULT', id
|
||||
return id.length
|
||||
@@ -186,18 +192,22 @@ exports.Lexer = class Lexer
|
||||
# what CoffeeScript would normally interpret as calls to functions named
|
||||
# `get` or `set`, i.e. `get({foo: function () {}})`.
|
||||
else if tag is 'PROPERTY' and prev
|
||||
if prev.spaced and prev[0] in CALLABLE and /^[gs]et$/.test(prev[1])
|
||||
@error "'#{prev[1]}' cannot be used as a keyword, or as a function call without parentheses", prev[2]
|
||||
else
|
||||
if prev.spaced and prev[0] in CALLABLE and /^[gs]et$/.test(prev[1]) and
|
||||
@tokens.length > 1 and @tokens[@tokens.length - 2][0] not in ['.', '?.', '@']
|
||||
@error "'#{prev[1]}' cannot be used as a keyword, or as a function call
|
||||
without parentheses", prev[2]
|
||||
else if @tokens.length > 2
|
||||
prevprev = @tokens[@tokens.length - 2]
|
||||
if prev[0] in ['@', 'THIS'] and prevprev and prevprev.spaced and /^[gs]et$/.test(prevprev[1]) and
|
||||
@tokens[@tokens.length - 3][0] isnt '.'
|
||||
@error "'#{prevprev[1]}' cannot be used as a keyword, or as a function call without parentheses", prevprev[2]
|
||||
if prev[0] in ['@', 'THIS'] and prevprev and prevprev.spaced and
|
||||
/^[gs]et$/.test(prevprev[1]) and
|
||||
@tokens[@tokens.length - 3][0] not in ['.', '?.', '@']
|
||||
@error "'#{prevprev[1]}' cannot be used as a keyword, or as a
|
||||
function call without parentheses", prevprev[2]
|
||||
|
||||
if tag is 'IDENTIFIER' and id in RESERVED
|
||||
@error "reserved word '#{id}'", length: id.length
|
||||
|
||||
unless tag is 'PROPERTY'
|
||||
unless tag is 'PROPERTY' or @exportSpecifierList
|
||||
if id in COFFEE_ALIASES
|
||||
alias = id
|
||||
id = COFFEE_ALIAS_MAP[id]
|
||||
@@ -443,9 +453,11 @@ exports.Lexer = class Lexer
|
||||
return 0 unless match = MULTI_DENT.exec chunk
|
||||
indent = match[0]
|
||||
|
||||
@seenFor = no
|
||||
@seenImport = no unless @importSpecifierList
|
||||
@seenExport = no unless @exportSpecifierList
|
||||
prev = @prev()
|
||||
backslash = prev?[0] is '\\'
|
||||
@seenFor = no unless backslash and @seenFor
|
||||
@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()
|
||||
@@ -466,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
|
||||
@@ -550,7 +562,7 @@ exports.Lexer = class Lexer
|
||||
# Check the previous token to detect if attribute is spread.
|
||||
prevChar = if @tokens.length > 0 then @tokens[@tokens.length - 1][0] else ''
|
||||
if firstChar is '<'
|
||||
match = CSX_IDENTIFIER.exec @chunk[1...]
|
||||
match = CSX_IDENTIFIER.exec(@chunk[1...]) or CSX_FRAGMENT_IDENTIFIER.exec(@chunk[1...])
|
||||
return 0 unless match and (
|
||||
@csxDepth > 0 or
|
||||
# Not the right hand side of an unspaced comparison (i.e. `a<b`).
|
||||
@@ -590,8 +602,8 @@ exports.Lexer = class Lexer
|
||||
@matchWithInterpolations INSIDE_CSX, '>', '</', CSX_INTERPOLATION
|
||||
@mergeInterpolationTokens tokens, {delimiter: '"'}, (value, i) =>
|
||||
@formatString value, delimiter: '>'
|
||||
match = CSX_IDENTIFIER.exec @chunk[end...]
|
||||
if not match or match[0] isnt csxTag.name
|
||||
match = CSX_IDENTIFIER.exec(@chunk[end...]) or CSX_FRAGMENT_IDENTIFIER.exec(@chunk[end...])
|
||||
if not match or match[1] isnt csxTag.name
|
||||
@error "expected corresponding CSX closing tag for #{csxTag.name}",
|
||||
csxTag.origin[2]
|
||||
afterTag = end + csxTag.name.length
|
||||
@@ -965,9 +977,12 @@ exports.Lexer = class Lexer
|
||||
token?[0]
|
||||
|
||||
# Peek at the last value in the token stream.
|
||||
value: ->
|
||||
value: (useOrigin = no) ->
|
||||
[..., token] = @tokens
|
||||
token?[1]
|
||||
if useOrigin and token?.origin?
|
||||
token.origin?[1]
|
||||
else
|
||||
token?[1]
|
||||
|
||||
# Get the previous token in the token stream.
|
||||
prev: ->
|
||||
@@ -1169,6 +1184,11 @@ CSX_IDENTIFIER = /// ^
|
||||
( (?: (?!\s)[\.\-$\w\x7f-\uffff] )+ ) # Like `IDENTIFIER`, but includes `-`s and `.`s.
|
||||
///
|
||||
|
||||
# Fragment: <></>
|
||||
CSX_FRAGMENT_IDENTIFIER = /// ^
|
||||
()> # Ends immediately with `>`.
|
||||
///
|
||||
|
||||
CSX_ATTRIBUTE = /// ^
|
||||
(?!\d)
|
||||
( (?: (?!\s)[\-$\w\x7f-\uffff] )+ ) # Like `IDENTIFIER`, but includes `-`s.
|
||||
@@ -1241,9 +1261,22 @@ REGEX = /// ^
|
||||
///
|
||||
|
||||
REGEX_FLAGS = /^\w*/
|
||||
VALID_FLAGS = /^(?!.*(.).*\1)[imguy]*$/
|
||||
VALID_FLAGS = /^(?!.*(.).*\1)[gimsuy]*$/
|
||||
|
||||
HEREGEX = /// ^(?: [^\\/#] | \\[\s\S] | /(?!//) | \#(?!\{) )* ///
|
||||
HEREGEX = /// ^
|
||||
(?:
|
||||
# Match any character, except those that need special handling below.
|
||||
[^\\/#\s]
|
||||
# Match `\` followed by any character.
|
||||
| \\[\s\S]
|
||||
# Match any `/` except `///`.
|
||||
| /(?!//)
|
||||
# Match `#` which is not part of interpolation, e.g. `#{}`.
|
||||
| \#(?!\{)
|
||||
# Comments consume everything until the end of the line, including `///`.
|
||||
| \s+(?:#(?!\{).*)?
|
||||
)*
|
||||
///
|
||||
|
||||
HEREGEX_OMIT = ///
|
||||
((?:\\\\)+) # Consume (and preserve) an even number of backslashes.
|
||||
@@ -1345,4 +1378,4 @@ INDENTABLE_CLOSERS = [')', '}', ']']
|
||||
# Tokens that, when appearing at the end of a line, suppress a following TERMINATOR/INDENT token
|
||||
UNFINISHED = ['\\', '.', '?.', '?::', 'UNARY', 'MATH', 'UNARY_MATH', '+', '-',
|
||||
'**', 'SHIFT', 'RELATION', 'COMPARE', '&', '^', '|', '&&', '||',
|
||||
'BIN?', 'EXTENDS', 'DEFAULT']
|
||||
'BIN?', 'EXTENDS']
|
||||
|
||||
775
src/nodes.coffee
775
src/nodes.coffee
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,8 @@ path = require 'path'
|
||||
|
||||
# Load and run a CoffeeScript file for Node, stripping any `BOM`s.
|
||||
loadFile = (module, filename) ->
|
||||
answer = CoffeeScript._compileFile filename, no, yes
|
||||
options = module.options or getRootModule(module).options
|
||||
answer = CoffeeScript._compileFile filename, options
|
||||
module._compile answer, filename
|
||||
|
||||
# If the installed version of Node supports `require.extensions`, register
|
||||
@@ -48,3 +49,7 @@ if child_process
|
||||
args = [path].concat args
|
||||
path = binary
|
||||
fork path, args, options
|
||||
|
||||
# Utility function to find the `options` object attached to the topmost module.
|
||||
getRootModule = (module) ->
|
||||
if module.parent then getRootModule module.parent else module
|
||||
|
||||
@@ -6,6 +6,7 @@ CoffeeScript = require './'
|
||||
{merge, updateSyntaxError} = require './helpers'
|
||||
|
||||
sawSIGINT = no
|
||||
transpile = no
|
||||
|
||||
replDefaults =
|
||||
prompt: 'coffee> ',
|
||||
@@ -29,20 +30,33 @@ replDefaults =
|
||||
try
|
||||
# Tokenize the clean input.
|
||||
tokens = CoffeeScript.tokens input
|
||||
# Filter out tokens generated just to hold comments.
|
||||
if tokens.length >= 2 and tokens[0].generated and
|
||||
tokens[0].comments?.length isnt 0 and tokens[0][1] is '' and
|
||||
tokens[1][0] is 'TERMINATOR'
|
||||
tokens = tokens[2...]
|
||||
if tokens.length >= 1 and tokens[tokens.length - 1].generated and
|
||||
tokens[tokens.length - 1].comments?.length isnt 0 and tokens[tokens.length - 1][1] is ''
|
||||
tokens.pop()
|
||||
# Collect referenced variable names just like in `CoffeeScript.compile`.
|
||||
referencedVars = (token[1] for token in tokens when token[0] is 'IDENTIFIER')
|
||||
# Generate the AST of the tokens.
|
||||
ast = CoffeeScript.nodes tokens
|
||||
# Add assignment to `__` variable to force the input to be an expression.
|
||||
ast = new Block [new Assign (new Value new Literal '__'), ast, '=']
|
||||
# Wrap the expression in a closure to support top-level `await`
|
||||
# Wrap the expression in a closure to support top-level `await`.
|
||||
ast = new Code [], ast
|
||||
isAsync = ast.isAsync
|
||||
# Invoke the wrapping closure
|
||||
# Invoke the wrapping closure.
|
||||
ast = new Block [new Call ast]
|
||||
js = ast.compile {bare: yes, locals: Object.keys(context), referencedVars, sharedScope: yes}
|
||||
if transpile
|
||||
js = transpile.transpile(js, transpile.options).code
|
||||
# Strip `"use strict"`, to avoid an exception on assigning to
|
||||
# undeclared variable `__`.
|
||||
js = js.replace /^"use strict"|^'use strict'/, ''
|
||||
result = runInContext js, context, filename
|
||||
# Await an async result, if necessary
|
||||
# Await an async result, if necessary.
|
||||
if isAsync
|
||||
result.then (resolvedResult) ->
|
||||
cb null, resolvedResult unless sawSIGINT
|
||||
@@ -167,6 +181,31 @@ module.exports =
|
||||
|
||||
CoffeeScript.register()
|
||||
process.argv = ['coffee'].concat process.argv[2..]
|
||||
if opts.transpile
|
||||
try
|
||||
transpile = {}
|
||||
transpile.transpile = require('babel-core').transform
|
||||
catch
|
||||
console.error '''
|
||||
To use --transpile with an interactive REPL, babel-core must be installed either in the current folder or globally:
|
||||
npm install --save-dev babel-core
|
||||
or
|
||||
npm install --global babel-core
|
||||
And you must save options to configure Babel in one of the places it looks to find its options.
|
||||
See http://coffeescript.org/#transpilation
|
||||
'''
|
||||
process.exit 1
|
||||
transpile.options =
|
||||
filename: path.resolve process.cwd(), '<repl>'
|
||||
# Since the REPL compilation path is unique (in `eval` above), we need
|
||||
# another way to get the `options` object attached to a module so that
|
||||
# it knows later on whether it needs to be transpiled. In the case of
|
||||
# the REPL, the only applicable option is `transpile`.
|
||||
Module = require 'module'
|
||||
originalModuleLoad = Module::load
|
||||
Module::load = (filename) ->
|
||||
@options = transpile: transpile.options
|
||||
originalModuleLoad.call @, filename
|
||||
opts = merge replDefaults, opts
|
||||
repl = nodeREPL.start opts
|
||||
runInContext opts.prelude, repl.context, 'prelude' if opts.prelude
|
||||
|
||||
@@ -263,6 +263,20 @@ exports.Rewriter = class Rewriter
|
||||
stack.pop()
|
||||
start = stack.pop()
|
||||
|
||||
inControlFlow = =>
|
||||
seenFor = @findTagsBackwards(i, ['FOR']) and @findTagsBackwards(i, ['FORIN', 'FOROF', 'FORFROM'])
|
||||
controlFlow = seenFor or @findTagsBackwards i, ['WHILE', 'UNTIL', 'LOOP', 'LEADING_WHEN']
|
||||
return no unless controlFlow
|
||||
isFunc = no
|
||||
tagCurrentLine = token[2].first_line
|
||||
@detectEnd i,
|
||||
(token, i) -> token[0] in LINEBREAKS
|
||||
(token, i) ->
|
||||
[prevTag, ,{first_line}] = tokens[i - 1] || []
|
||||
isFunc = tagCurrentLine is first_line and prevTag in ['->', '=>']
|
||||
returnOnNegativeLevel: yes
|
||||
isFunc
|
||||
|
||||
# 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
|
||||
@@ -271,7 +285,8 @@ exports.Rewriter = class Rewriter
|
||||
(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)
|
||||
not nextToken.spaced and not nextToken.newLine) and
|
||||
not inControlFlow()
|
||||
tag = token[0] = 'FUNC_EXIST' if tag is '?'
|
||||
startImplicitCall i + 1
|
||||
return forward(2)
|
||||
@@ -343,11 +358,14 @@ exports.Rewriter = class Rewriter
|
||||
stackItem[2].sameLine = no if isImplicitObject stackItem
|
||||
|
||||
newLine = prevTag is 'OUTDENT' or prevToken.newLine
|
||||
if tag in IMPLICIT_END or tag in CALL_CLOSERS and newLine
|
||||
if tag in IMPLICIT_END or
|
||||
(tag in CALL_CLOSERS and newLine) or
|
||||
(tag in ['..', '...'] and @findTagsBackwards(i, ["INDEX_START"]))
|
||||
while inImplicit()
|
||||
[stackTag, stackIdx, {sameLine, startsLine}] = stackTop()
|
||||
# Close implicit calls when reached end of argument list
|
||||
if inImplicitCall() and prevTag isnt ','
|
||||
if inImplicitCall() and prevTag isnt ',' or
|
||||
(prevTag is ',' and tag is 'TERMINATOR' and not nextTag?)
|
||||
endImplicitCall()
|
||||
# Close implicit objects such as:
|
||||
# return a: 1, b: 2 unless true
|
||||
@@ -377,7 +395,7 @@ exports.Rewriter = class Rewriter
|
||||
#
|
||||
# f a, b: c, d: e, f, g: h: i, j
|
||||
#
|
||||
if tag is ',' and not @looksObjectish(i + 1) and inImplicitObject() and
|
||||
if tag is ',' and not @looksObjectish(i + 1) and inImplicitObject() and not (@tag(i + 2) in ['FOROF', 'FORIN']) and
|
||||
(nextTag isnt 'TERMINATOR' or not @looksObjectish(i + 2))
|
||||
# When nextTag is OUTDENT the comma is insignificant and
|
||||
# should just be ignored so embed it in the implicit object.
|
||||
@@ -544,20 +562,49 @@ exports.Rewriter = class Rewriter
|
||||
# blocks are added.
|
||||
normalizeLines: ->
|
||||
starter = indent = outdent = null
|
||||
leading_switch_when = null
|
||||
leading_if_then = null
|
||||
# Count `THEN` tags
|
||||
ifThens = []
|
||||
|
||||
condition = (token, i) ->
|
||||
token[1] isnt ';' and token[0] in SINGLE_CLOSERS and
|
||||
not (token[0] is 'TERMINATOR' and @tag(i + 1) in EXPRESSION_CLOSE) and
|
||||
not (token[0] is 'ELSE' and starter isnt 'THEN') and
|
||||
not (token[0] is 'ELSE' and
|
||||
(starter isnt 'THEN' or (leading_if_then or leading_switch_when))) and
|
||||
not (token[0] in ['CATCH', 'FINALLY'] and starter in ['->', '=>']) or
|
||||
token[0] in CALL_CLOSERS and
|
||||
(@tokens[i - 1].newLine or @tokens[i - 1][0] is 'OUTDENT')
|
||||
|
||||
action = (token, i) ->
|
||||
ifThens.pop() if token[0] is 'ELSE' and starter is 'THEN'
|
||||
@tokens.splice (if @tag(i - 1) is ',' then i - 1 else i), 0, outdent
|
||||
|
||||
closeElseTag = (tokens, i) =>
|
||||
tlen = ifThens.length
|
||||
return i unless tlen > 0
|
||||
lastThen = ifThens.pop()
|
||||
[, outdentElse] = @indentation tokens[lastThen]
|
||||
# Insert `OUTDENT` to close inner `IF`.
|
||||
outdentElse[1] = tlen*2
|
||||
tokens.splice(i, 0, outdentElse)
|
||||
# Insert `OUTDENT` to close outer `IF`.
|
||||
outdentElse[1] = 2
|
||||
tokens.splice(i + 1, 0, outdentElse)
|
||||
# Remove outdents from the end.
|
||||
@detectEnd i + 2,
|
||||
(token, i) -> token[0] in ['OUTDENT', 'TERMINATOR']
|
||||
(token, i) ->
|
||||
if @tag(i) is 'OUTDENT' and @tag(i + 1) is 'OUTDENT'
|
||||
tokens.splice i, 2
|
||||
i + 2
|
||||
|
||||
@scanTokens (token, i, tokens) ->
|
||||
[tag] = token
|
||||
conditionTag = tag in ['->', '=>'] and
|
||||
@findTagsBackwards(i, ['IF', 'WHILE', 'FOR', 'UNTIL', 'SWITCH', 'WHEN', 'LEADING_WHEN', '[', 'INDEX_START']) and
|
||||
not (@findTagsBackwards i, ['THEN', '..', '...'])
|
||||
|
||||
if tag is 'TERMINATOR'
|
||||
if @tag(i + 1) is 'ELSE' and @tag(i - 1) isnt 'OUTDENT'
|
||||
tokens.splice i, 1, @indentation()...
|
||||
@@ -574,10 +621,18 @@ exports.Rewriter = class Rewriter
|
||||
tokens.splice i + 1, 0, indent, outdent
|
||||
return 1
|
||||
if tag in SINGLE_LINERS and @tag(i + 1) isnt 'INDENT' and
|
||||
not (tag is 'ELSE' and @tag(i + 1) is 'IF')
|
||||
not (tag is 'ELSE' and @tag(i + 1) is 'IF') and
|
||||
not conditionTag
|
||||
starter = tag
|
||||
[indent, outdent] = @indentation tokens[i]
|
||||
indent.fromThen = true if starter is 'THEN'
|
||||
if tag is 'THEN'
|
||||
leading_switch_when = @findTagsBackwards(i, ['LEADING_WHEN']) and @tag(i + 1) is 'IF'
|
||||
leading_if_then = @findTagsBackwards(i, ['IF']) and @tag(i + 1) is 'IF'
|
||||
ifThens.push i if tag is 'THEN' and @findTagsBackwards(i, ['IF'])
|
||||
# `ELSE` tag is not closed.
|
||||
if tag is 'ELSE' and @tag(i - 1) isnt 'OUTDENT'
|
||||
i = closeElseTag tokens, i
|
||||
tokens.splice i + 1, 0, indent
|
||||
@detectEnd i + 2, condition, action
|
||||
tokens.splice i, 1 if tag is 'THEN'
|
||||
@@ -693,6 +748,6 @@ CONTROL_IN_IMPLICIT = ['IF', 'TRY', 'FINALLY', 'CATCH', 'CLASS', 'SWITCH']
|
||||
DISCARDED = ['(', ')', '[', ']', '{', '}', '.', '..', '...', ',', '=', '++', '--', '?',
|
||||
'AS', 'AWAIT', 'CALL_START', 'CALL_END', 'DEFAULT', 'ELSE', 'EXTENDS', 'EXPORT',
|
||||
'FORIN', 'FOROF', 'FORFROM', 'IMPORT', 'INDENT', 'INDEX_SOAK', 'LEADING_WHEN',
|
||||
'OUTDENT', 'PARAM_START', 'PARAM_END', 'REGEX_START', 'REGEX_END', 'RETURN',
|
||||
'STRING_END', 'THROW', 'UNARY', 'YIELD'
|
||||
'OUTDENT', 'PARAM_END', 'REGEX_START', 'REGEX_END', 'RETURN', 'STRING_END', 'THROW',
|
||||
'UNARY', 'YIELD'
|
||||
].concat IMPLICIT_UNSPACED_CALL.concat IMPLICIT_END.concat CALL_CLOSERS.concat CONTROL_IN_IMPLICIT
|
||||
|
||||
@@ -11,10 +11,12 @@ Initialize a scope with its parent, for lookups up the chain,
|
||||
as well as a reference to the **Block** node it belongs to, which is
|
||||
where it should declare its variables, a reference to the function that
|
||||
it belongs to, and a list of variables referenced in the source code
|
||||
and therefore should be avoided when generating variables.
|
||||
and therefore should be avoided when generating variables. Also track comments
|
||||
that should be output as part of variable declarations.
|
||||
|
||||
constructor: (@parent, @expressions, @method, @referencedVars) ->
|
||||
@variables = [{name: 'arguments', type: 'arguments'}]
|
||||
@comments = {}
|
||||
@positions = {}
|
||||
@utilities = {} unless @parent
|
||||
|
||||
|
||||
@@ -26,6 +26,94 @@ test "incorrect indentation without commas", ->
|
||||
ok result[0][0] is 'a'
|
||||
ok result[1]['b'] is 'c'
|
||||
|
||||
# Elisions
|
||||
test "array elisions", ->
|
||||
eq [,1].length, 2
|
||||
eq [,,1,2,,].length, 5
|
||||
arr = [1,,2]
|
||||
eq arr.length, 3
|
||||
eq arr[1], undefined
|
||||
eq [,,].length, 2
|
||||
|
||||
test "array elisions indentation and commas", ->
|
||||
arr1 = [
|
||||
, 1, 2, , , 3,
|
||||
4, 5, 6
|
||||
, , 8, 9,
|
||||
]
|
||||
eq arr1.length, 12
|
||||
eq arr1[5], 3
|
||||
eq arr1[9], undefined
|
||||
arr2 = [, , 1,
|
||||
2, , 3,
|
||||
, 4, 5
|
||||
6
|
||||
, , ,
|
||||
]
|
||||
eq arr2.length, 12
|
||||
eq arr2[8], 5
|
||||
eq arr2[1], undefined
|
||||
|
||||
test "array elisions destructuring", ->
|
||||
arr = [1,2,3,4,5,6,7,8,9]
|
||||
[,a] = arr
|
||||
[,,,b] = arr
|
||||
arrayEq [a,b], [2,4]
|
||||
[,a,,b,,c,,,d] = arr
|
||||
arrayEq [a,b,c,d], [2,4,6,9]
|
||||
[
|
||||
,e,
|
||||
,f,
|
||||
,g,
|
||||
,,h] = arr
|
||||
arrayEq [e,f,g,h], [2,4,6,9]
|
||||
|
||||
test "array elisions destructuring with splats and expansions", ->
|
||||
arr = [1,2,3,4,5,6,7,8,9]
|
||||
[,a,,,b...] = arr
|
||||
arrayEq [a,b], [2,[5,6,7,8,9]]
|
||||
[,c,...,,d,,e] = arr
|
||||
arrayEq [c,d,e], [2,7,9]
|
||||
[...,f,,,g,,,] = arr
|
||||
arrayEq [f,g], [4,7]
|
||||
|
||||
test "array elisions as function parameters", ->
|
||||
arr = [1,2,3,4,5,6,7,8,9]
|
||||
foo = ([,a]) -> a
|
||||
a = foo arr
|
||||
eq a, 2
|
||||
foo = ([,,,a]) -> a
|
||||
a = foo arr
|
||||
eq a, 4
|
||||
foo = ([,a,,b,,c,,,d]) -> [a,b,c,d]
|
||||
[a,b,c,d] = foo arr
|
||||
arrayEq [a,b,c,d], [2,4,6,9]
|
||||
|
||||
test "array elisions nested destructuring", ->
|
||||
arr = [
|
||||
1,
|
||||
[2,3, [4,5,6, [7,8,9] ] ]
|
||||
]
|
||||
[,a] = arr
|
||||
arrayEq a[2][3], [7,8,9]
|
||||
[,[,,[,b,,[,,c]]]] = arr
|
||||
eq b, 5
|
||||
eq c, 9
|
||||
aobj = [
|
||||
{},
|
||||
{x: 2},
|
||||
{},
|
||||
[
|
||||
{},
|
||||
{},
|
||||
{z:1, w:[1,2,4], p:3, q:4}
|
||||
{},
|
||||
{}
|
||||
]
|
||||
]
|
||||
[,d,,[,,{w}]] = aobj
|
||||
deepEqual d, {x:2}
|
||||
arrayEq w, [1,2,4]
|
||||
|
||||
# Splats in Array Literals
|
||||
|
||||
|
||||
@@ -178,6 +178,13 @@ test "#713: destructuring assignment should return right-hand-side value", ->
|
||||
eq nonceB, b
|
||||
eq nonceB, d
|
||||
|
||||
test "#4787 destructuring of objects within arrays", ->
|
||||
arr = [1, {a:1, b:2}]
|
||||
[...,{a, b}] = arr
|
||||
eq a, 1
|
||||
eq b, arr[1].b
|
||||
deepEqual {a, b}, arr[1]
|
||||
|
||||
test "destructuring assignment with splats", ->
|
||||
a = {}; b = {}; c = {}; d = {}; e = {}
|
||||
[x,y...,z] = [a,b,c,d,e]
|
||||
@@ -246,311 +253,6 @@ test "destructuring assignment against an expression", ->
|
||||
eq a, y
|
||||
eq b, z
|
||||
|
||||
test "destructuring assignment with objects and splats: ES2015", ->
|
||||
obj = {a: 1, b: 2, c: 3, d: 4, e: 5}
|
||||
throws (-> CoffeeScript.compile "{a, r..., s...} = x"), null, "multiple rest elements are disallowed"
|
||||
throws (-> CoffeeScript.compile "{a, r..., s..., b} = x"), null, "multiple rest elements are disallowed"
|
||||
prop = "b"
|
||||
{a, b, r...} = obj
|
||||
eq a, 1
|
||||
eq b, 2
|
||||
eq r.e, obj.e
|
||||
eq r.a, undefined
|
||||
{d, c: x, r...} = obj
|
||||
eq x, 3
|
||||
eq d, 4
|
||||
eq r.c, undefined
|
||||
eq r.b, 2
|
||||
{a, 'b': z, g = 9, r...} = obj
|
||||
eq g, 9
|
||||
eq z, 2
|
||||
eq r.b, undefined
|
||||
|
||||
test "destructuring assignment with splats and default values", ->
|
||||
obj = {}
|
||||
c = {b: 1}
|
||||
{ a: {b} = c, d...} = obj
|
||||
|
||||
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}
|
||||
{ a: {b...} = c } = obj
|
||||
|
||||
deepEqual b, val: 1
|
||||
|
||||
test "destructuring assignment with multiple splats in different objects", ->
|
||||
obj = { a: {val: 1}, b: {val: 2} }
|
||||
{ a: {a...}, b: {b...} } = obj
|
||||
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
|
||||
|
||||
obj = {1: 'a', 2: 'b'}
|
||||
{ "#{foo()}": a, b... } = obj
|
||||
|
||||
eq a, 'a'
|
||||
eq i, 1
|
||||
deepEqual b, 2: 'b'
|
||||
|
||||
# Tests from https://babeljs.io/docs/plugins/transform-object-rest-spread/.
|
||||
test "destructuring assignment with objects and splats: Babel tests", ->
|
||||
# What Babel calls “rest properties:”
|
||||
{ x, y, z... } = { x: 1, y: 2, a: 3, b: 4 }
|
||||
eq x, 1
|
||||
eq y, 2
|
||||
deepEqual z, { a: 3, b: 4 }
|
||||
|
||||
# What Babel calls “spread properties:”
|
||||
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 = {
|
||||
a: a1
|
||||
b: {
|
||||
'c': {
|
||||
d: {
|
||||
b1
|
||||
e: c1
|
||||
f: d1
|
||||
}
|
||||
}
|
||||
}
|
||||
b2: {b1, c1}
|
||||
}
|
||||
{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
|
||||
|
||||
# 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' }
|
||||
foo: 'bar'
|
||||
j =
|
||||
f: 'world'
|
||||
i =
|
||||
some: 'prop'
|
||||
{
|
||||
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'
|
||||
|
||||
# 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
|
||||
deepEqual obj3.g, {obj..., c: 1}
|
||||
|
||||
(({a, b, r...}) ->
|
||||
eq 1, a
|
||||
deepEqual r, {c: 3, d: 44, e: 55}
|
||||
) {obj2..., d: 44, e: 55}
|
||||
|
||||
obj = {a: 1, b: 2, c: {d: 3, e: 4, f: {g: 5}}}
|
||||
obj4 = {a: 10, obj.c...}
|
||||
eq obj4.a, 10
|
||||
eq obj4.d, 3
|
||||
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
|
||||
deepEqual obj6.c, {d: 33, e: 44, f: {g: 55}}
|
||||
|
||||
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:
|
||||
c:
|
||||
d:
|
||||
e: {}
|
||||
obj9 = {a:1, obj.a.b.c..., g:3}
|
||||
deepEqual obj9.d, {e: {}}
|
||||
|
||||
a = "a"
|
||||
c = "c"
|
||||
obj9 = {a:1, obj[a].b[c]..., g:3}
|
||||
deepEqual obj9.d, {e: {}}
|
||||
|
||||
obj9 = {a:1, obj.a["b"].c["d"]..., g:3}
|
||||
deepEqual obj9["e"], {}
|
||||
|
||||
test "bracket insertion when necessary", ->
|
||||
[a] = [0] ? [1]
|
||||
eq a, 0
|
||||
@@ -898,32 +600,124 @@ 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; };
|
||||
test "#4878: Compile error when using destructuring with a splat or expansion in an array", ->
|
||||
arr = ['a', 'b', 'c', 'd']
|
||||
|
||||
_extends({a}, b, c, {d});
|
||||
"""
|
||||
)
|
||||
f1 = (list) ->
|
||||
[first, ..., last] = list
|
||||
|
||||
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
|
||||
f2 = (list) ->
|
||||
[first..., last] = list
|
||||
|
||||
test "#4673: complex destructured object spread variables", ->
|
||||
b = c: 1
|
||||
{{a...}...} = b
|
||||
eq a.c, 1
|
||||
f3 = (list) ->
|
||||
([first, ...] = list); first
|
||||
|
||||
d = {}
|
||||
{d.e...} = f: 1
|
||||
eq d.e.f, 1
|
||||
f4 = (list) ->
|
||||
([first, rest...] = list); rest
|
||||
|
||||
{{g}...} = g: 1
|
||||
eq g, 1
|
||||
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']
|
||||
|
||||
test "#4884: destructured object splat", ->
|
||||
[{length}...] = [1, 2, 3]
|
||||
eq length, 3
|
||||
[{length: len}...] = [1, 2, 3]
|
||||
eq len, 3
|
||||
[{length}..., three] = [1, 2, 3]
|
||||
eq length, 2
|
||||
eq three, 3
|
||||
[{length: len}..., three] = [1, 2, 3]
|
||||
eq len, 2
|
||||
eq three, 3
|
||||
x = [{length}..., three] = [1, 2, 3]
|
||||
eq length, 2
|
||||
eq three, 3
|
||||
eq x[2], 3
|
||||
x = [{length: len}..., three] = [1, 2, 3]
|
||||
eq len, 2
|
||||
eq three, 3
|
||||
eq x[2], 3
|
||||
|
||||
test "#4884: destructured array splat", ->
|
||||
[[one, two, three]...] = [1, 2, 3]
|
||||
eq one, 1
|
||||
eq two, 2
|
||||
eq three, 3
|
||||
[[one, two]..., three] = [1, 2, 3]
|
||||
eq one, 1
|
||||
eq two, 2
|
||||
eq three, 3
|
||||
x = [[one, two]..., three] = [1, 2, 3]
|
||||
eq one, 1
|
||||
eq two, 2
|
||||
eq three, 3
|
||||
eq x[2], 3
|
||||
|
||||
@@ -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 don’t support the `await` keyword will throw an error,
|
||||
# even if we put `return unless global.supportsAsync` at the top of this file.
|
||||
# Therefore we need to prevent runtimes which will choke on such code from even
|
||||
# But runtimes that don’t 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`.
|
||||
|
||||
|
||||
|
||||
32
test/async_iterators.coffee
Normal file
32
test/async_iterators.coffee
Normal file
@@ -0,0 +1,32 @@
|
||||
# This is always fulfilled.
|
||||
winLater = (val, ms) ->
|
||||
new Promise (resolve) -> setTimeout (-> resolve val), ms
|
||||
|
||||
# This is always rejected.
|
||||
failLater = (val, ms) ->
|
||||
new Promise (resolve, reject) -> setTimeout (-> reject new Error val), ms
|
||||
|
||||
createAsyncIterable = (syncIterable) ->
|
||||
for elem in syncIterable
|
||||
yield await winLater elem, 50
|
||||
|
||||
test "async iteration", ->
|
||||
foo = (x for await x from createAsyncIterable [1,2,3])
|
||||
arrayEq foo, [1, 2, 3]
|
||||
|
||||
test "async generator functions", ->
|
||||
foo = (val) ->
|
||||
yield await winLater val + 1, 50
|
||||
|
||||
bar = (val) ->
|
||||
yield await failLater val - 1, 50
|
||||
|
||||
a = await foo(41).next()
|
||||
eq a.value, 42
|
||||
|
||||
try
|
||||
b = do -> await bar(41).next()
|
||||
b.catch (err) ->
|
||||
eq "40", err.message
|
||||
catch err
|
||||
ok no
|
||||
@@ -266,6 +266,7 @@ test "classes with value'd constructors", ->
|
||||
inner = ++counter
|
||||
->
|
||||
@value = inner
|
||||
@
|
||||
|
||||
class One
|
||||
constructor: classMaker()
|
||||
@@ -1833,3 +1834,69 @@ test "#4591: super.x.y, super['x'].y", ->
|
||||
eq 2, b.t
|
||||
eq 2, b.s
|
||||
eq 2, b.r
|
||||
|
||||
test "#4464: backticked expressions in class body", ->
|
||||
class A
|
||||
`get x() { return 42; }`
|
||||
|
||||
class B
|
||||
`get x() { return 42; }`
|
||||
constructor: ->
|
||||
@y = 84
|
||||
|
||||
a = new A
|
||||
eq 42, a.x
|
||||
b = new B
|
||||
eq 42, b.x
|
||||
eq 84, b.y
|
||||
|
||||
test "#4724: backticked expression in a class body with hoisted member", ->
|
||||
class A
|
||||
`get x() { return 42; }`
|
||||
hoisted: 84
|
||||
|
||||
a = new A
|
||||
eq 42, a.x
|
||||
eq 84, a.hoisted
|
||||
|
||||
test "#4822: nested anonymous classes use non-conflicting variable names", ->
|
||||
Class = class
|
||||
@a: class
|
||||
@b: 1
|
||||
|
||||
eq Class.a.b, 1
|
||||
|
||||
test "#4827: executable class body wrappers have correct context", ->
|
||||
test = ->
|
||||
class @A
|
||||
class @B extends @A
|
||||
@property = 1
|
||||
|
||||
o = {}
|
||||
test.call o
|
||||
ok typeof o.A is typeof o.B is 'function'
|
||||
|
||||
test "#4868: Incorrect ‘Can’t call super with @params’ error", ->
|
||||
class A
|
||||
constructor: (@func = ->) ->
|
||||
@x = 1
|
||||
@func()
|
||||
|
||||
class B extends A
|
||||
constructor: ->
|
||||
super -> @x = 2
|
||||
|
||||
a = new A
|
||||
b = new B
|
||||
eq 1, a.x
|
||||
eq 2, b.x
|
||||
|
||||
class C
|
||||
constructor: (@c = class) -> @c
|
||||
|
||||
class D extends C
|
||||
constructor: ->
|
||||
super class then constructor: (@a) -> @a = 3
|
||||
|
||||
d = new (new D).c
|
||||
eq 3, d.a
|
||||
@@ -364,7 +364,7 @@ test "#3132: Place block-comments nicely", ->
|
||||
|
||||
return DummyClass;
|
||||
|
||||
})();"""
|
||||
}).call(this);"""
|
||||
|
||||
test "#3638: Demand a whitespace after # symbol", ->
|
||||
eqJS """
|
||||
@@ -973,3 +973,150 @@ test "Flow comment-based syntax support", ->
|
||||
fn = function(str/*: string */, num/*: number */)/*: string */ {
|
||||
return str + num;
|
||||
};'''
|
||||
|
||||
test "#4706: Flow comments around function parameters", ->
|
||||
eqJS '''
|
||||
identity = ###::<T>### (value ###: T ###) ###: T ### ->
|
||||
value
|
||||
''', '''
|
||||
var identity;
|
||||
|
||||
identity = function/*::<T>*/(value/*: T */)/*: T */ {
|
||||
return value;
|
||||
};'''
|
||||
|
||||
test "#4706: Flow comments around function parameters", ->
|
||||
eqJS '''
|
||||
copy = arr.map(###:: <T> ###(item ###: T ###) ###: T ### => item)
|
||||
''', '''
|
||||
var copy;
|
||||
|
||||
copy = arr.map(/*:: <T> */(item/*: T */)/*: T */ => {
|
||||
return item;
|
||||
});'''
|
||||
|
||||
test "#4706: Flow comments after class name", ->
|
||||
eqJS '''
|
||||
class Container ###::<T> ###
|
||||
method: ###::<U> ### () -> true
|
||||
''', '''
|
||||
var Container;
|
||||
|
||||
Container = class Container/*::<T> */ {
|
||||
method() {
|
||||
return true;
|
||||
}
|
||||
|
||||
};'''
|
||||
|
||||
test "#4706: Identifiers with comments wrapped in parentheses remain wrapped", ->
|
||||
eqJS '(arr ###: Array<number> ###)', '(arr/*: Array<number> */);'
|
||||
eqJS 'other = (arr ###: any ###)', '''
|
||||
var other;
|
||||
|
||||
other = (arr/*: any */);'''
|
||||
|
||||
test "#4706: Flow comments before class methods", ->
|
||||
eqJS '''
|
||||
class Container
|
||||
###::
|
||||
method: (number) => string;
|
||||
method: (string) => number;
|
||||
###
|
||||
method: -> true
|
||||
''', '''
|
||||
var Container;
|
||||
|
||||
Container = class Container {
|
||||
/*::
|
||||
method: (number) => string;
|
||||
method: (string) => number;
|
||||
*/
|
||||
method() {
|
||||
return true;
|
||||
}
|
||||
|
||||
};'''
|
||||
|
||||
test "#4706: Flow comments for class method params", ->
|
||||
eqJS '''
|
||||
class Container
|
||||
method: (param ###: string ###) -> true
|
||||
''', '''
|
||||
var Container;
|
||||
|
||||
Container = class Container {
|
||||
method(param/*: string */) {
|
||||
return true;
|
||||
}
|
||||
|
||||
};'''
|
||||
|
||||
test "#4706: Flow comments for class method returns", ->
|
||||
eqJS '''
|
||||
class Container
|
||||
method: () ###: string ### -> true
|
||||
''', '''
|
||||
var Container;
|
||||
|
||||
Container = class Container {
|
||||
method()/*: string */ {
|
||||
return true;
|
||||
}
|
||||
|
||||
};'''
|
||||
|
||||
test "#4706: Flow comments for function spread", ->
|
||||
eqJS '''
|
||||
method = (...rest ###: Array<string> ###) =>
|
||||
''', '''
|
||||
var method;
|
||||
|
||||
method = (...rest/*: Array<string> */) => {};'''
|
||||
|
||||
test "#4747: Flow comments for local variable declaration", ->
|
||||
eqJS 'a ###: number ### = 1', '''
|
||||
var a/*: number */;
|
||||
|
||||
a = 1;
|
||||
'''
|
||||
|
||||
test "#4747: Flow comments for local variable declarations", ->
|
||||
eqJS '''
|
||||
a ###: number ### = 1
|
||||
b ###: string ### = 'c'
|
||||
''', '''
|
||||
var a/*: number */, b/*: string */;
|
||||
|
||||
a = 1;
|
||||
|
||||
b = 'c';
|
||||
'''
|
||||
|
||||
test "#4747: Flow comments for local variable declarations with reassignment", ->
|
||||
eqJS '''
|
||||
a ###: number ### = 1
|
||||
b ###: string ### = 'c'
|
||||
a ### some other comment ### = 2
|
||||
''', '''
|
||||
var a/*: number */, b/*: string */;
|
||||
|
||||
a = 1;
|
||||
|
||||
b = 'c';
|
||||
|
||||
a/* some other comment */ = 2;
|
||||
'''
|
||||
|
||||
test "#4756: Comment before ? operation", ->
|
||||
eqJS '''
|
||||
do ->
|
||||
### Comment ###
|
||||
@foo ? 42
|
||||
''', '''
|
||||
(function() {
|
||||
var ref;
|
||||
/* Comment */
|
||||
return (ref = this.foo) != null ? ref : 42;
|
||||
})();
|
||||
'''
|
||||
|
||||
@@ -166,3 +166,14 @@ test "using transpile from the Node API requires an object", ->
|
||||
CoffeeScript.compile '', transpile: yes
|
||||
catch exception
|
||||
eq exception.message, 'The transpile option must be given an object with options to pass to Babel'
|
||||
|
||||
test "transpile option applies to imported .coffee files", ->
|
||||
return if global.testingBrowser
|
||||
doesNotThrow -> transpile 'run', "import { getSep } from './test/importing/transpile_import'\ngetSep()"
|
||||
|
||||
test "#3306: trailing comma in a function call in the last line", ->
|
||||
eqJS '''
|
||||
foo bar,
|
||||
''', '''
|
||||
foo(bar);
|
||||
'''
|
||||
@@ -484,3 +484,828 @@ test "#4267: lots of for-loops in the same scope", ->
|
||||
true
|
||||
"""
|
||||
ok CoffeeScript.eval(code)
|
||||
|
||||
# Test for issue #2342: Lexer: Inline `else` binds to wrong `if`/`switch`
|
||||
test "#2343: if / then / if / then / else", ->
|
||||
a = b = yes
|
||||
c = e = g = no
|
||||
d = 1
|
||||
f = 2
|
||||
h = 3
|
||||
i = 4
|
||||
|
||||
s = ->
|
||||
if a
|
||||
if b
|
||||
if c
|
||||
d
|
||||
else
|
||||
if e
|
||||
f
|
||||
else
|
||||
if g
|
||||
h
|
||||
else
|
||||
i
|
||||
|
||||
t = ->
|
||||
if a then if b
|
||||
if c then d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else
|
||||
i
|
||||
|
||||
u = ->
|
||||
if a then if b
|
||||
if c then d else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else i
|
||||
|
||||
v = ->
|
||||
if a then if b
|
||||
if c then d else if e then f
|
||||
else if g then h
|
||||
else i
|
||||
|
||||
w = ->
|
||||
if a then if b
|
||||
if c then d
|
||||
else if e
|
||||
f
|
||||
else
|
||||
if g then h
|
||||
else i
|
||||
|
||||
x = -> if a then if b then if c then d else if e then f else if g then h else i
|
||||
|
||||
y = -> if a then if b then (if c then d else (if e then f else (if g then h else i)))
|
||||
|
||||
eq 4, s()
|
||||
eq 4, t()
|
||||
eq 4, u()
|
||||
eq 4, v()
|
||||
eq 4, w()
|
||||
eq 4, x()
|
||||
eq 4, y()
|
||||
|
||||
c = yes
|
||||
eq 1, s()
|
||||
eq 1, t()
|
||||
eq 1, u()
|
||||
eq 1, v()
|
||||
eq 1, w()
|
||||
eq 1, x()
|
||||
eq 1, y()
|
||||
|
||||
b = no
|
||||
eq undefined, s()
|
||||
eq undefined, t()
|
||||
eq undefined, u()
|
||||
eq undefined, v()
|
||||
eq undefined, w()
|
||||
eq undefined, x()
|
||||
eq undefined, y()
|
||||
|
||||
test "#2343: if / then / if / then / else / else", ->
|
||||
a = b = yes
|
||||
c = e = g = no
|
||||
d = 1
|
||||
f = 2
|
||||
h = 3
|
||||
i = 4
|
||||
j = 5
|
||||
k = 6
|
||||
|
||||
s = ->
|
||||
if a
|
||||
if b
|
||||
if c
|
||||
d
|
||||
else
|
||||
e
|
||||
if e
|
||||
f
|
||||
else
|
||||
if g
|
||||
h
|
||||
else
|
||||
i
|
||||
else
|
||||
j
|
||||
else
|
||||
k
|
||||
|
||||
t = ->
|
||||
if a
|
||||
if b
|
||||
if c then d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else
|
||||
i
|
||||
else
|
||||
j
|
||||
else
|
||||
k
|
||||
|
||||
u = ->
|
||||
if a
|
||||
if b
|
||||
if c then d else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else i
|
||||
else j
|
||||
else k
|
||||
|
||||
v = ->
|
||||
if a
|
||||
if b
|
||||
if c then d else if e then f
|
||||
else if g then h
|
||||
else i
|
||||
else j else k
|
||||
|
||||
w = ->
|
||||
if a then if b
|
||||
if c then d
|
||||
else if e
|
||||
f
|
||||
else
|
||||
if g then h
|
||||
else i
|
||||
else j else k
|
||||
|
||||
x = -> if a then if b then if c then d else if e then f else if g then h else i else j else k
|
||||
|
||||
y = -> if a then (if b then (if c then d else (if e then f else (if g then h else i))) else j) else k
|
||||
|
||||
eq 4, s()
|
||||
eq 4, t()
|
||||
eq 4, u()
|
||||
eq 4, v()
|
||||
eq 4, w()
|
||||
eq 4, x()
|
||||
eq 4, y()
|
||||
|
||||
c = yes
|
||||
eq 1, s()
|
||||
eq 1, t()
|
||||
eq 1, u()
|
||||
eq 1, v()
|
||||
eq 1, w()
|
||||
eq 1, x()
|
||||
eq 1, y()
|
||||
|
||||
b = no
|
||||
eq 5, s()
|
||||
eq 5, t()
|
||||
eq 5, u()
|
||||
eq 5, v()
|
||||
eq 5, w()
|
||||
eq 5, x()
|
||||
eq 5, y()
|
||||
|
||||
a = no
|
||||
eq 6, s()
|
||||
eq 6, t()
|
||||
eq 6, u()
|
||||
eq 6, v()
|
||||
eq 6, w()
|
||||
eq 6, x()
|
||||
eq 6, y()
|
||||
|
||||
|
||||
test "#2343: switch / when / then / if / then / else", ->
|
||||
a = b = yes
|
||||
c = e = g = no
|
||||
d = 1
|
||||
f = 2
|
||||
h = 3
|
||||
i = 4
|
||||
|
||||
s = ->
|
||||
switch
|
||||
when a
|
||||
if b
|
||||
if c
|
||||
d
|
||||
else
|
||||
if e
|
||||
f
|
||||
else
|
||||
if g
|
||||
h
|
||||
else
|
||||
i
|
||||
|
||||
|
||||
t = ->
|
||||
switch
|
||||
when a then if b
|
||||
if c then d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else
|
||||
i
|
||||
|
||||
u = ->
|
||||
switch
|
||||
when a then if b then if c then d
|
||||
else if e then f
|
||||
else if g then h else i
|
||||
|
||||
v = ->
|
||||
switch
|
||||
when a then if b then if c then d else if e then f
|
||||
else if g then h else i
|
||||
|
||||
w = ->
|
||||
switch
|
||||
when a then if b then if c then d else if e then f
|
||||
else if g
|
||||
h
|
||||
else i
|
||||
|
||||
x = ->
|
||||
switch
|
||||
when a then if b then if c then d else if e then f else if g then h else i
|
||||
|
||||
y = -> switch
|
||||
when a then if b then (if c then d else (if e then f else (if g then h else i)))
|
||||
|
||||
eq 4, s()
|
||||
eq 4, t()
|
||||
eq 4, u()
|
||||
eq 4, v()
|
||||
eq 4, w()
|
||||
eq 4, x()
|
||||
eq 4, y()
|
||||
|
||||
c = yes
|
||||
eq 1, s()
|
||||
eq 1, t()
|
||||
eq 1, u()
|
||||
eq 1, v()
|
||||
eq 1, w()
|
||||
eq 1, x()
|
||||
eq 1, y()
|
||||
|
||||
b = no
|
||||
eq undefined, s()
|
||||
eq undefined, t()
|
||||
eq undefined, u()
|
||||
eq undefined, v()
|
||||
eq undefined, w()
|
||||
eq undefined, x()
|
||||
eq undefined, y()
|
||||
|
||||
test "#2343: switch / when / then / if / then / else / else", ->
|
||||
a = b = yes
|
||||
c = e = g = no
|
||||
d = 1
|
||||
f = 2
|
||||
h = 3
|
||||
i = 4
|
||||
|
||||
s = ->
|
||||
switch
|
||||
when a
|
||||
if b
|
||||
if c
|
||||
d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else
|
||||
i
|
||||
else
|
||||
0
|
||||
|
||||
t = ->
|
||||
switch
|
||||
when a
|
||||
if b
|
||||
if c then d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else i
|
||||
else 0
|
||||
|
||||
u = ->
|
||||
switch
|
||||
when a
|
||||
if b then if c
|
||||
d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else i
|
||||
else 0
|
||||
|
||||
v = ->
|
||||
switch
|
||||
when a
|
||||
if b then if c then d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else i
|
||||
else 0
|
||||
|
||||
w = ->
|
||||
switch
|
||||
when a
|
||||
if b then if c then d
|
||||
else if e then f
|
||||
else if g then h
|
||||
else i
|
||||
else 0
|
||||
|
||||
x = ->
|
||||
switch
|
||||
when a
|
||||
if b then if c then d else if e then f else if g then h else i
|
||||
else 0
|
||||
|
||||
y = -> switch
|
||||
when a
|
||||
if b then (if c then d else (if e then f else (if g then h else i)))
|
||||
else 0
|
||||
|
||||
eq 4, s()
|
||||
eq 4, t()
|
||||
eq 4, u()
|
||||
eq 4, v()
|
||||
eq 4, w()
|
||||
eq 4, x()
|
||||
eq 4, y()
|
||||
|
||||
c = yes
|
||||
eq 1, s()
|
||||
eq 1, t()
|
||||
eq 1, u()
|
||||
eq 1, v()
|
||||
eq 1, w()
|
||||
eq 1, x()
|
||||
eq 1, y()
|
||||
|
||||
b = no
|
||||
eq undefined, s()
|
||||
eq undefined, t()
|
||||
eq undefined, u()
|
||||
eq undefined, v()
|
||||
eq undefined, w()
|
||||
eq undefined, x()
|
||||
eq undefined, y()
|
||||
|
||||
b = yes
|
||||
a = no
|
||||
eq 0, s()
|
||||
eq 0, t()
|
||||
eq 0, u()
|
||||
eq 0, v()
|
||||
eq 0, w()
|
||||
eq 0, x()
|
||||
eq 0, y()
|
||||
|
||||
test "#2343: switch / when / then / if / then / else / else / else", ->
|
||||
a = b = yes
|
||||
c = e = g = no
|
||||
d = 1
|
||||
f = 2
|
||||
h = 3
|
||||
i = 4
|
||||
j = 5
|
||||
|
||||
s = ->
|
||||
switch
|
||||
when a
|
||||
if b
|
||||
if c
|
||||
d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else
|
||||
i
|
||||
else
|
||||
j
|
||||
else
|
||||
0
|
||||
|
||||
t = ->
|
||||
switch
|
||||
when a
|
||||
if b
|
||||
if c then d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else i
|
||||
else
|
||||
j
|
||||
else 0
|
||||
|
||||
u = ->
|
||||
switch
|
||||
when a
|
||||
if b
|
||||
if c
|
||||
d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else i
|
||||
else j
|
||||
else 0
|
||||
|
||||
v = ->
|
||||
switch
|
||||
when a
|
||||
if b
|
||||
if c then d
|
||||
else if e
|
||||
f
|
||||
else if g then h
|
||||
else i
|
||||
else j
|
||||
else 0
|
||||
|
||||
w = ->
|
||||
switch
|
||||
when a
|
||||
if b
|
||||
if c then d
|
||||
else if e then f
|
||||
else if g then h
|
||||
else i
|
||||
else j
|
||||
else 0
|
||||
|
||||
x = ->
|
||||
switch
|
||||
when a
|
||||
if b then if c then d else if e then f else if g then h else i else j
|
||||
else 0
|
||||
|
||||
y = -> switch
|
||||
when a
|
||||
if b then (if c then d else (if e then f else (if g then h else i))) else j
|
||||
else 0
|
||||
|
||||
eq 4, s()
|
||||
eq 4, t()
|
||||
eq 4, u()
|
||||
eq 4, v()
|
||||
eq 4, w()
|
||||
eq 4, x()
|
||||
eq 4, y()
|
||||
|
||||
c = yes
|
||||
eq 1, s()
|
||||
eq 1, t()
|
||||
eq 1, u()
|
||||
eq 1, v()
|
||||
eq 1, w()
|
||||
eq 1, x()
|
||||
eq 1, y()
|
||||
|
||||
b = no
|
||||
eq 5, s()
|
||||
eq 5, t()
|
||||
eq 5, u()
|
||||
eq 5, v()
|
||||
eq 5, w()
|
||||
eq 5, x()
|
||||
eq 5, y()
|
||||
|
||||
b = yes
|
||||
a = no
|
||||
eq 0, s()
|
||||
eq 0, t()
|
||||
eq 0, u()
|
||||
eq 0, v()
|
||||
eq 0, w()
|
||||
eq 0, x()
|
||||
eq 0, y()
|
||||
|
||||
# Test for issue #3921: Inline function without parentheses used in condition fails to compile
|
||||
test "#3921: `if` & `unless`", ->
|
||||
a = {}
|
||||
eq a, if do -> no then undefined else a
|
||||
a1 = undefined
|
||||
if do -> yes
|
||||
a1 = a
|
||||
eq a, a1
|
||||
|
||||
b = {}
|
||||
eq b, unless do -> no then b else undefined
|
||||
b1 = undefined
|
||||
unless do -> no
|
||||
b1 = b
|
||||
eq b, b1
|
||||
|
||||
c = 0
|
||||
if (arg = undefined) -> yes then c++
|
||||
eq 1, c
|
||||
d = 0
|
||||
if (arg = undefined) -> yes
|
||||
d++
|
||||
eq 1, d
|
||||
|
||||
answer = 'correct'
|
||||
eq answer, if do -> 'wrong' then 'correct' else 'wrong'
|
||||
eq answer, unless do -> no then 'correct' else 'wrong'
|
||||
statm1 = undefined
|
||||
if do -> 'wrong'
|
||||
statm1 = 'correct'
|
||||
eq answer, statm1
|
||||
statm2 = undefined
|
||||
unless do -> no
|
||||
statm2 = 'correct'
|
||||
eq answer, statm2
|
||||
|
||||
test "#3921: `post if`", ->
|
||||
a = {}
|
||||
eq a, a unless do -> no
|
||||
a1 = a if do -> yes
|
||||
eq a, a1
|
||||
|
||||
c = 0
|
||||
c++ if (arg = undefined) -> yes
|
||||
eq 1, c
|
||||
d = 0
|
||||
d++ if (arg = undefined) -> yes
|
||||
eq 1, d
|
||||
|
||||
answer = 'correct'
|
||||
eq answer, 'correct' if do -> 'wrong'
|
||||
eq answer, 'correct' unless do -> not 'wrong'
|
||||
statm1 = undefined
|
||||
statm1 = 'correct' if do -> 'wrong'
|
||||
eq answer, statm1
|
||||
statm2 = undefined
|
||||
statm2 = 'correct' unless do -> not 'wrong'
|
||||
eq answer, statm2
|
||||
|
||||
test "Issue 3921: `while` & `until`", ->
|
||||
i = 5
|
||||
assert = (a) -> ok 5 > a > 0
|
||||
result1 = while do (num = 1) -> i -= num
|
||||
assert i
|
||||
i
|
||||
ok result1.join(' ') is '4 3 2 1'
|
||||
|
||||
j = 5
|
||||
result2 = until do (num = 1) -> (j -= num) < 1
|
||||
assert j
|
||||
j
|
||||
ok result2.join(' ') is '4 3 2 1'
|
||||
|
||||
test "#3921: `switch`", ->
|
||||
i = 1
|
||||
a = switch do (m = 2) -> i * m
|
||||
when 5 then "five"
|
||||
when 4 then "four"
|
||||
when 3 then "three"
|
||||
when 2 then "two"
|
||||
when 1 then "one"
|
||||
else "none"
|
||||
eq "two", a
|
||||
|
||||
j = 12
|
||||
b = switch do (m = 3) -> j / m
|
||||
when 5 then "five"
|
||||
when 4 then "four"
|
||||
when 3 then "three"
|
||||
when 2 then "two"
|
||||
when 1 then "one"
|
||||
else "none"
|
||||
eq "four", b
|
||||
|
||||
k = 20
|
||||
c = switch do (m = 4) -> k / m
|
||||
when 5 then "five"
|
||||
when 4 then "four"
|
||||
when 3 then "three"
|
||||
when 2 then "two"
|
||||
when 1 then "one"
|
||||
else "none"
|
||||
eq "five", c
|
||||
|
||||
# Issue #3909: backslash to break line in `for` loops throw syntax error
|
||||
test "#3909: backslash `for own ... of`", ->
|
||||
|
||||
obj = {a: 1, b: 2, c: 3}
|
||||
arr = ['a', 'b', 'c']
|
||||
|
||||
x1 \
|
||||
= ( key for own key of obj )
|
||||
arrayEq x1, arr
|
||||
|
||||
x2 = \
|
||||
( key for own key of obj )
|
||||
arrayEq x2, arr
|
||||
|
||||
x3 = ( \
|
||||
key for own key of obj )
|
||||
arrayEq x3, arr
|
||||
|
||||
x4 = ( key \
|
||||
for own key of obj )
|
||||
arrayEq x4, arr
|
||||
|
||||
x5 = ( key for own key of \
|
||||
obj )
|
||||
arrayEq x5, arr
|
||||
|
||||
x6 = ( key for own key of obj \
|
||||
)
|
||||
arrayEq x6, arr
|
||||
|
||||
x7 = ( key for \
|
||||
own key of obj )
|
||||
arrayEq x7, arr
|
||||
|
||||
x8 = ( key for own \
|
||||
key of obj )
|
||||
arrayEq x8, arr
|
||||
|
||||
x9 = ( key for own key \
|
||||
of obj )
|
||||
arrayEq x9, arr
|
||||
|
||||
|
||||
test "#3909: backslash `for ... of`", ->
|
||||
obj = {a: 1, b: 2, c: 3}
|
||||
arr = ['a', 'b', 'c']
|
||||
|
||||
x1 \
|
||||
= ( key for key of obj )
|
||||
arrayEq x1, arr
|
||||
|
||||
x2 = \
|
||||
( key for key of obj )
|
||||
arrayEq x2, arr
|
||||
|
||||
x3 = ( \
|
||||
key for key of obj )
|
||||
arrayEq x3, arr
|
||||
|
||||
x4 = ( key \
|
||||
for key of obj )
|
||||
arrayEq x4, arr
|
||||
|
||||
x5 = ( key for key of \
|
||||
obj )
|
||||
arrayEq x5, arr
|
||||
|
||||
x6 = ( key for key of obj \
|
||||
)
|
||||
arrayEq x6, arr
|
||||
|
||||
x7 = ( key for \
|
||||
key of obj )
|
||||
arrayEq x7, arr
|
||||
|
||||
x8 = ( key for key \
|
||||
of obj )
|
||||
arrayEq x8, arr
|
||||
|
||||
|
||||
test "#3909: backslash `for ... in`", ->
|
||||
arr = ['a', 'b', 'c']
|
||||
|
||||
x1 \
|
||||
= ( key for key in arr )
|
||||
arrayEq x1, arr
|
||||
|
||||
x2 = \
|
||||
( key for key in arr )
|
||||
arrayEq x2, arr
|
||||
|
||||
x3 = ( \
|
||||
key for key in arr )
|
||||
arrayEq x3, arr
|
||||
|
||||
x4 = ( key \
|
||||
for key in arr )
|
||||
arrayEq x4, arr
|
||||
|
||||
x5 = ( key for key in \
|
||||
arr )
|
||||
arrayEq x5, arr
|
||||
|
||||
x6 = ( key for key in arr \
|
||||
)
|
||||
arrayEq x6, arr
|
||||
|
||||
x7 = ( key for \
|
||||
key in arr )
|
||||
arrayEq x7, arr
|
||||
|
||||
x8 = ( key for key \
|
||||
in arr )
|
||||
arrayEq x8, arr
|
||||
|
||||
test "#4871: `else if` no longer output together ", ->
|
||||
eqJS '''
|
||||
if a then b else if c then d else if e then f else g
|
||||
''',
|
||||
'''
|
||||
if (a) {
|
||||
b;
|
||||
} else if (c) {
|
||||
d;
|
||||
} else if (e) {
|
||||
f;
|
||||
} else {
|
||||
g;
|
||||
}
|
||||
'''
|
||||
|
||||
eqJS '''
|
||||
if no
|
||||
1
|
||||
else if yes
|
||||
2
|
||||
''',
|
||||
'''
|
||||
if (false) {
|
||||
1;
|
||||
} else if (true) {
|
||||
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
|
||||
|
||||
@@ -742,3 +742,47 @@ test '#4686: comments inside interpolations that also contain CSX attributes', -
|
||||
</div>;
|
||||
'''
|
||||
|
||||
# https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html
|
||||
test 'JSX fragments: empty fragment', ->
|
||||
eqJS '''
|
||||
<></>
|
||||
''', '''
|
||||
<></>;
|
||||
'''
|
||||
|
||||
test 'JSX fragments: fragment with text nodes', ->
|
||||
eqJS '''
|
||||
<>
|
||||
Some text.
|
||||
<h2>A heading</h2>
|
||||
More text.
|
||||
<h2>Another heading</h2>
|
||||
Even more text.
|
||||
</>
|
||||
''', '''
|
||||
<>
|
||||
Some text.
|
||||
<h2>A heading</h2>
|
||||
More text.
|
||||
<h2>Another heading</h2>
|
||||
Even more text.
|
||||
</>;
|
||||
'''
|
||||
|
||||
test 'JSX fragments: fragment with component nodes', ->
|
||||
eqJS '''
|
||||
Component = (props) =>
|
||||
<Fragment>
|
||||
<OtherComponent />
|
||||
<OtherComponent />
|
||||
</Fragment>
|
||||
''', '''
|
||||
var Component;
|
||||
|
||||
Component = (props) => {
|
||||
return <Fragment>
|
||||
<OtherComponent />
|
||||
<OtherComponent />
|
||||
</Fragment>;
|
||||
};
|
||||
'''
|
||||
|
||||
@@ -65,7 +65,7 @@ if require?
|
||||
|
||||
try
|
||||
assertErrorFormat """
|
||||
require '#{tempFile}'
|
||||
require '#{tempFile.replace /\\/g, '\\\\'}'
|
||||
""",
|
||||
"""
|
||||
#{fs.realpathSync tempFile}:1:15: error: unexpected in
|
||||
@@ -183,9 +183,9 @@ test "#1096: unexpected generated tokens", ->
|
||||
for i in [1]:
|
||||
1
|
||||
''', '''
|
||||
[stdin]:1:10: error: unexpected [
|
||||
for i in [1]:
|
||||
^
|
||||
[stdin]:2:4: error: unexpected end of input
|
||||
1
|
||||
^
|
||||
'''
|
||||
# Unexpected regex
|
||||
assertErrorFormat '{/a/i: val}', '''
|
||||
@@ -808,29 +808,8 @@ test "invalid numbers", ->
|
||||
^^^
|
||||
'''
|
||||
|
||||
test "unexpected object keys", ->
|
||||
assertErrorFormat '''
|
||||
{[[]]}
|
||||
''', '''
|
||||
[stdin]:1:2: error: unexpected [
|
||||
{[[]]}
|
||||
^
|
||||
'''
|
||||
assertErrorFormat '''
|
||||
{[[]]: 1}
|
||||
''', '''
|
||||
[stdin]:1:2: error: unexpected [
|
||||
{[[]]: 1}
|
||||
^
|
||||
'''
|
||||
assertErrorFormat '''
|
||||
[[]]: 1
|
||||
''', '''
|
||||
[stdin]:1:1: error: unexpected [
|
||||
[[]]: 1
|
||||
^
|
||||
'''
|
||||
|
||||
test "unexpected object keys", ->
|
||||
assertErrorFormat '''
|
||||
{(a + "b")}
|
||||
''', '''
|
||||
@@ -852,20 +831,6 @@ test "unexpected object keys", ->
|
||||
(a + "b"): 1
|
||||
^
|
||||
'''
|
||||
assertErrorFormat '''
|
||||
a: 1, [[]]: 2
|
||||
''', '''
|
||||
[stdin]:1:7: error: unexpected [
|
||||
a: 1, [[]]: 2
|
||||
^
|
||||
'''
|
||||
assertErrorFormat '''
|
||||
{a: 1, [[]]: 2}
|
||||
''', '''
|
||||
[stdin]:1:8: error: unexpected [
|
||||
{a: 1, [[]]: 2}
|
||||
^
|
||||
'''
|
||||
|
||||
test "invalid object keys", ->
|
||||
assertErrorFormat '''
|
||||
@@ -997,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
|
||||
@@ -1197,6 +1198,18 @@ test "bound functions cannot be generators", ->
|
||||
^^^^^^^^^^
|
||||
'''
|
||||
|
||||
test "#4790: bound functions cannot be generators, even when we’re creating IIFEs", ->
|
||||
assertErrorFormat '''
|
||||
=>
|
||||
for x in []
|
||||
for y in []
|
||||
yield z
|
||||
''', '''
|
||||
[stdin]:4:7: error: yield cannot occur inside bound (fat arrow) functions
|
||||
yield z
|
||||
^^^^^^^
|
||||
'''
|
||||
|
||||
test "CoffeeScript keywords cannot be used as unaliased names in import lists", ->
|
||||
assertErrorFormat """
|
||||
import { unless, baz as bar } from 'lib'
|
||||
@@ -1217,28 +1230,6 @@ test "CoffeeScript keywords cannot be used as local names in import list aliases
|
||||
^^^^^^
|
||||
'''
|
||||
|
||||
test "function cannot contain both `await` and `yield`", ->
|
||||
assertErrorFormat '''
|
||||
f = () ->
|
||||
yield 5
|
||||
await a
|
||||
''', '''
|
||||
[stdin]:3:3: error: function can't contain both yield and await
|
||||
await a
|
||||
^^^^^^^
|
||||
'''
|
||||
|
||||
test "function cannot contain both `await` and `yield from`", ->
|
||||
assertErrorFormat '''
|
||||
f = () ->
|
||||
yield from a
|
||||
await b
|
||||
''', '''
|
||||
[stdin]:3:3: error: function can't contain both yield and await
|
||||
await b
|
||||
^^^^^^^
|
||||
'''
|
||||
|
||||
test "cannot have `await` outside a function", ->
|
||||
assertErrorFormat '''
|
||||
await 1
|
||||
@@ -1339,6 +1330,20 @@ test "derived constructors can't use @params without calling super", ->
|
||||
^^
|
||||
'''
|
||||
|
||||
test "derived constructors can't call super with @params", ->
|
||||
assertErrorFormat 'class extends A then constructor: (@a) -> super(@a)', '''
|
||||
[stdin]:1:49: error: Can't call super with @params in derived class constructors
|
||||
class extends A then constructor: (@a) -> super(@a)
|
||||
^^
|
||||
'''
|
||||
|
||||
test "derived constructors can't call super with buried @params", ->
|
||||
assertErrorFormat 'class extends A then constructor: (@a) -> super((=> @a)())', '''
|
||||
[stdin]:1:53: error: Can't call super with @params in derived class constructors
|
||||
class extends A then constructor: (@a) -> super((=> @a)())
|
||||
^^
|
||||
'''
|
||||
|
||||
test "'super' is not allowed in constructor parameter defaults", ->
|
||||
assertErrorFormat 'class extends A then constructor: (a = super()) ->', '''
|
||||
[stdin]:1:40: error: 'super' is not allowed in constructor parameter defaults
|
||||
@@ -1777,3 +1782,62 @@ test "#3098: suppressed newline should be unsuppressed by semicolon", ->
|
||||
a = ; 5
|
||||
^
|
||||
'''
|
||||
|
||||
test "#4811: '///' inside a heregex comment does not close the heregex", ->
|
||||
assertErrorFormat '''
|
||||
/// .* # comment ///
|
||||
''', '''
|
||||
[stdin]:1:1: error: missing ///
|
||||
/// .* # comment ///
|
||||
^^^
|
||||
'''
|
||||
|
||||
test "#3933: prevent implicit calls when cotrol flow is missing `THEN`", ->
|
||||
assertErrorFormat '''
|
||||
for a in b do ->
|
||||
''','''
|
||||
[stdin]:1:12: error: unexpected do
|
||||
for a in b do ->
|
||||
^^
|
||||
'''
|
||||
|
||||
assertErrorFormat '''
|
||||
for a in b ->
|
||||
''','''
|
||||
[stdin]:1:12: error: unexpected ->
|
||||
for a in b ->
|
||||
^^
|
||||
'''
|
||||
|
||||
assertErrorFormat '''
|
||||
for a in b do =>
|
||||
''','''
|
||||
[stdin]:1:12: error: unexpected do
|
||||
for a in b do =>
|
||||
^^
|
||||
'''
|
||||
|
||||
assertErrorFormat '''
|
||||
while a do ->
|
||||
''','''
|
||||
[stdin]:1:9: error: unexpected do
|
||||
while a do ->
|
||||
^^
|
||||
'''
|
||||
|
||||
assertErrorFormat '''
|
||||
until a do =>
|
||||
''','''
|
||||
[stdin]:1:9: error: unexpected do
|
||||
until a do =>
|
||||
^^
|
||||
'''
|
||||
|
||||
assertErrorFormat '''
|
||||
switch
|
||||
when a ->
|
||||
''','''
|
||||
[stdin]:2:10: error: unexpected ->
|
||||
when a ->
|
||||
^^
|
||||
'''
|
||||
@@ -8,7 +8,7 @@ nonce = {}
|
||||
# Throw
|
||||
|
||||
test "basic exception throwing", ->
|
||||
throws (-> throw 'error'), 'error'
|
||||
throws (-> throw 'error'), /^error$/
|
||||
|
||||
|
||||
# Empty Try/Catch/Finally
|
||||
|
||||
19
test/exponentiation.coffee
Normal file
19
test/exponentiation.coffee
Normal file
@@ -0,0 +1,19 @@
|
||||
# The `**` and `**=` operators are only supported in Node 7.5+, so the tests
|
||||
# for these exponentiation operators are split out into their own file to be
|
||||
# loaded only by supported runtimes.
|
||||
|
||||
test "exponentiation operator", ->
|
||||
eq 27, 3 ** 3
|
||||
|
||||
test "exponentiation operator has higher precedence than other maths operators", ->
|
||||
eq 55, 1 + 3 ** 3 * 2
|
||||
eq -4, -2 ** 2
|
||||
eq 0, (!2) ** 2
|
||||
|
||||
test "exponentiation operator is right associative", ->
|
||||
eq 2, 2 ** 1 ** 3
|
||||
|
||||
test "exponentiation operator compound assignment", ->
|
||||
a = 2
|
||||
a **= 3
|
||||
eq 8, a
|
||||
@@ -329,6 +329,15 @@ test "Simple Destructuring function arguments with same-named variables in scope
|
||||
eq f([2]), 2
|
||||
eq x, 1
|
||||
|
||||
test "#4843: Bad output when assigning to @prop in destructuring assignment with defaults", ->
|
||||
works = "maybe"
|
||||
drinks = "beer"
|
||||
class A
|
||||
constructor: ({@works = 'no', @drinks = 'wine'}) ->
|
||||
a = new A {works: 'yes', drinks: 'coffee'}
|
||||
eq a.works, 'yes'
|
||||
eq a.drinks, 'coffee'
|
||||
|
||||
test "caching base value", ->
|
||||
|
||||
obj =
|
||||
@@ -795,7 +804,7 @@ test "get and set can be used as class method names", ->
|
||||
eq 4, B.get()
|
||||
eq 5, B.set()
|
||||
|
||||
test "functions named get or set can be used without parentheses when attached to an object; #4524", ->
|
||||
test "#4524: functions named get or set can be used without parentheses when attached to an object", ->
|
||||
obj =
|
||||
get: (x) -> x + 2
|
||||
set: (x) -> x + 3
|
||||
@@ -806,8 +815,16 @@ test "functions named get or set can be used without parentheses when attached t
|
||||
|
||||
a = new A()
|
||||
|
||||
class B
|
||||
get: (x) -> x.value + 6
|
||||
set: (x) -> x.value + 7
|
||||
|
||||
b = new B()
|
||||
|
||||
eq 12, obj.get 10
|
||||
eq 13, obj.set 10
|
||||
eq 12, obj?.get 10
|
||||
eq 13, obj?.set 10
|
||||
|
||||
eq 14, a.get 10
|
||||
eq 15, a.set 10
|
||||
@@ -825,3 +842,64 @@ test "functions named get or set can be used without parentheses when attached t
|
||||
eq 12, obj.obj.get @ten
|
||||
eq 13, obj.obj.set @ten
|
||||
|
||||
eq 16, b.get value: 10
|
||||
eq 17, b.set value: 10
|
||||
|
||||
eq 16, b.get value: @ten
|
||||
eq 17, b.set value: @ten
|
||||
|
||||
test "#4836: functions named get or set can be used without parentheses when attached to this or @", ->
|
||||
@get = (x) -> x + 2
|
||||
@set = (x) -> x + 3
|
||||
@a = 4
|
||||
|
||||
eq 12, this.get 10
|
||||
eq 13, this.set 10
|
||||
eq 12, this?.get 10
|
||||
eq 13, this?.set 10
|
||||
eq 6, this.get @a
|
||||
eq 7, this.set @a
|
||||
eq 6, this?.get @a
|
||||
eq 7, this?.set @a
|
||||
|
||||
eq 12, @get 10
|
||||
eq 13, @set 10
|
||||
eq 12, @?.get 10
|
||||
eq 13, @?.set 10
|
||||
eq 6, @get @a
|
||||
eq 7, @set @a
|
||||
eq 6, @?.get @a
|
||||
eq 7, @?.set @a
|
||||
|
||||
test "#4852: functions named get or set can be used without parentheses when attached to this or @, with an argument of an implicit object", ->
|
||||
@get = ({ x }) -> x + 2
|
||||
@set = ({ x }) -> x + 3
|
||||
|
||||
eq 12, @get x: 10
|
||||
eq 13, @set x: 10
|
||||
eq 12, @?.get x: 10
|
||||
eq 13, @?.set x: 10
|
||||
eq 12, this?.get x: 10
|
||||
eq 13, this?.set x: 10
|
||||
|
||||
test "#4473: variable scope in chained calls", ->
|
||||
obj =
|
||||
foo: -> this
|
||||
bar: (a) ->
|
||||
a()
|
||||
this
|
||||
|
||||
obj.foo(a = 1).bar(-> a = 2)
|
||||
eq a, 2
|
||||
|
||||
obj.bar(-> b = 2).foo(b = 1)
|
||||
eq b, 1
|
||||
|
||||
obj.foo(c = 1).bar(-> c = 2).foo(c = 3)
|
||||
eq c, 3
|
||||
|
||||
obj.foo([d, e] = [1, 2]).bar(-> d = 4)
|
||||
eq d, 4
|
||||
|
||||
obj.foo({f} = {f: 1}).bar(-> f = 5)
|
||||
eq f, 5
|
||||
|
||||
@@ -127,6 +127,16 @@ test "destructured splatted parameters", ->
|
||||
splatArray = ([a ...]) -> a
|
||||
splatArrayRest = ([a ...],b ...) -> arrayEq(a,b); b
|
||||
|
||||
test "#4884: object-destructured splatted parameters", ->
|
||||
f = ({length}...) -> length
|
||||
eq f(4, 5, 6), 3
|
||||
f = ({length: len}...) -> len
|
||||
eq f(4, 5, 6), 3
|
||||
f = ({length}..., last) -> [length, last]
|
||||
arrayEq f(4, 5, 6), [2, 6]
|
||||
f = ({length: len}..., last) -> [len, last]
|
||||
arrayEq f(4, 5, 6), [2, 6]
|
||||
|
||||
test "@-parameters: automatically assign an argument's value to a property of the context", ->
|
||||
nonce = {}
|
||||
|
||||
@@ -215,86 +225,6 @@ test "destructuring in function definition", ->
|
||||
url: '/home', async: true, beforeSend: fn, cache: true, method: 'post', data: {}
|
||||
}
|
||||
|
||||
test "rest element destructuring in function definition", ->
|
||||
obj = {a: 1, b: 2, c: 3, d: 4, e: 5}
|
||||
|
||||
(({a, b, r...}) ->
|
||||
eq 1, a
|
||||
eq 2, b,
|
||||
deepEqual r, {c: 3, d: 4, e: 5}
|
||||
) obj
|
||||
|
||||
(({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
|
||||
|
||||
# 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
|
||||
b: {
|
||||
'c': {
|
||||
d: {
|
||||
b1
|
||||
e: c1
|
||||
f: d1
|
||||
}
|
||||
}
|
||||
}
|
||||
b2: {b1, c1}
|
||||
}
|
||||
|
||||
(({a: w, b: {c: {d: {b1: bb, r1...}}}, r2...}) ->
|
||||
eq a1, w
|
||||
eq bb, b1
|
||||
eq r2.b, undefined
|
||||
deepEqual r1, {e: c1, f: d1}
|
||||
deepEqual r2.b2, {b1, c1}
|
||||
) obj1
|
||||
|
||||
b = 3
|
||||
f = ({a, b...}) ->
|
||||
f {}
|
||||
eq 3, b
|
||||
|
||||
(({a, r...} = {}) ->
|
||||
eq a, undefined
|
||||
deepEqual r, {}
|
||||
)()
|
||||
|
||||
(({a, r...} = {}) ->
|
||||
eq a, 1
|
||||
deepEqual r, {b: 2, c: 3}
|
||||
) {a: 1, b: 2, c: 3}
|
||||
|
||||
f = ({a, r...} = {}) -> [a, r]
|
||||
deepEqual [undefined, {}], f()
|
||||
deepEqual [1, {b: 2}], f {a: 1, b: 2}
|
||||
deepEqual [1, {}], f {a: 1}
|
||||
|
||||
f = ({a, r...} = {a: 1, b: 2}) -> [a, r]
|
||||
deepEqual [1, {b:2}], f()
|
||||
deepEqual [2, {}], f {a:2}
|
||||
deepEqual [3, {c:5}], f {a:3, c:5}
|
||||
|
||||
f = ({ a: aa = 0, b: bb = 0 }) -> [aa, bb]
|
||||
deepEqual [0, 0], f {}
|
||||
deepEqual [0, 42], f {b:42}
|
||||
deepEqual [42, 0], f {a:42}
|
||||
deepEqual [42, 43], f {a:42, b:43}
|
||||
|
||||
test "#4005: `([a = {}]..., b) ->` weirdness", ->
|
||||
fn = ([a = {}]..., b) -> [a, b]
|
||||
deepEqual fn(5), [{}, 5]
|
||||
@@ -550,15 +480,6 @@ test "#4413: expressions in function parameters that create generated variables
|
||||
eq f(), 33
|
||||
eq g(), 34
|
||||
|
||||
test "#4673: complex destructured object spread variables", ->
|
||||
f = ({{a...}...}) ->
|
||||
a
|
||||
eq f(c: 1).c, 1
|
||||
|
||||
g = ({@y...}) ->
|
||||
eq @y.b, 1
|
||||
g b: 1
|
||||
|
||||
test "#4657: destructured array param declarations", ->
|
||||
a = 1
|
||||
b = 2
|
||||
|
||||
@@ -168,7 +168,7 @@ test "`throw` can be yielded", ->
|
||||
throws -> x.next()
|
||||
|
||||
test "symbolic operators has precedence over the `yield`", ->
|
||||
symbolic = '+ - * / << >> & | || && ** ^ // or and'.split ' '
|
||||
symbolic = '+ - * / << >> & | || && ^ // or and'.split ' '
|
||||
compound = ("#{op}=" for op in symbolic)
|
||||
relations = '< > == != <= >= is isnt'.split ' '
|
||||
|
||||
|
||||
3
test/importing/transpile_import.coffee
Normal file
3
test/importing/transpile_import.coffee
Normal file
@@ -0,0 +1,3 @@
|
||||
import path from 'path'
|
||||
|
||||
export getSep = -> path.sep
|
||||
@@ -139,7 +139,7 @@ eq 'multiline nested "interpolations" work', """multiline #{
|
||||
|
||||
eq 'function(){}', "#{->}".replace /\s/g, ''
|
||||
ok /^a[\s\S]+b$/.test "a#{=>}b"
|
||||
ok /^a[\s\S]+b$/.test "a#{ (x) -> x ** 2 }b"
|
||||
ok /^a[\s\S]+b$/.test "a#{ (x) -> x %% 2 }b"
|
||||
|
||||
# Regular Expression Interpolation
|
||||
|
||||
|
||||
@@ -1,34 +1,40 @@
|
||||
return unless require?
|
||||
|
||||
path = require 'path'
|
||||
{spawnSync, execFileSync} = require 'child_process'
|
||||
{ execFileSync, spawnSync } = require 'child_process'
|
||||
|
||||
# Get directory containing the compiled `coffee` executable and prepend it to
|
||||
# the path so `#!/usr/bin/env coffee` resolves to our locally built file.
|
||||
coffeeBinDir = path.dirname require.resolve('../bin/coffee')
|
||||
patchedPath = "#{coffeeBinDir}:#{process.env.PATH}"
|
||||
patchedEnv = Object.assign {}, process.env, {PATH: patchedPath}
|
||||
# Get the folder containing the compiled `coffee` executable and make it the
|
||||
# PATH so that `#!/usr/bin/env coffee` resolves to our locally built file.
|
||||
coffeeBinFolder = path.dirname require.resolve '../bin/coffee'
|
||||
# For some reason, Windows requires `coffee` to be executed as `node coffee`.
|
||||
coffeeCommand = if isWindows() then 'node coffee' else 'coffee'
|
||||
spawnOptions =
|
||||
cwd: coffeeBinFolder
|
||||
encoding: 'utf8'
|
||||
env:
|
||||
PATH: coffeeBinFolder + (if isWindows() then ';' else ':') + process.env.PATH
|
||||
shell: isWindows()
|
||||
|
||||
shebangScript = require.resolve './importing/shebang.coffee'
|
||||
initialSpaceScript = require.resolve './importing/shebang_initial_space.coffee'
|
||||
extraArgsScript = require.resolve './importing/shebang_extra_args.coffee'
|
||||
initialSpaceExtraArgsScript = require.resolve './importing/shebang_initial_space_extra_args.coffee'
|
||||
|
||||
test "parse arguments for shebang scripts correctly (on unix platforms)", ->
|
||||
test "parse arguments for shebang scripts correctly (on *nix platforms)", ->
|
||||
return if isWindows()
|
||||
|
||||
stdout = execFileSync shebangScript, ['-abck'], {env: patchedEnv}
|
||||
stdout = execFileSync shebangScript, ['-abck'], spawnOptions
|
||||
expectedArgs = ['coffee', shebangScript, '-abck']
|
||||
realArgs = JSON.parse stdout
|
||||
arrayEq expectedArgs, realArgs
|
||||
|
||||
stdout = execFileSync initialSpaceScript, ['-abck'], {env: patchedEnv}
|
||||
stdout = execFileSync initialSpaceScript, ['-abck'], spawnOptions
|
||||
expectedArgs = ['coffee', initialSpaceScript, '-abck']
|
||||
realArgs = JSON.parse stdout
|
||||
arrayEq expectedArgs, realArgs
|
||||
|
||||
test "warn and remove -- if it is the second positional argument", ->
|
||||
result = spawnSync 'coffee', [shebangScript, '--'], {env: patchedEnv}
|
||||
result = spawnSync coffeeCommand, [shebangScript, '--'], spawnOptions
|
||||
stderr = result.stderr.toString()
|
||||
arrayEq JSON.parse(result.stdout), ['coffee', shebangScript]
|
||||
ok stderr.match /^coffee was invoked with '--'/m
|
||||
@@ -36,7 +42,7 @@ test "warn and remove -- if it is the second positional argument", ->
|
||||
arrayEq JSON.parse(posArgs), [shebangScript, '--']
|
||||
ok result.status is 0
|
||||
|
||||
result = spawnSync 'coffee', ['-b', shebangScript, '--'], {env: patchedEnv}
|
||||
result = spawnSync coffeeCommand, ['-b', shebangScript, '--'], spawnOptions
|
||||
stderr = result.stderr.toString()
|
||||
arrayEq JSON.parse(result.stdout), ['coffee', shebangScript]
|
||||
ok stderr.match /^coffee was invoked with '--'/m
|
||||
@@ -45,16 +51,16 @@ test "warn and remove -- if it is the second positional argument", ->
|
||||
ok result.status is 0
|
||||
|
||||
result = spawnSync(
|
||||
'coffee', ['-b', shebangScript, '--', 'ANOTHER ONE'], {env: patchedEnv})
|
||||
coffeeCommand, ['-b', shebangScript, '--', 'ANOTHER'], spawnOptions)
|
||||
stderr = result.stderr.toString()
|
||||
arrayEq JSON.parse(result.stdout), ['coffee', shebangScript, 'ANOTHER ONE']
|
||||
arrayEq JSON.parse(result.stdout), ['coffee', shebangScript, 'ANOTHER']
|
||||
ok stderr.match /^coffee was invoked with '--'/m
|
||||
posArgs = stderr.match(/^The positional arguments were: (.*)$/m)[1]
|
||||
arrayEq JSON.parse(posArgs), [shebangScript, '--', 'ANOTHER ONE']
|
||||
arrayEq JSON.parse(posArgs), [shebangScript, '--', 'ANOTHER']
|
||||
ok result.status is 0
|
||||
|
||||
result = spawnSync(
|
||||
'coffee', ['--', initialSpaceScript, 'arg'], {env: patchedEnv})
|
||||
coffeeCommand, ['--', initialSpaceScript, 'arg'], spawnOptions)
|
||||
expectedArgs = ['coffee', initialSpaceScript, 'arg']
|
||||
realArgs = JSON.parse result.stdout
|
||||
arrayEq expectedArgs, realArgs
|
||||
@@ -62,7 +68,7 @@ test "warn and remove -- if it is the second positional argument", ->
|
||||
ok result.status is 0
|
||||
|
||||
test "warn about non-portable shebang lines", ->
|
||||
result = spawnSync 'coffee', [extraArgsScript, 'arg'], {env: patchedEnv}
|
||||
result = spawnSync coffeeCommand, [extraArgsScript, 'arg'], spawnOptions
|
||||
stderr = result.stderr.toString()
|
||||
arrayEq JSON.parse(result.stdout), ['coffee', extraArgsScript, 'arg']
|
||||
ok stderr.match /^The script to be run begins with a shebang line with more than one/m
|
||||
@@ -73,14 +79,14 @@ test "warn about non-portable shebang lines", ->
|
||||
arrayEq JSON.parse(args), ['coffee', '--']
|
||||
ok result.status is 0
|
||||
|
||||
result = spawnSync 'coffee', [initialSpaceScript, 'arg'], {env: patchedEnv}
|
||||
result = spawnSync coffeeCommand, [initialSpaceScript, 'arg'], spawnOptions
|
||||
stderr = result.stderr.toString()
|
||||
ok stderr is ''
|
||||
arrayEq JSON.parse(result.stdout), ['coffee', initialSpaceScript, 'arg']
|
||||
ok result.status is 0
|
||||
|
||||
result = spawnSync(
|
||||
'coffee', [initialSpaceExtraArgsScript, 'arg'], {env: patchedEnv})
|
||||
coffeeCommand, [initialSpaceExtraArgsScript, 'arg'], spawnOptions)
|
||||
stderr = result.stderr.toString()
|
||||
arrayEq JSON.parse(result.stdout), ['coffee', initialSpaceExtraArgsScript, 'arg']
|
||||
ok stderr.match /^The script to be run begins with a shebang line with more than one/m
|
||||
@@ -93,7 +99,7 @@ test "warn about non-portable shebang lines", ->
|
||||
|
||||
test "both warnings will be shown at once", ->
|
||||
result = spawnSync(
|
||||
'coffee', [initialSpaceExtraArgsScript, '--', 'arg'], {env: patchedEnv})
|
||||
coffeeCommand, [initialSpaceExtraArgsScript, '--', 'arg'], spawnOptions)
|
||||
stderr = result.stderr.toString()
|
||||
arrayEq JSON.parse(result.stdout), ['coffee', initialSpaceExtraArgsScript, 'arg']
|
||||
ok stderr.match /^The script to be run begins with a shebang line with more than one/m
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user