Compare commits

..

32 Commits
2.0.1 ... 2.1.1

Author SHA1 Message Date
Geoffrey Booth
12fcbfc654 2.1.1 (#4835)
* Bump version to 2.1.1

* 2.1.1 changelog

* 2.1.1 updated output
2017-12-29 16:54:57 -08:00
Chris Connelly
38f5963b85 Use free variables for anonymous classes (#4826)
Fixes #4822.
2017-12-28 14:50:12 -08:00
Chris Connelly
ffbe51e374 Set the context of executable class body wrappers (#4828)
Fixes #4827.
2017-12-18 10:51:08 -08:00
Geoffrey Booth
926cb8463c 2.1.0 (#4823)
* Changelog for 2.1.0; remove text from objects section that is no longer valid for CS2/ES2015.

* Update packages

* 2.1.0 build

* Update output

* Correct reference to `//` division, per https://github.com/coffeescript6/discuss/issues/39#issuecomment-347144647
2017-12-10 23:12:33 -08:00
zdenko
b1286752b9 improve elision output (#4824) 2017-12-10 15:22:34 -08:00
zdenko
5eb9dded52 [Enhancement] Computed property keys (#4622) (#4803)
* Computed property keys

* refactor

* improvements

* refactor tests

* fix comments
2017-12-08 22:42:47 -08:00
zdenko
7f5ab7eb0d [Enhancement] CSX fragments syntax (#4802) (#4804)
* CSX fragments

* regex improvement; tests

* regex improvement

* regex improvement

* bug fix; regex

* Fix style

* Split fragment tests
2017-12-08 22:41:02 -08:00
zdenko
5bc85b8f6d Fix #4798: Incorrect output for object rest destructuring inside array destructuring (#4799)
* fix #4798

* additional tests
2017-12-04 08:00:45 -08:00
zdenko
81d1b511f0 Fix #4811: Heregex comments cannot contain three slashes in a row (#4814)
* fix comment with /// in heregex

* cleanup

* improved pattern for comments in heregex; fixed unescaped hashes in lexer.coffee

* improvements

* refactor RegExp

* cleanup

* Improved RegEx
2017-12-03 11:55:26 -08:00
Geoffrey Booth
2dc3f6c87a Cache node_modules for AppVeyor builds (#4817) 2017-12-02 20:49:22 -08:00
Geoffrey Booth
04959162c6 AppVeyor (#4812)
* First attempt at using AppVeyor

* Maybe it doesn't like the leading dot?

* Versions are an array

* Fix tests on Windows: for some reason, Windows requires `coffee` to be executed as `node coffee` (in the context of `spawnSync`, at least)

* Use npm@latest, see if that's less noisy

* Nevermind, only an issue on Node 6

* Better to see the NPM version before npm install
2017-12-01 13:19:48 -08:00
zdenko
f14c7ffa3f Fixes #4684: Elision (#4796)
* Elision

* test

* improvements

* grammar optimization

* cleanup
2017-11-28 21:24:18 -08:00
Geoffrey Booth
64b8dd486a 2.0.3 (#4795)
* Fix #4775: Remove no-longer-correct mention of the docs using text/coffeescript

* 2.0.3 changelog

* Update output for 2.0.3

* Bump date
2017-11-26 19:29:08 -08:00
Geoffrey Booth
7864acabc3 Fix #4790: Double-check that we're not creating a bound generator function, even if the yield got stuffed inside a compiler-generated IIFE (#4792) 2017-11-21 17:14:32 -08:00
zdenko
9812d28748 Fix #4787: Destructuring of objects within arrays can generate invalid JavaScript (#4791)
* Fix #4787

* simplify condition
2017-11-20 20:00:27 -08:00
zdenko
555c22af58 fix #4580 (#4793) 2017-11-20 09:15:19 -08:00
Geoffrey Booth
3f4b03bcff Fix #4763: Comments at beginning or end of REPL input shouldn't throw errors (#4764) 2017-11-19 11:37:08 -08:00
Geoffrey Booth
a706a64a6d Fix #4765: .map file should always have the same output base filename as the generated .js file (#4784) 2017-11-16 13:30:40 -08:00
Geoffrey Booth
637fe305a6 Fix #4774: export default followed by an object should always work, even if the object contains braces. default shouldn't suppress a newline, we should handle it in the grammar the same way returning an implicit object is handled (#4783) 2017-11-15 21:38:05 -08:00
Geoffrey Booth
bd824c73dd Fix #4780: Don't mutate the options object when compiling and transpiling, so that options are correct on subsequent iterations (#4785) 2017-11-14 08:13:22 -08:00
Geoffrey Booth
cbc695b831 2.0.2 (#4758)
* Give the notes about `super` and `this` their own section in the docs

* 2.0.2 changelog

* 2.0.2 release output

* Rewrite
2017-10-26 18:29:45 -07:00
Geoffrey Booth
f3375e798c Fix #4756: When moving comments from the children of an Existence, we need to search all its descendants, not just the immediate children (#4757) 2017-10-25 22:15:40 -07:00
Geoffrey Booth
e2308093e4 Fix #4752: Error on calling super with @params in a derived class constructor (#4754)
* Fix #4752: Error on calling super with @params in a derived class constructor

* Catch calls to super with not-top-level @params
2017-10-25 22:15:05 -07:00
Geoffrey Booth
0dc4755920 Fix #4747: Flow local variables (#4753)
* Fix #4706: Comments before a PARAM_START token stay before that token

* Simplify nodes

* Add function-in-function test

* Fix #4706: Comments after class name should go after the identifier that's after `class`, not the variable assigned to

* Fix #4706: Top-level identifiers with trailing comments get wrapped in parentheses (around the comment too) so that Flow doesn't interpret it as a JavaScript label

* Cleanup

* If the source has parentheses wrapping an identifier followed by a block comment, output those parentheses rather than optimizing them away; this is a requirement of Flow, to distinguish from JavaScript labels

* More tests for Flow comments

* For local variables with trailing inline herecomments, output the comments up in the variable declarations line for Flow compatibility
2017-10-19 06:56:59 -07:00
Geoffrey Booth
6faa7f2b35 Fix #4706: Flow generics (#4736)
* Fix #4706: Comments before a PARAM_START token stay before that token

* Simplify nodes

* Add function-in-function test

* Fix #4706: Comments after class name should go after the identifier that's after `class`, not the variable assigned to

* Fix #4706: Top-level identifiers with trailing comments get wrapped in parentheses (around the comment too) so that Flow doesn't interpret it as a JavaScript label

* Cleanup

* If the source has parentheses wrapping an identifier followed by a block comment, output those parentheses rather than optimizing them away; this is a requirement of Flow, to distinguish from JavaScript labels

* More tests for Flow comments
2017-10-18 17:22:02 -07:00
geebo
063c2d1f56 Fix import/export list bug with aliased keywords (#4744) 2017-10-12 11:47:12 -07:00
Chris Connelly
4d4e47bfb2 Fix #4724 (#4737)
The handling of hoisted nodes in class bodies was incorrect, as the node
was being unwrapped *before* checking if it was hoisted, meaning nodes
that should have been hoisted would be output normally.

This affected `PassthroughLiteral`s as they were wrapped in a `Value`.
2017-10-07 11:32:43 -07:00
Geoffrey Booth
22fb31e317 Transpile REPL (#4729)
* Fix #4725: apply transpile option to require’d .coffee files

* Use the current module’s options if it has any, before going searching up the tree

* Don’t mutate passed-in options object

* If the REPL is run with `--transpile`, turn transpilation on for both the current REPL input and any files imported by that input

* Use the command.coffee machinery for parsing arguments

* Fix test for Windows
2017-10-04 17:50:25 -07:00
Geoffrey Booth
a2037e799f Fix #4725: apply transpile option to require’d .coffee files (#4728)
* Fix #4725: apply transpile option to require’d .coffee files

* Use the current module’s options if it has any, before going searching up the tree

* Don’t mutate passed-in options object
2017-10-04 17:49:59 -07:00
Geoffrey Booth
694e69d872 Fix #4727: Tests failing in Windows (#4731)
* ?

* ??

* Revert the coffee.EXE approach

* Explicitly define the PATH to include only the folders we need

* Get spawnSync working in Windows

* Simplify test to be cross-platform
2017-10-02 22:19:32 -07:00
Matthew Ryan
bb2871fdde Allow applying 'get'/'set' property to a bracketless object (#4730) 2017-10-02 11:10:43 -07:00
Geoffrey Booth
08e00331dd Fix #3440: --stdio and --map don’t make sense to use together (#4721) 2017-09-27 00:02:30 -07:00
68 changed files with 4113 additions and 1456 deletions

27
appveyor.yml Normal file
View File

@@ -0,0 +1,27 @@
environment:
matrix:
- nodejs_version: '6'
- nodejs_version: '8'
- nodejs_version: '' # Installs latest.
install:
- ps: Install-Product node $env:nodejs_version
- node --version
- npm --version
- npm install
cache:
- node_modules
test_script:
- node ./bin/cake build:except-parser
- node ./bin/cake build:parser
- node ./bin/cake build:full
- node ./bin/cake build:browser
- node ./bin/cake test
- node ./bin/cake test:browser
- node ./bin/cake test:integrations
build: off
version: "{build}"

View File

@@ -480,7 +480,9 @@ is run via the CLI or Node API.</p>
</div>
<div class="content"><div class='highlight'><pre> transpiler = options.transpile.transpile
<span class="hljs-keyword">delete</span> options.transpile.transpile</pre></div></div>
<span class="hljs-keyword">delete</span> options.transpile.transpile
transpilerOptions = Object.assign {}, options.transpile</pre></div></div>
</li>
@@ -497,9 +499,9 @@ and it will return an <em>updated</em> v3 source map object in its output.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> v3SourceMap <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> options.transpile.inputSourceMap?
options.transpile.inputSourceMap = v3SourceMap
transpilerOutput = transpiler js, options.transpile
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> v3SourceMap <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> transpilerOptions.inputSourceMap?
transpilerOptions.inputSourceMap = v3SourceMap
transpilerOutput = transpiler js, transpilerOptions
js = transpilerOutput.code
<span class="hljs-keyword">if</span> v3SourceMap <span class="hljs-keyword">and</span> transpilerOutput.map
v3SourceMap = transpilerOutput.map

View File

@@ -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> = -&gt;</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> -&gt;</span>
@@ -745,7 +749,7 @@ same directory as the <code>.js</code> file.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">writeJs</span> = <span class="hljs-params">(base, sourcePath, js, jsPath, generatedSourceMap = <span class="hljs-literal">null</span>)</span> -&gt;</span>
sourceMapPath = outputPath sourcePath, base, <span class="hljs-string">".js.map"</span>
sourceMapPath = <span class="hljs-string">"<span class="hljs-subst">#{jsPath}</span>.map"</span>
jsDir = path.dirname jsPath
<span class="hljs-function"> <span class="hljs-title">compile</span> = -&gt;</span>
<span class="hljs-keyword">if</span> opts.compile

View File

@@ -558,6 +558,7 @@ the ordinary <strong>Assign</strong> is that these allow numbers and strings as
o <span class="hljs-string">'Identifier'</span>
o <span class="hljs-string">'Property'</span>
o <span class="hljs-string">'ThisProperty'</span>
o <span class="hljs-string">'[ Expression ]'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> ComputedPropertyName $<span class="hljs-number">2</span>
]
ObjAssignable: [
@@ -650,7 +651,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">-&gt;</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">-&gt;</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">-&gt;</span> <span class="hljs-keyword">new</span> Code [], $<span class="hljs-number">2</span>, $<span class="hljs-number">1</span>
]</pre></div></div>
@@ -1007,6 +1008,7 @@ and optional references to the superclass.</p>
o <span class="hljs-string">'EXPORT Identifier = INDENT Expression OUTDENT'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration <span class="hljs-keyword">new</span> Assign $<span class="hljs-number">2</span>, $<span class="hljs-number">5</span>, <span class="hljs-literal">null</span>,
moduleDeclaration: <span class="hljs-string">'export'</span>
o <span class="hljs-string">'EXPORT DEFAULT Expression'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportDefaultDeclaration $<span class="hljs-number">3</span>
o <span class="hljs-string">'EXPORT DEFAULT INDENT Object OUTDENT'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportDefaultDeclaration <span class="hljs-keyword">new</span> Value $<span class="hljs-number">4</span>
o <span class="hljs-string">'EXPORT EXPORT_ALL FROM String'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportAllDeclaration <span class="hljs-keyword">new</span> Literal($<span class="hljs-number">2</span>), $<span class="hljs-number">4</span>
o <span class="hljs-string">'EXPORT { ExportSpecifierList OptComma } FROM String'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration <span class="hljs-keyword">new</span> ExportSpecifierList($<span class="hljs-number">3</span>), $<span class="hljs-number">7</span>
]
@@ -1132,7 +1134,8 @@ and optional references to the superclass.</p>
<div class="content"><div class='highlight'><pre> Array: [
o <span class="hljs-string">'[ ]'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Arr []
o <span class="hljs-string">'[ ArgList OptComma ]'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Arr $<span class="hljs-number">2</span>
o <span class="hljs-string">'[ Elisions ]'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Arr $<span class="hljs-number">2</span>
o <span class="hljs-string">'[ ArgElisionList OptElisions ]'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Arr [].concat $<span class="hljs-number">2</span>, $<span class="hljs-number">3</span>
]</pre></div></div>
</li>
@@ -1199,8 +1202,7 @@ and optional references to the superclass.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-49">&#182;</a>
</div>
<p>The <strong>ArgList</strong> is both the list of objects passed into a function call,
as well as the contents of an array literal
<p>The <strong>ArgList</strong> is the list of objects passed into a function call
(i.e. comma-separated expressions). Newlines work as well.</p>
</div>
@@ -1241,6 +1243,47 @@ as well as the contents of an array literal
<div class="pilwrap ">
<a class="pilcrow" href="#section-51">&#182;</a>
</div>
<p>The <strong>ArgElisionList</strong> is the list of objects, contents of an array literal
(i.e. comma-separated expressions and elisions). Newlines work as well.</p>
</div>
<div class="content"><div class='highlight'><pre> ArgElisionList: [
o <span class="hljs-string">'ArgElision'</span>
o <span class="hljs-string">'ArgElisionList , ArgElision'</span>, <span class="hljs-function">-&gt;</span> $<span class="hljs-number">1.</span>concat $<span class="hljs-number">3</span>
o <span class="hljs-string">'ArgElisionList OptElisions TERMINATOR ArgElision'</span>, <span class="hljs-function">-&gt;</span> $<span class="hljs-number">1.</span>concat $<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>
o <span class="hljs-string">'INDENT ArgElisionList OptElisions OUTDENT'</span>, <span class="hljs-function">-&gt;</span> $<span class="hljs-number">2.</span>concat $<span class="hljs-number">3</span>
o <span class="hljs-string">'ArgElisionList OptElisions INDENT ArgElisionList OptElisions OUTDENT'</span>, <span class="hljs-function">-&gt;</span> $<span class="hljs-number">1.</span>concat $<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>, $<span class="hljs-number">5</span>
]
ArgElision: [
o <span class="hljs-string">'Arg'</span>, <span class="hljs-function">-&gt;</span> [$<span class="hljs-number">1</span>]
o <span class="hljs-string">'Elisions Arg'</span>, <span class="hljs-function">-&gt;</span> $<span class="hljs-number">1.</span>concat $<span class="hljs-number">2</span>
]
OptElisions: [
o <span class="hljs-string">'OptComma'</span>, <span class="hljs-function">-&gt;</span> []
o <span class="hljs-string">', Elisions'</span>, <span class="hljs-function">-&gt;</span> [].concat $<span class="hljs-number">2</span>
]
Elisions: [
o <span class="hljs-string">'Elision'</span>, <span class="hljs-function">-&gt;</span> [$<span class="hljs-number">1</span>]
o <span class="hljs-string">'Elisions Elision'</span>, <span class="hljs-function">-&gt;</span> $<span class="hljs-number">1.</span>concat $<span class="hljs-number">2</span>
]
Elision: [
o <span class="hljs-string">','</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Elision
]</pre></div></div>
</li>
<li id="section-52">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-52">&#182;</a>
</div>
<p>Just simple, comma-separated, required arguments (no fancy syntax). We need
this to be separate from the <strong>ArgList</strong> for use in <strong>Switch</strong> blocks, where
having the newlines wouldnt make sense.</p>
@@ -1255,11 +1298,11 @@ having the newlines wouldnt make sense.</p>
</li>
<li id="section-52">
<li id="section-53">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-52">&#182;</a>
<a class="pilcrow" href="#section-53">&#182;</a>
</div>
<p>The variants of <em>try/catch/finally</em> exception handling blocks.</p>
@@ -1275,11 +1318,11 @@ having the newlines wouldnt make sense.</p>
</li>
<li id="section-53">
<li id="section-54">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-53">&#182;</a>
<a class="pilcrow" href="#section-54">&#182;</a>
</div>
<p>A catch clause names its error and runs a block of code.</p>
@@ -1294,11 +1337,11 @@ having the newlines wouldnt make sense.</p>
</li>
<li id="section-54">
<li id="section-55">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-54">&#182;</a>
<a class="pilcrow" href="#section-55">&#182;</a>
</div>
<p>Throw an exception object.</p>
@@ -1312,11 +1355,11 @@ having the newlines wouldnt make sense.</p>
</li>
<li id="section-55">
<li id="section-56">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-55">&#182;</a>
<a class="pilcrow" href="#section-56">&#182;</a>
</div>
<p>Parenthetical expressions. Note that the <strong>Parenthetical</strong> is a <strong>Value</strong>,
not an <strong>Expression</strong>, so if you need to use an expression in a place
@@ -1333,11 +1376,11 @@ the trick.</p>
</li>
<li id="section-56">
<li id="section-57">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-56">&#182;</a>
<a class="pilcrow" href="#section-57">&#182;</a>
</div>
<p>The condition portion of a while loop.</p>
@@ -1353,11 +1396,11 @@ the trick.</p>
</li>
<li id="section-57">
<li id="section-58">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-57">&#182;</a>
<a class="pilcrow" href="#section-58">&#182;</a>
</div>
<p>The while loop can either be normal, with a block of expressions to execute,
or postfix, with a single expression. There is no do..while.</p>
@@ -1379,11 +1422,11 @@ or postfix, with a single expression. There is no do..while.</p>
</li>
<li id="section-58">
<li id="section-59">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-58">&#182;</a>
<a class="pilcrow" href="#section-59">&#182;</a>
</div>
<p>Array, object, and range comprehensions, at the most generic level.
Comprehensions can either be normal, with a block of expressions to execute,
@@ -1411,11 +1454,11 @@ or postfix, with a single expression.</p>
</li>
<li id="section-59">
<li id="section-60">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-59">&#182;</a>
<a class="pilcrow" href="#section-60">&#182;</a>
</div>
<p>An array of all accepted values for a variable inside the loop.
This enables support for pattern matching.</p>
@@ -1432,11 +1475,11 @@ This enables support for pattern matching.</p>
</li>
<li id="section-60">
<li id="section-61">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-60">&#182;</a>
<a class="pilcrow" href="#section-61">&#182;</a>
</div>
<p>An array or range comprehension has variables for the current element
and (optional) reference to the current index. Or, <em>key, value</em>, in the case
@@ -1452,11 +1495,11 @@ of object comprehensions.</p>
</li>
<li id="section-61">
<li id="section-62">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-61">&#182;</a>
<a class="pilcrow" href="#section-62">&#182;</a>
</div>
<p>The source of a comprehension is an array or object with an optional guard
clause. If its an array comprehension, you can also choose to step through
@@ -1491,11 +1534,11 @@ in fixed-size increments.</p>
</li>
<li id="section-62">
<li id="section-63">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-62">&#182;</a>
<a class="pilcrow" href="#section-63">&#182;</a>
</div>
<p>An individual <strong>When</strong> clause, with action.</p>
@@ -1509,11 +1552,11 @@ in fixed-size increments.</p>
</li>
<li id="section-63">
<li id="section-64">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-63">&#182;</a>
<a class="pilcrow" href="#section-64">&#182;</a>
</div>
<p>The most basic form of <em>if</em> is a condition and an action. The following
if-related rules are broken up along these lines in order to avoid
@@ -1529,11 +1572,11 @@ ambiguity.</p>
</li>
<li id="section-64">
<li id="section-65">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-64">&#182;</a>
<a class="pilcrow" href="#section-65">&#182;</a>
</div>
<p>The full complement of <em>if</em> expressions, including postfix one-liner
<em>if</em> and <em>unless</em>.</p>
@@ -1550,11 +1593,11 @@ ambiguity.</p>
</li>
<li id="section-65">
<li id="section-66">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-65">&#182;</a>
<a class="pilcrow" href="#section-66">&#182;</a>
</div>
<p>Arithmetic and logical operators, working on one or more operands.
Here they are grouped by order of precedence. The actual precedence rules
@@ -1581,11 +1624,11 @@ rules are necessary.</p>
</li>
<li id="section-66">
<li id="section-67">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-66">&#182;</a>
<a class="pilcrow" href="#section-67">&#182;</a>
</div>
<p><a href="http://coffeescript.org/#existential-operator">The existential operator</a>.</p>
@@ -1623,26 +1666,14 @@ rules are necessary.</p>
</li>
<li id="section-67">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-67">&#182;</a>
</div>
<h2 id="precedence">Precedence</h2>
</div>
</li>
<li id="section-68">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-68">&#182;</a>
</div>
<h2 id="precedence">Precedence</h2>
</div>
</li>
@@ -1654,6 +1685,18 @@ rules are necessary.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-69">&#182;</a>
</div>
</div>
</li>
<li id="section-70">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-70">&#182;</a>
</div>
<p>Operators at the top of this list have higher precedence than the ones lower
down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
<pre><code><span class="hljs-number">2</span> + (<span class="hljs-number">3</span> * <span class="hljs-number">4</span>)
@@ -1693,26 +1736,14 @@ down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
</li>
<li id="section-70">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-70">&#182;</a>
</div>
<h2 id="wrapping-up">Wrapping Up</h2>
</div>
</li>
<li id="section-71">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-71">&#182;</a>
</div>
<h2 id="wrapping-up">Wrapping Up</h2>
</div>
</li>
@@ -1724,6 +1755,18 @@ down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-72">&#182;</a>
</div>
</div>
</li>
<li id="section-73">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-73">&#182;</a>
</div>
<p>Finally, now that we have our <strong>grammar</strong> and our <strong>operators</strong>, we can create
our <strong>Jison.Parser</strong>. We do this by processing all of our rules, recording all
terminals (every symbol which does not appear as the name of a rule above)
@@ -1742,11 +1785,11 @@ as “tokens”.</p>
</li>
<li id="section-73">
<li id="section-74">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-73">&#182;</a>
<a class="pilcrow" href="#section-74">&#182;</a>
</div>
<p>Initialize the <strong>Parser</strong> with our list of terminal <strong>tokens</strong>, our <strong>grammar</strong>
rules, and the name of the root. Reverse the operators because Jison orders

View File

@@ -274,6 +274,21 @@ setting <code>__filename</code>, <code>__dirname</code>, and relative <code>requ
<div class="pilwrap ">
<a class="pilcrow" href="#section-10">&#182;</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">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-12">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-13">&#182;</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">&#182;</a>
<a class="pilcrow" href="#section-14">&#182;</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">-&gt;</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">&#182;</a>
<a class="pilcrow" href="#section-15">&#182;</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">-&gt;</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> -&gt;</span>
CoffeeScript._compileFile = <span class="hljs-function"><span class="hljs-params">(filename, options = {})</span> -&gt;</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">&#182;</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">&#182;</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">&#182;</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>

View File

@@ -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]
@@ -1115,7 +1121,7 @@ comments that trail it.</p>
<div class="content"><div class='highlight'><pre> prevChar = <span class="hljs-keyword">if</span> @tokens.length &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">then</span> @tokens[@tokens.length - <span class="hljs-number">1</span>][<span class="hljs-number">0</span>] <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>
<span class="hljs-keyword">if</span> firstChar <span class="hljs-keyword">is</span> <span class="hljs-string">'&lt;'</span>
match = CSX_IDENTIFIER.exec @chunk[<span class="hljs-number">1.</span>..]
match = CSX_IDENTIFIER.exec(@chunk[<span class="hljs-number">1.</span>..]) <span class="hljs-keyword">or</span> CSX_FRAGMENT_IDENTIFIER.exec(@chunk[<span class="hljs-number">1.</span>..])
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span> <span class="hljs-keyword">unless</span> match <span class="hljs-keyword">and</span> (
@csxDepth &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">or</span></pre></div></div>
@@ -1181,8 +1187,8 @@ comments that trail it.</p>
@matchWithInterpolations INSIDE_CSX, <span class="hljs-string">'&gt;'</span>, <span class="hljs-string">'&lt;/'</span>, CSX_INTERPOLATION
@mergeInterpolationTokens tokens, {delimiter: <span class="hljs-string">'"'</span>}, <span class="hljs-function"><span class="hljs-params">(value, i)</span> =&gt;</span>
@formatString value, delimiter: <span class="hljs-string">'&gt;'</span>
match = CSX_IDENTIFIER.exec @chunk[end...]
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> match <span class="hljs-keyword">or</span> match[<span class="hljs-number">0</span>] <span class="hljs-keyword">isnt</span> csxTag.name
match = CSX_IDENTIFIER.exec(@chunk[end...]) <span class="hljs-keyword">or</span> CSX_FRAGMENT_IDENTIFIER.exec(@chunk[end...])
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> match <span class="hljs-keyword">or</span> match[<span class="hljs-number">1</span>] <span class="hljs-keyword">isnt</span> csxTag.name
@error <span class="hljs-string">"expected corresponding CSX closing tag for <span class="hljs-subst">#{csxTag.name}</span>"</span>,
csxTag.origin[<span class="hljs-number">2</span>]
afterTag = end + csxTag.name.length
@@ -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">-&gt;</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> -&gt;</span>
[..., token] = @tokens
token?[<span class="hljs-number">1</span>]</pre></div></div>
<span class="hljs-keyword">if</span> useOrigin <span class="hljs-keyword">and</span> token?.origin?
token.origin?[<span class="hljs-number">1</span>]
<span class="hljs-keyword">else</span>
token?[<span class="hljs-number">1</span>]</pre></div></div>
</li>
@@ -2449,6 +2458,23 @@ be used as identifiers or properties.</p>
CSX_IDENTIFIER = <span class="hljs-regexp">/// ^
(?![\d&lt;]) <span class="hljs-comment"># Must not start with `&lt;`.</span>
( (?: (?!\s)[\.\-$\w\x7f-\uffff] )+ ) <span class="hljs-comment"># Like `IDENTIFIER`, but includes `-`s and `.`s.</span>
///</span></pre></div></div>
</li>
<li id="section-98">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-98">&#182;</a>
</div>
<p>Fragment: &lt;&gt;&lt;/&gt;</p>
</div>
<div class="content"><div class='highlight'><pre>CSX_FRAGMENT_IDENTIFIER = <span class="hljs-regexp">/// ^
()&gt; <span class="hljs-comment"># Ends immediately with `&gt;`.</span>
///</span>
CSX_ATTRIBUTE = <span class="hljs-regexp">/// ^
@@ -2488,11 +2514,11 @@ HERE_JSTOKEN = <span class="hljs-regexp">///^ ``` ((?: [^`\\] | \\[\s\S] | `
</li>
<li id="section-98">
<li id="section-99">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-98">&#182;</a>
<a class="pilcrow" href="#section-99">&#182;</a>
</div>
<p>String-matching-regexes.</p>
@@ -2526,11 +2552,11 @@ HEREDOC_INDENT = <span class="hljs-regexp">/\n+([^\n\S]*)(?=\S)/g</span></pr
</li>
<li id="section-99">
<li id="section-100">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-99">&#182;</a>
<a class="pilcrow" href="#section-100">&#182;</a>
</div>
<p>Regex-matching-regexes.</p>
@@ -2549,7 +2575,86 @@ HEREDOC_INDENT = <span class="hljs-regexp">/\n+([^\n\S]*)(?=\S)/g</span></pr
REGEX_FLAGS = <span class="hljs-regexp">/^\w*/</span>
VALID_FLAGS = <span class="hljs-regexp">/^(?!.*(.).*\1)[imguy]*$/</span>
HEREGEX = <span class="hljs-regexp">/// ^(?: [^\\/<span class="hljs-comment">#] | \\[\s\S] | /(?!//) | \#(?!\{) )* ///</span>
HEREGEX = <span class="hljs-regexp">/// ^
(?:
</span></pre></div></div>
</li>
<li id="section-101">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-101">&#182;</a>
</div>
<p>Match any character, except those that need special handling below.</p>
</div>
<div class="content"><div class='highlight'><pre> [^\\/<span class="hljs-comment">#\s]</span></pre></div></div>
</li>
<li id="section-102">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-102">&#182;</a>
</div>
<p>Match <code>\</code> followed by any character.</p>
</div>
<div class="content"><div class='highlight'><pre> | \\[\s\S]</pre></div></div>
</li>
<li id="section-103">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-103">&#182;</a>
</div>
<p>Match any <code>/</code> except <code>///</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> | <span class="hljs-regexp">/(?!/</span>/)</pre></div></div>
</li>
<li id="section-104">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-104">&#182;</a>
</div>
<p>Match <code>#</code> which is not part of interpolation, e.g. <code>#{}</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> | \<span class="hljs-comment">#(?!\{)</span></pre></div></div>
</li>
<li id="section-105">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-105">&#182;</a>
</div>
<p>Comments consume everything until the end of the line, including <code>///</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> | \s+(?:<span class="hljs-comment">#(?!\{).*)?</span>
)*
<span class="hljs-regexp">///
HEREGEX_OMIT = ///</span>
((?:\\\\)+) <span class="hljs-comment"># Consume (and preserve) an even number of backslashes.</span>
@@ -2564,11 +2669,11 @@ POSSIBLY_DIVISION = <span class="hljs-regexp">/// ^ /=?\s ///</span></pre></di
</li>
<li id="section-100">
<li id="section-106">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-100">&#182;</a>
<a class="pilcrow" href="#section-106">&#182;</a>
</div>
<p>Other regexes.</p>
@@ -2611,11 +2716,11 @@ TRAILING_SPACES = <span class="hljs-regexp">/\s+$/</span></pre></div></div>
</li>
<li id="section-101">
<li id="section-107">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-101">&#182;</a>
<a class="pilcrow" href="#section-107">&#182;</a>
</div>
<p>Compound assignment tokens.</p>
@@ -2629,11 +2734,11 @@ TRAILING_SPACES = <span class="hljs-regexp">/\s+$/</span></pre></div></div>
</li>
<li id="section-102">
<li id="section-108">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-102">&#182;</a>
<a class="pilcrow" href="#section-108">&#182;</a>
</div>
<p>Unary tokens.</p>
@@ -2646,11 +2751,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
</li>
<li id="section-103">
<li id="section-109">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-103">&#182;</a>
<a class="pilcrow" href="#section-109">&#182;</a>
</div>
<p>Bit-shifting tokens.</p>
@@ -2661,11 +2766,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
</li>
<li id="section-104">
<li id="section-110">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-104">&#182;</a>
<a class="pilcrow" href="#section-110">&#182;</a>
</div>
<p>Comparison tokens.</p>
@@ -2676,11 +2781,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
</li>
<li id="section-105">
<li id="section-111">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-105">&#182;</a>
<a class="pilcrow" href="#section-111">&#182;</a>
</div>
<p>Mathematical tokens.</p>
@@ -2691,11 +2796,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
</li>
<li id="section-106">
<li id="section-112">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-106">&#182;</a>
<a class="pilcrow" href="#section-112">&#182;</a>
</div>
<p>Relational tokens that are negatable with <code>not</code> prefix.</p>
@@ -2706,11 +2811,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
</li>
<li id="section-107">
<li id="section-113">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-107">&#182;</a>
<a class="pilcrow" href="#section-113">&#182;</a>
</div>
<p>Boolean tokens.</p>
@@ -2721,11 +2826,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
</li>
<li id="section-108">
<li id="section-114">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-108">&#182;</a>
<a class="pilcrow" href="#section-114">&#182;</a>
</div>
<p>Tokens which could legitimately be invoked or indexed. An opening
parentheses or bracket following these tokens will be recorded as the start
@@ -2742,11 +2847,11 @@ INDEXABLE = CALLABLE.concat [
</li>
<li id="section-109">
<li id="section-115">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-109">&#182;</a>
<a class="pilcrow" href="#section-115">&#182;</a>
</div>
<p>Tokens which can be the left-hand side of a less-than comparison, i.e. <code>a&lt;b</code>.</p>
@@ -2757,11 +2862,11 @@ INDEXABLE = CALLABLE.concat [
</li>
<li id="section-110">
<li id="section-116">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-110">&#182;</a>
<a class="pilcrow" href="#section-116">&#182;</a>
</div>
<p>Tokens which a regular expression will never immediately follow (except spaced
CALLABLEs in some cases), but which a division operator can.</p>
@@ -2774,11 +2879,11 @@ CALLABLEs in some cases), but which a division operator can.</p>
</li>
<li id="section-111">
<li id="section-117">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-111">&#182;</a>
<a class="pilcrow" href="#section-117">&#182;</a>
</div>
<p>Tokens that, when immediately preceding a <code>WHEN</code>, indicate that the <code>WHEN</code>
occurs at the start of a line. We disambiguate these from trailing whens to
@@ -2791,11 +2896,11 @@ avoid an ambiguity in the grammar.</p>
</li>
<li id="section-112">
<li id="section-118">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-112">&#182;</a>
<a class="pilcrow" href="#section-118">&#182;</a>
</div>
<p>Additional indent in front of these is ignored.</p>
@@ -2806,11 +2911,11 @@ avoid an ambiguity in the grammar.</p>
</li>
<li id="section-113">
<li id="section-119">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-113">&#182;</a>
<a class="pilcrow" href="#section-119">&#182;</a>
</div>
<p>Tokens that, when appearing at the end of a line, suppress a following TERMINATOR/INDENT token</p>
@@ -2818,7 +2923,7 @@ avoid an ambiguity in the grammar.</p>
<div class="content"><div class='highlight'><pre>UNFINISHED = [<span class="hljs-string">'\\'</span>, <span class="hljs-string">'.'</span>, <span class="hljs-string">'?.'</span>, <span class="hljs-string">'?::'</span>, <span class="hljs-string">'UNARY'</span>, <span class="hljs-string">'MATH'</span>, <span class="hljs-string">'UNARY_MATH'</span>, <span class="hljs-string">'+'</span>, <span class="hljs-string">'-'</span>,
<span class="hljs-string">'**'</span>, <span class="hljs-string">'SHIFT'</span>, <span class="hljs-string">'RELATION'</span>, <span class="hljs-string">'COMPARE'</span>, <span class="hljs-string">'&amp;'</span>, <span class="hljs-string">'^'</span>, <span class="hljs-string">'|'</span>, <span class="hljs-string">'&amp;&amp;'</span>, <span class="hljs-string">'||'</span>,
<span class="hljs-string">'BIN?'</span>, <span class="hljs-string">'EXTENDS'</span>, <span class="hljs-string">'DEFAULT'</span>]</pre></div></div>
<span class="hljs-string">'BIN?'</span>, <span class="hljs-string">'EXTENDS'</span>]</pre></div></div>
</li>

File diff suppressed because it is too large Load Diff

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

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

View File

View 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> -&gt;</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">&#182;</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> -&gt;</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>

View File

@@ -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&gt; '</span>,
@@ -223,11 +224,17 @@ Unwrap that too.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-7">&#182;</a>
</div>
<p>Collect referenced variable names just like in <code>CoffeeScript.compile</code>.</p>
<p>Filter out tokens generated just to hold comments.</p>
</div>
<div class="content"><div class='highlight'><pre> referencedVars = (token[<span class="hljs-number">1</span>] <span class="hljs-keyword">for</span> token <span class="hljs-keyword">in</span> tokens <span class="hljs-keyword">when</span> token[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'IDENTIFIER'</span>)</pre></div></div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> tokens.length &gt;= <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> tokens[<span class="hljs-number">0</span>].generated <span class="hljs-keyword">and</span>
tokens[<span class="hljs-number">0</span>].comments?.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> tokens[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">''</span> <span class="hljs-keyword">and</span>
tokens[<span class="hljs-number">1</span>][<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'TERMINATOR'</span>
tokens = tokens[<span class="hljs-number">2.</span>..]
<span class="hljs-keyword">if</span> tokens.length &gt;= <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> tokens[tokens.length - <span class="hljs-number">1</span>].generated <span class="hljs-keyword">and</span>
tokens[tokens.length - <span class="hljs-number">1</span>].comments?.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> tokens[tokens.length - <span class="hljs-number">1</span>][<span class="hljs-number">1</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">''</span>
tokens.pop()</pre></div></div>
</li>
@@ -238,11 +245,11 @@ Unwrap that too.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-8">&#182;</a>
</div>
<p>Generate the AST of the tokens.</p>
<p>Collect referenced variable names just like in <code>CoffeeScript.compile</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> ast = CoffeeScript.nodes tokens</pre></div></div>
<div class="content"><div class='highlight'><pre> referencedVars = (token[<span class="hljs-number">1</span>] <span class="hljs-keyword">for</span> token <span class="hljs-keyword">in</span> tokens <span class="hljs-keyword">when</span> token[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'IDENTIFIER'</span>)</pre></div></div>
</li>
@@ -253,11 +260,11 @@ Unwrap that too.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-9">&#182;</a>
</div>
<p>Add assignment to <code>__</code> variable to force the input to be an expression.</p>
<p>Generate the AST of the tokens.</p>
</div>
<div class="content"><div class='highlight'><pre> ast = <span class="hljs-keyword">new</span> Block [<span class="hljs-keyword">new</span> Assign (<span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal <span class="hljs-string">'__'</span>), ast, <span class="hljs-string">'='</span>]</pre></div></div>
<div class="content"><div class='highlight'><pre> ast = CoffeeScript.nodes tokens</pre></div></div>
</li>
@@ -268,12 +275,11 @@ Unwrap that too.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-10">&#182;</a>
</div>
<p>Wrap the expression in a closure to support top-level <code>await</code></p>
<p>Add assignment to <code>__</code> variable to force the input to be an expression.</p>
</div>
<div class="content"><div class='highlight'><pre> ast = <span class="hljs-keyword">new</span> Code [], ast
isAsync = ast.isAsync</pre></div></div>
<div class="content"><div class='highlight'><pre> ast = <span class="hljs-keyword">new</span> Block [<span class="hljs-keyword">new</span> Assign (<span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal <span class="hljs-string">'__'</span>), ast, <span class="hljs-string">'='</span>]</pre></div></div>
</li>
@@ -284,13 +290,12 @@ Unwrap that too.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-11">&#182;</a>
</div>
<p>Invoke the wrapping closure</p>
<p>Wrap the expression in a closure to support top-level <code>await</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> ast = <span class="hljs-keyword">new</span> Block [<span class="hljs-keyword">new</span> Call ast]
js = ast.compile {bare: <span class="hljs-literal">yes</span>, locals: Object.keys(context), referencedVars, sharedScope: <span class="hljs-literal">yes</span>}
result = runInContext js, context, filename</pre></div></div>
<div class="content"><div class='highlight'><pre> ast = <span class="hljs-keyword">new</span> Code [], ast
isAsync = ast.isAsync</pre></div></div>
</li>
@@ -301,7 +306,42 @@ Unwrap that too.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-12">&#182;</a>
</div>
<p>Await an async result, if necessary</p>
<p>Invoke the wrapping closure.</p>
</div>
<div class="content"><div class='highlight'><pre> ast = <span class="hljs-keyword">new</span> Block [<span class="hljs-keyword">new</span> Call ast]
js = ast.compile {bare: <span class="hljs-literal">yes</span>, locals: Object.keys(context), referencedVars, sharedScope: <span class="hljs-literal">yes</span>}
<span class="hljs-keyword">if</span> transpile
js = transpile.transpile(js, transpile.options).code</pre></div></div>
</li>
<li id="section-13">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-13">&#182;</a>
</div>
<p>Strip <code>&quot;use strict&quot;</code>, to avoid an exception on assigning to
undeclared variable <code>__</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> js = js.replace <span class="hljs-regexp">/^"use strict"|^'use strict'/</span>, <span class="hljs-string">''</span>
result = runInContext js, context, filename</pre></div></div>
</li>
<li id="section-14">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-14">&#182;</a>
</div>
<p>Await an async result, if necessary.</p>
</div>
@@ -316,11 +356,11 @@ Unwrap that too.</p>
</li>
<li id="section-13">
<li id="section-15">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-13">&#182;</a>
<a class="pilcrow" href="#section-15">&#182;</a>
</div>
<p>ASTs <code>compile</code> does not add source code information to syntax errors.</p>
@@ -341,11 +381,11 @@ Unwrap that too.</p>
</li>
<li id="section-14">
<li id="section-16">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-14">&#182;</a>
<a class="pilcrow" href="#section-16">&#182;</a>
</div>
<p>Node 0.11.12 changed API, prompt is now _prompt.</p>
@@ -362,11 +402,11 @@ Unwrap that too.</p>
</li>
<li id="section-15">
<li id="section-17">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-15">&#182;</a>
<a class="pilcrow" href="#section-17">&#182;</a>
</div>
<p>Proxy nodes line listener</p>
@@ -387,11 +427,11 @@ Unwrap that too.</p>
</li>
<li id="section-16">
<li id="section-18">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-16">&#182;</a>
<a class="pilcrow" href="#section-18">&#182;</a>
</div>
<p>Handle Ctrl-v</p>
@@ -404,11 +444,11 @@ Unwrap that too.</p>
</li>
<li id="section-17">
<li id="section-19">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-17">&#182;</a>
<a class="pilcrow" href="#section-19">&#182;</a>
</div>
<p>allow arbitrarily switching between modes any time before multiple lines are entered</p>
@@ -423,11 +463,11 @@ Unwrap that too.</p>
</li>
<li id="section-18">
<li id="section-20">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-18">&#182;</a>
<a class="pilcrow" href="#section-20">&#182;</a>
</div>
<p>no-op unless the current line is empty</p>
@@ -438,11 +478,11 @@ Unwrap that too.</p>
</li>
<li id="section-19">
<li id="section-21">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-19">&#182;</a>
<a class="pilcrow" href="#section-21">&#182;</a>
</div>
<p>eval, print, loop</p>
@@ -457,11 +497,11 @@ Unwrap that too.</p>
</li>
<li id="section-20">
<li id="section-22">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-20">&#182;</a>
<a class="pilcrow" href="#section-22">&#182;</a>
</div>
<p>XXX: multiline hack</p>
@@ -479,11 +519,11 @@ Unwrap that too.</p>
</li>
<li id="section-21">
<li id="section-23">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-21">&#182;</a>
<a class="pilcrow" href="#section-23">&#182;</a>
</div>
<p>Store and load command history from a file</p>
@@ -496,11 +536,11 @@ Unwrap that too.</p>
</li>
<li id="section-22">
<li id="section-24">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-22">&#182;</a>
<a class="pilcrow" href="#section-24">&#182;</a>
</div>
<p>Get file info and at most maxSize of command history</p>
@@ -512,11 +552,11 @@ Unwrap that too.</p>
</li>
<li id="section-23">
<li id="section-25">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-23">&#182;</a>
<a class="pilcrow" href="#section-25">&#182;</a>
</div>
<p>Read last <code>size</code> bytes from the file</p>
@@ -530,11 +570,11 @@ Unwrap that too.</p>
</li>
<li id="section-24">
<li id="section-26">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-24">&#182;</a>
<a class="pilcrow" href="#section-26">&#182;</a>
</div>
<p>Set the history on the interpreter</p>
@@ -545,11 +585,11 @@ Unwrap that too.</p>
</li>
<li id="section-25">
<li id="section-27">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-25">&#182;</a>
<a class="pilcrow" href="#section-27">&#182;</a>
</div>
<p>If the history file was truncated we should pop off a potential partial line</p>
@@ -560,11 +600,11 @@ Unwrap that too.</p>
</li>
<li id="section-26">
<li id="section-28">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-26">&#182;</a>
<a class="pilcrow" href="#section-28">&#182;</a>
</div>
<p>Shift off the final blank newline</p>
@@ -582,11 +622,11 @@ Unwrap that too.</p>
</li>
<li id="section-27">
<li id="section-29">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-27">&#182;</a>
<a class="pilcrow" href="#section-29">&#182;</a>
</div>
<p>Save the latest command in the file</p>
@@ -598,11 +638,11 @@ Unwrap that too.</p>
</li>
<li id="section-28">
<li id="section-30">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-28">&#182;</a>
<a class="pilcrow" href="#section-30">&#182;</a>
</div>
<p>XXX: The SIGINT event from REPLServer is undocumented, so this is a bit fragile</p>
@@ -614,11 +654,11 @@ Unwrap that too.</p>
</li>
<li id="section-29">
<li id="section-31">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-29">&#182;</a>
<a class="pilcrow" href="#section-31">&#182;</a>
</div>
<p>Add a command to show the history stack</p>
@@ -635,11 +675,11 @@ Unwrap that too.</p>
</li>
<li id="section-30">
<li id="section-32">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-30">&#182;</a>
<a class="pilcrow" href="#section-32">&#182;</a>
</div>
<p>Node 0.11 changed API, a command such as .help is now stored as help</p>
@@ -658,6 +698,44 @@ Unwrap that too.</p>
CoffeeScript.register()
process.argv = [<span class="hljs-string">'coffee'</span>].concat process.argv[<span class="hljs-number">2.</span>.]
<span class="hljs-keyword">if</span> opts.transpile
<span class="hljs-keyword">try</span>
transpile = {}
transpile.transpile = <span class="hljs-built_in">require</span>(<span class="hljs-string">'babel-core'</span>).transform
<span class="hljs-keyword">catch</span>
<span class="hljs-built_in">console</span>.error <span class="hljs-string">'''
To use --transpile with an interactive REPL, babel-core must be installed either in the current folder or globally:
npm install --save-dev babel-core
or
npm install --global babel-core
And you must save options to configure Babel in one of the places it looks to find its options.
See http://coffeescript.org/#transpilation
'''</span>
process.exit <span class="hljs-number">1</span>
transpile.options =
filename: path.resolve process.cwd(), <span class="hljs-string">'&lt;repl&gt;'</span></pre></div></div>
</li>
<li id="section-33">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-33">&#182;</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> -&gt;</span>
@options = transpile: transpile.options
originalModuleLoad.call @, filename
opts = merge replDefaults, opts
repl = nodeREPL.start opts
runInContext opts.prelude, repl.context, <span class="hljs-string">'prelude'</span> <span class="hljs-keyword">if</span> opts.prelude
@@ -668,11 +746,11 @@ Unwrap that too.</p>
</li>
<li id="section-31">
<li id="section-34">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-31">&#182;</a>
<a class="pilcrow" href="#section-34">&#182;</a>
</div>
<p>Adapt help inherited from the node REPL</p>

View File

@@ -916,7 +916,7 @@ e = <span class="hljs-number">2</span>
</code></pre>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">','</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @looksObjectish(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">and</span> inImplicitObject() <span class="hljs-keyword">and</span>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">','</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @looksObjectish(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">and</span> inImplicitObject() <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> (@tag(i + <span class="hljs-number">2</span>) <span class="hljs-keyword">in</span> [<span class="hljs-string">'FOROF'</span>, <span class="hljs-string">'FORIN'</span>]) <span class="hljs-keyword">and</span>
(nextTag <span class="hljs-keyword">isnt</span> <span class="hljs-string">'TERMINATOR'</span> <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> @looksObjectish(i + <span class="hljs-number">2</span>))</pre></div></div>
</li>
@@ -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>

View File

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

View File

@@ -619,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>&lt;</code> and <code>&gt;</code> Operators</a>
<a href="#breaking-changes-literate-coffeescript" class="nav-link" data-action="sidebar-nav">Literate CoffeeScript Parsing</a>
@@ -645,7 +646,7 @@ div.CodeMirror-cursor {
<section id="overview">
<p><strong>CoffeeScript is a little language that compiles into JavaScript.</strong> Underneath that awkward Java-esque patina, JavaScript has always had a gorgeous heart. CoffeeScript is an attempt to expose the good parts of JavaScript in a simple way.</p>
<p>The golden rule of CoffeeScript is: <em>“Its just JavaScript.”</em> The code compiles one-to-one into the equivalent JS, and there is no interpretation at runtime. You can use any existing JavaScript library seamlessly from CoffeeScript (and vice-versa). The compiled output is readable, pretty-printed, and tends to run as fast or faster than the equivalent handwritten JavaScript.</p>
<p><strong>Latest Version:</strong> <a href="https://github.com/jashkenas/coffeescript/tarball/2.0.1">2.0.1</a></p>
<p><strong>Latest Version:</strong> <a href="https://github.com/jashkenas/coffeescript/tarball/2.1.1">2.1.1</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
@@ -1342,36 +1343,6 @@ kids = {
</div>
</div>
</aside>
<p>In JavaScript, you cant use reserved words, like <code>class</code>, as properties of an object, without quoting them as strings. CoffeeScript notices reserved words used as keys in objects and quotes them for you, so you dont have to worry about it (say, when using jQuery).</p>
<aside class="code-example container-fluid bg-ribbed-dark" data-example="objects_reserved">
<div class="row">
<div class="col-md-6 coffeescript-input-column">
<textarea class="coffeescript-input" id="objects_reserved-coffee">$('.account').prop class: 'active'
log object.class
</textarea>
<pre class="placeholder-code"><span class="cm-variable">$</span><span class="cm-punctuation">(</span><span class="cm-string">'.account'</span><span class="cm-punctuation">).</span><span class="cm-property">prop</span> <span class="cm-keyword">class</span><span class="cm-punctuation">:</span> <span class="cm-string">'active'</span>
<span class="cm-variable">log</span> <span class="cm-variable">object</span><span class="cm-punctuation">.</span><span class="cm-property">class</span>
</pre>
</div>
<div class="col-md-6 javascript-output-column">
<textarea class="javascript-output" id="objects_reserved-js">$('.account').prop({
class: 'active'
});
log(object.class);
</textarea>
<pre class="placeholder-code"><span class="cm-variable">$</span>(<span class="cm-string">'.account'</span>).<span class="cm-property">prop</span>({
<span class="cm-property">class</span>: <span class="cm-string">'active'</span>
});
<span class="cm-variable">log</span>(<span class="cm-variable">object</span>.<span class="cm-property">class</span>);
</pre>
</div>
</div>
</aside>
<p>CoffeeScript has a shortcut for creating objects when you want the key to be set with a variable of the same name.</p>
<aside class="code-example container-fluid bg-ribbed-dark" data-example="objects_shorthand">
@@ -2488,7 +2459,7 @@ alert((function() {
<span class="cm-variable">alert</span>((<span class="cm-keyword">function</span>() {
<span class="cm-keyword">try</span> {
<span class="cm-keyword">return</span> <span class="cm-variable">nonexistent</span> <span class="cm-operator">/</span> <span class="cm-variable">void</span> <span class="cm-number">0</span>;
<span class="cm-keyword">return</span> <span class="cm-variable">nonexistent</span> <span class="cm-operator">/</span> <span class="cm-keyword">void</span> <span class="cm-number">0</span>;
} <span class="cm-keyword">catch</span> (<span class="cm-def">error1</span>) {
<span class="cm-variable">error</span> <span class="cm-operator">=</span> <span class="cm-variable-2">error1</span>;
<span class="cm-keyword">return</span> <span class="cm-string-2">`And the error is ... ${</span><span class="cm-variable">error</span><span class="cm-string-2">}`</span>;
@@ -2522,7 +2493,7 @@ alert((function() {
<p>As a shortcut for <code>this.property</code>, you can use <code>@property</code>.</p>
<p>You can use <code>in</code> to test for array presence, and <code>of</code> to test for JavaScript object-key presence.</p>
<p>In a <code>for</code> loop, <code>from</code> compiles to the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of">ES2015 <code>of</code></a>. (Yes, its unfortunate; the CoffeeScript <code>of</code> predates the ES2015 <code>of</code>.)</p>
<p>To simplify math expressions, <code>**</code> can be used for exponentiation and <code>//</code> performs integer division. <code>%</code> works just like in JavaScript, while <code>%%</code> provides <a href="https://en.wikipedia.org/wiki/Modulo_operation">“dividend dependent modulo”</a>:</p>
<p>To simplify math expressions, <code>**</code> can be used for exponentiation and <code>//</code> performs floor division. <code>%</code> works just like in JavaScript, while <code>%%</code> provides <a href="https://en.wikipedia.org/wiki/Modulo_operation">“dividend dependent modulo”</a>:</p>
<aside class="code-example container-fluid bg-ribbed-dark" data-example="modulo">
<div class="row">
<div class="col-md-6 coffeescript-input-column">
@@ -2852,7 +2823,7 @@ zip = typeof lottery.drawWinner === "function" ? (ref = lottery.drawWinner().add
</textarea>
<pre class="placeholder-code"><span class="cm-keyword">var</span> <span class="cm-def">ref</span>, <span class="cm-def">zip</span>;
<span class="cm-variable">zip</span> <span class="cm-operator">=</span> <span class="cm-keyword">typeof</span> <span class="cm-variable">lottery</span>.<span class="cm-property">drawWinner</span> <span class="cm-operator">===</span> <span class="cm-string">"function"</span> <span class="cm-operator">?</span> (<span class="cm-variable">ref</span> <span class="cm-operator">=</span> <span class="cm-variable">lottery</span>.<span class="cm-property">drawWinner</span>().<span class="cm-property">address</span>) <span class="cm-operator">!=</span> <span class="cm-atom">null</span> <span class="cm-operator">?</span> <span class="cm-variable">ref</span>.<span class="cm-property">zipcode</span> : <span class="cm-variable">void</span> <span class="cm-number">0</span> : <span class="cm-variable">void</span> <span class="cm-number">0</span>;
<span class="cm-variable">zip</span> <span class="cm-operator">=</span> <span class="cm-keyword">typeof</span> <span class="cm-variable">lottery</span>.<span class="cm-property">drawWinner</span> <span class="cm-operator">===</span> <span class="cm-string">"function"</span> <span class="cm-operator">?</span> (<span class="cm-variable">ref</span> <span class="cm-operator">=</span> <span class="cm-variable">lottery</span>.<span class="cm-property">drawWinner</span>().<span class="cm-property">address</span>) <span class="cm-operator">!=</span> <span class="cm-atom">null</span> <span class="cm-operator">?</span> <span class="cm-variable">ref</span>.<span class="cm-property">zipcode</span> : <span class="cm-keyword">void</span> <span class="cm-number">0</span> : <span class="cm-keyword">void</span> <span class="cm-number">0</span>;
</pre>
</div>
</div>
@@ -4634,25 +4605,25 @@ fn = (str ###: string ###, obj ###: Obj ###) ###: string ### ->
</div>
<div class="col-md-6 javascript-output-column">
<textarea class="javascript-output" id="type_annotations-js">// @flow
var fn;
/*::
type Obj = {
num: number,
};
*/
var fn;
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-keyword">var</span> <span class="cm-def">fn</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">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>;
};
@@ -4753,7 +4724,6 @@ task('build:parser', 'rebuild the Jison parser', function(options) {
<section id="scripts">
<h2><code>&quot;text/coffeescript&quot;</code> Script Tags</h2>
<p>While its not recommended for serious use, CoffeeScripts may be included directly within the browser using <code>&lt;script type=&quot;text/coffeescript&quot;&gt;</code> tags. The source includes a compressed and minified version of the compiler (<a href="/v2/browser-compiler/coffeescript.js">Download current version here, 51k when gzipped</a>) as <code>docs/v2/browser-compiler/coffeescript.js</code>. Include this file on a page with inline CoffeeScript tags, and it will compile and evaluate them in order.</p>
<p>In fact, the little bit of glue script that runs <a href="#try">Try CoffeeScript</a>, as well as the code examples and other interactive parts of this site, is implemented in just this way. View source and look at the bottom of the page to see the example. Including the script also gives you access to <code>CoffeeScript.compile()</code> so you can pop open your JavaScript console and try compiling some strings.</p>
<p>The usual caveats about CoffeeScript apply — your inline scripts will run within a closure wrapper, so if you want to expose global variables or functions, attach them to the <code>window</code> object.</p>
</section>
@@ -4820,7 +4790,7 @@ The CoffeeScript logo is available in SVG for use in presentations.</li>
</section>
<section id="annotated-source">
<h2>Annotated Source</h2>
<p>You can browse the CoffeeScript 2.0.1 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.1.1 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>
@@ -5150,10 +5120,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">-&gt;</span> <span class="keyword">this</span> <span class="comment"># Throws a compiler error</span>
</code></pre>
</blockquote><p>ES2015 classes dont allow bound (fat arrow) methods. The CoffeeScript compiler goes through some contortions to preserve support for them, but one thing that cant 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">-&gt;</span>
@@ -5177,6 +5143,59 @@ f = function*() {
@::[name] = <span class="function">-&gt;</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">-&gt;</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> -&gt;</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>
@@ -5448,6 +5467,53 @@ x = <span class="number">2</span> + <span class="number">2</span>
</section>
<section id="changelog">
<h2>Changelog</h2>
<div class="anchor" id="2.1.1"></div>
<h2 class="header">
<a href="https://github.com/jashkenas/coffeescript/compare/2.1.0...2.1.1">2.1.1</a>
<span class="timestamp"> &mdash; <time datetime="2017-12-29">December 29, 2017</time></span>
</h2><ul>
<li>Bugfix to set the correct context for executable class bodies. So in <code>class @B extends @A then @property = 1</code>, the <code>@</code> in <code>@property</code> now refers to the class, not the global object.</li>
<li>Bugfix where anonymous classes were getting created using the same automatic variable name. They now each receive unique names, so as not to override each other.</li>
</ul>
<div class="anchor" id="2.1.0"></div>
<h2 class="header">
<a href="https://github.com/jashkenas/coffeescript/compare/2.0.3...2.1.0">2.1.0</a>
<span class="timestamp"> &mdash; <time datetime="2017-12-10">December 10, 2017</time></span>
</h2><ul>
<li>Computed property keys in object literals are now supported: <code>obj = { ['key' + i]: 42 }</code>, or <code>obj = [Symbol.iterator]: -&gt; yield i++</code>.</li>
<li>Skipping of array elements, a.k.a. elision, is now supported: <code>arr = [a, , b]</code>, or <code>[, protocol] = url.match /^(.*):\/\//</code>.</li>
<li><a href="https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html">JSX fragments syntax</a> is now supported.</li>
<li>Bugfix where <code>///</code> within a <code>#</code> line comment inside a <code>///</code> block regex was erroneously closing the regex, rather than being treated as part of the comment.</li>
<li>Bugfix for incorrect output for object rest destructuring inside array destructuring.</li>
</ul>
<div class="anchor" id="2.0.3"></div>
<h2 class="header">
<a href="https://github.com/jashkenas/coffeescript/compare/2.0.2...2.0.3">2.0.3</a>
<span class="timestamp"> &mdash; <time datetime="2017-11-26">November 26, 2017</time></span>
</h2><ul>
<li>Bugfix for <code>export default</code> followed by an implicit object that contains an explicit object, for example <code>exportedMember: { obj... }</code>.</li>
<li>Bugfix for <code>key, val of obj</code> after an implicit object member, e.g. <code>foo: bar for key, val of obj</code>.</li>
<li>Bugfix for combining array and object destructuring, e.g. <code>[ ..., {a, b} ] = arr</code>.</li>
<li>Bugfix for an edge case where it was possible to create a bound (<code>=&gt;</code>) generator function, which should throw an error as such functions arent allowed in ES2015.</li>
<li>Bugfix for source maps: <code>.map</code> files should always have the same base filename as the requested output filename. So <code>coffee --map --output foo.js test.coffee</code> should generate <code>foo.js</code> and <code>foo.js.map</code>.</li>
<li>Bugfix for incorrect source maps generated when using <code>--transpile</code> with <code>--map</code> for multiple input files.</li>
<li>Bugfix for comments at the beginning or end of input into the REPL (<code>coffee --interactive</code>).</li>
</ul>
<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"> &mdash; <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 theyre 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) -&gt; super(@arg)</code>. This isnt 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) -&gt; 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>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
class B extends A
constructor: (arg) ->
super arg
@arg = arg

View File

@@ -9,13 +9,6 @@ Class constructors cant 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 dont allow bound (fat arrow) methods. The CoffeeScript compiler goes through some contortions to preserve support for them, but one thing that cant be accommodated is calling a bound method before it is bound:
```coffee

View 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')
```

View File

@@ -1,5 +1,48 @@
## Changelog
```
releaseHeader('2017-12-29', '2.1.1', '2.1.0')
```
* Bugfix to set the correct context for executable class bodies. So in `class @B extends @A then @property = 1`, the `@` in `@property` now refers to the class, not the global object.
* Bugfix where anonymous classes were getting created using the same automatic variable name. They now each receive unique names, so as not to override each other.
```
releaseHeader('2017-12-10', '2.1.0', '2.0.3')
```
* Computed property keys in object literals are now supported: `obj = { ['key' + i]: 42 }`, or `obj = [Symbol.iterator]: -> yield i++`.
* Skipping of array elements, a.k.a. elision, is now supported: `arr = [a, , b]`, or `[, protocol] = url.match /^(.*):\/\//`.
* [JSX fragments syntax](https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html) is now supported.
* Bugfix where `///` within a `#` line comment inside a `///` block regex was erroneously closing the regex, rather than being treated as part of the comment.
* Bugfix for incorrect output for object rest destructuring inside array destructuring.
```
releaseHeader('2017-11-26', '2.0.3', '2.0.2')
```
* Bugfix for `export default` followed by an implicit object that contains an explicit object, for example `exportedMember: { obj... }`.
* Bugfix for `key, val of obj` after an implicit object member, e.g. `foo: bar for key, val of obj`.
* Bugfix for combining array and object destructuring, e.g. `[ ..., {a, b} ] = arr`.
* Bugfix for an edge case where it was possible to create a bound (`=>`) generator function, which should throw an error as such functions arent allowed in ES2015.
* Bugfix for source maps: `.map` files should always have the same base filename as the requested output filename. So `coffee --map --output foo.js test.coffee` should generate `foo.js` and `foo.js.map`.
* Bugfix for incorrect source maps generated when using `--transpile` with `--map` for multiple input files.
* Bugfix for comments at the beginning or end of input into the REPL (`coffee --interactive`).
```
releaseHeader('2017-10-26', '2.0.2', '2.0.1')
```
* `--transpile` now also applies to `require`d or `import`ed CoffeeScript files.
* `--transpile` can be used with the REPL: `coffee --interactive --transpile`.
* Improvements to comments output that should now cover all of the [Flow comment-based syntax](https://flow.org/en/docs/types/comments/). Inline `###` comments near [variable](https://flow.org/en/docs/types/variables/) initial assignments are now output in the variable declaration statement, and `###` comments near a [class and method names](https://flow.org/en/docs/types/generics/) are now output where Flow expects them.
* Importing CoffeeScript keywords is now allowed, so long as theyre 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 isnt 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')
```

View File

@@ -6,12 +6,6 @@ The CoffeeScript literals for objects and arrays look very similar to their Java
codeFor('objects_and_arrays', 'song.join(" … ")')
```
In JavaScript, you cant use reserved words, like `class`, as properties of an object, without quoting them as strings. CoffeeScript notices reserved words used as keys in objects and quotes them for you, so you dont have to worry about it (say, when using jQuery).
```
codeFor('objects_reserved')
```
CoffeeScript has a shortcut for creating objects when you want the key to be set with a variable of the same name.
```

View File

@@ -18,7 +18,7 @@ You can use `in` to test for array presence, and `of` to test for JavaScript obj
In a `for` loop, `from` compiles to the [ES2015 `of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of). (Yes, its unfortunate; the CoffeeScript `of` predates the ES2015 `of`.)
To simplify math expressions, `**` can be used for exponentiation and `//` performs integer division. `%` works just like in JavaScript, while `%%` provides [“dividend dependent modulo”](https://en.wikipedia.org/wiki/Modulo_operation):
To simplify math expressions, `**` can be used for exponentiation and `//` performs floor division. `%` works just like in JavaScript, while `%%` provides [“dividend dependent modulo”](https://en.wikipedia.org/wiki/Modulo_operation):
```
codeFor('modulo')

View File

@@ -2,6 +2,4 @@
While its not recommended for serious use, CoffeeScripts may be included directly within the browser using `<script type="text/coffeescript">` tags. The source includes a compressed and minified version of the compiler ([Download current version here, 51k when gzipped](/v<%= majorVersion %>/browser-compiler/coffeescript.js)) as `docs/v<%= majorVersion %>/browser-compiler/coffeescript.js`. Include this file on a page with inline CoffeeScript tags, and it will compile and evaluate them in order.
In fact, the little bit of glue script that runs [Try CoffeeScript](#try), as well as the code examples and other interactive parts of this site, is implemented in just this way. View source and look at the bottom of the page to see the example. Including the script also gives you access to `CoffeeScript.compile()` so you can pop open your JavaScript console and try compiling some strings.
The usual caveats about CoffeeScript apply — your inline scripts will run within a closure wrapper, so if you want to expose global variables or functions, attach them to the `window` object.

View File

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

View File

@@ -71,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>&lt;</code> and <code>&gt;</code> Operators</a>
<a href="#breaking-changes-literate-coffeescript" class="nav-link" data-action="sidebar-nav">Literate CoffeeScript Parsing</a>

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.0.1
// Generated by CoffeeScript 2.1.1
(function() {
// This **Browser** compatibility layer extends core CoffeeScript functions
// to make things work smoothly when compiling code directly in the browser.

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.0.1
// Generated by CoffeeScript 2.1.1
(function() {
// `cake` is a simplified version of [Make](http://www.gnu.org/software/make/)
// ([Rake](http://rake.rubyforge.org/), [Jake](https://github.com/280north/jake))

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.0.1
// Generated by CoffeeScript 2.1.1
(function() {
// CoffeeScript can be used both on the server, as a command-line compiler based
// on Node.js/V8, or to run CoffeeScript directly in the browser. This module
@@ -85,7 +85,7 @@
// object, where sourceMap is a sourcemap.coffee#SourceMap object, handy for
// doing programmatic lookups.
exports.compile = compile = withPrettyErrors(function(code, options = {}) {
var currentColumn, currentLine, encoded, filename, fragment, fragments, generateSourceMap, header, i, j, js, len, len1, map, newLines, ref, ref1, sourceMapDataURI, sourceURL, token, tokens, transpiler, transpilerOutput, v3SourceMap;
var currentColumn, currentLine, encoded, filename, fragment, fragments, generateSourceMap, header, i, j, js, len, len1, map, newLines, ref, ref1, sourceMapDataURI, sourceURL, token, tokens, transpiler, transpilerOptions, transpilerOutput, v3SourceMap;
// Clone `options`, to avoid mutating the `options` object passed in.
options = Object.assign({}, options);
// Always generate a source map if no filename is passed in, since without a
@@ -177,13 +177,14 @@
// is run via the CLI or Node API.
transpiler = options.transpile.transpile;
delete options.transpile.transpile;
transpilerOptions = Object.assign({}, options.transpile);
// See https://github.com/babel/babel/issues/827#issuecomment-77573107:
// Babel can take a v3 source map object as input in `inputSourceMap`
// and it will return an *updated* v3 source map object in its output.
if (v3SourceMap && (options.transpile.inputSourceMap == null)) {
options.transpile.inputSourceMap = v3SourceMap;
if (v3SourceMap && (transpilerOptions.inputSourceMap == null)) {
transpilerOptions.inputSourceMap = v3SourceMap;
}
transpilerOutput = transpiler(js, options.transpile);
transpilerOutput = transpiler(js, transpilerOptions);
js = transpilerOutput.code;
if (v3SourceMap && transpilerOutput.map) {
v3SourceMap = transpilerOutput.map;

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.0.1
// Generated by CoffeeScript 2.1.1
(function() {
// The `coffee` utility. Handles command-line compilation of CoffeeScript
// into various forms: saved into `.js` files or printed to stdout
@@ -92,6 +92,7 @@
opts.prelude = makePrelude(opts.require);
}
replCliOpts.prelude = opts.prelude;
replCliOpts.transpile = opts.transpile;
if (opts.nodejs) {
return forkNode();
}
@@ -303,6 +304,10 @@
// and write them back to **stdout**.
compileStdio = function() {
var buffers, stdin;
if (opts.map) {
console.error('--stdio and --map cannot be used together');
process.exit(1);
}
buffers = [];
stdin = process.openStdin();
stdin.on('data', function(buffer) {
@@ -529,7 +534,7 @@
// same directory as the `.js` file.
writeJs = function(base, sourcePath, js, jsPath, generatedSourceMap = null) {
var compile, jsDir, sourceMapPath;
sourceMapPath = outputPath(sourcePath, base, ".js.map");
sourceMapPath = `${jsPath}.map`;
jsDir = path.dirname(jsPath);
compile = function() {
if (opts.compile) {

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.0.1
// Generated by CoffeeScript 2.1.1
(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
@@ -282,7 +282,15 @@
});
})
],
SimpleObjAssignable: [o('Identifier'), o('Property'), o('ThisProperty')],
SimpleObjAssignable: [
o('Identifier'),
o('Property'),
o('ThisProperty'),
o('[ Expression ]',
function() {
return new Value(new ComputedPropertyName($2));
})
],
ObjAssignable: [o('SimpleObjAssignable'), o('AlphaNumeric')],
// Object literal spread properties.
ObjRestValue: [
@@ -389,7 +397,8 @@
function() {
return new Code($2,
$5,
$4);
$4,
LOC(1)(new Literal($1)));
}),
o('FuncGlyph Block',
function() {
@@ -821,6 +830,10 @@
function() {
return new ExportDefaultDeclaration($3);
}),
o('EXPORT DEFAULT INDENT Object OUTDENT',
function() {
return new ExportDefaultDeclaration(new Value($4));
}),
o('EXPORT EXPORT_ALL FROM String',
function() {
return new ExportAllDeclaration(new Literal($2),
@@ -949,9 +962,14 @@
function() {
return new Arr([]);
}),
o('[ ArgList OptComma ]',
o('[ Elisions ]',
function() {
return new Arr($2);
}),
o('[ ArgElisionList OptElisions ]',
function() {
return new Arr([].concat($2,
$3));
})
],
// Inclusive and exclusive range dots.
@@ -1001,8 +1019,7 @@
$1);
})
],
// The **ArgList** is both the list of objects passed into a function call,
// as well as the contents of an array literal
// The **ArgList** is the list of objects passed into a function call
// (i.e. comma-separated expressions). Newlines work as well.
ArgList: [
o('Arg',
@@ -1035,6 +1052,66 @@
return new Expansion;
})
],
// The **ArgElisionList** is the list of objects, contents of an array literal
// (i.e. comma-separated expressions and elisions). Newlines work as well.
ArgElisionList: [
o('ArgElision'),
o('ArgElisionList , ArgElision',
function() {
return $1.concat($3);
}),
o('ArgElisionList OptElisions TERMINATOR ArgElision',
function() {
return $1.concat($2,
$4);
}),
o('INDENT ArgElisionList OptElisions OUTDENT',
function() {
return $2.concat($3);
}),
o('ArgElisionList OptElisions INDENT ArgElisionList OptElisions OUTDENT',
function() {
return $1.concat($2,
$4,
$5);
})
],
ArgElision: [
o('Arg',
function() {
return [$1];
}),
o('Elisions Arg',
function() {
return $1.concat($2);
})
],
OptElisions: [
o('OptComma',
function() {
return [];
}),
o(', Elisions',
function() {
return [].concat($2);
})
],
Elisions: [
o('Elision',
function() {
return [$1];
}),
o('Elisions Elision',
function() {
return $1.concat($2);
})
],
Elision: [
o(',',
function() {
return new Elision;
})
],
// Just simple, comma-separated, required arguments (no fancy syntax). We need
// this to be separate from the **ArgList** for use in **Switch** blocks, where
// having the newlines wouldn't make sense.

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.0.1
// Generated by CoffeeScript 2.1.1
(function() {
// This file contains the common helper functions that we'd like to share among
// the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten

View File

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

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.0.1
// Generated by CoffeeScript 2.1.1
(function() {
// The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt
// matches against the beginning of the source code. When a match is found,
@@ -10,7 +10,7 @@
// where locationData is {first_line, first_column, last_line, last_column}, which is a
// format that can be fed directly into [Jison](https://github.com/zaach/jison). These
// are read by jison in the `parser.lexer` function defined in coffeescript.coffee.
var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARABLE_LEFT_SIDE, COMPARE, COMPOUND_ASSIGN, CSX_ATTRIBUTE, CSX_IDENTIFIER, CSX_INTERPOLATION, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, HERE_JSTOKEN, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INSIDE_CSX, INVERSES, JSTOKEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, REGEX_INVALID_ESCAPE, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_INVALID_ESCAPE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, UNFINISHED, UNICODE_CODE_POINT_ESCAPE, VALID_FLAGS, WHITESPACE, attachCommentsToNode, compact, count, invertLiterate, isForFrom, isUnassignable, key, locationDataToString, merge, repeat, starts, throwSyntaxError,
var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARABLE_LEFT_SIDE, COMPARE, COMPOUND_ASSIGN, CSX_ATTRIBUTE, CSX_FRAGMENT_IDENTIFIER, CSX_IDENTIFIER, CSX_INTERPOLATION, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, HERE_JSTOKEN, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INSIDE_CSX, INVERSES, JSTOKEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, REGEX_INVALID_ESCAPE, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_INVALID_ESCAPE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, UNFINISHED, UNICODE_CODE_POINT_ESCAPE, VALID_FLAGS, WHITESPACE, attachCommentsToNode, compact, count, invertLiterate, isForFrom, isUnassignable, key, locationDataToString, merge, repeat, starts, throwSyntaxError,
indexOf = [].indexOf;
({Rewriter, INVERSES} = require('./rewriter'));
@@ -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];
@@ -732,7 +741,7 @@
// Check the previous token to detect if attribute is spread.
prevChar = this.tokens.length > 0 ? this.tokens[this.tokens.length - 1][0] : '';
if (firstChar === '<') {
match = CSX_IDENTIFIER.exec(this.chunk.slice(1));
match = CSX_IDENTIFIER.exec(this.chunk.slice(1)) || CSX_FRAGMENT_IDENTIFIER.exec(this.chunk.slice(1));
// Not the right hand side of an unspaced comparison (i.e. `a<b`).
if (!(match && (this.csxDepth > 0 || !(prev = this.prev()) || prev.spaced || (ref = prev[0], indexOf.call(COMPARABLE_LEFT_SIDE, ref) < 0)))) {
return 0;
@@ -784,8 +793,8 @@
delimiter: '>'
});
});
match = CSX_IDENTIFIER.exec(this.chunk.slice(end));
if (!match || match[0] !== csxTag.name) {
match = CSX_IDENTIFIER.exec(this.chunk.slice(end)) || CSX_FRAGMENT_IDENTIFIER.exec(this.chunk.slice(end));
if (!match || match[1] !== csxTag.name) {
this.error(`expected corresponding CSX closing tag for ${csxTag.name}`, csxTag.origin[2]);
}
afterTag = end + csxTag.name.length;
@@ -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.
@@ -1528,6 +1541,9 @@
CSX_IDENTIFIER = /^(?![\d<])((?:(?!\s)[\.\-$\w\x7f-\uffff])+)/; // Must not start with `<`.
// Like `IDENTIFIER`, but includes `-`s and `.`s.
// Fragment: <></>
CSX_FRAGMENT_IDENTIFIER = /^()>/; // Ends immediately with `>`.
CSX_ATTRIBUTE = /^(?!\d)((?:(?!\s)[\-$\w\x7f-\uffff])+)([^\S]*=(?!=))?/; // Like `IDENTIFIER`, but includes `-`s.
// Is this an attribute with a value?
@@ -1589,7 +1605,12 @@
VALID_FLAGS = /^(?!.*(.).*\1)[imguy]*$/;
HEREGEX = /^(?:[^\\\/#]|\\[\s\S]|\/(?!\/\/)|\#(?!\{))*/;
// Match any character, except those that need special handling below.
// Match `\` followed by any character.
// Match any `/` except `///`.
// Match `#` which is not part of interpolation, e.g. `#{}`.
// Comments consume everything until the end of the line, including `///`.
HEREGEX = /^(?:[^\\\/#\s]|\\[\s\S]|\/(?!\/\/)|\#(?!\{)|\s+(?:#(?!\{).*)?)*/;
HEREGEX_OMIT = /((?:\\\\)+)|\\(\s)|\s+(?:#.*)?/g; // Consume (and preserve) an even number of backslashes.
// Preserve escaped whitespace.
@@ -1672,6 +1693,6 @@
INDENTABLE_CLOSERS = [')', '}', ']'];
// Tokens that, when appearing at the end of a line, suppress a following TERMINATOR/INDENT token
UNFINISHED = ['\\', '.', '?.', '?::', 'UNARY', 'MATH', 'UNARY_MATH', '+', '-', '**', 'SHIFT', 'RELATION', 'COMPARE', '&', '^', '|', '&&', '||', 'BIN?', 'EXTENDS', 'DEFAULT'];
UNFINISHED = ['\\', '.', '?.', '?::', 'UNARY', 'MATH', 'UNARY_MATH', '+', '-', '**', 'SHIFT', 'RELATION', 'COMPARE', '&', '^', '|', '&&', '||', 'BIN?', 'EXTENDS'];
}).call(this);

View File

@@ -1,10 +1,10 @@
// Generated by CoffeeScript 2.0.1
// Generated by CoffeeScript 2.1.1
(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),
// but some are created by other nodes as a method of code generation. To convert
// the syntax tree into a string of JavaScript code, call `compile()` on the root.
var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, CSXTag, Call, Class, Code, CodeFragment, ExecutableClassBody, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, FuncGlyph, HereComment, HoistTarget, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, JS_FORBIDDEN, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, LineComment, Literal, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, SIMPLENUM, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, Super, SuperCall, Switch, TAB, THIS, TaggedTemplateCall, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addDataToNode, attachCommentsToNode, compact, del, ends, extend, flatten, fragmentsToText, hasLineComments, indentInitial, isLiteralArguments, isLiteralThis, isUnassignable, locationDataToString, merge, moveComments, multident, shouldCacheOrIsAssignable, some, starts, throwSyntaxError, unfoldSoak, unshiftAfterComments, utility,
var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, CSXTag, Call, Class, Code, CodeFragment, ComputedPropertyName, Elision, ExecutableClassBody, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, FuncGlyph, HereComment, HoistTarget, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, JS_FORBIDDEN, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, LineComment, Literal, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, SIMPLENUM, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, Super, SuperCall, Switch, TAB, THIS, TaggedTemplateCall, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addDataToNode, attachCommentsToNode, compact, del, ends, extend, flatten, fragmentsToText, hasLineComments, indentInitial, isLiteralArguments, isLiteralThis, isUnassignable, locationDataToString, merge, moveComments, multident, shouldCacheOrIsAssignable, some, starts, throwSyntaxError, unfoldSoak, unshiftAfterComments, utility,
indexOf = [].indexOf,
splice = [].splice,
slice = [].slice;
@@ -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 = [];
@@ -540,7 +543,7 @@
return Base;
})();
}).call(this);
//### HoistTarget
@@ -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 dont 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) {
@@ -983,7 +997,7 @@
return Block;
})();
}).call(this);
//### Literal
@@ -1016,7 +1030,7 @@
return Literal;
})();
}).call(this);
exports.NumberLiteral = NumberLiteral = class NumberLiteral extends Literal {};
@@ -1080,7 +1094,7 @@
return IdentifierLiteral;
})();
}).call(this);
exports.CSXTag = CSXTag = class CSXTag extends IdentifierLiteral {};
@@ -1091,7 +1105,14 @@
return PropertyName;
})();
}).call(this);
exports.ComputedPropertyName = ComputedPropertyName = class ComputedPropertyName extends PropertyName {
compileNode(o) {
return [this.makeCode('['), ...this.value.compileToFragments(o, LEVEL_LIST), this.makeCode(']')];
}
};
exports.StatementLiteral = StatementLiteral = (function() {
class StatementLiteral extends Literal {
@@ -1116,7 +1137,7 @@
return StatementLiteral;
})();
}).call(this);
exports.ThisLiteral = ThisLiteral = class ThisLiteral extends Literal {
constructor() {
@@ -1210,7 +1231,7 @@
return Return;
})();
}).call(this);
// `yield return` works exactly like `return`, except that it turns the function
// into a generator.
@@ -1252,6 +1273,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);
}
@@ -1348,6 +1371,13 @@
return (this.base instanceof Obj) && (!onlyGenerated || this.base.generated);
}
isElision() {
if (!(this.base instanceof Arr)) {
return false;
}
return this.base.hasElision();
}
isSplice() {
var lastProp, ref1;
ref1 = this.properties, lastProp = ref1[ref1.length - 1];
@@ -1460,7 +1490,7 @@
return Value;
})();
}).call(this);
//### HereComment
@@ -1554,6 +1584,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]);
}
@@ -1717,7 +1751,7 @@
return Call;
})();
}).call(this);
//### Super
@@ -1755,7 +1789,7 @@
return SuperCall;
})();
}).call(this);
exports.Super = Super = (function() {
class Super extends Base {
@@ -1803,7 +1837,7 @@
return Super;
})();
}).call(this);
//### RegexWithInterpolations
@@ -1855,7 +1889,7 @@
return Extends;
})();
}).call(this);
//### Access
@@ -1888,7 +1922,7 @@
return Access;
})();
}).call(this);
//### Index
@@ -1914,7 +1948,7 @@
return Index;
})();
}).call(this);
//### Range
@@ -2031,7 +2065,7 @@
return Range;
})();
}).call(this);
//### Slice
@@ -2069,7 +2103,7 @@
return Slice;
})();
}).call(this);
//### Obj
@@ -2187,6 +2221,18 @@
key = new PropertyName(key.value);
}
prop = new Assign(key, value, 'object');
} else if (key instanceof Value && key.base instanceof ComputedPropertyName) {
// `{ [foo()] }` output as `{ [ref = foo()]: ref }`.
if (prop.base.value.shouldCache()) {
[key, value] = prop.base.value.cache(o);
if (key instanceof IdentifierLiteral) {
key = new ComputedPropertyName(key.value);
}
prop = new Assign(key, value, 'object');
} else {
// `{ [expression] }` output as `{ [expression]: expression }`.
prop = new Assign(key, prop.base.value, 'object');
}
} else if (!(typeof prop.bareLiteral === "function" ? prop.bareLiteral(IdentifierLiteral) : void 0)) {
prop = new Assign(prop, prop, 'object');
}
@@ -2302,7 +2348,7 @@
return Obj;
})();
}).call(this);
//### Arr
@@ -2315,6 +2361,18 @@
this.objects = objs || [];
}
hasElision() {
var j, len1, obj, ref1;
ref1 = this.objects;
for (j = 0, len1 = ref1.length; j < len1; j++) {
obj = ref1[j];
if (obj instanceof Elision) {
return true;
}
}
return false;
}
isAssignable() {
var i, j, len1, obj, ref1;
if (!this.objects.length) {
@@ -2338,11 +2396,16 @@
}
compileNode(o) {
var answer, compiledObjs, fragment, fragmentIndex, fragments, includesLineCommentsOnNonFirstElement, index, j, k, l, len1, len2, len3, len4, len5, obj, objIndex, q, r, ref1, unwrappedObj;
var answer, compiledObjs, fragment, fragmentIndex, fragmentIsElision, fragments, includesLineCommentsOnNonFirstElement, index, j, k, l, len1, len2, len3, len4, len5, obj, objIndex, olen, passedElision, q, r, ref1, unwrappedObj;
if (!this.objects.length) {
return [this.makeCode('[]')];
}
o.indent += TAB;
fragmentIsElision = function(fragment) {
return fragmentsToText(fragment).trim() === ',';
};
// Detect if `Elisions` at the beginning of the array are processed (e.g. [, , , a]).
passedElision = false;
answer = [];
ref1 = this.objects;
for (objIndex = j = 0, len1 = ref1.length; j < len1; objIndex = ++j) {
@@ -2373,6 +2436,7 @@
}
return results;
}).call(this);
olen = compiledObjs.length;
// If `compiledObjs` includes newlines, we will output this as a multiline
// array (i.e. with a newline and indentation after the `[`). If an element
// contains line comments, that should also trigger multiline output since
@@ -2391,9 +2455,12 @@
includesLineCommentsOnNonFirstElement = true;
}
}
if (index !== 0) {
// Add ', ' if all `Elisions` from the beginning of the array are processed (e.g. [, , , a]) and
// element isn't `Elision` or last element is `Elision` (e.g. [a,,b,,])
if (index !== 0 && passedElision && (!fragmentIsElision(fragments) || index === olen - 1)) {
answer.push(this.makeCode(', '));
}
passedElision = passedElision || !fragmentIsElision(fragments);
answer.push(...fragments);
}
if (includesLineCommentsOnNonFirstElement || indexOf.call(fragmentsToText(answer), '\n') >= 0) {
@@ -2401,7 +2468,7 @@
fragment = answer[fragmentIndex];
if (fragment.isHereComment) {
fragment.code = `${multident(fragment.code, o.indent, false)}\n${o.indent}`;
} else if (fragment.code === ', ') {
} else if (fragment.code === ', ' && !(fragment != null ? fragment.isElision : void 0)) {
fragment.code = `,\n${o.indent}`;
}
}
@@ -2450,7 +2517,7 @@
return Arr;
})();
}).call(this);
//### Class
@@ -2501,7 +2568,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 +2584,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(' '));
@@ -2730,7 +2803,7 @@
return Class;
})();
}).call(this);
exports.ExecutableClassBody = ExecutableClassBody = (function() {
class ExecutableClassBody extends Base {
@@ -2748,16 +2821,16 @@
if (argumentsNode = this.body.contains(isLiteralArguments)) {
argumentsNode.error("Class bodies shouldn't reference arguments");
}
this.name = (ref1 = this.class.name) != null ? ref1 : this.defaultClassVariableName;
directives = this.walkBody();
this.setContext();
ident = new IdentifierLiteral(this.name);
params = [];
args = [];
args = [new ThisLiteral];
wrapper = new Code(params, this.body);
klass = new Parens(new Call(wrapper, args));
klass = new Parens(new Call(new Value(wrapper, [new Access(new PropertyName('call'))]), args));
this.body.spaced = true;
o.classScope = wrapper.makeScope(o.scope);
this.name = (ref1 = this.class.name) != null ? ref1 : o.classScope.freeVariable(this.defaultClassVariableName);
ident = new IdentifierLiteral(this.name);
directives = this.walkBody();
this.setContext();
if (this.class.hasNameClash) {
parent = new IdentifierLiteral(o.classScope.freeVariable('superClass'));
wrapper.params.push(new Param(parent));
@@ -2874,7 +2947,7 @@
return ExecutableClassBody;
})();
}).call(this);
//### Import and Export
exports.ModuleDeclaration = ModuleDeclaration = (function() {
@@ -2910,7 +2983,7 @@
return ModuleDeclaration;
})();
}).call(this);
exports.ImportDeclaration = ImportDeclaration = class ImportDeclaration extends ModuleDeclaration {
compileNode(o) {
@@ -2963,7 +3036,7 @@
return ImportClause;
})();
}).call(this);
exports.ExportDeclaration = ExportDeclaration = class ExportDeclaration extends ModuleDeclaration {
compileNode(o) {
@@ -3045,7 +3118,7 @@
return ModuleSpecifierList;
})();
}).call(this);
exports.ImportSpecifierList = ImportSpecifierList = class ImportSpecifierList extends ModuleSpecifierList {};
@@ -3089,7 +3162,7 @@
return ModuleSpecifier;
})();
}).call(this);
exports.ImportSpecifier = ImportSpecifier = class ImportSpecifier extends ModuleSpecifier {
constructor(imported, local) {
@@ -3158,7 +3231,7 @@
// we've been assigned to, for correct internal references. If the variable
// has not been seen yet within the current scope, declare it.
compileNode(o) {
var answer, compiledName, isValue, j, name, objDestructAnswer, properties, prototype, ref1, ref2, ref3, ref4, ref5, val, varBase;
var answer, compiledName, hasSplat, isValue, j, name, objDestructAnswer, properties, prototype, ref1, ref2, ref3, ref4, ref5, val, varBase;
isValue = this.variable instanceof Value;
if (isValue) {
// When compiling `@variable`, remember if it is part of a function parameter.
@@ -3172,12 +3245,14 @@
// know that, so that those nodes know that theyre assignable as
// destructured variables.
this.variable.base.lhs = true;
if (!this.variable.isAssignable()) {
// Check if @variable contains Obj with splats.
hasSplat = this.variable.contains(function(node) {
return node instanceof Obj && node.hasSplat();
});
if (!this.variable.isAssignable() || this.variable.isArray() && hasSplat) {
return this.compileDestructuring(o);
}
if (this.variable.isObject() && this.variable.contains(function(node) {
return node instanceof Obj && node.hasSplat();
})) {
if (this.variable.isObject() && hasSplat) {
// Object destructuring. Can be removed once ES proposal hits Stage 4.
objDestructAnswer = this.compileObjectDestruct(o);
}
@@ -3201,7 +3276,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;
}
@@ -3209,14 +3284,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. Dont 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;
}
}
});
}
@@ -3245,7 +3335,9 @@
answer = compiledName.concat(this.makeCode(` ${this.context || '='} `), val);
// Per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Assignment_without_declaration,
// if were destructuring without declaring, the destructuring assignment must be wrapped in parentheses.
if (o.level > LEVEL_LIST || o.level === LEVEL_TOP && isValue && this.variable.base instanceof Obj && !this.nestedLhs && !(this.param === true)) {
// The assignment is wrapped in parentheses if 'o.level' has lower precedence than LEVEL_LIST (3)
// (i.e. LEVEL_COND (4), LEVEL_OP (5) or LEVEL_ACCESS (6)), or if we're destructuring object, e.g. {a,b} = obj.
if (o.level > LEVEL_LIST || isValue && this.variable.base instanceof Obj && !this.nestedLhs && !(this.param === true)) {
return this.wrapInParentheses(answer);
} else {
return answer;
@@ -3528,10 +3620,17 @@
obj.error(message);
}
}
assigns.push(new Assign(obj, val, null, {
param: this.param,
subpattern: true
}).compileToFragments(o, LEVEL_LIST));
if (!(obj instanceof Elision)) {
assigns.push(new Assign(obj, val, null, {
param: this.param,
subpattern: true
}).compileToFragments(o, LEVEL_LIST));
} else {
if (expandedIdx) {
// Output `Elision` only if `idx` is `i++`, e.g. expandedIdx.
assigns.push(idx.compileToFragments(o, LEVEL_LIST));
}
}
}
if (!(top || this.subpattern)) {
assigns.push(vvar);
@@ -3631,7 +3730,7 @@
return Assign;
})();
}).call(this);
//### FuncGlyph
exports.FuncGlyph = FuncGlyph = class FuncGlyph extends Base {
@@ -3649,10 +3748,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) === '=>';
@@ -3687,7 +3787,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, yieldNode;
if (this.ctor) {
if (this.isAsync) {
this.name.error('Class constructor may not be async');
@@ -3872,7 +3972,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];
@@ -3895,6 +3997,14 @@
if (!(wasEmpty || this.noReturn)) {
this.body.makeReturn();
}
// JavaScript doesnt allow bound (`=>`) functions to also be generators.
// This is usually caught via `Op::compileContinuation`, but double-check:
if (this.bound && this.isGenerator) {
yieldNode = this.body.contains(function(node) {
return node instanceof Op && node.operator === 'yield';
});
(yieldNode || this).error('yield cannot occur inside bound (fat arrow) functions');
}
// Assemble the output
modifiers = [];
if (this.isMethod && this.isStatic) {
@@ -3909,6 +4019,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) {
@@ -3929,10 +4044,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);
@@ -4035,13 +4150,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) {
@@ -4061,7 +4186,7 @@
return Code;
})();
}).call(this);
//### Param
@@ -4168,6 +4293,8 @@
// * simple destructured parameters {foo}
iterator(obj.base.value, obj.base, this);
}
} else if (obj instanceof Elision) {
obj;
} else if (!(obj instanceof Expansion)) {
obj.error(`illegal parameter ${obj.compile()}`);
}
@@ -4202,7 +4329,7 @@
return Param;
})();
}).call(this);
//### Splat
@@ -4237,7 +4364,7 @@
return Splat;
})();
}).call(this);
//### Expansion
@@ -4261,7 +4388,39 @@
return Expansion;
})();
}).call(this);
//### Elision
// Array elision element (for example, [,a, , , b, , c, ,]).
exports.Elision = Elision = (function() {
class Elision extends Base {
compileToFragments(o, level) {
var fragment;
fragment = super.compileToFragments(o, level);
fragment.isElision = true;
return fragment;
}
compileNode(o) {
return [this.makeCode(', ')];
}
asReference(o) {
return this;
}
eachName(iterator) {}
};
Elision.prototype.isAssignable = YES;
Elision.prototype.shouldCache = NO;
return Elision;
}).call(this);
//### While
@@ -4348,7 +4507,7 @@
return While;
})();
}).call(this);
//### Op
@@ -4646,7 +4805,7 @@
return Op;
})();
}).call(this);
//### In
exports.In = In = (function() {
@@ -4724,7 +4883,7 @@
return In;
})();
}).call(this);
//### Try
@@ -4777,7 +4936,7 @@
return Try;
})();
}).call(this);
//### Throw
@@ -4811,7 +4970,7 @@
return Throw;
})();
}).call(this);
//### Existence
@@ -4826,8 +4985,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++) {
@@ -4836,17 +4995,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);
@@ -4881,7 +5030,7 @@
return Existence;
})();
}).call(this);
//### Parens
@@ -4906,14 +5055,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, dont 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);
}
@@ -4930,7 +5087,7 @@
return Parens;
})();
}).call(this);
//### StringWithInterpolations
exports.StringWithInterpolations = StringWithInterpolations = (function() {
@@ -5056,7 +5213,7 @@
return StringWithInterpolations;
})();
}).call(this);
//### For
@@ -5304,7 +5461,7 @@
return For;
})();
}).call(this);
//### Switch
@@ -5391,7 +5548,7 @@
return Switch;
})();
}).call(this);
//### If
@@ -5528,7 +5685,7 @@
return If;
})();
}).call(this);
// Constants
// ---------

