mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-13 16:57:54 -05:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
43
README.md
43
README.md
@@ -1,22 +1,27 @@
|
||||
{
|
||||
} } {
|
||||
{ { } }
|
||||
} }{ {
|
||||
{ }{ } } _____ __ __
|
||||
{ }{ }{ { } / ____| / _|/ _|
|
||||
.- { { } { }} -. | | ___ | |_| |_ ___ ___
|
||||
( { } { } { } } ) | | / _ \| _| _/ _ \/ _ \
|
||||
|`-..________ ..-'| | |___| (_) | | | || __/ __/
|
||||
| | \_____\___/|_| |_| \___|\___|
|
||||
| ;--.
|
||||
| (__ \ _____ _ _
|
||||
| | ) ) / ____| (_) | |
|
||||
| |/ / | (___ ___ _ __ _ _ __ | |_
|
||||
| ( / \___ \ / __| '__| | '_ \| __|
|
||||
| |/ ____) | (__| | | | |_) | |_
|
||||
| | |_____/ \___|_| |_| .__/ \__|
|
||||
`-.._________..-' | |
|
||||
|_|
|
||||
@@@@@@@ @@@@ @@@@@
|
||||
{ @@@@@@@@@@ @@@ @@@
|
||||
} } { @@@@ @@ @@@ @@@
|
||||
{ { } } @@@@ @@@@@@@ @@@ @@@ @@@@@@ @@@@@@
|
||||
} }{ { @@@@ @@@ @@ @@@@@ @@@@@@ @@@ @@ @@@@ @@
|
||||
{ }{ } } @@@@ @@@@ @@ @@@ @@@ @@@ @@@ @@@ @@@
|
||||
{ }{ }{ { } @@@@ @@@@ @@ @@@ @@@ @@@@@@@@ @@@@@@@@
|
||||
{ { } { } { } } @@@@@ @@@@ @@ @@@ @@@ @@@ @@@
|
||||
{ } { } { } @@@@@@@@@@ @@@@@@@@ @@@ @@@ @@@@@@@@ @@@@@@@@
|
||||
@@@@@@ { } { } @@@@@@@ @@@@@ @@@ @@@ @@@@@ @@@@@
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@ @@@
|
||||
@@ @@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@ @@@ @@@
|
||||
@@ @@@@@@@@@@@@@@@@@@@@@@@@ @@@@ @@ @@@ @@@@
|
||||
@@@ @@@@@@@@@@@@@@@@@@@@@ @@@@ @@@ @@ @@@@
|
||||
@@@ @@@@@@@@@@@@@@@@@@ @@@@@ @@@@@ @@ @@ @@@ @@@@@@@ @@@@@
|
||||
@@@ @@@@@@@@@@@@@@@@ @@@@@ @@@ @@@ @@@@@@@@ @@@@ @@@@ @@@@@@@
|
||||
@@@@@@@@@@@@@@ @@@@@ @@@ @@@@ @@@@ @@@ @@@ @@@
|
||||
@@@@@ @@@@ @@@@ @@@@ @@@@ @@@@ @@@@ @@@@
|
||||
@@@ @@@@ @@@ @@@@ @@@@ @@@ @@@@ @@@@
|
||||
@@@ @@@@ @@@@ @@@@ @@@@ @@@@ @@@@ @@@@
|
||||
@@@@@@@@@ @@@@@@ @@@@ @@@@ @@@@@@@@@ @@@@
|
||||
@@@ @@@@
|
||||
@@@
|
||||
@@@
|
||||
|
||||
CoffeeScript is a little language that compiles into JavaScript.
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -650,7 +650,7 @@ of <strong>Block</strong> preceded by a function arrow, with an optional paramet
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> Code: [
|
||||
o <span class="hljs-string">'PARAM_START ParamList PARAM_END FuncGlyph Block'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Code $<span class="hljs-number">2</span>, $<span class="hljs-number">5</span>, $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'PARAM_START ParamList PARAM_END FuncGlyph Block'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Code $<span class="hljs-number">2</span>, $<span class="hljs-number">5</span>, $<span class="hljs-number">4</span>, LOC(<span class="hljs-number">1</span>)(<span class="hljs-keyword">new</span> Literal $<span class="hljs-number">1</span>)
|
||||
o <span class="hljs-string">'FuncGlyph Block'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Code [], $<span class="hljs-number">2</span>, $<span class="hljs-number">1</span>
|
||||
]</pre></div></div>
|
||||
|
||||
|
||||
@@ -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,7 +461,7 @@ 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>])
|
||||
<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[@tokens.length - <span class="hljs-number">2</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">#{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>
|
||||
prevprev = @tokens[@tokens.length - <span class="hljs-number">2</span>]
|
||||
@@ -466,7 +472,7 @@ what CoffeeScript would normally interpret as calls to functions named
|
||||
<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]
|
||||
@@ -1968,9 +1974,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>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
0
docs/v2/annotated-source/public/fonts/roboto-black.eot
Executable file → Normal file
0
docs/v2/annotated-source/public/fonts/roboto-black.eot
Executable file → Normal file
0
docs/v2/annotated-source/public/fonts/roboto-black.ttf
Executable file → Normal file
0
docs/v2/annotated-source/public/fonts/roboto-black.ttf
Executable file → Normal file
0
docs/v2/annotated-source/public/fonts/roboto-black.woff
Executable file → Normal file
0
docs/v2/annotated-source/public/fonts/roboto-black.woff
Executable file → Normal file
@@ -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>,
|
||||
@@ -268,7 +269,7 @@ 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>Wrap the expression in a closure to support top-level <code>await</code>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -284,13 +285,14 @@ Unwrap that too.</p>
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
</div>
|
||||
<p>Invoke the wrapping closure</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>}
|
||||
result = runInContext js, context, filename</pre></div></div>
|
||||
<span class="hljs-keyword">if</span> transpile
|
||||
js = transpile.transpile(js, transpile.options).code</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -301,7 +303,24 @@ Unwrap that too.</p>
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-12">¶</a>
|
||||
</div>
|
||||
<p>Await an async result, if necessary</p>
|
||||
<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-13">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-13">¶</a>
|
||||
</div>
|
||||
<p>Await an async result, if necessary.</p>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -316,11 +335,11 @@ Unwrap that too.</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>AST’s <code>compile</code> does not add source code information to syntax errors.</p>
|
||||
|
||||
@@ -341,11 +360,11 @@ Unwrap that too.</p>
|
||||
</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>Node 0.11.12 changed API, prompt is now _prompt.</p>
|
||||
|
||||
@@ -362,11 +381,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-15">
|
||||
<li id="section-16">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-15">¶</a>
|
||||
<a class="pilcrow" href="#section-16">¶</a>
|
||||
</div>
|
||||
<p>Proxy node’s line listener</p>
|
||||
|
||||
@@ -387,11 +406,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-16">
|
||||
<li id="section-17">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-16">¶</a>
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
</div>
|
||||
<p>Handle Ctrl-v</p>
|
||||
|
||||
@@ -404,11 +423,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-17">
|
||||
<li id="section-18">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
<a class="pilcrow" href="#section-18">¶</a>
|
||||
</div>
|
||||
<p>allow arbitrarily switching between modes any time before multiple lines are entered</p>
|
||||
|
||||
@@ -423,11 +442,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-18">
|
||||
<li id="section-19">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-18">¶</a>
|
||||
<a class="pilcrow" href="#section-19">¶</a>
|
||||
</div>
|
||||
<p>no-op unless the current line is empty</p>
|
||||
|
||||
@@ -438,11 +457,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-19">
|
||||
<li id="section-20">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-19">¶</a>
|
||||
<a class="pilcrow" href="#section-20">¶</a>
|
||||
</div>
|
||||
<p>eval, print, loop</p>
|
||||
|
||||
@@ -457,11 +476,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-20">
|
||||
<li id="section-21">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-20">¶</a>
|
||||
<a class="pilcrow" href="#section-21">¶</a>
|
||||
</div>
|
||||
<p>XXX: multiline hack</p>
|
||||
|
||||
@@ -479,11 +498,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-21">
|
||||
<li id="section-22">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-21">¶</a>
|
||||
<a class="pilcrow" href="#section-22">¶</a>
|
||||
</div>
|
||||
<p>Store and load command history from a file</p>
|
||||
|
||||
@@ -496,11 +515,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-22">
|
||||
<li id="section-23">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-22">¶</a>
|
||||
<a class="pilcrow" href="#section-23">¶</a>
|
||||
</div>
|
||||
<p>Get file info and at most maxSize of command history</p>
|
||||
|
||||
@@ -512,11 +531,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-23">
|
||||
<li id="section-24">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-23">¶</a>
|
||||
<a class="pilcrow" href="#section-24">¶</a>
|
||||
</div>
|
||||
<p>Read last <code>size</code> bytes from the file</p>
|
||||
|
||||
@@ -530,11 +549,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-24">
|
||||
<li id="section-25">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-24">¶</a>
|
||||
<a class="pilcrow" href="#section-25">¶</a>
|
||||
</div>
|
||||
<p>Set the history on the interpreter</p>
|
||||
|
||||
@@ -545,11 +564,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-25">
|
||||
<li id="section-26">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-25">¶</a>
|
||||
<a class="pilcrow" href="#section-26">¶</a>
|
||||
</div>
|
||||
<p>If the history file was truncated we should pop off a potential partial line</p>
|
||||
|
||||
@@ -560,11 +579,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-26">
|
||||
<li id="section-27">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-26">¶</a>
|
||||
<a class="pilcrow" href="#section-27">¶</a>
|
||||
</div>
|
||||
<p>Shift off the final blank newline</p>
|
||||
|
||||
@@ -582,11 +601,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-27">
|
||||
<li id="section-28">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-27">¶</a>
|
||||
<a class="pilcrow" href="#section-28">¶</a>
|
||||
</div>
|
||||
<p>Save the latest command in the file</p>
|
||||
|
||||
@@ -598,11 +617,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-28">
|
||||
<li id="section-29">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-28">¶</a>
|
||||
<a class="pilcrow" href="#section-29">¶</a>
|
||||
</div>
|
||||
<p>XXX: The SIGINT event from REPLServer is undocumented, so this is a bit fragile</p>
|
||||
|
||||
@@ -614,11 +633,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-29">
|
||||
<li id="section-30">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-29">¶</a>
|
||||
<a class="pilcrow" href="#section-30">¶</a>
|
||||
</div>
|
||||
<p>Add a command to show the history stack</p>
|
||||
|
||||
@@ -635,11 +654,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-30">
|
||||
<li id="section-31">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-30">¶</a>
|
||||
<a class="pilcrow" href="#section-31">¶</a>
|
||||
</div>
|
||||
<p>Node 0.11 changed API, a command such as ‘.help’ is now stored as ‘help’</p>
|
||||
|
||||
@@ -658,6 +677,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-32">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-32">¶</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 +725,11 @@ Unwrap that too.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-31">
|
||||
<li id="section-33">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-31">¶</a>
|
||||
<a class="pilcrow" href="#section-33">¶</a>
|
||||
</div>
|
||||
<p>Adapt help inherited from the node REPL</p>
|
||||
|
||||
|
||||
@@ -1596,8 +1596,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
@@ -180,16 +180,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 {
|
||||
@@ -214,11 +215,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 {
|
||||
@@ -239,13 +247,18 @@ h3, h4, h2 time {
|
||||
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 {
|
||||
font-family: 'Roboto Mono';
|
||||
font-weight: 400;
|
||||
}
|
||||
code, a > code {
|
||||
background-color: #f8f3f0;
|
||||
padding: 0.2rem 0.4rem;
|
||||
}
|
||||
code {
|
||||
color: #2f2625;
|
||||
@@ -290,6 +303,10 @@ textarea {
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.CodeMirror pre, pre.placeholder-code {
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
.CodeMirror,
|
||||
.placeholder-code {
|
||||
/* https://codemirror.net/demo/resize.html */
|
||||
@@ -379,12 +396,18 @@ textarea {
|
||||
/* 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: 90%; /* 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;
|
||||
}
|
||||
div.CodeMirror-cursor {
|
||||
@@ -530,7 +553,6 @@ div.CodeMirror-cursor {
|
||||
<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>
|
||||
@@ -597,6 +619,7 @@ div.CodeMirror-cursor {
|
||||
<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>
|
||||
@@ -609,20 +632,26 @@ div.CodeMirror-cursor {
|
||||
|
||||
</nav>
|
||||
<main class="main col-lg-9 ml-auto">
|
||||
<header class="title-logo d-none d-lg-block">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-22 347 566 100">
|
||||
<header class="d-none d-lg-block">
|
||||
<p class="title-logo">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-22 347 566 100">
|
||||
<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"/>
|
||||
</svg>
|
||||
|
||||
</p>
|
||||
</header>
|
||||
<section id="overview">
|
||||
<p><strong>CoffeeScript is a little language that compiles into JavaScript.</strong> Underneath that awkward Java-esque patina, JavaScript has always had a gorgeous heart. CoffeeScript is an attempt to expose the good parts of JavaScript in a simple way.</p>
|
||||
<p>The golden rule of CoffeeScript is: <em>“It’s just JavaScript.”</em> The code compiles one-to-one into the equivalent JS, and there is no interpretation at runtime. You can use any existing JavaScript library seamlessly from CoffeeScript (and vice-versa). The compiled output is readable, pretty-printed, and tends to run as fast or faster than the equivalent handwritten JavaScript.</p>
|
||||
<p><strong>Latest Version:</strong> <a href="https://github.com/jashkenas/coffeescript/tarball/2.0.0">2.0.0</a></p>
|
||||
<blockquote class="uneditable-code-block"><pre><code class="language-bash">npm install -g coffeescript
|
||||
<p><strong>Latest Version:</strong> <a href="https://github.com/jashkenas/coffeescript/tarball/2.0.2">2.0.2</a></p>
|
||||
<blockquote class="uneditable-code-block"><pre><code class="language-bash"><span class="comment"># Install locally for a project:</span>
|
||||
npm install --save-dev coffeescript
|
||||
|
||||
<span class="comment"># Install globally to execute .coffee files anywhere:</span>
|
||||
npm install --global coffeescript
|
||||
</code></pre>
|
||||
</blockquote>
|
||||
<h2>Overview</h2>
|
||||
@@ -813,12 +842,6 @@ cubes = (function() {
|
||||
<p>The biggest change in CoffeeScript 2 is that now the CoffeeScript compiler produces modern JavaScript syntax (ES6, or ES2015 and later). A CoffeeScript <code>=></code> becomes a JS <code>=></code>, a CoffeeScript <code>class</code> becomes a JS <code>class</code> and so on. Major new features in CoffeeScript 2 include <a href="#async-functions">async functions</a> and <a href="#jsx">JSX</a>. You can read more in the <a href="announcing-coffeescript-2/">announcement</a>.</p>
|
||||
<p>There are very few <a href="#breaking-changes">breaking changes from CoffeeScript 1.x to 2</a>; we hope the upgrade process is smooth for most projects.</p>
|
||||
|
||||
</section>
|
||||
<section id="why-coffeescript">
|
||||
<h3>Why CoffeeScript When There’s ES6?</h3>
|
||||
<p>CoffeeScript introduced many new features to the JavaScript world, such as <a href="#fat-arrow"><code>=></code></a> and <a href="#destructuring">destructuring</a> and <a href="#classes">classes</a>. We are happy that ECMA has seen their utility and adopted them into ECMAScript.</p>
|
||||
<p>CoffeeScript’s intent, however, was never to be a superset of JavaScript. One of the guiding principles of CoffeeScript has been <em>simplicity:</em> 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.</p>
|
||||
|
||||
</section>
|
||||
<section id="compatibility">
|
||||
<h3>Compatibility</h3>
|
||||
@@ -829,15 +852,16 @@ cubes = (function() {
|
||||
</section>
|
||||
<section id="installation">
|
||||
<h2>Installation</h2>
|
||||
<p>The command-line version of <code>coffee</code> is available as a <a href="https://nodejs.org/">Node.js</a> utility. The <a href="/v2/browser-compiler/coffeescript.js">core compiler</a> however, does not depend on Node, and can be run in any JavaScript environment, or in the browser (see <a href="#try">Try CoffeeScript</a>).</p>
|
||||
<p>The command-line version of <code>coffee</code> is available as a <a href="https://nodejs.org/">Node.js</a> utility, requiring Node 6 or later. The <a href="/v2/browser-compiler/coffeescript.js">core compiler</a> however, does not depend on Node, and can be run in any JavaScript environment, or in the browser (see <a href="#try">Try CoffeeScript</a>).</p>
|
||||
<p>To install, first make sure you have a working copy of the latest stable version of <a href="https://nodejs.org/">Node.js</a>. You can then install CoffeeScript globally with <a href="https://www.npmjs.com/">npm</a>:</p>
|
||||
<blockquote class="uneditable-code-block"><pre><code class="language-bash">npm install --global coffeescript
|
||||
</code></pre>
|
||||
</blockquote><p>This will make the <code>coffee</code> and <code>cake</code> commands available globally.</p>
|
||||
<p>When you need CoffeeScript as a dependency of a project, within that project’s folder you can install it locally:</p>
|
||||
<p>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:</p>
|
||||
<blockquote class="uneditable-code-block"><pre><code class="language-bash">npm install --save-dev coffeescript
|
||||
</code></pre>
|
||||
</blockquote><p>The <code>coffee</code> and <code>cake</code> 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.</p>
|
||||
<p>If you plan to use the <code>--transpile</code> option (see <a href="#transpilation">Transpilation</a>) you will need to also install <code>babel-core</code> either globally or locally, depending on whether you are running a globally or locally installed version of CoffeeScript.</p>
|
||||
|
||||
</section>
|
||||
<section id="usage">
|
||||
@@ -967,30 +991,31 @@ eval CoffeeScript.compile <span class="string">'console.log "Mmmmm, I could real
|
||||
</section>
|
||||
<section id="transpilation">
|
||||
<h3>Transpilation</h3>
|
||||
<p>CoffeeScript 2 generates JavaScript that uses the latest, modern syntax. Your runtime <a href="#compatibility">might not support all of that syntax</a>. If so, you need to <em>transpile</em> the JavaScript. To make things a little easier, CoffeeScript has built-in support for the popular <a href="http://babeljs.io/">Babel</a> transpiler.</p>
|
||||
<p>CoffeeScript 2 generates JavaScript that uses the latest, modern syntax. The runtime or browsers where you want your code to run <a href="#compatibility">might not support all of that syntax</a>. 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, <code>{ a } = obj</code> into <code>a = obj.a</code>. This is done via transpilers like <a href="http://babeljs.io/">Babel</a>, <a href="https://buble.surge.sh/">Bublé</a> or <a href="https://github.com/google/traceur-compiler">Traceur Compiler</a>.</p>
|
||||
<h4>Quickstart</h4>
|
||||
<p>From the root of your project:</p>
|
||||
<blockquote class="uneditable-code-block"><pre><code class="language-bash">npm install --save-dev babel-core babel-preset-env
|
||||
<span class="built_in">echo</span> <span class="string">'{ "presets": ["env"] }'</span> > .babelrc
|
||||
coffee --compile --transpile --inline-map some-file.coffee
|
||||
</code></pre>
|
||||
</blockquote><h4>About Transpilation</h4>
|
||||
<p>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, <code>{ a } = obj</code> into <code>a = obj.a</code>. This is done via transpilers like <a href="http://babeljs.io/">Babel</a>, <a href="https://buble.surge.sh/">Bublé</a> or <a href="https://github.com/google/traceur-compiler">Traceur Compiler</a>.</p>
|
||||
<p>CoffeeScript includes a <code>--transpile</code> option when used via the <code>coffee</code> command, or a <code>transpile</code> option when used via Node. To use either, <a href="http://babeljs.io/">Babel</a> must be installed in your project:</p>
|
||||
</blockquote><h4>Transpiling with the CoffeeScript compiler</h4>
|
||||
<p>To make things easy, CoffeeScript has built-in support for the popular <a href="http://babeljs.io/">Babel</a> transpiler. You can use it via the <code>--transpile</code> command-line option or the <code>transpile</code> Node API option. To use either, <code>babel-core</code> must be installed in your project:</p>
|
||||
<blockquote class="uneditable-code-block"><pre><code class="language-bash">npm install --save-dev babel-core
|
||||
</code></pre>
|
||||
</blockquote><p>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.</p>
|
||||
<p>If you’re not sure what you need, a good starting point is <a href="https://babeljs.io/docs/plugins/preset-env/"><code>babel-preset-env</code></a>:</p>
|
||||
<blockquote class="uneditable-code-block"><pre><code class="language-bash">npm install --save-dev babel-preset-env
|
||||
</blockquote><p>Or if you’re running the <code>coffee</code> command outside of a project folder, using a globally-installed <code>coffeescript</code> module, <code>babel-core</code> needs to be installed globally:</p>
|
||||
<blockquote class="uneditable-code-block"><pre><code class="language-bash">npm install --global babel-core
|
||||
</code></pre>
|
||||
</blockquote><p>See <a href="https://babeljs.io/docs/plugins/">Babel’s website to learn about presets and plugins</a> and the multitude of options you have.</p>
|
||||
<p>Simply installing <code>babel-preset-env</code> isn’t enough. You also need to define the configuration options that you want Babel to use. You can do this by creating a <a href="https://babeljs.io/docs/usage/babelrc/"><code>.babelrc</code> file</a> 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 <code>~/app</code> and your files are in <code>~/app/src</code>, you can put <code>.babelrc</code> in either <code>~/app</code> or in <code>~/app/src</code>. You can also define the Babel options via a <code>babel</code> key in the <code>package.json</code> file for your project. A minimal <code>.babelrc</code> file (or <code>package.json</code> <code>babel</code> key) for use with <code>babel-preset-env</code> would be just <code>{ "presets": ["env"] }</code>.</p>
|
||||
<p>Once you have <code>babel-core</code> and <code>babel-preset-env</code> (or other presets or plugins) installed, and a <code>.babelrc</code> file (or <code>package.json</code> <code>babel</code> key) in place, you can use <code>coffee --transpile</code> to pipe CoffeeScript’s output through Babel using the options you’ve saved.</p>
|
||||
</blockquote><p>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 <a href="https://babeljs.io/docs/usage/babelrc/"><code>.babelrc</code> file</a> in the folder containing the files you’re compiling, or in any parent folder up the path above those files. (Babel supports <a href="https://babeljs.io/docs/usage/babelrc/">other ways</a>, too.) A minimal <code>.babelrc</code> file would be just <code>{ "presets": ["env"] }</code>. This implies that you have installed <a href="https://babeljs.io/docs/plugins/preset-env/"><code>babel-preset-env</code></a>:</p>
|
||||
<blockquote class="uneditable-code-block"><pre><code class="language-bash">npm install --save-dev babel-preset-env <span class="comment"># Or --global for non-project-based usage</span>
|
||||
</code></pre>
|
||||
</blockquote><p>See <a href="https://babeljs.io/docs/plugins/">Babel’s website to learn about presets and plugins</a> and the multitude of options you have. Another preset you might need is <a href="https://babeljs.io/docs/plugins/transform-react-jsx/"><code>transform-react-jsx</code></a> if you’re using JSX with React (JSX can also be used with other frameworks).</p>
|
||||
<p>Once you have <code>babel-core</code> and <code>babel-preset-env</code> (or other presets or plugins) installed, and a <code>.babelrc</code> file (or other equivalent) in place, you can use <code>coffee --transpile</code> to pipe CoffeeScript’s output through Babel using the options you’ve saved.</p>
|
||||
<p>If you’re using CoffeeScript via the <a href="nodejs_usage">Node API</a>, where you call <code>CoffeeScript.compile</code> with a string to be compiled and an <code>options</code> object, the <code>transpile</code> key of the <code>options</code> object should be the Babel options:</p>
|
||||
<blockquote class="uneditable-code-block"><pre><code class="language-js">CoffeeScript.compile(code, {<span class="attr">transpile</span>: {<span class="attr">presets</span>: [<span class="string">'env'</span>]}})
|
||||
</code></pre>
|
||||
</blockquote><p>You can also transpile CoffeeScript’s output without using the <code>transpile</code> 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 <a href="http://gulpjs.com/">Gulp</a>, <a href="https://webpack.github.io/">Webpack</a>, <a href="https://gruntjs.com/">Grunt</a> and <a href="http://broccolijs.com/">Broccoli</a>.</p>
|
||||
<p>Note that <a href="https://babeljs.io/docs/plugins/preset-env/">babel-preset-env</a> doesn’t automatically supply <a href="https://developer.mozilla.org/en-US/docs/Glossary/Polyfill">polyfills</a> for your code. CoffeeScript itself will output <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf"><code>Array.indexOf</code></a> if you use the <code>in</code> operator, or destructuring or spread/rest syntax; and <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind"><code>Function.bind</code></a> if you use a bound (<code>=></code>) 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 <a href="https://babeljs.io/docs/usage/polyfill/"><code>babel-polyfill</code></a>, though there are many <a href="https://hackernoon.com/polyfills-everything-you-ever-wanted-to-know-or-maybe-a-bit-less-7c8de164e423">other</a> <a href="https://philipwalton.com/articles/loading-polyfills-only-when-needed/">strategies</a>.</p>
|
||||
<h4>Polyfills</h4>
|
||||
<p>Note that transpiling doesn’t automatically supply <a href="https://developer.mozilla.org/en-US/docs/Glossary/Polyfill">polyfills</a> for your code. CoffeeScript itself will output <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf"><code>Array.indexOf</code></a> if you use the <code>in</code> operator, or destructuring or spread/rest syntax; and <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind"><code>Function.bind</code></a> if you use a bound (<code>=></code>) 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 <a href="https://babeljs.io/docs/usage/polyfill/"><code>babel-polyfill</code></a>, though there are many <a href="https://hackernoon.com/polyfills-everything-you-ever-wanted-to-know-or-maybe-a-bit-less-7c8de164e423">other</a> <a href="https://philipwalton.com/articles/loading-polyfills-only-when-needed/">strategies</a>.</p>
|
||||
|
||||
</section>
|
||||
</section>
|
||||
@@ -1678,7 +1703,10 @@ alert(`Gold: ${gold}\nSilver: ${silver}\nThe Field: ${rest.join(', ')}`);
|
||||
|
||||
<div class="row">
|
||||
<div class="col text-right">
|
||||
<button type="button" class="btn btn-primary" data-action="run-code-example" data-example="splats" data-run="true"></button>
|
||||
<button type="button" class="btn btn-primary" data-action="run-code-example" data-example="splats" data-run="true"><small><svg class="play-button" viewBox="0 0 24 24">
|
||||
<path d="M2.56-0.01v24.02L21.44 11.98 2.56-0.01z"/>
|
||||
</svg>
|
||||
</small></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2473,7 +2501,10 @@ alert((function() {
|
||||
|
||||
<div class="row">
|
||||
<div class="col text-right">
|
||||
<button type="button" class="btn btn-primary" data-action="run-code-example" data-example="expressions_try" data-run="true"></button>
|
||||
<button type="button" class="btn btn-primary" data-action="run-code-example" data-example="expressions_try" data-run="true"><small><svg class="play-button" viewBox="0 0 24 24">
|
||||
<path d="M2.56-0.01v24.02L21.44 11.98 2.56-0.01z"/>
|
||||
</svg>
|
||||
</small></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3543,7 +3574,10 @@ countdown(3);
|
||||
|
||||
<div class="row">
|
||||
<div class="col text-right">
|
||||
<button type="button" class="btn btn-primary" data-action="run-code-example" data-example="async" data-run="true"></button>
|
||||
<button type="button" class="btn btn-primary" data-action="run-code-example" data-example="async" data-run="true"><small><svg class="play-button" viewBox="0 0 24 24">
|
||||
<path d="M2.56-0.01v24.02L21.44 11.98 2.56-0.01z"/>
|
||||
</svg>
|
||||
</small></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3681,7 +3715,10 @@ tom.move();
|
||||
|
||||
<div class="row">
|
||||
<div class="col text-right">
|
||||
<button type="button" class="btn btn-primary" data-action="run-code-example" data-example="classes" data-run="true"></button>
|
||||
<button type="button" class="btn btn-primary" data-action="run-code-example" data-example="classes" data-run="true"><small><svg class="play-button" viewBox="0 0 24 24">
|
||||
<path d="M2.56-0.01v24.02L21.44 11.98 2.56-0.01z"/>
|
||||
</svg>
|
||||
</small></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4575,28 +4612,50 @@ renderStarRating = function({rating, maxStars}) {
|
||||
<div class="col-md-6 coffeescript-input-column">
|
||||
<textarea class="coffeescript-input" id="type_annotations-coffee"># @flow
|
||||
|
||||
fn = (str ###: string ###, num ###: number ###) ###: string ### ->
|
||||
str + num
|
||||
###::
|
||||
type Obj = {
|
||||
num: number,
|
||||
};
|
||||
###
|
||||
|
||||
fn = (str ###: string ###, obj ###: Obj ###) ###: string ### ->
|
||||
str + obj.num
|
||||
</textarea>
|
||||
<pre class="placeholder-code"><span class="cm-comment"># @flow</span>
|
||||
|
||||
<span class="cm-variable">fn</span> <span class="cm-punctuation">=</span> <span class="cm-punctuation">(</span><span class="cm-variable">str</span> <span class="cm-comment">###: string ###</span><span class="cm-punctuation">,</span> <span class="cm-variable">num</span> <span class="cm-comment">###: number ###</span><span class="cm-punctuation">)</span> <span class="cm-comment">###: string ###</span> <span class="cm-operator">-></span>
|
||||
<span class="cm-variable">str</span> <span class="cm-operator">+</span> <span class="cm-variable">num</span>
|
||||
<span class="cm-comment">###::</span>
|
||||
<span class="cm-comment">type Obj = {</span>
|
||||
<span class="cm-comment"> num: number,</span>
|
||||
<span class="cm-comment">};</span>
|
||||
<span class="cm-comment">###</span>
|
||||
|
||||
<span class="cm-variable">fn</span> <span class="cm-punctuation">=</span> <span class="cm-punctuation">(</span><span class="cm-variable">str</span> <span class="cm-comment">###: string ###</span><span class="cm-punctuation">,</span> <span class="cm-variable">obj</span> <span class="cm-comment">###: Obj ###</span><span class="cm-punctuation">)</span> <span class="cm-comment">###: string ###</span> <span class="cm-operator">-></span>
|
||||
<span class="cm-variable">str</span> <span class="cm-operator">+</span> <span class="cm-variable">obj</span><span class="cm-punctuation">.</span><span class="cm-property">num</span>
|
||||
</pre>
|
||||
</div>
|
||||
<div class="col-md-6 javascript-output-column">
|
||||
<textarea class="javascript-output" id="type_annotations-js">// @flow
|
||||
/*::
|
||||
type Obj = {
|
||||
num: number,
|
||||
};
|
||||
*/
|
||||
var fn;
|
||||
|
||||
fn = function(str/*: string */, num/*: number */)/*: string */ {
|
||||
return str + num;
|
||||
fn = function(str/*: string */, obj/*: Obj */)/*: string */ {
|
||||
return str + obj.num;
|
||||
};
|
||||
</textarea>
|
||||
<pre class="placeholder-code"><span class="cm-comment">// @flow</span>
|
||||
<span class="cm-comment">/*::</span>
|
||||
<span class="cm-comment">type Obj = {</span>
|
||||
<span class="cm-comment"> num: number,</span>
|
||||
<span class="cm-comment">};</span>
|
||||
<span class="cm-comment">*/</span>
|
||||
<span class="cm-keyword">var</span> <span class="cm-def">fn</span>;
|
||||
|
||||
<span class="cm-variable">fn</span> <span class="cm-operator">=</span> <span class="cm-keyword">function</span>(<span class="cm-def">str</span><span class="cm-comment">/*: string */</span>, <span class="cm-def">num</span><span class="cm-comment">/*: number */</span>)<span class="cm-comment">/*: string */</span> {
|
||||
<span class="cm-keyword">return</span> <span class="cm-variable-2">str</span> <span class="cm-operator">+</span> <span class="cm-variable-2">num</span>;
|
||||
<span class="cm-variable">fn</span> <span class="cm-operator">=</span> <span class="cm-keyword">function</span>(<span class="cm-def">str</span><span class="cm-comment">/*: string */</span>, <span class="cm-def">obj</span><span class="cm-comment">/*: Obj */</span>)<span class="cm-comment">/*: string */</span> {
|
||||
<span class="cm-keyword">return</span> <span class="cm-variable-2">str</span> <span class="cm-operator">+</span> <span class="cm-variable-2">obj</span>.<span class="cm-property">num</span>;
|
||||
};
|
||||
</pre>
|
||||
</div>
|
||||
@@ -4713,7 +4772,7 @@ If you’ve ever learned a neat CoffeeScript tip or trick, or ran into a gotcha
|
||||
Perhaps your CoffeeScript-related question has been asked before. Check the FAQ first.</li>
|
||||
<li><a href="http://js2.coffee/">JS2Coffee</a><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.</li>
|
||||
<li><a href="https://github.com/jashkenas/coffeescript/tree/master/documentation/images">High-Rez Logo</a><br>
|
||||
<li><a href="https://github.com/jashkenas/coffeescript/tree/master/documentation/site">High-Rez Logo</a><br>
|
||||
The CoffeeScript logo is available in SVG for use in presentations.</li>
|
||||
</ul>
|
||||
|
||||
@@ -4762,7 +4821,7 @@ The CoffeeScript logo is available in SVG for use in presentations.</li>
|
||||
</section>
|
||||
<section id="annotated-source">
|
||||
<h2>Annotated Source</h2>
|
||||
<p>You can browse the CoffeeScript 2.0.0 source in readable, annotated form <a href="annotated-source/">here</a>. You can also jump directly to a particular source file:</p>
|
||||
<p>You can browse the CoffeeScript 2.0.2 source in readable, annotated form <a href="annotated-source/">here</a>. You can also jump directly to a particular source file:</p>
|
||||
<ul>
|
||||
<li><a href="annotated-source/grammar.html">Grammar Rules — src/grammar</a></li>
|
||||
<li><a href="annotated-source/lexer.html">Lexing Tokens — src/lexer</a></li>
|
||||
@@ -5092,10 +5151,6 @@ f = function*() {
|
||||
<blockquote class="uneditable-code-block"><pre><code class="language-coffee">(<span class="class"><span class="keyword">class</span>)()</span>
|
||||
<span class="comment"># Throws a TypeError at runtime</span>
|
||||
</code></pre>
|
||||
</blockquote><p>Derived (extended) class <code>constructor</code>s cannot use <code>this</code> before calling <code>super</code>:</p>
|
||||
<blockquote class="uneditable-code-block"><pre><code class="language-coffee"><span class="class"><span class="keyword">class</span> <span class="title">B</span> <span class="keyword">extends</span> <span class="title">A</span></span>
|
||||
constructor: <span class="function">-></span> <span class="keyword">this</span> <span class="comment"># Throws a compiler error</span>
|
||||
</code></pre>
|
||||
</blockquote><p>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:</p>
|
||||
<blockquote class="uneditable-code-block"><pre><code class="language-coffee"><span class="class"><span class="keyword">class</span> <span class="title">Base</span></span>
|
||||
constructor: <span class="function">-></span>
|
||||
@@ -5119,6 +5174,59 @@ f = function*() {
|
||||
@::[name] = <span class="function">-></span> <span class="comment"># This will work; assigns to `A.prototype.method`</span>
|
||||
</code></pre>
|
||||
</blockquote>
|
||||
</section>
|
||||
<section id="breaking-changes-super-this">
|
||||
<h3><code>super</code> and <code>this</code></h3>
|
||||
<p>In the constructor of a derived class (a class that <code>extends</code> another class), <code>this</code> cannot be used before calling <code>super</code>:</p>
|
||||
<blockquote class="uneditable-code-block"><pre><code class="language-coffee"><span class="class"><span class="keyword">class</span> <span class="title">B</span> <span class="keyword">extends</span> <span class="title">A</span></span>
|
||||
constructor: <span class="function">-></span> <span class="keyword">this</span> <span class="comment"># Throws a compiler error</span>
|
||||
</code></pre>
|
||||
</blockquote><p>This also means you cannot pass a reference to <code>this</code> as an argument to <code>super</code> in the constructor of a derived class:</p>
|
||||
<blockquote class="uneditable-code-block"><pre><code class="language-coffee"><span class="class"><span class="keyword">class</span> <span class="title">B</span> <span class="keyword">extends</span> <span class="title">A</span></span>
|
||||
constructor: <span class="function"><span class="params">(@arg)</span> -></span>
|
||||
<span class="keyword">super</span> @arg <span class="comment"># Throws a compiler error</span>
|
||||
</code></pre>
|
||||
</blockquote><p>This is a limitation of ES2015 classes. As a workaround, assign to <code>this</code> after the <code>super</code> call:</p>
|
||||
<aside class="code-example container-fluid bg-ribbed-dark" data-example="breaking_change_super_this">
|
||||
<div class="row">
|
||||
<div class="col-md-6 coffeescript-input-column">
|
||||
<textarea class="coffeescript-input" id="breaking_change_super_this-coffee">class B extends A
|
||||
constructor: (arg) ->
|
||||
super arg
|
||||
@arg = arg
|
||||
</textarea>
|
||||
<pre class="placeholder-code"><span class="cm-keyword">class</span> <span class="cm-variable">B</span> <span class="cm-keyword">extends</span> <span class="cm-variable">A</span>
|
||||
<span class="cm-variable">constructor</span><span class="cm-punctuation">:</span> <span class="cm-punctuation">(</span><span class="cm-variable">arg</span><span class="cm-punctuation">)</span> <span class="cm-operator">-></span>
|
||||
<span class="cm-variable">super</span> <span class="cm-variable">arg</span>
|
||||
<span class="cm-property">@arg</span> <span class="cm-punctuation">=</span> <span class="cm-variable">arg</span>
|
||||
</pre>
|
||||
</div>
|
||||
<div class="col-md-6 javascript-output-column">
|
||||
<textarea class="javascript-output" id="breaking_change_super_this-js">var B;
|
||||
|
||||
B = class B extends A {
|
||||
constructor(arg) {
|
||||
super(arg);
|
||||
this.arg = arg;
|
||||
}
|
||||
|
||||
};
|
||||
</textarea>
|
||||
<pre class="placeholder-code"><span class="cm-keyword">var</span> <span class="cm-def">B</span>;
|
||||
|
||||
<span class="cm-variable">B</span> <span class="cm-operator">=</span> <span class="cm-keyword">class</span> <span class="cm-def">B</span> <span class="cm-keyword">extends</span> <span class="cm-variable">A</span> {
|
||||
<span class="cm-property">constructor</span>(<span class="cm-def">arg</span>) {
|
||||
<span class="cm-keyword">super</span>(<span class="cm-variable-2">arg</span>);
|
||||
<span class="cm-keyword">this</span>.<span class="cm-property">arg</span> <span class="cm-operator">=</span> <span class="cm-variable-2">arg</span>;
|
||||
}
|
||||
|
||||
};
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</aside>
|
||||
|
||||
</section>
|
||||
<section id="breaking-changes-super-extends">
|
||||
<h3><code>super</code> and <code>extends</code></h3>
|
||||
@@ -5390,10 +5498,34 @@ x = <span class="number">2</span> + <span class="number">2</span>
|
||||
</section>
|
||||
<section id="changelog">
|
||||
<h2>Changelog</h2>
|
||||
<div class="anchor" id="2.0.2"></div>
|
||||
<h2 class="header">
|
||||
<a href="https://github.com/jashkenas/coffeescript/compare/2.0.1...2.0.2">2.0.2</a>
|
||||
<span class="timestamp"> — <time datetime="2017-10-26">October 26, 2017</time></span>
|
||||
</h2><ul>
|
||||
<li><code>--transpile</code> now also applies to <code>require</code>d or <code>import</code>ed CoffeeScript files.</li>
|
||||
<li><code>--transpile</code> can be used with the REPL: <code>coffee --interactive --transpile</code>.</li>
|
||||
<li>Improvements to comments output that should now cover all of the <a href="https://flow.org/en/docs/types/comments/">Flow comment-based syntax</a>. Inline <code>###</code> comments near <a href="https://flow.org/en/docs/types/variables/">variable</a> initial assignments are now output in the variable declaration statement, and <code>###</code> comments near a <a href="https://flow.org/en/docs/types/generics/">class and method names</a> are now output where Flow expects them.</li>
|
||||
<li>Importing CoffeeScript keywords is now allowed, so long as they’re aliased: <code>import { and as andFn } from 'lib'</code>. (You could also do <code>import lib from 'lib'</code> and then reference <code>lib.and</code>.)</li>
|
||||
<li>Calls to functions named <code>get</code> and <code>set</code> no longer throw an error when given a bracketless object literal as an argument: <code>obj.set propertyName: propertyValue</code>.</li>
|
||||
<li>In the constructor of a derived class (a class that <code>extends</code> another class), you cannot call <code>super</code> with an argument that references <code>this</code>: <code>class Child extends Parent then constructor: (@arg) -> super(@arg)</code>. This isn’t allowed in JavaScript, and now the CoffeeScript compiler will throw an error. Instead, assign to <code>this</code> after calling <code>super</code>: <code>(arg) -> super(arg); @arg = arg</code>.</li>
|
||||
<li>Bugfix for incorrect output when backticked statements and hoisted expressions were both in the same class body. This allows a backticked line like <code>`field = 3`</code>, for people using the experimental <a href="https://github.com/tc39/proposal-class-fields">class fields</a> syntax, in the same class along with traditional class body expressions like <code>prop: 3</code> that CoffeeScript outputs as part of the class prototype.</li>
|
||||
<li>Bugfix for comments not output before a complex <code>?</code> operation, e.g. <code>@a ? b</code>.</li>
|
||||
<li>All tests now pass in Windows.</li>
|
||||
</ul>
|
||||
<div class="anchor" id="2.0.1"></div>
|
||||
<h2 class="header">
|
||||
<a href="https://github.com/jashkenas/coffeescript/compare/2.0.0...2.0.1">2.0.1</a>
|
||||
<span class="timestamp"> — <time datetime="2017-09-26">September 26, 2017</time></span>
|
||||
</h2><ul>
|
||||
<li><code>babel-core</code> is no longer listed in <code>package.json</code>, even as an <code>optionalDependency</code>, to avoid it being automatically installed for most users. If you wish to use <code>--transpile</code>, simply install <code>babel-core</code> manually. See <a href="#transpilation">Transpilation</a>.</li>
|
||||
<li><code>--transpile</code> now relies on Babel to find its options, i.e. the <code>.babelrc</code> 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 <code>.babelrc.js</code> file coming in Babel 7.</li>
|
||||
<li>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 <a href="https://github.com/tc39/proposal-class-fields">class fields proposal</a>, assuming your <a href="https://babeljs.io/docs/plugins/transform-class-properties/">transpiler supports it</a>.</li>
|
||||
</ul>
|
||||
<div class="anchor" id="2.0.0"></div>
|
||||
<h2 class="header">
|
||||
<a href="https://github.com/jashkenas/coffeescript/compare/2.0.0-beta5...2.0.0">2.0.0</a>
|
||||
<span class="timestamp"> — <time datetime="2017-09-17">September 17, 2017</time></span>
|
||||
<span class="timestamp"> — <time datetime="2017-09-18">September 18, 2017</time></span>
|
||||
</h2><ul>
|
||||
<li>Added <code>--transpile</code> flag or <code>transpile</code> Node API option to tell the CoffeeScript compiler to pipe its output through Babel before saving or returning it; see <a href="#transpilation">Transpilation</a>. Also changed the <code>-t</code> short flag to refer to <code>--transpile</code> instead of <code>--tokens</code>.</li>
|
||||
<li>Always populate source maps’ <code>sourcesContent</code> property.</li>
|
||||
@@ -5586,21 +5718,12 @@ x = <span class="number">2</span> + <span class="number">2</span>
|
||||
<a href="https://github.com/jashkenas/coffeescript/compare/1.10.0...1.11.0">1.11.0</a>
|
||||
<span class="timestamp"> — <time datetime="2016-09-24">September 24, 2016</time></span>
|
||||
</h2><ul>
|
||||
<li>
|
||||
<p>CoffeeScript now supports ES2015 <a href="#modules"><code>import</code> and <code>export</code> syntax</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Added the <code>-M, --inline-map</code> flag to the compiler, allowing you embed the source map directly into the output JavaScript, rather than as a separate file.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>A bunch of fixes for <code>yield</code>:</p>
|
||||
<li>CoffeeScript now supports ES2015 <a href="#modules"><code>import</code> and <code>export</code> syntax</a>.</li>
|
||||
<li>Added the <code>-M, --inline-map</code> flag to the compiler, allowing you embed the source map directly into the output JavaScript, rather than as a separate file.</li>
|
||||
<li>A bunch of fixes for <code>yield</code>:
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>yield return</code> can no longer mistakenly be used as an expression.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>yield</code> now mirrors <code>return</code> in that it can be used stand-alone as well as with expressions. Where you previously wrote <code>yield undefined</code>, you may now write simply <code>yield</code>. However, this means also inheriting the same syntax limitations that <code>return</code> has, so these examples no longer compile:</p>
|
||||
<blockquote class="uneditable-code-block"><pre><code>doubles = ->
|
||||
<li><code>yield return</code> can no longer mistakenly be used as an expression.</li>
|
||||
<li><code>yield</code> now mirrors <code>return</code> in that it can be used stand-alone as well as with expressions. Where you previously wrote <code>yield undefined</code>, you may now write simply <code>yield</code>. However, this means also inheriting the same syntax limitations that <code>return</code> has, so these examples no longer compile:<blockquote class="uneditable-code-block"><pre><code>doubles = ->
|
||||
yield for i in [1..3]
|
||||
i * 2
|
||||
six = ->
|
||||
@@ -5608,28 +5731,15 @@ six = ->
|
||||
2 * 3
|
||||
</code></pre>
|
||||
</blockquote></li>
|
||||
<li>
|
||||
<p>The JavaScript output is a bit nicer, with unnecessary parentheses and spaces, double indentation and double semicolons around <code>yield</code> no longer present.</p>
|
||||
</li>
|
||||
<li>The JavaScript output is a bit nicer, with unnecessary parentheses and spaces, double indentation and double semicolons around <code>yield</code> no longer present.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>&&=</code>, <code>||=</code>, <code>and=</code> and <code>or=</code> no longer accidentally allow a space before the equals sign.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Improved several error messages.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Just like <code>undefined</code> compiles to <code>void 0</code>, <code>NaN</code> now compiles into <code>0/0</code> and <code>Infinity</code> into <code>2e308</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Bugfix for renamed destructured parameters with defaults. <code>({a: b = 1}) -></code> no longer crashes the compiler.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Improved the internal representation of a CoffeeScript program. This is only noticeable to tools that use <code>CoffeeScript.tokens</code> or <code>CoffeeScript.nodes</code>. Such tools need to update to take account for changed or added tokens and nodes.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Several minor bug fixes, including:</p>
|
||||
<li><code>&&=</code>, <code>||=</code>, <code>and=</code> and <code>or=</code> no longer accidentally allow a space before the equals sign.</li>
|
||||
<li>Improved several error messages.</li>
|
||||
<li>Just like <code>undefined</code> compiles to <code>void 0</code>, <code>NaN</code> now compiles into <code>0/0</code> and <code>Infinity</code> into <code>2e308</code>.</li>
|
||||
<li>Bugfix for renamed destructured parameters with defaults. <code>({a: b = 1}) -></code> no longer crashes the compiler.</li>
|
||||
<li>Improved the internal representation of a CoffeeScript program. This is only noticeable to tools that use <code>CoffeeScript.tokens</code> or <code>CoffeeScript.nodes</code>. Such tools need to update to take account for changed or added tokens and nodes.</li>
|
||||
<li>Several minor bug fixes, including:
|
||||
<ul>
|
||||
<li>The caught error in <code>catch</code> blocks is no longer declared unnecessarily, and no longer mistakenly named <code>undefined</code> for <code>catch</code>-less <code>try</code> blocks.</li>
|
||||
<li>Unassignable parameter destructuring no longer crashes the compiler.</li>
|
||||
@@ -5646,14 +5756,9 @@ six = ->
|
||||
<a href="https://github.com/jashkenas/coffeescript/compare/1.9.3...1.10.0">1.10.0</a>
|
||||
<span class="timestamp"> — <time datetime="2015-09-03">September 3, 2015</time></span>
|
||||
</h2><ul>
|
||||
<li>
|
||||
<p>CoffeeScript now supports ES2015-style destructuring defaults.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>(offsetHeight: height) -></code> no longer compiles. That syntax was accidental and partly broken. Use <code>({offsetHeight: height}) -></code> instead. Object destructuring always requires braces.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Several minor bug fixes, including:</p>
|
||||
<li>CoffeeScript now supports ES2015-style destructuring defaults.</li>
|
||||
<li><code>(offsetHeight: height) -></code> no longer compiles. That syntax was accidental and partly broken. Use <code>({offsetHeight: height}) -></code> instead. Object destructuring always requires braces.</li>
|
||||
<li>Several minor bug fixes, including:
|
||||
<ul>
|
||||
<li>A bug where the REPL would sometimes report valid code as invalid, based on what you had typed earlier.</li>
|
||||
<li>A problem with multiple JS contexts in the jest test framework.</li>
|
||||
@@ -6078,7 +6183,7 @@ The <code>extends</code> keyword now functions identically to <code>goog.inherit
|
||||
|
||||
<script src="browser-compiler/coffeescript.js"></script>
|
||||
<script>
|
||||
(function(){window.location.origin||(window.location.origin=window.location.protocol+'//'+window.location.hostname),$(document).ready(function(){var a,b,c,d,e,f,g,h,i,j;if(i=function(){return $('.navbar-toggler, .sidebar').toggleClass('show')},$('[data-toggle="offcanvas"]').click(i),$('[data-action="sidebar-nav"]').click(function(a){return $('.navbar-toggler').is(':visible')&&(a.preventDefault(),i(),setTimeout(function(){return window.location=a.target.href},260)),gtag('event','sidebar_navigate',{event_category:'navigation',event_label:a.target.href.replace(window.location.origin,'')})}),$('body').scrollspy({target:'#contents',offset:Math.round($('main').css('padding-top').replace('px',''))}),e=function(a){return $('#contents a.active[href!=\''+a+'\']').removeClass('show')},$(window).on('activate.bs.scrollspy',function(a,b){var c;if($('#contents a.active[href!=\''+b.relatedTarget+'\']').removeClass('show'),c=$('#contents a[href=\''+b.relatedTarget+'\']'),c.prop('href')!==window.location.origin+'/#try')return window.history.pushState({},c.text(),c.prop('href')),gtag('config',GA_TRACKING_ID,{page_path:c.prop('href').replace(window.location.origin,'')})}),h=[],c=[],g=200,$('textarea').each(function(a){return h[a]=this,$(this).data('index',a)}),d=function(a){var b,d,e,f;if(d=a.data('index'),e=a.hasClass('javascript-output')?'javascript':'coffeescript',c[d]=b=CodeMirror.fromTextArea(a[0],{mode:e,theme:'twilight',indentUnit:2,tabSize:2,lineWrapping:!0,lineNumbers:!1,inputStyle:'contenteditable',readOnly:'coffeescript'!==e,viewportMargin:2e308}),'coffeescript'===e)return f=null,b.on('change',function(){return clearTimeout(f),f=setTimeout(function(){var e,f,h,i,j;h=Date.now();try{if(e=b.getValue(),0===d&&$('#try').hasClass('show')){i='try:'+encodeURIComponent(e),window.history.pushState({},'CoffeeScript',location.href.split('#')[0]+'#'+i);try{null!=window.localStorage&&window.localStorage.setItem('tryCoffeeScriptCode',e)}catch(a){f=a}}j=CoffeeScript.compile(e,{bare:!0}),g=Math.max(200,Date.now()-h)}catch(a){f=a,j=''+f}return c[d+1].setValue(j),gtag('event','edit_code',{event_category:'engagement',event_label:a.closest('[data-example]').data('example')})},g)}),b.addKeyMap({Tab:function Tab(a){return a.somethingSelected()?a.indentSelection('add'):/^\t/m.test(a.getValue())?a.execCommand('insertTab'):a.execCommand('insertSoftTab')},"Shift-Tab":function ShiftTab(a){return a.indentSelection('subtract')},Enter:function Enter(a){return a.options.indentWithTabs=/^\t/m.test(a.getValue()),a.execCommand('newlineAndIndent')}})},$('.placeholder-code').one('mouseover',function(){var a,b;return b=$(this).prev('textarea'),$(this).remove(),d(b),a=$(b.parent().siblings()[0]),a.children('.placeholder-code').remove(),d($(a.children('textarea')[0]))}),f=function(){return d($('#try-coffeescript-coffee')),d($('#try-coffeescript-js'))},$('[data-action="run-code-example"]').click(function(){var a,b,d;return d=$(this).data('run'),a=$('#'+$(this).data('example')+'-js').data('index'),b=null==c[a]?$(h[a]).val():c[a].getValue(),!0!==d&&(b=b+'\nalert('+unescape(d)+');'),eval(b),gtag('event','run_code',{event_category:'engagement',event_label:$(this).closest('[data-example]').data('example')})}),a=function(){return window.history.pushState('',document.title,window.location.pathname)},$(window).on('hashchange',function(){if(''===window.location.hash)return a()}),j=function(){var b,d=0<arguments.length&&void 0!==arguments[0]&&arguments[0];if(0===$('#try .CodeMirror').length&&f(),d&&null!=window.localStorage)try{b=window.localStorage.getItem('tryCoffeeScriptCode'),null!=b&&c[0].setValue(b)}catch(a){}return($('#try, #try-link').toggleClass('show'),!$('#try').hasClass('show'))?setTimeout(a,200):void 0},b=function(){return $('#try, #try-link').removeClass('show'),window.history.pushState('',document.title,window.location.pathname)},$('[data-toggle="try"]').click(j),$('[data-close="try"]').click(b),null!=window.location.hash){if('#try'===window.location.hash)return j(!0);if(0===window.location.hash.indexOf('#try'))return 0===$('#try .CodeMirror').length&&f(),c[0].setValue(decodeURIComponent(window.location.hash.slice(5))),j();if(''===window.location.hash)return a();if(e(window.location.hash),1<window.location.hash.length)return document.getElementById(window.location.hash.slice(1).replace(/try:.*/,'')).scrollIntoView()}})}).call(this);
|
||||
(function(){window.location.origin||(window.location.origin=window.location.protocol+'//'+window.location.hostname),$(document).ready(function(){var a,b,c,d,e,f,g,h,i,j,k,l;if(k=function(){return $('.navbar-toggler, .sidebar').toggleClass('show')},$('[data-toggle="offcanvas"]').click(k),$('[data-action="sidebar-nav"]').click(function(a){return $('.navbar-toggler').is(':visible')&&(a.preventDefault(),k(),setTimeout(function(){return window.location=a.target.href},260)),gtag('event','sidebar_navigate',{event_category:'navigation',event_label:a.target.href.replace(window.location.origin,'')})}),$('body').scrollspy({target:'#contents',offset:Math.round($('main').css('padding-top').replace('px',''))}),e=function(a){return $('#contents a.active[href!=\''+a+'\']').removeClass('show')},$(window).on('activate.bs.scrollspy',function(a,b){var c;if($('#contents a.active[href!=\''+b.relatedTarget+'\']').removeClass('show'),c=$('#contents a[href=\''+b.relatedTarget+'\']'),c.prop('href')!==window.location.origin+'/#try')return i(c.prop('href')),gtag('config',GA_TRACKING_ID,{page_path:c.prop('href').replace(window.location.origin,'')})}),j=[],c=[],g=200,$('textarea').each(function(a){return j[a]=this,$(this).data('index',a)}),d=function(a){var b,d,e,f;if(d=a.data('index'),e=a.hasClass('javascript-output')?'javascript':'coffeescript',c[d]=b=CodeMirror.fromTextArea(a[0],{mode:e,theme:'twilight',indentUnit:2,tabSize:2,lineWrapping:!0,lineNumbers:!1,inputStyle:'contenteditable',readOnly:'coffeescript'!==e,viewportMargin:2e308}),'coffeescript'===e)return f=null,b.on('change',function(){return clearTimeout(f),f=setTimeout(function(){var e,f,h,j,k;h=Date.now();try{if(e=b.getValue(),0===d&&$('#try').hasClass('show')){$('#try').hasClass('show')&&(j='try:'+encodeURIComponent(e),i(window.location.href.split('#')[0]+'#'+j));try{null!=window.localStorage&&window.localStorage.setItem('tryCoffeeScriptCode',e)}catch(a){f=a}}k=CoffeeScript.compile(e,{bare:!0}),g=Math.max(200,Date.now()-h)}catch(a){f=a,k=''+f}return c[d+1].setValue(k),gtag('event','edit_code',{event_category:'engagement',event_label:a.closest('[data-example]').data('example')})},g)}),b.addKeyMap({Tab:function Tab(a){return a.somethingSelected()?a.indentSelection('add'):/^\t/m.test(a.getValue())?a.execCommand('insertTab'):a.execCommand('insertSoftTab')},"Shift-Tab":function ShiftTab(a){return a.indentSelection('subtract')},Enter:function Enter(a){return a.options.indentWithTabs=/^\t/m.test(a.getValue()),a.execCommand('newlineAndIndent')}})},$('.placeholder-code').one('mouseover',function(){var a,b;return b=$(this).prev('textarea'),$(this).remove(),d(b),a=$(b.parent().siblings()[0]),a.children('.placeholder-code').remove(),d($(a.children('textarea')[0]))}),f=function(){return d($('#try-coffeescript-coffee')),d($('#try-coffeescript-js'))},$('[data-action="run-code-example"]').click(function(){var a,b,d;return d=$(this).data('run'),a=$('#'+$(this).data('example')+'-js').data('index'),b=null==c[a]?$(j[a]).val():c[a].getValue(),!0!==d&&(b=b+'\nalert('+unescape(d)+');'),eval(b),gtag('event','run_code',{event_category:'engagement',event_label:$(this).closest('[data-example]').data('example')})}),h=null,l=function(b){var d,e;if($('#try, #try-link').toggleClass('show'),!$('#try').hasClass('show'))return h?i(h):a();if(window.location.hash&&(h=window.location.hash),0===$('#try .CodeMirror').length&&f(),b&&null!=window.localStorage)try{return d=window.localStorage.getItem('tryCoffeeScriptCode'),null==d?i('#try'):c[0].setValue(d)}catch(a){return e=a,i('#try')}else return i('#try')},b=function(){return $('#try, #try-link').removeClass('show'),h?i(h):a()},$('[data-toggle="try"]').click(function(a){return a.preventDefault(),l(!0)}),$('[data-close="try"]').click(b),a=function(){return window.history.replaceState({},document.title,window.location.pathname)},i=function(a){return 0===(null==a?void 0:a.indexOf('#'))&&(a=''+window.location.pathname+a),window.history.replaceState({},document.title,a||'')},$(window).on('hashchange',function(){if(''===window.location.hash)return a()}),null!=window.location.hash){if('#try'===window.location.hash)return l(!0);if(0===window.location.hash.indexOf('#try'))return 0===$('#try .CodeMirror').length&&f(),c[0].setValue(decodeURIComponent(window.location.hash.slice(5))),l(!1);if(''===window.location.hash)return a();if(e(window.location.hash),1<window.location.hash.length)return document.getElementById(window.location.hash.slice(1).replace(/try:.*/,'')).scrollIntoView()}})}).call(this);
|
||||
</script>
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-106156830-1"></script>
|
||||
<script>
|
||||
|
||||
@@ -3529,6 +3529,30 @@ test "#4591: super.x.y, super['x'].y", ->
|
||||
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
|
||||
|
||||
</script>
|
||||
<script type="text/x-coffeescript" class="test" id="cluster">
|
||||
# Cluster Module
|
||||
@@ -4525,6 +4549,153 @@ test "Flow comment-based syntax support", ->
|
||||
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;
|
||||
})();
|
||||
'''
|
||||
|
||||
</script>
|
||||
<script type="text/x-coffeescript" class="test" id="compilation">
|
||||
# Compilation
|
||||
@@ -4696,6 +4867,10 @@ test "using transpile from the Node API requires an object", ->
|
||||
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()"
|
||||
|
||||
</script>
|
||||
<script type="text/x-coffeescript" class="test" id="comprehensions">
|
||||
# Comprehensions
|
||||
@@ -6582,7 +6757,7 @@ if require?
|
||||
|
||||
try
|
||||
assertErrorFormat """
|
||||
require '#{tempFile}'
|
||||
require '#{tempFile.replace /\\/g, '\\\\'}'
|
||||
""",
|
||||
"""
|
||||
#{fs.realpathSync tempFile}:1:15: error: unexpected in
|
||||
@@ -7856,6 +8031,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
|
||||
@@ -9778,6 +9967,12 @@ 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
|
||||
|
||||
@@ -9797,6 +9992,11 @@ 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
|
||||
|
||||
</script>
|
||||
<script type="text/x-coffeescript" class="test" id="functions">
|
||||
@@ -11051,13 +11251,17 @@ test "heregex interpolation", ->
|
||||
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'
|
||||
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'
|
||||
@@ -11067,18 +11271,18 @@ initialSpaceExtraArgsScript = require.resolve './importing/shebang_initial_space
|
||||
test "parse arguments for shebang scripts correctly (on unix 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 'coffee', [shebangScript, '--'], spawnOptions
|
||||
stderr = result.stderr.toString()
|
||||
arrayEq JSON.parse(result.stdout), ['coffee', shebangScript]
|
||||
ok stderr.match /^coffee was invoked with '--'/m
|
||||
@@ -11086,7 +11290,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 'coffee', ['-b', shebangScript, '--'], spawnOptions
|
||||
stderr = result.stderr.toString()
|
||||
arrayEq JSON.parse(result.stdout), ['coffee', shebangScript]
|
||||
ok stderr.match /^coffee was invoked with '--'/m
|
||||
@@ -11095,16 +11299,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})
|
||||
'coffee', ['-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})
|
||||
'coffee', ['--', initialSpaceScript, 'arg'], spawnOptions)
|
||||
expectedArgs = ['coffee', initialSpaceScript, 'arg']
|
||||
realArgs = JSON.parse result.stdout
|
||||
arrayEq expectedArgs, realArgs
|
||||
@@ -11112,7 +11316,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 'coffee', [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
|
||||
@@ -11123,14 +11327,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 'coffee', [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})
|
||||
'coffee', [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
|
||||
@@ -11143,7 +11347,7 @@ test "warn about non-portable shebang lines", ->
|
||||
|
||||
test "both warnings will be shown at once", ->
|
||||
result = spawnSync(
|
||||
'coffee', [initialSpaceExtraArgsScript, '--', 'arg'], {env: patchedEnv})
|
||||
'coffee', [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
|
||||
@@ -12640,7 +12844,6 @@ test "export default named member, within an object", ->
|
||||
bar
|
||||
};"""
|
||||
|
||||
|
||||
# Import and export in the same statement
|
||||
|
||||
test "export an entire module's contents", ->
|
||||
@@ -12664,18 +12867,21 @@ test "export as aliases members imported from another module", ->
|
||||
} from 'lib';"""
|
||||
|
||||
test "export list can contain CoffeeScript keywords", ->
|
||||
eqJS "export { unless } from 'lib'",
|
||||
eqJS "export { unless, and } from 'lib'",
|
||||
"""
|
||||
export {
|
||||
unless
|
||||
unless,
|
||||
and
|
||||
} from 'lib';"""
|
||||
|
||||
test "export list can contain CoffeeScript keywords when aliasing", ->
|
||||
eqJS "export { when as bar, baz as unless } from 'lib'",
|
||||
eqJS "export { when as bar, baz as unless, and as foo, booze as not } from 'lib'",
|
||||
"""
|
||||
export {
|
||||
when as bar,
|
||||
baz as unless
|
||||
baz as unless,
|
||||
and as foo,
|
||||
booze as not
|
||||
} from 'lib';"""
|
||||
|
||||
|
||||
@@ -12769,11 +12975,12 @@ test "`as` can be used as an alias name", ->
|
||||
|
||||
test "CoffeeScript keywords can be used as imported names in import lists", ->
|
||||
eqJS """
|
||||
import { unless as bar } from 'lib'
|
||||
import { unless as bar, and as computedAnd } from 'lib'
|
||||
bar.barMethod()""",
|
||||
"""
|
||||
import {
|
||||
unless as bar
|
||||
unless as bar,
|
||||
and as computedAnd
|
||||
} from 'lib';
|
||||
|
||||
bar.barMethod();"""
|
||||
@@ -15005,6 +15212,10 @@ testRepl "#4604: wraps an async function", (input, output) ->
|
||||
eq '33', output.lastWrite()
|
||||
, 20
|
||||
|
||||
testRepl "transpile REPL", (input, output) ->
|
||||
input.emitLine 'require("./test/importing/transpile_import").getSep()'
|
||||
eq "'#{path.sep.replace '\\', '\\\\'}'", output.lastWrite()
|
||||
|
||||
process.on 'exit', ->
|
||||
try
|
||||
fs.unlinkSync historyFile
|
||||
|
||||
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
|
||||
@@ -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,28 @@
|
||||
## Changelog
|
||||
|
||||
```
|
||||
releaseHeader('2017-09-17', '2.0.0', '2.0.0-beta5')
|
||||
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 +205,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 +215,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 +222,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 +237,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,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
|
||||
```
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
@@ -8,8 +8,10 @@
|
||||
<%= include('sidebar.html') %>
|
||||
</nav>
|
||||
<main class="main col-lg-9 ml-auto">
|
||||
<header class="title-logo d-none d-lg-block">
|
||||
<%= include('logo.svg') %>
|
||||
<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>
|
||||
|
||||
@@ -7,12 +7,18 @@
|
||||
/* 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: 90%; /* 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;
|
||||
}
|
||||
div.CodeMirror-cursor {
|
||||
|
||||
@@ -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>
|
||||
<% } %>
|
||||
|
||||
@@ -33,8 +33,8 @@ $(document).ready ->
|
||||
$("#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 +74,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 +136,46 @@ $(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
|
||||
|
||||
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 +183,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
|
||||
|
||||
@@ -160,16 +160,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 +195,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 {
|
||||
@@ -219,13 +227,18 @@ h3, h4, h2 time {
|
||||
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 {
|
||||
font-family: 'Roboto Mono';
|
||||
font-weight: 400;
|
||||
}
|
||||
code, a > code {
|
||||
background-color: #f8f3f0;
|
||||
padding: 0.2rem 0.4rem;
|
||||
}
|
||||
code {
|
||||
color: #2f2625;
|
||||
@@ -270,6 +283,10 @@ textarea {
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.CodeMirror pre, pre.placeholder-code {
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
.CodeMirror,
|
||||
.placeholder-code {
|
||||
/* https://codemirror.net/demo/resize.html */
|
||||
|
||||
@@ -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,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.0.2
|
||||
(function() {
|
||||
// This **Browser** compatibility layer extends core CoffeeScript functions
|
||||
// to make things work smoothly when compiling code directly in the browser.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.0.2
|
||||
(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.0.2
|
||||
(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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.0.2
|
||||
(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) {
|
||||
@@ -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.0.2
|
||||
(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
|
||||
@@ -389,7 +389,8 @@
|
||||
function() {
|
||||
return new Code($2,
|
||||
$5,
|
||||
$4);
|
||||
$4,
|
||||
LOC(1)(new Literal($1)));
|
||||
}),
|
||||
o('FuncGlyph Block',
|
||||
function() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.0.2
|
||||
(function() {
|
||||
// This file contains the common helper functions that we'd like to share among
|
||||
// the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.0.2
|
||||
(function() {
|
||||
// Node.js Implementation
|
||||
var CoffeeScript, ext, fn, fs, helpers, i, len, path, ref, universalCompile, vm,
|
||||
@@ -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);
|
||||
@@ -147,19 +149,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
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.0.2
|
||||
(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,
|
||||
@@ -111,7 +111,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, ref2, ref3, ref4, ref5, ref6, ref7, ref8, regExSuper, regex, sup, tag, tagToken;
|
||||
inCSXTag = this.atCSXTag();
|
||||
regex = inCSXTag ? CSX_ATTRIBUTE : IDENTIFIER;
|
||||
if (!(match = regex.exec(this.chunk))) {
|
||||
@@ -132,19 +132,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 +165,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 +199,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[this.tokens.length - 2][0] !== '.') {
|
||||
this.error(`'${prev[1]}' cannot be used as a keyword, or as a function call without parentheses`, prev[2]);
|
||||
} else {
|
||||
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 (((ref8 = prev[0]) === '@' || ref8 === 'THIS') && prevprev && prevprev.spaced && /^[gs]et$/.test(prevprev[1]) && this.tokens[this.tokens.length - 3][0] !== '.') {
|
||||
this.error(`'${prevprev[1]}' cannot be used as a keyword, or as a function call without parentheses`, prevprev[2]);
|
||||
}
|
||||
}
|
||||
@@ -204,7 +213,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];
|
||||
@@ -1275,10 +1284,14 @@
|
||||
}
|
||||
|
||||
// Peek at the last value in the token stream.
|
||||
value() {
|
||||
var ref, token;
|
||||
value(useOrigin = false) {
|
||||
var ref, ref1, token;
|
||||
ref = this.tokens, token = ref[ref.length - 1];
|
||||
return token != null ? token[1] : void 0;
|
||||
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.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.0.2
|
||||
(function() {
|
||||
// `nodes.coffee` contains all of the node classes for the syntax tree. Most
|
||||
// nodes are created as the result of actions in the [grammar](grammar.html),
|
||||
@@ -237,6 +237,9 @@
|
||||
// `compileToFragments` method has logic for outputting comments.
|
||||
unshiftCommentFragment(commentFragment);
|
||||
} else {
|
||||
if (fragments.length === 0) {
|
||||
fragments.push(this.makeCode(''));
|
||||
}
|
||||
if (commentFragment.unshift) {
|
||||
if ((base1 = fragments[0]).precedingComments == null) {
|
||||
base1.precedingComments = [];
|
||||
@@ -701,17 +704,18 @@
|
||||
ref1 = this.expressions;
|
||||
for (index = j = 0, len1 = ref1.length; j < len1; index = ++j) {
|
||||
node = ref1[index];
|
||||
node = node.unwrapAll();
|
||||
if (node.hoisted) {
|
||||
// This is a hoisted expression.
|
||||
// We want to compile this and ignore the result.
|
||||
node.compileToFragments(o);
|
||||
continue;
|
||||
}
|
||||
node = node.unfoldSoak(o) || node;
|
||||
if (node instanceof Block) {
|
||||
// This is a nested block. We don’t do anything special here like
|
||||
// enclose it in a new scope; we just compile the statements in this
|
||||
// block along with our own.
|
||||
compiledNodes.push(node.compileNode(o));
|
||||
} else if (node.hoisted) {
|
||||
// This is a hoisted expression.
|
||||
// We want to compile this and ignore the result.
|
||||
node.compileToFragments(o);
|
||||
} else if (top) {
|
||||
node.front = true;
|
||||
fragments = node.compileToFragments(o);
|
||||
@@ -774,7 +778,7 @@
|
||||
// Compile the expressions body for the contents of a function, with
|
||||
// declarations of all inner variables pushed up to the top.
|
||||
compileWithDeclarations(o) {
|
||||
var assigns, declars, exp, fragments, i, j, len1, post, ref1, rest, scope, spaced;
|
||||
var assigns, declaredVariable, declaredVariables, declaredVariablesIndex, declars, exp, fragments, i, j, k, len1, len2, post, ref1, rest, scope, spaced;
|
||||
fragments = [];
|
||||
post = [];
|
||||
ref1 = this.expressions;
|
||||
@@ -805,7 +809,17 @@
|
||||
}
|
||||
fragments.push(this.makeCode(`${this.tab}var `));
|
||||
if (declars) {
|
||||
fragments.push(this.makeCode(scope.declaredVariables().join(', ')));
|
||||
declaredVariables = scope.declaredVariables();
|
||||
for (declaredVariablesIndex = k = 0, len2 = declaredVariables.length; k < len2; declaredVariablesIndex = ++k) {
|
||||
declaredVariable = declaredVariables[declaredVariablesIndex];
|
||||
fragments.push(this.makeCode(declaredVariable));
|
||||
if (Object.prototype.hasOwnProperty.call(o.scope.comments, declaredVariable)) {
|
||||
fragments.push(...o.scope.comments[declaredVariable]);
|
||||
}
|
||||
if (declaredVariablesIndex !== declaredVariables.length - 1) {
|
||||
fragments.push(this.makeCode(', '));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (assigns) {
|
||||
if (declars) {
|
||||
@@ -1252,6 +1266,8 @@
|
||||
this[tag] = true;
|
||||
}
|
||||
this.isDefaultValue = isDefaultValue;
|
||||
// If this is a `@foo =` assignment, if there are comments on `@` move them
|
||||
// to be on `foo`.
|
||||
if (((ref1 = this.base) != null ? ref1.comments : void 0) && this.base instanceof ThisLiteral && (((ref2 = this.properties[0]) != null ? ref2.name : void 0) != null)) {
|
||||
moveComments(this.base, this.properties[0].name);
|
||||
}
|
||||
@@ -1554,6 +1570,10 @@
|
||||
this.variable.error("literal is not a function");
|
||||
}
|
||||
this.csx = this.variable.base instanceof CSXTag;
|
||||
// `@variable` never gets output as a result of this node getting created as
|
||||
// part of `RegexWithInterpolations`, so for that case move any comments to
|
||||
// the `args` property that gets passed into `RegexWithInterpolations` via
|
||||
// the grammar.
|
||||
if (((ref1 = this.variable.base) != null ? ref1.value : void 0) === 'RegExp' && this.args.length !== 0) {
|
||||
moveComments(this.variable, this.args[0]);
|
||||
}
|
||||
@@ -2501,7 +2521,7 @@
|
||||
}
|
||||
|
||||
compileClassDeclaration(o) {
|
||||
var ref1, result;
|
||||
var ref1, ref2, result;
|
||||
if (this.externalCtor || this.boundMethods.length) {
|
||||
if (this.ctor == null) {
|
||||
this.ctor = this.makeDefaultConstructor();
|
||||
@@ -2517,7 +2537,13 @@
|
||||
result = [];
|
||||
result.push(this.makeCode("class "));
|
||||
if (this.name) {
|
||||
result.push(this.makeCode(`${this.name} `));
|
||||
result.push(this.makeCode(this.name));
|
||||
}
|
||||
if (((ref2 = this.variable) != null ? ref2.comments : void 0) != null) {
|
||||
this.compileCommentFragments(o, this.variable, result);
|
||||
}
|
||||
if (this.name) {
|
||||
result.push(this.makeCode(' '));
|
||||
}
|
||||
if (this.parent) {
|
||||
result.push(this.makeCode('extends '), ...this.parent.compileToFragments(o), this.makeCode(' '));
|
||||
@@ -2630,10 +2656,23 @@
|
||||
|
||||
// Add an expression to the class initializer
|
||||
|
||||
// NOTE Currently, only methods and static methods are valid in ES class initializers.
|
||||
// When additional expressions become valid, this method should be updated to handle them.
|
||||
// This is the key method for determining whether an expression in a class
|
||||
// body should appear in the initializer or the executable body. If the given
|
||||
// `node` is valid in a class body the method will return a (new, modified,
|
||||
// or identical) node for inclusion in the class initializer, otherwise
|
||||
// nothing will be returned and the node will appear in the executable body.
|
||||
|
||||
// At time of writing, only methods (instance and static) are valid in ES
|
||||
// class initializers. As new ES class features (such as class fields) reach
|
||||
// Stage 4, this method will need to be updated to support them. We
|
||||
// additionally allow `PassthroughLiteral`s (backticked expressions) in the
|
||||
// initializer as an escape hatch for ES features that are not implemented
|
||||
// (e.g. getters and setters defined via the `get` and `set` keywords as
|
||||
// opposed to the `Object.defineProperty` method).
|
||||
addInitializerExpression(node) {
|
||||
if (this.validInitializerMethod(node)) {
|
||||
if (node.unwrapAll() instanceof PassthroughLiteral) {
|
||||
return node;
|
||||
} else if (this.validInitializerMethod(node)) {
|
||||
return this.addInitializerMethod(node);
|
||||
} else {
|
||||
return null;
|
||||
@@ -3188,7 +3227,7 @@
|
||||
this.variable.error(`'${this.variable.compile(o)}' can't be assigned`);
|
||||
}
|
||||
varBase.eachName((name) => {
|
||||
var message;
|
||||
var commentFragments, commentsNode, message;
|
||||
if (typeof name.hasProperties === "function" ? name.hasProperties() : void 0) {
|
||||
return;
|
||||
}
|
||||
@@ -3196,14 +3235,29 @@
|
||||
if (message) {
|
||||
name.error(message);
|
||||
}
|
||||
// `moduleDeclaration` can be `'import'` or `'export'`
|
||||
// `moduleDeclaration` can be `'import'` or `'export'`.
|
||||
this.checkAssignability(o, name);
|
||||
if (this.moduleDeclaration) {
|
||||
return o.scope.add(name.value, this.moduleDeclaration);
|
||||
} else if (this.param) {
|
||||
return o.scope.add(name.value, this.param === 'alwaysDeclare' ? 'var' : 'param');
|
||||
} else {
|
||||
return o.scope.find(name.value);
|
||||
o.scope.find(name.value);
|
||||
// If this assignment identifier has one or more herecomments
|
||||
// attached, output them as part of the declarations line (unless
|
||||
// other herecomments are already staged there) for compatibility
|
||||
// with Flow typing. Don’t do this if this assignment is for a
|
||||
// class, e.g. `ClassName = class ClassName {`, as Flow requires
|
||||
// the comment to be between the class name and the `{`.
|
||||
if (name.comments && !o.scope.comments[name.value] && !(this.value instanceof Class) && name.comments.every(function(comment) {
|
||||
return comment.here && !comment.multiline;
|
||||
})) {
|
||||
commentsNode = new IdentifierLiteral(name.value);
|
||||
commentsNode.comments = name.comments;
|
||||
commentFragments = [];
|
||||
this.compileCommentFragments(o, commentsNode, commentFragments);
|
||||
return o.scope.comments[name.value] = commentFragments;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -3636,10 +3690,11 @@
|
||||
// has no *children* -- they're within the inner scope.
|
||||
exports.Code = Code = (function() {
|
||||
class Code extends Base {
|
||||
constructor(params, body, funcGlyph) {
|
||||
constructor(params, body, funcGlyph, paramStart) {
|
||||
var ref1;
|
||||
super();
|
||||
this.funcGlyph = funcGlyph;
|
||||
this.paramStart = paramStart;
|
||||
this.params = params || [];
|
||||
this.body = body || new Block;
|
||||
this.bound = ((ref1 = this.funcGlyph) != null ? ref1.glyph : void 0) === '=>';
|
||||
@@ -3674,7 +3729,7 @@
|
||||
// parameters after the splat, they are declared via expressions in the
|
||||
// function body.
|
||||
compileNode(o) {
|
||||
var answer, body, boundMethodCheck, comment, condition, exprs, generatedVariables, haveBodyParam, haveSplatParam, i, ifTrue, j, k, l, len1, len2, len3, m, methodScope, modifiers, name, param, paramNames, paramToAddToScope, params, paramsAfterSplat, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, scopeVariablesCount, signature, splatParamName, thisAssignments, wasEmpty;
|
||||
var answer, body, boundMethodCheck, comment, condition, exprs, generatedVariables, haveBodyParam, haveSplatParam, i, ifTrue, j, k, l, len1, len2, len3, m, methodScope, modifiers, name, param, paramNames, paramToAddToScope, params, paramsAfterSplat, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, scopeVariablesCount, signature, splatParamName, thisAssignments, wasEmpty;
|
||||
if (this.ctor) {
|
||||
if (this.isAsync) {
|
||||
this.name.error('Class constructor may not be async');
|
||||
@@ -3859,7 +3914,9 @@
|
||||
exprs.unshift(new Assign(new Value(new Arr([
|
||||
new Splat(new IdentifierLiteral(splatParamName)),
|
||||
...((function() {
|
||||
var k, len2, results;
|
||||
var k,
|
||||
len2,
|
||||
results;
|
||||
results = [];
|
||||
for (k = 0, len2 = paramsAfterSplat.length; k < len2; k++) {
|
||||
param = paramsAfterSplat[k];
|
||||
@@ -3896,6 +3953,11 @@
|
||||
modifiers.push('*');
|
||||
}
|
||||
signature = [this.makeCode('(')];
|
||||
// Block comments between a function name and `(` get output between
|
||||
// `function` and `(`.
|
||||
if (((ref6 = this.paramStart) != null ? ref6.comments : void 0) != null) {
|
||||
this.compileCommentFragments(o, this.paramStart, signature);
|
||||
}
|
||||
for (i = k = 0, len2 = params.length; k < len2; i = ++k) {
|
||||
param = params[i];
|
||||
if (i !== 0) {
|
||||
@@ -3916,10 +3978,10 @@
|
||||
}
|
||||
signature.push(this.makeCode(')'));
|
||||
// Block comments between `)` and `->`/`=>` get output between `)` and `{`.
|
||||
if (((ref6 = this.funcGlyph) != null ? ref6.comments : void 0) != null) {
|
||||
ref7 = this.funcGlyph.comments;
|
||||
for (l = 0, len3 = ref7.length; l < len3; l++) {
|
||||
comment = ref7[l];
|
||||
if (((ref7 = this.funcGlyph) != null ? ref7.comments : void 0) != null) {
|
||||
ref8 = this.funcGlyph.comments;
|
||||
for (l = 0, len3 = ref8.length; l < len3; l++) {
|
||||
comment = ref8[l];
|
||||
comment.unshift = false;
|
||||
}
|
||||
this.compileCommentFragments(o, this.funcGlyph, signature);
|
||||
@@ -4022,13 +4084,23 @@
|
||||
return seenSuper;
|
||||
}
|
||||
|
||||
// Find all super calls in the given context node
|
||||
// Returns `true` if `iterator` is called
|
||||
// Find all super calls in the given context node;
|
||||
// returns `true` if `iterator` is called.
|
||||
eachSuperCall(context, iterator) {
|
||||
var seenSuper;
|
||||
seenSuper = false;
|
||||
context.traverseChildren(true, (child) => {
|
||||
if (child instanceof SuperCall) {
|
||||
// `super` in a constructor (the only `super` without an accessor)
|
||||
// cannot be given an argument with a reference to `this`, as that would
|
||||
// be referencing `this` before calling `super`.
|
||||
if (!child.variable.accessor) {
|
||||
Block.wrap(child.args).traverseChildren(true, (node) => {
|
||||
if (node.this) {
|
||||
return node.error("Can't call super with @params in derived class constructors");
|
||||
}
|
||||
});
|
||||
}
|
||||
seenSuper = true;
|
||||
iterator(child);
|
||||
} else if (child instanceof ThisLiteral && this.ctor === 'derived' && !seenSuper) {
|
||||
@@ -4813,8 +4885,8 @@
|
||||
this.expression = expression1;
|
||||
this.comparisonTarget = onlyNotUndefined ? 'undefined' : 'null';
|
||||
salvagedComments = [];
|
||||
this.expression.eachChild(function(child) {
|
||||
var comment, j, k, len1, len2, ref1, ref2, ref3;
|
||||
this.expression.traverseChildren(true, function(child) {
|
||||
var comment, j, len1, ref1;
|
||||
if (child.comments) {
|
||||
ref1 = child.comments;
|
||||
for (j = 0, len1 = ref1.length; j < len1; j++) {
|
||||
@@ -4823,17 +4895,7 @@
|
||||
salvagedComments.push(comment);
|
||||
}
|
||||
}
|
||||
delete child.comments;
|
||||
}
|
||||
if ((ref2 = child.name) != null ? ref2.comments : void 0) {
|
||||
ref3 = child.name.comments;
|
||||
for (k = 0, len2 = ref3.length; k < len2; k++) {
|
||||
comment = ref3[k];
|
||||
if (indexOf.call(salvagedComments, comment) < 0) {
|
||||
salvagedComments.push(comment);
|
||||
}
|
||||
}
|
||||
return delete child.name.comments;
|
||||
return delete child.comments;
|
||||
}
|
||||
});
|
||||
attachCommentsToNode(salvagedComments, this);
|
||||
@@ -4893,14 +4955,22 @@
|
||||
}
|
||||
|
||||
compileNode(o) {
|
||||
var bare, expr, fragments;
|
||||
var bare, expr, fragments, ref1, shouldWrapComment;
|
||||
expr = this.body.unwrap();
|
||||
if (expr instanceof Value && expr.isAtomic() && !this.csxAttribute) {
|
||||
// If these parentheses are wrapping an `IdentifierLiteral` followed by a
|
||||
// block comment, output the parentheses (or put another way, don’t optimize
|
||||
// away these redundant parentheses). This is because Flow requires
|
||||
// parentheses in certain circumstances to distinguish identifiers followed
|
||||
// by comment-based type annotations from JavaScript labels.
|
||||
shouldWrapComment = (ref1 = expr.comments) != null ? ref1.some(function(comment) {
|
||||
return comment.here && !comment.unshift && !comment.newLine;
|
||||
}) : void 0;
|
||||
if (expr instanceof Value && expr.isAtomic() && !this.csxAttribute && !shouldWrapComment) {
|
||||
expr.front = this.front;
|
||||
return expr.compileToFragments(o);
|
||||
}
|
||||
fragments = expr.compileToFragments(o, LEVEL_PAREN);
|
||||
bare = o.level < LEVEL_OP && (expr instanceof Op || expr.unwrap() instanceof Call || (expr instanceof For && expr.returns)) && (o.level < LEVEL_COND || fragments.length <= 3);
|
||||
bare = o.level < LEVEL_OP && !shouldWrapComment && (expr instanceof Op || expr.unwrap() instanceof Call || (expr instanceof For && expr.returns)) && (o.level < LEVEL_COND || fragments.length <= 3);
|
||||
if (this.csxAttribute) {
|
||||
return this.wrapInBraces(fragments);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.0.2
|
||||
(function() {
|
||||
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments, repeat,
|
||||
slice = [].slice;
|
||||
|
||||
@@ -267,7 +267,8 @@ break;
|
||||
case 86:
|
||||
this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Code($$[$0-3],
|
||||
$$[$0],
|
||||
$$[$0-1]));
|
||||
$$[$0-1],
|
||||
yy.addDataToNode(yy, _$[$0-4])(new yy.Literal($$[$0-4]))));
|
||||
break;
|
||||
case 87:
|
||||
this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Code([],
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Generated by CoffeeScript 2.0.0
|
||||
// Generated by CoffeeScript 2.0.2
|
||||
(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.0.2
|
||||
(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() {
|
||||
@@ -57,10 +59,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 +70,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 +232,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 +242,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.0.2
|
||||
(function() {
|
||||
// The CoffeeScript language has a good deal of optional syntax, implicit syntax,
|
||||
// and shorthand syntax. This can greatly complicate a grammar and bloat
|
||||
@@ -944,6 +944,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.0.2
|
||||
(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.0.2
|
||||
(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 = [];
|
||||
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "coffeescript",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"compiler"
|
||||
],
|
||||
"author": "Jeremy Ashkenas",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.2",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
@@ -51,8 +51,5 @@
|
||||
"underscore": "~1.8.3",
|
||||
"webpack": "~3.6.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"babel-core": "^6"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
|
||||
@@ -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) ->
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -262,7 +262,7 @@ 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
|
||||
]
|
||||
|
||||
|
||||
@@ -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,7 +192,7 @@ 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])
|
||||
if prev.spaced and prev[0] in CALLABLE and /^[gs]et$/.test(prev[1]) and @tokens[@tokens.length - 2][0] isnt '.'
|
||||
@error "'#{prev[1]}' cannot be used as a keyword, or as a function call without parentheses", prev[2]
|
||||
else
|
||||
prevprev = @tokens[@tokens.length - 2]
|
||||
@@ -197,7 +203,7 @@ exports.Lexer = class Lexer
|
||||
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]
|
||||
@@ -965,9 +971,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: ->
|
||||
|
||||
@@ -179,6 +179,7 @@ exports.Base = class Base
|
||||
# `compileToFragments` method has logic for outputting comments.
|
||||
unshiftCommentFragment commentFragment
|
||||
else
|
||||
fragments.push @makeCode '' if fragments.length is 0
|
||||
if commentFragment.unshift
|
||||
fragments[0].precedingComments ?= []
|
||||
fragments[0].precedingComments.push commentFragment
|
||||
@@ -497,17 +498,17 @@ exports.Block = class Block extends Base
|
||||
compiledNodes = []
|
||||
|
||||
for node, index in @expressions
|
||||
node = node.unwrapAll()
|
||||
if node.hoisted
|
||||
# This is a hoisted expression.
|
||||
# We want to compile this and ignore the result.
|
||||
node.compileToFragments o
|
||||
continue
|
||||
node = (node.unfoldSoak(o) or node)
|
||||
if node instanceof Block
|
||||
# This is a nested block. We don’t do anything special here like
|
||||
# enclose it in a new scope; we just compile the statements in this
|
||||
# block along with our own.
|
||||
compiledNodes.push node.compileNode o
|
||||
else if node.hoisted
|
||||
# This is a hoisted expression.
|
||||
# We want to compile this and ignore the result.
|
||||
node.compileToFragments o
|
||||
else if top
|
||||
node.front = yes
|
||||
fragments = node.compileToFragments o
|
||||
@@ -570,7 +571,13 @@ exports.Block = class Block extends Base
|
||||
fragments.push @makeCode '\n' if i
|
||||
fragments.push @makeCode "#{@tab}var "
|
||||
if declars
|
||||
fragments.push @makeCode scope.declaredVariables().join(', ')
|
||||
declaredVariables = scope.declaredVariables()
|
||||
for declaredVariable, declaredVariablesIndex in declaredVariables
|
||||
fragments.push @makeCode declaredVariable
|
||||
if Object::hasOwnProperty.call o.scope.comments, declaredVariable
|
||||
fragments.push o.scope.comments[declaredVariable]...
|
||||
if declaredVariablesIndex isnt declaredVariables.length - 1
|
||||
fragments.push @makeCode ', '
|
||||
if assigns
|
||||
fragments.push @makeCode ",\n#{@tab + TAB}" if declars
|
||||
fragments.push @makeCode scope.assignedVariables().join(",\n#{@tab + TAB}")
|
||||
@@ -1674,7 +1681,9 @@ exports.Class = class Class extends Base
|
||||
|
||||
result = []
|
||||
result.push @makeCode "class "
|
||||
result.push @makeCode "#{@name} " if @name
|
||||
result.push @makeCode @name if @name
|
||||
@compileCommentFragments o, @variable, result if @variable?.comments?
|
||||
result.push @makeCode ' ' if @name
|
||||
result.push @makeCode('extends '), @parent.compileToFragments(o)..., @makeCode ' ' if @parent
|
||||
|
||||
result.push @makeCode '{'
|
||||
@@ -1752,10 +1761,23 @@ exports.Class = class Class extends Base
|
||||
|
||||
# Add an expression to the class initializer
|
||||
#
|
||||
# NOTE Currently, only methods and static methods are valid in ES class initializers.
|
||||
# When additional expressions become valid, this method should be updated to handle them.
|
||||
# This is the key method for determining whether an expression in a class
|
||||
# body should appear in the initializer or the executable body. If the given
|
||||
# `node` is valid in a class body the method will return a (new, modified,
|
||||
# or identical) node for inclusion in the class initializer, otherwise
|
||||
# nothing will be returned and the node will appear in the executable body.
|
||||
#
|
||||
# At time of writing, only methods (instance and static) are valid in ES
|
||||
# class initializers. As new ES class features (such as class fields) reach
|
||||
# Stage 4, this method will need to be updated to support them. We
|
||||
# additionally allow `PassthroughLiteral`s (backticked expressions) in the
|
||||
# initializer as an escape hatch for ES features that are not implemented
|
||||
# (e.g. getters and setters defined via the `get` and `set` keywords as
|
||||
# opposed to the `Object.defineProperty` method).
|
||||
addInitializerExpression: (node) ->
|
||||
if @validInitializerMethod node
|
||||
if node.unwrapAll() instanceof PassthroughLiteral
|
||||
node
|
||||
else if @validInitializerMethod node
|
||||
@addInitializerMethod node
|
||||
else
|
||||
null
|
||||
@@ -2140,7 +2162,7 @@ exports.Assign = class Assign extends Base
|
||||
message = isUnassignable name.value
|
||||
name.error message if message
|
||||
|
||||
# `moduleDeclaration` can be `'import'` or `'export'`
|
||||
# `moduleDeclaration` can be `'import'` or `'export'`.
|
||||
@checkAssignability o, name
|
||||
if @moduleDeclaration
|
||||
o.scope.add name.value, @moduleDeclaration
|
||||
@@ -2152,6 +2174,20 @@ exports.Assign = class Assign extends Base
|
||||
'param'
|
||||
else
|
||||
o.scope.find name.value
|
||||
# If this assignment identifier has one or more herecomments
|
||||
# attached, output them as part of the declarations line (unless
|
||||
# other herecomments are already staged there) for compatibility
|
||||
# with Flow typing. Don’t do this if this assignment is for a
|
||||
# class, e.g. `ClassName = class ClassName {`, as Flow requires
|
||||
# the comment to be between the class name and the `{`.
|
||||
if name.comments and not o.scope.comments[name.value] and
|
||||
@value not instanceof Class and
|
||||
name.comments.every((comment) -> comment.here and not comment.multiline)
|
||||
commentsNode = new IdentifierLiteral name.value
|
||||
commentsNode.comments = name.comments
|
||||
commentFragments = []
|
||||
@compileCommentFragments o, commentsNode, commentFragments
|
||||
o.scope.comments[name.value] = commentFragments
|
||||
|
||||
if @value instanceof Code
|
||||
if @value.isStatic
|
||||
@@ -2471,7 +2507,7 @@ exports.FuncGlyph = class FuncGlyph extends Base
|
||||
# When for the purposes of walking the contents of a function body, the Code
|
||||
# has no *children* -- they're within the inner scope.
|
||||
exports.Code = class Code extends Base
|
||||
constructor: (params, body, @funcGlyph) ->
|
||||
constructor: (params, body, @funcGlyph, @paramStart) ->
|
||||
super()
|
||||
|
||||
@params = params or []
|
||||
@@ -2671,6 +2707,10 @@ exports.Code = class Code extends Base
|
||||
modifiers.push '*'
|
||||
|
||||
signature = [@makeCode '(']
|
||||
# Block comments between a function name and `(` get output between
|
||||
# `function` and `(`.
|
||||
if @paramStart?.comments?
|
||||
@compileCommentFragments o, @paramStart, signature
|
||||
for param, i in params
|
||||
signature.push @makeCode ', ' if i isnt 0
|
||||
signature.push @makeCode '...' if haveSplatParam and i is params.length - 1
|
||||
@@ -2743,13 +2783,19 @@ exports.Code = class Code extends Base
|
||||
|
||||
seenSuper
|
||||
|
||||
# Find all super calls in the given context node
|
||||
# Returns `true` if `iterator` is called
|
||||
# Find all super calls in the given context node;
|
||||
# returns `true` if `iterator` is called.
|
||||
eachSuperCall: (context, iterator) ->
|
||||
seenSuper = no
|
||||
|
||||
context.traverseChildren true, (child) =>
|
||||
context.traverseChildren yes, (child) =>
|
||||
if child instanceof SuperCall
|
||||
# `super` in a constructor (the only `super` without an accessor)
|
||||
# cannot be given an argument with a reference to `this`, as that would
|
||||
# be referencing `this` before calling `super`.
|
||||
unless child.variable.accessor
|
||||
Block.wrap(child.args).traverseChildren yes, (node) =>
|
||||
node.error "Can't call super with @params in derived class constructors" if node.this
|
||||
seenSuper = yes
|
||||
iterator child
|
||||
else if child instanceof ThisLiteral and @ctor is 'derived' and not seenSuper
|
||||
@@ -3269,15 +3315,11 @@ exports.Existence = class Existence extends Base
|
||||
super()
|
||||
@comparisonTarget = if onlyNotUndefined then 'undefined' else 'null'
|
||||
salvagedComments = []
|
||||
@expression.eachChild (child) ->
|
||||
@expression.traverseChildren yes, (child) ->
|
||||
if child.comments
|
||||
for comment in child.comments
|
||||
salvagedComments.push comment unless comment in salvagedComments
|
||||
delete child.comments
|
||||
if child.name?.comments
|
||||
for comment in child.name.comments
|
||||
salvagedComments.push comment unless comment in salvagedComments
|
||||
delete child.name.comments
|
||||
attachCommentsToNode salvagedComments, @
|
||||
moveComments @expression, @
|
||||
|
||||
@@ -3324,13 +3366,21 @@ exports.Parens = class Parens extends Base
|
||||
|
||||
compileNode: (o) ->
|
||||
expr = @body.unwrap()
|
||||
if expr instanceof Value and expr.isAtomic() and not @csxAttribute
|
||||
# If these parentheses are wrapping an `IdentifierLiteral` followed by a
|
||||
# block comment, output the parentheses (or put another way, don’t optimize
|
||||
# away these redundant parentheses). This is because Flow requires
|
||||
# parentheses in certain circumstances to distinguish identifiers followed
|
||||
# by comment-based type annotations from JavaScript labels.
|
||||
shouldWrapComment = expr.comments?.some(
|
||||
(comment) -> comment.here and not comment.unshift and not comment.newLine)
|
||||
if expr instanceof Value and expr.isAtomic() and not @csxAttribute and not shouldWrapComment
|
||||
expr.front = @front
|
||||
return expr.compileToFragments o
|
||||
fragments = expr.compileToFragments o, LEVEL_PAREN
|
||||
bare = o.level < LEVEL_OP and (expr instanceof Op or expr.unwrap() instanceof Call or
|
||||
(expr instanceof For and expr.returns)) and (o.level < LEVEL_COND or
|
||||
fragments.length <= 3)
|
||||
bare = o.level < LEVEL_OP and not shouldWrapComment and (
|
||||
expr instanceof Op or expr.unwrap() instanceof Call or
|
||||
(expr instanceof For and expr.returns)
|
||||
) and (o.level < LEVEL_COND or fragments.length <= 3)
|
||||
return @wrapInBraces fragments if @csxAttribute
|
||||
if bare then fragments else @wrapInParentheses fragments
|
||||
|
||||
|
||||
@@ -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> ',
|
||||
@@ -35,14 +36,19 @@ replDefaults =
|
||||
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 +173,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
|
||||
|
||||
@@ -693,6 +693,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
|
||||
|
||||
|
||||
@@ -1833,3 +1833,27 @@ 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
|
||||
|
||||
@@ -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,7 @@ 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()"
|
||||
|
||||
@@ -65,7 +65,7 @@ if require?
|
||||
|
||||
try
|
||||
assertErrorFormat """
|
||||
require '#{tempFile}'
|
||||
require '#{tempFile.replace /\\/g, '\\\\'}'
|
||||
""",
|
||||
"""
|
||||
#{fs.realpathSync tempFile}:1:15: error: unexpected in
|
||||
@@ -1339,6 +1339,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
|
||||
|
||||
@@ -806,6 +806,12 @@ 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
|
||||
|
||||
@@ -825,3 +831,8 @@ 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
|
||||
|
||||
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
|
||||
@@ -1,13 +1,17 @@
|
||||
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'
|
||||
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'
|
||||
@@ -17,18 +21,18 @@ initialSpaceExtraArgsScript = require.resolve './importing/shebang_initial_space
|
||||
test "parse arguments for shebang scripts correctly (on unix 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 'coffee', [shebangScript, '--'], spawnOptions
|
||||
stderr = result.stderr.toString()
|
||||
arrayEq JSON.parse(result.stdout), ['coffee', shebangScript]
|
||||
ok stderr.match /^coffee was invoked with '--'/m
|
||||
@@ -36,7 +40,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 'coffee', ['-b', shebangScript, '--'], spawnOptions
|
||||
stderr = result.stderr.toString()
|
||||
arrayEq JSON.parse(result.stdout), ['coffee', shebangScript]
|
||||
ok stderr.match /^coffee was invoked with '--'/m
|
||||
@@ -45,16 +49,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})
|
||||
'coffee', ['-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})
|
||||
'coffee', ['--', initialSpaceScript, 'arg'], spawnOptions)
|
||||
expectedArgs = ['coffee', initialSpaceScript, 'arg']
|
||||
realArgs = JSON.parse result.stdout
|
||||
arrayEq expectedArgs, realArgs
|
||||
@@ -62,7 +66,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 'coffee', [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 +77,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 'coffee', [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})
|
||||
'coffee', [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 +97,7 @@ test "warn about non-portable shebang lines", ->
|
||||
|
||||
test "both warnings will be shown at once", ->
|
||||
result = spawnSync(
|
||||
'coffee', [initialSpaceExtraArgsScript, '--', 'arg'], {env: patchedEnv})
|
||||
'coffee', [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
|
||||
|
||||
@@ -473,7 +473,6 @@ test "export default named member, within an object", ->
|
||||
bar
|
||||
};"""
|
||||
|
||||
|
||||
# Import and export in the same statement
|
||||
|
||||
test "export an entire module's contents", ->
|
||||
@@ -497,18 +496,21 @@ test "export as aliases members imported from another module", ->
|
||||
} from 'lib';"""
|
||||
|
||||
test "export list can contain CoffeeScript keywords", ->
|
||||
eqJS "export { unless } from 'lib'",
|
||||
eqJS "export { unless, and } from 'lib'",
|
||||
"""
|
||||
export {
|
||||
unless
|
||||
unless,
|
||||
and
|
||||
} from 'lib';"""
|
||||
|
||||
test "export list can contain CoffeeScript keywords when aliasing", ->
|
||||
eqJS "export { when as bar, baz as unless } from 'lib'",
|
||||
eqJS "export { when as bar, baz as unless, and as foo, booze as not } from 'lib'",
|
||||
"""
|
||||
export {
|
||||
when as bar,
|
||||
baz as unless
|
||||
baz as unless,
|
||||
and as foo,
|
||||
booze as not
|
||||
} from 'lib';"""
|
||||
|
||||
|
||||
@@ -602,11 +604,12 @@ test "`as` can be used as an alias name", ->
|
||||
|
||||
test "CoffeeScript keywords can be used as imported names in import lists", ->
|
||||
eqJS """
|
||||
import { unless as bar } from 'lib'
|
||||
import { unless as bar, and as computedAnd } from 'lib'
|
||||
bar.barMethod()""",
|
||||
"""
|
||||
import {
|
||||
unless as bar
|
||||
unless as bar,
|
||||
and as computedAnd
|
||||
} from 'lib';
|
||||
|
||||
bar.barMethod();"""
|
||||
|
||||
@@ -122,6 +122,10 @@ testRepl "#4604: wraps an async function", (input, output) ->
|
||||
eq '33', output.lastWrite()
|
||||
, 20
|
||||
|
||||
testRepl "transpile REPL", (input, output) ->
|
||||
input.emitLine 'require("./test/importing/transpile_import").getSep()'
|
||||
eq "'#{path.sep.replace '\\', '\\\\'}'", output.lastWrite()
|
||||
|
||||
process.on 'exit', ->
|
||||
try
|
||||
fs.unlinkSync historyFile
|
||||
|
||||
Reference in New Issue
Block a user