Compare commits

...

19 Commits
2.3.1 ... 2.4.0

Author SHA1 Message Date
Geoffrey Booth
e6f6aa8c85 Version bump in lockfile 2019-03-30 11:33:20 -07:00
Geoffrey Booth
c09d8fbedb Release 2.4.0 (#5182)
* cake doc:site:watch should also watch the changelog files

* Changelog for 2.4.0

* 2.4.0 output
2019-03-30 11:31:22 -07:00
Geoffrey Booth
f6d63776c3 ES module version of compiler for use in browsers; dynamic import() docs; revised Stage 3 policy (#5177)
* Build both a legacy and modern browser compiler

* Dynamic import example and documentation

* Update the docs to use the modern browser compiler if the browser supports it

* Update policy regarding Stage 3 features

* This never made sense, and assigning a string to index 0 *of a string* throws in Module mode (and silently does nothing in Script mode) so remove this unneeded code that throws when compiling `fn for i from from iterable` in Module mode

* Have browser-based tests use the ES module version if supported

* Simplify building logic

* Update output

* For the ES module version of the browser compiler, don't automatically attach the runScripts event handler

* Consistent comments

* Fix comment
2019-03-26 23:55:31 -07:00
Ruben Bridgewater
41b31c7293 Fix repl.rli deprecation (#5178)
The `rli` property is just a reference to itself. It still exists
for legacy reasons but it will likely be removed in a future major
version. This makes sure everything works as expected.
2019-03-24 19:12:32 -07:00
Geoffrey Booth
ec034e2673 Fix tests (#5176)
* Fix cake test:integrations per newer Webpack

* Update dependencies

* Update dependencies
2019-03-23 23:28:13 -07:00
Julian Rosse
ff24e5ce52 Dynamic import (#5169)
* dynamic import

* updated grammar

* specify callable

* DynamicImportCall

* Fix from code review

Co-Authored-By: helixbass <julian@helixbass.net>

* recompile
2019-03-20 13:08:10 -07:00
Julian Rosse
ca275c2a1c Fix #5128: parens around default param (#5167)
* compile params at LEVEL_PAREN

* test
2019-03-14 18:14:35 -07:00
Alex
63ffe0aead Fix 5085 (#5145)
* Add test for #5085

    $ cake test
    failed 1 and passed 1274 tests in 4.81 seconds

      #5085: Bug: @ reference to class not maintained in do block
      AssertionError [ERR_ASSERTION]: Expected undefined to equal 2

* Fix #5085: @ reference to class in "do" block

Assuming that a bound Code node inside an ExecutableClassBody without a
name must be a "do" block.

* Additional tests

https://github.com/jashkenas/coffeescript/pull/5145#issuecomment-462127244

Also switched to concat'g strings for test values, as opposed to
incrementing numbers: makes the tests a bit easier to read.
2019-02-11 07:28:04 -08:00
Robert de Forest
247b511c6a Remove extra word in comment in src/nodes.coffee (#5158) 2019-02-09 18:48:24 -08:00
Adrian
2f82b75862 implement coffeescript.registerCompiled method (#5130)
* implement coffeescript._addSoucrse method

This method enables an external module to implement caching of
compilation results. When the compiled js source is loaded from cache,
the original coffee code should be added with this method in order to
enable the Error.prepareStackTrace below to correctly adjust the stack
trace for the corresponding file (the source map will be generated on
demand).

* replace _addSource with registerCompiled

* extract the logic from _compileFile into _compileRawFileContent

_compileFile takes care of logging the file and calls _compileRawFileContent

this way an external caching implementation which computes cache key
based on raw content of the sources file, can reuse the logic of
_compileFile and avoid having calling `fs.readFileSync` for the file
more twice in case of cache miss

* remove 'output' argument from registerCompiled
2018-11-28 09:09:06 -08:00
Geoffrey Booth
294bb4754e Fix #5112: A string of ', ' in an array should not be detected as an elision (#5113) 2018-10-05 06:45:54 -07:00
Geoffrey Booth
6e86b67818 Release 2.3.2 (#5110)
* Bump version to 2.3.2

* 2.3.2 changelog

* Update output for 2.3.2
2018-09-19 23:53:49 -07:00
Geoffrey Booth
b4dceaea67 Fix #5086: Don't generate unnecessary interpolations in JSX tags when the tags contain only here (/* ... */) comments (#5108) 2018-09-18 08:02:41 -07:00
Julian Rosse
6225627579 Fix #4609: support new.target (#5106)
* support new.target

* check token type
2018-09-16 13:52:47 -07:00
Geoffrey Booth
c4245e50c2 Babel 7 (#5105)
* Port to Babel 7

Use the Babel 7 @babel/core transpiler, falling back to the older babel-core version if possible.

* Use Babel 7 and preset-env 7 to build the browser compiler and test Babel transpilation

* Update docs for Babel 7
2018-09-09 13:41:49 -07:00
Geoffrey Booth
98b2a69416 Update dependencies; disable some babel-minify transforms to work around https://github.com/babel/minify/issues/893 (#5095) 2018-08-14 08:47:38 -07:00
Geoffrey Booth
7f8b36a8bd Revert "fix momentum scrolling on iOS (#5083)" (#5084)
This reverts commit 812571843c.
2018-06-16 15:35:34 -07:00
Paul Nta
812571843c fix momentum scrolling on iOS (#5083) 2018-06-16 15:32:16 -07:00
Julian Rosse
70f6cb70e2 Allow yield indented object (#5072)
* allow yield indented object

* allow await indented object

* fixes from code review
2018-06-10 21:45:45 -07:00
64 changed files with 15132 additions and 2971 deletions

View File

@@ -1,3 +1,3 @@
{
"presets": ["env"]
"presets": ["@babel/env"]
}

View File

@@ -66,15 +66,18 @@ build = (callback) ->
buildParser()
buildExceptParser callback
transpile = (code) ->
babel = require 'babel-core'
transpile = (code, options = {}) ->
options.minify = process.env.MINIFY isnt 'false'
options.transform = process.env.TRANSFORM isnt 'false'
babel = require '@babel/core'
presets = []
# Exclude the `modules` plugin in order to not break the `}(this));`
# at the end of the `build:browser` code block.
presets.push ['env', {modules: no}] unless process.env.TRANSFORM is 'false'
presets.push ['minify', {mangle: no}] unless process.env.MINIFY is 'false'
presets.push ['@babel/env', {modules: no}] if options.transform
presets.push ['minify', {mangle: no, evaluate: no, removeUndefined: no}] if options.minify
babelOptions =
compact: process.env.MINIFY isnt 'false'
compact: not options.minify
comments: not options.minify
presets: presets
sourceType: 'script'
{ code } = babel.transform code, babelOptions unless presets.length is 0
@@ -140,13 +143,18 @@ task 'build:browser', 'merge the built scripts into a single file for use in a b
return module.exports;
})();
"""
# From here, we generate two outputs: a legacy script output for all browsers
# and a module output for browsers that support `<script type="module">`.
code = """
var CoffeeScript = function() {
function require(path){ return require[path]; }
#{code}
return require['./browser'];
}();
"""
scriptCode = transpile """
(function(root) {
var CoffeeScript = function() {
function require(path){ return require[path]; }
#{code}
return require['./browser'];
}();
#{code}
if (typeof define === 'function' && define.amd) {
define(function() { return CoffeeScript; });
@@ -155,10 +163,20 @@ task 'build:browser', 'merge the built scripts into a single file for use in a b
}
}(this));
"""
code = transpile code
outputFolder = "docs/v#{majorVersion}/browser-compiler"
fs.mkdirSync outputFolder unless fs.existsSync outputFolder
fs.writeFileSync "#{outputFolder}/coffeescript.js", header + '\n' + code
moduleCode = """
#{code}
export default CoffeeScript;
const { VERSION, compile, eval: evaluate, load, run, runScripts } = CoffeeScript;
export { VERSION, compile, evaluate as eval, load, run, runScripts };
"""
for folder in ['browser-compiler', 'browser-compiler-modern']
outputFolder = "docs/v#{majorVersion}/#{folder}"
fs.mkdirSync outputFolder unless fs.existsSync outputFolder
fs.writeFileSync "#{outputFolder}/coffeescript.js", """
#{header}
#{if folder is 'browser-compiler' then scriptCode else moduleCode}
"""
task 'build:browser:full', 'merge the built scripts into a single file for use in a browser, and test it', ->
invoke 'build:browser'
@@ -174,11 +192,12 @@ task 'build:watch:harmony', 'watch and continually rebuild the CoffeeScript comp
buildDocs = (watch = no) ->
# Constants
indexFile = 'documentation/site/index.html'
siteSourceFolder = "documentation/site"
sectionsSourceFolder = 'documentation/sections'
examplesSourceFolder = 'documentation/examples'
outputFolder = "docs/v#{majorVersion}"
indexFile = 'documentation/site/index.html'
siteSourceFolder = "documentation/site"
sectionsSourceFolder = 'documentation/sections'
changelogSourceFolder = 'documentation/sections/changelog'
examplesSourceFolder = 'documentation/examples'
outputFolder = "docs/v#{majorVersion}"
# Helpers
releaseHeader = (date, version, prevVersion) ->
@@ -261,7 +280,7 @@ buildDocs = (watch = no) ->
catch exception
if watch
for target in [indexFile, siteSourceFolder, examplesSourceFolder, sectionsSourceFolder]
for target in [indexFile, siteSourceFolder, examplesSourceFolder, sectionsSourceFolder, changelogSourceFolder]
fs.watch target, interval: 200, renderIndex
log 'watching...', green
@@ -486,6 +505,9 @@ task 'test:integrations', 'test the module integrated with other libraries and e
webpack = require 'webpack'
webpack {
entry: './'
optimization:
# Webpacks minification causes the CoffeeScript module to fail some tests.
minimize: off
output:
path: tmpdir
filename: 'coffeescript.js'

View File

@@ -0,0 +1 @@
v2/browser-compiler-modern

View File

@@ -262,7 +262,7 @@ This happens on page load.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">runScripts</span> = -&gt;</span>
<div class="content"><div class='highlight'><pre>CoffeeScript.runScripts = <span class="hljs-function">-&gt;</span>
scripts = <span class="hljs-built_in">window</span>.<span class="hljs-built_in">document</span>.getElementsByTagName <span class="hljs-string">'script'</span>
coffeetypes = [<span class="hljs-string">'text/coffeescript'</span>, <span class="hljs-string">'text/literate-coffeescript'</span>]
coffees = (s <span class="hljs-keyword">for</span> s <span class="hljs-keyword">in</span> scripts <span class="hljs-keyword">when</span> s.type <span class="hljs-keyword">in</span> coffeetypes)
@@ -321,14 +321,19 @@ only one CoffeeScript script block to parse.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-10">&#182;</a>
</div>
<p>Listen for window load, both in decent browsers and in IE.</p>
<p>Listen for window load, both in decent browsers and in IE.
Only attach this event handler on startup for the
non-ES module version of the browser compiler, to preserve
backward compatibility while letting the ES module version
be importable without side effects.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-keyword">if</span> <span class="hljs-built_in">window</span>.addEventListener
<span class="hljs-built_in">window</span>.addEventListener <span class="hljs-string">'DOMContentLoaded'</span>, runScripts, <span class="hljs-literal">no</span>
<span class="hljs-keyword">else</span>
<span class="hljs-built_in">window</span>.attachEvent <span class="hljs-string">'onload'</span>, runScripts</pre></div></div>
<div class="content"><div class='highlight'><pre><span class="hljs-keyword">if</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">is</span> <span class="hljs-built_in">window</span>
<span class="hljs-keyword">if</span> <span class="hljs-built_in">window</span>.addEventListener
<span class="hljs-built_in">window</span>.addEventListener <span class="hljs-string">'DOMContentLoaded'</span>, CoffeeScript.runScripts, <span class="hljs-literal">no</span>
<span class="hljs-keyword">else</span>
<span class="hljs-built_in">window</span>.attachEvent <span class="hljs-string">'onload'</span>, CoffeeScript.runScripts</pre></div></div>
</li>

View File

@@ -282,6 +282,32 @@ its not likely to be used. Save in form of <code>filename</code>: [<code>(sou
<div class="pilwrap ">
<a class="pilcrow" href="#section-10">&#182;</a>
</div>
<p>This is exported to enable an external module to implement caching of
compilation results. When the compiled js source is loaded from cache, the
original coffee code should be added with this method in order to enable the
Error.prepareStackTrace below to correctly adjust the stack trace for the
corresponding file (the source map will be generated on demand).</p>
</div>
<div class="content"><div class='highlight'><pre>exports.registerCompiled = registerCompiled = <span class="hljs-function"><span class="hljs-params">(filename, source, sourcemap)</span> -&gt;</span>
sources[filename] ?= []
sources[filename].push source
<span class="hljs-keyword">if</span> sourcemap?
sourceMaps[filename] ?= []
sourceMaps[filename].push sourcemap</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 CoffeeScript code to JavaScript, using the Coffee/Jison compiler.</p>
<p>If <code>options.sourceMap</code> is specified, then <code>options.filename</code> must also be
specified. All options that can be passed to <code>SourceMap#generate</code> may also
@@ -298,11 +324,11 @@ doing programmatic lookups.</p>
</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>Clone <code>options</code>, to avoid mutating the <code>options</code> object passed in.</p>
@@ -313,11 +339,11 @@ doing programmatic lookups.</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>Always generate a source map if no filename is passed in, since without a
a filename we have no way to retrieve this source later in the event that
@@ -330,8 +356,6 @@ we need to recompile it to get a source map for <code>prepareStackTrace</code>.<
checkShebangLine filename, code
sources[filename] ?= []
sources[filename].push code
map = <span class="hljs-keyword">new</span> SourceMap <span class="hljs-keyword">if</span> generateSourceMap
tokens = lexer.tokenize code, options</pre></div></div>
@@ -339,11 +363,11 @@ we need to recompile it to get a source map for <code>prepareStackTrace</code>.<
</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>Pass a list of referenced variables, so that generated variables wont get
the same name.</p>
@@ -357,11 +381,11 @@ the same name.</p>
</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>Check for import or export; if found, force bare mode.</p>
@@ -385,11 +409,11 @@ the same name.</p>
</li>
<li id="section-15">
<li id="section-16">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-15">&#182;</a>
<a class="pilcrow" href="#section-16">&#182;</a>
</div>
<p>Update the sourcemap with data from each fragment.</p>
@@ -400,11 +424,11 @@ the same name.</p>
</li>
<li id="section-16">
<li id="section-17">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-16">&#182;</a>
<a class="pilcrow" href="#section-17">&#182;</a>
</div>
<p>Do not include empty, whitespace, or semicolon-only fragments.</p>
@@ -425,11 +449,11 @@ the same name.</p>
</li>
<li id="section-17">
<li id="section-18">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-17">&#182;</a>
<a class="pilcrow" href="#section-18">&#182;</a>
</div>
<p>Copy the code from each fragment into the final JavaScript.</p>
@@ -443,8 +467,6 @@ the same name.</p>
<span class="hljs-keyword">if</span> generateSourceMap
v3SourceMap = map.generate options, code
sourceMaps[filename] ?= []
sourceMaps[filename].push map
<span class="hljs-keyword">if</span> options.transpile
<span class="hljs-keyword">if</span> <span class="hljs-keyword">typeof</span> options.transpile <span class="hljs-keyword">isnt</span> <span class="hljs-string">'object'</span></pre></div></div>
@@ -452,11 +474,11 @@ the same name.</p>
</li>
<li id="section-18">
<li id="section-19">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-18">&#182;</a>
<a class="pilcrow" href="#section-19">&#182;</a>
</div>
<p>This only happens if run via the Node API and <code>transpile</code> is set to
something other than an object.</p>
@@ -468,11 +490,11 @@ something other than an object.</p>
</li>
<li id="section-19">
<li id="section-20">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-19">&#182;</a>
<a class="pilcrow" href="#section-20">&#182;</a>
</div>
<p>Get the reference to Babel that we have been passed if this compiler
is run via the CLI or Node API.</p>
@@ -487,11 +509,11 @@ is run via the CLI or Node API.</p>
</li>
<li id="section-20">
<li id="section-21">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-20">&#182;</a>
<a class="pilcrow" href="#section-21">&#182;</a>
</div>
<p>See <a href="https://github.com/babel/babel/issues/827#issuecomment-77573107">https://github.com/babel/babel/issues/827#issuecomment-77573107</a>:
Babel can take a v3 source map object as input in <code>inputSourceMap</code>
@@ -512,6 +534,8 @@ and it will return an <em>updated</em> v3 source map object in its output.</p>
sourceURL = <span class="hljs-string">"//# sourceURL=<span class="hljs-subst">#{options.filename ? <span class="hljs-string">'coffeescript'</span>}</span>"</span>
js = <span class="hljs-string">"<span class="hljs-subst">#{js}</span>\n<span class="hljs-subst">#{sourceMapDataURI}</span>\n<span class="hljs-subst">#{sourceURL}</span>"</span>
registerCompiled filename, code, map
<span class="hljs-keyword">if</span> options.sourceMap
{
js
@@ -524,11 +548,11 @@ and it will return an <em>updated</em> v3 source map object in its output.</p>
</li>
<li id="section-21">
<li id="section-22">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-21">&#182;</a>
<a class="pilcrow" href="#section-22">&#182;</a>
</div>
<p>Tokenize a string of CoffeeScript code, and return the array of tokens.</p>
@@ -540,11 +564,11 @@ and it will return an <em>updated</em> v3 source map object in its output.</p>
</li>
<li id="section-22">
<li id="section-23">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-22">&#182;</a>
<a class="pilcrow" href="#section-23">&#182;</a>
</div>
<p>Parse a string of CoffeeScript code or an array of lexed tokens, and
return the AST. You can then compile it by calling <code>.compile()</code> on the root,
@@ -561,11 +585,11 @@ or traverse it by using <code>.traverseChildren()</code> with a callback.</p>
</li>
<li id="section-23">
<li id="section-24">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-23">&#182;</a>
<a class="pilcrow" href="#section-24">&#182;</a>
</div>
<p>This file used to export these methods; leave stubs that throw warnings
instead. These methods have been moved into <code>index.coffee</code> to provide
@@ -581,11 +605,11 @@ environment.</p>
</li>
<li id="section-24">
<li id="section-25">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-24">&#182;</a>
<a class="pilcrow" href="#section-25">&#182;</a>
</div>
<p>Instantiate a Lexer for our use here.</p>
@@ -596,11 +620,11 @@ environment.</p>
</li>
<li id="section-25">
<li id="section-26">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-25">&#182;</a>
<a class="pilcrow" href="#section-26">&#182;</a>
</div>
<p>The real Lexer produces a generic stream of tokens. This object provides a
thin wrapper around it, compatible with the Jison API. We can then pass it
@@ -626,11 +650,11 @@ directly as a “Jison lexer.”</p>
</li>
<li id="section-26">
<li id="section-27">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-26">&#182;</a>
<a class="pilcrow" href="#section-27">&#182;</a>
</div>
<p>Make all the AST nodes visible to the parser.</p>
@@ -641,11 +665,11 @@ directly as a “Jison lexer.”</p>
</li>
<li id="section-27">
<li id="section-28">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-27">&#182;</a>
<a class="pilcrow" href="#section-28">&#182;</a>
</div>
<p>Override Jisons default error handling function.</p>
@@ -656,11 +680,11 @@ directly as a “Jison lexer.”</p>
</li>
<li id="section-28">
<li id="section-29">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-28">&#182;</a>
<a class="pilcrow" href="#section-29">&#182;</a>
</div>
<p>Disregard Jisons message, it contains redundant line number information.
Disregard the token, we take its value directly from the lexer in case
@@ -684,11 +708,11 @@ the error is caused by a generated token which might refer to its origin.</p>
</li>
<li id="section-29">
<li id="section-30">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-29">&#182;</a>
<a class="pilcrow" href="#section-30">&#182;</a>
</div>
<p>The second argument has a <code>loc</code> property, which should have the location
data for this token. Unfortunately, Jison seems to send an outdated <code>loc</code>
@@ -702,11 +726,11 @@ from the lexer.</p>
</li>
<li id="section-30">
<li id="section-31">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-30">&#182;</a>
<a class="pilcrow" href="#section-31">&#182;</a>
</div>
<p>Based on <a href="http://v8.googlecode.com/svn/branches/bleeding_edge/src/messages.js">http://v8.googlecode.com/svn/branches/bleeding_edge/src/messages.js</a>
Modified to handle sourceMap</p>
@@ -734,11 +758,11 @@ Modified to handle sourceMap</p>
</li>
<li id="section-31">
<li id="section-32">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-31">&#182;</a>
<a class="pilcrow" href="#section-32">&#182;</a>
</div>
<p>Check for a sourceMap position</p>
@@ -781,11 +805,11 @@ Modified to handle sourceMap</p>
</li>
<li id="section-32">
<li id="section-33">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-32">&#182;</a>
<a class="pilcrow" href="#section-33">&#182;</a>
</div>
<p>Skip files that we didnt compile, like Node system files that appear in
the stack trace, as they never have source maps.</p>
@@ -800,11 +824,11 @@ the stack trace, as they never have source maps.</p>
</li>
<li id="section-33">
<li id="section-34">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-33">&#182;</a>
<a class="pilcrow" href="#section-34">&#182;</a>
</div>
<p>CoffeeScript compiled in a browser or via <code>CoffeeScript.compile</code> or <code>.run</code>
may get compiled with <code>options.filename</code> thats missing, which becomes
@@ -819,11 +843,11 @@ filename of the script file. See if we have a source map cached under
</li>
<li id="section-34">
<li id="section-35">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-34">&#182;</a>
<a class="pilcrow" href="#section-35">&#182;</a>
</div>
<p>Work backwards from the most recent anonymous source maps, until we find
one that works. This isnt foolproof; there is a chance that multiple
@@ -840,11 +864,11 @@ and its not foolproof either.</p>
</li>
<li id="section-35">
<li id="section-36">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-35">&#182;</a>
<a class="pilcrow" href="#section-36">&#182;</a>
</div>
<p>If all else fails, recompile this source to get a source map. We need the
previous section (for <code>&lt;anonymous&gt;</code>) despite this option, because after it
@@ -867,11 +891,11 @@ time the source map we want is the last one.</p>
</li>
<li id="section-36">
<li id="section-37">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-36">&#182;</a>
<a class="pilcrow" href="#section-37">&#182;</a>
</div>
<p>Based on <a href="http://goo.gl/ZTx1p">michaelficarra/CoffeeScriptRedux</a>
NodeJS / V8 have no support for transforming positions in stack traces using

View File

@@ -875,8 +875,11 @@ browsers) or use a proper build chain like Gulp or Webpack.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">try</span>
<span class="hljs-built_in">require</span> <span class="hljs-string">'babel-core'</span>
<span class="hljs-keyword">catch</span></pre></div></div>
<span class="hljs-built_in">require</span> <span class="hljs-string">'@babel/core'</span>
<span class="hljs-keyword">catch</span>
<span class="hljs-keyword">try</span>
<span class="hljs-built_in">require</span> <span class="hljs-string">'babel-core'</span>
<span class="hljs-keyword">catch</span></pre></div></div>
</li>
@@ -892,21 +895,21 @@ locally or globally.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> <span class="hljs-built_in">require</span>.resolve(<span class="hljs-string">'.'</span>).indexOf(process.cwd()) <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
<span class="hljs-built_in">console</span>.error <span class="hljs-string">'''
To use --transpile, you must have babel-core installed:
npm install --save-dev babel-core
And you must save options to configure Babel in one of the places it looks to find its options.
See https://coffeescript.org/#transpilation
'''</span>
<span class="hljs-keyword">else</span>
<span class="hljs-built_in">console</span>.error <span class="hljs-string">'''
To use --transpile with globally-installed CoffeeScript, you must have babel-core installed globally:
npm install --global babel-core
And you must save options to configure Babel in one of the places it looks to find its options, relative to the file being compiled or to the current folder.
See https://coffeescript.org/#transpilation
'''</span>
process.exit <span class="hljs-number">1</span>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> <span class="hljs-built_in">require</span>.resolve(<span class="hljs-string">'.'</span>).indexOf(process.cwd()) <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
<span class="hljs-built_in">console</span>.error <span class="hljs-string">'''
To use --transpile, you must have @babel/core installed:
npm install --save-dev @babel/core
And you must save options to configure Babel in one of the places it looks to find its options.
See https://coffeescript.org/#transpilation
'''</span>
<span class="hljs-keyword">else</span>
<span class="hljs-built_in">console</span>.error <span class="hljs-string">'''
To use --transpile with globally-installed CoffeeScript, you must have @babel/core installed globally:
npm install --global @babel/core
And you must save options to configure Babel in one of the places it looks to find its options, relative to the file being compiled or to the current folder.
See https://coffeescript.org/#transpilation
'''</span>
process.exit <span class="hljs-number">1</span>
opts.transpile = {} <span class="hljs-keyword">unless</span> <span class="hljs-keyword">typeof</span> opts.transpile <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span></pre></div></div>

View File

@@ -442,6 +442,7 @@ wrapped in braces: E.g <code>a = b if do -&gt; f a is 1</code>, <code>if f (a) -
Yield: [
o <span class="hljs-string">'YIELD'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Op $<span class="hljs-number">1</span>, <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal <span class="hljs-string">''</span>
o <span class="hljs-string">'YIELD Expression'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Op $<span class="hljs-number">1</span>, $<span class="hljs-number">2</span>
o <span class="hljs-string">'YIELD INDENT Object OUTDENT'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Op $<span class="hljs-number">1</span>, $<span class="hljs-number">3</span>
o <span class="hljs-string">'YIELD FROM Expression'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Op $<span class="hljs-number">1.</span>concat($<span class="hljs-number">2</span>), $<span class="hljs-number">3</span>
]</pre></div></div>
@@ -615,6 +616,7 @@ the ordinary <strong>Assign</strong> is that these allow numbers and strings as
o <span class="hljs-string">'Super'</span>
o <span class="hljs-string">'This'</span>
o <span class="hljs-string">'SUPER Arguments'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> SuperCall LOC(<span class="hljs-number">1</span>)(<span class="hljs-keyword">new</span> Super), $<span class="hljs-number">2</span>, <span class="hljs-literal">no</span>, $<span class="hljs-number">1</span>
o <span class="hljs-string">'DYNAMIC_IMPORT Arguments'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> DynamicImportCall LOC(<span class="hljs-number">1</span>)(<span class="hljs-keyword">new</span> DynamicImport), $<span class="hljs-number">2</span>
o <span class="hljs-string">'SimpleObjAssignable Arguments'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Call (<span class="hljs-keyword">new</span> Value $<span class="hljs-number">1</span>), $<span class="hljs-number">2</span>
o <span class="hljs-string">'ObjSpreadExpr Arguments'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Call $<span class="hljs-number">1</span>, $<span class="hljs-number">2</span>
]
@@ -1088,6 +1090,7 @@ and optional references to the superclass.</p>
o <span class="hljs-string">'Value OptFuncExist String'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> TaggedTemplateCall $<span class="hljs-number">1</span>, $<span class="hljs-number">3</span>, $<span class="hljs-number">2</span>
o <span class="hljs-string">'Value OptFuncExist Arguments'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Call $<span class="hljs-number">1</span>, $<span class="hljs-number">3</span>, $<span class="hljs-number">2</span>
o <span class="hljs-string">'SUPER OptFuncExist Arguments'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> SuperCall LOC(<span class="hljs-number">1</span>)(<span class="hljs-keyword">new</span> Super), $<span class="hljs-number">3</span>, $<span class="hljs-number">2</span>, $<span class="hljs-number">1</span>
o <span class="hljs-string">'DYNAMIC_IMPORT Arguments'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> DynamicImportCall LOC(<span class="hljs-number">1</span>)(<span class="hljs-keyword">new</span> DynamicImport), $<span class="hljs-number">2</span>
]</pre></div></div>
</li>
@@ -1733,7 +1736,8 @@ rules are necessary.</p>
o <span class="hljs-string">'- Expression'</span>, (<span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Op <span class="hljs-string">'-'</span>, $<span class="hljs-number">2</span>), prec: <span class="hljs-string">'UNARY_MATH'</span>
o <span class="hljs-string">'+ Expression'</span>, (<span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Op <span class="hljs-string">'+'</span>, $<span class="hljs-number">2</span>), prec: <span class="hljs-string">'UNARY_MATH'</span>
o <span class="hljs-string">'AWAIT Expression'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Op $<span class="hljs-number">1</span> , $<span class="hljs-number">2</span>
o <span class="hljs-string">'AWAIT Expression'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Op $<span class="hljs-number">1</span>, $<span class="hljs-number">2</span>
o <span class="hljs-string">'AWAIT INDENT Object OUTDENT'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Op $<span class="hljs-number">1</span>, $<span class="hljs-number">3</span>
o <span class="hljs-string">'-- SimpleAssignable'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Op <span class="hljs-string">'--'</span>, $<span class="hljs-number">2</span>
o <span class="hljs-string">'++ SimpleAssignable'</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Op <span class="hljs-string">'++'</span>, $<span class="hljs-number">2</span>
@@ -1848,7 +1852,7 @@ down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
[<span class="hljs-string">'right'</span>, <span class="hljs-string">'YIELD'</span>]
[<span class="hljs-string">'right'</span>, <span class="hljs-string">'='</span>, <span class="hljs-string">':'</span>, <span class="hljs-string">'COMPOUND_ASSIGN'</span>, <span class="hljs-string">'RETURN'</span>, <span class="hljs-string">'THROW'</span>, <span class="hljs-string">'EXTENDS'</span>]
[<span class="hljs-string">'right'</span>, <span class="hljs-string">'FORIN'</span>, <span class="hljs-string">'FOROF'</span>, <span class="hljs-string">'FORFROM'</span>, <span class="hljs-string">'BY'</span>, <span class="hljs-string">'WHEN'</span>]
[<span class="hljs-string">'right'</span>, <span class="hljs-string">'IF'</span>, <span class="hljs-string">'ELSE'</span>, <span class="hljs-string">'FOR'</span>, <span class="hljs-string">'WHILE'</span>, <span class="hljs-string">'UNTIL'</span>, <span class="hljs-string">'LOOP'</span>, <span class="hljs-string">'SUPER'</span>, <span class="hljs-string">'CLASS'</span>, <span class="hljs-string">'IMPORT'</span>, <span class="hljs-string">'EXPORT'</span>]
[<span class="hljs-string">'right'</span>, <span class="hljs-string">'IF'</span>, <span class="hljs-string">'ELSE'</span>, <span class="hljs-string">'FOR'</span>, <span class="hljs-string">'WHILE'</span>, <span class="hljs-string">'UNTIL'</span>, <span class="hljs-string">'LOOP'</span>, <span class="hljs-string">'SUPER'</span>, <span class="hljs-string">'CLASS'</span>, <span class="hljs-string">'IMPORT'</span>, <span class="hljs-string">'EXPORT'</span>, <span class="hljs-string">'DYNAMIC_IMPORT'</span>]
[<span class="hljs-string">'left'</span>, <span class="hljs-string">'POST_IF'</span>]
]</pre></div></div>

View File

@@ -128,8 +128,11 @@ helpers = CoffeeScript.helpers
CoffeeScript.transpile = <span class="hljs-function"><span class="hljs-params">(js, options)</span> -&gt;</span>
<span class="hljs-keyword">try</span>
babel = <span class="hljs-built_in">require</span> <span class="hljs-string">'babel-core'</span>
<span class="hljs-keyword">catch</span></pre></div></div>
babel = <span class="hljs-built_in">require</span> <span class="hljs-string">'@babel/core'</span>
<span class="hljs-keyword">catch</span>
<span class="hljs-keyword">try</span>
babel = <span class="hljs-built_in">require</span> <span class="hljs-string">'babel-core'</span>
<span class="hljs-keyword">catch</span></pre></div></div>
</li>
@@ -145,7 +148,7 @@ earlier if they dont have Babel installed.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Error <span class="hljs-string">'To use the transpile option, you must have the \'babel-core\' module installed'</span>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Error <span class="hljs-string">'To use the transpile option, you must have the \'@babel/core\' module installed'</span>
babel.transform js, options</pre></div></div>
</li>
@@ -400,8 +403,7 @@ 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, options = {})</span> -&gt;</span>
raw = fs.readFileSync filename, <span class="hljs-string">'utf8'</span></pre></div></div>
CoffeeScript._compileRawFileContent = <span class="hljs-function"><span class="hljs-params">(raw, filename, options = {})</span> -&gt;</span></pre></div></div>
</li>
@@ -447,6 +449,11 @@ information to error so it can be pretty-printed later.</p>
answer
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>
CoffeeScript._compileRawFileContent raw, filename, options
<span class="hljs-built_in">module</span>.exports = CoffeeScript</pre></div></div>
</li>

View File

@@ -465,6 +465,8 @@ what CoffeeScript would normally interpret as calls to functions named
@tokens.length &gt; <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> @tokens[@tokens.length - <span class="hljs-number">2</span>][<span class="hljs-number">0</span>] <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'.'</span>, <span class="hljs-string">'?.'</span>, <span class="hljs-string">'@'</span>]
@error <span class="hljs-string">"'<span class="hljs-subst">#{prev[<span class="hljs-number">1</span>]}</span>' cannot be used as a keyword, or as a function call
without parentheses"</span>, prev[<span class="hljs-number">2</span>]
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'.'</span> <span class="hljs-keyword">and</span> @tokens.length &gt; <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> (prevprev = @tokens[@tokens.length - <span class="hljs-number">2</span>])[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'UNARY'</span> <span class="hljs-keyword">and</span> prevprev[<span class="hljs-number">1</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'new'</span>
prevprev[<span class="hljs-number">0</span>] = <span class="hljs-string">'IDENTIFIER'</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @tokens.length &gt; <span class="hljs-number">2</span>
prevprev = @tokens[@tokens.length - <span class="hljs-number">2</span>]
<span class="hljs-keyword">if</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> [<span class="hljs-string">'@'</span>, <span class="hljs-string">'THIS'</span>] <span class="hljs-keyword">and</span> prevprev <span class="hljs-keyword">and</span> prevprev.spaced <span class="hljs-keyword">and</span>
@@ -1294,6 +1296,9 @@ parentheses that indicate a method call from regular parentheses, and so on.</p>
@error message, origin[<span class="hljs-number">2</span>] <span class="hljs-keyword">if</span> message
<span class="hljs-keyword">return</span> value.length <span class="hljs-keyword">if</span> skipToken
<span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-string">'('</span> <span class="hljs-keyword">and</span> prev?[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'IMPORT'</span>
prev[<span class="hljs-number">0</span>] = <span class="hljs-string">'DYNAMIC_IMPORT'</span>
<span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-string">'{'</span> <span class="hljs-keyword">and</span> @seenImport
@importSpecifierList = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @importSpecifierList <span class="hljs-keyword">and</span> value <span class="hljs-keyword">is</span> <span class="hljs-string">'}'</span>
@@ -2268,8 +2273,7 @@ loop. Try to detect when <code>from</code> is a variable identifier and when it
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">isForFrom</span> = <span class="hljs-params">(prev)</span> -&gt;</span>
<span class="hljs-keyword">if</span> prev[<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-function"><span class="hljs-title">isForFrom</span> = <span class="hljs-params">(prev)</span> -&gt;</span></pre></div></div>
</li>
@@ -2280,13 +2284,12 @@ loop. Try to detect when <code>from</code> is a variable identifier and when it
<div class="pilwrap ">
<a class="pilcrow" href="#section-88">&#182;</a>
</div>
<p><code>for i from from</code>, <code>for from from iterable</code></p>
<p><code>for i from iterable</code></p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> prev[<span class="hljs-number">1</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'from'</span>
prev[<span class="hljs-number">1</span>][<span class="hljs-number">0</span>] = <span class="hljs-string">'IDENTIFIER'</span>
<span class="hljs-literal">yes</span></pre></div></div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'IDENTIFIER'</span>
<span class="hljs-literal">yes</span></pre></div></div>
</li>
@@ -2297,21 +2300,6 @@ loop. Try to detect when <code>from</code> is a variable identifier and when it
<div class="pilwrap ">
<a class="pilcrow" href="#section-89">&#182;</a>
</div>
<p><code>for i from iterable</code></p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-literal">yes</span></pre></div></div>
</li>
<li id="section-90">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-90">&#182;</a>
</div>
<p><code>for from…</code></p>
</div>
@@ -2322,11 +2310,11 @@ loop. Try to detect when <code>from</code> is a variable identifier and when it
</li>
<li id="section-91">
<li id="section-90">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-91">&#182;</a>
<a class="pilcrow" href="#section-90">&#182;</a>
</div>
<p><code>for {from}…</code>, <code>for [from]…</code>, <code>for {a, from}…</code>, <code>for {a: from}…</code></p>
@@ -2340,14 +2328,26 @@ loop. Try to detect when <code>from</code> is a variable identifier and when it
</li>
<li id="section-91">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-91">&#182;</a>
</div>
<h2 id="constants">Constants</h2>
</div>
</li>
<li id="section-92">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-92">&#182;</a>
</div>
<h2 id="constants">Constants</h2>
</div>
</li>
@@ -2359,18 +2359,6 @@ loop. Try to detect when <code>from</code> is a variable identifier and when it
<div class="pilwrap ">
<a class="pilcrow" href="#section-93">&#182;</a>
</div>
</div>
</li>
<li id="section-94">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-94">&#182;</a>
</div>
<p>Keywords that CoffeeScript shares in common with JavaScript.</p>
</div>
@@ -2387,11 +2375,11 @@ loop. Try to detect when <code>from</code> is a variable identifier and when it
</li>
<li id="section-95">
<li id="section-94">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-95">&#182;</a>
<a class="pilcrow" href="#section-94">&#182;</a>
</div>
<p>CoffeeScript-only keywords.</p>
@@ -2419,11 +2407,11 @@ COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat COFFEE_ALIASES</pre></div></div>
</li>
<li id="section-96">
<li id="section-95">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-96">&#182;</a>
<a class="pilcrow" href="#section-95">&#182;</a>
</div>
<p>The list of keywords that are reserved by JavaScript, but not used, or are
used by CoffeeScript internally. We throw an error when these are encountered,
@@ -2442,11 +2430,11 @@ STRICT_PROSCRIBED = [<span class="hljs-string">'arguments'</span>, <span class="
</li>
<li id="section-97">
<li id="section-96">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-97">&#182;</a>
<a class="pilcrow" href="#section-96">&#182;</a>
</div>
<p>The superset of both JavaScript keywords and reserved words, none of which may
be used as identifiers or properties.</p>
@@ -2458,11 +2446,11 @@ be used as identifiers or properties.</p>
</li>
<li id="section-98">
<li id="section-97">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-98">&#182;</a>
<a class="pilcrow" href="#section-97">&#182;</a>
</div>
<p>The character code of the nasty Microsoft madness otherwise known as the BOM.</p>
@@ -2473,11 +2461,11 @@ be used as identifiers or properties.</p>
</li>
<li id="section-99">
<li id="section-98">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-99">&#182;</a>
<a class="pilcrow" href="#section-98">&#182;</a>
</div>
<p>Token matching regexes.</p>
@@ -2497,11 +2485,11 @@ CSX_IDENTIFIER = <span class="hljs-regexp">/// ^
</li>
<li id="section-100">
<li id="section-99">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-100">&#182;</a>
<a class="pilcrow" href="#section-99">&#182;</a>
</div>
<p>Fragment: &lt;&gt;&lt;/&gt;</p>
@@ -2548,11 +2536,11 @@ HERE_JSTOKEN = <span class="hljs-regexp">///^ ``` ((?: [^`\\] | \\[\s\S] | `
</li>
<li id="section-101">
<li id="section-100">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-101">&#182;</a>
<a class="pilcrow" href="#section-100">&#182;</a>
</div>
<p>String-matching-regexes.</p>
@@ -2586,11 +2574,11 @@ HEREDOC_INDENT = <span class="hljs-regexp">/\n+([^\n\S]*)(?=\S)/g</span></pr
</li>
<li id="section-102">
<li id="section-101">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-102">&#182;</a>
<a class="pilcrow" href="#section-101">&#182;</a>
</div>
<p>Regex-matching-regexes.</p>
@@ -2616,11 +2604,11 @@ HEREGEX = <span class="hljs-regexp">/// ^
</li>
<li id="section-103">
<li id="section-102">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-103">&#182;</a>
<a class="pilcrow" href="#section-102">&#182;</a>
</div>
<p>Match any character, except those that need special handling below.</p>
@@ -2631,11 +2619,11 @@ HEREGEX = <span class="hljs-regexp">/// ^
</li>
<li id="section-104">
<li id="section-103">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-104">&#182;</a>
<a class="pilcrow" href="#section-103">&#182;</a>
</div>
<p>Match <code>\</code> followed by any character.</p>
@@ -2646,11 +2634,11 @@ HEREGEX = <span class="hljs-regexp">/// ^
</li>
<li id="section-105">
<li id="section-104">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-105">&#182;</a>
<a class="pilcrow" href="#section-104">&#182;</a>
</div>
<p>Match any <code>/</code> except <code>///</code>.</p>
@@ -2661,11 +2649,11 @@ HEREGEX = <span class="hljs-regexp">/// ^
</li>
<li id="section-106">
<li id="section-105">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-106">&#182;</a>
<a class="pilcrow" href="#section-105">&#182;</a>
</div>
<p>Match <code>#</code> which is not part of interpolation, e.g. <code>#{}</code>.</p>
@@ -2676,11 +2664,11 @@ HEREGEX = <span class="hljs-regexp">/// ^
</li>
<li id="section-107">
<li id="section-106">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-107">&#182;</a>
<a class="pilcrow" href="#section-106">&#182;</a>
</div>
<p>Comments consume everything until the end of the line, including <code>///</code>.</p>
@@ -2703,11 +2691,11 @@ POSSIBLY_DIVISION = <span class="hljs-regexp">/// ^ /=?\s ///</span></pre></di
</li>
<li id="section-108">
<li id="section-107">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-108">&#182;</a>
<a class="pilcrow" href="#section-107">&#182;</a>
</div>
<p>Other regexes.</p>
@@ -2750,11 +2738,11 @@ TRAILING_SPACES = <span class="hljs-regexp">/\s+$/</span></pre></div></div>
</li>
<li id="section-109">
<li id="section-108">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-109">&#182;</a>
<a class="pilcrow" href="#section-108">&#182;</a>
</div>
<p>Compound assignment tokens.</p>
@@ -2768,11 +2756,11 @@ TRAILING_SPACES = <span class="hljs-regexp">/\s+$/</span></pre></div></div>
</li>
<li id="section-110">
<li id="section-109">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-110">&#182;</a>
<a class="pilcrow" href="#section-109">&#182;</a>
</div>
<p>Unary tokens.</p>
@@ -2785,11 +2773,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
</li>
<li id="section-111">
<li id="section-110">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-111">&#182;</a>
<a class="pilcrow" href="#section-110">&#182;</a>
</div>
<p>Bit-shifting tokens.</p>
@@ -2800,11 +2788,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
</li>
<li id="section-112">
<li id="section-111">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-112">&#182;</a>
<a class="pilcrow" href="#section-111">&#182;</a>
</div>
<p>Comparison tokens.</p>
@@ -2815,11 +2803,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
</li>
<li id="section-113">
<li id="section-112">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-113">&#182;</a>
<a class="pilcrow" href="#section-112">&#182;</a>
</div>
<p>Mathematical tokens.</p>
@@ -2830,11 +2818,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
</li>
<li id="section-114">
<li id="section-113">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-114">&#182;</a>
<a class="pilcrow" href="#section-113">&#182;</a>
</div>
<p>Relational tokens that are negatable with <code>not</code> prefix.</p>
@@ -2845,11 +2833,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
</li>
<li id="section-115">
<li id="section-114">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-115">&#182;</a>
<a class="pilcrow" href="#section-114">&#182;</a>
</div>
<p>Boolean tokens.</p>
@@ -2860,11 +2848,11 @@ UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~
</li>
<li id="section-116">
<li id="section-115">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-116">&#182;</a>
<a class="pilcrow" href="#section-115">&#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
@@ -2872,7 +2860,7 @@ of a function invocation or indexing operation.</p>
</div>
<div class="content"><div class='highlight'><pre>CALLABLE = [<span class="hljs-string">'IDENTIFIER'</span>, <span class="hljs-string">'PROPERTY'</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">'THIS'</span>, <span class="hljs-string">'SUPER'</span>]
<div class="content"><div class='highlight'><pre>CALLABLE = [<span class="hljs-string">'IDENTIFIER'</span>, <span class="hljs-string">'PROPERTY'</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">'THIS'</span>, <span class="hljs-string">'SUPER'</span>, <span class="hljs-string">'DYNAMIC_IMPORT'</span>]
INDEXABLE = CALLABLE.concat [
<span class="hljs-string">'NUMBER'</span>, <span class="hljs-string">'INFINITY'</span>, <span class="hljs-string">'NAN'</span>, <span class="hljs-string">'STRING'</span>, <span class="hljs-string">'STRING_END'</span>, <span class="hljs-string">'REGEX'</span>, <span class="hljs-string">'REGEX_END'</span>
<span class="hljs-string">'BOOL'</span>, <span class="hljs-string">'NULL'</span>, <span class="hljs-string">'UNDEFINED'</span>, <span class="hljs-string">'}'</span>, <span class="hljs-string">'::'</span>
@@ -2881,11 +2869,11 @@ INDEXABLE = CALLABLE.concat [
</li>
<li id="section-117">
<li id="section-116">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-117">&#182;</a>
<a class="pilcrow" href="#section-116">&#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>
@@ -2896,11 +2884,11 @@ INDEXABLE = CALLABLE.concat [
</li>
<li id="section-118">
<li id="section-117">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-118">&#182;</a>
<a class="pilcrow" href="#section-117">&#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>
@@ -2913,11 +2901,11 @@ CALLABLEs in some cases), but which a division operator can.</p>
</li>
<li id="section-119">
<li id="section-118">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-119">&#182;</a>
<a class="pilcrow" href="#section-118">&#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
@@ -2930,11 +2918,11 @@ avoid an ambiguity in the grammar.</p>
</li>
<li id="section-120">
<li id="section-119">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-120">&#182;</a>
<a class="pilcrow" href="#section-119">&#182;</a>
</div>
<p>Additional indent in front of these is ignored.</p>
@@ -2945,11 +2933,11 @@ avoid an ambiguity in the grammar.</p>
</li>
<li id="section-121">
<li id="section-120">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-121">&#182;</a>
<a class="pilcrow" href="#section-120">&#182;</a>
</div>
<p>Tokens that, when appearing at the end of a line, suppress a following TERMINATOR/INDENT token</p>

View File

@@ -542,7 +542,7 @@ the two values are raw nodes which have not been compiled.</p>
</div>
<p>Occasionally it may be useful to make an expression behave as if it was hoisted, whereby the
result of the expression is available before its location in the source, but the expressions
variable scope corresponds the source position. This is used extensively to deal with executable
variable scope corresponds to the source position. This is used extensively to deal with executable
class bodies in classes.</p>
<p>Calling this method mutates the node, proxying the <code>compileNode</code> and <code>compileToFragments</code>
methods to store their result for later replacing the <code>target</code> node, which is returned by the
@@ -2117,6 +2117,7 @@ evaluate anything twice when building the soak chain.</p>
</div>
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkNewTarget o
@base.front = @front
props = @properties
<span class="hljs-keyword">if</span> props.length <span class="hljs-keyword">and</span> @base.cached?</pre></div></div>
@@ -2147,7 +2148,15 @@ Example:
<span class="hljs-keyword">for</span> prop <span class="hljs-keyword">in</span> props
fragments.push (prop.compileToFragments o)...
fragments</pre></div></div>
fragments
checkNewTarget: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> @base <span class="hljs-keyword">instanceof</span> IdentifierLiteral <span class="hljs-keyword">and</span> @base.value <span class="hljs-keyword">is</span> <span class="hljs-string">'new'</span> <span class="hljs-keyword">and</span> @properties.length
<span class="hljs-keyword">if</span> @properties[<span class="hljs-number">0</span>] <span class="hljs-keyword">instanceof</span> Access <span class="hljs-keyword">and</span> @properties[<span class="hljs-number">0</span>].name.value <span class="hljs-keyword">is</span> <span class="hljs-string">'target'</span>
<span class="hljs-keyword">unless</span> o.scope.parent?
@error <span class="hljs-string">"new.target can only occur inside functions"</span>
<span class="hljs-keyword">else</span>
@error <span class="hljs-string">"the only valid meta property for new is new.target"</span></pre></div></div>
</li>
@@ -3470,7 +3479,8 @@ are too.</p>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> [@makeCode <span class="hljs-string">'[]'</span>] <span class="hljs-keyword">unless</span> @objects.length
o.indent += TAB
<span class="hljs-function"> <span class="hljs-title">fragmentIsElision</span> = <span class="hljs-params">(fragment)</span> -&gt;</span> fragmentsToText(fragment).trim() <span class="hljs-keyword">is</span> <span class="hljs-string">','</span></pre></div></div>
<span class="hljs-function"> <span class="hljs-title">fragmentIsElision</span> = <span class="hljs-params">([ fragment ])</span> -&gt;</span>
fragment.type <span class="hljs-keyword">is</span> <span class="hljs-string">'Elision'</span> <span class="hljs-keyword">and</span> fragment.code.trim() <span class="hljs-keyword">is</span> <span class="hljs-string">','</span></pre></div></div>
</li>
@@ -3481,7 +3491,7 @@ are too.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-144">&#182;</a>
</div>
<p>Detect if <code>Elisions</code> at the beginning of the array are processed (e.g. [, , , a]).</p>
<p>Detect if <code>Elision</code>s at the beginning of the array are processed (e.g. [, , , a]).</p>
</div>
@@ -3578,7 +3588,7 @@ element isnt <code>Elision</code> or last element is <code>Elision</code> (e.
<span class="hljs-keyword">for</span> fragment, fragmentIndex <span class="hljs-keyword">in</span> answer
<span class="hljs-keyword">if</span> fragment.isHereComment
fragment.code = <span class="hljs-string">"<span class="hljs-subst">#{multident(fragment.code, o.indent, <span class="hljs-literal">no</span>)}</span>\n<span class="hljs-subst">#{o.indent}</span>"</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> fragment.code <span class="hljs-keyword">is</span> <span class="hljs-string">', '</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> fragment?.isElision
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> fragment.code <span class="hljs-keyword">is</span> <span class="hljs-string">', '</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> fragment?.isElision <span class="hljs-keyword">and</span> fragment.type <span class="hljs-keyword">isnt</span> <span class="hljs-string">'StringLiteral'</span>
fragment.code = <span class="hljs-string">",\n<span class="hljs-subst">#{o.indent}</span>"</span>
answer.unshift @makeCode <span class="hljs-string">"[\n<span class="hljs-subst">#{o.indent}</span>"</span>
answer.push @makeCode <span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>]"</span>
@@ -3987,7 +3997,7 @@ exports.ExecutableClassBody = <span class="hljs-class"><span class="hljs-keyword
@body.traverseChildren <span class="hljs-literal">false</span>, <span class="hljs-function"><span class="hljs-params">(node)</span> =&gt;</span>
<span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> ThisLiteral
node.value = @name
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span> node.bound <span class="hljs-keyword">and</span> node.isStatic
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span> node.bound <span class="hljs-keyword">and</span> (node.isStatic <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> node.name)
node.context = @name</pre></div></div>
</li>
@@ -4242,7 +4252,17 @@ exports.ImportNamespaceSpecifier = <span class="hljs-class"><span class="hljs-ke
exports.ExportSpecifier = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExportSpecifier</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ModuleSpecifier</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(local, exported)</span> -&gt;</span>
<span class="hljs-keyword">super</span> local, exported, <span class="hljs-string">'export'</span></pre></div></div>
<span class="hljs-keyword">super</span> local, exported, <span class="hljs-string">'export'</span>
exports.DynamicImport = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DynamicImport</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
compileNode: <span class="hljs-function">-&gt;</span>
[@makeCode <span class="hljs-string">'import'</span>]
exports.DynamicImportCall = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DynamicImportCall</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Call</span></span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">unless</span> @args.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span>
@error <span class="hljs-string">'import() requires exactly one argument'</span>
<span class="hljs-keyword">super</span> o</pre></div></div>
</li>
@@ -5573,7 +5593,7 @@ This is usually caught via <code>Op::compileContinuation</code>, but double-chec
</div>
<div class="content"><div class='highlight'><pre> scopeVariablesCount = o.scope.variables.length
signature.push param.compileToFragments(o)...
signature.push param.compileToFragments(o, LEVEL_PAREN)...
<span class="hljs-keyword">if</span> scopeVariablesCount <span class="hljs-keyword">isnt</span> o.scope.variables.length
generatedVariables = o.scope.variables.splice scopeVariablesCount
o.scope.parent.variables.push generatedVariables...
@@ -7071,7 +7091,8 @@ and using @body.compileNode. <code>StringWithInterpolations.compileNode</code> i
<span class="hljs-keyword">else</span>
fragments.push @makeCode <span class="hljs-string">'$'</span> <span class="hljs-keyword">unless</span> @csx
code = element.compileToFragments(o, LEVEL_PAREN)
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> @isNestedTag(element) <span class="hljs-keyword">or</span> code.some(<span class="hljs-function"><span class="hljs-params">(fragment)</span> -&gt;</span> fragment.comments?)
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> @isNestedTag(element) <span class="hljs-keyword">or</span>
code.some(<span class="hljs-function"><span class="hljs-params">(fragment)</span> -&gt;</span> fragment.comments?.some(<span class="hljs-function"><span class="hljs-params">(comment)</span> -&gt;</span> comment.here <span class="hljs-keyword">is</span> <span class="hljs-literal">no</span>))
code = @wrapInBraces code</pre></div></div>
</li>
@@ -7085,8 +7106,10 @@ and using @body.compileNode. <code>StringWithInterpolations.compileNode</code> i
</div>
<p>Flag the <code>{</code> and <code>}</code> fragments as having been generated by this
<code>StringWithInterpolations</code> node, so that <code>compileComments</code> knows
to treat them as bounds. Dont trust <code>fragment.type</code>, which can
report minified variable names when this compiler is minified.</p>
to treat them as bounds. But the braces are unnecessary if all of
the enclosed comments are <code>/* */</code> comments. Dont trust
<code>fragment.type</code>, which can report minified variable names when
this compiler is minified.</p>
</div>

View File

@@ -376,7 +376,7 @@ undeclared variable <code>__</code>.</p>
vm.runInContext js, context, filename
<span class="hljs-function">
<span class="hljs-title">addMultilineHandler</span> = <span class="hljs-params">(repl)</span> -&gt;</span>
{rli, inputStream, outputStream} = repl</pre></div></div>
{inputStream, outputStream} = repl</pre></div></div>
</li>
@@ -412,15 +412,15 @@ undeclared variable <code>__</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> nodeLineListener = rli.listeners(<span class="hljs-string">'line'</span>)[<span class="hljs-number">0</span>]
rli.removeListener <span class="hljs-string">'line'</span>, nodeLineListener
rli.<span class="hljs-literal">on</span> <span class="hljs-string">'line'</span>, <span class="hljs-function"><span class="hljs-params">(cmd)</span> -&gt;</span>
<div class="content"><div class='highlight'><pre> nodeLineListener = repl.listeners(<span class="hljs-string">'line'</span>)[<span class="hljs-number">0</span>]
repl.removeListener <span class="hljs-string">'line'</span>, nodeLineListener
repl.<span class="hljs-literal">on</span> <span class="hljs-string">'line'</span>, <span class="hljs-function"><span class="hljs-params">(cmd)</span> -&gt;</span>
<span class="hljs-keyword">if</span> multiline.enabled
multiline.buffer += <span class="hljs-string">"<span class="hljs-subst">#{cmd}</span>\n"</span>
rli.setPrompt multiline.prompt
rli.prompt <span class="hljs-literal">true</span>
repl.setPrompt multiline.prompt
repl.prompt <span class="hljs-literal">true</span>
<span class="hljs-keyword">else</span>
rli.setPrompt origPrompt
repl.setPrompt origPrompt
nodeLineListener cmd
<span class="hljs-keyword">return</span></pre></div></div>
@@ -456,8 +456,8 @@ undeclared variable <code>__</code>.</p>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">unless</span> multiline.buffer.match <span class="hljs-regexp">/\n/</span>
multiline.enabled = <span class="hljs-keyword">not</span> multiline.enabled
rli.setPrompt origPrompt
rli.prompt <span class="hljs-literal">true</span>
repl.setPrompt origPrompt
repl.prompt <span class="hljs-literal">true</span>
<span class="hljs-keyword">return</span></pre></div></div>
</li>
@@ -473,7 +473,7 @@ undeclared variable <code>__</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> rli.line? <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> rli.line.match <span class="hljs-regexp">/^\s*$/</span></pre></div></div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> repl.line? <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> repl.line.match <span class="hljs-regexp">/^\s*$/</span></pre></div></div>
</li>
@@ -489,10 +489,10 @@ undeclared variable <code>__</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> multiline.enabled = <span class="hljs-keyword">not</span> multiline.enabled
rli.line = <span class="hljs-string">''</span>
rli.cursor = <span class="hljs-number">0</span>
rli.output.cursorTo <span class="hljs-number">0</span>
rli.output.clearLine <span class="hljs-number">1</span></pre></div></div>
repl.line = <span class="hljs-string">''</span>
repl.cursor = <span class="hljs-number">0</span>
repl.output.cursorTo <span class="hljs-number">0</span>
repl.output.clearLine <span class="hljs-number">1</span></pre></div></div>
</li>
@@ -508,12 +508,12 @@ undeclared variable <code>__</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> multiline.buffer = multiline.buffer.replace <span class="hljs-regexp">/\n/g</span>, <span class="hljs-string">'\uFF00'</span>
rli.emit <span class="hljs-string">'line'</span>, multiline.buffer
repl.emit <span class="hljs-string">'line'</span>, multiline.buffer
multiline.buffer = <span class="hljs-string">''</span>
<span class="hljs-keyword">else</span>
multiline.enabled = <span class="hljs-keyword">not</span> multiline.enabled
rli.setPrompt multiline.initialPrompt
rli.prompt <span class="hljs-literal">true</span>
repl.setPrompt multiline.initialPrompt
repl.prompt <span class="hljs-literal">true</span>
<span class="hljs-keyword">return</span></pre></div></div>
</li>
@@ -580,7 +580,7 @@ undeclared variable <code>__</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> repl.rli.history = buffer.toString().split(<span class="hljs-string">'\n'</span>).reverse()</pre></div></div>
<div class="content"><div class='highlight'><pre> repl.history = buffer.toString().split(<span class="hljs-string">'\n'</span>).reverse()</pre></div></div>
</li>
@@ -595,7 +595,7 @@ undeclared variable <code>__</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> repl.rli.history.pop() <span class="hljs-keyword">if</span> stat.size &gt; maxSize</pre></div></div>
<div class="content"><div class='highlight'><pre> repl.history.pop() <span class="hljs-keyword">if</span> stat.size &gt; maxSize</pre></div></div>
</li>
@@ -610,13 +610,13 @@ undeclared variable <code>__</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> repl.rli.history.shift() <span class="hljs-keyword">if</span> repl.rli.history[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">''</span>
repl.rli.historyIndex = <span class="hljs-number">-1</span>
lastLine = repl.rli.history[<span class="hljs-number">0</span>]
<div class="content"><div class='highlight'><pre> repl.history.shift() <span class="hljs-keyword">if</span> repl.history[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">''</span>
repl.historyIndex = <span class="hljs-number">-1</span>
lastLine = repl.history[<span class="hljs-number">0</span>]
fd = fs.openSync filename, <span class="hljs-string">'a'</span>
repl.rli.addListener <span class="hljs-string">'line'</span>, <span class="hljs-function"><span class="hljs-params">(code)</span> -&gt;</span>
repl.addListener <span class="hljs-string">'line'</span>, <span class="hljs-function"><span class="hljs-params">(code)</span> -&gt;</span>
<span class="hljs-keyword">if</span> code <span class="hljs-keyword">and</span> code.length <span class="hljs-keyword">and</span> code <span class="hljs-keyword">isnt</span> <span class="hljs-string">'.history'</span> <span class="hljs-keyword">and</span> code <span class="hljs-keyword">isnt</span> <span class="hljs-string">'.exit'</span> <span class="hljs-keyword">and</span> lastLine <span class="hljs-keyword">isnt</span> code</pre></div></div>
</li>
@@ -667,7 +667,7 @@ undeclared variable <code>__</code>.</p>
<div class="content"><div class='highlight'><pre> repl.commands[getCommandId(repl, <span class="hljs-string">'history'</span>)] =
help: <span class="hljs-string">'Show command history'</span>
action: <span class="hljs-function">-&gt;</span>
repl.outputStream.write <span class="hljs-string">"<span class="hljs-subst">#{repl.rli.history[..].reverse().join <span class="hljs-string">'\n'</span>}</span>\n"</span>
repl.outputStream.write <span class="hljs-string">"<span class="hljs-subst">#{repl.history[..].reverse().join <span class="hljs-string">'\n'</span>}</span>\n"</span>
repl.displayPrompt()
<span class="hljs-function">
<span class="hljs-title">getCommandId</span> = <span class="hljs-params">(repl, commandName)</span> -&gt;</span></pre></div></div>
@@ -699,19 +699,22 @@ undeclared variable <code>__</code>.</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
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
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 https://coffeescript.org/#transpilation
'''</span>
process.exit <span class="hljs-number">1</span>
<span class="hljs-keyword">try</span>
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 https://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>
@@ -739,7 +742,7 @@ the REPL, the only applicable option is <code>transpile</code>.</p>
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
repl.<span class="hljs-literal">on</span> <span class="hljs-string">'exit'</span>, <span class="hljs-function">-&gt;</span> repl.outputStream.write <span class="hljs-string">'\n'</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> repl.rli.closed
repl.<span class="hljs-literal">on</span> <span class="hljs-string">'exit'</span>, <span class="hljs-function">-&gt;</span> repl.outputStream.write <span class="hljs-string">'\n'</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> repl.closed
addMultilineHandler repl
addHistory repl, opts.historyFile, opts.historyMaxInputSize <span class="hljs-keyword">if</span> opts.historyFile</pre></div></div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -3,7 +3,12 @@
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>CoffeeScript Test Suite</title>
<script src="browser-compiler/coffeescript.js"></script>
<script nomodule src="browser-compiler/coffeescript.js"></script>
<script type="module">
import CoffeeScript from './browser-compiler-modern/coffeescript.js';
window.CoffeeScript = CoffeeScript;
window.addEventListener('DOMContentLoaded', CoffeeScript.runScripts, false);
</script>
<script src="https://cdn.jsdelivr.net/underscorejs/1.8.3/underscore-min.js"></script>
<style>
body, pre {
@@ -452,6 +457,12 @@ test "array elisions nested destructuring", ->
deepEqual d, {x:2}
arrayEq w, [1,2,4]
test "#5112: array elisions not detected inside strings", ->
arr = [
str: ", #{3}"
]
eq arr[0].str, ', 3'
# Splats in Array Literals
test "array splat expansions with assignments", ->
@@ -1552,6 +1563,14 @@ test "async methods in classes", ->
eq await Child.static(), 1
eq await new Child().method(), 2
test "#3199: await multiline implicit object", ->
do ->
y =
if no then await
type: 'a'
msg: 'b'
eq undefined, y
</script>
<script type="text/x-coffeescript" class="test" id="async_iterators">
# This is always fulfilled.
@@ -3515,6 +3534,42 @@ test "#4868: Incorrect Cant call super with @params error", ->
d = new (new D).c
eq 3, d.a
test "#4609: Support new.target", ->
class A
constructor: ->
@calledAs = new.target.name
class B extends A
b = new B
eq b.calledAs, 'B'
newTarget = null
Foo = ->
newTarget = !!new.target
Foo()
eq newTarget, no
newTarget = null
new Foo()
eq newTarget, yes
test "#5085: Bug: @ reference to class not maintained in do block", ->
thisFoo = 'initial foo'
thisBar = 'initial bar'
fn = (o) -> o.bar()
class A
@foo = 'foo assigned in class'
do => thisFoo = @foo
fn bar: => thisBar = @foo
eq thisFoo, 'foo assigned in class'
eq thisBar, 'foo assigned in class'
</script>
<script type="text/x-coffeescript" class="test" id="cluster">
# Cluster Module
@@ -4673,7 +4728,7 @@ transpile = (method, code, options = {}) ->
options.bare = yes
options.transpile =
# Target Internet Explorer 6, which supports no ES2015+ features.
presets: [['env', {targets: browsers: ['ie 6']}]]
presets: [['@babel/env', {targets: browsers: ['ie 6']}]]
CoffeeScript[method] code, options
@@ -4839,6 +4894,7 @@ test "#3306: trailing comma in a function call in the last line", ->
''', '''
foo(bar);
'''
</script>
<script type="text/x-coffeescript" class="test" id="comprehensions">
# Comprehensions
@@ -7480,6 +7536,47 @@ test '#4686: comments inside interpolations that also contain CSX attributes', -
</div>;
'''
test '#5086: comments inside CSX tags but outside interpolations', ->
eqJS '''
<div>
<div ###comment### attribute={value} />
</div>
''', '''
<div>
<div /*comment*/attribute={value} />
</div>;
'''
test '#5086: comments inside CSX attributes but outside interpolations', ->
eqJS '''
<div>
<div attribute={###attr comment### value} />
</div>
''', '''
<div>
<div attribute={/*attr comment*/value} />
</div>;
'''
test '#5086: comments inside nested CSX tags and attributes but outside interpolations', ->
eqJS '''
<div>
<div>
<div>
<div ###comment### attribute={###attr comment### value} />
</div>
</div>
</div>
''', '''
<div>
<div>
<div>
<div /*comment*/attribute={/*attr comment*/value} />
</div>
</div>
</div>;
'''
# https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html
test 'JSX fragments: empty fragment', ->
eqJS '''
@@ -9377,6 +9474,50 @@ test "#3199: error message for throw indented comprehension", ->
^
'''
test "#3199: error message for yield indented non-object", ->
assertErrorFormat '''
->
yield
1
''', '''
[stdin]:3:5: error: unexpected number
1
^
'''
test "#3199: error message for yield indented comprehension", ->
assertErrorFormat '''
->
yield
x for x in [1, 2, 3]
''', '''
[stdin]:3:5: error: unexpected identifier
x for x in [1, 2, 3]
^
'''
test "#3199: error message for await indented non-object", ->
assertErrorFormat '''
->
await
1
''', '''
[stdin]:3:5: error: unexpected number
1
^
'''
test "#3199: error message for await indented comprehension", ->
assertErrorFormat '''
->
await
x for x in [1, 2, 3]
''', '''
[stdin]:3:5: error: unexpected identifier
x for x in [1, 2, 3]
^
'''
test "#3098: suppressed newline should be unsuppressed by semicolon", ->
assertErrorFormat '''
a = ; 5
@@ -9445,6 +9586,50 @@ test "#3933: prevent implicit calls when cotrol flow is missing `THEN`", ->
^^
'''
test "`new.target` outside of a function", ->
assertErrorFormat '''
new.target
''', '''
[stdin]:1:1: error: new.target can only occur inside functions
new.target
^^^^^^^^^^
'''
test "`new.target` is only allowed meta property", ->
assertErrorFormat '''
-> new.something
''', '''
[stdin]:1:4: error: the only valid meta property for new is new.target
-> new.something
^^^^^^^^^^^^^
'''
test "#4834: dynamic import requires exactly one argument", ->
assertErrorFormat '''
import()
''', '''
[stdin]:1:1: error: import() requires exactly one argument
import()
^^^^^^^^
'''
assertErrorFormat '''
import('x', {})
''', '''
[stdin]:1:1: error: import() requires exactly one argument
import('x', {})
^^^^^^^^^^^^^^^
'''
test "#4834: dynamic import requires explicit call parentheses", ->
assertErrorFormat '''
promise = import 'foo'
''', '''
[stdin]:1:23: error: unexpected end of input
promise = import 'foo'
^
'''
</script>
<script type="text/x-coffeescript" class="test" id="eval">
if vm = require? 'vm'
@@ -10108,6 +10293,22 @@ test "#3199: throw multiline implicit object", ->
msg: 'b'
eq undefined, y
y = do ->
yield
type: 'a'
msg: 'b'
if no then yield
type: 'c'
msg: 'd'
1
{value, done} = y.next()
ok value.type is 'a' and done is no
{value, done} = y.next()
ok value is 1 and done is yes
test "#4576: multiple row function chaining", ->
->
eq @a, 3
@@ -11573,6 +11774,10 @@ test "#4657: destructured array parameters", ->
arrayEq result.a, [1, 2, 3]
eq result.b, 4
test "#5128: default parameters of function in binary operation", ->
foo = yes or (a, b = {}) -> null
eq foo, yes
</script>
<script type="text/x-coffeescript" class="test" id="generators">
# Generators
@@ -14292,6 +14497,27 @@ test "#4874: backslash `export`", ->
} from 'underscore';
"""
test "#4834: dynamic import", ->
eqJS """
import('module').then ->
""",
"""
import('module').then(function() {});
"""
eqJS """
foo = ->
bar = await import('bar')
""",
"""
var foo;
foo = async function() {
var bar;
return bar = (await import('bar'));
};
"""
</script>
<script type="text/x-coffeescript" class="test" id="numbers">
# Number Literals
@@ -14806,6 +15032,16 @@ test "#4673: complex destructured object spread variables", ->
eq @y.b, 1
g b: 1
test "#4834: dynamic import can technically be object spread", ->
eqJS """
x = {...import('module')}
""",
"""
var x;
x = {...import('module')};
"""
</script>
<script type="text/x-coffeescript" class="test" id="objects">
# Object Literals
@@ -16987,7 +17223,7 @@ ctrlV = { ctrl: true, name: 'v'}
testRepl 'reads history file', (input, output, repl) ->
input.emitLine repl.rli.history[0]
input.emitLine repl.history[0]
eq '3', output.lastWrite()
testRepl "starts with coffee prompt", (input, output) ->

View File

@@ -0,0 +1,10 @@
# Your browser must support dynamic import to run this example.
do ->
{ run } = await import('./browser-compiler-modern/coffeescript.js')
run '''
if 5 < new Date().getHours() < 9
alert 'Time to make the coffee!'
else
alert 'Time to get some work done.'
'''

View File

@@ -1,4 +1,4 @@
import 'local-file.coffee'
import './local-file.coffee'
import 'coffeescript'
import _ from 'underscore'

View File

@@ -0,0 +1,8 @@
```
releaseHeader('2018-09-19', '2.3.2', '2.3.1')
```
* Babel 7 is now supported. With version 7, the Babel team moved from `babel-core` on NPM to `@babel/core`. Now the CoffeeScript `--transpile` option will first search for `@babel/core` (Babel versions 7 and above) and then search for `babel-core` (versions 6 and below) to try to find an installed version of Babel to use for transpilation.
* The syntax [`new.target`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target) is now supported.
* You can now follow the keyword `yield` with an indented object, like has already been allowed for `return` and other keywords.
* Previously, any comments inside a JSX tag or attribute would cause interpolation braces (`{` and `}`) to be output. This is only necessary for line (`#`, or `//` in JavaScript) comments, not here (`###`, or `/* */`) comments; so now the compiler checks if all the comments that would trigger the braces are here comments, and if so it doesnt generate the unnecessary interpolation braces.

View File

@@ -0,0 +1,8 @@
```
releaseHeader('2019-03-29', '2.4.0', '2.3.2')
```
* Dynamic `import()` expressions are now supported. The parentheses are always required, to distinguish from `import` statements. See [Modules](#dynamic-import). Note that as of this writing, the JavaScript feature itself is still Stage 3; if it changes before being fully standardized, it may change in CoffeeScript too. Using `import()` before its upstream [ECMAScript proposal](https://github.com/tc39/proposal-dynamic-import) is finalized should be considered provisional, subject to breaking changes if the proposal changes or is rejected. We have also revised our [policy](#contributing) on Stage 3 ECMAScript features, to support them when the features are [shipped](https://caniuse.com/#feat=es6-module-dynamic-import) in significant runtimes such as major browsers or Node.js.
* There are now two browser versions of the CoffeeScript compiler: the traditional one thats been published for years, and a new [ES module version](/browser-compiler-modern/coffeescript.js) that can be used via `import`. If your browser supports it, it is in effect on this page. A reference to the ES module browser compiler is in the `package.json` `"module"` field.
* The Node API now exposes the previously private `registerCompiled` method, to allow plugins that use the `coffeescript` package to take advantage of CoffeeScripts internal caching.
* Bugfixes for commas in strings in block arrays, a reference to `@` not being maintained in a `do` block in a class, and function default parameters should no longer be wrapped by extraneous parentheses.

View File

@@ -5,7 +5,7 @@ Once installed, you should have access to the `coffee` command, which can execut
| Option | Description |
| --- | --- |
| `-c, --compile` | Compile a `.coffee` script into a `.js` JavaScript file of the same name. |
| `-t, --transpile` | Pipe the CoffeeScript compilers output through Babel before saving or running the generated JavaScript. Requires `babel-core` to be installed, and options to pass to Babel in a `.babelrc` file or a `package.json` with a `babel` key in the path of the file or folder to be compiled. See [Transpilation](#transpilation).
| `-t, --transpile` | Pipe the CoffeeScript compilers output through Babel before saving or running the generated JavaScript. Requires `@babel/core` to be installed, and options to pass to Babel in a `.babelrc` file or a `package.json` with a `babel` key in the path of the file or folder to be compiled. See [Transpilation](#transpilation).
| `-m, --map` | Generate source maps alongside the compiled JavaScript files. Adds `sourceMappingURL` directives to the JavaScript as well. |
| `-M, --inline-map` | Just like `--map`, but include the source map directly in the compiled JavaScript files, rather than in a separate file. |
| `-i, --interactive` | Launch an interactive CoffeeScript session to try short snippets. Identical to calling `coffee` with no arguments. |
@@ -37,4 +37,4 @@ Once installed, you should have access to the `coffee` command, which can execut
* Start the CoffeeScript REPL (`Ctrl-D` to exit, `Ctrl-V`for multi-line):<br>
`coffee`
To use `--transpile`, see [Transpilation](#transpilation).
To use `--transpile`, see [Transpilation](#transpilation).

View File

@@ -2,7 +2,7 @@
Contributions are welcome! Feel free to fork [the repo](https://github.com/jashkenas/coffeescript) and submit a pull request.
[Some features of ECMAScript are intentionally unsupported](#unsupported). Please review both the open and closed [issues on GitHub](https://github.com/jashkenas/coffeescript/issues) to see if the feature youre looking for has already been discussed. As a general rule, we dont support ECMAScript syntax for features that arent yet finalized (at Stage 4 in the proposal approval process).
[Some features of ECMAScript are intentionally unsupported](#unsupported). Please review both the open and closed [issues on GitHub](https://github.com/jashkenas/coffeescript/issues) to see if the feature youre looking for has already been discussed. As a general rule, we dont support ECMAScript syntax for features that arent yet finalized (at Stage 4 in the [proposal approval process](https://github.com/tc39/proposals)) or implemented in major browsers and/or Node (which can sometimes happen for features in Stage 3). Any Stage 3 features that CoffeeScript chooses to support should be considered experimental, subject to breaking changes or removal until the feature reaches Stage 4.
For more resources on adding to CoffeeScript, please see [the Wiki](https://github.com/jashkenas/coffeescript/wiki/%5BHowto%5D-Hacking-on-the-CoffeeScript-Compiler), especially [How The Parser Works](https://github.com/jashkenas/coffeescript/wiki/%5BHowTo%5D-How-parsing-works).
@@ -10,7 +10,7 @@ There are several things you can do to increase your odds of having your pull re
* Create tests! Any pull request should probably include basic tests to verify you didnt break anything, or future changes wont break your code.
* Follow the style of the rest of the CoffeeScript codebase.
* Ensure any ECMAScript syntax is mature (at Stage 4), with no further potential changes.
* Ensure any ECMAScript syntax is mature (at Stage 4, or at Stage 3 with support in major browsers or runtimes).
* Add only features that have broad utility, rather than a feature aimed at a specific use case or framework.
Of course, its entirely possible that you have a great addition, but it doesnt fit within these constraints. Feel free to roll your own solution; you will have [plenty of company](https://github.com/jashkenas/coffeescript/wiki/In-The-Wild).

View File

@@ -18,4 +18,4 @@ npm install --save-dev coffeescript
The `coffee` and `cake` commands will first look in the current folder to see if CoffeeScript is installed locally, and use that version if so. This allows different versions of CoffeeScript to be installed globally and locally.
If you plan to use the `--transpile` option (see [Transpilation](#transpilation)) you will need to also install `babel-core` either globally or locally, depending on whether you are running a globally or locally installed version of CoffeeScript.
If you plan to use the `--transpile` option (see [Transpilation](#transpilation)) you will need to also install `@babel/core` either globally or locally, depending on whether you are running a globally or locally installed version of CoffeeScript.

View File

@@ -6,6 +6,14 @@ ES2015 modules are supported in CoffeeScript, with very similar `import` and `ex
codeFor('modules')
```
<div id="dynamic-import" class="bookmark"></div>
[Dynamic import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Dynamic_Imports) is also supported, with mandatory parentheses:
```
codeFor('dynamic_import', true)
```
<div id="modules-note" class="bookmark"></div>
Note that the CoffeeScript compiler **does not resolve modules**; writing an `import` or `export` statement in CoffeeScript will produce an `import` or `export` statement in the resulting output. It is your responsibility to [transpile](#transpilation) this ES2015 syntax into code that will work in your target runtimes.

View File

@@ -7,43 +7,43 @@ CoffeeScript 2 generates JavaScript that uses the latest, modern syntax. The run
From the root of your project:
```bash
npm install --save-dev babel-core babel-preset-env
echo '{ "presets": ["env"] }' > .babelrc
npm install --save-dev @babel/core @babel/preset-env
echo '{ "presets": ["@babel/env"] }' > .babelrc
coffee --compile --transpile --inline-map some-file.coffee
```
#### Transpiling with the CoffeeScript compiler
To make things easy, CoffeeScript has built-in support for the popular [Babel](http://babeljs.io/) transpiler. You can use it via the `--transpile` command-line option or the `transpile` Node API option. To use either, `babel-core` must be installed in your project:
To make things easy, CoffeeScript has built-in support for the popular [Babel](http://babeljs.io/) transpiler. You can use it via the `--transpile` command-line option or the `transpile` Node API option. To use either, `@babel/core` must be installed in your project:
```bash
npm install --save-dev babel-core
npm install --save-dev @babel/core
```
Or if youre running the `coffee` command outside of a project folder, using a globally-installed `coffeescript` module, `babel-core` needs to be installed globally:
Or if youre running the `coffee` command outside of a project folder, using a globally-installed `coffeescript` module, `@babel/core` needs to be installed globally:
```bash
npm install --global babel-core
npm install --global @babel/core
```
By default, Babel doesnt do anything—it doesnt make assumptions about what you want to transpile to. You need to provide it with a configuration so that it knows what to do. One way to do this is by creating a [`.babelrc` file](https://babeljs.io/docs/usage/babelrc/) in the folder containing the files youre compiling, or in any parent folder up the path above those files. (Babel supports [other ways](https://babeljs.io/docs/usage/babelrc/), too.) A minimal `.babelrc` file would be just `{ "presets": ["env"] }`. This implies that you have installed [`babel-preset-env`](https://babeljs.io/docs/plugins/preset-env/):
By default, Babel doesnt do anything—it doesnt make assumptions about what you want to transpile to. You need to provide it with a configuration so that it knows what to do. One way to do this is by creating a [`.babelrc` file](https://babeljs.io/docs/usage/babelrc/) in the folder containing the files youre compiling, or in any parent folder up the path above those files. (Babel supports [other ways](https://babeljs.io/docs/usage/babelrc/), too.) A minimal `.babelrc` file would be just `{ "presets": ["@babel/env"] }`. This implies that you have installed [`@babel/preset-env`](https://babeljs.io/docs/plugins/preset-env/):
```bash
npm install --save-dev babel-preset-env # Or --global for non-project-based usage
npm install --save-dev @babel/preset-env # Or --global for non-project-based usage
```
See [Babels website to learn about presets and plugins](https://babeljs.io/docs/plugins/) and the multitude of options you have. Another preset you might need is [`transform-react-jsx`](https://babeljs.io/docs/plugins/transform-react-jsx/) if youre using JSX with React (JSX can also be used with other frameworks).
See [Babels website to learn about presets and plugins](https://babeljs.io/docs/plugins/) and the multitude of options you have. Another preset you might need is [`@babel/plugin-transform-react-jsx`](https://babeljs.io/docs/en/babel-plugin-transform-react-jsx/) if youre using JSX with React (JSX can also be used with other frameworks).
Once you have `babel-core` and `babel-preset-env` (or other presets or plugins) installed, and a `.babelrc` file (or other equivalent) in place, you can use `coffee --transpile` to pipe CoffeeScripts output through Babel using the options youve saved.
Once you have `@babel/core` and `@babel/preset-env` (or other presets or plugins) installed, and a `.babelrc` file (or other equivalent) in place, you can use `coffee --transpile` to pipe CoffeeScripts output through Babel using the options youve saved.
If youre using CoffeeScript via the [Node API](nodejs_usage), where you call `CoffeeScript.compile` with a string to be compiled and an `options` object, the `transpile` key of the `options` object should be the Babel options:
```js
CoffeeScript.compile(code, {transpile: {presets: ['env']}})
CoffeeScript.compile(code, {transpile: {presets: ['@babel/env']}})
```
You can also transpile CoffeeScripts output without using the `transpile` option, for example as part of a build chain. This lets you use transpilers other than Babel, and it gives you greater control over the process. There are many great task runners for setting up JavaScript build chains, such as [Gulp](http://gulpjs.com/), [Webpack](https://webpack.github.io/), [Grunt](https://gruntjs.com/) and [Broccoli](http://broccolijs.com/).
#### Polyfills
Note that transpiling doesnt automatically supply [polyfills](https://developer.mozilla.org/en-US/docs/Glossary/Polyfill) for your code. CoffeeScript itself will output [`Array.indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) if you use the `in` operator, or destructuring or spread/rest syntax; and [`Function.bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) if you use a bound (`=>`) method in a class. Both are supported in Internet Explorer 9+ and all more recent browsers, but you will need to supply polyfills if you need to support Internet Explorer 8 or below and are using features that would cause these methods to be output. Youll also need to supply polyfills if your own code uses these methods or another method added in recent versions of JavaScript. One polyfill option is [`babel-polyfill`](https://babeljs.io/docs/usage/polyfill/), though there are many [other](https://hackernoon.com/polyfills-everything-you-ever-wanted-to-know-or-maybe-a-bit-less-7c8de164e423) [strategies](https://philipwalton.com/articles/loading-polyfills-only-when-needed/).
Note that transpiling doesnt automatically supply [polyfills](https://developer.mozilla.org/en-US/docs/Glossary/Polyfill) for your code. CoffeeScript itself will output [`Array.indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) if you use the `in` operator, or destructuring or spread/rest syntax; and [`Function.bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) if you use a bound (`=>`) method in a class. Both are supported in Internet Explorer 9+ and all more recent browsers, but you will need to supply polyfills if you need to support Internet Explorer 8 or below and are using features that would cause these methods to be output. Youll also need to supply polyfills if your own code uses these methods or another method added in recent versions of JavaScript. One polyfill option is [`@babel/polyfill`](https://babeljs.io/docs/en/babel-polyfill/), though there are many [other](https://hackernoon.com/polyfills-everything-you-ever-wanted-to-know-or-maybe-a-bit-less-7c8de164e423) [strategies](https://philipwalton.com/articles/loading-polyfills-only-when-needed/).

View File

@@ -207,6 +207,12 @@
</section>
<section id="changelog">
<%= htmlFor('changelog') %>
<section id="2.4.0">
<%= htmlFor('changelog/2.4.0') %>
</section>
<section id="2.3.2">
<%= htmlFor('changelog/2.3.2') %>
</section>
<section id="2.3.1">
<%= htmlFor('changelog/2.3.1') %>
</section>

View File

@@ -1,9 +1,14 @@
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js" integrity="sha384-xBuQ/xzmlsLoJpyjoggmTEz8OWUFM0/RC5BsqQBDX2v5cMvDHcMakNTNrHIW2I5f" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js" integrity="sha384-uefMccjFJAIv6A+rW+L4AHf99KvxDjWSu1z9VI8SKNVmz4sk7buKt/6v9KI65qnm" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/combine/npm/codemirror@5.37.0/lib/codemirror.js,npm/codemirror@5.37.0/mode/coffeescript/coffeescript.js,npm/codemirror@5.37.0/addon/lint/coffeescript-lint.js,npm/codemirror@5.37.0/mode/javascript/javascript.js"></script>
<script src="browser-compiler/coffeescript.js"></script>
<script>
<script nomodule src="./browser-compiler/coffeescript.js"></script>
<script nomodule>
<%= includeScript('docs.coffee') %>
</script>
<script type="module">
import CoffeeScript from './browser-compiler-modern/coffeescript.js';
<%= includeScript('docs.coffee') %>
</script>
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-106156830-1"></script>

View File

@@ -3,7 +3,12 @@
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>CoffeeScript Test Suite</title>
<script src="browser-compiler/coffeescript.js"></script>
<script nomodule src="browser-compiler/coffeescript.js"></script>
<script type="module">
import CoffeeScript from './browser-compiler-modern/coffeescript.js';
window.CoffeeScript = CoffeeScript;
window.addEventListener('DOMContentLoaded', CoffeeScript.runScripts, false);
</script>
<script src="https://cdn.jsdelivr.net/underscorejs/1.8.3/underscore-min.js"></script>
<style>
body, pre {

View File

@@ -1,10 +1,10 @@
// Generated by CoffeeScript 2.3.1
// Generated by CoffeeScript 2.4.0
(function() {
// This **Browser** compatibility layer extends core CoffeeScript functions
// to make things work smoothly when compiling code directly in the browser.
// We add support for loading remote Coffee scripts via **XHR**, and
// `text/coffeescript` script tags, source maps via data-URLs, and so on.
var CoffeeScript, compile, runScripts,
var CoffeeScript, compile,
indexOf = [].indexOf;
CoffeeScript = require('./coffeescript');
@@ -81,7 +81,7 @@
// Activate CoffeeScript in the browser by having it compile and evaluate
// all script tags with a content-type of `text/coffeescript`.
// This happens on page load.
runScripts = function() {
CoffeeScript.runScripts = function() {
var coffees, coffeetypes, execute, i, index, j, len, s, script, scripts;
scripts = window.document.getElementsByTagName('script');
coffeetypes = ['text/coffeescript', 'text/literate-coffeescript'];
@@ -136,10 +136,16 @@
};
// Listen for window load, both in decent browsers and in IE.
if (window.addEventListener) {
window.addEventListener('DOMContentLoaded', runScripts, false);
} else {
window.attachEvent('onload', runScripts);
// Only attach this event handler on startup for the
// non-ES module version of the browser compiler, to preserve
// backward compatibility while letting the ES module version
// be importable without side effects.
if (this === window) {
if (window.addEventListener) {
window.addEventListener('DOMContentLoaded', CoffeeScript.runScripts, false);
} else {
window.attachEvent('onload', CoffeeScript.runScripts);
}
}
}).call(this);

View File

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

View File

@@ -1,10 +1,10 @@
// Generated by CoffeeScript 2.3.1
// Generated by CoffeeScript 2.4.0
(function() {
// CoffeeScript can be used both on the server, as a command-line compiler based
// on Node.js/V8, or to run CoffeeScript directly in the browser. This module
// contains the main entry functions for tokenizing, parsing, and compiling
// source CoffeeScript into JavaScript.
var FILE_EXTENSIONS, Lexer, SourceMap, base64encode, checkShebangLine, compile, formatSourcePosition, getSourceMap, helpers, lexer, packageJson, parser, sourceMaps, sources, withPrettyErrors,
var FILE_EXTENSIONS, Lexer, SourceMap, base64encode, checkShebangLine, compile, formatSourcePosition, getSourceMap, helpers, lexer, packageJson, parser, registerCompiled, sourceMaps, sources, withPrettyErrors,
indexOf = [].indexOf;
({Lexer} = require('./lexer'));
@@ -74,6 +74,24 @@
// Also save source maps if generated, in form of `(source)`: [`(source map)`].
sourceMaps = {};
// This is exported to enable an external module to implement caching of
// compilation results. When the compiled js source is loaded from cache, the
// original coffee code should be added with this method in order to enable the
// Error.prepareStackTrace below to correctly adjust the stack trace for the
// corresponding file (the source map will be generated on demand).
exports.registerCompiled = registerCompiled = function(filename, source, sourcemap) {
if (sources[filename] == null) {
sources[filename] = [];
}
sources[filename].push(source);
if (sourcemap != null) {
if (sourceMaps[filename] == null) {
sourceMaps[filename] = [];
}
return sourceMaps[filename].push(sourcemap);
}
};
// Compile CoffeeScript code to JavaScript, using the Coffee/Jison compiler.
// If `options.sourceMap` is specified, then `options.filename` must also be
@@ -94,10 +112,6 @@
generateSourceMap = options.sourceMap || options.inlineMap || (options.filename == null);
filename = options.filename || '<anonymous>';
checkShebangLine(filename, code);
if (sources[filename] == null) {
sources[filename] = [];
}
sources[filename].push(code);
if (generateSourceMap) {
map = new SourceMap;
}
@@ -162,10 +176,6 @@
}
if (generateSourceMap) {
v3SourceMap = map.generate(options, code);
if (sourceMaps[filename] == null) {
sourceMaps[filename] = [];
}
sourceMaps[filename].push(map);
}
if (options.transpile) {
if (typeof options.transpile !== 'object') {
@@ -196,6 +206,7 @@
sourceURL = `//# sourceURL=${(ref1 = options.filename) != null ? ref1 : 'coffeescript'}`;
js = `${js}\n${sourceMapDataURI}\n${sourceURL}`;
}
registerCompiled(filename, code, map);
if (options.sourceMap) {
return {
js,

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.3.1
// Generated by CoffeeScript 2.4.0
(function() {
// The `coffee` utility. Handles command-line compilation of CoffeeScript
// into various forms: saved into `.js` files or printed to stdout
@@ -619,16 +619,20 @@
// on us to transpile for them; we assume most users will probably either
// run CoffeeScripts output without transpilation (modern Node or evergreen
// browsers) or use a proper build chain like Gulp or Webpack.
require('babel-core');
require('@babel/core');
} catch (error) {
// Give appropriate instructions depending on whether `coffee` was run
// locally or globally.
if (require.resolve('.').indexOf(process.cwd()) === 0) {
console.error('To use --transpile, you must have babel-core installed:\n npm install --save-dev babel-core\nAnd you must save options to configure Babel in one of the places it looks to find its options.\nSee https://coffeescript.org/#transpilation');
} else {
console.error('To use --transpile with globally-installed CoffeeScript, you must have babel-core installed globally:\n npm install --global babel-core\nAnd you must save options to configure Babel in one of the places it looks to find its options, relative to the file being compiled or to the current folder.\nSee https://coffeescript.org/#transpilation');
try {
require('babel-core');
} catch (error) {
// Give appropriate instructions depending on whether `coffee` was run
// locally or globally.
if (require.resolve('.').indexOf(process.cwd()) === 0) {
console.error('To use --transpile, you must have @babel/core installed:\n npm install --save-dev @babel/core\nAnd you must save options to configure Babel in one of the places it looks to find its options.\nSee https://coffeescript.org/#transpilation');
} else {
console.error('To use --transpile with globally-installed CoffeeScript, you must have @babel/core installed globally:\n npm install --global @babel/core\nAnd you must save options to configure Babel in one of the places it looks to find its options, relative to the file being compiled or to the current folder.\nSee https://coffeescript.org/#transpilation');
}
process.exit(1);
}
process.exit(1);
}
if (typeof opts.transpile !== 'object') {
opts.transpile = {};

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.3.1
// Generated by CoffeeScript 2.4.0
(function() {
// The CoffeeScript parser is generated by [Jison](https://github.com/zaach/jison)
// from this grammar file. Jison is a bottom-up parser generator, similar in
@@ -129,6 +129,11 @@
return new Op($1,
$2);
}),
o('YIELD INDENT Object OUTDENT',
function() {
return new Op($1,
$3);
}),
o('YIELD FROM Expression',
function() {
return new Op($1.concat($2),
@@ -327,6 +332,11 @@
false,
$1);
}),
o('DYNAMIC_IMPORT Arguments',
function() {
return new DynamicImportCall(LOC(1)(new DynamicImport),
$2);
}),
o('SimpleObjAssignable Arguments',
function() {
return new Call(new Value($1),
@@ -936,6 +946,11 @@
$3,
$2,
$1);
}),
o('DYNAMIC_IMPORT Arguments',
function() {
return new DynamicImportCall(LOC(1)(new DynamicImport),
$2);
})
],
// An optional existence check on a function.
@@ -1958,6 +1973,11 @@
return new Op($1,
$2);
}),
o('AWAIT INDENT Object OUTDENT',
function() {
return new Op($1,
$3);
}),
o('-- SimpleAssignable',
function() {
return new Op('--',
@@ -2103,7 +2123,7 @@
// And not:
// (2 + 3) * 4
operators = [['left', '.', '?.', '::', '?::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['right', 'AWAIT'], ['right', '**'], ['right', 'UNARY_MATH'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', '&'], ['left', '^'], ['left', '|'], ['left', '&&'], ['left', '||'], ['left', 'BIN?'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', 'YIELD'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'FORFROM', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT'], ['left', 'POST_IF']];
operators = [['left', '.', '?.', '::', '?::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['right', 'AWAIT'], ['right', '**'], ['right', 'UNARY_MATH'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', '&'], ['left', '^'], ['left', '|'], ['left', '&&'], ['left', '||'], ['left', 'BIN?'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', 'YIELD'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'FORFROM', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT', 'DYNAMIC_IMPORT'], ['left', 'POST_IF']];
// Wrapping Up
// -----------

View File

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

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.3.1
// Generated by CoffeeScript 2.4.0
(function() {
// Node.js Implementation
var CoffeeScript, ext, fs, helpers, i, len, path, ref, universalCompile, vm,
@@ -17,11 +17,15 @@
CoffeeScript.transpile = function(js, options) {
var babel;
try {
babel = require('babel-core');
babel = require('@babel/core');
} catch (error) {
// This error is only for Node, as CLI users will see a different error
// earlier if they dont have Babel installed.
throw new Error('To use the transpile option, you must have the \'babel-core\' module installed');
try {
babel = require('babel-core');
} catch (error) {
// This error is only for Node, as CLI users will see a different error
// earlier if they dont have Babel installed.
throw new Error('To use the transpile option, you must have the \'@babel/core\' module installed');
}
}
return babel.transform(js, options);
};
@@ -148,9 +152,8 @@
}
}
CoffeeScript._compileFile = function(filename, options = {}) {
var answer, err, raw, stripped;
raw = fs.readFileSync(filename, 'utf8');
CoffeeScript._compileRawFileContent = function(raw, filename, options = {}) {
var answer, err, stripped;
// 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, {
@@ -171,6 +174,12 @@
return answer;
};
CoffeeScript._compileFile = function(filename, options = {}) {
var raw;
raw = fs.readFileSync(filename, 'utf8');
return CoffeeScript._compileRawFileContent(raw, filename, options);
};
module.exports = CoffeeScript;
}).call(this);

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.3.1
// Generated by CoffeeScript 2.4.0
(function() {
// The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt
// matches against the beginning of the source code. When a match is found,
@@ -202,6 +202,8 @@
} else if (tag === 'PROPERTY' && prev) {
if (prev.spaced && (ref7 = prev[0], indexOf.call(CALLABLE, ref7) >= 0) && /^[gs]et$/.test(prev[1]) && this.tokens.length > 1 && ((ref8 = this.tokens[this.tokens.length - 2][0]) !== '.' && ref8 !== '?.' && ref8 !== '@')) {
this.error(`'${prev[1]}' cannot be used as a keyword, or as a function call without parentheses`, prev[2]);
} else if (prev[0] === '.' && this.tokens.length > 1 && (prevprev = this.tokens[this.tokens.length - 2])[0] === 'UNARY' && prevprev[1] === 'new') {
prevprev[0] = 'IDENTIFIER';
} else if (this.tokens.length > 2) {
prevprev = this.tokens[this.tokens.length - 2];
if (((ref9 = prev[0]) === '@' || ref9 === 'THIS') && prevprev && prevprev.spaced && /^[gs]et$/.test(prevprev[1]) && ((ref10 = this.tokens[this.tokens.length - 3][0]) !== '.' && ref10 !== '?.' && ref10 !== '@')) {
@@ -887,6 +889,9 @@
return value.length;
}
}
if (value === '(' && (prev != null ? prev[0] : void 0) === 'IMPORT') {
prev[0] = 'DYNAMIC_IMPORT';
}
if (value === '{' && this.seenImport) {
this.importSpecifierList = true;
} else if (this.importSpecifierList && value === '}') {
@@ -1482,13 +1487,8 @@
// “sometimes” keyword.
isForFrom = function(prev) {
var ref;
// `for i from iterable`
if (prev[0] === 'IDENTIFIER') {
// `for i from from`, `for from from iterable`
if (prev[1] === 'from') {
prev[1][0] = 'IDENTIFIER';
true;
}
// `for i from iterable`
return true;
// `for from…`
} else if (prev[0] === 'FOR') {
@@ -1683,7 +1683,7 @@
// Tokens which could legitimately be invoked or indexed. An opening
// parentheses or bracket following these tokens will be recorded as the start
// of a function invocation or indexing operation.
CALLABLE = ['IDENTIFIER', 'PROPERTY', ')', ']', '?', '@', 'THIS', 'SUPER'];
CALLABLE = ['IDENTIFIER', 'PROPERTY', ')', ']', '?', '@', 'THIS', 'SUPER', 'DYNAMIC_IMPORT'];
INDEXABLE = CALLABLE.concat(['NUMBER', 'INFINITY', 'NAN', 'STRING', 'STRING_END', 'REGEX', 'REGEX_END', 'BOOL', 'NULL', 'UNDEFINED', '}', '::']);

View File

@@ -1,10 +1,10 @@
// Generated by CoffeeScript 2.3.1
// Generated by CoffeeScript 2.4.0
(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, 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,
var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, CSXTag, Call, Class, Code, CodeFragment, ComputedPropertyName, DynamicImport, DynamicImportCall, 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,
slice1 = [].slice;
@@ -282,7 +282,7 @@
// Occasionally it may be useful to make an expression behave as if it was 'hoisted', whereby the
// result of the expression is available before its location in the source, but the expression's
// variable scope corresponds the source position. This is used extensively to deal with executable
// variable scope corresponds to the source position. This is used extensively to deal with executable
// class bodies in classes.
// Calling this method mutates the node, proxying the `compileNode` and `compileToFragments`
@@ -1445,6 +1445,7 @@
// evaluate anything twice when building the soak chain.
compileNode(o) {
var fragments, j, len1, prop, props;
this.checkNewTarget(o);
this.base.front = this.front;
props = this.properties;
if (props.length && (this.base.cached != null)) {
@@ -1468,6 +1469,19 @@
return fragments;
}
checkNewTarget(o) {
if (!(this.base instanceof IdentifierLiteral && this.base.value === 'new' && this.properties.length)) {
return;
}
if (this.properties[0] instanceof Access && this.properties[0].name.value === 'target') {
if (o.scope.parent == null) {
return this.error("new.target can only occur inside functions");
}
} else {
return this.error("the only valid meta property for new is new.target");
}
}
// Unfold a soak into an `If`: `a?.b` -> `a.b if a?`
unfoldSoak(o) {
return this.unfoldedSoak != null ? this.unfoldedSoak : this.unfoldedSoak = (() => {
@@ -2455,10 +2469,10 @@
return [this.makeCode('[]')];
}
o.indent += TAB;
fragmentIsElision = function(fragment) {
return fragmentsToText(fragment).trim() === ',';
fragmentIsElision = function([fragment]) {
return fragment.type === 'Elision' && fragment.code.trim() === ',';
};
// Detect if `Elisions` at the beginning of the array are processed (e.g. [, , , a]).
// Detect if `Elision`s at the beginning of the array are processed (e.g. [, , , a]).
passedElision = false;
answer = [];
ref1 = this.objects;
@@ -2522,7 +2536,7 @@
fragment = answer[fragmentIndex];
if (fragment.isHereComment) {
fragment.code = `${multident(fragment.code, o.indent, false)}\n${o.indent}`;
} else if (fragment.code === ', ' && !(fragment != null ? fragment.isElision : void 0)) {
} else if (fragment.code === ', ' && !(fragment != null ? fragment.isElision : void 0) && fragment.type !== 'StringLiteral') {
fragment.code = `,\n${o.indent}`;
}
}
@@ -2954,7 +2968,7 @@
return this.body.traverseChildren(false, (node) => {
if (node instanceof ThisLiteral) {
return node.value = this.name;
} else if (node instanceof Code && node.bound && node.isStatic) {
} else if (node instanceof Code && node.bound && (node.isStatic || !node.name)) {
return node.context = this.name;
}
});
@@ -3248,6 +3262,23 @@
};
exports.DynamicImport = DynamicImport = class DynamicImport extends Base {
compileNode() {
return [this.makeCode('import')];
}
};
exports.DynamicImportCall = DynamicImportCall = class DynamicImportCall extends Call {
compileNode(o) {
if (this.args.length !== 1) {
this.error('import() requires exactly one argument');
}
return super.compileNode(o);
}
};
//### Assign
// The **Assign** is used to assign a local variable to value, or to set the
@@ -4044,7 +4075,7 @@
// (e.g. `ref`), shift those into the parent scope since we cant put a
// `var` line inside a function parameter list.
scopeVariablesCount = o.scope.variables.length;
signature.push(...param.compileToFragments(o));
signature.push(...param.compileToFragments(o, LEVEL_PAREN));
if (scopeVariablesCount !== o.scope.variables.length) {
generatedVariables = o.scope.variables.splice(scopeVariablesCount);
o.scope.parent.variables.push(...generatedVariables);
@@ -5201,13 +5232,18 @@
}
code = element.compileToFragments(o, LEVEL_PAREN);
if (!this.isNestedTag(element) || code.some(function(fragment) {
return fragment.comments != null;
var ref1;
return (ref1 = fragment.comments) != null ? ref1.some(function(comment) {
return comment.here === false;
}) : void 0;
})) {
code = this.wrapInBraces(code);
// Flag the `{` and `}` fragments as having been generated by this
// `StringWithInterpolations` node, so that `compileComments` knows
// to treat them as bounds. Dont trust `fragment.type`, which can
// report minified variable names when this compiler is minified.
// to treat them as bounds. But the braces are unnecessary if all of
// the enclosed comments are `/* */` comments. Dont trust
// `fragment.type`, which can report minified variable names when
// this compiler is minified.
code[0].isStringWithInterpolations = true;
code[code.length - 1].isStringWithInterpolations = true;
}

View File

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

File diff suppressed because one or more lines are too long

View File

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

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.3.1
// Generated by CoffeeScript 2.4.0
(function() {
var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, replDefaults, runInContext, sawSIGINT, transpile, updateSyntaxError, vm;
@@ -113,8 +113,8 @@
};
addMultilineHandler = function(repl) {
var inputStream, multiline, nodeLineListener, origPrompt, outputStream, ref, rli;
({rli, inputStream, outputStream} = repl);
var inputStream, multiline, nodeLineListener, origPrompt, outputStream, ref;
({inputStream, outputStream} = repl);
// Node 0.11.12 changed API, prompt is now _prompt.
origPrompt = (ref = repl._prompt) != null ? ref : repl.prompt;
multiline = {
@@ -128,15 +128,15 @@
buffer: ''
};
// Proxy node's line listener
nodeLineListener = rli.listeners('line')[0];
rli.removeListener('line', nodeLineListener);
rli.on('line', function(cmd) {
nodeLineListener = repl.listeners('line')[0];
repl.removeListener('line', nodeLineListener);
repl.on('line', function(cmd) {
if (multiline.enabled) {
multiline.buffer += `${cmd}\n`;
rli.setPrompt(multiline.prompt);
rli.prompt(true);
repl.setPrompt(multiline.prompt);
repl.prompt(true);
} else {
rli.setPrompt(origPrompt);
repl.setPrompt(origPrompt);
nodeLineListener(cmd);
}
});
@@ -149,28 +149,28 @@
// allow arbitrarily switching between modes any time before multiple lines are entered
if (!multiline.buffer.match(/\n/)) {
multiline.enabled = !multiline.enabled;
rli.setPrompt(origPrompt);
rli.prompt(true);
repl.setPrompt(origPrompt);
repl.prompt(true);
return;
}
// no-op unless the current line is empty
if ((rli.line != null) && !rli.line.match(/^\s*$/)) {
if ((repl.line != null) && !repl.line.match(/^\s*$/)) {
return;
}
// eval, print, loop
multiline.enabled = !multiline.enabled;
rli.line = '';
rli.cursor = 0;
rli.output.cursorTo(0);
rli.output.clearLine(1);
repl.line = '';
repl.cursor = 0;
repl.output.cursorTo(0);
repl.output.clearLine(1);
// XXX: multiline hack
multiline.buffer = multiline.buffer.replace(/\n/g, '\uFF00');
rli.emit('line', multiline.buffer);
repl.emit('line', multiline.buffer);
multiline.buffer = '';
} else {
multiline.enabled = !multiline.enabled;
rli.setPrompt(multiline.initialPrompt);
rli.prompt(true);
repl.setPrompt(multiline.initialPrompt);
repl.prompt(true);
}
});
};
@@ -189,20 +189,20 @@
fs.readSync(readFd, buffer, 0, size, stat.size - size);
fs.closeSync(readFd);
// Set the history on the interpreter
repl.rli.history = buffer.toString().split('\n').reverse();
repl.history = buffer.toString().split('\n').reverse();
if (stat.size > maxSize) {
// If the history file was truncated we should pop off a potential partial line
repl.rli.history.pop();
repl.history.pop();
}
if (repl.rli.history[0] === '') {
if (repl.history[0] === '') {
// Shift off the final blank newline
repl.rli.history.shift();
repl.history.shift();
}
repl.rli.historyIndex = -1;
lastLine = repl.rli.history[0];
repl.historyIndex = -1;
lastLine = repl.history[0];
} catch (error) {}
fd = fs.openSync(filename, 'a');
repl.rli.addListener('line', function(code) {
repl.addListener('line', function(code) {
if (code && code.length && code !== '.history' && code !== '.exit' && lastLine !== code) {
// Save the latest command in the file
fs.writeSync(fd, `${code}\n`);
@@ -220,7 +220,7 @@
return repl.commands[getCommandId(repl, 'history')] = {
help: 'Show command history',
action: function() {
repl.outputStream.write(`${repl.rli.history.slice(0).reverse().join('\n')}\n`);
repl.outputStream.write(`${repl.history.slice(0).reverse().join('\n')}\n`);
return repl.displayPrompt();
}
};
@@ -250,12 +250,16 @@
CoffeeScript.register();
process.argv = ['coffee'].concat(process.argv.slice(2));
if (opts.transpile) {
transpile = {};
try {
transpile = {};
transpile.transpile = require('babel-core').transform;
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 https://coffeescript.org/#transpilation');
process.exit(1);
try {
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 https://coffeescript.org/#transpilation');
process.exit(1);
}
}
transpile.options = {
filename: path.resolve(process.cwd(), '<repl>')
@@ -279,7 +283,7 @@
runInContext(opts.prelude, repl.context, 'prelude');
}
repl.on('exit', function() {
if (!repl.rli.closed) {
if (!repl.closed) {
return repl.outputStream.write('\n');
}
});

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.3.1
// Generated by CoffeeScript 2.4.0
(function() {
// The CoffeeScript language has a good deal of optional syntax, implicit syntax,
// and shorthand syntax. This can greatly complicate a grammar and bloat

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.3.1
// Generated by CoffeeScript 2.4.0
(function() {
// The **Scope** class regulates lexical scoping within CoffeeScript. As you
// generate code, you create a tree of scopes in the same shape as the nested

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.3.1
// Generated by CoffeeScript 2.4.0
(function() {
// Source maps allow JavaScript runtimes to match running JavaScript back to
// the original source code that corresponds to it. This can be minified

4593
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.3.1",
"version": "2.4.0",
"license": "MIT",
"engines": {
"node": ">=6"
@@ -17,6 +17,7 @@
"lib": "./lib/coffeescript"
},
"main": "./lib/coffeescript/index",
"module": "./docs/v2/browser-compiler-modern/coffeescript.js",
"browser": "./lib/coffeescript/browser",
"bin": {
"coffee": "./bin/coffee",
@@ -39,16 +40,16 @@
"url": "git://github.com/jashkenas/coffeescript.git"
},
"devDependencies": {
"babel-core": "6.26.3",
"babel-preset-env": "1.6.1",
"babel-preset-minify": "0.4.0",
"codemirror": "^5.37.0",
"@babel/core": "^7.4.0",
"@babel/preset-env": "^7.4.2",
"babel-preset-minify": "^0.5.0",
"codemirror": "^5.45.0",
"docco": "~0.8.0",
"highlight.js": "~9.12.0",
"jison": ">=0.4.18",
"markdown-it": "~8.4.1",
"underscore": "~1.9.0",
"webpack": "~4.6.0"
"highlight.js": "~9.15.6",
"jison": "^0.4.18",
"markdown-it": "~8.4.2",
"underscore": "~1.9.1",
"webpack": "~4.29.6"
},
"dependencies": {}
}

View File

@@ -58,7 +58,7 @@ CoffeeScript.load = (url, callback, options = {}, hold = false) ->
# Activate CoffeeScript in the browser by having it compile and evaluate
# all script tags with a content-type of `text/coffeescript`.
# This happens on page load.
runScripts = ->
CoffeeScript.runScripts = ->
scripts = window.document.getElementsByTagName 'script'
coffeetypes = ['text/coffeescript', 'text/literate-coffeescript']
coffees = (s for s in scripts when s.type in coffeetypes)
@@ -96,7 +96,12 @@ runScripts = ->
execute()
# Listen for window load, both in decent browsers and in IE.
if window.addEventListener
window.addEventListener 'DOMContentLoaded', runScripts, no
else
window.attachEvent 'onload', runScripts
# Only attach this event handler on startup for the
# non-ES module version of the browser compiler, to preserve
# backward compatibility while letting the ES module version
# be importable without side effects.
if this is window
if window.addEventListener
window.addEventListener 'DOMContentLoaded', CoffeeScript.runScripts, no
else
window.attachEvent 'onload', CoffeeScript.runScripts

View File

@@ -54,6 +54,20 @@ sources = {}
# Also save source maps if generated, in form of `(source)`: [`(source map)`].
sourceMaps = {}
# This is exported to enable an external module to implement caching of
# compilation results. When the compiled js source is loaded from cache, the
# original coffee code should be added with this method in order to enable the
# Error.prepareStackTrace below to correctly adjust the stack trace for the
# corresponding file (the source map will be generated on demand).
exports.registerCompiled = registerCompiled = (filename, source, sourcemap) ->
sources[filename] ?= []
sources[filename].push source
if sourcemap?
sourceMaps[filename] ?= []
sourceMaps[filename].push sourcemap
# Compile CoffeeScript code to JavaScript, using the Coffee/Jison compiler.
#
# If `options.sourceMap` is specified, then `options.filename` must also be
@@ -75,8 +89,6 @@ exports.compile = compile = withPrettyErrors (code, options = {}) ->
checkShebangLine filename, code
sources[filename] ?= []
sources[filename].push code
map = new SourceMap if generateSourceMap
tokens = lexer.tokenize code, options
@@ -126,8 +138,6 @@ exports.compile = compile = withPrettyErrors (code, options = {}) ->
if generateSourceMap
v3SourceMap = map.generate options, code
sourceMaps[filename] ?= []
sourceMaps[filename].push map
if options.transpile
if typeof options.transpile isnt 'object'
@@ -158,6 +168,8 @@ exports.compile = compile = withPrettyErrors (code, options = {}) ->
sourceURL = "//# sourceURL=#{options.filename ? 'coffeescript'}"
js = "#{js}\n#{sourceMapDataURI}\n#{sourceURL}"
registerCompiled filename, code, map
if options.sourceMap
{
js

View File

@@ -454,25 +454,28 @@ compileOptions = (filename, base) ->
# run CoffeeScripts output without transpilation (modern Node or evergreen
# browsers) or use a proper build chain like Gulp or Webpack.
try
require 'babel-core'
require '@babel/core'
catch
# Give appropriate instructions depending on whether `coffee` was run
# locally or globally.
if require.resolve('.').indexOf(process.cwd()) is 0
console.error '''
To use --transpile, you must have babel-core installed:
npm install --save-dev babel-core
And you must save options to configure Babel in one of the places it looks to find its options.
See https://coffeescript.org/#transpilation
'''
else
console.error '''
To use --transpile with globally-installed CoffeeScript, you must have babel-core installed globally:
npm install --global babel-core
And you must save options to configure Babel in one of the places it looks to find its options, relative to the file being compiled or to the current folder.
See https://coffeescript.org/#transpilation
'''
process.exit 1
try
require 'babel-core'
catch
# Give appropriate instructions depending on whether `coffee` was run
# locally or globally.
if require.resolve('.').indexOf(process.cwd()) is 0
console.error '''
To use --transpile, you must have @babel/core installed:
npm install --save-dev @babel/core
And you must save options to configure Babel in one of the places it looks to find its options.
See https://coffeescript.org/#transpilation
'''
else
console.error '''
To use --transpile with globally-installed CoffeeScript, you must have @babel/core installed globally:
npm install --global @babel/core
And you must save options to configure Babel in one of the places it looks to find its options, relative to the file being compiled or to the current folder.
See https://coffeescript.org/#transpilation
'''
process.exit 1
opts.transpile = {} unless typeof opts.transpile is 'object'

View File

@@ -138,6 +138,7 @@ grammar =
Yield: [
o 'YIELD', -> new Op $1, new Value new Literal ''
o 'YIELD Expression', -> new Op $1, $2
o 'YIELD INDENT Object OUTDENT', -> new Op $1, $3
o 'YIELD FROM Expression', -> new Op $1.concat($2), $3
]
@@ -239,6 +240,7 @@ grammar =
o 'Super'
o 'This'
o 'SUPER Arguments', -> new SuperCall LOC(1)(new Super), $2, no, $1
o 'DYNAMIC_IMPORT Arguments', -> new DynamicImportCall LOC(1)(new DynamicImport), $2
o 'SimpleObjAssignable Arguments', -> new Call (new Value $1), $2
o 'ObjSpreadExpr Arguments', -> new Call $1, $2
]
@@ -484,6 +486,7 @@ grammar =
o 'Value OptFuncExist String', -> new TaggedTemplateCall $1, $3, $2
o 'Value OptFuncExist Arguments', -> new Call $1, $3, $2
o 'SUPER OptFuncExist Arguments', -> new SuperCall LOC(1)(new Super), $3, $2, $1
o 'DYNAMIC_IMPORT Arguments', -> new DynamicImportCall LOC(1)(new DynamicImport), $2
]
# An optional existence check on a function.
@@ -817,7 +820,8 @@ grammar =
o '- Expression', (-> new Op '-', $2), prec: 'UNARY_MATH'
o '+ Expression', (-> new Op '+', $2), prec: 'UNARY_MATH'
o 'AWAIT Expression', -> new Op $1 , $2
o 'AWAIT Expression', -> new Op $1, $2
o 'AWAIT INDENT Object OUTDENT', -> new Op $1, $3
o '-- SimpleAssignable', -> new Op '--', $2
o '++ SimpleAssignable', -> new Op '++', $2
@@ -889,7 +893,7 @@ operators = [
['right', 'YIELD']
['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS']
['right', 'FORIN', 'FOROF', 'FORFROM', 'BY', 'WHEN']
['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT']
['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT', 'DYNAMIC_IMPORT']
['left', 'POST_IF']
]

View File

@@ -8,11 +8,14 @@ helpers = CoffeeScript.helpers
CoffeeScript.transpile = (js, options) ->
try
babel = require 'babel-core'
babel = require '@babel/core'
catch
# This error is only for Node, as CLI users will see a different error
# earlier if they dont have Babel installed.
throw new Error 'To use the transpile option, you must have the \'babel-core\' module installed'
try
babel = require 'babel-core'
catch
# This error is only for Node, as CLI users will see a different error
# earlier if they dont have Babel installed.
throw new Error 'To use the transpile option, you must have the \'@babel/core\' module installed'
babel.transform js, options
# The `compile` method shared by the CLI, Node and browser APIs.
@@ -107,8 +110,8 @@ if require.extensions
Use CoffeeScript.register() or require the coffeescript/register module to require #{ext} files.
"""
CoffeeScript._compileFile = (filename, options = {}) ->
raw = fs.readFileSync filename, 'utf8'
CoffeeScript._compileRawFileContent = (raw, filename, options = {}) ->
# 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
@@ -128,4 +131,9 @@ CoffeeScript._compileFile = (filename, options = {}) ->
answer
CoffeeScript._compileFile = (filename, options = {}) ->
raw = fs.readFileSync filename, 'utf8'
CoffeeScript._compileRawFileContent raw, filename, options
module.exports = CoffeeScript

View File

@@ -196,6 +196,8 @@ exports.Lexer = class Lexer
@tokens.length > 1 and @tokens[@tokens.length - 2][0] not in ['.', '?.', '@']
@error "'#{prev[1]}' cannot be used as a keyword, or as a function call
without parentheses", prev[2]
else if prev[0] is '.' and @tokens.length > 1 and (prevprev = @tokens[@tokens.length - 2])[0] is 'UNARY' and prevprev[1] is 'new'
prevprev[0] = 'IDENTIFIER'
else if @tokens.length > 2
prevprev = @tokens[@tokens.length - 2]
if prev[0] in ['@', 'THIS'] and prevprev and prevprev.spaced and
@@ -665,6 +667,9 @@ exports.Lexer = class Lexer
@error message, origin[2] if message
return value.length if skipToken
if value is '(' and prev?[0] is 'IMPORT'
prev[0] = 'DYNAMIC_IMPORT'
if value is '{' and @seenImport
@importSpecifierList = yes
else if @importSpecifierList and value is '}'
@@ -1107,12 +1112,8 @@ exports.isUnassignable = isUnassignable
# loop. Try to detect when `from` is a variable identifier and when it is this
# “sometimes” keyword.
isForFrom = (prev) ->
# `for i from iterable`
if prev[0] is 'IDENTIFIER'
# `for i from from`, `for from from iterable`
if prev[1] is 'from'
prev[1][0] = 'IDENTIFIER'
yes
# `for i from iterable`
yes
# `for from…`
else if prev[0] is 'FOR'
@@ -1354,7 +1355,7 @@ BOOL = ['TRUE', 'FALSE']
# Tokens which could legitimately be invoked or indexed. An opening
# parentheses or bracket following these tokens will be recorded as the start
# of a function invocation or indexing operation.
CALLABLE = ['IDENTIFIER', 'PROPERTY', ')', ']', '?', '@', 'THIS', 'SUPER']
CALLABLE = ['IDENTIFIER', 'PROPERTY', ')', ']', '?', '@', 'THIS', 'SUPER', 'DYNAMIC_IMPORT']
INDEXABLE = CALLABLE.concat [
'NUMBER', 'INFINITY', 'NAN', 'STRING', 'STRING_END', 'REGEX', 'REGEX_END'
'BOOL', 'NULL', 'UNDEFINED', '}', '::'

View File

@@ -207,7 +207,7 @@ exports.Base = class Base
# Occasionally it may be useful to make an expression behave as if it was 'hoisted', whereby the
# result of the expression is available before its location in the source, but the expression's
# variable scope corresponds the source position. This is used extensively to deal with executable
# variable scope corresponds to the source position. This is used extensively to deal with executable
# class bodies in classes.
#
# Calling this method mutates the node, proxying the `compileNode` and `compileToFragments`
@@ -965,6 +965,7 @@ exports.Value = class Value extends Base
# operators `?.` interspersed. Then we have to take care not to accidentally
# evaluate anything twice when building the soak chain.
compileNode: (o) ->
@checkNewTarget o
@base.front = @front
props = @properties
if props.length and @base.cached?
@@ -984,6 +985,14 @@ exports.Value = class Value extends Base
fragments
checkNewTarget: (o) ->
return unless @base instanceof IdentifierLiteral and @base.value is 'new' and @properties.length
if @properties[0] instanceof Access and @properties[0].name.value is 'target'
unless o.scope.parent?
@error "new.target can only occur inside functions"
else
@error "the only valid meta property for new is new.target"
# Unfold a soak into an `If`: `a?.b` -> `a.b if a?`
unfoldSoak: (o) ->
@unfoldedSoak ?= do =>
@@ -1635,8 +1644,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]).
fragmentIsElision = ([ fragment ]) ->
fragment.type is 'Elision' and fragment.code.trim() is ','
# Detect if `Elision`s at the beginning of the array are processed (e.g. [, , , a]).
passedElision = no
answer = []
@@ -1678,7 +1688,7 @@ exports.Arr = class Arr extends Base
for fragment, fragmentIndex in answer
if fragment.isHereComment
fragment.code = "#{multident(fragment.code, o.indent, no)}\n#{o.indent}"
else if fragment.code is ', ' and not fragment?.isElision
else if fragment.code is ', ' and not fragment?.isElision and fragment.type isnt 'StringLiteral'
fragment.code = ",\n#{o.indent}"
answer.unshift @makeCode "[\n#{o.indent}"
answer.push @makeCode "\n#{@tab}]"
@@ -1979,7 +1989,7 @@ exports.ExecutableClassBody = class ExecutableClassBody extends Base
@body.traverseChildren false, (node) =>
if node instanceof ThisLiteral
node.value = @name
else if node instanceof Code and node.bound and node.isStatic
else if node instanceof Code and node.bound and (node.isStatic or not node.name)
node.context = @name
# Make class/prototype assignments for invalid ES properties
@@ -2162,6 +2172,16 @@ exports.ExportSpecifier = class ExportSpecifier extends ModuleSpecifier
constructor: (local, exported) ->
super local, exported, 'export'
exports.DynamicImport = class DynamicImport extends Base
compileNode: ->
[@makeCode 'import']
exports.DynamicImportCall = class DynamicImportCall extends Call
compileNode: (o) ->
unless @args.length is 1
@error 'import() requires exactly one argument'
super o
#### Assign
# The **Assign** is used to assign a local variable to value, or to set the
@@ -2734,7 +2754,7 @@ exports.Code = class Code extends Base
# (e.g. `ref`), shift those into the parent scope since we cant put a
# `var` line inside a function parameter list.
scopeVariablesCount = o.scope.variables.length
signature.push param.compileToFragments(o)...
signature.push param.compileToFragments(o, LEVEL_PAREN)...
if scopeVariablesCount isnt o.scope.variables.length
generatedVariables = o.scope.variables.splice scopeVariablesCount
o.scope.parent.variables.push generatedVariables...
@@ -3501,12 +3521,15 @@ exports.StringWithInterpolations = class StringWithInterpolations extends Base
else
fragments.push @makeCode '$' unless @csx
code = element.compileToFragments(o, LEVEL_PAREN)
if not @isNestedTag(element) or code.some((fragment) -> fragment.comments?)
if not @isNestedTag(element) or
code.some((fragment) -> fragment.comments?.some((comment) -> comment.here is no))
code = @wrapInBraces code
# Flag the `{` and `}` fragments as having been generated by this
# `StringWithInterpolations` node, so that `compileComments` knows
# to treat them as bounds. Dont trust `fragment.type`, which can
# report minified variable names when this compiler is minified.
# to treat them as bounds. But the braces are unnecessary if all of
# the enclosed comments are `/* */` comments. Dont trust
# `fragment.type`, which can report minified variable names when
# this compiler is minified.
code[0].isStringWithInterpolations = yes
code[code.length - 1].isStringWithInterpolations = yes
fragments.push code...

View File

@@ -75,7 +75,7 @@ runInContext = (js, context, filename) ->
vm.runInContext js, context, filename
addMultilineHandler = (repl) ->
{rli, inputStream, outputStream} = repl
{inputStream, outputStream} = repl
# Node 0.11.12 changed API, prompt is now _prompt.
origPrompt = repl._prompt ? repl.prompt
@@ -86,15 +86,15 @@ addMultilineHandler = (repl) ->
buffer: ''
# Proxy node's line listener
nodeLineListener = rli.listeners('line')[0]
rli.removeListener 'line', nodeLineListener
rli.on 'line', (cmd) ->
nodeLineListener = repl.listeners('line')[0]
repl.removeListener 'line', nodeLineListener
repl.on 'line', (cmd) ->
if multiline.enabled
multiline.buffer += "#{cmd}\n"
rli.setPrompt multiline.prompt
rli.prompt true
repl.setPrompt multiline.prompt
repl.prompt true
else
rli.setPrompt origPrompt
repl.setPrompt origPrompt
nodeLineListener cmd
return
@@ -105,25 +105,25 @@ addMultilineHandler = (repl) ->
# allow arbitrarily switching between modes any time before multiple lines are entered
unless multiline.buffer.match /\n/
multiline.enabled = not multiline.enabled
rli.setPrompt origPrompt
rli.prompt true
repl.setPrompt origPrompt
repl.prompt true
return
# no-op unless the current line is empty
return if rli.line? and not rli.line.match /^\s*$/
return if repl.line? and not repl.line.match /^\s*$/
# eval, print, loop
multiline.enabled = not multiline.enabled
rli.line = ''
rli.cursor = 0
rli.output.cursorTo 0
rli.output.clearLine 1
repl.line = ''
repl.cursor = 0
repl.output.cursorTo 0
repl.output.clearLine 1
# XXX: multiline hack
multiline.buffer = multiline.buffer.replace /\n/g, '\uFF00'
rli.emit 'line', multiline.buffer
repl.emit 'line', multiline.buffer
multiline.buffer = ''
else
multiline.enabled = not multiline.enabled
rli.setPrompt multiline.initialPrompt
rli.prompt true
repl.setPrompt multiline.initialPrompt
repl.prompt true
return
# Store and load command history from a file
@@ -139,17 +139,17 @@ addHistory = (repl, filename, maxSize) ->
fs.readSync readFd, buffer, 0, size, stat.size - size
fs.closeSync readFd
# Set the history on the interpreter
repl.rli.history = buffer.toString().split('\n').reverse()
repl.history = buffer.toString().split('\n').reverse()
# If the history file was truncated we should pop off a potential partial line
repl.rli.history.pop() if stat.size > maxSize
repl.history.pop() if stat.size > maxSize
# Shift off the final blank newline
repl.rli.history.shift() if repl.rli.history[0] is ''
repl.rli.historyIndex = -1
lastLine = repl.rli.history[0]
repl.history.shift() if repl.history[0] is ''
repl.historyIndex = -1
lastLine = repl.history[0]
fd = fs.openSync filename, 'a'
repl.rli.addListener 'line', (code) ->
repl.addListener 'line', (code) ->
if code and code.length and code isnt '.history' and code isnt '.exit' and lastLine isnt code
# Save the latest command in the file
fs.writeSync fd, "#{code}\n"
@@ -163,7 +163,7 @@ addHistory = (repl, filename, maxSize) ->
repl.commands[getCommandId(repl, 'history')] =
help: 'Show command history'
action: ->
repl.outputStream.write "#{repl.rli.history[..].reverse().join '\n'}\n"
repl.outputStream.write "#{repl.history[..].reverse().join '\n'}\n"
repl.displayPrompt()
getCommandId = (repl, commandName) ->
@@ -182,19 +182,22 @@ module.exports =
CoffeeScript.register()
process.argv = ['coffee'].concat process.argv[2..]
if opts.transpile
transpile = {}
try
transpile = {}
transpile.transpile = require('babel-core').transform
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 https://coffeescript.org/#transpilation
'''
process.exit 1
try
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 https://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
@@ -209,7 +212,7 @@ module.exports =
opts = merge replDefaults, opts
repl = nodeREPL.start opts
runInContext opts.prelude, repl.context, 'prelude' if opts.prelude
repl.on 'exit', -> repl.outputStream.write '\n' if not repl.rli.closed
repl.on 'exit', -> repl.outputStream.write '\n' if not repl.closed
addMultilineHandler repl
addHistory repl, opts.historyFile, opts.historyMaxInputSize if opts.historyFile
# Adapt help inherited from the node REPL

View File

@@ -115,6 +115,12 @@ test "array elisions nested destructuring", ->
deepEqual d, {x:2}
arrayEq w, [1,2,4]
test "#5112: array elisions not detected inside strings", ->
arr = [
str: ", #{3}"
]
eq arr[0].str, ', 3'
# Splats in Array Literals
test "array splat expansions with assignments", ->

View File

@@ -196,3 +196,11 @@ test "async methods in classes", ->
eq await Child.static(), 1
eq await new Child().method(), 2
test "#3199: await multiline implicit object", ->
do ->
y =
if no then await
type: 'a'
msg: 'b'
eq undefined, y

View File

@@ -1899,4 +1899,39 @@ test "#4868: Incorrect Cant call super with @params error", ->
super class then constructor: (@a) -> @a = 3
d = new (new D).c
eq 3, d.a
eq 3, d.a
test "#4609: Support new.target", ->
class A
constructor: ->
@calledAs = new.target.name
class B extends A
b = new B
eq b.calledAs, 'B'
newTarget = null
Foo = ->
newTarget = !!new.target
Foo()
eq newTarget, no
newTarget = null
new Foo()
eq newTarget, yes
test "#5085: Bug: @ reference to class not maintained in do block", ->
thisFoo = 'initial foo'
thisBar = 'initial bar'
fn = (o) -> o.bar()
class A
@foo = 'foo assigned in class'
do => thisFoo = @foo
fn bar: => thisBar = @foo
eq thisFoo, 'foo assigned in class'
eq thisBar, 'foo assigned in class'

View File

@@ -11,7 +11,7 @@ transpile = (method, code, options = {}) ->
options.bare = yes
options.transpile =
# Target Internet Explorer 6, which supports no ES2015+ features.
presets: [['env', {targets: browsers: ['ie 6']}]]
presets: [['@babel/env', {targets: browsers: ['ie 6']}]]
CoffeeScript[method] code, options
@@ -176,4 +176,4 @@ test "#3306: trailing comma in a function call in the last line", ->
foo bar,
''', '''
foo(bar);
'''
'''

View File

@@ -742,6 +742,47 @@ test '#4686: comments inside interpolations that also contain CSX attributes', -
</div>;
'''
test '#5086: comments inside CSX tags but outside interpolations', ->
eqJS '''
<div>
<div ###comment### attribute={value} />
</div>
''', '''
<div>
<div /*comment*/attribute={value} />
</div>;
'''
test '#5086: comments inside CSX attributes but outside interpolations', ->
eqJS '''
<div>
<div attribute={###attr comment### value} />
</div>
''', '''
<div>
<div attribute={/*attr comment*/value} />
</div>;
'''
test '#5086: comments inside nested CSX tags and attributes but outside interpolations', ->
eqJS '''
<div>
<div>
<div>
<div ###comment### attribute={###attr comment### value} />
</div>
</div>
</div>
''', '''
<div>
<div>
<div>
<div /*comment*/attribute={/*attr comment*/value} />
</div>
</div>
</div>;
'''
# https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html
test 'JSX fragments: empty fragment', ->
eqJS '''

View File

@@ -1796,6 +1796,50 @@ test "#3199: error message for throw indented comprehension", ->
^
'''
test "#3199: error message for yield indented non-object", ->
assertErrorFormat '''
->
yield
1
''', '''
[stdin]:3:5: error: unexpected number
1
^
'''
test "#3199: error message for yield indented comprehension", ->
assertErrorFormat '''
->
yield
x for x in [1, 2, 3]
''', '''
[stdin]:3:5: error: unexpected identifier
x for x in [1, 2, 3]
^
'''
test "#3199: error message for await indented non-object", ->
assertErrorFormat '''
->
await
1
''', '''
[stdin]:3:5: error: unexpected number
1
^
'''
test "#3199: error message for await indented comprehension", ->
assertErrorFormat '''
->
await
x for x in [1, 2, 3]
''', '''
[stdin]:3:5: error: unexpected identifier
x for x in [1, 2, 3]
^
'''
test "#3098: suppressed newline should be unsuppressed by semicolon", ->
assertErrorFormat '''
a = ; 5
@@ -1863,3 +1907,47 @@ test "#3933: prevent implicit calls when cotrol flow is missing `THEN`", ->
when a ->
^^
'''
test "`new.target` outside of a function", ->
assertErrorFormat '''
new.target
''', '''
[stdin]:1:1: error: new.target can only occur inside functions
new.target
^^^^^^^^^^
'''
test "`new.target` is only allowed meta property", ->
assertErrorFormat '''
-> new.something
''', '''
[stdin]:1:4: error: the only valid meta property for new is new.target
-> new.something
^^^^^^^^^^^^^
'''
test "#4834: dynamic import requires exactly one argument", ->
assertErrorFormat '''
import()
''', '''
[stdin]:1:1: error: import() requires exactly one argument
import()
^^^^^^^^
'''
assertErrorFormat '''
import('x', {})
''', '''
[stdin]:1:1: error: import() requires exactly one argument
import('x', {})
^^^^^^^^^^^^^^^
'''
test "#4834: dynamic import requires explicit call parentheses", ->
assertErrorFormat '''
promise = import 'foo'
''', '''
[stdin]:1:23: error: unexpected end of input
promise = import 'foo'
^
'''

View File

@@ -417,6 +417,22 @@ test "#3199: throw multiline implicit object", ->
msg: 'b'
eq undefined, y
y = do ->
yield
type: 'a'
msg: 'b'
if no then yield
type: 'c'
msg: 'd'
1
{value, done} = y.next()
ok value.type is 'a' and done is no
{value, done} = y.next()
ok value is 1 and done is yes
test "#4576: multiple row function chaining", ->
->
eq @a, 3

View File

@@ -493,3 +493,7 @@ test "#4657: destructured array parameters", ->
result = f [1, 2, 3, 4]
arrayEq result.a, [1, 2, 3]
eq result.b, 4
test "#5128: default parameters of function in binary operation", ->
foo = yes or (a, b = {}) -> null
eq foo, yes

View File

@@ -920,3 +920,24 @@ test "#4874: backslash `export`", ->
min
} from 'underscore';
"""
test "#4834: dynamic import", ->
eqJS """
import('module').then ->
""",
"""
import('module').then(function() {});
"""
eqJS """
foo = ->
bar = await import('bar')
""",
"""
var foo;
foo = async function() {
var bar;
return bar = (await import('bar'));
};
"""

View File

@@ -418,3 +418,13 @@ test "#4673: complex destructured object spread variables", ->
g = ({@y...}) ->
eq @y.b, 1
g b: 1
test "#4834: dynamic import can technically be object spread", ->
eqJS """
x = {...import('module')}
""",
"""
var x;
x = {...import('module')};
"""

View File

@@ -45,7 +45,7 @@ ctrlV = { ctrl: true, name: 'v'}
testRepl 'reads history file', (input, output, repl) ->
input.emitLine repl.rli.history[0]
input.emitLine repl.history[0]
eq '3', output.lastWrite()
testRepl "starts with coffee prompt", (input, output) ->