View File

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

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
// Generated by CoffeeScript 2.0.1
// Generated by CoffeeScript 2.1.1
(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);

View File

@@ -1,6 +1,6 @@
// Generated by CoffeeScript 2.0.1
// Generated by CoffeeScript 2.1.1
(function() {
var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, replDefaults, runInContext, sawSIGINT, updateSyntaxError, vm;
var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, replDefaults, runInContext, sawSIGINT, transpile, updateSyntaxError, vm;
fs = require('fs');
@@ -16,6 +16,8 @@
sawSIGINT = false;
transpile = false;
replDefaults = {
prompt: 'coffee> ',
historyFile: (function() {
@@ -27,7 +29,7 @@
})(),
historyMaxInputSize: 10240,
eval: function(input, context, filename, cb) {
var Assign, Block, Call, Code, Literal, Value, ast, err, isAsync, js, referencedVars, result, token, tokens;
var Assign, Block, Call, Code, Literal, Value, ast, err, isAsync, js, ref, ref1, referencedVars, result, token, tokens;
// XXX: multiline hack.
input = input.replace(/\uFF00/g, '\n');
// Node's REPL sends the input ending with a newline and then wrapped in
@@ -41,6 +43,13 @@
try {
// Tokenize the clean input.
tokens = CoffeeScript.tokens(input);
// Filter out tokens generated just to hold comments.
if (tokens.length >= 2 && tokens[0].generated && ((ref = tokens[0].comments) != null ? ref.length : void 0) !== 0 && tokens[0][1] === '' && tokens[1][0] === 'TERMINATOR') {
tokens = tokens.slice(2);
}
if (tokens.length >= 1 && tokens[tokens.length - 1].generated && ((ref1 = tokens[tokens.length - 1].comments) != null ? ref1.length : void 0) !== 0 && tokens[tokens.length - 1][1] === '') {
tokens.pop();
}
// Collect referenced variable names just like in `CoffeeScript.compile`.
referencedVars = (function() {
var i, len, results;
@@ -57,10 +66,10 @@
ast = CoffeeScript.nodes(tokens);
// Add assignment to `__` variable to force the input to be an expression.
ast = new Block([new Assign(new Value(new Literal('__')), ast, '=')]);
// Wrap the expression in a closure to support top-level `await`
// Wrap the expression in a closure to support top-level `await`.
ast = new Code([], ast);
isAsync = ast.isAsync;
// Invoke the wrapping closure
// Invoke the wrapping closure.
ast = new Block([new Call(ast)]);
js = ast.compile({
bare: true,
@@ -68,8 +77,14 @@
referencedVars,
sharedScope: true
});
if (transpile) {
js = transpile.transpile(js, transpile.options).code;
// Strip `"use strict"`, to avoid an exception on assigning to
// undeclared variable `__`.
js = js.replace(/^"use strict"|^'use strict'/, '');
}
result = runInContext(js, context, filename);
// Await an async result, if necessary
// Await an async result, if necessary.
if (isAsync) {
result.then(function(resolvedResult) {
if (!sawSIGINT) {
@@ -224,7 +239,7 @@
module.exports = {
start: function(opts = {}) {
var build, major, minor, repl;
var Module, build, major, minor, originalModuleLoad, repl;
[major, minor, build] = process.versions.node.split('.').map(function(n) {
return parseInt(n, 10);
});
@@ -234,6 +249,30 @@
}
CoffeeScript.register();
process.argv = ['coffee'].concat(process.argv.slice(2));
if (opts.transpile) {
try {
transpile = {};
transpile.transpile = require('babel-core').transform;
} catch (error) {
console.error('To use --transpile with an interactive REPL, babel-core must be installed either in the current folder or globally:\n npm install --save-dev babel-core\nor\n npm install --global babel-core\nAnd you must save options to configure Babel in one of the places it looks to find its options.\nSee http://coffeescript.org/#transpilation');
process.exit(1);
}
transpile.options = {
filename: path.resolve(process.cwd(), '<repl>')
};
// Since the REPL compilation path is unique (in `eval` above), we need
// another way to get the `options` object attached to a module so that
// it knows later on whether it needs to be transpiled. In the case of
// the REPL, the only applicable option is `transpile`.
Module = require('module');
originalModuleLoad = Module.prototype.load;
Module.prototype.load = function(filename) {
this.options = {
transpile: transpile.options
};
return originalModuleLoad.call(this, filename);
};
}
opts = merge(replDefaults, opts);
repl = nodeREPL.start(opts);
if (opts.prelude) {

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.0.1
// Generated by CoffeeScript 2.1.1
(function() {
// The CoffeeScript language has a good deal of optional syntax, implicit syntax,
// and shorthand syntax. This can greatly complicate a grammar and bloat
@@ -281,7 +281,7 @@
stack = [];
start = null;
return this.scanTokens(function(token, i, tokens) {
var endImplicitCall, endImplicitObject, forward, implicitObjectContinues, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, isImplicit, isImplicitCall, isImplicitObject, k, newLine, nextTag, nextToken, offset, prevTag, prevToken, ref, ref1, s, sameLine, stackIdx, stackItem, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag;
var endImplicitCall, endImplicitObject, forward, implicitObjectContinues, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, isImplicit, isImplicitCall, isImplicitObject, k, newLine, nextTag, nextToken, offset, prevTag, prevToken, ref, ref1, ref2, s, sameLine, stackIdx, stackItem, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag;
[tag] = token;
[prevTag] = prevToken = i > 0 ? tokens[i - 1] : [];
[nextTag] = nextToken = i < tokens.length - 1 ? tokens[i + 1] : [];
@@ -539,7 +539,7 @@
// f a, b: c, d: e, f, g: h: i, j
if (tag === ',' && !this.looksObjectish(i + 1) && inImplicitObject() && (nextTag !== 'TERMINATOR' || !this.looksObjectish(i + 2))) {
if (tag === ',' && !this.looksObjectish(i + 1) && inImplicitObject() && !((ref2 = this.tag(i + 2)) === 'FOROF' || ref2 === 'FORIN') && (nextTag !== 'TERMINATOR' || !this.looksObjectish(i + 2))) {
// When nextTag is OUTDENT the comma is insignificant and
// should just be ignored so embed it in the implicit object.
@@ -886,7 +886,7 @@
return Rewriter;
})();
}).call(this);
// Constants
// ---------
@@ -944,6 +944,6 @@
// `STRING_START` isnt 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);

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.0.1
// Generated by CoffeeScript 2.1.1
(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 = {};

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.0.1
// Generated by CoffeeScript 2.1.1
(function() {
// Source maps allow JavaScript runtimes to match running JavaScript back to
// the original source code that corresponds to it. This can be minified
@@ -47,18 +47,18 @@
};
// SourceMap
// ---------
// Maps locations in a single generated JavaScript file back to locations in
// the original CoffeeScript source file.
// This is intentionally agnostic towards how a source map might be represented on
// disk. Once the compiler is ready to produce a "v3"-style source map, we can walk
// through the arrays of line and column buffer to produce it.
SourceMap = (function() {
var BASE64_CHARS, VLQ_CONTINUATION_BIT, VLQ_SHIFT, VLQ_VALUE_MASK;
// SourceMap
// ---------
// Maps locations in a single generated JavaScript file back to locations in
// the original CoffeeScript source file.
// This is intentionally agnostic towards how a source map might be represented on
// disk. Once the compiler is ready to produce a "v3"-style source map, we can walk
// through the arrays of line and column buffer to produce it.
class SourceMap {
constructor() {
this.lines = [];
@@ -203,7 +203,7 @@
return SourceMap;
})();
}).call(this);
// Our API for source maps is just the `SourceMap` class.
module.exports = SourceMap;

642
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@
"compiler"
],
"author": "Jeremy Ashkenas",
"version": "2.0.1",
"version": "2.1.1",
"license": "MIT",
"engines": {
"node": ">=6"
@@ -41,15 +41,15 @@
"devDependencies": {
"babel-core": "~6.26.0",
"babel-preset-babili": "~0.1.4",
"babel-preset-env": "~1.6.0",
"babel-preset-env": "~1.6.1",
"babel-preset-minify": "^0.2.0",
"codemirror": "^5.29.0",
"codemirror": "^5.32.0",
"docco": "~0.7.0",
"highlight.js": "~9.12.0",
"jison": ">=0.4.18",
"markdown-it": "~8.4.0",
"underscore": "~1.8.3",
"webpack": "~3.6.0"
"webpack": "~3.10.0"
},
"dependencies": {}
}

View File

@@ -140,12 +140,14 @@ exports.compile = compile = withPrettyErrors (code, options = {}) ->
transpiler = options.transpile.transpile
delete options.transpile.transpile
transpilerOptions = Object.assign {}, options.transpile
# See https://github.com/babel/babel/issues/827#issuecomment-77573107:
# Babel can take a v3 source map object as input in `inputSourceMap`
# and it will return an *updated* v3 source map object in its output.
if v3SourceMap and not options.transpile.inputSourceMap?
options.transpile.inputSourceMap = v3SourceMap
transpilerOutput = transpiler js, options.transpile
if v3SourceMap and not transpilerOptions.inputSourceMap?
transpilerOptions.inputSourceMap = v3SourceMap
transpilerOutput = transpiler js, transpilerOptions
js = transpilerOutput.code
if v3SourceMap and transpilerOutput.map
v3SourceMap = transpilerOutput.map

View File

@@ -92,6 +92,7 @@ exports.run = ->
replCliOpts = useGlobal: yes
opts.prelude = makePrelude opts.require if opts.require
replCliOpts.prelude = opts.prelude
replCliOpts.transpile = opts.transpile
return forkNode() if opts.nodejs
return usage() if opts.help
return version() if opts.version
@@ -243,6 +244,9 @@ compileScript = (file, input, base = null) ->
# Attach the appropriate listeners to compile scripts incoming over **stdin**,
# and write them back to **stdout**.
compileStdio = ->
if opts.map
console.error '--stdio and --map cannot be used together'
process.exit 1
buffers = []
stdin = process.openStdin()
stdin.on 'data', (buffer) ->
@@ -397,7 +401,7 @@ mkdirp = (dir, fn) ->
# If `generatedSourceMap` is provided, this will write a `.js.map` file into the
# same directory as the `.js` file.
writeJs = (base, sourcePath, js, jsPath, generatedSourceMap = null) ->
sourceMapPath = outputPath sourcePath, base, ".js.map"
sourceMapPath = "#{jsPath}.map"
jsDir = path.dirname jsPath
compile = ->
if opts.compile

View File

@@ -206,6 +206,7 @@ grammar =
o 'Identifier'
o 'Property'
o 'ThisProperty'
o '[ Expression ]', -> new Value new ComputedPropertyName $2
]
ObjAssignable: [
@@ -262,7 +263,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
]
@@ -439,6 +440,7 @@ grammar =
o 'EXPORT Identifier = INDENT Expression OUTDENT', -> new ExportNamedDeclaration new Assign $2, $5, null,
moduleDeclaration: 'export'
o 'EXPORT DEFAULT Expression', -> new ExportDefaultDeclaration $3
o 'EXPORT DEFAULT INDENT Object OUTDENT', -> new ExportDefaultDeclaration new Value $4
o 'EXPORT EXPORT_ALL FROM String', -> new ExportAllDeclaration new Literal($2), $4
o 'EXPORT { ExportSpecifierList OptComma } FROM String', -> new ExportNamedDeclaration new ExportSpecifierList($3), $7
]
@@ -492,7 +494,8 @@ grammar =
# The array literal.
Array: [
o '[ ]', -> new Arr []
o '[ ArgList OptComma ]', -> new Arr $2
o '[ Elisions ]', -> new Arr $2
o '[ ArgElisionList OptElisions ]', -> new Arr [].concat $2, $3
]
# Inclusive and exclusive range dots.
@@ -514,8 +517,7 @@ grammar =
o 'RangeDots', -> new Range null, null, $1
]
# The **ArgList** is both the list of objects passed into a function call,
# as well as the contents of an array literal
# The **ArgList** is the list of objects passed into a function call
# (i.e. comma-separated expressions). Newlines work as well.
ArgList: [
o 'Arg', -> [$1]
@@ -532,6 +534,35 @@ grammar =
o '...', -> new Expansion
]
# The **ArgElisionList** is the list of objects, contents of an array literal
# (i.e. comma-separated expressions and elisions). Newlines work as well.
ArgElisionList: [
o 'ArgElision'
o 'ArgElisionList , ArgElision', -> $1.concat $3
o 'ArgElisionList OptElisions TERMINATOR ArgElision', -> $1.concat $2, $4
o 'INDENT ArgElisionList OptElisions OUTDENT', -> $2.concat $3
o 'ArgElisionList OptElisions INDENT ArgElisionList OptElisions OUTDENT', -> $1.concat $2, $4, $5
]
ArgElision: [
o 'Arg', -> [$1]
o 'Elisions Arg', -> $1.concat $2
]
OptElisions: [
o 'OptComma', -> []
o ', Elisions', -> [].concat $2
]
Elisions: [
o 'Elision', -> [$1]
o 'Elisions Elision', -> $1.concat $2
]
Elision: [
o ',', -> new Elision
]
# Just simple, comma-separated, required arguments (no fancy syntax). We need
# this to be separate from the **ArgList** for use in **Switch** blocks, where
# having the newlines wouldn't make sense.

View File

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

View File

@@ -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]
@@ -550,7 +556,7 @@ exports.Lexer = class Lexer
# Check the previous token to detect if attribute is spread.
prevChar = if @tokens.length > 0 then @tokens[@tokens.length - 1][0] else ''
if firstChar is '<'
match = CSX_IDENTIFIER.exec @chunk[1...]
match = CSX_IDENTIFIER.exec(@chunk[1...]) or CSX_FRAGMENT_IDENTIFIER.exec(@chunk[1...])
return 0 unless match and (
@csxDepth > 0 or
# Not the right hand side of an unspaced comparison (i.e. `a<b`).
@@ -590,8 +596,8 @@ exports.Lexer = class Lexer
@matchWithInterpolations INSIDE_CSX, '>', '</', CSX_INTERPOLATION
@mergeInterpolationTokens tokens, {delimiter: '"'}, (value, i) =>
@formatString value, delimiter: '>'
match = CSX_IDENTIFIER.exec @chunk[end...]
if not match or match[0] isnt csxTag.name
match = CSX_IDENTIFIER.exec(@chunk[end...]) or CSX_FRAGMENT_IDENTIFIER.exec(@chunk[end...])
if not match or match[1] isnt csxTag.name
@error "expected corresponding CSX closing tag for #{csxTag.name}",
csxTag.origin[2]
afterTag = end + csxTag.name.length
@@ -965,9 +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: ->
@@ -1169,6 +1178,11 @@ CSX_IDENTIFIER = /// ^
( (?: (?!\s)[\.\-$\w\x7f-\uffff] )+ ) # Like `IDENTIFIER`, but includes `-`s and `.`s.
///
# Fragment: <></>
CSX_FRAGMENT_IDENTIFIER = /// ^
()> # Ends immediately with `>`.
///
CSX_ATTRIBUTE = /// ^
(?!\d)
( (?: (?!\s)[\-$\w\x7f-\uffff] )+ ) # Like `IDENTIFIER`, but includes `-`s.
@@ -1243,7 +1257,20 @@ REGEX = /// ^
REGEX_FLAGS = /^\w*/
VALID_FLAGS = /^(?!.*(.).*\1)[imguy]*$/
HEREGEX = /// ^(?: [^\\/#] | \\[\s\S] | /(?!//) | \#(?!\{) )* ///
HEREGEX = /// ^
(?:
# Match any character, except those that need special handling below.
[^\\/#\s]
# Match `\` followed by any character.
| \\[\s\S]
# Match any `/` except `///`.
| /(?!//)
# Match `#` which is not part of interpolation, e.g. `#{}`.
| \#(?!\{)
# Comments consume everything until the end of the line, including `///`.
| \s+(?:#(?!\{).*)?
)*
///
HEREGEX_OMIT = ///
((?:\\\\)+) # Consume (and preserve) an even number of backslashes.
@@ -1345,4 +1372,4 @@ INDENTABLE_CLOSERS = [')', '}', ']']
# Tokens that, when appearing at the end of a line, suppress a following TERMINATOR/INDENT token
UNFINISHED = ['\\', '.', '?.', '?::', 'UNARY', 'MATH', 'UNARY_MATH', '+', '-',
'**', 'SHIFT', 'RELATION', 'COMPARE', '&', '^', '|', '&&', '||',
'BIN?', 'EXTENDS', 'DEFAULT']
'BIN?', 'EXTENDS']

View File

@@ -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 dont 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}")
@@ -758,6 +765,10 @@ exports.CSXTag = class CSXTag extends IdentifierLiteral
exports.PropertyName = class PropertyName extends Literal
isAssignable: YES
exports.ComputedPropertyName = class ComputedPropertyName extends PropertyName
compileNode: (o) ->
[@makeCode('['), @value.compileToFragments(o, LEVEL_LIST)..., @makeCode(']')]
exports.StatementLiteral = class StatementLiteral extends Literal
isStatement: YES
@@ -903,6 +914,10 @@ exports.Value = class Value extends Base
return no if @properties.length
(@base instanceof Obj) and (not onlyGenerated or @base.generated)
isElision: ->
return no unless @base instanceof Arr
@base.hasElision()
isSplice: ->
[..., lastProp] = @properties
lastProp instanceof Slice
@@ -1490,6 +1505,15 @@ exports.Obj = class Obj extends Base
[key, value] = prop.base.cache o
key = new PropertyName key.value if key instanceof IdentifierLiteral
prop = new Assign key, value, 'object'
else if key instanceof Value and key.base instanceof ComputedPropertyName
# `{ [foo()] }` output as `{ [ref = foo()]: ref }`.
if prop.base.value.shouldCache()
[key, value] = prop.base.value.cache o
key = new ComputedPropertyName key.value if key instanceof IdentifierLiteral
prop = new Assign key, value, 'object'
else
# `{ [expression] }` output as `{ [expression]: expression }`.
prop = new Assign key, prop.base.value, 'object'
else if not prop.bareLiteral?(IdentifierLiteral)
prop = new Assign prop, prop, 'object'
if indent then answer.push @makeCode indent
@@ -1554,6 +1578,10 @@ exports.Arr = class Arr extends Base
children: ['objects']
hasElision: ->
return yes for obj in @objects when obj instanceof Elision
no
isAssignable: ->
return no unless @objects.length
@@ -1568,6 +1596,9 @@ exports.Arr = class Arr extends Base
compileNode: (o) ->
return [@makeCode '[]'] unless @objects.length
o.indent += TAB
fragmentIsElision = (fragment) -> fragmentsToText(fragment).trim() is ','
# Detect if `Elisions` at the beginning of the array are processed (e.g. [, , , a]).
passedElision = no
answer = []
for obj, objIndex in @objects
@@ -1583,6 +1614,7 @@ exports.Arr = class Arr extends Base
unwrappedObj.lhs = yes if unwrappedObj instanceof Arr or unwrappedObj instanceof Obj
compiledObjs = (obj.compileToFragments o, LEVEL_LIST for obj in @objects)
olen = compiledObjs.length
# If `compiledObjs` includes newlines, we will output this as a multiline
# array (i.e. with a newline and indentation after the `[`). If an element
# contains line comments, that should also trigger multiline output since
@@ -1597,14 +1629,17 @@ exports.Arr = class Arr extends Base
fragment.code = fragment.code.trim()
else if index isnt 0 and includesLineCommentsOnNonFirstElement is no and hasLineComments fragment
includesLineCommentsOnNonFirstElement = yes
if index isnt 0
# Add ', ' if all `Elisions` from the beginning of the array are processed (e.g. [, , , a]) and
# element isn't `Elision` or last element is `Elision` (e.g. [a,,b,,])
if index isnt 0 and passedElision and (not fragmentIsElision(fragments) or index is olen - 1)
answer.push @makeCode ', '
passedElision = passedElision or not fragmentIsElision fragments
answer.push fragments...
if includesLineCommentsOnNonFirstElement or '\n' in fragmentsToText(answer)
for fragment, fragmentIndex in answer
if fragment.isHereComment
fragment.code = "#{multident(fragment.code, o.indent, no)}\n#{o.indent}"
else if fragment.code is ', '
else if fragment.code is ', ' and not fragment?.isElision
fragment.code = ",\n#{o.indent}"
answer.unshift @makeCode "[\n#{o.indent}"
answer.push @makeCode "\n#{@tab}]"
@@ -1674,7 +1709,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 '{'
@@ -1834,20 +1871,20 @@ exports.ExecutableClassBody = class ExecutableClassBody extends Base
if argumentsNode = @body.contains isLiteralArguments
argumentsNode.error "Class bodies shouldn't reference arguments"
@name = @class.name ? @defaultClassVariableName
directives = @walkBody()
@setContext()
ident = new IdentifierLiteral @name
params = []
args = []
args = [new ThisLiteral]
wrapper = new Code params, @body
klass = new Parens new Call wrapper, args
klass = new Parens new Call (new Value wrapper, [new Access new PropertyName 'call']), args
@body.spaced = true
o.classScope = wrapper.makeScope o.scope
@name = @class.name ? o.classScope.freeVariable @defaultClassVariableName
ident = new IdentifierLiteral @name
directives = @walkBody()
@setContext()
if @class.hasNameClash
parent = new IdentifierLiteral o.classScope.freeVariable 'superClass'
wrapper.params.push new Param parent
@@ -2132,10 +2169,11 @@ exports.Assign = class Assign extends Base
# know that, so that those nodes know that theyre assignable as
# destructured variables.
@variable.base.lhs = yes
return @compileDestructuring o unless @variable.isAssignable()
# Check if @variable contains Obj with splats.
hasSplat = @variable.contains (node) -> node instanceof Obj and node.hasSplat()
return @compileDestructuring o if not @variable.isAssignable() or @variable.isArray() and hasSplat
# Object destructuring. Can be removed once ES proposal hits Stage 4.
objDestructAnswer = @compileObjectDestruct(o) if @variable.isObject() and @variable.contains (node) ->
node instanceof Obj and node.hasSplat()
objDestructAnswer = @compileObjectDestruct(o) if @variable.isObject() and hasSplat
return objDestructAnswer if objDestructAnswer
return @compileSplice o if @variable.isSplice()
@@ -2153,7 +2191,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
@@ -2165,6 +2203,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. Dont 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
@@ -2186,7 +2238,9 @@ exports.Assign = class Assign extends Base
answer = compiledName.concat @makeCode(" #{ @context or '=' } "), val
# Per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Assignment_without_declaration,
# if were destructuring without declaring, the destructuring assignment must be wrapped in parentheses.
if o.level > LEVEL_LIST or o.level is LEVEL_TOP and isValue and @variable.base instanceof Obj and not @nestedLhs and not (@param is yes)
# The assignment is wrapped in parentheses if 'o.level' has lower precedence than LEVEL_LIST (3)
# (i.e. LEVEL_COND (4), LEVEL_OP (5) or LEVEL_ACCESS (6)), or if we're destructuring object, e.g. {a,b} = obj.
if o.level > LEVEL_LIST or isValue and @variable.base instanceof Obj and not @nestedLhs and not (@param is yes)
@wrapInParentheses answer
else
answer
@@ -2415,7 +2469,11 @@ exports.Assign = class Assign extends Base
if name?
message = isUnassignable name
obj.error message if message
assigns.push new Assign(obj, val, null, param: @param, subpattern: yes).compileToFragments o, LEVEL_LIST
unless obj instanceof Elision
assigns.push new Assign(obj, val, null, param: @param, subpattern: yes).compileToFragments o, LEVEL_LIST
else
# Output `Elision` only if `idx` is `i++`, e.g. expandedIdx.
assigns.push idx.compileToFragments o, LEVEL_LIST if expandedIdx
assigns.push vvar unless top or @subpattern
fragments = @joinFragmentArrays assigns, ', '
@@ -2484,7 +2542,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 []
@@ -2674,6 +2732,12 @@ exports.Code = class Code extends Base
@body.expressions.unshift new Call(boundMethodCheck, [new Value(new ThisLiteral), @classVariable])
@body.makeReturn() unless wasEmpty or @noReturn
# JavaScript doesnt allow bound (`=>`) functions to also be generators.
# This is usually caught via `Op::compileContinuation`, but double-check:
if @bound and @isGenerator
yieldNode = @body.contains (node) -> node instanceof Op and node.operator is 'yield'
(yieldNode or @).error 'yield cannot occur inside bound (fat arrow) functions'
# Assemble the output
modifiers = []
modifiers.push 'static' if @isMethod and @isStatic
@@ -2684,6 +2748,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
@@ -2756,13 +2824,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
@@ -2849,6 +2923,8 @@ exports.Param = class Param extends Base
atParam obj
# * simple destructured parameters {foo}
else iterator obj.base.value, obj.base, @
else if obj instanceof Elision
obj
else if obj not instanceof Expansion
obj.error "illegal parameter #{obj.compile()}"
return
@@ -2905,6 +2981,28 @@ exports.Expansion = class Expansion extends Base
eachName: (iterator) ->
#### Elision
# Array elision element (for example, [,a, , , b, , c, ,]).
exports.Elision = class Elision extends Base
isAssignable: YES
shouldCache: NO
compileToFragments: (o, level) ->
fragment = super o, level
fragment.isElision = yes
fragment
compileNode: (o) ->
[@makeCode ', ']
asReference: (o) ->
this
eachName: (iterator) ->
#### While
# A while loop, the only sort of low-level loop exposed by CoffeeScript. From
@@ -3282,15 +3380,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, @
@@ -3337,13 +3431,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, dont 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

View File

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

View File

@@ -6,6 +6,7 @@ CoffeeScript = require './'
{merge, updateSyntaxError} = require './helpers'
sawSIGINT = no
transpile = no
replDefaults =
prompt: 'coffee> ',
@@ -29,20 +30,33 @@ replDefaults =
try
# Tokenize the clean input.
tokens = CoffeeScript.tokens input
# Filter out tokens generated just to hold comments.
if tokens.length >= 2 and tokens[0].generated and
tokens[0].comments?.length isnt 0 and tokens[0][1] is '' and
tokens[1][0] is 'TERMINATOR'
tokens = tokens[2...]
if tokens.length >= 1 and tokens[tokens.length - 1].generated and
tokens[tokens.length - 1].comments?.length isnt 0 and tokens[tokens.length - 1][1] is ''
tokens.pop()
# Collect referenced variable names just like in `CoffeeScript.compile`.
referencedVars = (token[1] for token in tokens when token[0] is 'IDENTIFIER')
# Generate the AST of the tokens.
ast = CoffeeScript.nodes tokens
# Add assignment to `__` variable to force the input to be an expression.
ast = new Block [new Assign (new Value new Literal '__'), ast, '=']
# Wrap the expression in a closure to support top-level `await`
# Wrap the expression in a closure to support top-level `await`.
ast = new Code [], ast
isAsync = ast.isAsync
# Invoke the wrapping closure
# Invoke the wrapping closure.
ast = new Block [new Call ast]
js = ast.compile {bare: yes, locals: Object.keys(context), referencedVars, sharedScope: yes}
if transpile
js = transpile.transpile(js, transpile.options).code
# Strip `"use strict"`, to avoid an exception on assigning to
# undeclared variable `__`.
js = js.replace /^"use strict"|^'use strict'/, ''
result = runInContext js, context, filename
# Await an async result, if necessary
# Await an async result, if necessary.
if isAsync
result.then (resolvedResult) ->
cb null, resolvedResult unless sawSIGINT
@@ -167,6 +181,31 @@ module.exports =
CoffeeScript.register()
process.argv = ['coffee'].concat process.argv[2..]
if opts.transpile
try
transpile = {}
transpile.transpile = require('babel-core').transform
catch
console.error '''
To use --transpile with an interactive REPL, babel-core must be installed either in the current folder or globally:
npm install --save-dev babel-core
or
npm install --global babel-core
And you must save options to configure Babel in one of the places it looks to find its options.
See http://coffeescript.org/#transpilation
'''
process.exit 1
transpile.options =
filename: path.resolve process.cwd(), '<repl>'
# Since the REPL compilation path is unique (in `eval` above), we need
# another way to get the `options` object attached to a module so that
# it knows later on whether it needs to be transpiled. In the case of
# the REPL, the only applicable option is `transpile`.
Module = require 'module'
originalModuleLoad = Module::load
Module::load = (filename) ->
@options = transpile: transpile.options
originalModuleLoad.call @, filename
opts = merge replDefaults, opts
repl = nodeREPL.start opts
runInContext opts.prelude, repl.context, 'prelude' if opts.prelude

View File

@@ -377,7 +377,7 @@ exports.Rewriter = class Rewriter
#
# f a, b: c, d: e, f, g: h: i, j
#
if tag is ',' and not @looksObjectish(i + 1) and inImplicitObject() and
if tag is ',' and not @looksObjectish(i + 1) and inImplicitObject() and not (@tag(i + 2) in ['FOROF', 'FORIN']) and
(nextTag isnt 'TERMINATOR' or not @looksObjectish(i + 2))
# When nextTag is OUTDENT the comma is insignificant and
# should just be ignored so embed it in the implicit object.
@@ -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

View File

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

View File

@@ -26,6 +26,94 @@ test "incorrect indentation without commas", ->
ok result[0][0] is 'a'
ok result[1]['b'] is 'c'
# Elisions
test "array elisions", ->
eq [,1].length, 2
eq [,,1,2,,].length, 5
arr = [1,,2]
eq arr.length, 3
eq arr[1], undefined
eq [,,].length, 2
test "array elisions indentation and commas", ->
arr1 = [
, 1, 2, , , 3,
4, 5, 6
, , 8, 9,
]
eq arr1.length, 12
eq arr1[5], 3
eq arr1[9], undefined
arr2 = [, , 1,
2, , 3,
, 4, 5
6
, , ,
]
eq arr2.length, 12
eq arr2[8], 5
eq arr2[1], undefined
test "array elisions destructuring", ->
arr = [1,2,3,4,5,6,7,8,9]
[,a] = arr
[,,,b] = arr
arrayEq [a,b], [2,4]
[,a,,b,,c,,,d] = arr
arrayEq [a,b,c,d], [2,4,6,9]
[
,e,
,f,
,g,
,,h] = arr
arrayEq [e,f,g,h], [2,4,6,9]
test "array elisions destructuring with splats and expansions", ->
arr = [1,2,3,4,5,6,7,8,9]
[,a,,,b...] = arr
arrayEq [a,b], [2,[5,6,7,8,9]]
[,c,...,,d,,e] = arr
arrayEq [c,d,e], [2,7,9]
[...,f,,,g,,,] = arr
arrayEq [f,g], [4,7]
test "array elisions as function parameters", ->
arr = [1,2,3,4,5,6,7,8,9]
foo = ([,a]) -> a
a = foo arr
eq a, 2
foo = ([,,,a]) -> a
a = foo arr
eq a, 4
foo = ([,a,,b,,c,,,d]) -> [a,b,c,d]
[a,b,c,d] = foo arr
arrayEq [a,b,c,d], [2,4,6,9]
test "array elisions nested destructuring", ->
arr = [
1,
[2,3, [4,5,6, [7,8,9] ] ]
]
[,a] = arr
arrayEq a[2][3], [7,8,9]
[,[,,[,b,,[,,c]]]] = arr
eq b, 5
eq c, 9
aobj = [
{},
{x: 2},
{},
[
{},
{},
{z:1, w:[1,2,4], p:3, q:4}
{},
{}
]
]
[,d,,[,,{w}]] = aobj
deepEqual d, {x:2}
arrayEq w, [1,2,4]
# Splats in Array Literals

View File

@@ -178,6 +178,24 @@ test "#713: destructuring assignment should return right-hand-side value", ->
eq nonceB, b
eq nonceB, d
test "#4787 destructuring of objects within arrays", ->
arr = [1, {a:1, b:2}]
[...,{a, b}] = arr
eq a, 1
eq b, arr[1].b
deepEqual {a, b}, arr[1]
test "#4798 destructuring of objects with splat within arrays", ->
arr = [1, {a:1, b:2}]
[...,{a, r...}] = arr
eq a, 1
deepEqual r, {b:2}
[b, {q...}] = arr
eq b, 1
deepEqual q, arr[1]
eq q.b, r.b
eq q.a, a
test "destructuring assignment with splats", ->
a = {}; b = {}; c = {}; d = {}; e = {}
[x,y...,z] = [a,b,c,d,e]

View File

@@ -1848,3 +1848,29 @@ test "#4464: backticked expressions in class body", ->
b = new B
eq 42, b.x
eq 84, b.y
test "#4724: backticked expression in a class body with hoisted member", ->
class A
`get x() { return 42; }`
hoisted: 84
a = new A
eq 42, a.x
eq 84, a.hoisted
test "#4822: nested anonymous classes use non-conflicting variable names", ->
Class = class
@a: class
@b: 1
eq Class.a.b, 1
test "#4827: executable class body wrappers have correct context", ->
test = ->
class @A
class @B extends @A
@property = 1
o = {}
test.call o
ok typeof o.A is typeof o.B is 'function'

View File

@@ -364,7 +364,7 @@ test "#3132: Place block-comments nicely", ->
return DummyClass;
})();"""
}).call(this);"""
test "#3638: Demand a whitespace after # symbol", ->
eqJS """
@@ -973,3 +973,150 @@ test "Flow comment-based syntax support", ->
fn = function(str/*: string */, num/*: number */)/*: string */ {
return str + num;
};'''
test "#4706: Flow comments around function parameters", ->
eqJS '''
identity = ###::<T>### (value ###: T ###) ###: T ### ->
value
''', '''
var identity;
identity = function/*::<T>*/(value/*: T */)/*: T */ {
return value;
};'''
test "#4706: Flow comments around function parameters", ->
eqJS '''
copy = arr.map(###:: <T> ###(item ###: T ###) ###: T ### => item)
''', '''
var copy;
copy = arr.map(/*:: <T> */(item/*: T */)/*: T */ => {
return item;
});'''
test "#4706: Flow comments after class name", ->
eqJS '''
class Container ###::<T> ###
method: ###::<U> ### () -> true
''', '''
var Container;
Container = class Container/*::<T> */ {
method() {
return true;
}
};'''
test "#4706: Identifiers with comments wrapped in parentheses remain wrapped", ->
eqJS '(arr ###: Array<number> ###)', '(arr/*: Array<number> */);'
eqJS 'other = (arr ###: any ###)', '''
var other;
other = (arr/*: any */);'''
test "#4706: Flow comments before class methods", ->
eqJS '''
class Container
###::
method: (number) => string;
method: (string) => number;
###
method: -> true
''', '''
var Container;
Container = class Container {
/*::
method: (number) => string;
method: (string) => number;
*/
method() {
return true;
}
};'''
test "#4706: Flow comments for class method params", ->
eqJS '''
class Container
method: (param ###: string ###) -> true
''', '''
var Container;
Container = class Container {
method(param/*: string */) {
return true;
}
};'''
test "#4706: Flow comments for class method returns", ->
eqJS '''
class Container
method: () ###: string ### -> true
''', '''
var Container;
Container = class Container {
method()/*: string */ {
return true;
}
};'''
test "#4706: Flow comments for function spread", ->
eqJS '''
method = (...rest ###: Array<string> ###) =>
''', '''
var method;
method = (...rest/*: Array<string> */) => {};'''
test "#4747: Flow comments for local variable declaration", ->
eqJS 'a ###: number ### = 1', '''
var a/*: number */;
a = 1;
'''
test "#4747: Flow comments for local variable declarations", ->
eqJS '''
a ###: number ### = 1
b ###: string ### = 'c'
''', '''
var a/*: number */, b/*: string */;
a = 1;
b = 'c';
'''
test "#4747: Flow comments for local variable declarations with reassignment", ->
eqJS '''
a ###: number ### = 1
b ###: string ### = 'c'
a ### some other comment ### = 2
''', '''
var a/*: number */, b/*: string */;
a = 1;
b = 'c';
a/* some other comment */ = 2;
'''
test "#4756: Comment before ? operation", ->
eqJS '''
do ->
### Comment ###
@foo ? 42
''', '''
(function() {
var ref;
/* Comment */
return (ref = this.foo) != null ? ref : 42;
})();
'''

View File

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

View File

@@ -742,3 +742,47 @@ test '#4686: comments inside interpolations that also contain CSX attributes', -
</div>;
'''
# https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html
test 'JSX fragments: empty fragment', ->
eqJS '''
<></>
''', '''
<></>;
'''
test 'JSX fragments: fragment with text nodes', ->
eqJS '''
<>
Some text.
<h2>A heading</h2>
More text.
<h2>Another heading</h2>
Even more text.
</>
''', '''
<>
Some text.
<h2>A heading</h2>
More text.
<h2>Another heading</h2>
Even more text.
</>;
'''
test 'JSX fragments: fragment with component nodes', ->
eqJS '''
Component = (props) =>
<Fragment>
<OtherComponent />
<OtherComponent />
</Fragment>
''', '''
var Component;
Component = (props) => {
return <Fragment>
<OtherComponent />
<OtherComponent />
</Fragment>;
};
'''

View File

@@ -65,7 +65,7 @@ if require?
try
assertErrorFormat """
require '#{tempFile}'
require '#{tempFile.replace /\\/g, '\\\\'}'
""",
"""
#{fs.realpathSync tempFile}:1:15: error: unexpected in
@@ -183,9 +183,9 @@ test "#1096: unexpected generated tokens", ->
for i in [1]:
1
''', '''
[stdin]:1:10: error: unexpected [
for i in [1]:
^
[stdin]:2:4: error: unexpected end of input
1
^
'''
# Unexpected regex
assertErrorFormat '{/a/i: val}', '''
@@ -808,29 +808,8 @@ test "invalid numbers", ->
^^^
'''
test "unexpected object keys", ->
assertErrorFormat '''
{[[]]}
''', '''
[stdin]:1:2: error: unexpected [
{[[]]}
^
'''
assertErrorFormat '''
{[[]]: 1}
''', '''
[stdin]:1:2: error: unexpected [
{[[]]: 1}
^
'''
assertErrorFormat '''
[[]]: 1
''', '''
[stdin]:1:1: error: unexpected [
[[]]: 1
^
'''
test "unexpected object keys", ->
assertErrorFormat '''
{(a + "b")}
''', '''
@@ -852,20 +831,6 @@ test "unexpected object keys", ->
(a + "b"): 1
^
'''
assertErrorFormat '''
a: 1, [[]]: 2
''', '''
[stdin]:1:7: error: unexpected [
a: 1, [[]]: 2
^
'''
assertErrorFormat '''
{a: 1, [[]]: 2}
''', '''
[stdin]:1:8: error: unexpected [
{a: 1, [[]]: 2}
^
'''
test "invalid object keys", ->
assertErrorFormat '''
@@ -1197,6 +1162,18 @@ test "bound functions cannot be generators", ->
^^^^^^^^^^
'''
test "#4790: bound functions cannot be generators, even when were creating IIFEs", ->
assertErrorFormat '''
=>
for x in []
for y in []
yield z
''', '''
[stdin]:4:7: error: yield cannot occur inside bound (fat arrow) functions
yield z
^^^^^^^
'''
test "CoffeeScript keywords cannot be used as unaliased names in import lists", ->
assertErrorFormat """
import { unless, baz as bar } from 'lib'
@@ -1339,6 +1316,20 @@ test "derived constructors can't use @params without calling super", ->
^^
'''
test "derived constructors can't call super with @params", ->
assertErrorFormat 'class extends A then constructor: (@a) -> super(@a)', '''
[stdin]:1:49: error: Can't call super with @params in derived class constructors
class extends A then constructor: (@a) -> super(@a)
^^
'''
test "derived constructors can't call super with buried @params", ->
assertErrorFormat 'class extends A then constructor: (@a) -> super((=> @a)())', '''
[stdin]:1:53: error: Can't call super with @params in derived class constructors
class extends A then constructor: (@a) -> super((=> @a)())
^^
'''
test "'super' is not allowed in constructor parameter defaults", ->
assertErrorFormat 'class extends A then constructor: (a = super()) ->', '''
[stdin]:1:40: error: 'super' is not allowed in constructor parameter defaults
@@ -1777,3 +1768,12 @@ test "#3098: suppressed newline should be unsuppressed by semicolon", ->
a = ; 5
^
'''
test "#4811: '///' inside a heregex comment does not close the heregex", ->
assertErrorFormat '''
/// .* # comment ///
''', '''
[stdin]:1:1: error: missing ///
/// .* # comment ///
^^^
'''

View File

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

View File

@@ -0,0 +1,3 @@
import path from 'path'
export getSep = -> path.sep

View File

@@ -1,34 +1,40 @@
return unless require?
path = require 'path'
{spawnSync, execFileSync} = require 'child_process'
{ execFileSync, spawnSync } = require 'child_process'
# Get directory containing the compiled `coffee` executable and prepend it to
# the path so `#!/usr/bin/env coffee` resolves to our locally built file.
coffeeBinDir = path.dirname require.resolve('../bin/coffee')
patchedPath = "#{coffeeBinDir}:#{process.env.PATH}"
patchedEnv = Object.assign {}, process.env, {PATH: patchedPath}
# Get the folder containing the compiled `coffee` executable and make it the
# PATH so that `#!/usr/bin/env coffee` resolves to our locally built file.
coffeeBinFolder = path.dirname require.resolve '../bin/coffee'
# For some reason, Windows requires `coffee` to be executed as `node coffee`.
coffeeCommand = if isWindows() then 'node coffee' else 'coffee'
spawnOptions =
cwd: coffeeBinFolder
encoding: 'utf8'
env:
PATH: coffeeBinFolder + (if isWindows() then ';' else ':') + process.env.PATH
shell: isWindows()
shebangScript = require.resolve './importing/shebang.coffee'
initialSpaceScript = require.resolve './importing/shebang_initial_space.coffee'
extraArgsScript = require.resolve './importing/shebang_extra_args.coffee'
initialSpaceExtraArgsScript = require.resolve './importing/shebang_initial_space_extra_args.coffee'
test "parse arguments for shebang scripts correctly (on unix platforms)", ->
test "parse arguments for shebang scripts correctly (on *nix platforms)", ->
return if isWindows()
stdout = execFileSync shebangScript, ['-abck'], {env: patchedEnv}
stdout = execFileSync shebangScript, ['-abck'], spawnOptions
expectedArgs = ['coffee', shebangScript, '-abck']
realArgs = JSON.parse stdout
arrayEq expectedArgs, realArgs
stdout = execFileSync initialSpaceScript, ['-abck'], {env: patchedEnv}
stdout = execFileSync initialSpaceScript, ['-abck'], spawnOptions
expectedArgs = ['coffee', initialSpaceScript, '-abck']
realArgs = JSON.parse stdout
arrayEq expectedArgs, realArgs
test "warn and remove -- if it is the second positional argument", ->
result = spawnSync 'coffee', [shebangScript, '--'], {env: patchedEnv}
result = spawnSync coffeeCommand, [shebangScript, '--'], spawnOptions
stderr = result.stderr.toString()
arrayEq JSON.parse(result.stdout), ['coffee', shebangScript]
ok stderr.match /^coffee was invoked with '--'/m
@@ -36,7 +42,7 @@ test "warn and remove -- if it is the second positional argument", ->
arrayEq JSON.parse(posArgs), [shebangScript, '--']
ok result.status is 0
result = spawnSync 'coffee', ['-b', shebangScript, '--'], {env: patchedEnv}
result = spawnSync coffeeCommand, ['-b', shebangScript, '--'], spawnOptions
stderr = result.stderr.toString()
arrayEq JSON.parse(result.stdout), ['coffee', shebangScript]
ok stderr.match /^coffee was invoked with '--'/m
@@ -45,16 +51,16 @@ test "warn and remove -- if it is the second positional argument", ->
ok result.status is 0
result = spawnSync(
'coffee', ['-b', shebangScript, '--', 'ANOTHER ONE'], {env: patchedEnv})
coffeeCommand, ['-b', shebangScript, '--', 'ANOTHER'], spawnOptions)
stderr = result.stderr.toString()
arrayEq JSON.parse(result.stdout), ['coffee', shebangScript, 'ANOTHER ONE']
arrayEq JSON.parse(result.stdout), ['coffee', shebangScript, 'ANOTHER']
ok stderr.match /^coffee was invoked with '--'/m
posArgs = stderr.match(/^The positional arguments were: (.*)$/m)[1]
arrayEq JSON.parse(posArgs), [shebangScript, '--', 'ANOTHER ONE']
arrayEq JSON.parse(posArgs), [shebangScript, '--', 'ANOTHER']
ok result.status is 0
result = spawnSync(
'coffee', ['--', initialSpaceScript, 'arg'], {env: patchedEnv})
coffeeCommand, ['--', initialSpaceScript, 'arg'], spawnOptions)
expectedArgs = ['coffee', initialSpaceScript, 'arg']
realArgs = JSON.parse result.stdout
arrayEq expectedArgs, realArgs
@@ -62,7 +68,7 @@ test "warn and remove -- if it is the second positional argument", ->
ok result.status is 0
test "warn about non-portable shebang lines", ->
result = spawnSync 'coffee', [extraArgsScript, 'arg'], {env: patchedEnv}
result = spawnSync coffeeCommand, [extraArgsScript, 'arg'], spawnOptions
stderr = result.stderr.toString()
arrayEq JSON.parse(result.stdout), ['coffee', extraArgsScript, 'arg']
ok stderr.match /^The script to be run begins with a shebang line with more than one/m
@@ -73,14 +79,14 @@ test "warn about non-portable shebang lines", ->
arrayEq JSON.parse(args), ['coffee', '--']
ok result.status is 0
result = spawnSync 'coffee', [initialSpaceScript, 'arg'], {env: patchedEnv}
result = spawnSync coffeeCommand, [initialSpaceScript, 'arg'], spawnOptions
stderr = result.stderr.toString()
ok stderr is ''
arrayEq JSON.parse(result.stdout), ['coffee', initialSpaceScript, 'arg']
ok result.status is 0
result = spawnSync(
'coffee', [initialSpaceExtraArgsScript, 'arg'], {env: patchedEnv})
coffeeCommand, [initialSpaceExtraArgsScript, 'arg'], spawnOptions)
stderr = result.stderr.toString()
arrayEq JSON.parse(result.stdout), ['coffee', initialSpaceExtraArgsScript, 'arg']
ok stderr.match /^The script to be run begins with a shebang line with more than one/m
@@ -93,7 +99,7 @@ test "warn about non-portable shebang lines", ->
test "both warnings will be shown at once", ->
result = spawnSync(
'coffee', [initialSpaceExtraArgsScript, '--', 'arg'], {env: patchedEnv})
coffeeCommand, [initialSpaceExtraArgsScript, '--', 'arg'], spawnOptions)
stderr = result.stderr.toString()
arrayEq JSON.parse(result.stdout), ['coffee', initialSpaceExtraArgsScript, 'arg']
ok stderr.match /^The script to be run begins with a shebang line with more than one/m

View File

@@ -329,7 +329,7 @@ test "export default implicit object", ->
test "export default multiline implicit object", ->
eqJS """
export default
foo: 'bar',
foo: 'bar'
baz: 'qux'
""",
"""
@@ -338,6 +338,22 @@ test "export default multiline implicit object", ->
baz: 'qux'
};"""
test "export default multiline implicit object with internal braces", ->
eqJS """
export default
foo: yes
bar: {
baz
}
quz: no
""",
"""
export default {
foo: true,
bar: {baz},
quz: false
};"""
test "export default assignment expression", ->
eqJS "export default foo = 'bar'",
"""
@@ -473,7 +489,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 +512,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 +620,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();"""

View File

@@ -453,8 +453,7 @@ test 'inline implicit object literals within multiline implicit object literals'
eq 0, x.b
eq 0, x.a.aa
test "object keys with interpolations", ->
# Simple cases.
test "object keys with interpolations: simple cases", ->
a = 'a'
obj = "#{a}": yes
eq obj.a, yes
@@ -465,7 +464,7 @@ test "object keys with interpolations", ->
obj = {"#{5}"}
eq obj[5], '5' # Note that the value is a string, just like the key.
# Commas in implicit object.
test "object keys with interpolations: commas in implicit object", ->
obj = "#{'a'}": 1, b: 2
deepEqual obj, {a: 1, b: 2}
obj = a: 1, "#{'b'}": 2
@@ -473,7 +472,7 @@ test "object keys with interpolations", ->
obj = "#{'a'}": 1, "#{'b'}": 2
deepEqual obj, {a: 1, b: 2}
# Commas in explicit object.
test "object keys with interpolations: commas in explicit object", ->
obj = {"#{'a'}": 1, b: 2}
deepEqual obj, {a: 1, b: 2}
obj = {a: 1, "#{'b'}": 2}
@@ -481,7 +480,7 @@ test "object keys with interpolations", ->
obj = {"#{'a'}": 1, "#{'b'}": 2}
deepEqual obj, {a: 1, b: 2}
# Commas after key with interpolation.
test "object keys with interpolations: commas after key with interpolation", ->
obj = {"#{'a'}": yes,}
eq obj.a, yes
obj = {
@@ -504,17 +503,17 @@ test "object keys with interpolations", ->
"#{'c'}": 3, "#{'d'}": 4,
deepEqual obj, {a: 1, b: 2, c: 3, d: 4}
# Key with interpolation mixed with `@prop`.
test "object keys with interpolations: key with interpolation mixed with `@prop`", ->
deepEqual (-> {@a, "#{'b'}": 2}).call(a: 1), {a: 1, b: 2}
# Evaluate only once.
test "object keys with interpolations: evaluate only once", ->
count = 0
b = -> count++; 'b'
obj = {"#{b()}"}
eq obj.b, 'b'
a = -> count++; 'a'
obj = {"#{a()}"}
eq obj.a, 'a'
eq count, 1
# Evaluation order.
test "object keys with interpolations: evaluation order", ->
arr = []
obj =
a: arr.push 1
@@ -527,13 +526,13 @@ test "object keys with interpolations", ->
arrayEq arr, [1..7]
deepEqual obj, {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7}
# Object starting with dynamic key.
test "object keys with interpolations: object starting with dynamic key", ->
obj =
"#{'a'}": 1
b: 2
deepEqual obj, {a: 1, b: 2}
# Comments in implicit object.
test "object keys with interpolations: comments in implicit object", ->
obj =
### leading comment ###
"#{'a'}": 1
@@ -564,7 +563,7 @@ test "object keys with interpolations", ->
}
deepEqual obj, {a: 1, b: 2, c: 3, d: 4, e: 5}
# A more complicated case.
test "object keys with interpolations: more complicated case", ->
obj = {
"#{'interpolated'}":
"""
@@ -582,6 +581,212 @@ test "#4324: Shorthand after interpolated key", ->
eq 1, obj[1]
eq 2, obj.a
test "computed property keys: simple cases", ->
a = 'a'
obj = [a]: yes
eq obj.a, yes
obj = {[a]: yes}
eq obj.a, yes
obj = {[a]}
eq obj.a, 'a'
obj = {[5]}
eq obj[5], 5
obj = {['5']}
eq obj['5'], '5'
test "computed property keys: commas in implicit object", ->
obj = ['a']: 1, b: 2
deepEqual obj, {a: 1, b: 2}
obj = a: 1, ['b']: 2
deepEqual obj, {a: 1, b: 2}
obj = ['a']: 1, ['b']: 2
deepEqual obj, {a: 1, b: 2}
test "computed property keys: commas in explicit object", ->
obj = {['a']: 1, b: 2}
deepEqual obj, {a: 1, b: 2}
obj = {a: 1, ['b']: 2}
deepEqual obj, {a: 1, b: 2}
obj = {['a']: 1, ['b']: 2}
deepEqual obj, {a: 1, b: 2}
test "computed property keys: commas after key with interpolation", ->
obj = {['a']: yes,}
eq obj.a, yes
obj = {
['a']: 1,
['b']: 2,
### herecomment ###
['c']: 3,
}
deepEqual obj, {a: 1, b: 2, c: 3}
obj =
['a']: 1,
['b']: 2,
### herecomment ###
['c']: 3,
deepEqual obj, {a: 1, b: 2, c: 3}
obj =
['a']: 1,
['b']: 2,
### herecomment ###
['c']: 3, ['d']: 4,
deepEqual obj, {a: 1, b: 2, c: 3, d: 4}
test "computed property keys: key with interpolation mixed with `@prop`", ->
deepEqual (-> {@a, ['b']: 2}).call(a: 1), {a: 1, b: 2}
test "computed property keys: evaluate only once", ->
count = 0
a = -> count++; 'a'
obj = {[a()]}
eq obj.a, 'a'
eq count, 1
test "computed property keys: evaluation order", ->
arr = []
obj =
a: arr.push 1
b: arr.push 2
['c']: arr.push 3
['d']: arr.push 4
e: arr.push 5
['f']: arr.push 6
g: arr.push 7
arrayEq arr, [1..7]
deepEqual obj, {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7}
test "computed property keys: object starting with dynamic key", ->
obj =
['a']: 1
b: 2
deepEqual obj, {a: 1, b: 2}
test "computed property keys: comments in implicit object", ->
obj =
### leading comment ###
['a']: 1
### middle ###
['b']: 2
# regular comment
'c': 3
### foo ###
d: 4
['e']: 5
deepEqual obj, {a: 1, b: 2, c: 3, d: 4, e: 5}
obj = {
### leading comment ###
['a']: 1
### middle ###
['b']: 2
# regular comment
'c': 3
### foo ###
d: 4
['e']: 5
}
deepEqual obj, {a: 1, b: 2, c: 3, d: 4, e: 5}
test "computed property keys: more complicated case", ->
obj = {
['interpolated']:
['nested']:
123: 456
}
deepEqual obj,
interpolated:
nested:
123: 456
test "computed property keys: empty array as key", ->
o1 = { [[]] }
deepEqual o1, { [[]]: [] }
arrayEq o1[[]], []
o2 = { [[]]: 1 }
deepEqual o2, { [[]]: 1 }
eq o2[[]], 1
o3 = [[]]: 1
deepEqual o3, { [[]]: 1 }
deepEqual o3, { [[]]: 1 }
eq o3[[]], 1
o4 = a: 1, [[]]: 2
deepEqual o4, { a: 1, [[]]: 2 }
eq o4.a, 1,
eq o4[[]], 2
o5 = { a: 1, [[]]: 2 }
deepEqual o5, { a: 1, [[]]: 2 }
eq o5.a, 1,
eq o5[[]], 2
test "computed property keys: shorthand after computed property key", ->
a = 2
obj = {[1]: 1, a}
eq 1, obj[1]
eq 2, obj.a
test "computed property keys: shorthand computed property key", ->
a = 'b'
o = {[a]}
p = {a}
r = {['a']}
eq o.b, 'b'
eq p.a, o.b
eq r.a, 'a'
foo = -> "a"
obj = { [foo()] }
eq obj.a, 'a'
test "computed property keys: arrays", ->
b = 'b'
f = (c) -> "#{c}1"
obj =
['a']: [1, 2, 3]
[b]: [4, 5, 6]
[f(b)]: [7, 8, 9]
arrayEq obj.a, [1, 2, 3]
arrayEq obj.b, [4, 5, 6]
arrayEq obj.b1, [7, 8, 9]
test "computed property keys: examples from developer.mozilla.org (Object initializer)", ->
i = 0
obj =
['foo' + ++i]: i
['foo' + ++i]: i
['foo' + ++i]: i
eq obj.foo1, 1
eq obj.foo2, 2
eq obj.foo3, 3
param = 'size'
config =
[param]: 12,
['mobile' + param.charAt(0).toUpperCase() + param.slice(1)]: 4
deepEqual config, {size: 12, mobileSize: 4}
test "computed property keys: [Symbol.iterator]", ->
obj =
[Symbol.iterator]: ->
yield "hello"
yield "world"
arrayEq [obj...], ['hello', 'world']
test "computed property keys: Class property", ->
increment_method = "increment"
decrement_method = "decrement"
class Obs
constructor: (@count) ->
[increment_method]: -> @count += 1
[decrement_method]: -> @count -= 1
ob = new Obs 2
eq ob.increment(), 3
eq ob.decrement(), 2
test "#1263: Braceless object return", ->
fn = ->
return
@@ -652,20 +857,22 @@ test "#4544: Postfix conditionals in first line of implicit object literals", ->
test "#4579: Postfix for/while/until in first line of implicit object literals", ->
two =
foo:
bar: x for x in [1, 2, 3]
bar1: x for x in [1, 2, 3]
bar2: x + y for x, y in [1, 2, 3]
baz: 1337
arrayEq [1, 2, 3], two.foo.bar
arrayEq [1, 2, 3], two.foo.bar1
arrayEq [1, 3, 5], two.foo.bar2
eq 1337, two.foo.baz
f = (x) -> x
three =
foo: f
# Uncomment when #4580 is fixed
# bar: x + y for x, y of a: 'b', c: 'd'
bar: x + 'c' for x of a: 1, b: 2
bar1: x + y for x, y of a: 'b', c: 'd'
bar2: x + 'c' for x of a: 1, b: 2
baz: 1337
arrayEq ['ac', 'bc'], three.foo.bar
arrayEq ['ab', 'cd'], three.foo.bar1
arrayEq ['ac', 'bc'], three.foo.bar2
eq 1337, three.foo.baz
four =
@@ -696,4 +903,3 @@ test "#4579: Postfix for/while/until in first line of implicit object literals",
baz: 1337
arrayEq [4, 3, 2, 1, 0], six.foo.bar
eq 1337, six.foo.baz

View File

@@ -313,3 +313,16 @@ test "#4248: Unicode code point escapes", ->
"""
/a\\udab3\\uddef/;
"""
test "#4811, heregex comments with ///", ->
eqJS """
///
a | # comment with ///
b # /// 'heregex' in comment will be consumed
///
""",
"""
// comment with ///
// /// 'heregex' in comment will be consumed
/a|b/;
"""

View File

@@ -77,6 +77,14 @@ testRepl "empty command evaluates to undefined", (input, output) ->
input.emitLine ''
eq 'undefined', output.lastWrite()
testRepl "#4763: comment evaluates to undefined", (input, output) ->
input.emitLine '# comment'
eq 'undefined', output.lastWrite()
testRepl "#4763: multiple comments evaluate to undefined", (input, output) ->
input.emitLine '### a ### ### b ### # c'
eq 'undefined', output.lastWrite()
testRepl "ctrl-v toggles multiline prompt", (input, output) ->
input.emit 'keypress', null, ctrlV
eq '------> ', output.lastWrite(0)
@@ -122,6 +130,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