mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-13 16:57:54 -05:00
Compare commits
204 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84b8b5ccee | ||
|
|
7b14a6aad2 | ||
|
|
342306587c | ||
|
|
3298c9caad | ||
|
|
7089b02a74 | ||
|
|
bd451800bf | ||
|
|
5e06f7e859 | ||
|
|
0f5ae54014 | ||
|
|
5496a189bc | ||
|
|
2e6a781014 | ||
|
|
b85cf5355f | ||
|
|
f038d0514a | ||
|
|
7c4128ee3b | ||
|
|
012e3c019c | ||
|
|
b3ffd25339 | ||
|
|
46a0dc6dce | ||
|
|
30b2af820a | ||
|
|
e7d01b903f | ||
|
|
e4407dd73c | ||
|
|
2fd956d8d4 | ||
|
|
c0aac8e598 | ||
|
|
d46a44ac48 | ||
|
|
9b1bdd4b36 | ||
|
|
fd47920c63 | ||
|
|
088b8b3ec5 | ||
|
|
afd9b44dea | ||
|
|
b54db2ea07 | ||
|
|
3650d6eb4e | ||
|
|
05b74f3743 | ||
|
|
174cd7eaa0 | ||
|
|
3921e3db34 | ||
|
|
63bc7fe354 | ||
|
|
ba01e36cc2 | ||
|
|
40d2761bd8 | ||
|
|
4ff7fef3bb | ||
|
|
7be996c010 | ||
|
|
f4332475b5 | ||
|
|
4da00e8296 | ||
|
|
e8fae286be | ||
|
|
f451bb5f61 | ||
|
|
d8d7495767 | ||
|
|
4b4f6ac222 | ||
|
|
7b9699c5fa | ||
|
|
8a59558e2d | ||
|
|
5162472f16 | ||
|
|
1917bb69ed | ||
|
|
3b38153759 | ||
|
|
e06a17d929 | ||
|
|
71aea4b862 | ||
|
|
4b4818d819 | ||
|
|
c785e00a15 | ||
|
|
c6398e16b1 | ||
|
|
ccc7c4404d | ||
|
|
69d66a1d4d | ||
|
|
af81f6de70 | ||
|
|
f21dc7a96e | ||
|
|
cf07fcb4b1 | ||
|
|
740a7bcb45 | ||
|
|
0e2d2ea637 | ||
|
|
feaea49eac | ||
|
|
170f311101 | ||
|
|
0cadcdc097 | ||
|
|
337ebd3ce9 | ||
|
|
5d5920c5d0 | ||
|
|
8be65dee93 | ||
|
|
4dbd9dc264 | ||
|
|
2d0e45c46d | ||
|
|
cc84d6ea67 | ||
|
|
53a5f26430 | ||
|
|
a1ff4ae7b8 | ||
|
|
3251efa9c6 | ||
|
|
17a1cdb2cf | ||
|
|
1643f7df7a | ||
|
|
3c0344b954 | ||
|
|
9bfafb88cb | ||
|
|
718224f99a | ||
|
|
b2d6997eff | ||
|
|
e26f982c24 | ||
|
|
1b2fe69a18 | ||
|
|
c159a64b58 | ||
|
|
e091c9d6b4 | ||
|
|
57d3cfd67f | ||
|
|
6dd61626d2 | ||
|
|
1e99f887e7 | ||
|
|
78d10f30a0 | ||
|
|
7f0610d0bd | ||
|
|
4bef435e0e | ||
|
|
194baa0bd7 | ||
|
|
c8b8beb500 | ||
|
|
6786bab2ba | ||
|
|
566a7dabb2 | ||
|
|
a3e8de338a | ||
|
|
4f815ea978 | ||
|
|
417008a030 | ||
|
|
84c44c0099 | ||
|
|
2d6a856d61 | ||
|
|
011d7dc245 | ||
|
|
b2aa1798b1 | ||
|
|
5fb047930e | ||
|
|
c24e957f17 | ||
|
|
fd0b1ffc4d | ||
|
|
0bfe6394a4 | ||
|
|
9d025df9e3 | ||
|
|
2f5b11b295 | ||
|
|
c44826acc7 | ||
|
|
4386f2abc7 | ||
|
|
f217a10721 | ||
|
|
b8d695a4e1 | ||
|
|
44c2b4aa7f | ||
|
|
52ca531b7c | ||
|
|
d4254a40a9 | ||
|
|
052e3cc8eb | ||
|
|
56413ba3b4 | ||
|
|
71bb6108fb | ||
|
|
7d08dbb86c | ||
|
|
a8b65565dd | ||
|
|
54258e441d | ||
|
|
4ac223b684 | ||
|
|
707655daef | ||
|
|
70e83030a7 | ||
|
|
9787ce543d | ||
|
|
22595424a8 | ||
|
|
601189ea2d | ||
|
|
d3263dc35b | ||
|
|
e1c6b083f8 | ||
|
|
f56f5f234e | ||
|
|
4ca6da4a95 | ||
|
|
b0cbd90e64 | ||
|
|
9b6772a390 | ||
|
|
b7f0653a0e | ||
|
|
45bcd9fa2f | ||
|
|
20d98c7106 | ||
|
|
5ec658c55d | ||
|
|
64301d0d08 | ||
|
|
119ec16e5e | ||
|
|
decc0f18fc | ||
|
|
5a004425ca | ||
|
|
69f6500ba9 | ||
|
|
97980ffc7f | ||
|
|
f0fcf4aee0 | ||
|
|
838e5e1163 | ||
|
|
af0bdae675 | ||
|
|
0d45287057 | ||
|
|
09f8df9640 | ||
|
|
dbb99f31a7 | ||
|
|
c7da623d4b | ||
|
|
b44435ab8a | ||
|
|
c53df12ec1 | ||
|
|
13fae12f69 | ||
|
|
0120db0efc | ||
|
|
c4f50b52d7 | ||
|
|
242f397bfa | ||
|
|
f85d19b459 | ||
|
|
8f7f3627e0 | ||
|
|
8b134cf348 | ||
|
|
67de35ff29 | ||
|
|
774ee6a554 | ||
|
|
4be4ea3623 | ||
|
|
18fec7e202 | ||
|
|
072df5ecc9 | ||
|
|
4d7151aa5d | ||
|
|
185b2ce632 | ||
|
|
ce6772f2be | ||
|
|
d6e1a979e4 | ||
|
|
de8ec2beb0 | ||
|
|
342a796cc0 | ||
|
|
355754ed20 | ||
|
|
fbe07f1fce | ||
|
|
304432c197 | ||
|
|
5da7f6a488 | ||
|
|
f8c6b494aa | ||
|
|
1b573412d3 | ||
|
|
b400047045 | ||
|
|
51b1affbc5 | ||
|
|
903e9c994c | ||
|
|
fca68717ff | ||
|
|
22d6a4b255 | ||
|
|
26102a0970 | ||
|
|
add84bfddc | ||
|
|
dcd74d3e59 | ||
|
|
2684737b66 | ||
|
|
74181c0ec0 | ||
|
|
ebff9fbc31 | ||
|
|
97a41adf0c | ||
|
|
9ea4268b92 | ||
|
|
589d67d8b7 | ||
|
|
3127e76f4b | ||
|
|
0affb4f936 | ||
|
|
55c99dfaec | ||
|
|
c98fae59fc | ||
|
|
3182475207 | ||
|
|
5115fcb162 | ||
|
|
1db89d1589 | ||
|
|
fbc8417263 | ||
|
|
44e3a76881 | ||
|
|
f2efada0d4 | ||
|
|
5f00d6478a | ||
|
|
7e5f1b14a3 | ||
|
|
caacd892cc | ||
|
|
25091fb2a0 | ||
|
|
334dcbd162 | ||
|
|
7065538224 | ||
|
|
7fdd21b26d | ||
|
|
deae3e53f5 |
20
Cakefile
20
Cakefile
@@ -85,20 +85,15 @@ task 'build:parser', 'rebuild the Jison parser (run build first)', ->
|
||||
fs.writeFile 'lib/coffee-script/parser.js', parser.generate()
|
||||
|
||||
|
||||
task 'build:ultraviolet', 'build and install the Ultraviolet syntax highlighter', ->
|
||||
exec 'plist2syntax ../coffee-script-tmbundle/Syntaxes/CoffeeScript.tmLanguage', (err) ->
|
||||
throw err if err
|
||||
exec 'sudo mv coffeescript.yaml /usr/local/lib/ruby/gems/1.8/gems/ultraviolet-0.10.2/syntax/coffeescript.syntax'
|
||||
|
||||
|
||||
task 'build:browser', 'rebuild the merged script for inclusion in the browser', ->
|
||||
code = ''
|
||||
for name in ['helpers', 'rewriter', 'lexer', 'parser', 'scope', 'nodes', 'sourcemap', 'coffee-script', 'browser']
|
||||
code += """
|
||||
require['./#{name}'] = new function() {
|
||||
var exports = this;
|
||||
require['./#{name}'] = (function() {
|
||||
var exports = {}, module = {exports: exports};
|
||||
#{fs.readFileSync "lib/coffee-script/#{name}.js"}
|
||||
};
|
||||
return module.exports;
|
||||
})();
|
||||
"""
|
||||
code = """
|
||||
(function(root) {
|
||||
@@ -211,20 +206,15 @@ runTests = (CoffeeScript) ->
|
||||
log "failed #{failures.length} and #{message}", red
|
||||
for fail in failures
|
||||
{error, filename, description, source} = fail
|
||||
jsFilename = filename.replace(/\.coffee$/,'.js')
|
||||
match = error.stack?.match(new RegExp(fail.file+":(\\d+):(\\d+)"))
|
||||
match = error.stack?.match(/on line (\d+):/) unless match
|
||||
[match, line, col] = match if match
|
||||
console.log ''
|
||||
log " #{description}", red if description
|
||||
log " #{error.stack}", red
|
||||
log " #{jsFilename}: line #{line ? 'unknown'}, column #{col ? 'unknown'}", red
|
||||
console.log " #{source}" if source
|
||||
return
|
||||
|
||||
# Run every test in the `test` folder, recording failures.
|
||||
files = fs.readdirSync 'test'
|
||||
for file in files when file.match /\.(lit)?coffee$/i
|
||||
for file in files when helpers.isCoffee file
|
||||
literate = helpers.isLiterate file
|
||||
currentFile = filename = path.join 'test', file
|
||||
code = fs.readFileSync filename
|
||||
|
||||
4
LICENSE
4
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2009-2012 Jeremy Ashkenas
|
||||
Copyright (c) 2009-2013 Jeremy Ashkenas
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
@@ -19,4 +19,4 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
###
|
||||
CoffeeScript Compiler v1.6.1
|
||||
SkinnyMochaHalfCaffScript Compiler v1.0
|
||||
Released under the MIT License
|
||||
###
|
||||
|
||||
|
||||
4
documentation/coffee/constructor_destructuring.coffee
Normal file
4
documentation/coffee/constructor_destructuring.coffee
Normal file
@@ -0,0 +1,4 @@
|
||||
class Person
|
||||
constructor: (options) ->
|
||||
{@name, @age, @height} = options
|
||||
|
||||
8
documentation/coffee/switch_with_no_expression.coffee
Normal file
8
documentation/coffee/switch_with_no_expression.coffee
Normal file
@@ -0,0 +1,8 @@
|
||||
score = 76
|
||||
grade = switch
|
||||
when score < 60 then 'F'
|
||||
when score < 70 then 'D'
|
||||
when score < 80 then 'C'
|
||||
when score < 90 then 'B'
|
||||
else 'A'
|
||||
# grade == 'C'
|
||||
@@ -85,7 +85,7 @@
|
||||
|
||||
|
||||
<a class="source" href="sourcemap.html">
|
||||
sourcemap.coffee
|
||||
sourcemap.litcoffee
|
||||
</a>
|
||||
|
||||
</div>
|
||||
@@ -108,15 +108,18 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-1">¶</a>
|
||||
</div>
|
||||
<p>Override exported methods for non-Node.js engines.
|
||||
|
||||
|
||||
<p>This <strong>Browser</strong> 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 <strong>XHR</strong>, and
|
||||
<code>text/coffeescript</code> script tags, source maps via data-URLs, and so on.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">CoffeeScript = </span><span class="nx">require</span> <span class="s">'./coffee-script'</span>
|
||||
<span class="nv">CoffeeScript.require = </span><span class="nx">require</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
CoffeeScript = require <span class="string">'./coffee-script'</span>
|
||||
CoffeeScript.require = require
|
||||
compile = CoffeeScript.compile</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -127,16 +130,14 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-2">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Use standard JavaScript <code>eval</code> to eval code.
|
||||
|
||||
<p>Use standard JavaScript <code>eval</code> to eval code.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">CoffeeScript.eval = </span><span class="nf">(code, options = {}) -></span>
|
||||
<span class="nx">options</span><span class="p">.</span><span class="nx">bare</span> <span class="o">?=</span> <span class="kc">on</span>
|
||||
<span class="nb">eval</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">options</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>CoffeeScript.<span class="function"><span class="title">eval</span></span> = (code, options = {}) ->
|
||||
options.bare ?= <span class="literal">on</span>
|
||||
eval compile code, options</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -147,16 +148,15 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-3">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Running code does not provide access to this scope.
|
||||
|
||||
<p>Running code does not provide access to this scope.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">CoffeeScript.run = </span><span class="nf">(code, options = {}) -></span>
|
||||
<span class="nv">options.bare = </span><span class="kc">on</span>
|
||||
<span class="nb">Function</span><span class="p">(</span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">)()</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>CoffeeScript.<span class="function"><span class="title">run</span></span> = (code, options = {}) ->
|
||||
options.bare = <span class="literal">on</span>
|
||||
options.shiftLine = <span class="literal">on</span>
|
||||
Function(compile code, options)()</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -167,14 +167,12 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-4">¶</a>
|
||||
</div>
|
||||
|
||||
<p>If we're not in a browser environment, we're finished with the public API.
|
||||
|
||||
<p>If we're not in a browser environment, we're finished with the public API.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="k">return</span> <span class="k">unless</span> <span class="nb">window</span><span class="o">?</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="keyword">return</span> <span class="keyword">unless</span> window?</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -185,28 +183,19 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-5">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Load a remote script from the current domain via XHR.
|
||||
|
||||
<p>Include source maps where possible. If we've got a base64 encoder, a
|
||||
JSON serializer, and tools for escaping unicode characters, we're good to go.
|
||||
Ported from <a href="https://developer.mozilla.org/en-US/docs/DOM/window.btoa">https://developer.mozilla.org/en-US/docs/DOM/window.btoa</a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">CoffeeScript.load = </span><span class="nf">(url, callback, options = {}) -></span>
|
||||
<span class="nv">xhr = </span><span class="k">if</span> <span class="nb">window</span><span class="p">.</span><span class="nx">ActiveXObject</span>
|
||||
<span class="k">new</span> <span class="nb">window</span><span class="p">.</span><span class="nx">ActiveXObject</span><span class="p">(</span><span class="s">'Microsoft.XMLHTTP'</span><span class="p">)</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">new</span> <span class="nx">XMLHttpRequest</span><span class="p">()</span>
|
||||
<span class="nx">xhr</span><span class="p">.</span><span class="nx">open</span> <span class="s">'GET'</span><span class="p">,</span> <span class="nx">url</span><span class="p">,</span> <span class="kc">true</span>
|
||||
<span class="nx">xhr</span><span class="p">.</span><span class="nx">overrideMimeType</span> <span class="s">'text/plain'</span> <span class="k">if</span> <span class="s">'overrideMimeType'</span> <span class="k">of</span> <span class="nx">xhr</span>
|
||||
<span class="nv">xhr.onreadystatechange = </span><span class="nf">-></span>
|
||||
<span class="k">if</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">readyState</span> <span class="o">is</span> <span class="mi">4</span>
|
||||
<span class="k">if</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">status</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">200</span><span class="p">]</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">responseText</span><span class="p">,</span> <span class="nx">options</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s">"Could not load </span><span class="si">#{</span><span class="nx">url</span><span class="si">}</span><span class="s">"</span>
|
||||
<span class="nx">callback</span><span class="p">()</span> <span class="k">if</span> <span class="nx">callback</span>
|
||||
<span class="nx">xhr</span><span class="p">.</span><span class="nx">send</span> <span class="kc">null</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="keyword">if</span> btoa? <span class="keyword">and</span> JSON? <span class="keyword">and</span> unescape? <span class="keyword">and</span> encodeURIComponent?
|
||||
<span class="function"><span class="title">compile</span></span> = (code, options = {}) ->
|
||||
options.sourceMap = <span class="literal">true</span>
|
||||
options.inline = <span class="literal">true</span>
|
||||
{js, v3SourceMap} = CoffeeScript.compile code, options
|
||||
<span class="string">"<span class="subst">#{js}</span>\n//@ sourceMappingURL=data:application/json;base64,<span class="subst">#{btoa unescape encodeURIComponent v3SourceMap}</span>\n//@ sourceURL=coffeescript"</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -217,32 +206,27 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-6">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Activate CoffeeScript in the browser by having it compile and evaluate
|
||||
all script tags with a content-type of <code>text/coffeescript</code>.
|
||||
This happens on page load.
|
||||
|
||||
<p>Load a remote script from the current domain via XHR.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">runScripts = </span><span class="nf">-></span>
|
||||
<span class="nv">scripts = </span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span> <span class="s">'script'</span>
|
||||
<span class="nv">coffeetypes = </span><span class="p">[</span><span class="s">'text/coffeescript'</span><span class="p">,</span> <span class="s">'text/literate-coffeescript'</span><span class="p">]</span>
|
||||
<span class="nv">coffees = </span><span class="p">(</span><span class="nx">s</span> <span class="k">for</span> <span class="nx">s</span> <span class="k">in</span> <span class="nx">scripts</span> <span class="k">when</span> <span class="nx">s</span><span class="p">.</span><span class="nx">type</span> <span class="k">in</span> <span class="nx">coffeetypes</span><span class="p">)</span>
|
||||
<span class="nv">index = </span><span class="mi">0</span>
|
||||
<span class="nv">length = </span><span class="nx">coffees</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nx">do</span> <span class="nv">execute = </span><span class="nf">-></span>
|
||||
<span class="nv">script = </span><span class="nx">coffees</span><span class="p">[</span><span class="nx">index</span><span class="o">++</span><span class="p">]</span>
|
||||
<span class="nv">mediatype = </span><span class="nx">script</span><span class="o">?</span><span class="p">.</span><span class="nx">type</span>
|
||||
<span class="k">if</span> <span class="nx">mediatype</span> <span class="k">in</span> <span class="nx">coffeetypes</span>
|
||||
<span class="nv">options = </span><span class="p">{</span><span class="nv">literate: </span><span class="nx">mediatype</span> <span class="o">is</span> <span class="s">'text/literate-coffeescript'</span><span class="p">}</span>
|
||||
<span class="k">if</span> <span class="nx">script</span><span class="p">.</span><span class="nx">src</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">load</span> <span class="nx">script</span><span class="p">.</span><span class="nx">src</span><span class="p">,</span> <span class="nx">execute</span><span class="p">,</span> <span class="nx">options</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">script</span><span class="p">.</span><span class="nx">innerHTML</span><span class="p">,</span> <span class="nx">options</span>
|
||||
<span class="nx">execute</span><span class="p">()</span>
|
||||
<span class="kc">null</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>CoffeeScript.<span class="function"><span class="title">load</span></span> = (url, callback, options = {}) ->
|
||||
options.sourceFiles = [url]
|
||||
xhr = <span class="keyword">if</span> window.ActiveXObject
|
||||
<span class="keyword">new</span> window.ActiveXObject(<span class="string">'Microsoft.XMLHTTP'</span>)
|
||||
<span class="keyword">else</span>
|
||||
<span class="keyword">new</span> window.XMLHttpRequest()
|
||||
xhr.open <span class="string">'GET'</span>, url, <span class="literal">true</span>
|
||||
xhr.overrideMimeType <span class="string">'text/plain'</span> <span class="keyword">if</span> <span class="string">'overrideMimeType'</span> <span class="keyword">of</span> xhr
|
||||
xhr.<span class="function"><span class="title">onreadystatechange</span></span> = ->
|
||||
<span class="keyword">if</span> xhr.readyState <span class="keyword">is</span> <span class="number">4</span>
|
||||
<span class="keyword">if</span> xhr.status <span class="keyword">in</span> [<span class="number">0</span>, <span class="number">200</span>]
|
||||
CoffeeScript.run xhr.responseText, options
|
||||
<span class="keyword">else</span>
|
||||
<span class="keyword">throw</span> <span class="keyword">new</span> Error <span class="string">"Could not load <span class="subst">#{url}</span>"</span>
|
||||
callback() <span class="keyword">if</span> callback
|
||||
xhr.send <span class="literal">null</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -253,18 +237,50 @@ This happens on page load.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-7">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Listen for window load, both in browsers and in IE.
|
||||
<p>Activate CoffeeScript in the browser by having it compile and evaluate
|
||||
all script tags with a content-type of <code>text/coffeescript</code>.
|
||||
This happens on page load.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="k">if</span> <span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span>
|
||||
<span class="nx">addEventListener</span> <span class="s">'DOMContentLoaded'</span><span class="p">,</span> <span class="nx">runScripts</span><span class="p">,</span> <span class="kc">no</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">attachEvent</span> <span class="s">'onload'</span><span class="p">,</span> <span class="nx">runScripts</span>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">runScripts</span></span> = ->
|
||||
scripts = window.document.getElementsByTagName <span class="string">'script'</span>
|
||||
coffeetypes = [<span class="string">'text/coffeescript'</span>, <span class="string">'text/literate-coffeescript'</span>]
|
||||
coffees = (s <span class="keyword">for</span> s <span class="keyword">in</span> scripts <span class="keyword">when</span> s.type <span class="keyword">in</span> coffeetypes)
|
||||
index = <span class="number">0</span>
|
||||
length = coffees.length
|
||||
<span class="keyword">do</span> <span class="function"><span class="title">execute</span></span> = ->
|
||||
script = coffees[index++]
|
||||
mediatype = script?.type
|
||||
<span class="keyword">if</span> mediatype <span class="keyword">in</span> coffeetypes
|
||||
options = {literate: mediatype <span class="keyword">is</span> <span class="string">'text/literate-coffeescript'</span>}
|
||||
<span class="keyword">if</span> script.src
|
||||
CoffeeScript.load script.src, execute, options
|
||||
<span class="keyword">else</span>
|
||||
options.sourceFiles = [<span class="string">'embedded'</span>]
|
||||
CoffeeScript.run script.innerHTML, options
|
||||
execute()
|
||||
<span class="literal">null</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-8">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-8">¶</a>
|
||||
</div>
|
||||
<p>Listen for window load, both in decent browsers and in IE.
|
||||
</p>
|
||||
|
||||
</pre></div></div>
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="keyword">if</span> window.addEventListener
|
||||
window.addEventListener <span class="string">'DOMContentLoaded'</span>, runScripts, <span class="literal">no</span>
|
||||
<span class="keyword">else</span>
|
||||
window.attachEvent <span class="string">'onload'</span>, runScripts</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
|
||||
|
||||
<a class="source" href="sourcemap.html">
|
||||
sourcemap.coffee
|
||||
sourcemap.litcoffee
|
||||
</a>
|
||||
|
||||
</div>
|
||||
@@ -116,22 +116,10 @@ and can call them from the command line, or invoke them from other tasks.
|
||||
</p>
|
||||
<p>Running <code>cake</code> with no arguments will print out a list of all the tasks in the
|
||||
current directory's Cakefile.
|
||||
|
||||
</p>
|
||||
<p>External dependencies.
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">fs = </span><span class="nx">require</span> <span class="s">'fs'</span>
|
||||
<span class="nv">path = </span><span class="nx">require</span> <span class="s">'path'</span>
|
||||
<span class="nv">helpers = </span><span class="nx">require</span> <span class="s">'./helpers'</span>
|
||||
<span class="nv">optparse = </span><span class="nx">require</span> <span class="s">'./optparse'</span>
|
||||
<span class="nv">CoffeeScript = </span><span class="nx">require</span> <span class="s">'./coffee-script'</span>
|
||||
|
||||
<span class="nv">existsSync = </span><span class="nx">fs</span><span class="p">.</span><span class="nx">existsSync</span> <span class="o">or</span> <span class="nx">path</span><span class="p">.</span><span class="nx">existsSync</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -141,17 +129,18 @@ current directory's Cakefile.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-2">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Keep track of the list of defined tasks, the accepted options, and so on.
|
||||
|
||||
<p>External dependencies.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">tasks = </span><span class="p">{}</span>
|
||||
<span class="nv">options = </span><span class="p">{}</span>
|
||||
<span class="nv">switches = </span><span class="p">[]</span>
|
||||
<span class="nv">oparse = </span><span class="kc">null</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>fs = require <span class="string">'fs'</span>
|
||||
path = require <span class="string">'path'</span>
|
||||
helpers = require <span class="string">'./helpers'</span>
|
||||
optparse = require <span class="string">'./optparse'</span>
|
||||
CoffeeScript = require <span class="string">'./coffee-script'</span>
|
||||
|
||||
existsSync = fs.existsSync <span class="keyword">or</span> path.existsSync</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -162,14 +151,15 @@ current directory's Cakefile.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-3">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Mixin the top-level Cake functions for Cakefiles to use directly.
|
||||
|
||||
<p>Keep track of the list of defined tasks, the accepted options, and so on.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nx">helpers</span><span class="p">.</span><span class="nx">extend</span> <span class="nx">global</span><span class="p">,</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>tasks = {}
|
||||
options = {}
|
||||
switches = []
|
||||
oparse = <span class="literal">null</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -180,17 +170,12 @@ current directory's Cakefile.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-4">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Define a Cake task with a short name, an optional sentence description,
|
||||
and the function to run as the action itself.
|
||||
|
||||
<p>Mixin the top-level Cake functions for Cakefiles to use directly.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">task: </span><span class="nf">(name, description, action) -></span>
|
||||
<span class="p">[</span><span class="nx">action</span><span class="p">,</span> <span class="nx">description</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nx">description</span><span class="p">,</span> <span class="nx">action</span><span class="p">]</span> <span class="k">unless</span> <span class="nx">action</span>
|
||||
<span class="nx">tasks</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="nx">name</span><span class="p">,</span> <span class="nx">description</span><span class="p">,</span> <span class="nx">action</span><span class="p">}</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>helpers.extend global,</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -201,17 +186,15 @@ and the function to run as the action itself.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-5">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Define an option that the Cakefile accepts. The parsed options hash,
|
||||
containing all of the command-line options passed, will be made available
|
||||
as the first argument to the action.
|
||||
|
||||
<p>Define a Cake task with a short name, an optional sentence description,
|
||||
and the function to run as the action itself.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">option: </span><span class="nf">(letter, flag, description) -></span>
|
||||
<span class="nx">switches</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="nx">letter</span><span class="p">,</span> <span class="nx">flag</span><span class="p">,</span> <span class="nx">description</span><span class="p">]</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> task: (name, description, action) ->
|
||||
[action, description] = [description, action] <span class="keyword">unless</span> action
|
||||
tasks[name] = {name, description, action}</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -222,16 +205,15 @@ as the first argument to the action.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-6">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Invoke another task in the current Cakefile.
|
||||
|
||||
<p>Define an option that the Cakefile accepts. The parsed options hash,
|
||||
containing all of the command-line options passed, will be made available
|
||||
as the first argument to the action.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">invoke: </span><span class="nf">(name) -></span>
|
||||
<span class="nx">missingTask</span> <span class="nx">name</span> <span class="k">unless</span> <span class="nx">tasks</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span>
|
||||
<span class="nx">tasks</span><span class="p">[</span><span class="nx">name</span><span class="p">].</span><span class="nx">action</span> <span class="nx">options</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> option: (letter, flag, description) ->
|
||||
switches.push [letter, flag, description]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -242,28 +224,14 @@ as the first argument to the action.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-7">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Run <code>cake</code>. Executes all of the tasks you pass, in order. Note that Node's
|
||||
asynchrony may cause tasks to execute in a different order than you'd expect.
|
||||
If no tasks are passed, print the help screen. Keep a reference to the
|
||||
original directory name, when running Cake tasks from subdirectories.
|
||||
|
||||
<p>Invoke another task in the current Cakefile.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.run = </span><span class="nf">-></span>
|
||||
<span class="nv">global.__originalDirname = </span><span class="nx">fs</span><span class="p">.</span><span class="nx">realpathSync</span> <span class="s">'.'</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">chdir</span> <span class="nx">cakefileDirectory</span> <span class="nx">__originalDirname</span>
|
||||
<span class="nv">args = </span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">..]</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">readFileSync</span><span class="p">(</span><span class="s">'Cakefile'</span><span class="p">).</span><span class="nx">toString</span><span class="p">(),</span> <span class="nv">filename: </span><span class="s">'Cakefile'</span>
|
||||
<span class="nv">oparse = </span><span class="k">new</span> <span class="nx">optparse</span><span class="p">.</span><span class="nx">OptionParser</span> <span class="nx">switches</span>
|
||||
<span class="k">return</span> <span class="nx">printTasks</span><span class="p">()</span> <span class="k">unless</span> <span class="nx">args</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">try</span>
|
||||
<span class="nv">options = </span><span class="nx">oparse</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">args</span><span class="p">)</span>
|
||||
<span class="k">catch</span> <span class="nx">e</span>
|
||||
<span class="k">return</span> <span class="nx">fatalError</span> <span class="s">"</span><span class="si">#{</span><span class="nx">e</span><span class="si">}</span><span class="s">"</span>
|
||||
<span class="nx">invoke</span> <span class="nx">arg</span> <span class="k">for</span> <span class="nx">arg</span> <span class="k">in</span> <span class="nx">options</span><span class="p">.</span><span class="nx">arguments</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> invoke: (name) ->
|
||||
missingTask name <span class="keyword">unless</span> tasks[name]
|
||||
tasks[name].action options</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -274,23 +242,26 @@ original directory name, when running Cake tasks from subdirectories.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-8">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Display the list of Cake tasks in a format similar to <code>rake -T</code>
|
||||
|
||||
<p>Run <code>cake</code>. Executes all of the tasks you pass, in order. Note that Node's
|
||||
asynchrony may cause tasks to execute in a different order than you'd expect.
|
||||
If no tasks are passed, print the help screen. Keep a reference to the
|
||||
original directory name, when running Cake tasks from subdirectories.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">printTasks = </span><span class="nf">-></span>
|
||||
<span class="nv">relative = </span><span class="nx">path</span><span class="p">.</span><span class="nx">relative</span> <span class="o">or</span> <span class="nx">path</span><span class="p">.</span><span class="nx">resolve</span>
|
||||
<span class="nv">cakefilePath = </span><span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">relative</span><span class="p">(</span><span class="nx">__originalDirname</span><span class="p">,</span> <span class="nx">process</span><span class="p">.</span><span class="nx">cwd</span><span class="p">()),</span> <span class="s">'Cakefile'</span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="s">"</span><span class="si">#{</span><span class="nx">cakefilePath</span><span class="si">}</span><span class="s"> defines the following tasks:\n"</span>
|
||||
<span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">task</span> <span class="k">of</span> <span class="nx">tasks</span>
|
||||
<span class="nv">spaces = </span><span class="mi">20</span> <span class="o">-</span> <span class="nx">name</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">spaces = </span><span class="k">if</span> <span class="nx">spaces</span> <span class="o">></span> <span class="mi">0</span> <span class="k">then</span> <span class="nb">Array</span><span class="p">(</span><span class="nx">spaces</span> <span class="o">+</span> <span class="mi">1</span><span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s">' '</span><span class="p">)</span> <span class="k">else</span> <span class="s">''</span>
|
||||
<span class="nv">desc = </span><span class="k">if</span> <span class="nx">task</span><span class="p">.</span><span class="nx">description</span> <span class="k">then</span> <span class="s">"</span><span class="err">#</span><span class="s"> </span><span class="si">#{</span><span class="nx">task</span><span class="p">.</span><span class="nx">description</span><span class="si">}</span><span class="s">"</span> <span class="k">else</span> <span class="s">''</span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="s">"cake </span><span class="si">#{</span><span class="nx">name</span><span class="si">}#{</span><span class="nx">spaces</span><span class="si">}</span><span class="s"> </span><span class="si">#{</span><span class="nx">desc</span><span class="si">}</span><span class="s">"</span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="nx">oparse</span><span class="p">.</span><span class="nx">help</span><span class="p">()</span> <span class="k">if</span> <span class="nx">switches</span><span class="p">.</span><span class="nx">length</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">run</span></span> = ->
|
||||
global.__originalDirname = fs.realpathSync <span class="string">'.'</span>
|
||||
process.chdir cakefileDirectory __originalDirname
|
||||
args = process.argv[<span class="number">2.</span>.]
|
||||
CoffeeScript.run fs.readFileSync(<span class="string">'Cakefile'</span>).toString(), filename: <span class="string">'Cakefile'</span>
|
||||
oparse = <span class="keyword">new</span> optparse.OptionParser switches
|
||||
<span class="keyword">return</span> printTasks() <span class="keyword">unless</span> args.length
|
||||
<span class="keyword">try</span>
|
||||
options = oparse.parse(args)
|
||||
<span class="keyword">catch</span> e
|
||||
<span class="keyword">return</span> fatalError <span class="string">"<span class="subst">#{e}</span>"</span>
|
||||
invoke arg <span class="keyword">for</span> arg <span class="keyword">in</span> options.arguments</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -301,19 +272,21 @@ original directory name, when running Cake tasks from subdirectories.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-9">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Print an error and exit when attempting to use an invalid task/option.
|
||||
|
||||
<p>Display the list of Cake tasks in a format similar to <code>rake -T</code>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">fatalError = </span><span class="nf">(message) -></span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">error</span> <span class="nx">message</span> <span class="o">+</span> <span class="s">'\n'</span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="s">'To see a list of all tasks/options, run "cake"'</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">1</span>
|
||||
|
||||
<span class="nv">missingTask = </span><span class="nf">(task) -></span> <span class="nx">fatalError</span> <span class="s">"No such task: </span><span class="si">#{</span><span class="nx">task</span><span class="si">}</span><span class="s">"</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">printTasks</span></span> = ->
|
||||
relative = path.relative <span class="keyword">or</span> path.resolve
|
||||
cakefilePath = path.join relative(__originalDirname, process.cwd()), <span class="string">'Cakefile'</span>
|
||||
console.log <span class="string">"<span class="subst">#{cakefilePath}</span> defines the following tasks:\n"</span>
|
||||
<span class="keyword">for</span> name, task <span class="keyword">of</span> tasks
|
||||
spaces = <span class="number">20</span> - name.length
|
||||
spaces = <span class="keyword">if</span> spaces > <span class="number">0</span> <span class="keyword">then</span> Array(spaces + <span class="number">1</span>).join(<span class="string">' '</span>) <span class="keyword">else</span> <span class="string">''</span>
|
||||
desc = <span class="keyword">if</span> task.description <span class="keyword">then</span> <span class="string">"# <span class="subst">#{task.description}</span>"</span> <span class="keyword">else</span> <span class="string">''</span>
|
||||
console.log <span class="string">"cake <span class="subst">#{name}</span><span class="subst">#{spaces}</span> <span class="subst">#{desc}</span>"</span>
|
||||
console.log oparse.help() <span class="keyword">if</span> switches.length</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -324,20 +297,38 @@ original directory name, when running Cake tasks from subdirectories.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-10">¶</a>
|
||||
</div>
|
||||
<p>Print an error and exit when attempting to use an invalid task/option.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">fatalError</span></span> = (message) ->
|
||||
console.error message + <span class="string">'\n'</span>
|
||||
console.log <span class="string">'To see a list of all tasks/options, run "cake"'</span>
|
||||
process.exit <span class="number">1</span>
|
||||
|
||||
<span class="function"><span class="title">missingTask</span></span> = (task) -> fatalError <span class="string">"No such task: <span class="subst">#{task}</span>"</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-11">
|
||||
<div class="annotation">
|
||||
|
||||
<p>When <code>cake</code> is invoked, search in the current and all parent directories
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
</div>
|
||||
<p>When <code>cake</code> is invoked, search in the current and all parent directories
|
||||
to find the relevant Cakefile.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">cakefileDirectory = </span><span class="nf">(dir) -></span>
|
||||
<span class="k">return</span> <span class="nx">dir</span> <span class="k">if</span> <span class="nx">existsSync</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">dir</span><span class="p">,</span> <span class="s">'Cakefile'</span>
|
||||
<span class="nv">parent = </span><span class="nx">path</span><span class="p">.</span><span class="nx">normalize</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">dir</span><span class="p">,</span> <span class="s">'..'</span>
|
||||
<span class="k">return</span> <span class="nx">cakefileDirectory</span> <span class="nx">parent</span> <span class="k">unless</span> <span class="nx">parent</span> <span class="o">is</span> <span class="nx">dir</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s">"Cakefile not found in </span><span class="si">#{</span><span class="nx">process</span><span class="p">.</span><span class="nx">cwd</span><span class="p">()</span><span class="si">}</span><span class="s">"</span>
|
||||
|
||||
</pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">cakefileDirectory</span></span> = (dir) ->
|
||||
<span class="keyword">return</span> dir <span class="keyword">if</span> existsSync path.join dir, <span class="string">'Cakefile'</span>
|
||||
parent = path.normalize path.join dir, <span class="string">'..'</span>
|
||||
<span class="keyword">return</span> cakefileDirectory parent <span class="keyword">unless</span> parent <span class="keyword">is</span> dir
|
||||
<span class="keyword">throw</span> <span class="keyword">new</span> Error <span class="string">"Cakefile not found in <span class="subst">#{process.cwd()}</span>"</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
|
||||
|
||||
<a class="source" href="sourcemap.html">
|
||||
sourcemap.coffee
|
||||
sourcemap.litcoffee
|
||||
</a>
|
||||
|
||||
</div>
|
||||
@@ -109,26 +109,22 @@
|
||||
<a class="pilcrow" href="#section-1">¶</a>
|
||||
</div>
|
||||
<p>CoffeeScript can be used both on the server, as a command-line compiler based
|
||||
on Node.js/V8, or to run CoffeeScripts directly in the browser. This module
|
||||
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.
|
||||
|
||||
</p>
|
||||
<p>If included on a webpage, it will automatically sniff out, compile, and
|
||||
execute all scripts present in <code>text/coffeescript</code> tags.
|
||||
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">fs = </span><span class="nx">require</span> <span class="s">'fs'</span>
|
||||
<span class="nv">path = </span><span class="nx">require</span> <span class="s">'path'</span>
|
||||
<span class="p">{</span><span class="nx">Lexer</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s">'./lexer'</span>
|
||||
<span class="p">{</span><span class="nx">parser</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s">'./parser'</span>
|
||||
<span class="nv">helpers = </span><span class="nx">require</span> <span class="s">'./helpers'</span>
|
||||
<span class="nv">vm = </span><span class="nx">require</span> <span class="s">'vm'</span>
|
||||
<span class="nv">sourcemap = </span><span class="nx">require</span> <span class="s">'./sourcemap'</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
fs = require <span class="string">'fs'</span>
|
||||
vm = require <span class="string">'vm'</span>
|
||||
path = require <span class="string">'path'</span>
|
||||
child_process = require <span class="string">'child_process'</span>
|
||||
{Lexer} = require <span class="string">'./lexer'</span>
|
||||
{parser} = require <span class="string">'./parser'</span>
|
||||
helpers = require <span class="string">'./helpers'</span>
|
||||
SourceMap = require <span class="string">'./sourcemap'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -139,21 +135,12 @@ execute all scripts present in <code>text/coffeescript</code> tags.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-2">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Load and run a CoffeeScript file for Node, stripping any <code>BOM</code>s.
|
||||
|
||||
<p>The current CoffeeScript version number.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">loadFile = </span><span class="nf">(module, filename) -></span>
|
||||
<span class="nv">raw = </span><span class="nx">fs</span><span class="p">.</span><span class="nx">readFileSync</span> <span class="nx">filename</span><span class="p">,</span> <span class="s">'utf8'</span>
|
||||
<span class="nv">stripped = </span><span class="k">if</span> <span class="nx">raw</span><span class="p">.</span><span class="nx">charCodeAt</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">is</span> <span class="mh">0xFEFF</span> <span class="k">then</span> <span class="nx">raw</span><span class="p">.</span><span class="nx">substring</span> <span class="mi">1</span> <span class="k">else</span> <span class="nx">raw</span>
|
||||
<span class="nx">module</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">compile</span><span class="p">(</span><span class="nx">stripped</span><span class="p">,</span> <span class="p">{</span><span class="nx">filename</span><span class="p">,</span> <span class="nv">literate: </span><span class="nx">helpers</span><span class="p">.</span><span class="nx">isLiterate</span> <span class="nx">filename</span><span class="p">}),</span> <span class="nx">filename</span>
|
||||
|
||||
<span class="k">if</span> <span class="nx">require</span><span class="p">.</span><span class="nx">extensions</span>
|
||||
<span class="k">for</span> <span class="nx">ext</span> <span class="k">in</span> <span class="p">[</span><span class="s">'.coffee'</span><span class="p">,</span> <span class="s">'.litcoffee'</span><span class="p">,</span> <span class="s">'.md'</span><span class="p">,</span> <span class="s">'.coffee.md'</span><span class="p">]</span>
|
||||
<span class="nx">require</span><span class="p">.</span><span class="nx">extensions</span><span class="p">[</span><span class="nx">ext</span><span class="p">]</span> <span class="o">=</span> <span class="nx">loadFile</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.VERSION = <span class="string">'1.6.3'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -164,14 +151,12 @@ execute all scripts present in <code>text/coffeescript</code> tags.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-3">¶</a>
|
||||
</div>
|
||||
|
||||
<p>The current CoffeeScript version number.
|
||||
|
||||
<p>Expose helpers for testing.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.VERSION = </span><span class="s">'1.6.1'</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.helpers = helpers</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -182,14 +167,35 @@ execute all scripts present in <code>text/coffeescript</code> tags.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-4">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Expose helpers for testing.
|
||||
<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 be passed here.
|
||||
|
||||
</p>
|
||||
<p>This returns a javascript string, unless <code>options.sourceMap</code> is passed,
|
||||
in which case this returns a <code>{js, v3SourceMap, sourceMap}</code>
|
||||
object, where sourceMap is a sourcemap.coffee#SourceMap object, handy for doing programatic
|
||||
lookups.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.helpers = </span><span class="nx">helpers</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.compile = <span class="function"><span class="title">compile</span></span> = (code, options = {}) ->
|
||||
{merge} = helpers
|
||||
|
||||
<span class="keyword">if</span> options.sourceMap
|
||||
map = <span class="keyword">new</span> SourceMap
|
||||
|
||||
fragments = parser.parse(lexer.tokenize code, options).compileToFragments options
|
||||
|
||||
currentLine = <span class="number">0</span>
|
||||
currentLine += <span class="number">1</span> <span class="keyword">if</span> options.header
|
||||
currentLine += <span class="number">1</span> <span class="keyword">if</span> options.shiftLine
|
||||
currentColumn = <span class="number">0</span>
|
||||
js = <span class="string">""</span>
|
||||
<span class="keyword">for</span> fragment <span class="keyword">in</span> fragments</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -200,39 +206,20 @@ execute all scripts present in <code>text/coffeescript</code> tags.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-5">¶</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.
|
||||
|
||||
</p>
|
||||
<p>This returns a javascript string, unless <code>options.sourceMap</code> is passed,
|
||||
in which case this returns a `{js, v3SourceMap, sourceMap}
|
||||
object, where sourceMap is a sourcemap.coffee#SourceMap object, handy for doing programatic
|
||||
lookups.
|
||||
|
||||
<p>Update the sourcemap with data from each fragment
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.compile = compile = </span><span class="nf">(code, options = {}) -></span>
|
||||
<span class="p">{</span><span class="nx">merge</span><span class="p">}</span> <span class="o">=</span> <span class="nx">exports</span><span class="p">.</span><span class="nx">helpers</span>
|
||||
<span class="k">try</span>
|
||||
|
||||
<span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">sourceMap</span>
|
||||
<span class="nv">coffeeFile = </span><span class="nx">helpers</span><span class="p">.</span><span class="nx">baseFileName</span> <span class="nx">options</span><span class="p">.</span><span class="nx">filename</span>
|
||||
<span class="nv">jsFile = </span><span class="nx">helpers</span><span class="p">.</span><span class="nx">baseFileName</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span><span class="p">,</span> <span class="kc">yes</span><span class="p">)</span> <span class="o">+</span> <span class="s">".js"</span>
|
||||
<span class="nv">sourceMap = </span><span class="k">new</span> <span class="nx">sourcemap</span><span class="p">.</span><span class="nx">SourceMap</span><span class="p">()</span>
|
||||
|
||||
<span class="nv">fragments = </span><span class="p">(</span><span class="nx">parser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">lexer</span><span class="p">.</span><span class="nx">tokenize</span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">)).</span><span class="nx">compileToFragments</span> <span class="nx">options</span>
|
||||
|
||||
<span class="nv">currentLine = </span><span class="mi">0</span>
|
||||
<span class="nx">currentLine</span> <span class="o">+=</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">header</span>
|
||||
<span class="nx">currentLine</span> <span class="o">+=</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">sourceMap</span>
|
||||
<span class="nv">currentColumn = </span><span class="mi">0</span>
|
||||
<span class="nv">js = </span><span class="s">""</span>
|
||||
<span class="k">for</span> <span class="nx">fragment</span> <span class="k">in</span> <span class="nx">fragments</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> options.sourceMap
|
||||
<span class="keyword">if</span> fragment.locationData
|
||||
map.add(
|
||||
[fragment.locationData.first_line, fragment.locationData.first_column]
|
||||
[currentLine, currentColumn]
|
||||
{noReplace: <span class="literal">true</span>})
|
||||
newLines = helpers.count fragment.code, <span class="string">"\n"</span>
|
||||
currentLine += newLines
|
||||
currentColumn = fragment.code.length - (<span class="keyword">if</span> newLines <span class="keyword">then</span> fragment.code.lastIndexOf <span class="string">"\n"</span> <span class="keyword">else</span> <span class="number">0</span>)</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -243,22 +230,24 @@ lookups.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-6">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Update the sourcemap with data from each fragment
|
||||
|
||||
<p>Copy the code from each fragment into the final JavaScript.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="k">if</span> <span class="nx">sourceMap</span>
|
||||
<span class="k">if</span> <span class="nx">fragment</span><span class="p">.</span><span class="nx">locationData</span>
|
||||
<span class="nx">sourceMap</span><span class="p">.</span><span class="nx">addMapping</span><span class="p">(</span>
|
||||
<span class="p">[</span><span class="nx">fragment</span><span class="p">.</span><span class="nx">locationData</span><span class="p">.</span><span class="nx">first_line</span><span class="p">,</span> <span class="nx">fragment</span><span class="p">.</span><span class="nx">locationData</span><span class="p">.</span><span class="nx">first_column</span><span class="p">],</span>
|
||||
<span class="p">[</span><span class="nx">currentLine</span><span class="p">,</span> <span class="nx">currentColumn</span><span class="p">],</span>
|
||||
<span class="p">{</span><span class="nv">noReplace: </span><span class="kc">true</span><span class="p">})</span>
|
||||
<span class="nv">newLines = </span><span class="nx">helpers</span><span class="p">.</span><span class="nx">count</span> <span class="nx">fragment</span><span class="p">.</span><span class="nx">code</span><span class="p">,</span> <span class="s">"\n"</span>
|
||||
<span class="nx">currentLine</span> <span class="o">+=</span> <span class="nx">newLines</span>
|
||||
<span class="nv">currentColumn = </span><span class="nx">fragment</span><span class="p">.</span><span class="nx">code</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="p">(</span><span class="k">if</span> <span class="nx">newLines</span> <span class="k">then</span> <span class="nx">fragment</span><span class="p">.</span><span class="nx">code</span><span class="p">.</span><span class="nx">lastIndexOf</span> <span class="s">"\n"</span> <span class="k">else</span> <span class="mi">0</span><span class="p">)</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> js += fragment.code
|
||||
|
||||
<span class="keyword">if</span> options.header
|
||||
header = <span class="string">"Generated by CoffeeScript <span class="subst">#{@VERSION}</span>"</span>
|
||||
js = <span class="string">"// <span class="subst">#{header}</span>\n<span class="subst">#{js}</span>"</span>
|
||||
|
||||
<span class="keyword">if</span> options.sourceMap
|
||||
answer = {js}
|
||||
answer.sourceMap = map
|
||||
answer.v3SourceMap = map.generate(options, code)
|
||||
answer
|
||||
<span class="keyword">else</span>
|
||||
js</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -269,31 +258,13 @@ lookups.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-7">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Copy the code from each fragment into the final JavaScript.
|
||||
|
||||
<p>Tokenize a string of CoffeeScript code, and return the array of tokens.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nx">js</span> <span class="o">+=</span> <span class="nx">fragment</span><span class="p">.</span><span class="nx">code</span>
|
||||
|
||||
<span class="k">catch</span> <span class="nx">err</span>
|
||||
<span class="nv">err.message = </span><span class="s">"In </span><span class="si">#{</span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span><span class="si">}</span><span class="s">, </span><span class="si">#{</span><span class="nx">err</span><span class="p">.</span><span class="nx">message</span><span class="si">}</span><span class="s">"</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">filename</span>
|
||||
<span class="k">throw</span> <span class="nx">err</span>
|
||||
|
||||
<span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">header</span>
|
||||
<span class="nv">header = </span><span class="s">"Generated by CoffeeScript </span><span class="si">#{</span><span class="nx">@VERSION</span><span class="si">}</span><span class="s">"</span>
|
||||
<span class="nv">js = </span><span class="s">"// </span><span class="si">#{</span><span class="nx">header</span><span class="si">}</span><span class="s">\n</span><span class="si">#{</span><span class="nx">js</span><span class="si">}</span><span class="s">"</span>
|
||||
|
||||
<span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">sourceMap</span>
|
||||
<span class="nv">answer = </span><span class="p">{</span><span class="nx">js</span><span class="p">}</span>
|
||||
<span class="k">if</span> <span class="nx">sourceMap</span>
|
||||
<span class="nv">answer.sourceMap = </span><span class="nx">sourceMap</span>
|
||||
<span class="nv">answer.v3SourceMap = </span><span class="nx">sourcemap</span><span class="p">.</span><span class="nx">generateV3SourceMap</span> <span class="nx">sourceMap</span><span class="p">,</span> <span class="nx">coffeeFile</span><span class="p">,</span> <span class="nx">jsFile</span>
|
||||
<span class="nx">answer</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">js</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">tokens</span></span> = (code, options) ->
|
||||
lexer.tokenize code, options</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -304,15 +275,18 @@ lookups.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-8">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Tokenize a string of CoffeeScript code, and return the array of tokens.
|
||||
|
||||
<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,
|
||||
or traverse it by using <code>.traverseChildren()</code> with a callback.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.tokens = </span><span class="nf">(code, options) -></span>
|
||||
<span class="nx">lexer</span><span class="p">.</span><span class="nx">tokenize</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">options</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">nodes</span></span> = (source, options) ->
|
||||
<span class="keyword">if</span> <span class="keyword">typeof</span> source <span class="keyword">is</span> <span class="string">'string'</span>
|
||||
parser.parse lexer.tokenize source, options
|
||||
<span class="keyword">else</span>
|
||||
parser.parse source</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -323,20 +297,15 @@ lookups.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-9">¶</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,
|
||||
or traverse it by using <code>.traverseChildren()</code> with a callback.
|
||||
|
||||
<p>Compile and execute a string of CoffeeScript (on the server), correctly
|
||||
setting <code>__filename</code>, <code>__dirname</code>, and relative <code>require()</code>.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.nodes = </span><span class="nf">(source, options) -></span>
|
||||
<span class="k">if</span> <span class="k">typeof</span> <span class="nx">source</span> <span class="o">is</span> <span class="s">'string'</span>
|
||||
<span class="nx">parser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">lexer</span><span class="p">.</span><span class="nx">tokenize</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">options</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">parser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">source</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">run</span></span> = (code, options = {}) ->
|
||||
mainModule = require.main
|
||||
options.sourceMap ?= <span class="literal">true</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -347,16 +316,13 @@ or traverse it by using <code>.traverseChildren()</code> with a callback.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-10">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Compile and execute a string of CoffeeScript (on the server), correctly
|
||||
setting <code>__filename</code>, <code>__dirname</code>, and relative <code>require()</code>.
|
||||
|
||||
<p>Set the filename.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.run = </span><span class="nf">(code, options = {}) -></span>
|
||||
<span class="nv">mainModule = </span><span class="nx">require</span><span class="p">.</span><span class="nx">main</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> mainModule.filename = process.argv[<span class="number">1</span>] =
|
||||
<span class="keyword">if</span> options.filename <span class="keyword">then</span> fs.realpathSync(options.filename) <span class="keyword">else</span> <span class="string">'.'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -367,15 +333,12 @@ setting <code>__filename</code>, <code>__dirname</code>, and relative <code>requ
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Set the filename.
|
||||
|
||||
<p>Clear the module cache.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">mainModule.filename = </span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span>
|
||||
<span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">filename</span> <span class="k">then</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">realpathSync</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span><span class="p">)</span> <span class="k">else</span> <span class="s">'.'</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> mainModule.moduleCache <span class="keyword">and</span>= {}</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -386,14 +349,12 @@ setting <code>__filename</code>, <code>__dirname</code>, and relative <code>requ
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-12">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Clear the module cache.
|
||||
|
||||
<p>Assign paths for node_modules loading
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nx">mainModule</span><span class="p">.</span><span class="nx">moduleCache</span> <span class="o">and=</span> <span class="p">{}</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> mainModule.paths = require(<span class="string">'module'</span>)._nodeModulePaths path.dirname fs.realpathSync options.filename <span class="keyword">or</span> <span class="string">'.'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -404,14 +365,13 @@ setting <code>__filename</code>, <code>__dirname</code>, and relative <code>requ
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-13">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Assign paths for node_modules loading
|
||||
|
||||
<p>Compile.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">mainModule.paths = </span><span class="nx">require</span><span class="p">(</span><span class="s">'module'</span><span class="p">).</span><span class="nx">_nodeModulePaths</span> <span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">realpathSync</span> <span class="nx">options</span><span class="p">.</span><span class="nx">filename</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> <span class="keyword">not</span> helpers.isCoffee(mainModule.filename) <span class="keyword">or</span> require.extensions
|
||||
answer = compile(code, options)</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -422,17 +382,17 @@ setting <code>__filename</code>, <code>__dirname</code>, and relative <code>requ
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-14">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Compile.
|
||||
|
||||
<p>Attach sourceMap object to sourceMaps[options.filename] so that
|
||||
it is accessible by Error.prepareStackTrace.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="k">if</span> <span class="o">not</span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">isCoffee</span><span class="p">(</span><span class="nx">mainModule</span><span class="p">.</span><span class="nx">filename</span><span class="p">)</span> <span class="o">or</span> <span class="nx">require</span><span class="p">.</span><span class="nx">extensions</span>
|
||||
<span class="nx">mainModule</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">compile</span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">),</span> <span class="nx">mainModule</span><span class="p">.</span><span class="nx">filename</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">mainModule</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">mainModule</span><span class="p">.</span><span class="nx">filename</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> <span class="keyword">do</span> patchStackTrace
|
||||
sourceMaps[mainModule.filename] = answer.sourceMap
|
||||
mainModule._compile answer.js, mainModule.filename
|
||||
<span class="keyword">else</span>
|
||||
mainModule._compile code, mainModule.filename</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -443,29 +403,27 @@ setting <code>__filename</code>, <code>__dirname</code>, and relative <code>requ
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-15">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
|
||||
<p>Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
|
||||
The CoffeeScript REPL uses this to run the input.
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.eval = </span><span class="nf">(code, options = {}) -></span>
|
||||
<span class="k">return</span> <span class="k">unless</span> <span class="nv">code = </span><span class="nx">code</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span>
|
||||
<span class="nv">Script = </span><span class="nx">vm</span><span class="p">.</span><span class="nx">Script</span>
|
||||
<span class="k">if</span> <span class="nx">Script</span>
|
||||
<span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">sandbox</span><span class="o">?</span>
|
||||
<span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">sandbox</span> <span class="k">instanceof</span> <span class="nx">Script</span><span class="p">.</span><span class="nx">createContext</span><span class="p">().</span><span class="nx">constructor</span>
|
||||
<span class="nv">sandbox = </span><span class="nx">options</span><span class="p">.</span><span class="nx">sandbox</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">sandbox = </span><span class="nx">Script</span><span class="p">.</span><span class="nx">createContext</span><span class="p">()</span>
|
||||
<span class="nx">sandbox</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span> <span class="k">for</span> <span class="k">own</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">options</span><span class="p">.</span><span class="nx">sandbox</span>
|
||||
<span class="nv">sandbox.global = sandbox.root = sandbox.GLOBAL = </span><span class="nx">sandbox</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">sandbox = </span><span class="nx">global</span>
|
||||
<span class="nv">sandbox.__filename = </span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span> <span class="o">||</span> <span class="s">'eval'</span>
|
||||
<span class="nv">sandbox.__dirname = </span><span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">sandbox</span><span class="p">.</span><span class="nx">__filename</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">eval</span></span> = (code, options = {}) ->
|
||||
<span class="keyword">return</span> <span class="keyword">unless</span> code = code.trim()
|
||||
Script = vm.Script
|
||||
<span class="keyword">if</span> Script
|
||||
<span class="keyword">if</span> options.sandbox?
|
||||
<span class="keyword">if</span> options.sandbox <span class="keyword">instanceof</span> Script.createContext().constructor
|
||||
sandbox = options.sandbox
|
||||
<span class="keyword">else</span>
|
||||
sandbox = Script.createContext()
|
||||
sandbox[k] = v <span class="keyword">for</span> own k, v <span class="keyword">of</span> options.sandbox
|
||||
sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox
|
||||
<span class="keyword">else</span>
|
||||
sandbox = global
|
||||
sandbox.__filename = options.filename || <span class="string">'eval'</span>
|
||||
sandbox.__dirname = path.dirname sandbox.__filename</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -476,19 +434,17 @@ The CoffeeScript REPL uses this to run the input.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-16">¶</a>
|
||||
</div>
|
||||
|
||||
<p>define module/require only if they chose not to specify their own
|
||||
|
||||
<p>define module/require only if they chose not to specify their own
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="k">unless</span> <span class="nx">sandbox</span> <span class="o">isnt</span> <span class="nx">global</span> <span class="o">or</span> <span class="nx">sandbox</span><span class="p">.</span><span class="nx">module</span> <span class="o">or</span> <span class="nx">sandbox</span><span class="p">.</span><span class="nx">require</span>
|
||||
<span class="nv">Module = </span><span class="nx">require</span> <span class="s">'module'</span>
|
||||
<span class="nv">sandbox.module = _module = </span><span class="k">new</span> <span class="nx">Module</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">modulename</span> <span class="o">||</span> <span class="s">'eval'</span><span class="p">)</span>
|
||||
<span class="nv">sandbox.require = _require = </span><span class="nf">(path) -></span> <span class="nx">Module</span><span class="p">.</span><span class="nx">_load</span> <span class="nx">path</span><span class="p">,</span> <span class="nx">_module</span><span class="p">,</span> <span class="kc">true</span>
|
||||
<span class="nv">_module.filename = </span><span class="nx">sandbox</span><span class="p">.</span><span class="nx">__filename</span>
|
||||
<span class="nx">_require</span><span class="p">[</span><span class="nx">r</span><span class="p">]</span> <span class="o">=</span> <span class="nx">require</span><span class="p">[</span><span class="nx">r</span><span class="p">]</span> <span class="k">for</span> <span class="nx">r</span> <span class="k">in</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">getOwnPropertyNames</span> <span class="nx">require</span> <span class="k">when</span> <span class="nx">r</span> <span class="o">isnt</span> <span class="s">'paths'</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> <span class="keyword">unless</span> sandbox <span class="keyword">isnt</span> global <span class="keyword">or</span> sandbox.module <span class="keyword">or</span> sandbox.require
|
||||
Module = require <span class="string">'module'</span>
|
||||
sandbox.module = _module = <span class="keyword">new</span> Module(options.modulename || <span class="string">'eval'</span>)
|
||||
sandbox.require = <span class="function"><span class="title">_require</span></span> = (path) -> Module._load path, _module, <span class="literal">true</span>
|
||||
_module.filename = sandbox.__filename
|
||||
_require[r] = require[r] <span class="keyword">for</span> r <span class="keyword">in</span> Object.getOwnPropertyNames require <span class="keyword">when</span> r <span class="keyword">isnt</span> <span class="string">'paths'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -499,23 +455,21 @@ The CoffeeScript REPL uses this to run the input.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
</div>
|
||||
|
||||
<p>use the same hack node currently uses for their own REPL
|
||||
|
||||
<p>use the same hack node currently uses for their own REPL
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">_require.paths = _module.paths = </span><span class="nx">Module</span><span class="p">.</span><span class="nx">_nodeModulePaths</span> <span class="nx">process</span><span class="p">.</span><span class="nx">cwd</span><span class="p">()</span>
|
||||
<span class="nv">_require.resolve = </span><span class="nf">(request) -></span> <span class="nx">Module</span><span class="p">.</span><span class="nx">_resolveFilename</span> <span class="nx">request</span><span class="p">,</span> <span class="nx">_module</span>
|
||||
<span class="nv">o = </span><span class="p">{}</span>
|
||||
<span class="nx">o</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span> <span class="k">for</span> <span class="k">own</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">options</span>
|
||||
<span class="nv">o.bare = </span><span class="kc">on</span> <span class="c1"># ensure return value</span>
|
||||
<span class="nv">js = </span><span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">o</span>
|
||||
<span class="k">if</span> <span class="nx">sandbox</span> <span class="o">is</span> <span class="nx">global</span>
|
||||
<span class="nx">vm</span><span class="p">.</span><span class="nx">runInThisContext</span> <span class="nx">js</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">vm</span><span class="p">.</span><span class="nx">runInContext</span> <span class="nx">js</span><span class="p">,</span> <span class="nx">sandbox</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> _require.paths = _module.paths = Module._nodeModulePaths process.cwd()
|
||||
_require.<span class="function"><span class="title">resolve</span></span> = (request) -> Module._resolveFilename request, _module
|
||||
o = {}
|
||||
o[k] = v <span class="keyword">for</span> own k, v <span class="keyword">of</span> options
|
||||
o.bare = <span class="literal">on</span> <span class="comment"># ensure return value</span>
|
||||
js = compile code, o
|
||||
<span class="keyword">if</span> sandbox <span class="keyword">is</span> global
|
||||
vm.runInThisContext js
|
||||
<span class="keyword">else</span>
|
||||
vm.runInContext js, sandbox</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -526,14 +480,17 @@ The CoffeeScript REPL uses this to run the input.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-18">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Instantiate a Lexer for our use here.
|
||||
|
||||
<p>Load and run a CoffeeScript file for Node, stripping any <code>BOM</code>s.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">lexer = </span><span class="k">new</span> <span class="nx">Lexer</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">loadFile</span></span> = (module, filename) ->
|
||||
raw = fs.readFileSync filename, <span class="string">'utf8'</span>
|
||||
stripped = <span class="keyword">if</span> raw.charCodeAt(<span class="number">0</span>) <span class="keyword">is</span> <span class="number">0xFEFF</span> <span class="keyword">then</span> raw.substring <span class="number">1</span> <span class="keyword">else</span> raw
|
||||
answer = compile(stripped, {filename, sourceMap: <span class="literal">true</span>, literate: helpers.isLiterate filename})
|
||||
sourceMaps[filename] = answer.sourceMap
|
||||
module._compile answer.js, filename</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -544,32 +501,370 @@ The CoffeeScript REPL uses this to run the input.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-19">¶</a>
|
||||
</div>
|
||||
<p>If the installed version of Node supports <code>require.extensions</code>, register
|
||||
CoffeeScript as an extension.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="keyword">if</span> require.extensions
|
||||
<span class="keyword">for</span> ext <span class="keyword">in</span> [<span class="string">'.coffee'</span>, <span class="string">'.litcoffee'</span>, <span class="string">'.coffee.md'</span>]
|
||||
require.extensions[ext] = loadFile</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-20">
|
||||
<div class="annotation">
|
||||
|
||||
<p>The real Lexer produces a generic stream of tokens. This object provides a
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-20">¶</a>
|
||||
</div>
|
||||
<p>Patch Node's module loader to be able to handle mult-dot extensions.
|
||||
This is a horrible thing that should not be required. Perhaps, one day,
|
||||
when a truly benevolent dictator comes to rule over the Republik of Node,
|
||||
it won't be.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> Module = require <span class="string">'module'</span>
|
||||
|
||||
<span class="function"><span class="title">findExtension</span></span> = (filename) ->
|
||||
extensions = path.basename(filename).split <span class="string">'.'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-21">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-21">¶</a>
|
||||
</div>
|
||||
<p>Remove the initial dot from dotfiles.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> extensions.shift() <span class="keyword">if</span> extensions[<span class="number">0</span>] <span class="keyword">is</span> <span class="string">''</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-22">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-22">¶</a>
|
||||
</div>
|
||||
<p>Start with the longest possible extension and work our way shortwards.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="keyword">while</span> extensions.shift()
|
||||
curExtension = <span class="string">'.'</span> + extensions.join <span class="string">'.'</span>
|
||||
<span class="keyword">return</span> curExtension <span class="keyword">if</span> Module._extensions[curExtension]
|
||||
<span class="string">'.js'</span>
|
||||
|
||||
Module::<span class="function"><span class="title">load</span></span> = (filename) ->
|
||||
<span class="property">@filename</span> = filename
|
||||
<span class="property">@paths</span> = Module._nodeModulePaths path.dirname filename
|
||||
extension = findExtension filename
|
||||
Module._extensions[extension](<span class="keyword">this</span>, filename)
|
||||
<span class="property">@loaded</span> = <span class="literal">true</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-23">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-23">¶</a>
|
||||
</div>
|
||||
<p>If we're on Node, patch <code>child_process.fork</code> so that Coffee scripts are able
|
||||
to fork both CoffeeScript files, and JavaScript files, directly.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="keyword">if</span> child_process
|
||||
{fork} = child_process
|
||||
child_process.<span class="function"><span class="title">fork</span></span> = (path, args = [], options = {}) ->
|
||||
execPath = <span class="keyword">if</span> helpers.isCoffee(path) <span class="keyword">then</span> <span class="string">'coffee'</span> <span class="keyword">else</span> <span class="literal">null</span>
|
||||
<span class="keyword">if</span> <span class="keyword">not</span> Array.isArray args
|
||||
args = []
|
||||
options = args <span class="keyword">or</span> {}
|
||||
options.execPath <span class="keyword">or</span>= execPath
|
||||
fork path, args, options</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-24">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-24">¶</a>
|
||||
</div>
|
||||
<p>Instantiate a Lexer for our use here.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>lexer = <span class="keyword">new</span> Lexer</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-25">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-25">¶</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
|
||||
directly as a "Jison lexer".
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">parser.lexer =</span>
|
||||
<span class="nv">lex: </span><span class="nf">-></span>
|
||||
<span class="nv">token = </span><span class="nx">@tokens</span><span class="p">[</span><span class="nx">@pos</span><span class="o">++</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="nx">token</span>
|
||||
<span class="p">[</span><span class="nx">tag</span><span class="p">,</span> <span class="nx">@yytext</span><span class="p">,</span> <span class="nx">@yylloc</span><span class="p">]</span> <span class="o">=</span> <span class="nx">token</span>
|
||||
<span class="vi">@yylineno = </span><span class="nx">@yylloc</span><span class="p">.</span><span class="nx">first_line</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">tag = </span><span class="s">''</span>
|
||||
<div class="content"><div class='highlight'><pre>parser.lexer =
|
||||
lex: ->
|
||||
token = <span class="property">@tokens</span>[<span class="property">@pos</span>++]
|
||||
<span class="keyword">if</span> token
|
||||
[tag, <span class="property">@yytext</span>, <span class="property">@yylloc</span>] = token
|
||||
<span class="property">@yylineno</span> = <span class="property">@yylloc</span>.first_line
|
||||
<span class="keyword">else</span>
|
||||
tag = <span class="string">''</span>
|
||||
|
||||
<span class="nx">tag</span>
|
||||
<span class="nv">setInput: </span><span class="nf">(@tokens) -></span>
|
||||
<span class="vi">@pos = </span><span class="mi">0</span>
|
||||
<span class="nv">upcomingInput: </span><span class="nf">-></span>
|
||||
<span class="s">""</span>
|
||||
tag
|
||||
setInput: (<span class="property">@tokens</span>) ->
|
||||
<span class="property">@pos</span> = <span class="number">0</span>
|
||||
upcomingInput: ->
|
||||
<span class="string">""</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-26">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-26">¶</a>
|
||||
</div>
|
||||
<p>Make all the AST nodes visible to the parser.
|
||||
</p>
|
||||
|
||||
<span class="nv">parser.yy = </span><span class="nx">require</span> <span class="s">'./nodes'</span>
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>parser.yy = require <span class="string">'./nodes'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-27">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-27">¶</a>
|
||||
</div>
|
||||
<p>Override Jison's default error handling function.
|
||||
</p>
|
||||
|
||||
</pre></div></div>
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>parser.yy.<span class="function"><span class="title">parseError</span></span> = (message, {token}) -></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-28">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-28">¶</a>
|
||||
</div>
|
||||
<p>Disregard Jison's message, it contains redundant line numer information.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> message = <span class="string">"unexpected <span class="subst">#{<span class="keyword">if</span> token <span class="keyword">is</span> <span class="number">1</span> <span class="keyword">then</span> 'end <span class="keyword">of</span> input' <span class="keyword">else</span> token}</span>"</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-29">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-29">¶</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>
|
||||
(from the previous token), so we take the location information directly
|
||||
from the lexer.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> helpers.throwSyntaxError message, parser.lexer.yylloc</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-30">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-30">¶</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
|
||||
sourceMap, so we must monkey-patch Error to display CoffeeScript source
|
||||
positions.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
patched = <span class="literal">false</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-31">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-31">¶</a>
|
||||
</div>
|
||||
<p>Map of filenames -> sourceMap object.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>sourceMaps = {}
|
||||
|
||||
<span class="function"><span class="title">patchStackTrace</span></span> = ->
|
||||
<span class="keyword">return</span> <span class="keyword">if</span> patched
|
||||
patched = <span class="literal">true</span>
|
||||
mainModule = require.main</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-32">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-32">¶</a>
|
||||
</div>
|
||||
<p>(Assigning to a property of the Module object in the normal module cache is
|
||||
unsuitable, because node deletes those objects from the cache if an
|
||||
exception is thrown in the module body.)
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
Error.<span class="function"><span class="title">prepareStackTrace</span></span> = (err, stack) ->
|
||||
sourceFiles = {}
|
||||
|
||||
<span class="function"><span class="title">getSourceMapping</span></span> = (filename, line, column) ->
|
||||
sourceMap = sourceMaps[filename]
|
||||
answer = sourceMap.sourceLocation [line - <span class="number">1</span>, column - <span class="number">1</span>] <span class="keyword">if</span> sourceMap
|
||||
<span class="keyword">if</span> answer <span class="keyword">then</span> [answer[<span class="number">0</span>] + <span class="number">1</span>, answer[<span class="number">1</span>] + <span class="number">1</span>] <span class="keyword">else</span> <span class="literal">null</span>
|
||||
|
||||
frames = <span class="keyword">for</span> frame <span class="keyword">in</span> stack
|
||||
<span class="keyword">break</span> <span class="keyword">if</span> frame.getFunction() <span class="keyword">is</span> exports.run
|
||||
<span class="string">" at <span class="subst">#{formatSourcePosition frame, getSourceMapping}</span>"</span>
|
||||
|
||||
<span class="string">"<span class="subst">#{err.name}</span>: <span class="subst">#{err.message ? ''}</span>\n<span class="subst">#{frames.join '\n'}</span>\n"</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-33">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-33">¶</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>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">formatSourcePosition</span></span> = (frame, getSourceMapping) ->
|
||||
fileName = <span class="literal">undefined</span>
|
||||
fileLocation = <span class="string">''</span>
|
||||
|
||||
<span class="keyword">if</span> frame.isNative()
|
||||
fileLocation = <span class="string">"native"</span>
|
||||
<span class="keyword">else</span>
|
||||
<span class="keyword">if</span> frame.isEval()
|
||||
fileName = frame.getScriptNameOrSourceURL()
|
||||
fileLocation = <span class="string">"<span class="subst">#{frame.getEvalOrigin()}</span>, "</span> <span class="keyword">unless</span> fileName
|
||||
<span class="keyword">else</span>
|
||||
fileName = frame.getFileName()
|
||||
|
||||
fileName <span class="keyword">or</span>= <span class="string">"<anonymous>"</span>
|
||||
|
||||
line = frame.getLineNumber()
|
||||
column = frame.getColumnNumber()</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-34">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-34">¶</a>
|
||||
</div>
|
||||
<p>Check for a sourceMap position
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> source = getSourceMapping fileName, line, column
|
||||
fileLocation =
|
||||
<span class="keyword">if</span> source
|
||||
<span class="string">"<span class="subst">#{fileName}</span>:<span class="subst">#{source[<span class="number">0</span>]}</span>:<span class="subst">#{source[<span class="number">1</span>]}</span>, <js>:<span class="subst">#{line}</span>:<span class="subst">#{column}</span>"</span>
|
||||
<span class="keyword">else</span>
|
||||
<span class="string">"<span class="subst">#{fileName}</span>:<span class="subst">#{line}</span>:<span class="subst">#{column}</span>"</span>
|
||||
|
||||
|
||||
functionName = frame.getFunctionName()
|
||||
isConstructor = frame.isConstructor()
|
||||
isMethodCall = <span class="keyword">not</span> (frame.isToplevel() <span class="keyword">or</span> isConstructor)
|
||||
|
||||
<span class="keyword">if</span> isMethodCall
|
||||
methodName = frame.getMethodName()
|
||||
typeName = frame.getTypeName()
|
||||
|
||||
<span class="keyword">if</span> functionName
|
||||
tp = as = <span class="string">''</span>
|
||||
<span class="keyword">if</span> typeName <span class="keyword">and</span> functionName.indexOf typeName
|
||||
tp = <span class="string">"<span class="subst">#{typeName}</span>."</span>
|
||||
<span class="keyword">if</span> methodName <span class="keyword">and</span> functionName.indexOf(<span class="string">".<span class="subst">#{methodName}</span>"</span>) <span class="keyword">isnt</span> functionName.length - methodName.length - <span class="number">1</span>
|
||||
as = <span class="string">" [as <span class="subst">#{methodName}</span>]"</span>
|
||||
|
||||
<span class="string">"<span class="subst">#{tp}</span><span class="subst">#{functionName}</span><span class="subst">#{as}</span> (<span class="subst">#{fileLocation}</span>)"</span>
|
||||
<span class="keyword">else</span>
|
||||
<span class="string">"<span class="subst">#{typeName}</span>.<span class="subst">#{methodName <span class="keyword">or</span> '<anonymous>'}</span> (<span class="subst">#{fileLocation}</span>)"</span>
|
||||
<span class="keyword">else</span> <span class="keyword">if</span> isConstructor
|
||||
<span class="string">"new <span class="subst">#{functionName <span class="keyword">or</span> '<anonymous>'}</span> (<span class="subst">#{fileLocation}</span>)"</span>
|
||||
<span class="keyword">else</span> <span class="keyword">if</span> functionName
|
||||
<span class="string">"<span class="subst">#{functionName}</span> (<span class="subst">#{fileLocation}</span>)"</span>
|
||||
<span class="keyword">else</span>
|
||||
fileLocation</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
|
||||
|
||||
<a class="source" href="sourcemap.html">
|
||||
sourcemap.coffee
|
||||
sourcemap.litcoffee
|
||||
</a>
|
||||
|
||||
</div>
|
||||
@@ -109,28 +109,14 @@
|
||||
<a class="pilcrow" href="#section-1">¶</a>
|
||||
</div>
|
||||
<p>The <code>coffee</code> utility. Handles command-line compilation of CoffeeScript
|
||||
into various forms: saved into <code>.js</code> files or printed to stdout, piped to
|
||||
<a href="http://javascriptlint.com/">JavaScript Lint</a> or recompiled every time the source is
|
||||
saved, printed as a token stream or as the syntax tree, or launch an
|
||||
into various forms: saved into <code>.js</code> files or printed to stdout
|
||||
or recompiled every time the source is saved,
|
||||
printed as a token stream or as the syntax tree, or launch an
|
||||
interactive REPL.
|
||||
|
||||
</p>
|
||||
<p>External dependencies.
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">fs = </span><span class="nx">require</span> <span class="s">'fs'</span>
|
||||
<span class="nv">path = </span><span class="nx">require</span> <span class="s">'path'</span>
|
||||
<span class="nv">helpers = </span><span class="nx">require</span> <span class="s">'./helpers'</span>
|
||||
<span class="nv">optparse = </span><span class="nx">require</span> <span class="s">'./optparse'</span>
|
||||
<span class="nv">CoffeeScript = </span><span class="nx">require</span> <span class="s">'./coffee-script'</span>
|
||||
<span class="p">{</span><span class="nx">spawn</span><span class="p">,</span> <span class="nx">exec</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s">'child_process'</span>
|
||||
<span class="p">{</span><span class="nx">EventEmitter</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s">'events'</span>
|
||||
|
||||
<span class="nv">exists = </span><span class="nx">fs</span><span class="p">.</span><span class="nx">exists</span> <span class="o">or</span> <span class="nx">path</span><span class="p">.</span><span class="nx">exists</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -140,19 +126,21 @@ interactive REPL.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-2">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Allow CoffeeScript to emit Node.js events.
|
||||
|
||||
<p>External dependencies.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nx">helpers</span><span class="p">.</span><span class="nx">extend</span> <span class="nx">CoffeeScript</span><span class="p">,</span> <span class="k">new</span> <span class="nx">EventEmitter</span>
|
||||
<div class="content"><div class='highlight'><pre>fs = require <span class="string">'fs'</span>
|
||||
path = require <span class="string">'path'</span>
|
||||
helpers = require <span class="string">'./helpers'</span>
|
||||
optparse = require <span class="string">'./optparse'</span>
|
||||
CoffeeScript = require <span class="string">'./coffee-script'</span>
|
||||
{spawn, exec} = require <span class="string">'child_process'</span>
|
||||
{EventEmitter} = require <span class="string">'events'</span>
|
||||
|
||||
<span class="nv">printLine = </span><span class="nf">(line) -></span> <span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span> <span class="nx">line</span> <span class="o">+</span> <span class="s">'\n'</span>
|
||||
<span class="nv">printWarn = </span><span class="nf">(line) -></span> <span class="nx">process</span><span class="p">.</span><span class="nx">stderr</span><span class="p">.</span><span class="nx">write</span> <span class="nx">line</span> <span class="o">+</span> <span class="s">'\n'</span>
|
||||
|
||||
<span class="nv">hidden = </span><span class="nf">(file) -></span> <span class="o">/^</span><span class="err">\</span><span class="p">.</span><span class="o">|~</span><span class="nx">$</span><span class="o">/</span><span class="p">.</span><span class="nx">test</span> <span class="nx">file</span></pre></div></div>
|
||||
exists = fs.exists <span class="keyword">or</span> path.exists
|
||||
useWinPathSep = path.sep <span class="keyword">is</span> <span class="string">'\\'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -163,18 +151,17 @@ interactive REPL.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-3">¶</a>
|
||||
</div>
|
||||
|
||||
<p>The help banner that is printed when <code>coffee</code> is called without arguments.
|
||||
|
||||
<p>Allow CoffeeScript to emit Node.js events.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">BANNER = </span><span class="s">'''</span>
|
||||
<span class="s"> Usage: coffee [options] path/to/script.coffee -- [args]</span>
|
||||
<div class="content"><div class='highlight'><pre>helpers.extend CoffeeScript, <span class="keyword">new</span> EventEmitter
|
||||
|
||||
<span class="s"> If called without options, `coffee` will run your script.</span>
|
||||
<span class="s">'''</span></pre></div></div>
|
||||
<span class="function"><span class="title">printLine</span></span> = (line) -> process.stdout.write line + <span class="string">'\n'</span>
|
||||
<span class="function"><span class="title">printWarn</span></span> = (line) -> process.stderr.write line + <span class="string">'\n'</span>
|
||||
|
||||
<span class="function"><span class="title">hidden</span></span> = (file) -> <span class="regexp">/^\.|~$/</span>.test file</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -185,31 +172,16 @@ interactive REPL.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-4">¶</a>
|
||||
</div>
|
||||
|
||||
<p>The list of all the valid option flags that <code>coffee</code> knows how to handle.
|
||||
|
||||
<p>The help banner that is printed when <code>coffee</code> is called without arguments.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">SWITCHES = </span><span class="p">[</span>
|
||||
<span class="p">[</span><span class="s">'-b'</span><span class="p">,</span> <span class="s">'--bare'</span><span class="p">,</span> <span class="s">'compile without a top-level function wrapper'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s">'-c'</span><span class="p">,</span> <span class="s">'--compile'</span><span class="p">,</span> <span class="s">'compile to JavaScript and save as .js files'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s">'-e'</span><span class="p">,</span> <span class="s">'--eval'</span><span class="p">,</span> <span class="s">'pass a string from the command line as input'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s">'-h'</span><span class="p">,</span> <span class="s">'--help'</span><span class="p">,</span> <span class="s">'display this help message'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s">'-i'</span><span class="p">,</span> <span class="s">'--interactive'</span><span class="p">,</span> <span class="s">'run an interactive CoffeeScript REPL'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s">'-j'</span><span class="p">,</span> <span class="s">'--join [FILE]'</span><span class="p">,</span> <span class="s">'concatenate the source CoffeeScript before compiling'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s">'-l'</span><span class="p">,</span> <span class="s">'--lint'</span><span class="p">,</span> <span class="s">'pipe the compiled JavaScript through JavaScript Lint'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s">'-m'</span><span class="p">,</span> <span class="s">'--map'</span><span class="p">,</span> <span class="s">'generate source map and save as .map files'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s">'-n'</span><span class="p">,</span> <span class="s">'--nodes'</span><span class="p">,</span> <span class="s">'print out the parse tree that the parser produces'</span><span class="p">]</span>
|
||||
<span class="p">[</span> <span class="s">'--nodejs [ARGS]'</span><span class="p">,</span> <span class="s">'pass options directly to the "node" binary'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s">'-o'</span><span class="p">,</span> <span class="s">'--output [DIR]'</span><span class="p">,</span> <span class="s">'set the output directory for compiled JavaScript'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s">'-p'</span><span class="p">,</span> <span class="s">'--print'</span><span class="p">,</span> <span class="s">'print out the compiled JavaScript'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s">'-s'</span><span class="p">,</span> <span class="s">'--stdio'</span><span class="p">,</span> <span class="s">'listen for and compile scripts over stdio'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s">'-t'</span><span class="p">,</span> <span class="s">'--tokens'</span><span class="p">,</span> <span class="s">'print out the tokens that the lexer/rewriter produce'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s">'-v'</span><span class="p">,</span> <span class="s">'--version'</span><span class="p">,</span> <span class="s">'display the version number'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s">'-w'</span><span class="p">,</span> <span class="s">'--watch'</span><span class="p">,</span> <span class="s">'watch scripts for changes and rerun commands'</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>BANNER = '''
|
||||
Usage: coffee [options] path/to/script.coffee -- [args]
|
||||
|
||||
If called without options, `coffee` will run your script.
|
||||
'''</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -220,19 +192,29 @@ interactive REPL.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-5">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Top-level objects shared by all the functions.
|
||||
|
||||
<p>The list of all the valid option flags that <code>coffee</code> knows how to handle.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">opts = </span><span class="p">{}</span>
|
||||
<span class="nv">sources = </span><span class="p">[]</span>
|
||||
<span class="nv">sourceCode = </span><span class="p">[]</span>
|
||||
<span class="nv">notSources = </span><span class="p">{}</span>
|
||||
<span class="nv">watchers = </span><span class="p">{}</span>
|
||||
<span class="nv">optionParser = </span><span class="kc">null</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>SWITCHES = [
|
||||
[<span class="string">'-b'</span>, <span class="string">'--bare'</span>, <span class="string">'compile without a top-level function wrapper'</span>]
|
||||
[<span class="string">'-c'</span>, <span class="string">'--compile'</span>, <span class="string">'compile to JavaScript and save as .js files'</span>]
|
||||
[<span class="string">'-e'</span>, <span class="string">'--eval'</span>, <span class="string">'pass a string from the command line as input'</span>]
|
||||
[<span class="string">'-h'</span>, <span class="string">'--help'</span>, <span class="string">'display this help message'</span>]
|
||||
[<span class="string">'-i'</span>, <span class="string">'--interactive'</span>, <span class="string">'run an interactive CoffeeScript REPL'</span>]
|
||||
[<span class="string">'-j'</span>, <span class="string">'--join [FILE]'</span>, <span class="string">'concatenate the source CoffeeScript before compiling'</span>]
|
||||
[<span class="string">'-m'</span>, <span class="string">'--map'</span>, <span class="string">'generate source map and save as .map files'</span>]
|
||||
[<span class="string">'-n'</span>, <span class="string">'--nodes'</span>, <span class="string">'print out the parse tree that the parser produces'</span>]
|
||||
[ <span class="string">'--nodejs [ARGS]'</span>, <span class="string">'pass options directly to the "node" binary'</span>]
|
||||
[<span class="string">'-o'</span>, <span class="string">'--output [DIR]'</span>, <span class="string">'set the output directory for compiled JavaScript'</span>]
|
||||
[<span class="string">'-p'</span>, <span class="string">'--print'</span>, <span class="string">'print out the compiled JavaScript'</span>]
|
||||
[<span class="string">'-s'</span>, <span class="string">'--stdio'</span>, <span class="string">'listen for and compile scripts over stdio'</span>]
|
||||
[<span class="string">'-l'</span>, <span class="string">'--literate'</span>, <span class="string">'treat stdio as literate style coffee-script'</span>]
|
||||
[<span class="string">'-t'</span>, <span class="string">'--tokens'</span>, <span class="string">'print out the tokens that the lexer/rewriter produce'</span>]
|
||||
[<span class="string">'-v'</span>, <span class="string">'--version'</span>, <span class="string">'display the version number'</span>]
|
||||
[<span class="string">'-w'</span>, <span class="string">'--watch'</span>, <span class="string">'watch scripts for changes and rerun commands'</span>]
|
||||
]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -243,31 +225,17 @@ interactive REPL.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-6">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Run <code>coffee</code> by parsing passed options and determining what action to take.
|
||||
Many flags cause us to divert before compiling anything. Flags passed after
|
||||
<code>--</code> will be passed verbatim to your script as arguments in <code>process.argv</code>
|
||||
|
||||
<p>Top-level objects shared by all the functions.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.run = </span><span class="nf">-></span>
|
||||
<span class="nx">parseOptions</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="nx">forkNode</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">nodejs</span>
|
||||
<span class="k">return</span> <span class="nx">usage</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">help</span>
|
||||
<span class="k">return</span> <span class="nx">version</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">version</span>
|
||||
<span class="k">return</span> <span class="nx">require</span><span class="p">(</span><span class="s">'./repl'</span><span class="p">).</span><span class="nx">start</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">interactive</span>
|
||||
<span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">watch</span> <span class="o">and</span> <span class="o">!</span><span class="nx">fs</span><span class="p">.</span><span class="nx">watch</span>
|
||||
<span class="k">return</span> <span class="nx">printWarn</span> <span class="s">"The --watch feature depends on Node v0.6.0+. You are running </span><span class="si">#{</span><span class="nx">process</span><span class="p">.</span><span class="nx">version</span><span class="si">}</span><span class="s">."</span>
|
||||
<span class="k">return</span> <span class="nx">compileStdio</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">stdio</span>
|
||||
<span class="k">return</span> <span class="nx">compileScript</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">sources</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nb">eval</span>
|
||||
<span class="k">return</span> <span class="nx">require</span><span class="p">(</span><span class="s">'./repl'</span><span class="p">).</span><span class="nx">start</span><span class="p">()</span> <span class="k">unless</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">literals = </span><span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">run</span> <span class="k">then</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">splice</span> <span class="mi">1</span> <span class="k">else</span> <span class="p">[]</span>
|
||||
<span class="nv">process.argv = </span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">..</span><span class="mi">1</span><span class="p">].</span><span class="nx">concat</span> <span class="nx">literals</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="s">'coffee'</span>
|
||||
<span class="k">for</span> <span class="nx">source</span> <span class="k">in</span> <span class="nx">sources</span>
|
||||
<span class="nx">compilePath</span> <span class="nx">source</span><span class="p">,</span> <span class="kc">yes</span><span class="p">,</span> <span class="nx">path</span><span class="p">.</span><span class="nx">normalize</span> <span class="nx">source</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>opts = {}
|
||||
sources = []
|
||||
sourceCode = []
|
||||
notSources = {}
|
||||
watchers = {}
|
||||
optionParser = <span class="literal">null</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -278,41 +246,29 @@ Many flags cause us to divert before compiling anything. Flags passed after
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-7">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Compile a path, which could be a script or a directory. If a directory
|
||||
is passed, recursively compile all '.coffee', '.litcoffee', and '.coffee.md'
|
||||
extension source files in it and all subdirectories.
|
||||
|
||||
<p>Run <code>coffee</code> by parsing passed options and determining what action to take.
|
||||
Many flags cause us to divert before compiling anything. Flags passed after
|
||||
<code>--</code> will be passed verbatim to your script as arguments in <code>process.argv</code>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">compilePath = </span><span class="nf">(source, topLevel, base) -></span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">stat</span> <span class="nx">source</span><span class="p">,</span> <span class="nf">(err, stats) -></span>
|
||||
<span class="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</span> <span class="o">and</span> <span class="nx">err</span><span class="p">.</span><span class="nx">code</span> <span class="o">isnt</span> <span class="s">'ENOENT'</span>
|
||||
<span class="k">if</span> <span class="nx">err</span><span class="o">?</span><span class="p">.</span><span class="nx">code</span> <span class="o">is</span> <span class="s">'ENOENT'</span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">error</span> <span class="s">"File not found: </span><span class="si">#{</span><span class="nx">source</span><span class="si">}</span><span class="s">"</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">1</span>
|
||||
<span class="k">if</span> <span class="nx">stats</span><span class="p">.</span><span class="nx">isDirectory</span><span class="p">()</span> <span class="o">and</span> <span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span><span class="p">(</span><span class="nx">source</span><span class="p">)</span> <span class="o">isnt</span> <span class="s">'node_modules'</span>
|
||||
<span class="nx">watchDir</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">base</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">watch</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">readdir</span> <span class="nx">source</span><span class="p">,</span> <span class="nf">(err, files) -></span>
|
||||
<span class="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</span> <span class="o">and</span> <span class="nx">err</span><span class="p">.</span><span class="nx">code</span> <span class="o">isnt</span> <span class="s">'ENOENT'</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">err</span><span class="o">?</span><span class="p">.</span><span class="nx">code</span> <span class="o">is</span> <span class="s">'ENOENT'</span>
|
||||
<span class="nv">index = </span><span class="nx">sources</span><span class="p">.</span><span class="nx">indexOf</span> <span class="nx">source</span>
|
||||
<span class="nv">files = </span><span class="nx">files</span><span class="p">.</span><span class="nx">filter</span> <span class="nf">(file) -></span> <span class="o">not</span> <span class="nx">hidden</span> <span class="nx">file</span>
|
||||
<span class="nx">sources</span><span class="p">[</span><span class="nx">index</span><span class="p">..</span><span class="nx">index</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">file</span> <span class="k">for</span> <span class="nx">file</span> <span class="k">in</span> <span class="nx">files</span><span class="p">)</span>
|
||||
<span class="nx">sourceCode</span><span class="p">[</span><span class="nx">index</span><span class="p">..</span><span class="nx">index</span><span class="p">]</span> <span class="o">=</span> <span class="nx">files</span><span class="p">.</span><span class="nx">map</span> <span class="nf">-></span> <span class="kc">null</span>
|
||||
<span class="nx">files</span><span class="p">.</span><span class="nx">forEach</span> <span class="nf">(file) -></span>
|
||||
<span class="nx">compilePath</span> <span class="p">(</span><span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">file</span><span class="p">),</span> <span class="kc">no</span><span class="p">,</span> <span class="nx">base</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">topLevel</span> <span class="o">or</span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">isCoffee</span> <span class="nx">source</span>
|
||||
<span class="nx">watch</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">base</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">watch</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span> <span class="nx">source</span><span class="p">,</span> <span class="nf">(err, code) -></span>
|
||||
<span class="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</span> <span class="o">and</span> <span class="nx">err</span><span class="p">.</span><span class="nx">code</span> <span class="o">isnt</span> <span class="s">'ENOENT'</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">err</span><span class="o">?</span><span class="p">.</span><span class="nx">code</span> <span class="o">is</span> <span class="s">'ENOENT'</span>
|
||||
<span class="nx">compileScript</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">code</span><span class="p">.</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">base</span><span class="p">)</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">notSources</span><span class="p">[</span><span class="nx">source</span><span class="p">]</span> <span class="o">=</span> <span class="kc">yes</span>
|
||||
<span class="nx">removeSource</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">base</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">run</span></span> = ->
|
||||
parseOptions()
|
||||
<span class="keyword">return</span> forkNode() <span class="keyword">if</span> opts.nodejs
|
||||
<span class="keyword">return</span> usage() <span class="keyword">if</span> opts.help
|
||||
<span class="keyword">return</span> version() <span class="keyword">if</span> opts.version
|
||||
<span class="keyword">return</span> require(<span class="string">'./repl'</span>).start() <span class="keyword">if</span> opts.interactive
|
||||
<span class="keyword">if</span> opts.watch <span class="keyword">and</span> <span class="keyword">not</span> fs.watch
|
||||
<span class="keyword">return</span> printWarn <span class="string">"The --watch feature depends on Node v0.6.0+. You are running <span class="subst">#{process.version}</span>."</span>
|
||||
<span class="keyword">return</span> compileStdio() <span class="keyword">if</span> opts.stdio
|
||||
<span class="keyword">return</span> compileScript <span class="literal">null</span>, sources[<span class="number">0</span>] <span class="keyword">if</span> opts.eval
|
||||
<span class="keyword">return</span> require(<span class="string">'./repl'</span>).start() <span class="keyword">unless</span> sources.length
|
||||
literals = <span class="keyword">if</span> opts.run <span class="keyword">then</span> sources.splice <span class="number">1</span> <span class="keyword">else</span> []
|
||||
process.argv = process.argv[<span class="number">0.</span><span class="number">.1</span>].concat literals
|
||||
process.argv[<span class="number">0</span>] = <span class="string">'coffee'</span>
|
||||
<span class="keyword">for</span> source <span class="keyword">in</span> sources
|
||||
compilePath source, <span class="literal">yes</span>, path.normalize source</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -323,47 +279,39 @@ extension source files in it and all subdirectories.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-8">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Compile a single source script, containing the given code, according to the
|
||||
requested options. If evaluating the script directly sets <code>__filename</code>,
|
||||
<code>__dirname</code> and <code>module.filename</code> to be correct relative to the script's path.
|
||||
|
||||
<p>Compile a path, which could be a script or a directory. If a directory
|
||||
is passed, recursively compile all '.coffee', '.litcoffee', and '.coffee.md'
|
||||
extension source files in it and all subdirectories.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">compileScript = </span><span class="nf">(file, input, base) -></span>
|
||||
<span class="nv">o = </span><span class="nx">opts</span>
|
||||
<span class="nv">options = </span><span class="nx">compileOptions</span> <span class="nx">file</span>
|
||||
<span class="k">try</span>
|
||||
<span class="nv">t = task = </span><span class="p">{</span><span class="nx">file</span><span class="p">,</span> <span class="nx">input</span><span class="p">,</span> <span class="nx">options</span><span class="p">}</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">emit</span> <span class="s">'compile'</span><span class="p">,</span> <span class="nx">task</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">tokens</span> <span class="k">then</span> <span class="nx">printTokens</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">tokens</span> <span class="nx">t</span><span class="p">.</span><span class="nx">input</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">options</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">nodes</span> <span class="k">then</span> <span class="nx">printLine</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">nodes</span><span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">input</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">options</span><span class="p">).</span><span class="nx">toString</span><span class="p">().</span><span class="nx">trim</span><span class="p">()</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">run</span> <span class="k">then</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">t</span><span class="p">.</span><span class="nx">input</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">options</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">join</span> <span class="o">and</span> <span class="nx">t</span><span class="p">.</span><span class="nx">file</span> <span class="o">isnt</span> <span class="nx">o</span><span class="p">.</span><span class="nx">join</span>
|
||||
<span class="nx">sourceCode</span><span class="p">[</span><span class="nx">sources</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">file</span><span class="p">)]</span> <span class="o">=</span> <span class="nx">t</span><span class="p">.</span><span class="nx">input</span>
|
||||
<span class="nx">compileJoin</span><span class="p">()</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">compiled = </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">t</span><span class="p">.</span><span class="nx">input</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">options</span>
|
||||
<span class="nv">t.output = </span><span class="nx">compiled</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">map</span>
|
||||
<span class="nv">t.output = </span><span class="nx">compiled</span><span class="p">.</span><span class="nx">js</span>
|
||||
<span class="nv">t.sourceMap = </span><span class="nx">compiled</span><span class="p">.</span><span class="nx">v3SourceMap</span>
|
||||
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">emit</span> <span class="s">'success'</span><span class="p">,</span> <span class="nx">task</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">print</span>
|
||||
<span class="nx">printLine</span> <span class="nx">t</span><span class="p">.</span><span class="nx">output</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="o">||</span> <span class="nx">o</span><span class="p">.</span><span class="nx">map</span>
|
||||
<span class="nx">writeJs</span> <span class="nx">base</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">file</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">output</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">sourceMap</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">lint</span>
|
||||
<span class="nx">lint</span> <span class="nx">t</span><span class="p">.</span><span class="nx">file</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">output</span>
|
||||
<span class="k">catch</span> <span class="nx">err</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">emit</span> <span class="s">'failure'</span><span class="p">,</span> <span class="nx">err</span><span class="p">,</span> <span class="nx">task</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">listeners</span><span class="p">(</span><span class="s">'failure'</span><span class="p">).</span><span class="nx">length</span>
|
||||
<span class="k">return</span> <span class="nx">printLine</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span> <span class="o">+</span> <span class="s">'\x07'</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">watch</span>
|
||||
<span class="nx">printWarn</span> <span class="nx">err</span> <span class="k">instanceof</span> <span class="nb">Error</span> <span class="o">and</span> <span class="nx">err</span><span class="p">.</span><span class="nx">stack</span> <span class="o">or</span> <span class="s">"ERROR: </span><span class="si">#{</span><span class="nx">err</span><span class="si">}</span><span class="s">"</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">1</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">compilePath</span></span> = (source, topLevel, base) ->
|
||||
fs.stat source, (err, stats) ->
|
||||
<span class="keyword">throw</span> err <span class="keyword">if</span> err <span class="keyword">and</span> err.code <span class="keyword">isnt</span> <span class="string">'ENOENT'</span>
|
||||
<span class="keyword">if</span> err?.code <span class="keyword">is</span> <span class="string">'ENOENT'</span>
|
||||
console.error <span class="string">"File not found: <span class="subst">#{source}</span>"</span>
|
||||
process.exit <span class="number">1</span>
|
||||
<span class="keyword">if</span> stats.isDirectory() <span class="keyword">and</span> path.dirname(source) <span class="keyword">isnt</span> <span class="string">'node_modules'</span>
|
||||
watchDir source, base <span class="keyword">if</span> opts.watch
|
||||
fs.readdir source, (err, files) ->
|
||||
<span class="keyword">throw</span> err <span class="keyword">if</span> err <span class="keyword">and</span> err.code <span class="keyword">isnt</span> <span class="string">'ENOENT'</span>
|
||||
<span class="keyword">return</span> <span class="keyword">if</span> err?.code <span class="keyword">is</span> <span class="string">'ENOENT'</span>
|
||||
index = sources.indexOf source
|
||||
files = files.filter (file) -> <span class="keyword">not</span> hidden file
|
||||
sources[index..index] = (path.join source, file <span class="keyword">for</span> file <span class="keyword">in</span> files)
|
||||
sourceCode[index..index] = files.map -> <span class="literal">null</span>
|
||||
files.forEach (file) ->
|
||||
compilePath (path.join source, file), <span class="literal">no</span>, base
|
||||
<span class="keyword">else</span> <span class="keyword">if</span> topLevel <span class="keyword">or</span> helpers.isCoffee source
|
||||
watch source, base <span class="keyword">if</span> opts.watch
|
||||
fs.readFile source, (err, code) ->
|
||||
<span class="keyword">throw</span> err <span class="keyword">if</span> err <span class="keyword">and</span> err.code <span class="keyword">isnt</span> <span class="string">'ENOENT'</span>
|
||||
<span class="keyword">return</span> <span class="keyword">if</span> err?.code <span class="keyword">is</span> <span class="string">'ENOENT'</span>
|
||||
compileScript(source, code.toString(), base)
|
||||
<span class="keyword">else</span>
|
||||
notSources[source] = <span class="literal">yes</span>
|
||||
removeSource source, base</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -374,21 +322,48 @@ requested options. If evaluating the script directly sets <code>__filename</code
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-9">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Attach the appropriate listeners to compile scripts incoming over <strong>stdin</strong>,
|
||||
and write them back to <strong>stdout</strong>.
|
||||
|
||||
<p>Compile a single source script, containing the given code, according to the
|
||||
requested options. If evaluating the script directly sets <code>__filename</code>,
|
||||
<code>__dirname</code> and <code>module.filename</code> to be correct relative to the script's path.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">compileStdio = </span><span class="nf">-></span>
|
||||
<span class="nv">code = </span><span class="s">''</span>
|
||||
<span class="nv">stdin = </span><span class="nx">process</span><span class="p">.</span><span class="nx">openStdin</span><span class="p">()</span>
|
||||
<span class="nx">stdin</span><span class="p">.</span><span class="nx">on</span> <span class="s">'data'</span><span class="p">,</span> <span class="nf">(buffer) -></span>
|
||||
<span class="nx">code</span> <span class="o">+=</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span> <span class="k">if</span> <span class="nx">buffer</span>
|
||||
<span class="nx">stdin</span><span class="p">.</span><span class="nx">on</span> <span class="s">'end'</span><span class="p">,</span> <span class="nf">-></span>
|
||||
<span class="nx">compileScript</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">code</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">compileScript</span></span> = (file, input, base=<span class="literal">null</span>) ->
|
||||
o = opts
|
||||
options = compileOptions file, base
|
||||
<span class="keyword">try</span>
|
||||
t = task = {file, input, options}
|
||||
CoffeeScript.emit <span class="string">'compile'</span>, task
|
||||
<span class="keyword">if</span> o.tokens <span class="keyword">then</span> printTokens CoffeeScript.tokens t.input, t.options
|
||||
<span class="keyword">else</span> <span class="keyword">if</span> o.nodes <span class="keyword">then</span> printLine CoffeeScript.nodes(t.input, t.options).toString().trim()
|
||||
<span class="keyword">else</span> <span class="keyword">if</span> o.run <span class="keyword">then</span> CoffeeScript.run t.input, t.options
|
||||
<span class="keyword">else</span> <span class="keyword">if</span> o.join <span class="keyword">and</span> t.file <span class="keyword">isnt</span> o.join
|
||||
t.input = helpers.invertLiterate t.input <span class="keyword">if</span> helpers.isLiterate file
|
||||
sourceCode[sources.indexOf(t.file)] = t.input
|
||||
compileJoin()
|
||||
<span class="keyword">else</span>
|
||||
compiled = CoffeeScript.compile t.input, t.options
|
||||
t.output = compiled
|
||||
<span class="keyword">if</span> o.map
|
||||
t.output = compiled.js
|
||||
t.sourceMap = compiled.v3SourceMap
|
||||
|
||||
CoffeeScript.emit <span class="string">'success'</span>, task
|
||||
<span class="keyword">if</span> o.print
|
||||
printLine t.output.trim()
|
||||
<span class="keyword">else</span> <span class="keyword">if</span> o.compile <span class="keyword">or</span> o.map
|
||||
writeJs base, t.file, t.output, options.jsPath, t.sourceMap
|
||||
<span class="keyword">catch</span> err
|
||||
CoffeeScript.emit <span class="string">'failure'</span>, err, task
|
||||
<span class="keyword">return</span> <span class="keyword">if</span> CoffeeScript.listeners(<span class="string">'failure'</span>).length
|
||||
useColors = process.stdout.isTTY <span class="keyword">and</span> <span class="keyword">not</span> process.env.NODE_DISABLE_COLORS
|
||||
message = helpers.prettyErrorMessage err, file <span class="keyword">or</span> <span class="string">'[stdin]'</span>, input, useColors
|
||||
<span class="keyword">if</span> o.watch
|
||||
printLine message + <span class="string">'\x07'</span>
|
||||
<span class="keyword">else</span>
|
||||
printWarn message
|
||||
process.exit <span class="number">1</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -399,21 +374,19 @@ and write them back to <strong>stdout</strong>.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-10">¶</a>
|
||||
</div>
|
||||
|
||||
<p>If all of the source files are done being read, concatenate and compile
|
||||
them together.
|
||||
|
||||
<p>Attach the appropriate listeners to compile scripts incoming over <strong>stdin</strong>,
|
||||
and write them back to <strong>stdout</strong>.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">joinTimeout = </span><span class="kc">null</span>
|
||||
<span class="nv">compileJoin = </span><span class="nf">-></span>
|
||||
<span class="k">return</span> <span class="k">unless</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span>
|
||||
<span class="k">unless</span> <span class="nx">sourceCode</span><span class="p">.</span><span class="nx">some</span><span class="p">(</span><span class="nf">(code) -></span> <span class="nx">code</span> <span class="o">is</span> <span class="kc">null</span><span class="p">)</span>
|
||||
<span class="nx">clearTimeout</span> <span class="nx">joinTimeout</span>
|
||||
<span class="nv">joinTimeout = </span><span class="nx">wait</span> <span class="mi">100</span><span class="p">,</span> <span class="nf">-></span>
|
||||
<span class="nx">compileScript</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span><span class="p">,</span> <span class="nx">sourceCode</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s">'\n'</span><span class="p">),</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">compileStdio</span></span> = ->
|
||||
code = <span class="string">''</span>
|
||||
stdin = process.openStdin()
|
||||
stdin.<span class="literal">on</span> <span class="string">'data'</span>, (buffer) ->
|
||||
code += buffer.toString() <span class="keyword">if</span> buffer
|
||||
stdin.<span class="literal">on</span> <span class="string">'end'</span>, ->
|
||||
compileScript <span class="literal">null</span>, code</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -424,52 +397,19 @@ them together.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Watch a source CoffeeScript file using <code>fs.watch</code>, recompiling it every
|
||||
time the file is updated. May be used in combination with other options,
|
||||
such as <code>--lint</code> or <code>--print</code>.
|
||||
|
||||
<p>If all of the source files are done being read, concatenate and compile
|
||||
them together.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">watch = </span><span class="nf">(source, base) -></span>
|
||||
|
||||
<span class="nv">prevStats = </span><span class="kc">null</span>
|
||||
<span class="nv">compileTimeout = </span><span class="kc">null</span>
|
||||
|
||||
<span class="nv">watchErr = </span><span class="nf">(e) -></span>
|
||||
<span class="k">if</span> <span class="nx">e</span><span class="p">.</span><span class="nx">code</span> <span class="o">is</span> <span class="s">'ENOENT'</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">source</span><span class="p">)</span> <span class="o">is</span> <span class="o">-</span><span class="mi">1</span>
|
||||
<span class="k">try</span>
|
||||
<span class="nx">rewatch</span><span class="p">()</span>
|
||||
<span class="nx">compile</span><span class="p">()</span>
|
||||
<span class="k">catch</span> <span class="nx">e</span>
|
||||
<span class="nx">removeSource</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">base</span><span class="p">,</span> <span class="kc">yes</span>
|
||||
<span class="nx">compileJoin</span><span class="p">()</span>
|
||||
<span class="k">else</span> <span class="k">throw</span> <span class="nx">e</span>
|
||||
|
||||
<span class="nv">compile = </span><span class="nf">-></span>
|
||||
<span class="nx">clearTimeout</span> <span class="nx">compileTimeout</span>
|
||||
<span class="nv">compileTimeout = </span><span class="nx">wait</span> <span class="mi">25</span><span class="p">,</span> <span class="nf">-></span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">stat</span> <span class="nx">source</span><span class="p">,</span> <span class="nf">(err, stats) -></span>
|
||||
<span class="k">return</span> <span class="nx">watchErr</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</span>
|
||||
<span class="k">return</span> <span class="nx">rewatch</span><span class="p">()</span> <span class="k">if</span> <span class="nx">prevStats</span> <span class="o">and</span> <span class="nx">stats</span><span class="p">.</span><span class="nx">size</span> <span class="o">is</span> <span class="nx">prevStats</span><span class="p">.</span><span class="nx">size</span> <span class="o">and</span>
|
||||
<span class="nx">stats</span><span class="p">.</span><span class="nx">mtime</span><span class="p">.</span><span class="nx">getTime</span><span class="p">()</span> <span class="o">is</span> <span class="nx">prevStats</span><span class="p">.</span><span class="nx">mtime</span><span class="p">.</span><span class="nx">getTime</span><span class="p">()</span>
|
||||
<span class="nv">prevStats = </span><span class="nx">stats</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span> <span class="nx">source</span><span class="p">,</span> <span class="nf">(err, code) -></span>
|
||||
<span class="k">return</span> <span class="nx">watchErr</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</span>
|
||||
<span class="nx">compileScript</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">code</span><span class="p">.</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">base</span><span class="p">)</span>
|
||||
<span class="nx">rewatch</span><span class="p">()</span>
|
||||
|
||||
<span class="k">try</span>
|
||||
<span class="nv">watcher = </span><span class="nx">fs</span><span class="p">.</span><span class="nx">watch</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">compile</span>
|
||||
<span class="k">catch</span> <span class="nx">e</span>
|
||||
<span class="nx">watchErr</span> <span class="nx">e</span>
|
||||
|
||||
<span class="nv">rewatch = </span><span class="nf">-></span>
|
||||
<span class="nx">watcher</span><span class="o">?</span><span class="p">.</span><span class="nx">close</span><span class="p">()</span>
|
||||
<span class="nv">watcher = </span><span class="nx">fs</span><span class="p">.</span><span class="nx">watch</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">compile</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>joinTimeout = <span class="literal">null</span>
|
||||
<span class="function"><span class="title">compileJoin</span></span> = ->
|
||||
<span class="keyword">return</span> <span class="keyword">unless</span> opts.join
|
||||
<span class="keyword">unless</span> sourceCode.some((code) -> code <span class="keyword">is</span> <span class="literal">null</span>)
|
||||
clearTimeout joinTimeout
|
||||
joinTimeout = wait <span class="number">100</span>, ->
|
||||
compileScript opts.join, sourceCode.join(<span class="string">'\n'</span>), opts.join</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -480,39 +420,50 @@ such as <code>--lint</code> or <code>--print</code>.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-12">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Watch a directory of files for new additions.
|
||||
|
||||
<p>Watch a source CoffeeScript file using <code>fs.watch</code>, recompiling it every
|
||||
time the file is updated. May be used in combination with other options,
|
||||
such as <code>--print</code>.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">watchDir = </span><span class="nf">(source, base) -></span>
|
||||
<span class="nv">readdirTimeout = </span><span class="kc">null</span>
|
||||
<span class="k">try</span>
|
||||
<span class="nv">watcher = </span><span class="nx">fs</span><span class="p">.</span><span class="nx">watch</span> <span class="nx">source</span><span class="p">,</span> <span class="nf">-></span>
|
||||
<span class="nx">clearTimeout</span> <span class="nx">readdirTimeout</span>
|
||||
<span class="nv">readdirTimeout = </span><span class="nx">wait</span> <span class="mi">25</span><span class="p">,</span> <span class="nf">-></span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">readdir</span> <span class="nx">source</span><span class="p">,</span> <span class="nf">(err, files) -></span>
|
||||
<span class="k">if</span> <span class="nx">err</span>
|
||||
<span class="k">throw</span> <span class="nx">err</span> <span class="k">unless</span> <span class="nx">err</span><span class="p">.</span><span class="nx">code</span> <span class="o">is</span> <span class="s">'ENOENT'</span>
|
||||
<span class="nx">watcher</span><span class="p">.</span><span class="nx">close</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="nx">unwatchDir</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">base</span>
|
||||
<span class="k">for</span> <span class="nx">file</span> <span class="k">in</span> <span class="nx">files</span> <span class="k">when</span> <span class="o">not</span> <span class="nx">hidden</span><span class="p">(</span><span class="nx">file</span><span class="p">)</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">notSources</span><span class="p">[</span><span class="nx">file</span><span class="p">]</span>
|
||||
<span class="nv">file = </span><span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">file</span>
|
||||
<span class="k">continue</span> <span class="k">if</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">some</span> <span class="nf">(s) -></span> <span class="nx">s</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">file</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span>
|
||||
<span class="nx">sources</span><span class="p">.</span><span class="nx">push</span> <span class="nx">file</span>
|
||||
<span class="nx">sourceCode</span><span class="p">.</span><span class="nx">push</span> <span class="kc">null</span>
|
||||
<span class="nx">compilePath</span> <span class="nx">file</span><span class="p">,</span> <span class="kc">no</span><span class="p">,</span> <span class="nx">base</span>
|
||||
<span class="k">catch</span> <span class="nx">e</span>
|
||||
<span class="k">throw</span> <span class="nx">e</span> <span class="k">unless</span> <span class="nx">e</span><span class="p">.</span><span class="nx">code</span> <span class="o">is</span> <span class="s">'ENOENT'</span>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">watch</span></span> = (source, base) ->
|
||||
|
||||
<span class="nv">unwatchDir = </span><span class="nf">(source, base) -></span>
|
||||
<span class="nv">prevSources = </span><span class="nx">sources</span><span class="p">[..]</span>
|
||||
<span class="nv">toRemove = </span><span class="p">(</span><span class="nx">file</span> <span class="k">for</span> <span class="nx">file</span> <span class="k">in</span> <span class="nx">sources</span> <span class="k">when</span> <span class="nx">file</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">source</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">)</span>
|
||||
<span class="nx">removeSource</span> <span class="nx">file</span><span class="p">,</span> <span class="nx">base</span><span class="p">,</span> <span class="kc">yes</span> <span class="k">for</span> <span class="nx">file</span> <span class="k">in</span> <span class="nx">toRemove</span>
|
||||
<span class="k">return</span> <span class="k">unless</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">some</span> <span class="nf">(s, i) -></span> <span class="nx">prevSources</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">isnt</span> <span class="nx">s</span>
|
||||
<span class="nx">compileJoin</span><span class="p">()</span></pre></div></div>
|
||||
prevStats = <span class="literal">null</span>
|
||||
compileTimeout = <span class="literal">null</span>
|
||||
|
||||
<span class="function"><span class="title">watchErr</span></span> = (e) ->
|
||||
<span class="keyword">if</span> e.code <span class="keyword">is</span> <span class="string">'ENOENT'</span>
|
||||
<span class="keyword">return</span> <span class="keyword">if</span> sources.indexOf(source) <span class="keyword">is</span> -<span class="number">1</span>
|
||||
<span class="keyword">try</span>
|
||||
rewatch()
|
||||
compile()
|
||||
<span class="keyword">catch</span> e
|
||||
removeSource source, base, <span class="literal">yes</span>
|
||||
compileJoin()
|
||||
<span class="keyword">else</span> <span class="keyword">throw</span> e
|
||||
|
||||
<span class="function"><span class="title">compile</span></span> = ->
|
||||
clearTimeout compileTimeout
|
||||
compileTimeout = wait <span class="number">25</span>, ->
|
||||
fs.stat source, (err, stats) ->
|
||||
<span class="keyword">return</span> watchErr err <span class="keyword">if</span> err
|
||||
<span class="keyword">return</span> rewatch() <span class="keyword">if</span> prevStats <span class="keyword">and</span> stats.size <span class="keyword">is</span> prevStats.size <span class="keyword">and</span>
|
||||
stats.mtime.getTime() <span class="keyword">is</span> prevStats.mtime.getTime()
|
||||
prevStats = stats
|
||||
fs.readFile source, (err, code) ->
|
||||
<span class="keyword">return</span> watchErr err <span class="keyword">if</span> err
|
||||
compileScript(source, code.toString(), base)
|
||||
rewatch()
|
||||
|
||||
<span class="keyword">try</span>
|
||||
watcher = fs.watch source, compile
|
||||
<span class="keyword">catch</span> e
|
||||
watchErr e
|
||||
|
||||
<span class="function"><span class="title">rewatch</span></span> = ->
|
||||
watcher?.close()
|
||||
watcher = fs.watch source, compile</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -523,25 +474,37 @@ such as <code>--lint</code> or <code>--print</code>.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-13">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Remove a file from our source list, and source code cache. Optionally remove
|
||||
the compiled JS version as well.
|
||||
|
||||
<p>Watch a directory of files for new additions.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">removeSource = </span><span class="nf">(source, base, removeJs) -></span>
|
||||
<span class="nv">index = </span><span class="nx">sources</span><span class="p">.</span><span class="nx">indexOf</span> <span class="nx">source</span>
|
||||
<span class="nx">sources</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">index</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="nx">sourceCode</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">index</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="k">if</span> <span class="nx">removeJs</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span>
|
||||
<span class="nv">jsPath = </span><span class="nx">outputPath</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">base</span>
|
||||
<span class="nx">exists</span> <span class="nx">jsPath</span><span class="p">,</span> <span class="nf">(itExists) -></span>
|
||||
<span class="k">if</span> <span class="nx">itExists</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">unlink</span> <span class="nx">jsPath</span><span class="p">,</span> <span class="nf">(err) -></span>
|
||||
<span class="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</span> <span class="o">and</span> <span class="nx">err</span><span class="p">.</span><span class="nx">code</span> <span class="o">isnt</span> <span class="s">'ENOENT'</span>
|
||||
<span class="nx">timeLog</span> <span class="s">"removed </span><span class="si">#{</span><span class="nx">source</span><span class="si">}</span><span class="s">"</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">watchDir</span></span> = (source, base) ->
|
||||
readdirTimeout = <span class="literal">null</span>
|
||||
<span class="keyword">try</span>
|
||||
watcher = fs.watch source, ->
|
||||
clearTimeout readdirTimeout
|
||||
readdirTimeout = wait <span class="number">25</span>, ->
|
||||
fs.readdir source, (err, files) ->
|
||||
<span class="keyword">if</span> err
|
||||
<span class="keyword">throw</span> err <span class="keyword">unless</span> err.code <span class="keyword">is</span> <span class="string">'ENOENT'</span>
|
||||
watcher.close()
|
||||
<span class="keyword">return</span> unwatchDir source, base
|
||||
<span class="keyword">for</span> file <span class="keyword">in</span> files <span class="keyword">when</span> <span class="keyword">not</span> hidden(file) <span class="keyword">and</span> <span class="keyword">not</span> notSources[file]
|
||||
file = path.join source, file
|
||||
<span class="keyword">continue</span> <span class="keyword">if</span> sources.some (s) -> s.indexOf(file) >= <span class="number">0</span>
|
||||
sources.push file
|
||||
sourceCode.push <span class="literal">null</span>
|
||||
compilePath file, <span class="literal">no</span>, base
|
||||
<span class="keyword">catch</span> e
|
||||
<span class="keyword">throw</span> e <span class="keyword">unless</span> e.code <span class="keyword">is</span> <span class="string">'ENOENT'</span>
|
||||
|
||||
<span class="function"><span class="title">unwatchDir</span></span> = (source, base) ->
|
||||
prevSources = sources[..]
|
||||
toRemove = (file <span class="keyword">for</span> file <span class="keyword">in</span> sources <span class="keyword">when</span> file.indexOf(source) >= <span class="number">0</span>)
|
||||
removeSource file, base, <span class="literal">yes</span> <span class="keyword">for</span> file <span class="keyword">in</span> toRemove
|
||||
<span class="keyword">return</span> <span class="keyword">unless</span> sources.some (s, i) -> prevSources[i] <span class="keyword">isnt</span> s
|
||||
compileJoin()</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -552,19 +515,23 @@ the compiled JS version as well.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-14">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Get the corresponding output JavaScript path for a source file.
|
||||
|
||||
<p>Remove a file from our source list, and source code cache. Optionally remove
|
||||
the compiled JS version as well.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">outputPath = </span><span class="nf">(source, base, extension=".js") -></span>
|
||||
<span class="nv">basename = </span><span class="nx">helpers</span><span class="p">.</span><span class="nx">baseFileName</span> <span class="nx">source</span><span class="p">,</span> <span class="kc">yes</span>
|
||||
<span class="nv">srcDir = </span><span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">source</span>
|
||||
<span class="nv">baseDir = </span><span class="k">if</span> <span class="nx">base</span> <span class="o">is</span> <span class="s">'.'</span> <span class="k">then</span> <span class="nx">srcDir</span> <span class="k">else</span> <span class="nx">srcDir</span><span class="p">.</span><span class="nx">substring</span> <span class="nx">base</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">dir = </span><span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">output</span> <span class="k">then</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">output</span><span class="p">,</span> <span class="nx">baseDir</span> <span class="k">else</span> <span class="nx">srcDir</span>
|
||||
<span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">dir</span><span class="p">,</span> <span class="nx">basename</span> <span class="o">+</span> <span class="nx">extension</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">removeSource</span></span> = (source, base, removeJs) ->
|
||||
index = sources.indexOf source
|
||||
sources.splice index, <span class="number">1</span>
|
||||
sourceCode.splice index, <span class="number">1</span>
|
||||
<span class="keyword">if</span> removeJs <span class="keyword">and</span> <span class="keyword">not</span> opts.join
|
||||
jsPath = outputPath source, base
|
||||
exists jsPath, (itExists) ->
|
||||
<span class="keyword">if</span> itExists
|
||||
fs.unlink jsPath, (err) ->
|
||||
<span class="keyword">throw</span> err <span class="keyword">if</span> err <span class="keyword">and</span> err.code <span class="keyword">isnt</span> <span class="string">'ENOENT'</span>
|
||||
timeLog <span class="string">"removed <span class="subst">#{source}</span>"</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -575,38 +542,17 @@ the compiled JS version as well.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-15">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Write out a JavaScript source file with the compiled code. By default, files
|
||||
are written out in <code>cwd</code> as <code>.js</code> files with the same name, but the output
|
||||
directory can be customized with <code>--output</code>.
|
||||
|
||||
</p>
|
||||
<p>If <code>generatedSourceMap</code> is provided, this will write a <code>.map</code> file into the
|
||||
same directory as the <code>.js</code> file.
|
||||
|
||||
<p>Get the corresponding output JavaScript path for a source file.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">writeJs = </span><span class="nf">(base, sourcePath, js, generatedSourceMap = null) -></span>
|
||||
<span class="nv">jsPath = </span><span class="nx">outputPath</span> <span class="nx">sourcePath</span><span class="p">,</span> <span class="nx">base</span>
|
||||
<span class="nv">sourceMapPath = </span><span class="nx">outputPath</span> <span class="nx">sourcePath</span><span class="p">,</span> <span class="nx">base</span><span class="p">,</span> <span class="s">".map"</span>
|
||||
<span class="nv">jsDir = </span><span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">jsPath</span>
|
||||
<span class="nv">compile = </span><span class="nf">-></span>
|
||||
<span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">compile</span>
|
||||
<span class="nv">js = </span><span class="s">' '</span> <span class="k">if</span> <span class="nx">js</span><span class="p">.</span><span class="nx">length</span> <span class="o"><=</span> <span class="mi">0</span>
|
||||
<span class="k">if</span> <span class="nx">generatedSourceMap</span> <span class="k">then</span> <span class="nv">js = </span><span class="s">"//@ sourceMappingURL=</span><span class="si">#{</span><span class="nx">helpers</span><span class="p">.</span><span class="nx">baseFileName</span> <span class="nx">sourceMapPath</span><span class="si">}</span><span class="s">\n</span><span class="si">#{</span><span class="nx">js</span><span class="si">}</span><span class="s">"</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">writeFile</span> <span class="nx">jsPath</span><span class="p">,</span> <span class="nx">js</span><span class="p">,</span> <span class="nf">(err) -></span>
|
||||
<span class="k">if</span> <span class="nx">err</span>
|
||||
<span class="nx">printLine</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">compile</span> <span class="o">and</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">watch</span>
|
||||
<span class="nx">timeLog</span> <span class="s">"compiled </span><span class="si">#{</span><span class="nx">sourcePath</span><span class="si">}</span><span class="s">"</span>
|
||||
<span class="k">if</span> <span class="nx">generatedSourceMap</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">writeFile</span> <span class="nx">sourceMapPath</span><span class="p">,</span> <span class="nx">generatedSourceMap</span><span class="p">,</span> <span class="nf">(err) -></span>
|
||||
<span class="k">if</span> <span class="nx">err</span>
|
||||
<span class="nx">printLine</span> <span class="s">"Could not write source map: </span><span class="si">#{</span><span class="nx">err</span><span class="p">.</span><span class="nx">message</span><span class="si">}</span><span class="s">"</span>
|
||||
<span class="nx">exists</span> <span class="nx">jsDir</span><span class="p">,</span> <span class="nf">(itExists) -></span>
|
||||
<span class="k">if</span> <span class="nx">itExists</span> <span class="k">then</span> <span class="nx">compile</span><span class="p">()</span> <span class="k">else</span> <span class="nx">exec</span> <span class="s">"mkdir -p </span><span class="si">#{</span><span class="nx">jsDir</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="nx">compile</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">outputPath</span></span> = (source, base, extension=<span class="string">".js"</span>) ->
|
||||
basename = helpers.baseFileName source, <span class="literal">yes</span>, useWinPathSep
|
||||
srcDir = path.dirname source
|
||||
baseDir = <span class="keyword">if</span> base <span class="keyword">is</span> <span class="string">'.'</span> <span class="keyword">then</span> srcDir <span class="keyword">else</span> srcDir.substring base.length
|
||||
dir = <span class="keyword">if</span> opts.output <span class="keyword">then</span> path.join opts.output, baseDir <span class="keyword">else</span> srcDir
|
||||
path.join dir, basename + extension</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -617,14 +563,35 @@ same directory as the <code>.js</code> file.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-16">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Convenience for cleaner setTimeouts.
|
||||
<p>Write out a JavaScript source file with the compiled code. By default, files
|
||||
are written out in <code>cwd</code> as <code>.js</code> files with the same name, but the output
|
||||
directory can be customized with <code>--output</code>.
|
||||
|
||||
</p>
|
||||
<p>If <code>generatedSourceMap</code> is provided, this will write a <code>.map</code> file into the
|
||||
same directory as the <code>.js</code> file.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">wait = </span><span class="nf">(milliseconds, func) -></span> <span class="nx">setTimeout</span> <span class="nx">func</span><span class="p">,</span> <span class="nx">milliseconds</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">writeJs</span></span> = (base, sourcePath, js, jsPath, generatedSourceMap = <span class="literal">null</span>) ->
|
||||
sourceMapPath = outputPath sourcePath, base, <span class="string">".map"</span>
|
||||
jsDir = path.dirname jsPath
|
||||
<span class="function"><span class="title">compile</span></span> = ->
|
||||
<span class="keyword">if</span> opts.compile
|
||||
js = <span class="string">' '</span> <span class="keyword">if</span> js.length <= <span class="number">0</span>
|
||||
<span class="keyword">if</span> generatedSourceMap <span class="keyword">then</span> js = <span class="string">"<span class="subst">#{js}</span>\n/*\n//@ sourceMappingURL=<span class="subst">#{helpers.baseFileName sourceMapPath, <span class="literal">no</span>, useWinPathSep}</span>\n*/\n"</span>
|
||||
fs.writeFile jsPath, js, (err) ->
|
||||
<span class="keyword">if</span> err
|
||||
printLine err.message
|
||||
<span class="keyword">else</span> <span class="keyword">if</span> opts.compile <span class="keyword">and</span> opts.watch
|
||||
timeLog <span class="string">"compiled <span class="subst">#{sourcePath}</span>"</span>
|
||||
<span class="keyword">if</span> generatedSourceMap
|
||||
fs.writeFile sourceMapPath, generatedSourceMap, (err) ->
|
||||
<span class="keyword">if</span> err
|
||||
printLine <span class="string">"Could not write source map: <span class="subst">#{err.message}</span>"</span>
|
||||
exists jsDir, (itExists) ->
|
||||
<span class="keyword">if</span> itExists <span class="keyword">then</span> compile() <span class="keyword">else</span> exec <span class="string">"mkdir -p <span class="subst">#{jsDir}</span>"</span>, compile</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -635,15 +602,12 @@ same directory as the <code>.js</code> file.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
</div>
|
||||
|
||||
<p>When watching scripts, it's useful to log changes with the timestamp.
|
||||
|
||||
<p>Convenience for cleaner setTimeouts.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">timeLog = </span><span class="nf">(message) -></span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="s">"</span><span class="si">#{</span><span class="p">(</span><span class="k">new</span> <span class="nb">Date</span><span class="p">).</span><span class="nx">toLocaleTimeString</span><span class="p">()</span><span class="si">}</span><span class="s"> - </span><span class="si">#{</span><span class="nx">message</span><span class="si">}</span><span class="s">"</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">wait</span></span> = (milliseconds, func) -> setTimeout func, milliseconds</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -654,22 +618,13 @@ same directory as the <code>.js</code> file.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-18">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Pipe compiled JS through JSLint (requires a working <code>jsl</code> command), printing
|
||||
any errors or warnings that arise.
|
||||
|
||||
<p>When watching scripts, it's useful to log changes with the timestamp.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">lint = </span><span class="nf">(file, js) -></span>
|
||||
<span class="nv">printIt = </span><span class="nf">(buffer) -></span> <span class="nx">printLine</span> <span class="nx">file</span> <span class="o">+</span> <span class="s">':\t'</span> <span class="o">+</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">().</span><span class="nx">trim</span><span class="p">()</span>
|
||||
<span class="nv">conf = </span><span class="nx">__dirname</span> <span class="o">+</span> <span class="s">'/../../extras/jsl.conf'</span>
|
||||
<span class="nv">jsl = </span><span class="nx">spawn</span> <span class="s">'jsl'</span><span class="p">,</span> <span class="p">[</span><span class="s">'-nologo'</span><span class="p">,</span> <span class="s">'-stdin'</span><span class="p">,</span> <span class="s">'-conf'</span><span class="p">,</span> <span class="nx">conf</span><span class="p">]</span>
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">on</span> <span class="s">'data'</span><span class="p">,</span> <span class="nx">printIt</span>
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stderr</span><span class="p">.</span><span class="nx">on</span> <span class="s">'data'</span><span class="p">,</span> <span class="nx">printIt</span>
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stdin</span><span class="p">.</span><span class="nx">write</span> <span class="nx">js</span>
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stdin</span><span class="p">.</span><span class="nx">end</span><span class="p">()</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">timeLog</span></span> = (message) ->
|
||||
console.log <span class="string">"<span class="subst">#{(<span class="keyword">new</span> Date).toLocaleTimeString()}</span> - <span class="subst">#{message}</span>"</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -680,19 +635,17 @@ any errors or warnings that arise.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-19">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Pretty-print a stream of tokens, sans location data.
|
||||
|
||||
<p>Pretty-print a stream of tokens, sans location data.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">printTokens = </span><span class="nf">(tokens) -></span>
|
||||
<span class="nv">strings = </span><span class="k">for</span> <span class="nx">token</span> <span class="k">in</span> <span class="nx">tokens</span>
|
||||
<span class="nv">tag = </span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nv">value = </span><span class="nx">token</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">toString</span><span class="p">().</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/\n/</span><span class="p">,</span> <span class="s">'\\n'</span><span class="p">)</span>
|
||||
<span class="s">"[</span><span class="si">#{</span><span class="nx">tag</span><span class="si">}</span><span class="s"> </span><span class="si">#{</span><span class="nx">value</span><span class="si">}</span><span class="s">]"</span>
|
||||
<span class="nx">printLine</span> <span class="nx">strings</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s">' '</span><span class="p">)</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">printTokens</span></span> = (tokens) ->
|
||||
strings = <span class="keyword">for</span> token <span class="keyword">in</span> tokens
|
||||
tag = token[<span class="number">0</span>]
|
||||
value = token[<span class="number">1</span>].toString().replace(<span class="regexp">/\n/</span>, <span class="string">'\\n'</span>)
|
||||
<span class="string">"[<span class="subst">#{tag}</span> <span class="subst">#{value}</span>]"</span>
|
||||
printLine strings.join(<span class="string">' '</span>)</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -703,23 +656,21 @@ any errors or warnings that arise.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-20">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Use the <a href="optparse.html">OptionParser module</a> to extract all options from
|
||||
<p>Use the <a href="optparse.html">OptionParser module</a> to extract all options from
|
||||
<code>process.argv</code> that are specified in <code>SWITCHES</code>.
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">parseOptions = </span><span class="nf">-></span>
|
||||
<span class="nv">optionParser = </span><span class="k">new</span> <span class="nx">optparse</span><span class="p">.</span><span class="nx">OptionParser</span> <span class="nx">SWITCHES</span><span class="p">,</span> <span class="nx">BANNER</span>
|
||||
<span class="nv">o = opts = </span><span class="nx">optionParser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">..]</span>
|
||||
<span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="o">or=</span> <span class="o">!!</span><span class="nx">o</span><span class="p">.</span><span class="nx">output</span>
|
||||
<span class="nv">o.run = </span><span class="o">not</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">lint</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">map</span><span class="p">)</span>
|
||||
<span class="nv">o.print = </span><span class="o">!!</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="o">or</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nb">eval</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">stdio</span> <span class="o">and</span> <span class="nx">o</span><span class="p">.</span><span class="nx">compile</span><span class="p">))</span>
|
||||
<span class="nv">sources = </span><span class="nx">o</span><span class="p">.</span><span class="nx">arguments</span>
|
||||
<span class="nx">sourceCode</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="kc">null</span> <span class="k">for</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">sources</span>
|
||||
<span class="k">return</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">parseOptions</span></span> = ->
|
||||
optionParser = <span class="keyword">new</span> optparse.OptionParser SWITCHES, BANNER
|
||||
o = opts = optionParser.parse process.argv[<span class="number">2.</span>.]
|
||||
o.compile <span class="keyword">or</span>= !!o.output
|
||||
o.run = <span class="keyword">not</span> (o.compile <span class="keyword">or</span> o.print <span class="keyword">or</span> o.map)
|
||||
o.print = !! (o.print <span class="keyword">or</span> (o.eval <span class="keyword">or</span> o.stdio <span class="keyword">and</span> o.compile))
|
||||
sources = o.arguments
|
||||
sourceCode[i] = <span class="literal">null</span> <span class="keyword">for</span> source, i <span class="keyword">in</span> sources
|
||||
<span class="keyword">return</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -730,21 +681,36 @@ any errors or warnings that arise.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-21">¶</a>
|
||||
</div>
|
||||
|
||||
<p>The compile-time options to pass to the CoffeeScript compiler.
|
||||
|
||||
<p>The compile-time options to pass to the CoffeeScript compiler.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">compileOptions = </span><span class="nf">(filename) -></span>
|
||||
<span class="p">{</span>
|
||||
<span class="nx">filename</span>
|
||||
<span class="nv">literate: </span><span class="nx">helpers</span><span class="p">.</span><span class="nx">isLiterate</span><span class="p">(</span><span class="nx">filename</span><span class="p">)</span>
|
||||
<span class="nv">bare: </span><span class="nx">opts</span><span class="p">.</span><span class="nx">bare</span>
|
||||
<span class="nv">header: </span><span class="nx">opts</span><span class="p">.</span><span class="nx">compile</span>
|
||||
<span class="nv">sourceMap: </span><span class="nx">opts</span><span class="p">.</span><span class="nx">map</span>
|
||||
<span class="p">}</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">compileOptions</span></span> = (filename, base) ->
|
||||
answer = {
|
||||
filename
|
||||
literate: opts.literate <span class="keyword">or</span> helpers.isLiterate(filename)
|
||||
bare: opts.bare
|
||||
header: opts.compile
|
||||
sourceMap: opts.map
|
||||
}
|
||||
<span class="keyword">if</span> filename
|
||||
<span class="keyword">if</span> base
|
||||
cwd = process.cwd()
|
||||
jsPath = outputPath filename, base
|
||||
jsDir = path.dirname jsPath
|
||||
answer = helpers.merge answer, {
|
||||
jsPath
|
||||
sourceRoot: path.relative jsDir, cwd
|
||||
sourceFiles: [path.relative cwd, filename]
|
||||
generatedFile: helpers.baseFileName(jsPath, <span class="literal">no</span>, useWinPathSep)
|
||||
}
|
||||
<span class="keyword">else</span>
|
||||
answer = helpers.merge answer,
|
||||
sourceRoot: <span class="string">""</span>
|
||||
sourceFiles: [helpers.baseFileName filename, <span class="literal">no</span>, useWinPathSep]
|
||||
generatedFile: helpers.baseFileName(filename, <span class="literal">yes</span>, useWinPathSep) + <span class="string">".js"</span>
|
||||
answer</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -755,22 +721,20 @@ any errors or warnings that arise.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-22">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Start up a new Node.js instance with the arguments in <code>--nodejs</code> passed to
|
||||
<p>Start up a new Node.js instance with the arguments in <code>--nodejs</code> passed to
|
||||
the <code>node</code> binary, preserving the other options.
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">forkNode = </span><span class="nf">-></span>
|
||||
<span class="nv">nodeArgs = </span><span class="nx">opts</span><span class="p">.</span><span class="nx">nodejs</span><span class="p">.</span><span class="nx">split</span> <span class="sr">/\s+/</span>
|
||||
<span class="nv">args = </span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">..]</span>
|
||||
<span class="nx">args</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">args</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s">'--nodejs'</span><span class="p">),</span> <span class="mi">2</span>
|
||||
<span class="nx">spawn</span> <span class="nx">process</span><span class="p">.</span><span class="nx">execPath</span><span class="p">,</span> <span class="nx">nodeArgs</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">args</span><span class="p">),</span>
|
||||
<span class="nv">cwd: </span> <span class="nx">process</span><span class="p">.</span><span class="nx">cwd</span><span class="p">()</span>
|
||||
<span class="nv">env: </span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span>
|
||||
<span class="nv">customFds: </span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">forkNode</span></span> = ->
|
||||
nodeArgs = opts.nodejs.split <span class="regexp">/\s+/</span>
|
||||
args = process.argv[<span class="number">1.</span>.]
|
||||
args.splice args.indexOf(<span class="string">'--nodejs'</span>), <span class="number">2</span>
|
||||
spawn process.execPath, nodeArgs.concat(args),
|
||||
cwd: process.cwd()
|
||||
env: process.env
|
||||
customFds: [<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -781,16 +745,14 @@ the <code>node</code> binary, preserving the other options.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-23">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Print the <code>--help</code> usage message and exit. Deprecated switches are not
|
||||
<p>Print the <code>--help</code> usage message and exit. Deprecated switches are not
|
||||
shown.
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">usage = </span><span class="nf">-></span>
|
||||
<span class="nx">printLine</span> <span class="p">(</span><span class="k">new</span> <span class="nx">optparse</span><span class="p">.</span><span class="nx">OptionParser</span> <span class="nx">SWITCHES</span><span class="p">,</span> <span class="nx">BANNER</span><span class="p">).</span><span class="nx">help</span><span class="p">()</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">usage</span></span> = ->
|
||||
printLine (<span class="keyword">new</span> optparse.OptionParser SWITCHES, BANNER).help()</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -801,16 +763,13 @@ shown.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-24">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Print the <code>--version</code> message and exit.
|
||||
<p>Print the <code>--version</code> message and exit.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">version = </span><span class="nf">-></span>
|
||||
<span class="nx">printLine</span> <span class="s">"CoffeeScript version </span><span class="si">#{</span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">VERSION</span><span class="si">}</span><span class="s">"</span>
|
||||
|
||||
</pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">version</span></span> = ->
|
||||
printLine <span class="string">"CoffeeScript version <span class="subst">#{CoffeeScript.VERSION}</span>"</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -51,9 +51,17 @@ b, strong {
|
||||
font-family: "aller-bold";
|
||||
}
|
||||
|
||||
p, ul, ol {
|
||||
p {
|
||||
margin: 15px 0 0px;
|
||||
}
|
||||
.annotation ul, .annotation ol {
|
||||
margin: 25px 0;
|
||||
}
|
||||
.annotation ul li, .annotation ol li {
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: #112233;
|
||||
@@ -99,12 +107,12 @@ pre, tt, code {
|
||||
|
||||
blockquote {
|
||||
border-left: 5px solid #ccc;
|
||||
margin-left: 0;
|
||||
margin: 0;
|
||||
padding: 1px 0 1px 1em;
|
||||
}
|
||||
.sections blockquote p {
|
||||
font-family: Menlo, Consolas, Monaco, monospace;
|
||||
font-size: 14px; line-height: 19px;
|
||||
font-size: 12px; line-height: 16px;
|
||||
color: #999;
|
||||
margin: 10px 0 0;
|
||||
white-space: pre-wrap;
|
||||
@@ -361,66 +369,141 @@ ul.sections > li > div {
|
||||
}
|
||||
|
||||
/*---------------------- Syntax Highlighting -----------------------------*/
|
||||
|
||||
td.linenos { background-color: #f0f0f0; padding-right: 10px; }
|
||||
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
|
||||
body .hll { background-color: #ffffcc }
|
||||
body .c { color: #408080; font-style: italic } /* Comment */
|
||||
body .err { border: 1px solid #FF0000 } /* Error */
|
||||
body .k { color: #954121 } /* Keyword */
|
||||
body .o { color: #666666 } /* Operator */
|
||||
body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
|
||||
body .cp { color: #BC7A00 } /* Comment.Preproc */
|
||||
body .c1 { color: #408080; font-style: italic } /* Comment.Single */
|
||||
body .cs { color: #408080; font-style: italic } /* Comment.Special */
|
||||
body .gd { color: #A00000 } /* Generic.Deleted */
|
||||
body .ge { font-style: italic } /* Generic.Emph */
|
||||
body .gr { color: #FF0000 } /* Generic.Error */
|
||||
body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
|
||||
body .gi { color: #00A000 } /* Generic.Inserted */
|
||||
body .go { color: #808080 } /* Generic.Output */
|
||||
body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
|
||||
body .gs { font-weight: bold } /* Generic.Strong */
|
||||
body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
|
||||
body .gt { color: #0040D0 } /* Generic.Traceback */
|
||||
body .kc { color: #954121 } /* Keyword.Constant */
|
||||
body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
|
||||
body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
|
||||
body .kp { color: #954121 } /* Keyword.Pseudo */
|
||||
body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
|
||||
body .kt { color: #B00040 } /* Keyword.Type */
|
||||
body .m { color: #666666 } /* Literal.Number */
|
||||
body .s { color: #219161 } /* Literal.String */
|
||||
body .na { color: #7D9029 } /* Name.Attribute */
|
||||
body .nb { color: #954121 } /* Name.Builtin */
|
||||
body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
|
||||
body .no { color: #880000 } /* Name.Constant */
|
||||
body .nd { color: #AA22FF } /* Name.Decorator */
|
||||
body .ni { color: #999999; font-weight: bold } /* Name.Entity */
|
||||
body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
|
||||
body .nf { color: #0000FF } /* Name.Function */
|
||||
body .nl { color: #A0A000 } /* Name.Label */
|
||||
body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
|
||||
body .nt { color: #954121; font-weight: bold } /* Name.Tag */
|
||||
body .nv { color: #19469D } /* Name.Variable */
|
||||
body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
|
||||
body .w { color: #bbbbbb } /* Text.Whitespace */
|
||||
body .mf { color: #666666 } /* Literal.Number.Float */
|
||||
body .mh { color: #666666 } /* Literal.Number.Hex */
|
||||
body .mi { color: #666666 } /* Literal.Number.Integer */
|
||||
body .mo { color: #666666 } /* Literal.Number.Oct */
|
||||
body .sb { color: #219161 } /* Literal.String.Backtick */
|
||||
body .sc { color: #219161 } /* Literal.String.Char */
|
||||
body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
|
||||
body .s2 { color: #219161 } /* Literal.String.Double */
|
||||
body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
|
||||
body .sh { color: #219161 } /* Literal.String.Heredoc */
|
||||
body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
|
||||
body .sx { color: #954121 } /* Literal.String.Other */
|
||||
body .sr { color: #BB6688 } /* Literal.String.Regex */
|
||||
body .s1 { color: #219161 } /* Literal.String.Single */
|
||||
body .ss { color: #19469D } /* Literal.String.Symbol */
|
||||
body .bp { color: #954121 } /* Name.Builtin.Pseudo */
|
||||
body .vc { color: #19469D } /* Name.Variable.Class */
|
||||
body .vg { color: #19469D } /* Name.Variable.Global */
|
||||
body .vi { color: #19469D } /* Name.Variable.Instance */
|
||||
body .il { color: #666666 } /* Literal.Number.Integer.Long */
|
||||
/*
|
||||
|
||||
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
||||
|
||||
*/
|
||||
|
||||
pre code {
|
||||
display: block; padding: 0.5em;
|
||||
color: #000;
|
||||
background: #f8f8ff
|
||||
}
|
||||
|
||||
pre .comment,
|
||||
pre .template_comment,
|
||||
pre .diff .header,
|
||||
pre .javadoc {
|
||||
color: #408080;
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
pre .keyword,
|
||||
pre .assignment,
|
||||
pre .literal,
|
||||
pre .css .rule .keyword,
|
||||
pre .winutils,
|
||||
pre .javascript .title,
|
||||
pre .lisp .title,
|
||||
pre .subst,
|
||||
pre .reserved {
|
||||
color: #954121;
|
||||
/*font-weight: bold*/
|
||||
}
|
||||
|
||||
pre .number,
|
||||
pre .hexcolor {
|
||||
color: #40a070
|
||||
}
|
||||
|
||||
pre .string,
|
||||
pre .tag .value,
|
||||
pre .phpdoc,
|
||||
pre .tex .formula {
|
||||
color: #219161;
|
||||
}
|
||||
|
||||
pre .title,
|
||||
pre .id {
|
||||
color: #19469D;
|
||||
}
|
||||
pre .params {
|
||||
color: #00F;
|
||||
}
|
||||
|
||||
pre .javascript .title,
|
||||
pre .lisp .title,
|
||||
pre .subst {
|
||||
font-weight: normal
|
||||
}
|
||||
|
||||
pre .class .title,
|
||||
pre .haskell .label,
|
||||
pre .tex .command {
|
||||
color: #458;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
pre .tag,
|
||||
pre .tag .title,
|
||||
pre .rules .property,
|
||||
pre .django .tag .keyword {
|
||||
color: #000080;
|
||||
font-weight: normal
|
||||
}
|
||||
|
||||
pre .attribute,
|
||||
pre .variable,
|
||||
pre .instancevar,
|
||||
pre .lisp .body {
|
||||
color: #008080
|
||||
}
|
||||
|
||||
pre .regexp {
|
||||
color: #B68
|
||||
}
|
||||
|
||||
pre .class {
|
||||
color: #458;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
pre .symbol,
|
||||
pre .ruby .symbol .string,
|
||||
pre .ruby .symbol .keyword,
|
||||
pre .ruby .symbol .keymethods,
|
||||
pre .lisp .keyword,
|
||||
pre .tex .special,
|
||||
pre .input_number {
|
||||
color: #990073
|
||||
}
|
||||
|
||||
pre .builtin,
|
||||
pre .constructor,
|
||||
pre .built_in,
|
||||
pre .lisp .title {
|
||||
color: #0086b3
|
||||
}
|
||||
|
||||
pre .preprocessor,
|
||||
pre .pi,
|
||||
pre .doctype,
|
||||
pre .shebang,
|
||||
pre .cdata {
|
||||
color: #999;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
pre .deletion {
|
||||
background: #fdd
|
||||
}
|
||||
|
||||
pre .addition {
|
||||
background: #dfd
|
||||
}
|
||||
|
||||
pre .diff .change {
|
||||
background: #0086b3
|
||||
}
|
||||
|
||||
pre .chunk {
|
||||
color: #aaa
|
||||
}
|
||||
|
||||
pre .tex .formula {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -85,7 +85,7 @@
|
||||
|
||||
|
||||
<a class="source" href="sourcemap.html">
|
||||
sourcemap.coffee
|
||||
sourcemap.litcoffee
|
||||
</a>
|
||||
|
||||
</div>
|
||||
@@ -111,17 +111,10 @@
|
||||
<p>This file contains the common helper functions that we'd like to share among
|
||||
the <strong>Lexer</strong>, <strong>Rewriter</strong>, and the <strong>Nodes</strong>. Merge objects, flatten
|
||||
arrays, count characters, that sort of thing.
|
||||
|
||||
</p>
|
||||
<p>Peek at the beginning of a given string to see if it matches a sequence.
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.starts = </span><span class="nf">(string, literal, start) -></span>
|
||||
<span class="nx">literal</span> <span class="o">is</span> <span class="nx">string</span><span class="p">.</span><span class="nx">substr</span> <span class="nx">start</span><span class="p">,</span> <span class="nx">literal</span><span class="p">.</span><span class="nx">length</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -131,16 +124,13 @@ arrays, count characters, that sort of thing.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-2">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Peek at the end of a given string to see if it matches a sequence.
|
||||
|
||||
<p>Peek at the beginning of a given string to see if it matches a sequence.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.ends = </span><span class="nf">(string, literal, back) -></span>
|
||||
<span class="nv">len = </span><span class="nx">literal</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nx">literal</span> <span class="o">is</span> <span class="nx">string</span><span class="p">.</span><span class="nx">substr</span> <span class="nx">string</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="nx">len</span> <span class="o">-</span> <span class="p">(</span><span class="nx">back</span> <span class="o">or</span> <span class="mi">0</span><span class="p">),</span> <span class="nx">len</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">starts</span></span> = (string, literal, start) ->
|
||||
literal <span class="keyword">is</span> string.substr start, literal.length</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -151,15 +141,14 @@ arrays, count characters, that sort of thing.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-3">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Trim out all falsy values from an array.
|
||||
|
||||
<p>Peek at the end of a given string to see if it matches a sequence.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.compact = </span><span class="nf">(array) -></span>
|
||||
<span class="nx">item</span> <span class="k">for</span> <span class="nx">item</span> <span class="k">in</span> <span class="nx">array</span> <span class="k">when</span> <span class="nx">item</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">ends</span></span> = (string, literal, back) ->
|
||||
len = literal.length
|
||||
literal <span class="keyword">is</span> string.substr string.length - len - (back <span class="keyword">or</span> <span class="number">0</span>), len</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -170,18 +159,12 @@ arrays, count characters, that sort of thing.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-4">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Count the number of occurrences of a string in a string.
|
||||
|
||||
<p>Repeat a string <code>n</code> times.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.count = </span><span class="nf">(string, substr) -></span>
|
||||
<span class="nv">num = pos = </span><span class="mi">0</span>
|
||||
<span class="k">return</span> <span class="mi">1</span><span class="o">/</span><span class="mi">0</span> <span class="k">unless</span> <span class="nx">substr</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nx">num</span><span class="o">++</span> <span class="k">while</span> <span class="nv">pos = </span><span class="mi">1</span> <span class="o">+</span> <span class="nx">string</span><span class="p">.</span><span class="nx">indexOf</span> <span class="nx">substr</span><span class="p">,</span> <span class="nx">pos</span>
|
||||
<span class="nx">num</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.repeat = <span class="function"><span class="title">repeat</span></span> = (str, n) -></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -192,17 +175,17 @@ arrays, count characters, that sort of thing.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-5">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Merge objects, returning a fresh copy with attributes from both sides.
|
||||
Used every time <code>Base#compile</code> is called, to allow properties in the
|
||||
options hash to propagate down the tree without polluting other branches.
|
||||
|
||||
<p>Use clever algorithm to have O(log(n)) string concatenation operations.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.merge = </span><span class="nf">(options, overrides) -></span>
|
||||
<span class="nx">extend</span> <span class="p">(</span><span class="nx">extend</span> <span class="p">{},</span> <span class="nx">options</span><span class="p">),</span> <span class="nx">overrides</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> res = <span class="string">''</span>
|
||||
<span class="keyword">while</span> n > <span class="number">0</span>
|
||||
res += str <span class="keyword">if</span> n & <span class="number">1</span>
|
||||
n >>>= <span class="number">1</span>
|
||||
str += str
|
||||
res</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -213,17 +196,13 @@ options hash to propagate down the tree without polluting other branches.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-6">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Extend a source object with the properties of another object (shallow copy).
|
||||
|
||||
<p>Trim out all falsy values from an array.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">extend = exports.extend = </span><span class="nf">(object, properties) -></span>
|
||||
<span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">properties</span>
|
||||
<span class="nx">object</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="nx">val</span>
|
||||
<span class="nx">object</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">compact</span></span> = (array) ->
|
||||
item <span class="keyword">for</span> item <span class="keyword">in</span> array <span class="keyword">when</span> item</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -234,22 +213,16 @@ options hash to propagate down the tree without polluting other branches.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-7">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Return a flattened version of an array.
|
||||
Handy for getting a list of <code>children</code> from the nodes.
|
||||
|
||||
<p>Count the number of occurrences of a string in a string.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.flatten = flatten = </span><span class="nf">(array) -></span>
|
||||
<span class="nv">flattened = </span><span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="nx">element</span> <span class="k">in</span> <span class="nx">array</span>
|
||||
<span class="k">if</span> <span class="nx">element</span> <span class="k">instanceof</span> <span class="nb">Array</span>
|
||||
<span class="nv">flattened = </span><span class="nx">flattened</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">flatten</span> <span class="nx">element</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">flattened</span><span class="p">.</span><span class="nx">push</span> <span class="nx">element</span>
|
||||
<span class="nx">flattened</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">count</span></span> = (string, substr) ->
|
||||
num = pos = <span class="number">0</span>
|
||||
<span class="keyword">return</span> <span class="number">1</span>/<span class="number">0</span> <span class="keyword">unless</span> substr.length
|
||||
num++ <span class="keyword">while</span> pos = <span class="number">1</span> + string.indexOf substr, pos
|
||||
num</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -260,18 +233,15 @@ Handy for getting a list of <code>children</code> from the nodes.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-8">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Delete a key from an object, returning the value. Useful when a node is
|
||||
looking for a particular method in an options hash.
|
||||
|
||||
<p>Merge objects, returning a fresh copy with attributes from both sides.
|
||||
Used every time <code>Base#compile</code> is called, to allow properties in the
|
||||
options hash to propagate down the tree without polluting other branches.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.del = </span><span class="nf">(obj, key) -></span>
|
||||
<span class="nv">val = </span> <span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span>
|
||||
<span class="k">delete</span> <span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span>
|
||||
<span class="nx">val</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">merge</span></span> = (options, overrides) ->
|
||||
extend (extend {}, options), overrides</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -282,14 +252,15 @@ looking for a particular method in an options hash.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-9">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Gets the last item of an array(-like) object.
|
||||
|
||||
<p>Extend a source object with the properties of another object (shallow copy).
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.last = </span><span class="nf">(array, back) -></span> <span class="nx">array</span><span class="p">[</span><span class="nx">array</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="p">(</span><span class="nx">back</span> <span class="o">or</span> <span class="mi">0</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>extend = exports.<span class="function"><span class="title">extend</span></span> = (object, properties) ->
|
||||
<span class="keyword">for</span> key, val <span class="keyword">of</span> properties
|
||||
object[key] = val
|
||||
object</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -300,16 +271,20 @@ looking for a particular method in an options hash.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-10">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Typical Array::some
|
||||
|
||||
<p>Return a flattened version of an array.
|
||||
Handy for getting a list of <code>children</code> from the nodes.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.some = </span><span class="nb">Array</span><span class="o">::</span><span class="nx">some</span> <span class="o">?</span> <span class="nf">(fn) -></span>
|
||||
<span class="k">return</span> <span class="kc">true</span> <span class="k">for</span> <span class="nx">e</span> <span class="k">in</span> <span class="k">this</span> <span class="k">when</span> <span class="nx">fn</span> <span class="nx">e</span>
|
||||
<span class="kc">false</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.flatten = <span class="function"><span class="title">flatten</span></span> = (array) ->
|
||||
flattened = []
|
||||
<span class="keyword">for</span> element <span class="keyword">in</span> array
|
||||
<span class="keyword">if</span> element <span class="keyword">instanceof</span> Array
|
||||
flattened = flattened.concat flatten element
|
||||
<span class="keyword">else</span>
|
||||
flattened.push element
|
||||
flattened</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -320,22 +295,16 @@ looking for a particular method in an options hash.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Merge two jison-style location data objects together.
|
||||
If <code>last</code> is not provided, this will simply return <code>first</code>.
|
||||
|
||||
<p>Delete a key from an object, returning the value. Useful when a node is
|
||||
looking for a particular method in an options hash.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">buildLocationData = </span><span class="nf">(first, last) -></span>
|
||||
<span class="k">if</span> <span class="o">not</span> <span class="nx">last</span>
|
||||
<span class="nx">first</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">first_line: </span><span class="nx">first</span><span class="p">.</span><span class="nx">first_line</span>
|
||||
<span class="nv">first_column: </span><span class="nx">first</span><span class="p">.</span><span class="nx">first_column</span>
|
||||
<span class="nv">last_line: </span><span class="nx">last</span><span class="p">.</span><span class="nx">last_line</span>
|
||||
<span class="nv">last_column: </span><span class="nx">last</span><span class="p">.</span><span class="nx">last_column</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">del</span></span> = (obj, key) ->
|
||||
val = obj[key]
|
||||
<span class="keyword">delete</span> obj[key]
|
||||
val</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -346,20 +315,12 @@ If <code>last</code> is not provided, this will simply return <code>first</code>
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-12">¶</a>
|
||||
</div>
|
||||
|
||||
<p>This returns a function which takes an object as a parameter, and if that object is an AST node,
|
||||
updates that object's locationData. The object is returned either way.
|
||||
|
||||
<p>Gets the last item of an array(-like) object.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.addLocationDataFn = </span><span class="nf">(first, last) -></span>
|
||||
<span class="nf">(obj) -></span>
|
||||
<span class="k">if</span> <span class="p">((</span><span class="k">typeof</span> <span class="nx">obj</span><span class="p">)</span> <span class="o">is</span> <span class="s">'object'</span><span class="p">)</span> <span class="o">and</span> <span class="p">(</span><span class="o">!!</span><span class="nx">obj</span><span class="p">[</span><span class="s">'updateLocationDataIfMissing'</span><span class="p">])</span>
|
||||
<span class="nx">obj</span><span class="p">.</span><span class="nx">updateLocationDataIfMissing</span> <span class="nx">buildLocationData</span><span class="p">(</span><span class="nx">first</span><span class="p">,</span> <span class="nx">last</span><span class="p">)</span>
|
||||
|
||||
<span class="k">return</span> <span class="nx">obj</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.last = <span class="function"><span class="title">last</span></span> = (array, back) -> array[array.length - (back <span class="keyword">or</span> <span class="number">0</span>) - <span class="number">1</span>]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -370,23 +331,14 @@ updates that object's locationData. The object is returned either way.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-13">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Convert jison location data to a string.
|
||||
<code>obj</code> can be a token, or a locationData.
|
||||
|
||||
<p>Typical Array::some
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.locationDataToString = </span><span class="nf">(obj) -></span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="s">"2"</span> <span class="k">of</span> <span class="nx">obj</span><span class="p">)</span> <span class="o">and</span> <span class="p">(</span><span class="s">"first_line"</span> <span class="k">of</span> <span class="nx">obj</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span> <span class="k">then</span> <span class="nv">locationData = </span><span class="nx">obj</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="s">"first_line"</span> <span class="k">of</span> <span class="nx">obj</span> <span class="k">then</span> <span class="nv">locationData = </span><span class="nx">obj</span>
|
||||
|
||||
<span class="k">if</span> <span class="nx">locationData</span>
|
||||
<span class="s">"</span><span class="si">#{</span><span class="nx">locationData</span><span class="p">.</span><span class="nx">first_line</span> <span class="o">+</span> <span class="mi">1</span><span class="si">}</span><span class="s">:</span><span class="si">#{</span><span class="nx">locationData</span><span class="p">.</span><span class="nx">first_column</span> <span class="o">+</span> <span class="mi">1</span><span class="si">}</span><span class="s">-"</span> <span class="o">+</span>
|
||||
<span class="s">"</span><span class="si">#{</span><span class="nx">locationData</span><span class="p">.</span><span class="nx">last_line</span> <span class="o">+</span> <span class="mi">1</span><span class="si">}</span><span class="s">:</span><span class="si">#{</span><span class="nx">locationData</span><span class="p">.</span><span class="nx">last_column</span> <span class="o">+</span> <span class="mi">1</span><span class="si">}</span><span class="s">"</span>
|
||||
<span class="k">else</span>
|
||||
<span class="s">"No location data"</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.some = Array::some ? (fn) ->
|
||||
<span class="keyword">return</span> <span class="literal">true</span> <span class="keyword">for</span> e <span class="keyword">in</span> <span class="keyword">this</span> <span class="keyword">when</span> fn e
|
||||
<span class="literal">false</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -397,21 +349,23 @@ updates that object's locationData. The object is returned either way.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-14">¶</a>
|
||||
</div>
|
||||
|
||||
<p>A <code>.coffee.md</code> compatible version of <code>basename</code>, that returns the file sans-extension.
|
||||
|
||||
<p>Simple function for inverting Literate CoffeeScript code by putting the
|
||||
documentation in comments, producing a string of CoffeeScript code that
|
||||
can be compiled "normally".
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.baseFileName = </span><span class="nf">(file, stripExt = no) -></span>
|
||||
<span class="nv">parts = </span><span class="nx">file</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s">'/'</span><span class="p">)</span>
|
||||
<span class="nv">file = </span><span class="nx">parts</span><span class="p">[</span><span class="nx">parts</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="nx">file</span> <span class="k">unless</span> <span class="nx">stripExt</span>
|
||||
<span class="nv">parts = </span><span class="nx">file</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s">'.'</span><span class="p">)</span>
|
||||
<span class="nx">parts</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="nx">parts</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span> <span class="k">if</span> <span class="nx">parts</span><span class="p">[</span><span class="nx">parts</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">is</span> <span class="s">'coffee'</span>
|
||||
<span class="nx">parts</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s">'.'</span><span class="p">)</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">invertLiterate</span></span> = (code) ->
|
||||
maybe_code = <span class="literal">true</span>
|
||||
lines = <span class="keyword">for</span> line <span class="keyword">in</span> code.split(<span class="string">'\n'</span>)
|
||||
<span class="keyword">if</span> maybe_code <span class="keyword">and</span> <span class="regexp">/^([ ]{4}|[ ]{0,3}\t)/</span>.test line
|
||||
line
|
||||
<span class="keyword">else</span> <span class="keyword">if</span> maybe_code = <span class="regexp">/^\s*$/</span>.test line
|
||||
line
|
||||
<span class="keyword">else</span>
|
||||
<span class="string">'# '</span> + line
|
||||
lines.join <span class="string">'\n'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -422,14 +376,20 @@ updates that object's locationData. The object is returned either way.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-15">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Determine if a filename represents a CoffeeScript file.
|
||||
|
||||
<p>Merge two jison-style location data objects together.
|
||||
If <code>last</code> is not provided, this will simply return <code>first</code>.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.isCoffee = </span><span class="nf">(file) -></span> <span class="o">/</span><span class="err">\</span><span class="p">.((</span><span class="nx">lit</span><span class="p">)</span><span class="o">?</span><span class="nx">coffee</span><span class="o">|</span><span class="nx">coffee</span><span class="err">\</span><span class="p">.</span><span class="nx">md</span><span class="p">)</span><span class="nx">$</span><span class="o">/</span><span class="p">.</span><span class="nx">test</span> <span class="nx">file</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">buildLocationData</span></span> = (first, last) ->
|
||||
<span class="keyword">if</span> <span class="keyword">not</span> last
|
||||
first
|
||||
<span class="keyword">else</span>
|
||||
first_line: first.first_line
|
||||
first_column: first.first_column
|
||||
last_line: last.last_line
|
||||
last_column: last.last_column</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -440,15 +400,192 @@ updates that object's locationData. The object is returned either way.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-16">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Determine if a filename represents a Literate CoffeeScript file.
|
||||
<p>This returns a function which takes an object as a parameter, and if that
|
||||
object is an AST node, updates that object's locationData.
|
||||
The object is returned either way.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.isLiterate = </span><span class="nf">(file) -></span> <span class="o">/</span><span class="err">\</span><span class="p">.(</span><span class="nx">litcoffee</span><span class="o">|</span><span class="nx">coffee</span><span class="err">\</span><span class="p">.</span><span class="nx">md</span><span class="p">)</span><span class="nx">$</span><span class="o">/</span><span class="p">.</span><span class="nx">test</span> <span class="nx">file</span>
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">addLocationDataFn</span></span> = (first, last) ->
|
||||
(obj) ->
|
||||
<span class="keyword">if</span> ((<span class="keyword">typeof</span> obj) <span class="keyword">is</span> <span class="string">'object'</span>) <span class="keyword">and</span> (!!obj[<span class="string">'updateLocationDataIfMissing'</span>])
|
||||
obj.updateLocationDataIfMissing buildLocationData(first, last)
|
||||
|
||||
</pre></div></div>
|
||||
<span class="keyword">return</span> obj</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-17">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
</div>
|
||||
<p>Convert jison location data to a string.
|
||||
<code>obj</code> can be a token, or a locationData.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">locationDataToString</span></span> = (obj) ->
|
||||
<span class="keyword">if</span> (<span class="string">"2"</span> <span class="keyword">of</span> obj) <span class="keyword">and</span> (<span class="string">"first_line"</span> <span class="keyword">of</span> obj[<span class="number">2</span>]) <span class="keyword">then</span> locationData = obj[<span class="number">2</span>]
|
||||
<span class="keyword">else</span> <span class="keyword">if</span> <span class="string">"first_line"</span> <span class="keyword">of</span> obj <span class="keyword">then</span> locationData = obj
|
||||
|
||||
<span class="keyword">if</span> locationData
|
||||
<span class="string">"<span class="subst">#{locationData.first_line + <span class="number">1</span>}</span>:<span class="subst">#{locationData.first_column + <span class="number">1</span>}</span>-"</span> +
|
||||
<span class="string">"<span class="subst">#{locationData.last_line + <span class="number">1</span>}</span>:<span class="subst">#{locationData.last_column + <span class="number">1</span>}</span>"</span>
|
||||
<span class="keyword">else</span>
|
||||
<span class="string">"No location data"</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-18">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-18">¶</a>
|
||||
</div>
|
||||
<p>A <code>.coffee.md</code> compatible version of <code>basename</code>, that returns the file sans-extension.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">baseFileName</span></span> = (file, stripExt = <span class="literal">no</span>, useWinPathSep = <span class="literal">no</span>) ->
|
||||
pathSep = <span class="keyword">if</span> useWinPathSep <span class="keyword">then</span> <span class="regexp">/\\|\// else /\//</span>
|
||||
parts = file.split(pathSep)
|
||||
file = parts[parts.length - <span class="number">1</span>]
|
||||
<span class="keyword">return</span> file <span class="keyword">unless</span> stripExt
|
||||
parts = file.split(<span class="string">'.'</span>)
|
||||
parts.pop()
|
||||
parts.pop() <span class="keyword">if</span> parts[parts.length - <span class="number">1</span>] <span class="keyword">is</span> <span class="string">'coffee'</span> <span class="keyword">and</span> parts.length > <span class="number">1</span>
|
||||
parts.join(<span class="string">'.'</span>)</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-19">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-19">¶</a>
|
||||
</div>
|
||||
<p>Determine if a filename represents a CoffeeScript file.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">isCoffee</span></span> = (file) -> <span class="regexp">/\.((lit)?coffee|coffee\.md)$/</span>.test file</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-20">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-20">¶</a>
|
||||
</div>
|
||||
<p>Determine if a filename represents a Literate CoffeeScript file.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">isLiterate</span></span> = (file) -> <span class="regexp">/\.(litcoffee|coffee\.md)$/</span>.test file</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-21">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-21">¶</a>
|
||||
</div>
|
||||
<p>Throws a SyntaxError with a source file location data attached to it in a
|
||||
property called <code>location</code>.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">throwSyntaxError</span></span> = (message, location) ->
|
||||
location.last_line ?= location.first_line
|
||||
location.last_column ?= location.first_column
|
||||
error = <span class="keyword">new</span> SyntaxError message
|
||||
error.location = location
|
||||
<span class="keyword">throw</span> error</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-22">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-22">¶</a>
|
||||
</div>
|
||||
<p>Creates a nice error message like, following the "standard" format
|
||||
</p>
|
||||
<p><filename>:<line>:<col>: <message> plus the line with the error and a marker
|
||||
showing where the error is.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>exports.<span class="function"><span class="title">prettyErrorMessage</span></span> = (error, fileName, code, useColors) ->
|
||||
<span class="keyword">return</span> error.stack <span class="keyword">or</span> <span class="string">"<span class="subst">#{error}</span>"</span> <span class="keyword">unless</span> error.location
|
||||
|
||||
{first_line, first_column, last_line, last_column} = error.location
|
||||
codeLine = code.split(<span class="string">'\n'</span>)[first_line]
|
||||
start = first_column</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-23">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-23">¶</a>
|
||||
</div>
|
||||
<p>Show only the first line on multi-line errors.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> end = <span class="keyword">if</span> first_line <span class="keyword">is</span> last_line <span class="keyword">then</span> last_column + <span class="number">1</span> <span class="keyword">else</span> codeLine.length
|
||||
marker = repeat(<span class="string">' '</span>, start) + repeat(<span class="string">'^'</span>, end - start)
|
||||
|
||||
<span class="keyword">if</span> useColors
|
||||
<span class="function"><span class="title">colorize</span></span> = (str) -> <span class="string">"\x1B[1;31m<span class="subst">#{str}</span>\x1B[0m"</span>
|
||||
codeLine = codeLine[...start] + colorize(codeLine[start...end]) + codeLine[end..]
|
||||
marker = colorize marker
|
||||
|
||||
message = <span class="string">"""
|
||||
<span class="subst">#{fileName}</span>:<span class="subst">#{first_line + <span class="number">1</span>}</span>:<span class="subst">#{first_column + <span class="number">1</span>}</span>: error: <span class="subst">#{error.message}</span>
|
||||
<span class="subst">#{codeLine}</span>
|
||||
<span class="subst">#{marker}</span>
|
||||
"""</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-24">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-24">¶</a>
|
||||
</div>
|
||||
<p>Uncomment to add stacktrace.
|
||||
message += "\n#{error.stack}"
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
message</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
|
||||
|
||||
<a class="source" href="sourcemap.html">
|
||||
sourcemap.coffee
|
||||
sourcemap.litcoffee
|
||||
</a>
|
||||
|
||||
</div>
|
||||
@@ -113,9 +113,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nx">exports</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="nx">val</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">require</span> <span class="s">'./coffee-script'</span>
|
||||
|
||||
</pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports[key] = val <span class="keyword">for</span> key, val <span class="keyword">of</span> require <span class="string">'./coffee-script'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -85,7 +85,7 @@
|
||||
|
||||
|
||||
<a class="source" href="sourcemap.html">
|
||||
sourcemap.coffee
|
||||
sourcemap.litcoffee
|
||||
</a>
|
||||
|
||||
</div>
|
||||
@@ -108,20 +108,10 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-1">¶</a>
|
||||
</div>
|
||||
<p>A simple <strong>OptionParser</strong> class to parse option flags from the command-line.
|
||||
Use it like so:
|
||||
|
||||
</p>
|
||||
<pre><code>parser = new OptionParser switches, helpBanner
|
||||
options = parser.parse process.argv</code></pre>
|
||||
<p>The first non-option is considered to be the start of the file (and file
|
||||
option) list, and all subsequent arguments are left unparsed.
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.OptionParser = </span><span class="k">class</span> <span class="nx">OptionParser</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>{repeat} = require <span class="string">'./helpers'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -132,19 +122,19 @@ option) list, and all subsequent arguments are left unparsed.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-2">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Initialize with a list of valid options, in the form:
|
||||
<p>A simple <strong>OptionParser</strong> class to parse option flags from the command-line.
|
||||
Use it like so:
|
||||
|
||||
</p>
|
||||
<pre><code>[short-flag, long-flag, description]</code></pre>
|
||||
<p>Along with an an optional banner for the usage help.
|
||||
|
||||
<pre><code>parser = new OptionParser switches, helpBanner
|
||||
options = parser.parse process.argv</code></pre>
|
||||
<p>The first non-option is considered to be the start of the file (and file
|
||||
option) list, and all subsequent arguments are left unparsed.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">constructor: </span><span class="nf">(rules, @banner) -></span>
|
||||
<span class="vi">@rules = </span><span class="nx">buildRules</span> <span class="nx">rules</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>exports.OptionParser = <span class="class"><span class="keyword">class</span> <span class="title">OptionParser</span></span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -155,32 +145,17 @@ option) list, and all subsequent arguments are left unparsed.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-3">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Parse the list of arguments, populating an <code>options</code> object with all of the
|
||||
specified options, and return it. Options after the first non-option
|
||||
argument are treated as arguments. <code>options.arguments</code> will be an array
|
||||
containing the remaining arguments. This is a simpler API than many option
|
||||
parsers that allow you to attach callback actions for every flag. Instead,
|
||||
you're responsible for interpreting the options object.
|
||||
<p>Initialize with a list of valid options, in the form:
|
||||
|
||||
</p>
|
||||
<pre><code>[short-flag, long-flag, description]</code></pre>
|
||||
<p>Along with an an optional banner for the usage help.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">parse: </span><span class="nf">(args) -></span>
|
||||
<span class="nv">options = arguments: </span><span class="p">[]</span>
|
||||
<span class="nv">skippingArgument = </span><span class="kc">no</span>
|
||||
<span class="nv">originalArgs = </span><span class="nx">args</span>
|
||||
<span class="nv">args = </span><span class="nx">normalizeArguments</span> <span class="nx">args</span>
|
||||
<span class="k">for</span> <span class="nx">arg</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">args</span>
|
||||
<span class="k">if</span> <span class="nx">skippingArgument</span>
|
||||
<span class="nv">skippingArgument = </span><span class="kc">no</span>
|
||||
<span class="k">continue</span>
|
||||
<span class="k">if</span> <span class="nx">arg</span> <span class="o">is</span> <span class="s">'--'</span>
|
||||
<span class="nv">pos = </span><span class="nx">originalArgs</span><span class="p">.</span><span class="nx">indexOf</span> <span class="s">'--'</span>
|
||||
<span class="nv">options.arguments = </span><span class="nx">options</span><span class="p">.</span><span class="nx">arguments</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">originalArgs</span><span class="p">[(</span><span class="nx">pos</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)..]</span>
|
||||
<span class="k">break</span>
|
||||
<span class="nv">isOption = </span><span class="o">!!</span><span class="p">(</span><span class="nx">arg</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">LONG_FLAG</span><span class="p">)</span> <span class="o">or</span> <span class="nx">arg</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">SHORT_FLAG</span><span class="p">))</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> constructor: (rules, <span class="property">@banner</span>) ->
|
||||
<span class="property">@rules</span> = buildRules rules</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -191,30 +166,30 @@ you're responsible for interpreting the options object.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-4">¶</a>
|
||||
</div>
|
||||
|
||||
<p>the CS option parser is a little odd; options after the first
|
||||
non-option argument are treated as non-option arguments themselves
|
||||
|
||||
<p>Parse the list of arguments, populating an <code>options</code> object with all of the
|
||||
specified options, and return it. Options after the first non-option
|
||||
argument are treated as arguments. <code>options.arguments</code> will be an array
|
||||
containing the remaining arguments. This is a simpler API than many option
|
||||
parsers that allow you to attach callback actions for every flag. Instead,
|
||||
you're responsible for interpreting the options object.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">seenNonOptionArg = </span><span class="nx">options</span><span class="p">.</span><span class="nx">arguments</span><span class="p">.</span><span class="nx">length</span> <span class="o">></span> <span class="mi">0</span>
|
||||
<span class="k">unless</span> <span class="nx">seenNonOptionArg</span>
|
||||
<span class="nv">matchedRule = </span><span class="kc">no</span>
|
||||
<span class="k">for</span> <span class="nx">rule</span> <span class="k">in</span> <span class="nx">@rules</span>
|
||||
<span class="k">if</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">shortFlag</span> <span class="o">is</span> <span class="nx">arg</span> <span class="o">or</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">longFlag</span> <span class="o">is</span> <span class="nx">arg</span>
|
||||
<span class="nv">value = </span><span class="kc">true</span>
|
||||
<span class="k">if</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">hasArgument</span>
|
||||
<span class="nv">skippingArgument = </span><span class="kc">yes</span>
|
||||
<span class="nv">value = </span><span class="nx">args</span><span class="p">[</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nx">options</span><span class="p">[</span><span class="nx">rule</span><span class="p">.</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="k">if</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">isList</span> <span class="k">then</span> <span class="p">(</span><span class="nx">options</span><span class="p">[</span><span class="nx">rule</span><span class="p">.</span><span class="nx">name</span><span class="p">]</span> <span class="o">or</span> <span class="p">[]).</span><span class="nx">concat</span> <span class="nx">value</span> <span class="k">else</span> <span class="nx">value</span>
|
||||
<span class="nv">matchedRule = </span><span class="kc">yes</span>
|
||||
<span class="k">break</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s">"unrecognized option: </span><span class="si">#{</span><span class="nx">arg</span><span class="si">}</span><span class="s">"</span> <span class="k">if</span> <span class="nx">isOption</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">matchedRule</span>
|
||||
<span class="k">if</span> <span class="nx">seenNonOptionArg</span> <span class="o">or</span> <span class="o">not</span> <span class="nx">isOption</span>
|
||||
<span class="nx">options</span><span class="p">.</span><span class="nx">arguments</span><span class="p">.</span><span class="nx">push</span> <span class="nx">arg</span>
|
||||
<span class="nx">options</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> parse: (args) ->
|
||||
options = arguments: []
|
||||
skippingArgument = <span class="literal">no</span>
|
||||
originalArgs = args
|
||||
args = normalizeArguments args
|
||||
<span class="keyword">for</span> arg, i <span class="keyword">in</span> args
|
||||
<span class="keyword">if</span> skippingArgument
|
||||
skippingArgument = <span class="literal">no</span>
|
||||
<span class="keyword">continue</span>
|
||||
<span class="keyword">if</span> arg <span class="keyword">is</span> <span class="string">'--'</span>
|
||||
pos = originalArgs.indexOf <span class="string">'--'</span>
|
||||
options.arguments = options.arguments.concat originalArgs[(pos + <span class="number">1</span>)..]
|
||||
<span class="keyword">break</span>
|
||||
isOption = !!(arg.match(LONG_FLAG) <span class="keyword">or</span> arg.match(SHORT_FLAG))</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -225,23 +200,28 @@ non-option argument are treated as non-option arguments themselves
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-5">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Return the help text for this <strong>OptionParser</strong>, listing and describing all
|
||||
of the valid options, for <code>--help</code> and such.
|
||||
|
||||
<p>the CS option parser is a little odd; options after the first
|
||||
non-option argument are treated as non-option arguments themselves
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">help: </span><span class="nf">-></span>
|
||||
<span class="nv">lines = </span><span class="p">[]</span>
|
||||
<span class="nx">lines</span><span class="p">.</span><span class="nx">unshift</span> <span class="s">"</span><span class="si">#{</span><span class="nx">@banner</span><span class="si">}</span><span class="s">\n"</span> <span class="k">if</span> <span class="nx">@banner</span>
|
||||
<span class="k">for</span> <span class="nx">rule</span> <span class="k">in</span> <span class="nx">@rules</span>
|
||||
<span class="nv">spaces = </span><span class="mi">15</span> <span class="o">-</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">longFlag</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">spaces = </span><span class="k">if</span> <span class="nx">spaces</span> <span class="o">></span> <span class="mi">0</span> <span class="k">then</span> <span class="nb">Array</span><span class="p">(</span><span class="nx">spaces</span> <span class="o">+</span> <span class="mi">1</span><span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s">' '</span><span class="p">)</span> <span class="k">else</span> <span class="s">''</span>
|
||||
<span class="nv">letPart = </span><span class="k">if</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">shortFlag</span> <span class="k">then</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">shortFlag</span> <span class="o">+</span> <span class="s">', '</span> <span class="k">else</span> <span class="s">' '</span>
|
||||
<span class="nx">lines</span><span class="p">.</span><span class="nx">push</span> <span class="s">' '</span> <span class="o">+</span> <span class="nx">letPart</span> <span class="o">+</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">longFlag</span> <span class="o">+</span> <span class="nx">spaces</span> <span class="o">+</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">description</span>
|
||||
<span class="s">"\n</span><span class="si">#{</span> <span class="nx">lines</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s">'\n'</span><span class="p">)</span> <span class="si">}</span><span class="s">\n"</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> seenNonOptionArg = options.arguments.length > <span class="number">0</span>
|
||||
<span class="keyword">unless</span> seenNonOptionArg
|
||||
matchedRule = <span class="literal">no</span>
|
||||
<span class="keyword">for</span> rule <span class="keyword">in</span> <span class="property">@rules</span>
|
||||
<span class="keyword">if</span> rule.shortFlag <span class="keyword">is</span> arg <span class="keyword">or</span> rule.longFlag <span class="keyword">is</span> arg
|
||||
value = <span class="literal">true</span>
|
||||
<span class="keyword">if</span> rule.hasArgument
|
||||
skippingArgument = <span class="literal">yes</span>
|
||||
value = args[i + <span class="number">1</span>]
|
||||
options[rule.name] = <span class="keyword">if</span> rule.isList <span class="keyword">then</span> (options[rule.name] <span class="keyword">or</span> []).concat value <span class="keyword">else</span> value
|
||||
matchedRule = <span class="literal">yes</span>
|
||||
<span class="keyword">break</span>
|
||||
<span class="keyword">throw</span> <span class="keyword">new</span> Error <span class="string">"unrecognized option: <span class="subst">#{arg}</span>"</span> <span class="keyword">if</span> isOption <span class="keyword">and</span> <span class="keyword">not</span> matchedRule
|
||||
<span class="keyword">if</span> seenNonOptionArg <span class="keyword">or</span> <span class="keyword">not</span> isOption
|
||||
options.arguments.push arg
|
||||
options</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -249,35 +229,38 @@ of the valid options, for <code>--help</code> and such.
|
||||
<li id="section-6">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap for-h2">
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-6">¶</a>
|
||||
</div>
|
||||
|
||||
<h2>Helpers</h2>
|
||||
<p>Return the help text for this <strong>OptionParser</strong>, listing and describing all
|
||||
of the valid options, for <code>--help</code> and such.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> help: ->
|
||||
lines = []
|
||||
lines.unshift <span class="string">"<span class="subst">#{@banner}</span>\n"</span> <span class="keyword">if</span> <span class="property">@banner</span>
|
||||
<span class="keyword">for</span> rule <span class="keyword">in</span> <span class="property">@rules</span>
|
||||
spaces = <span class="number">15</span> - rule.longFlag.length
|
||||
spaces = <span class="keyword">if</span> spaces > <span class="number">0</span> <span class="keyword">then</span> repeat <span class="string">' '</span>, spaces <span class="keyword">else</span> <span class="string">''</span>
|
||||
letPart = <span class="keyword">if</span> rule.shortFlag <span class="keyword">then</span> rule.shortFlag + <span class="string">', '</span> <span class="keyword">else</span> <span class="string">' '</span>
|
||||
lines.push <span class="string">' '</span> + letPart + rule.longFlag + spaces + rule.description
|
||||
<span class="string">"\n<span class="subst">#{ lines.join('\n') }</span>\n"</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-7">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<div class="pilwrap for-h2">
|
||||
<a class="pilcrow" href="#section-7">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Regex matchers for option flags.
|
||||
|
||||
</p>
|
||||
<h2>Helpers</h2>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">LONG_FLAG = </span><span class="sr">/^(--\w[\w\-]*)/</span>
|
||||
<span class="nv">SHORT_FLAG = </span><span class="sr">/^(-\w)$/</span>
|
||||
<span class="nv">MULTI_FLAG = </span><span class="sr">/^-(\w{2,})/</span>
|
||||
<span class="nv">OPTIONAL = </span><span class="sr">/\[(\w+(\*?))\]/</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -288,18 +271,8 @@ of the valid options, for <code>--help</code> and such.
|
||||
<a class="pilcrow" href="#section-8">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Build and return the list of option rules. If the optional <em>short-flag</em> is
|
||||
unspecified, leave it out by padding with <code>null</code>.
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">buildRules = </span><span class="nf">(rules) -></span>
|
||||
<span class="k">for</span> <span class="nx">tuple</span> <span class="k">in</span> <span class="nx">rules</span>
|
||||
<span class="nx">tuple</span><span class="p">.</span><span class="nx">unshift</span> <span class="kc">null</span> <span class="k">if</span> <span class="nx">tuple</span><span class="p">.</span><span class="nx">length</span> <span class="o"><</span> <span class="mi">3</span>
|
||||
<span class="nx">buildRule</span> <span class="nx">tuple</span><span class="p">...</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -309,25 +282,15 @@ unspecified, leave it out by padding with <code>null</code>.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-9">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Build a rule from a <code>-o</code> short flag, a <code>--output [DIR]</code> long flag, and the
|
||||
description of what the option does.
|
||||
|
||||
<p>Regex matchers for option flags.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">buildRule = </span><span class="nf">(shortFlag, longFlag, description, options = {}) -></span>
|
||||
<span class="nv">match = </span><span class="nx">longFlag</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">OPTIONAL</span><span class="p">)</span>
|
||||
<span class="nv">longFlag = </span><span class="nx">longFlag</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">LONG_FLAG</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nv">name: </span> <span class="nx">longFlag</span><span class="p">.</span><span class="nx">substr</span> <span class="mi">2</span>
|
||||
<span class="nv">shortFlag: </span> <span class="nx">shortFlag</span>
|
||||
<span class="nv">longFlag: </span> <span class="nx">longFlag</span>
|
||||
<span class="nv">description: </span> <span class="nx">description</span>
|
||||
<span class="nv">hasArgument: </span> <span class="o">!!</span><span class="p">(</span><span class="nx">match</span> <span class="o">and</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
|
||||
<span class="nv">isList: </span> <span class="o">!!</span><span class="p">(</span><span class="nx">match</span> <span class="o">and</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
|
||||
<span class="p">}</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>LONG_FLAG = <span class="regexp">/^(--\w[\w\-]*)/</span>
|
||||
SHORT_FLAG = <span class="regexp">/^(-\w)$/</span>
|
||||
MULTI_FLAG = <span class="regexp">/^-(\w{2,})/</span>
|
||||
OPTIONAL = <span class="regexp">/\[(\w+(\*?))\]/</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -338,24 +301,68 @@ description of what the option does.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-10">¶</a>
|
||||
</div>
|
||||
<p>Build and return the list of option rules. If the optional <em>short-flag</em> is
|
||||
unspecified, leave it out by padding with <code>null</code>.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">buildRules</span></span> = (rules) ->
|
||||
<span class="keyword">for</span> tuple <span class="keyword">in</span> rules
|
||||
tuple.unshift <span class="literal">null</span> <span class="keyword">if</span> tuple.length < <span class="number">3</span>
|
||||
buildRule tuple...</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-11">
|
||||
<div class="annotation">
|
||||
|
||||
<p>Normalize arguments by expanding merged flags into multiple flags. This allows
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
</div>
|
||||
<p>Build a rule from a <code>-o</code> short flag, a <code>--output [DIR]</code> long flag, and the
|
||||
description of what the option does.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">buildRule</span></span> = (shortFlag, longFlag, description, options = {}) ->
|
||||
match = longFlag.match(OPTIONAL)
|
||||
longFlag = longFlag.match(LONG_FLAG)[<span class="number">1</span>]
|
||||
{
|
||||
name: longFlag.substr <span class="number">2</span>
|
||||
shortFlag: shortFlag
|
||||
longFlag: longFlag
|
||||
description: description
|
||||
hasArgument: !!(match <span class="keyword">and</span> match[<span class="number">1</span>])
|
||||
isList: !!(match <span class="keyword">and</span> match[<span class="number">2</span>])
|
||||
}</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-12">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-12">¶</a>
|
||||
</div>
|
||||
<p>Normalize arguments by expanding merged flags into multiple flags. This allows
|
||||
you to have <code>-wl</code> be the same as <code>--watch --lint</code>.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">normalizeArguments = </span><span class="nf">(args) -></span>
|
||||
<span class="nv">args = </span><span class="nx">args</span><span class="p">[..]</span>
|
||||
<span class="nv">result = </span><span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="nx">arg</span> <span class="k">in</span> <span class="nx">args</span>
|
||||
<span class="k">if</span> <span class="nv">match = </span><span class="nx">arg</span><span class="p">.</span><span class="nx">match</span> <span class="nx">MULTI_FLAG</span>
|
||||
<span class="nx">result</span><span class="p">.</span><span class="nx">push</span> <span class="s">'-'</span> <span class="o">+</span> <span class="nx">l</span> <span class="k">for</span> <span class="nx">l</span> <span class="k">in</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">split</span> <span class="s">''</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">result</span><span class="p">.</span><span class="nx">push</span> <span class="nx">arg</span>
|
||||
<span class="nx">result</span>
|
||||
|
||||
</pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">normalizeArguments</span></span> = (args) ->
|
||||
args = args[..]
|
||||
result = []
|
||||
<span class="keyword">for</span> arg <span class="keyword">in</span> args
|
||||
<span class="keyword">if</span> match = arg.match MULTI_FLAG
|
||||
result.push <span class="string">'-'</span> + l <span class="keyword">for</span> l <span class="keyword">in</span> match[<span class="number">1</span>].split <span class="string">''</span>
|
||||
<span class="keyword">else</span>
|
||||
result.push arg
|
||||
result</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 56 KiB |
@@ -85,7 +85,7 @@
|
||||
|
||||
|
||||
<a class="source" href="sourcemap.html">
|
||||
sourcemap.coffee
|
||||
sourcemap.litcoffee
|
||||
</a>
|
||||
|
||||
</div>
|
||||
@@ -111,14 +111,18 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">vm = </span><span class="nx">require</span> <span class="s">'vm'</span>
|
||||
<span class="nv">nodeREPL = </span><span class="nx">require</span> <span class="s">'repl'</span>
|
||||
<span class="nv">CoffeeScript = </span><span class="nx">require</span> <span class="s">'./coffee-script'</span>
|
||||
<span class="p">{</span><span class="nx">merge</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s">'./helpers'</span>
|
||||
<div class="content"><div class='highlight'><pre>fs = require <span class="string">'fs'</span>
|
||||
path = require <span class="string">'path'</span>
|
||||
vm = require <span class="string">'vm'</span>
|
||||
nodeREPL = require <span class="string">'repl'</span>
|
||||
CoffeeScript = require <span class="string">'./coffee-script'</span>
|
||||
{merge, prettyErrorMessage} = require <span class="string">'./helpers'</span>
|
||||
|
||||
<span class="nv">replDefaults =</span>
|
||||
<span class="nv">prompt: </span><span class="s">'coffee> '</span><span class="p">,</span>
|
||||
<span class="nb">eval</span><span class="o">:</span> <span class="nf">(input, context, filename, cb) -></span></pre></div></div>
|
||||
replDefaults =
|
||||
prompt: <span class="string">'coffee> '</span>,
|
||||
historyFile: path.join process.env.HOME, <span class="string">'.coffee_history'</span> <span class="keyword">if</span> process.env.HOME
|
||||
historyMaxInputSize: <span class="number">10240</span>
|
||||
eval: (input, context, filename, cb) -></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -129,14 +133,12 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-2">¶</a>
|
||||
</div>
|
||||
|
||||
<p>XXX: multiline hack
|
||||
|
||||
<p>XXX: multiline hack.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">input = </span><span class="nx">input</span><span class="p">.</span><span class="nx">replace</span> <span class="sr">/\uFF00/g</span><span class="p">,</span> <span class="s">'\n'</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> input = input.replace <span class="regexp">/\uFF00/g</span>, <span class="string">'\n'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -147,14 +149,13 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-3">¶</a>
|
||||
</div>
|
||||
|
||||
<p>strip single-line comments
|
||||
|
||||
<p>Node's REPL sends the input ending with a newline and then wrapped in
|
||||
parens. Unwrap all that.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">input = </span><span class="nx">input</span><span class="p">.</span><span class="nx">replace</span> <span class="sr">/(^|[\r\n]+)(\s*)##?(?:[^#\r\n][^\r\n]*|)($|[\r\n])/</span><span class="p">,</span> <span class="s">'$1$2$3'</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> input = input.replace <span class="regexp">/^\(([\s\S]*)\n\)$/m</span>, <span class="string">'$1'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -165,14 +166,14 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-4">¶</a>
|
||||
</div>
|
||||
|
||||
<p>empty command
|
||||
|
||||
<p>Require AST nodes to do some AST manipulation.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="k">return</span> <span class="nx">cb</span> <span class="kc">null</span> <span class="k">if</span> <span class="sr">/^(\s*|\(\s*\))$/</span><span class="p">.</span><span class="nx">test</span> <span class="nx">input</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> {Block, Assign, Value, Literal} = require <span class="string">'./nodes'</span>
|
||||
|
||||
<span class="keyword">try</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -183,27 +184,12 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-5">¶</a>
|
||||
</div>
|
||||
|
||||
<p>TODO: fix #1829: pass in-scope vars and avoid accidentally shadowing them by omitting those declarations
|
||||
|
||||
<p>Generate the AST of the clean input.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="k">try</span>
|
||||
<span class="nv">js = </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">compile</span> <span class="s">"_=(</span><span class="si">#{</span><span class="nx">input</span><span class="si">}</span><span class="s">\n)"</span><span class="p">,</span> <span class="p">{</span><span class="nx">filename</span><span class="p">,</span> <span class="nv">bare: </span><span class="kc">yes</span><span class="p">}</span>
|
||||
<span class="nx">cb</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">vm</span><span class="p">.</span><span class="nx">runInContext</span><span class="p">(</span><span class="nx">js</span><span class="p">,</span> <span class="nx">context</span><span class="p">,</span> <span class="nx">filename</span><span class="p">)</span>
|
||||
<span class="k">catch</span> <span class="nx">err</span>
|
||||
<span class="nx">cb</span> <span class="nx">err</span>
|
||||
|
||||
<span class="nv">addMultilineHandler = </span><span class="nf">(repl) -></span>
|
||||
<span class="p">{</span><span class="nx">rli</span><span class="p">,</span> <span class="nx">inputStream</span><span class="p">,</span> <span class="nx">outputStream</span><span class="p">}</span> <span class="o">=</span> <span class="nx">repl</span>
|
||||
|
||||
<span class="nv">multiline =</span>
|
||||
<span class="nv">enabled: </span><span class="kc">off</span>
|
||||
<span class="nv">initialPrompt: </span><span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/^[^> ]*/</span><span class="p">,</span> <span class="nf">(x) -></span> <span class="nx">x</span><span class="p">.</span><span class="nx">replace</span> <span class="sr">/./g</span><span class="p">,</span> <span class="s">'-'</span><span class="p">)</span>
|
||||
<span class="nv">prompt: </span><span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/^[^> ]*>?/</span><span class="p">,</span> <span class="nf">(x) -></span> <span class="nx">x</span><span class="p">.</span><span class="nx">replace</span> <span class="sr">/./g</span><span class="p">,</span> <span class="s">'.'</span><span class="p">)</span>
|
||||
<span class="nv">buffer: </span><span class="s">''</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> ast = CoffeeScript.nodes input</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -214,23 +200,27 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-6">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Proxy node's line listener
|
||||
|
||||
<p>Add assignment to <code>_</code> variable to force the input to be an expression.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">nodeLineListener = </span><span class="nx">rli</span><span class="p">.</span><span class="nx">listeners</span><span class="p">(</span><span class="s">'line'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nx">rli</span><span class="p">.</span><span class="nx">removeListener</span> <span class="s">'line'</span><span class="p">,</span> <span class="nx">nodeLineListener</span>
|
||||
<span class="nx">rli</span><span class="p">.</span><span class="nx">on</span> <span class="s">'line'</span><span class="p">,</span> <span class="nf">(cmd) -></span>
|
||||
<span class="k">if</span> <span class="nx">multiline</span><span class="p">.</span><span class="nx">enabled</span>
|
||||
<span class="nx">multiline</span><span class="p">.</span><span class="nx">buffer</span> <span class="o">+=</span> <span class="s">"</span><span class="si">#{</span><span class="nx">cmd</span><span class="si">}</span><span class="s">\n"</span>
|
||||
<span class="nx">rli</span><span class="p">.</span><span class="nx">setPrompt</span> <span class="nx">multiline</span><span class="p">.</span><span class="nx">prompt</span>
|
||||
<span class="nx">rli</span><span class="p">.</span><span class="nx">prompt</span> <span class="kc">true</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">nodeLineListener</span> <span class="nx">cmd</span>
|
||||
<span class="k">return</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> ast = <span class="keyword">new</span> Block [
|
||||
<span class="keyword">new</span> Assign (<span class="keyword">new</span> Value <span class="keyword">new</span> Literal <span class="string">'_'</span>), ast, <span class="string">'='</span>
|
||||
]
|
||||
js = ast.compile bare: <span class="literal">yes</span>, locals: Object.keys(context)
|
||||
cb <span class="literal">null</span>, vm.runInContext(js, context, filename)
|
||||
<span class="keyword">catch</span> err
|
||||
cb prettyErrorMessage(err, filename, input, <span class="literal">yes</span>)
|
||||
|
||||
<span class="function"><span class="title">addMultilineHandler</span></span> = (repl) ->
|
||||
{rli, inputStream, outputStream} = repl
|
||||
|
||||
multiline =
|
||||
enabled: <span class="literal">off</span>
|
||||
initialPrompt: repl.prompt.replace <span class="regexp">/^[^> ]*/, (x) -> x.replace /./g</span>, <span class="string">'-'</span>
|
||||
prompt: repl.prompt.replace <span class="regexp">/^[^> ]*>?/, (x) -> x.replace /./g</span>, <span class="string">'.'</span>
|
||||
buffer: <span class="string">''</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -241,16 +231,21 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-7">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Handle Ctrl-v
|
||||
|
||||
<p>Proxy node's line listener
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nx">inputStream</span><span class="p">.</span><span class="nx">on</span> <span class="s">'keypress'</span><span class="p">,</span> <span class="nf">(char, key) -></span>
|
||||
<span class="k">return</span> <span class="k">unless</span> <span class="nx">key</span> <span class="o">and</span> <span class="nx">key</span><span class="p">.</span><span class="nx">ctrl</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">key</span><span class="p">.</span><span class="nx">meta</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">key</span><span class="p">.</span><span class="nx">shift</span> <span class="o">and</span> <span class="nx">key</span><span class="p">.</span><span class="nx">name</span> <span class="o">is</span> <span class="s">'v'</span>
|
||||
<span class="k">if</span> <span class="nx">multiline</span><span class="p">.</span><span class="nx">enabled</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> nodeLineListener = rli.listeners(<span class="string">'line'</span>)[<span class="number">0</span>]
|
||||
rli.removeListener <span class="string">'line'</span>, nodeLineListener
|
||||
rli.<span class="literal">on</span> <span class="string">'line'</span>, (cmd) ->
|
||||
<span class="keyword">if</span> multiline.enabled
|
||||
multiline.buffer += <span class="string">"<span class="subst">#{cmd}</span>\n"</span>
|
||||
rli.setPrompt multiline.prompt
|
||||
rli.prompt <span class="literal">true</span>
|
||||
<span class="keyword">else</span>
|
||||
nodeLineListener cmd
|
||||
<span class="keyword">return</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -261,18 +256,14 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-8">¶</a>
|
||||
</div>
|
||||
|
||||
<p>allow arbitrarily switching between modes any time before multiple lines are entered
|
||||
|
||||
<p>Handle Ctrl-v
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="k">unless</span> <span class="nx">multiline</span><span class="p">.</span><span class="nx">buffer</span><span class="p">.</span><span class="nx">match</span> <span class="sr">/\n/</span>
|
||||
<span class="nv">multiline.enabled = </span><span class="o">not</span> <span class="nx">multiline</span><span class="p">.</span><span class="nx">enabled</span>
|
||||
<span class="nx">rli</span><span class="p">.</span><span class="nx">setPrompt</span> <span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span>
|
||||
<span class="nx">rli</span><span class="p">.</span><span class="nx">prompt</span> <span class="kc">true</span>
|
||||
<span class="k">return</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> inputStream.<span class="literal">on</span> <span class="string">'keypress'</span>, (char, key) ->
|
||||
<span class="keyword">return</span> <span class="keyword">unless</span> key <span class="keyword">and</span> key.ctrl <span class="keyword">and</span> <span class="keyword">not</span> key.meta <span class="keyword">and</span> <span class="keyword">not</span> key.shift <span class="keyword">and</span> key.name <span class="keyword">is</span> <span class="string">'v'</span>
|
||||
<span class="keyword">if</span> multiline.enabled</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -283,14 +274,16 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-9">¶</a>
|
||||
</div>
|
||||
|
||||
<p>no-op unless the current line is empty
|
||||
|
||||
<p>allow arbitrarily switching between modes any time before multiple lines are entered
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="k">return</span> <span class="k">if</span> <span class="nx">rli</span><span class="p">.</span><span class="nx">line</span><span class="o">?</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">rli</span><span class="p">.</span><span class="nx">line</span><span class="p">.</span><span class="nx">match</span> <span class="sr">/^\s*$/</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> <span class="keyword">unless</span> multiline.buffer.match <span class="regexp">/\n/</span>
|
||||
multiline.enabled = <span class="keyword">not</span> multiline.enabled
|
||||
rli.setPrompt repl.prompt
|
||||
rli.prompt <span class="literal">true</span>
|
||||
<span class="keyword">return</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -301,18 +294,12 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-10">¶</a>
|
||||
</div>
|
||||
|
||||
<p>eval, print, loop
|
||||
|
||||
<p>no-op unless the current line is empty
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">multiline.enabled = </span><span class="o">not</span> <span class="nx">multiline</span><span class="p">.</span><span class="nx">enabled</span>
|
||||
<span class="nv">rli.line = </span><span class="s">''</span>
|
||||
<span class="nv">rli.cursor = </span><span class="mi">0</span>
|
||||
<span class="nx">rli</span><span class="p">.</span><span class="nx">output</span><span class="p">.</span><span class="nx">cursorTo</span> <span class="mi">0</span>
|
||||
<span class="nx">rli</span><span class="p">.</span><span class="nx">output</span><span class="p">.</span><span class="nx">clearLine</span> <span class="mi">1</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> <span class="keyword">return</span> <span class="keyword">if</span> rli.line? <span class="keyword">and</span> <span class="keyword">not</span> rli.line.match <span class="regexp">/^\s*$/</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -323,30 +310,201 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
</div>
|
||||
|
||||
<p>XXX: multiline hack
|
||||
<p>eval, print, loop
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">multiline.buffer = </span><span class="nx">multiline</span><span class="p">.</span><span class="nx">buffer</span><span class="p">.</span><span class="nx">replace</span> <span class="sr">/\n/g</span><span class="p">,</span> <span class="s">'\uFF00'</span>
|
||||
<span class="nx">rli</span><span class="p">.</span><span class="nx">emit</span> <span class="s">'line'</span><span class="p">,</span> <span class="nx">multiline</span><span class="p">.</span><span class="nx">buffer</span>
|
||||
<span class="nv">multiline.buffer = </span><span class="s">''</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">multiline.enabled = </span><span class="o">not</span> <span class="nx">multiline</span><span class="p">.</span><span class="nx">enabled</span>
|
||||
<span class="nx">rli</span><span class="p">.</span><span class="nx">setPrompt</span> <span class="nx">multiline</span><span class="p">.</span><span class="nx">initialPrompt</span>
|
||||
<span class="nx">rli</span><span class="p">.</span><span class="nx">prompt</span> <span class="kc">true</span>
|
||||
<span class="k">return</span>
|
||||
<div class="content"><div class='highlight'><pre> multiline.enabled = <span class="keyword">not</span> multiline.enabled
|
||||
rli.line = <span class="string">''</span>
|
||||
rli.cursor = <span class="number">0</span>
|
||||
rli.output.cursorTo <span class="number">0</span>
|
||||
rli.output.clearLine <span class="number">1</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-12">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-12">¶</a>
|
||||
</div>
|
||||
<p>XXX: multiline hack
|
||||
</p>
|
||||
|
||||
<span class="nv">module.exports =</span>
|
||||
<span class="nv">start: </span><span class="nf">(opts = {}) -></span>
|
||||
<span class="nv">opts = </span><span class="nx">merge</span> <span class="nx">replDefaults</span><span class="p">,</span> <span class="nx">opts</span>
|
||||
<span class="nv">repl = </span><span class="nx">nodeREPL</span><span class="p">.</span><span class="nx">start</span> <span class="nx">opts</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">on</span> <span class="s">'exit'</span><span class="p">,</span> <span class="nf">-></span> <span class="nx">repl</span><span class="p">.</span><span class="nx">outputStream</span><span class="p">.</span><span class="nx">write</span> <span class="s">'\n'</span>
|
||||
<span class="nx">addMultilineHandler</span> <span class="nx">repl</span>
|
||||
<span class="nx">repl</span>
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> multiline.buffer = multiline.buffer.replace <span class="regexp">/\n/g</span>, <span class="string">'\uFF00'</span>
|
||||
rli.emit <span class="string">'line'</span>, multiline.buffer
|
||||
multiline.buffer = <span class="string">''</span>
|
||||
<span class="keyword">else</span>
|
||||
multiline.enabled = <span class="keyword">not</span> multiline.enabled
|
||||
rli.setPrompt multiline.initialPrompt
|
||||
rli.prompt <span class="literal">true</span>
|
||||
<span class="keyword">return</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-13">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-13">¶</a>
|
||||
</div>
|
||||
<p>Store and load command history from a file
|
||||
</p>
|
||||
|
||||
</pre></div></div>
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">addHistory</span></span> = (repl, filename, maxSize) ->
|
||||
lastLine = <span class="literal">null</span>
|
||||
<span class="keyword">try</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-14">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-14">¶</a>
|
||||
</div>
|
||||
<p>Get file info and at most maxSize of command history
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> stat = fs.statSync filename
|
||||
size = Math.min maxSize, stat.size</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-15">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-15">¶</a>
|
||||
</div>
|
||||
<p>Read last <code>size</code> bytes from the file
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> readFd = fs.openSync filename, <span class="string">'r'</span>
|
||||
buffer = <span class="keyword">new</span> Buffer(size)
|
||||
fs.readSync readFd, buffer, <span class="number">0</span>, size, stat.size - size</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-16">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-16">¶</a>
|
||||
</div>
|
||||
<p>Set the history on the interpreter
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> repl.rli.history = buffer.toString().split(<span class="string">'\n'</span>).reverse()</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-17">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
</div>
|
||||
<p>If the history file was truncated we should pop off a potential partial line
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> repl.rli.history.pop() <span class="keyword">if</span> stat.size > maxSize</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-18">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-18">¶</a>
|
||||
</div>
|
||||
<p>Shift off the final blank newline
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> repl.rli.history.shift() <span class="keyword">if</span> repl.rli.history[<span class="number">0</span>] <span class="keyword">is</span> <span class="string">''</span>
|
||||
repl.rli.historyIndex = -<span class="number">1</span>
|
||||
lastLine = repl.rli.history[<span class="number">0</span>]
|
||||
|
||||
fd = fs.openSync filename, <span class="string">'a'</span>
|
||||
|
||||
repl.rli.addListener <span class="string">'line'</span>, (code) ->
|
||||
<span class="keyword">if</span> code <span class="keyword">and</span> code.length <span class="keyword">and</span> code <span class="keyword">isnt</span> <span class="string">'.history'</span> <span class="keyword">and</span> lastLine <span class="keyword">isnt</span> code</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-19">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-19">¶</a>
|
||||
</div>
|
||||
<p>Save the latest command in the file
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> fs.write fd, <span class="string">"<span class="subst">#{code}</span>\n"</span>
|
||||
lastLine = code
|
||||
|
||||
repl.rli.<span class="literal">on</span> <span class="string">'exit'</span>, -> fs.close fd</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-20">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-20">¶</a>
|
||||
</div>
|
||||
<p>Add a command to show the history stack
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> repl.commands[<span class="string">'.history'</span>] =
|
||||
help: <span class="string">'Show command history'</span>
|
||||
action: ->
|
||||
repl.outputStream.write <span class="string">"<span class="subst">#{repl.rli.history[..].reverse().join '\n'}</span>\n"</span>
|
||||
repl.displayPrompt()
|
||||
|
||||
module.exports =
|
||||
start: (opts = {}) ->
|
||||
[major, minor, build] = process.versions.node.split(<span class="string">'.'</span>).map (n) -> parseInt(n)
|
||||
|
||||
<span class="keyword">if</span> major <span class="keyword">is</span> <span class="number">0</span> <span class="keyword">and</span> minor < <span class="number">8</span>
|
||||
console.warn <span class="string">"Node 0.8.0+ required for CoffeeScript REPL"</span>
|
||||
process.exit <span class="number">1</span>
|
||||
|
||||
opts = merge replDefaults, opts
|
||||
repl = nodeREPL.start opts
|
||||
repl.<span class="literal">on</span> <span class="string">'exit'</span>, -> repl.outputStream.write <span class="string">'\n'</span>
|
||||
addMultilineHandler repl
|
||||
addHistory repl, opts.historyFile, opts.historyMaxInputSize <span class="keyword">if</span> opts.historyFile
|
||||
repl</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -85,7 +85,7 @@
|
||||
|
||||
|
||||
<a class="source" href="sourcemap.html">
|
||||
sourcemap.coffee
|
||||
sourcemap.litcoffee
|
||||
</a>
|
||||
|
||||
</div>
|
||||
@@ -114,19 +114,10 @@ function bodies. Each scope knows about the variables declared within it,
|
||||
and has a reference to its parent enclosing scope. In this way, we know which
|
||||
variables are new and need to be declared with <code>var</code>, and which are shared
|
||||
with external scopes.
|
||||
|
||||
</p>
|
||||
<p>Import the helpers we plan to use.
|
||||
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="p">{</span><span class="nx">extend</span><span class="p">,</span> <span class="nx">last</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s">'./helpers'</span>
|
||||
|
||||
<span class="nv">exports.Scope = </span><span class="k">class</span> <span class="nx">Scope</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -136,15 +127,15 @@ with external scopes.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-2">¶</a>
|
||||
</div>
|
||||
|
||||
<p>The <code>root</code> is the top-level <strong>Scope</strong> object for a given file.
|
||||
|
||||
|
||||
<p>Import the helpers we plan to use.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="vi">@root: </span><span class="kc">null</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
{extend, last} = require <span class="string">'./helpers'</span>
|
||||
|
||||
exports.Scope = <span class="class"><span class="keyword">class</span> <span class="title">Scope</span></span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -155,21 +146,13 @@ with external scopes.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-3">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Initialize a scope with its parent, for lookups up the chain,
|
||||
as well as a reference to the <strong>Block</strong> node it belongs to, which is
|
||||
where it should declare its variables, and a reference to the function that
|
||||
it belongs to.
|
||||
|
||||
|
||||
<p>The <code>root</code> is the top-level <strong>Scope</strong> object for a given file.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">constructor: </span><span class="nf">(@parent, @expressions, @method) -></span>
|
||||
<span class="vi">@variables = </span><span class="p">[{</span><span class="nv">name: </span><span class="s">'arguments'</span><span class="p">,</span> <span class="nv">type: </span><span class="s">'arguments'</span><span class="p">}]</span>
|
||||
<span class="vi">@positions = </span><span class="p">{}</span>
|
||||
<span class="nv">Scope.root = </span><span class="k">this</span> <span class="k">unless</span> <span class="nx">@parent</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
<span class="property">@root</span>: <span class="literal">null</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -180,20 +163,19 @@ it belongs to.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-4">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Adds a new variable or overrides an existing one.
|
||||
|
||||
|
||||
<p>Initialize a scope with its parent, for lookups up the chain,
|
||||
as well as a reference to the <strong>Block</strong> node it belongs to, which is
|
||||
where it should declare its variables, and a reference to the function that
|
||||
it belongs to.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">add: </span><span class="nf">(name, type, immediate) -></span>
|
||||
<span class="k">return</span> <span class="nx">@parent</span><span class="p">.</span><span class="nx">add</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">immediate</span> <span class="k">if</span> <span class="nx">@shared</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">immediate</span>
|
||||
<span class="k">if</span> <span class="nb">Object</span><span class="o">::</span><span class="nx">hasOwnProperty</span><span class="p">.</span><span class="nx">call</span> <span class="nx">@positions</span><span class="p">,</span> <span class="nx">name</span>
|
||||
<span class="nx">@variables</span><span class="p">[</span><span class="nx">@positions</span><span class="p">[</span><span class="nx">name</span><span class="p">]].</span><span class="nv">type = </span><span class="nx">type</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">@positions</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="nx">@variables</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span><span class="nx">name</span><span class="p">,</span> <span class="nx">type</span><span class="p">})</span> <span class="o">-</span> <span class="mi">1</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
constructor: (<span class="property">@parent</span>, <span class="property">@expressions</span>, <span class="property">@method</span>) ->
|
||||
<span class="property">@variables</span> = [{name: <span class="string">'arguments'</span>, type: <span class="string">'arguments'</span>}]
|
||||
<span class="property">@positions</span> = {}
|
||||
Scope.root = <span class="keyword">this</span> <span class="keyword">unless</span> <span class="property">@parent</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -204,21 +186,18 @@ it belongs to.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-5">¶</a>
|
||||
</div>
|
||||
|
||||
<p>When <code>super</code> is called, we need to find the name of the current method we're
|
||||
in, so that we know how to invoke the same method of the parent class. This
|
||||
can get complicated if super is being called from an inner function.
|
||||
<code>namedMethod</code> will walk up the scope tree until it either finds the first
|
||||
function object that has a name filled in, or bottoms out.
|
||||
|
||||
|
||||
<p>Adds a new variable or overrides an existing one.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">namedMethod: </span><span class="nf">-></span>
|
||||
<span class="k">return</span> <span class="nx">@method</span> <span class="k">if</span> <span class="nx">@method</span><span class="o">?</span><span class="p">.</span><span class="nx">name</span> <span class="o">or</span> <span class="o">!</span><span class="nx">@parent</span>
|
||||
<span class="nx">@parent</span><span class="p">.</span><span class="nx">namedMethod</span><span class="p">()</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
add: (name, type, immediate) ->
|
||||
<span class="keyword">return</span> <span class="property">@parent</span>.add name, type, immediate <span class="keyword">if</span> <span class="property">@shared</span> <span class="keyword">and</span> <span class="keyword">not</span> immediate
|
||||
<span class="keyword">if</span> Object::hasOwnProperty.call <span class="property">@positions</span>, name
|
||||
<span class="property">@variables</span>[<span class="property">@positions</span>[name]].type = type
|
||||
<span class="keyword">else</span>
|
||||
<span class="property">@positions</span>[name] = <span class="property">@variables</span>.push({name, type}) - <span class="number">1</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -229,19 +208,19 @@ function object that has a name filled in, or bottoms out.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-6">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Look up a variable name in lexical scope, and declare it if it does not
|
||||
already exist.
|
||||
|
||||
|
||||
<p>When <code>super</code> is called, we need to find the name of the current method we're
|
||||
in, so that we know how to invoke the same method of the parent class. This
|
||||
can get complicated if super is being called from an inner function.
|
||||
<code>namedMethod</code> will walk up the scope tree until it either finds the first
|
||||
function object that has a name filled in, or bottoms out.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">find: </span><span class="nf">(name) -></span>
|
||||
<span class="k">return</span> <span class="kc">yes</span> <span class="k">if</span> <span class="nx">@check</span> <span class="nx">name</span>
|
||||
<span class="nx">@add</span> <span class="nx">name</span><span class="p">,</span> <span class="s">'var'</span>
|
||||
<span class="kc">no</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
namedMethod: ->
|
||||
<span class="keyword">return</span> <span class="property">@method</span> <span class="keyword">if</span> <span class="property">@method</span>?.name <span class="keyword">or</span> !<span class="property">@parent</span>
|
||||
<span class="property">@parent</span>.namedMethod()</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -252,18 +231,17 @@ already exist.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-7">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Reserve a variable name as originating from a function parameter for this
|
||||
scope. No <code>var</code> required for internal references.
|
||||
|
||||
|
||||
<p>Look up a variable name in lexical scope, and declare it if it does not
|
||||
already exist.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">parameter: </span><span class="nf">(name) -></span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@shared</span> <span class="o">and</span> <span class="nx">@parent</span><span class="p">.</span><span class="nx">check</span> <span class="nx">name</span><span class="p">,</span> <span class="kc">yes</span>
|
||||
<span class="nx">@add</span> <span class="nx">name</span><span class="p">,</span> <span class="s">'param'</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
find: (name) ->
|
||||
<span class="keyword">return</span> <span class="literal">yes</span> <span class="keyword">if</span> <span class="property">@check</span> name
|
||||
<span class="property">@add</span> name, <span class="string">'var'</span>
|
||||
<span class="literal">no</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -274,17 +252,16 @@ scope. No <code>var</code> required for internal references.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-8">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Just check to see if a variable has already been declared, without reserving,
|
||||
walks up to the root scope.
|
||||
|
||||
|
||||
<p>Reserve a variable name as originating from a function parameter for this
|
||||
scope. No <code>var</code> required for internal references.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">check: </span><span class="nf">(name) -></span>
|
||||
<span class="o">!!</span><span class="p">(</span><span class="nx">@type</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">or</span> <span class="nx">@parent</span><span class="o">?</span><span class="p">.</span><span class="nx">check</span><span class="p">(</span><span class="nx">name</span><span class="p">))</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
parameter: (name) ->
|
||||
<span class="keyword">return</span> <span class="keyword">if</span> <span class="property">@shared</span> <span class="keyword">and</span> <span class="property">@parent</span>.check name, <span class="literal">yes</span>
|
||||
<span class="property">@add</span> name, <span class="string">'param'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -295,19 +272,15 @@ walks up to the root scope.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-9">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Generate a temporary variable name at the given index.
|
||||
|
||||
|
||||
<p>Just check to see if a variable has already been declared, without reserving,
|
||||
walks up to the root scope.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">temporary: </span><span class="nf">(name, index) -></span>
|
||||
<span class="k">if</span> <span class="nx">name</span><span class="p">.</span><span class="nx">length</span> <span class="o">></span> <span class="mi">1</span>
|
||||
<span class="s">'_'</span> <span class="o">+</span> <span class="nx">name</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">index</span> <span class="o">></span> <span class="mi">1</span> <span class="k">then</span> <span class="nx">index</span> <span class="o">-</span> <span class="mi">1</span> <span class="k">else</span> <span class="s">''</span>
|
||||
<span class="k">else</span>
|
||||
<span class="s">'_'</span> <span class="o">+</span> <span class="p">(</span><span class="nx">index</span> <span class="o">+</span> <span class="nb">parseInt</span> <span class="nx">name</span><span class="p">,</span> <span class="mi">36</span><span class="p">).</span><span class="nx">toString</span><span class="p">(</span><span class="mi">36</span><span class="p">).</span><span class="nx">replace</span> <span class="sr">/\d/g</span><span class="p">,</span> <span class="s">'a'</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
check: (name) ->
|
||||
!!(<span class="property">@type</span>(name) <span class="keyword">or</span> <span class="property">@parent</span>?.check(name))</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -318,17 +291,17 @@ walks up to the root scope.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-10">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Gets the type of a variable.
|
||||
|
||||
|
||||
<p>Generate a temporary variable name at the given index.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">type: </span><span class="nf">(name) -></span>
|
||||
<span class="k">return</span> <span class="nx">v</span><span class="p">.</span><span class="nx">type</span> <span class="k">for</span> <span class="nx">v</span> <span class="k">in</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">v</span><span class="p">.</span><span class="nx">name</span> <span class="o">is</span> <span class="nx">name</span>
|
||||
<span class="kc">null</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
temporary: (name, index) ->
|
||||
<span class="keyword">if</span> name.length > <span class="number">1</span>
|
||||
<span class="string">'_'</span> + name + <span class="keyword">if</span> index > <span class="number">1</span> <span class="keyword">then</span> index - <span class="number">1</span> <span class="keyword">else</span> <span class="string">''</span>
|
||||
<span class="keyword">else</span>
|
||||
<span class="string">'_'</span> + (index + parseInt name, <span class="number">36</span>).toString(<span class="number">36</span>).replace <span class="regexp">/\d/g</span>, <span class="string">'a'</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -339,20 +312,15 @@ walks up to the root scope.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
</div>
|
||||
|
||||
<p>If we need to store an intermediate result, find an available name for a
|
||||
compiler-generated variable. <code>_var</code>, <code>_var2</code>, and so on...
|
||||
|
||||
|
||||
<p>Gets the type of a variable.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">freeVariable: </span><span class="nf">(name, reserve=true) -></span>
|
||||
<span class="nv">index = </span><span class="mi">0</span>
|
||||
<span class="nx">index</span><span class="o">++</span> <span class="k">while</span> <span class="nx">@check</span><span class="p">((</span><span class="nv">temp = </span><span class="nx">@temporary</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">index</span><span class="p">))</span>
|
||||
<span class="nx">@add</span> <span class="nx">temp</span><span class="p">,</span> <span class="s">'var'</span><span class="p">,</span> <span class="kc">yes</span> <span class="k">if</span> <span class="nx">reserve</span>
|
||||
<span class="nx">temp</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
type: (name) ->
|
||||
<span class="keyword">return</span> v.type <span class="keyword">for</span> v <span class="keyword">in</span> <span class="property">@variables</span> <span class="keyword">when</span> v.name <span class="keyword">is</span> name
|
||||
<span class="literal">null</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -363,18 +331,18 @@ compiler-generated variable. <code>_var</code>, <code>_var2</code>, and so on...
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-12">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Ensure that an assignment is made at the top of this scope
|
||||
(or at the top-level scope, if requested).
|
||||
|
||||
|
||||
<p>If we need to store an intermediate result, find an available name for a
|
||||
compiler-generated variable. <code>_var</code>, <code>_var2</code>, and so on...
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">assign: </span><span class="nf">(name, value) -></span>
|
||||
<span class="nx">@add</span> <span class="nx">name</span><span class="p">,</span> <span class="p">{</span><span class="nx">value</span><span class="p">,</span> <span class="nv">assigned: </span><span class="kc">yes</span><span class="p">},</span> <span class="kc">yes</span>
|
||||
<span class="vi">@hasAssignments = </span><span class="kc">yes</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
freeVariable: (name, reserve=<span class="literal">true</span>) ->
|
||||
index = <span class="number">0</span>
|
||||
index++ <span class="keyword">while</span> <span class="property">@check</span>((temp = <span class="property">@temporary</span> name, index))
|
||||
<span class="property">@add</span> temp, <span class="string">'var'</span>, <span class="literal">yes</span> <span class="keyword">if</span> reserve
|
||||
temp</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -385,16 +353,16 @@ compiler-generated variable. <code>_var</code>, <code>_var2</code>, and so on...
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-13">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Does this scope have any declared variables?
|
||||
|
||||
|
||||
<p>Ensure that an assignment is made at the top of this scope
|
||||
(or at the top-level scope, if requested).
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">hasDeclarations: </span><span class="nf">-></span>
|
||||
<span class="o">!!</span><span class="nx">@declaredVariables</span><span class="p">().</span><span class="nx">length</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
assign: (name, value) ->
|
||||
<span class="property">@add</span> name, {value, assigned: <span class="literal">yes</span>}, <span class="literal">yes</span>
|
||||
<span class="property">@hasAssignments</span> = <span class="literal">yes</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -405,20 +373,14 @@ compiler-generated variable. <code>_var</code>, <code>_var2</code>, and so on...
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-14">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Return the list of variables first declared in this scope.
|
||||
|
||||
|
||||
<p>Does this scope have any declared variables?
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">declaredVariables: </span><span class="nf">-></span>
|
||||
<span class="nv">realVars = </span><span class="p">[]</span>
|
||||
<span class="nv">tempVars = </span><span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="nx">v</span> <span class="k">in</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">v</span><span class="p">.</span><span class="nx">type</span> <span class="o">is</span> <span class="s">'var'</span>
|
||||
<span class="p">(</span><span class="k">if</span> <span class="nx">v</span><span class="p">.</span><span class="nx">name</span><span class="p">.</span><span class="nx">charAt</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">is</span> <span class="s">'_'</span> <span class="k">then</span> <span class="nx">tempVars</span> <span class="k">else</span> <span class="nx">realVars</span><span class="p">).</span><span class="nx">push</span> <span class="nx">v</span><span class="p">.</span><span class="nx">name</span>
|
||||
<span class="nx">realVars</span><span class="p">.</span><span class="nx">sort</span><span class="p">().</span><span class="nx">concat</span> <span class="nx">tempVars</span><span class="p">.</span><span class="nx">sort</span><span class="p">()</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
hasDeclarations: ->
|
||||
!!<span class="property">@declaredVariables</span>().length</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -429,18 +391,37 @@ compiler-generated variable. <code>_var</code>, <code>_var2</code>, and so on...
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-15">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Return the list of assignments that are supposed to be made at the top
|
||||
of this scope.
|
||||
|
||||
<p>Return the list of variables first declared in this scope.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">assignedVariables: </span><span class="nf">-></span>
|
||||
<span class="s">"</span><span class="si">#{</span><span class="nx">v</span><span class="p">.</span><span class="nx">name</span><span class="si">}</span><span class="s"> = </span><span class="si">#{</span><span class="nx">v</span><span class="p">.</span><span class="nx">type</span><span class="p">.</span><span class="nx">value</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="nx">v</span> <span class="k">in</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">v</span><span class="p">.</span><span class="nx">type</span><span class="p">.</span><span class="nx">assigned</span>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
declaredVariables: ->
|
||||
realVars = []
|
||||
tempVars = []
|
||||
<span class="keyword">for</span> v <span class="keyword">in</span> <span class="property">@variables</span> <span class="keyword">when</span> v.type <span class="keyword">is</span> <span class="string">'var'</span>
|
||||
(<span class="keyword">if</span> v.name.charAt(<span class="number">0</span>) <span class="keyword">is</span> <span class="string">'_'</span> <span class="keyword">then</span> tempVars <span class="keyword">else</span> realVars).push v.name
|
||||
realVars.sort().concat tempVars.sort()</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-16">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-16">¶</a>
|
||||
</div>
|
||||
<p>Return the list of assignments that are supposed to be made at the top
|
||||
of this scope.
|
||||
</p>
|
||||
|
||||
</pre></div></div>
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
assignedVariables: ->
|
||||
<span class="string">"<span class="subst">#{v.name}</span> = <span class="subst">#{v.type.value}</span>"</span> <span class="keyword">for</span> v <span class="keyword">in</span> <span class="property">@variables</span> <span class="keyword">when</span> v.type.assigned</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>sourcemap.coffee</title>
|
||||
<title>sourcemap.litcoffee</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
|
||||
<link rel="stylesheet" media="all" href="docco.css" />
|
||||
@@ -85,7 +85,7 @@
|
||||
|
||||
|
||||
<a class="source" href="sourcemap.html">
|
||||
sourcemap.coffee
|
||||
sourcemap.litcoffee
|
||||
</a>
|
||||
|
||||
</div>
|
||||
@@ -96,7 +96,7 @@
|
||||
|
||||
<li id="title">
|
||||
<div class="annotation">
|
||||
<h1>sourcemap.coffee</h1>
|
||||
<h1>sourcemap.litcoffee</h1>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@@ -108,16 +108,14 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-1">¶</a>
|
||||
</div>
|
||||
<p>Hold data about mappings for one line of generated source code.
|
||||
|
||||
|
||||
<p>Source maps allow JavaScript runtimes to match running JavaScript back to
|
||||
the original source code that corresponds to it. This can be minified
|
||||
JavaScript, but in our case, we're concerned with mapping pretty-printed
|
||||
JavaScript back to CoffeeScript.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="k">class</span> <span class="nx">LineMapping</span>
|
||||
<span class="nv">constructor: </span><span class="nf">(@generatedLine) -></span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -127,36 +125,28 @@
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-2">¶</a>
|
||||
</div>
|
||||
|
||||
<p>columnMap keeps track of which columns we've already mapped.
|
||||
|
||||
<p>In order to produce maps, we must keep track of positions (line number, column number)
|
||||
that originated every node in the syntax tree, and be able to generate a
|
||||
<a href="https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit">map file</a>
|
||||
— which is a compact, VLQ-encoded representation of the JSON serialization
|
||||
of this information — to write out alongside the generated JavaScript.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="vi">@columnMap = </span><span class="p">{}</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-3">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<div class="pilwrap for-h2">
|
||||
<a class="pilcrow" href="#section-3">¶</a>
|
||||
</div>
|
||||
|
||||
<p>columnMappings is an array of all column mappings, sorted by generated-column.
|
||||
|
||||
</p>
|
||||
<h2>LineMap</h2>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="vi">@columnMappings = </span><span class="p">[]</span>
|
||||
|
||||
<span class="nv">addMapping: </span><span class="nf">(generatedColumn, [sourceLine, sourceColumn], options={}) -></span>
|
||||
<span class="k">if</span> <span class="nx">@columnMap</span><span class="p">[</span><span class="nx">generatedColumn</span><span class="p">]</span> <span class="o">and</span> <span class="nx">options</span><span class="p">.</span><span class="nx">noReplace</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -167,60 +157,36 @@
|
||||
<a class="pilcrow" href="#section-4">¶</a>
|
||||
</div>
|
||||
|
||||
<p>We already have a mapping for this column.
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="k">return</span>
|
||||
|
||||
<span class="nx">@columnMap</span><span class="p">[</span><span class="nx">generatedColumn</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="nv">generatedLine: </span><span class="nx">@generatedLine</span>
|
||||
<span class="nx">generatedColumn</span>
|
||||
<span class="nx">sourceLine</span>
|
||||
<span class="nx">sourceColumn</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="nx">@columnMappings</span><span class="p">.</span><span class="nx">push</span> <span class="nx">@columnMap</span><span class="p">[</span><span class="nx">generatedColumn</span><span class="p">]</span>
|
||||
<span class="nx">@columnMappings</span><span class="p">.</span><span class="nx">sort</span> <span class="nf">(a,b) -></span> <span class="nx">a</span><span class="p">.</span><span class="nx">generatedColumn</span> <span class="o">-</span> <span class="nx">b</span><span class="p">.</span><span class="nx">generatedColumn</span>
|
||||
|
||||
<span class="nv">getSourcePosition: </span><span class="nf">(generatedColumn) -></span>
|
||||
<span class="nv">answer = </span><span class="kc">null</span>
|
||||
<span class="nv">lastColumnMapping = </span><span class="kc">null</span>
|
||||
<span class="k">for</span> <span class="nx">columnMapping</span> <span class="k">in</span> <span class="nx">@columnMappings</span>
|
||||
<span class="k">if</span> <span class="nx">columnMapping</span><span class="p">.</span><span class="nx">generatedColumn</span> <span class="o">></span> <span class="nx">generatedColumn</span>
|
||||
<span class="k">break</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">lastColumnMapping = </span><span class="nx">columnMapping</span>
|
||||
<span class="k">if</span> <span class="nx">lastColumnMapping</span>
|
||||
<span class="nv">answer = </span><span class="p">[</span><span class="nx">lastColumnMapping</span><span class="p">.</span><span class="nx">sourceLine</span><span class="p">,</span> <span class="nx">lastColumnMapping</span><span class="p">.</span><span class="nx">sourceColumn</span><span class="p">]</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-5">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap for-h3">
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-5">¶</a>
|
||||
</div>
|
||||
|
||||
<h3>SourceMap</h3>
|
||||
<p>Maps locations in a generated source file back to locations in the original source file.
|
||||
|
||||
</p>
|
||||
<p>This is intentionally agnostic towards how a source map might be represented on disk. A
|
||||
SourceMap can be converted to a "v3" style sourcemap with <code>#generateV3SourceMap()</code>, for example
|
||||
but the SourceMap class itself knows nothing about v3 source maps.
|
||||
|
||||
|
||||
<p>A <strong>LineMap</strong> object keeps track of information about original line and column
|
||||
positions for a single line of output JavaScript code.
|
||||
<strong>SourceMaps</strong> are implemented in terms of <strong>LineMaps</strong>.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="k">class</span> <span class="nx">exports</span><span class="p">.</span><span class="nx">SourceMap</span>
|
||||
<span class="nv">constructor: </span><span class="p">()</span> <span class="nf">-></span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
<span class="class"><span class="keyword">class</span> <span class="title">LineMap</span></span>
|
||||
constructor: (<span class="property">@line</span>) ->
|
||||
<span class="property">@columns</span> = []
|
||||
|
||||
add: (column, [sourceLine, sourceColumn], options={}) ->
|
||||
<span class="keyword">return</span> <span class="keyword">if</span> <span class="property">@columns</span>[column] <span class="keyword">and</span> options.noReplace
|
||||
<span class="property">@columns</span>[column] = {line: <span class="property">@line</span>, column, sourceLine, sourceColumn}
|
||||
|
||||
sourceLocation: (column) ->
|
||||
column-- <span class="keyword">until</span> (mapping = <span class="property">@columns</span>[column]) <span class="keyword">or</span> (column <= <span class="number">0</span>)
|
||||
mapping <span class="keyword">and</span> [mapping.sourceLine, mapping.sourceColumn]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -228,18 +194,13 @@ but the SourceMap class itself knows nothing about v3 source maps.
|
||||
<li id="section-6">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<div class="pilwrap for-h2">
|
||||
<a class="pilcrow" href="#section-6">¶</a>
|
||||
</div>
|
||||
|
||||
<p><code>generatedLines</code> is an array of LineMappings, one per generated line.
|
||||
|
||||
</p>
|
||||
<h2>SourceMap</h2>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="vi">@generatedLines = </span><span class="p">[]</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -250,28 +211,8 @@ but the SourceMap class itself knows nothing about v3 source maps.
|
||||
<a class="pilcrow" href="#section-7">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Adds a mapping to this SourceMap.
|
||||
|
||||
</p>
|
||||
<p><code>sourceLocation</code> and <code>generatedLocation</code> are both [line, column] arrays.
|
||||
|
||||
</p>
|
||||
<p>If <code>options.noReplace</code> is true, then if there is already a mapping for
|
||||
the specified <code>generatedLine</code> and <code>generatedColumn</code>, this will have no effect.
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">addMapping: </span><span class="nf">(sourceLocation, generatedLocation, options={}) -></span>
|
||||
<span class="p">[</span><span class="nx">generatedLine</span><span class="p">,</span> <span class="nx">generatedColumn</span><span class="p">]</span> <span class="o">=</span> <span class="nx">generatedLocation</span>
|
||||
|
||||
<span class="nv">lineMapping = </span><span class="nx">@generatedLines</span><span class="p">[</span><span class="nx">generatedLine</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="o">not</span> <span class="nx">lineMapping</span>
|
||||
<span class="nv">lineMapping = </span><span class="nx">@generatedLines</span><span class="p">[</span><span class="nx">generatedLine</span><span class="p">]</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">LineMapping</span><span class="p">(</span><span class="nx">generatedLine</span><span class="p">)</span>
|
||||
|
||||
<span class="nx">lineMapping</span><span class="p">.</span><span class="nx">addMapping</span> <span class="nx">generatedColumn</span><span class="p">,</span> <span class="nx">sourceLocation</span><span class="p">,</span> <span class="nx">options</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -281,18 +222,12 @@ the specified <code>generatedLine</code> and <code>generatedColumn</code>, this
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-8">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Returns [sourceLine, sourceColumn], or null if no mapping could be found.
|
||||
|
||||
<p>Maps locations in a single generated JavaScript file back to locations in
|
||||
the original CoffeeScript source file.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">getSourcePosition: </span><span class="nf">([generatedLine, generatedColumn]) -></span>
|
||||
<span class="nv">answer = </span><span class="kc">null</span>
|
||||
<span class="nv">lineMapping = </span><span class="nx">@generatedLines</span><span class="p">[</span><span class="nx">generatedLine</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="o">not</span> <span class="nx">lineMapping</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -302,17 +237,17 @@ the specified <code>generatedLine</code> and <code>generatedColumn</code>, this
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-9">¶</a>
|
||||
</div>
|
||||
|
||||
<p>TODO: Search backwards for the line?
|
||||
|
||||
<p>This is intentionally agnostic towards how a source map might be represented on
|
||||
disk. Once the compiler is ready to produce a "v3"-style source map, we can walk
|
||||
through the arrays of line and column buffer to produce it.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="k">else</span>
|
||||
<span class="nv">answer = </span><span class="nx">lineMapping</span><span class="p">.</span><span class="nx">getSourcePosition</span> <span class="nx">generatedColumn</span>
|
||||
|
||||
<span class="nx">answer</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
<span class="class"><span class="keyword">class</span> <span class="title">SourceMap</span></span>
|
||||
constructor: ->
|
||||
<span class="property">@lines</span> = []</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -323,21 +258,19 @@ the specified <code>generatedLine</code> and <code>generatedColumn</code>, this
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-10">¶</a>
|
||||
</div>
|
||||
|
||||
<p><code>fn</code> will be called once for every recorded mapping, in the order in
|
||||
which they occur in the generated source. <code>fn</code> will be passed an object
|
||||
with four properties: sourceLine, sourceColumn, generatedLine, and
|
||||
generatedColumn.
|
||||
|
||||
<p>Adds a mapping to this SourceMap. <code>sourceLocation</code> and <code>generatedLocation</code>
|
||||
are both <code>[line, column]</code> arrays. If <code>options.noReplace</code> is true, then if there
|
||||
is already a mapping for the specified <code>line</code> and <code>column</code>, this will have no
|
||||
effect.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">forEachMapping: </span><span class="nf">(fn) -></span>
|
||||
<span class="k">for</span> <span class="nx">lineMapping</span><span class="p">,</span> <span class="nx">generatedLineNumber</span> <span class="k">in</span> <span class="nx">@generatedLines</span>
|
||||
<span class="k">if</span> <span class="nx">lineMapping</span>
|
||||
<span class="k">for</span> <span class="nx">columnMapping</span> <span class="k">in</span> <span class="nx">lineMapping</span><span class="p">.</span><span class="nx">columnMappings</span>
|
||||
<span class="nx">fn</span><span class="p">(</span><span class="nx">columnMapping</span><span class="p">)</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
add: (sourceLocation, generatedLocation, options = {}) ->
|
||||
[line, column] = generatedLocation
|
||||
lineMap = (<span class="property">@lines</span>[line] <span class="keyword">or</span>= <span class="keyword">new</span> LineMap(line))
|
||||
lineMap.add column, sourceLocation, options</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -345,34 +278,19 @@ generatedColumn.
|
||||
<li id="section-11">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap for-h3">
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
</div>
|
||||
|
||||
<h3>generateV3SourceMap</h3>
|
||||
<p>Builds a V3 source map from a SourceMap object.
|
||||
Returns the generated JSON as a string.
|
||||
|
||||
|
||||
<p>Look up the original position of a given <code>line</code> and <code>column</code> in the generated
|
||||
code.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.generateV3SourceMap = </span><span class="nf">(sourceMap, sourceFile=null, generatedFile=null) -></span>
|
||||
<span class="nv">writingGeneratedLine = </span><span class="mi">0</span>
|
||||
<span class="nv">lastGeneratedColumnWritten = </span><span class="mi">0</span>
|
||||
<span class="nv">lastSourceLineWritten = </span><span class="mi">0</span>
|
||||
<span class="nv">lastSourceColumnWritten = </span><span class="mi">0</span>
|
||||
<span class="nv">needComma = </span><span class="kc">no</span>
|
||||
|
||||
<span class="nv">mappings = </span><span class="s">""</span>
|
||||
|
||||
<span class="nx">sourceMap</span><span class="p">.</span><span class="nx">forEachMapping</span> <span class="nf">(mapping) -></span>
|
||||
<span class="k">while</span> <span class="nx">writingGeneratedLine</span> <span class="o"><</span> <span class="nx">mapping</span><span class="p">.</span><span class="nx">generatedLine</span>
|
||||
<span class="nv">lastGeneratedColumnWritten = </span><span class="mi">0</span>
|
||||
<span class="nv">needComma = </span><span class="kc">no</span>
|
||||
<span class="nx">mappings</span> <span class="o">+=</span> <span class="s">";"</span>
|
||||
<span class="nx">writingGeneratedLine</span><span class="o">++</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
sourceLocation: ([line, column]) ->
|
||||
line-- <span class="keyword">until</span> (lineMap = <span class="property">@lines</span>[line]) <span class="keyword">or</span> (line <= <span class="number">0</span>)
|
||||
lineMap <span class="keyword">and</span> lineMap.sourceLocation column</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -380,20 +298,13 @@ Returns the generated JSON as a string.
|
||||
<li id="section-12">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<div class="pilwrap for-h2">
|
||||
<a class="pilcrow" href="#section-12">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Write a comma if we've already written a segment on this line.
|
||||
|
||||
</p>
|
||||
<h2>V3 SourceMap Generation</h2>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="k">if</span> <span class="nx">needComma</span>
|
||||
<span class="nx">mappings</span> <span class="o">+=</span> <span class="s">","</span>
|
||||
<span class="nv">needComma = </span><span class="kc">no</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -404,28 +315,8 @@ Returns the generated JSON as a string.
|
||||
<a class="pilcrow" href="#section-13">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Write the next segment.
|
||||
Segments can be 1, 4, or 5 values. If just one, then it is a generated column which
|
||||
doesn't match anything in the source code.
|
||||
|
||||
</p>
|
||||
<p>Fields are all zero-based, and relative to the previous occurence unless otherwise noted:
|
||||
<em> starting-column in generated source, relative to previous occurence for the current line.
|
||||
</em> index into the "sources" list
|
||||
<em> starting line in the original source
|
||||
</em> starting column in the original source
|
||||
* index into the "names" list associated with this segment.
|
||||
|
||||
</p>
|
||||
<p>Add the generated start-column
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nx">mappings</span> <span class="o">+=</span> <span class="nx">exports</span><span class="p">.</span><span class="nx">vlqEncodeValue</span><span class="p">(</span><span class="nx">mapping</span><span class="p">.</span><span class="nx">generatedColumn</span> <span class="o">-</span> <span class="nx">lastGeneratedColumnWritten</span><span class="p">)</span>
|
||||
<span class="nv">lastGeneratedColumnWritten = </span><span class="nx">mapping</span><span class="p">.</span><span class="nx">generatedColumn</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -435,14 +326,30 @@ doesn't match anything in the source code.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-14">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Add the index into the sources list
|
||||
|
||||
<p>Builds up a V3 source map, returning the generated JSON as a string.
|
||||
<code>options.sourceRoot</code> may be used to specify the sourceRoot written to the source
|
||||
map. Also, <code>options.sourceFiles</code> and <code>options.generatedFile</code> may be passed to
|
||||
set "sources" and "file", respectively.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nx">mappings</span> <span class="o">+=</span> <span class="nx">exports</span><span class="p">.</span><span class="nx">vlqEncodeValue</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
generate: (options = {}, code = <span class="literal">null</span>) ->
|
||||
writingline = <span class="number">0</span>
|
||||
lastColumn = <span class="number">0</span>
|
||||
lastSourceLine = <span class="number">0</span>
|
||||
lastSourceColumn = <span class="number">0</span>
|
||||
needComma = <span class="literal">no</span>
|
||||
buffer = <span class="string">""</span>
|
||||
|
||||
<span class="keyword">for</span> lineMap, lineNumber <span class="keyword">in</span> <span class="property">@lines</span> <span class="keyword">when</span> lineMap
|
||||
<span class="keyword">for</span> mapping <span class="keyword">in</span> lineMap.columns <span class="keyword">when</span> mapping
|
||||
<span class="keyword">while</span> writingline < mapping.line
|
||||
lastColumn = <span class="number">0</span>
|
||||
needComma = <span class="literal">no</span>
|
||||
buffer += <span class="string">";"</span>
|
||||
writingline++</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -453,15 +360,15 @@ doesn't match anything in the source code.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-15">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Add the source start-line
|
||||
|
||||
<p>Write a comma if we've already written a segment on this line.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nx">mappings</span> <span class="o">+=</span> <span class="nx">exports</span><span class="p">.</span><span class="nx">vlqEncodeValue</span><span class="p">(</span><span class="nx">mapping</span><span class="p">.</span><span class="nx">sourceLine</span> <span class="o">-</span> <span class="nx">lastSourceLineWritten</span><span class="p">)</span>
|
||||
<span class="nv">lastSourceLineWritten = </span><span class="nx">mapping</span><span class="p">.</span><span class="nx">sourceLine</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
<span class="keyword">if</span> needComma
|
||||
buffer += <span class="string">","</span>
|
||||
needComma = <span class="literal">no</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -472,16 +379,12 @@ doesn't match anything in the source code.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-16">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Add the source start-column
|
||||
|
||||
<p>Write the next segment. Segments can be 1, 4, or 5 values. If just one, then it
|
||||
is a generated column which doesn't match anything in the source code.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nx">mappings</span> <span class="o">+=</span> <span class="nx">exports</span><span class="p">.</span><span class="nx">vlqEncodeValue</span><span class="p">(</span><span class="nx">mapping</span><span class="p">.</span><span class="nx">sourceColumn</span> <span class="o">-</span> <span class="nx">lastSourceColumnWritten</span><span class="p">)</span>
|
||||
<span class="nv">lastSourceColumnWritten = </span><span class="nx">mapping</span><span class="p">.</span><span class="nx">sourceColumn</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -491,26 +394,15 @@ doesn't match anything in the source code.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
</div>
|
||||
|
||||
<p>TODO: Do we care about symbol names for CoffeeScript? Probably not.
|
||||
|
||||
|
||||
<p>The starting column in the generated source, relative to any previous recorded
|
||||
column for the current line:
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">needComma = </span><span class="kc">yes</span>
|
||||
|
||||
<span class="nv">answer = </span><span class="p">{</span>
|
||||
<span class="nv">version: </span><span class="mi">3</span>
|
||||
<span class="nv">file: </span><span class="nx">generatedFile</span>
|
||||
<span class="nv">sourceRoot: </span><span class="s">""</span>
|
||||
<span class="nv">sources: </span><span class="k">if</span> <span class="nx">sourceFile</span> <span class="k">then</span> <span class="p">[</span><span class="nx">sourceFile</span><span class="p">]</span> <span class="k">else</span> <span class="p">[]</span>
|
||||
<span class="nv">names: </span><span class="p">[]</span>
|
||||
<span class="nx">mappings</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="k">return</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span> <span class="nx">answer</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="mi">2</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
buffer += <span class="property">@encodeVlq</span> mapping.column - lastColumn
|
||||
lastColumn = mapping.column</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -521,15 +413,13 @@ doesn't match anything in the source code.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-18">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Load a SourceMap from a JSON string. Returns the SourceMap object.
|
||||
|
||||
<p>The index into the list of sources:
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.loadV3SourceMap = </span><span class="nf">(sourceMap) -></span>
|
||||
<span class="nx">todo</span><span class="p">()</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
buffer += <span class="property">@encodeVlq</span> <span class="number">0</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -537,29 +427,17 @@ doesn't match anything in the source code.
|
||||
<li id="section-19">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap for-h3">
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-19">¶</a>
|
||||
</div>
|
||||
|
||||
<h3>Base64 encoding helpers</h3>
|
||||
<p>The starting line in the original source, relative to the previous source line.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">BASE64_CHARS = </span><span class="s">'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'</span>
|
||||
<span class="nv">MAX_BASE64_VALUE = </span><span class="nx">BASE64_CHARS</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
|
||||
|
||||
<span class="nv">encodeBase64Char = </span><span class="nf">(value) -></span>
|
||||
<span class="k">if</span> <span class="nx">value</span> <span class="o">></span> <span class="nx">MAX_BASE64_VALUE</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s">"Cannot encode value </span><span class="si">#{</span><span class="nx">value</span><span class="si">}</span><span class="s"> > </span><span class="si">#{</span><span class="nx">MAX_BASE64_VALUE</span><span class="si">}</span><span class="s">"</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">value</span> <span class="o"><</span> <span class="mi">0</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s">"Cannot encode value </span><span class="si">#{</span><span class="nx">value</span><span class="si">}</span><span class="s"> < 0"</span>
|
||||
<span class="nx">BASE64_CHARS</span><span class="p">[</span><span class="nx">value</span><span class="p">]</span>
|
||||
|
||||
<span class="nv">decodeBase64Char = </span><span class="nf">(char) -></span>
|
||||
<span class="nv">value = </span><span class="nx">BASE64_CHARS</span><span class="p">.</span><span class="nx">indexOf</span> <span class="nx">char</span>
|
||||
<span class="k">if</span> <span class="nx">value</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s">"Invalid Base 64 character: </span><span class="si">#{</span><span class="nx">char</span><span class="si">}</span><span class="s">"</span>
|
||||
<span class="nx">value</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
buffer += <span class="property">@encodeVlq</span> mapping.sourceLine - lastSourceLine
|
||||
lastSourceLine = mapping.sourceLine</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -567,25 +445,18 @@ doesn't match anything in the source code.
|
||||
<li id="section-20">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap for-h3">
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-20">¶</a>
|
||||
</div>
|
||||
|
||||
<h3>Base 64 VLQ encoding/decoding helpers</h3>
|
||||
<p>Note that SourceMap VLQ encoding is "backwards". MIDI style VLQ encoding puts the
|
||||
most-significant-bit (MSB) from the original value into the MSB of the VLQ encoded value
|
||||
(see <a href="http://en.wikipedia.org/wiki/File:Uintvar_coding.svg">http://en.wikipedia.org/wiki/File:Uintvar_coding.svg</a>). SourceMap VLQ does things
|
||||
the other way around, with the least significat four bits of the original value encoded
|
||||
into the first byte of the VLQ encoded value.
|
||||
|
||||
|
||||
<p>The starting column in the original source, relative to the previous column.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">VLQ_SHIFT = </span><span class="mi">5</span>
|
||||
<span class="nv">VLQ_CONTINUATION_BIT = </span><span class="mi">1</span> <span class="o"><<</span> <span class="nx">VLQ_SHIFT</span> <span class="c1"># 0010 0000</span>
|
||||
<span class="nv">VLQ_VALUE_MASK = </span><span class="nx">VLQ_CONTINUATION_BIT</span> <span class="o">-</span> <span class="mi">1</span> <span class="c1"># 0001 1111</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
buffer += <span class="property">@encodeVlq</span> mapping.sourceColumn - lastSourceColumn
|
||||
lastSourceColumn = mapping.sourceColumn
|
||||
needComma = <span class="literal">yes</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -596,14 +467,23 @@ into the first byte of the VLQ encoded value.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-21">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Encode a value as Base 64 VLQ.
|
||||
|
||||
<p>Produce the canonical JSON object format for a "v3" source map.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.vlqEncodeValue = </span><span class="nf">(value) -></span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
v3 =
|
||||
version: <span class="number">3</span>
|
||||
file: options.generatedFile <span class="keyword">or</span> <span class="string">''</span>
|
||||
sourceRoot: options.sourceRoot <span class="keyword">or</span> <span class="string">''</span>
|
||||
sources: options.sourceFiles <span class="keyword">or</span> [<span class="string">''</span>]
|
||||
names: []
|
||||
mappings: buffer
|
||||
|
||||
v3.sourcesContent = [code] <span class="keyword">if</span> options.inline
|
||||
|
||||
JSON.stringify v3, <span class="literal">null</span>, <span class="number">2</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -611,18 +491,13 @@ into the first byte of the VLQ encoded value.
|
||||
<li id="section-22">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<div class="pilwrap for-h2">
|
||||
<a class="pilcrow" href="#section-22">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Least significant bit represents the sign.
|
||||
|
||||
</p>
|
||||
<h2>Base64 VLQ Encoding</h2>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">signBit = </span><span class="k">if</span> <span class="nx">value</span> <span class="o"><</span> <span class="mi">0</span> <span class="k">then</span> <span class="mi">1</span> <span class="k">else</span> <span class="mi">0</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -633,16 +508,8 @@ into the first byte of the VLQ encoded value.
|
||||
<a class="pilcrow" href="#section-23">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Next bits are the actual value
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">valueToEncode = </span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">abs</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="o"><<</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="nx">signBit</span>
|
||||
|
||||
<span class="nv">answer = </span><span class="s">""</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -652,23 +519,22 @@ into the first byte of the VLQ encoded value.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-24">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Make sure we encode at least one character, even if valueToEncode is 0.
|
||||
|
||||
<p>Note that SourceMap VLQ encoding is "backwards". MIDI-style VLQ encoding puts
|
||||
the most-significant-bit (MSB) from the original value into the MSB of the VLQ
|
||||
encoded value (see <a href="http://en.wikipedia.org/wiki/File:Uintvar_coding.svg">Wikipedia</a>).
|
||||
SourceMap VLQ does things the other way around, with the least significat four
|
||||
bits of the original value encoded into the first byte of the VLQ encoded value.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="k">while</span> <span class="nx">valueToEncode</span> <span class="o">||</span> <span class="o">!</span><span class="nx">answer</span>
|
||||
<span class="nv">nextVlqChunk = </span><span class="nx">valueToEncode</span> <span class="o">&</span> <span class="nx">VLQ_VALUE_MASK</span>
|
||||
<span class="nv">valueToEncode = </span><span class="nx">valueToEncode</span> <span class="o">>></span> <span class="nx">VLQ_SHIFT</span>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
VLQ_SHIFT = <span class="number">5</span>
|
||||
VLQ_CONTINUATION_BIT = <span class="number">1</span> << VLQ_SHIFT <span class="comment"># 0010 0000</span>
|
||||
VLQ_VALUE_MASK = VLQ_CONTINUATION_BIT - <span class="number">1</span> <span class="comment"># 0001 1111</span>
|
||||
|
||||
<span class="k">if</span> <span class="nx">valueToEncode</span>
|
||||
<span class="nx">nextVlqChunk</span> <span class="o">|=</span> <span class="nx">VLQ_CONTINUATION_BIT</span>
|
||||
|
||||
<span class="nx">answer</span> <span class="o">+=</span> <span class="nx">encodeBase64Char</span><span class="p">(</span><span class="nx">nextVlqChunk</span><span class="p">)</span>
|
||||
|
||||
<span class="k">return</span> <span class="nx">answer</span></pre></div></div>
|
||||
encodeVlq: (value) ->
|
||||
answer = <span class="string">''</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -679,32 +545,12 @@ into the first byte of the VLQ encoded value.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-25">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Decode a Base 64 VLQ value.
|
||||
|
||||
</p>
|
||||
<p>Returns <code>[value, consumed]</code> where <code>value</code> is the decoded value, and <code>consumed</code> is the number
|
||||
of characters consumed from <code>str</code>.
|
||||
|
||||
<p>Least significant bit represents the sign.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre><span class="nv">exports.vlqDecodeValue = </span><span class="nf">(str, offset=0) -></span>
|
||||
<span class="nv">position = </span><span class="nx">offset</span>
|
||||
<span class="nv">done = </span><span class="kc">false</span>
|
||||
|
||||
<span class="nv">value = </span><span class="mi">0</span>
|
||||
<span class="nv">continuationShift = </span><span class="mi">0</span>
|
||||
|
||||
<span class="k">while</span> <span class="o">!</span><span class="nx">done</span>
|
||||
<span class="nv">nextVlqChunk = </span><span class="nx">decodeBase64Char</span><span class="p">(</span><span class="nx">str</span><span class="p">[</span><span class="nx">position</span><span class="p">])</span>
|
||||
<span class="nx">position</span> <span class="o">+=</span> <span class="mi">1</span>
|
||||
|
||||
<span class="nv">nextChunkValue = </span><span class="nx">nextVlqChunk</span> <span class="o">&</span> <span class="nx">VLQ_VALUE_MASK</span>
|
||||
<span class="nx">value</span> <span class="o">+=</span> <span class="p">(</span><span class="nx">nextChunkValue</span> <span class="o"><<</span> <span class="nx">continuationShift</span><span class="p">)</span>
|
||||
|
||||
<span class="k">if</span> <span class="o">!</span><span class="p">(</span><span class="nx">nextVlqChunk</span> <span class="o">&</span> <span class="nx">VLQ_CONTINUATION_BIT</span><span class="p">)</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> signBit = <span class="keyword">if</span> value < <span class="number">0</span> <span class="keyword">then</span> <span class="number">1</span> <span class="keyword">else</span> <span class="number">0</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -715,14 +561,12 @@ of characters consumed from <code>str</code>.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-26">¶</a>
|
||||
</div>
|
||||
|
||||
<p>We'll be done after this character.
|
||||
|
||||
<p>The next bits are the actual value.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">done = </span><span class="kc">true</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> valueToEncode = (Math.abs(value) << <span class="number">1</span>) + signBit</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -733,17 +577,18 @@ of characters consumed from <code>str</code>.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-27">¶</a>
|
||||
</div>
|
||||
|
||||
<p>Bits are encoded least-significant first (opposite of MIDI VLQ). Increase the
|
||||
continuationShift, so the next byte will end up where it should in the value.
|
||||
|
||||
<p>Make sure we encode at least one character, even if valueToEncode is 0.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nx">continuationShift</span> <span class="o">+=</span> <span class="nx">VLQ_SHIFT</span>
|
||||
<div class="content"><div class='highlight'><pre> <span class="keyword">while</span> valueToEncode <span class="keyword">or</span> <span class="keyword">not</span> answer
|
||||
nextChunk = valueToEncode & VLQ_VALUE_MASK
|
||||
valueToEncode = valueToEncode >> VLQ_SHIFT
|
||||
nextChunk |= VLQ_CONTINUATION_BIT <span class="keyword">if</span> valueToEncode
|
||||
answer += <span class="property">@encodeBase64</span> nextChunk
|
||||
|
||||
<span class="nv">consumed = </span><span class="nx">position</span> <span class="o">-</span> <span class="nx">offset</span></pre></div></div>
|
||||
answer</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -751,23 +596,47 @@ continuationShift, so the next byte will end up where it should in the value.
|
||||
<li id="section-28">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<div class="pilwrap for-h2">
|
||||
<a class="pilcrow" href="#section-28">¶</a>
|
||||
</div>
|
||||
<h2>Regular Base64 Encoding</h2>
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-29">
|
||||
<div class="annotation">
|
||||
|
||||
<p>Least significant bit represents the sign.
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-29">¶</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
BASE64_CHARS = <span class="string">'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'</span>
|
||||
|
||||
encodeBase64: (value) ->
|
||||
BASE64_CHARS[value] <span class="keyword">or</span> <span class="keyword">throw</span> <span class="keyword">new</span> Error <span class="string">"Cannot Base64 encode value: <span class="subst">#{value}</span>"</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-30">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-30">¶</a>
|
||||
</div>
|
||||
<p>Our API for source maps is just the <code>SourceMap</code> class.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class="highlight"><pre> <span class="nv">signBit = </span><span class="nx">value</span> <span class="o">&</span> <span class="mi">1</span>
|
||||
<span class="nv">value = </span><span class="nx">value</span> <span class="o">>></span> <span class="mi">1</span>
|
||||
|
||||
<span class="k">if</span> <span class="nx">signBit</span> <span class="k">then</span> <span class="nv">value = </span><span class="o">-</span><span class="nx">value</span>
|
||||
|
||||
<span class="k">return</span> <span class="p">[</span><span class="nx">value</span><span class="p">,</span> <span class="nx">consumed</span><span class="p">]</span>
|
||||
|
||||
</pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre>
|
||||
module.exports = SourceMap</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
295
documentation/docs/underscore.html
Normal file
295
documentation/docs/underscore.html
Normal file
File diff suppressed because one or more lines are too long
@@ -131,15 +131,13 @@
|
||||
compiles one-to-one into the equivalent JS, and there is
|
||||
no interpretation at runtime. You can use any existing JavaScript library
|
||||
seamlessly from CoffeeScript (and vice-versa). The compiled output is
|
||||
readable and pretty-printed, passes through
|
||||
<a href="http://www.javascriptlint.com/">JavaScript Lint</a>
|
||||
without warnings, will work in every JavaScript runtime, and tends
|
||||
readable and pretty-printed, will work in every JavaScript runtime, and tends
|
||||
to run as fast or faster than the equivalent handwritten JavaScript.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Latest Version:</b>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/1.6.1">1.6.1</a>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/1.6.3">1.6.3</a>
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -266,16 +264,6 @@ sudo bin/cake install</pre>
|
||||
directly to <b>stdout</b>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-l, --lint</code></td>
|
||||
<td>
|
||||
If the <tt>jsl</tt>
|
||||
(<a href="http://www.javascriptlint.com/">JavaScript Lint</a>)
|
||||
command is installed, use it
|
||||
to check the compilation of a CoffeeScript file. (Handy in
|
||||
conjunction with <br /> <tt>--watch</tt>)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-s, --stdio</code></td>
|
||||
<td>
|
||||
@@ -284,6 +272,14 @@ sudo bin/cake install</pre>
|
||||
<tt>cat src/cake.coffee | coffee -sc</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-l, --literate</code></td>
|
||||
<td>
|
||||
Parses the code as Literate CoffeeScript. You only need to specify
|
||||
this when passing in code directly over <b>stdio</b>, or using some sort
|
||||
of extension-less file name.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-e, --eval</code></td>
|
||||
<td>
|
||||
@@ -291,13 +287,6 @@ sudo bin/cake install</pre>
|
||||
command line. For example:<br /><tt>coffee -e "console.log num for num in [10..1]"</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-r, --require</code></td>
|
||||
<td>
|
||||
Load a library before compiling or executing your script. Can be used
|
||||
to hook in to the compiler (to add Growl notifications, for example).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-b, --bare</code></td>
|
||||
<td>
|
||||
@@ -812,6 +801,11 @@ Expressions
|
||||
Destructuring assignment can even be combined with splats.
|
||||
</p>
|
||||
<%= code_for('patterns_and_splats', 'contents.join("")') %>
|
||||
<p>
|
||||
Destructuring assignment is also useful when combined with class constructors
|
||||
to assign properties to your instance from an options object passed to the constructor.
|
||||
</p>
|
||||
<%= code_for('constructor_destructuring', 'contents.join("")') %>
|
||||
|
||||
<p>
|
||||
<span id="fat-arrow" class="bookmark"></span>
|
||||
@@ -869,6 +863,11 @@ Expressions
|
||||
</p>
|
||||
<%= code_for('switch') %>
|
||||
|
||||
<p>
|
||||
Switch statements can also be used without a control expression, turning them in to a cleaner alternative to if/else chains.
|
||||
</p>
|
||||
<%= code_for('switch_with_no_expression') %>
|
||||
|
||||
<p>
|
||||
<span id="try" class="bookmark"></span>
|
||||
<b class="header">Try/Catch/Finally</b>
|
||||
@@ -922,7 +921,7 @@ Expressions
|
||||
<b class="header">Block Regular Expressions</b>
|
||||
Similar to block strings and comments, CoffeeScript supports block regexes —
|
||||
extended regular expressions that ignore internal whitespace and can contain
|
||||
comments and interpolation. Modeled after Perl's <tt>/x</tt> modifier, CoffeeSctipt's
|
||||
comments and interpolation. Modeled after Perl's <tt>/x</tt> modifier, CoffeeScript's
|
||||
block regexes are delimited by <tt>///</tt> and go a long way towards making complex
|
||||
regular expressions readable. To quote from the CoffeeScript source:
|
||||
</p>
|
||||
@@ -1165,6 +1164,13 @@ Expressions
|
||||
<a href="http://github.com/jashkenas/coffee-script/wiki/FAQ">The FAQ</a><br />
|
||||
Perhaps your CoffeeScript-related question has been asked before. Check the FAQ first.
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://js2coffee.org">JS2Coffee</a><br />
|
||||
Is a very well done reverse JavaScript-to-CoffeeScript compiler. It's
|
||||
not going to be perfect (infer what your JavaScript classes are, when
|
||||
you need bound functions, and so on...) — but it's a great starting
|
||||
point for converting simple scripts.
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/jashkenas/coffee-script/downloads">High-Rez Logo</a><br />
|
||||
The CoffeeScript logo is available in Illustrator, EPS and PSD formats, for use
|
||||
@@ -1192,6 +1198,64 @@ Expressions
|
||||
Change Log
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">
|
||||
<a href="https://github.com/jashkenas/coffee-script/compare/1.6.2...1.6.3">1.6.3</a>
|
||||
<span class="timestamp"> – <small>June 2, 2013</small></span>
|
||||
</b>
|
||||
<ul>
|
||||
<li>
|
||||
The CoffeeScript REPL now remembers your history between sessions.
|
||||
Just like a proper REPL should.
|
||||
</li>
|
||||
<li>
|
||||
You can now use <tt>require</tt> in Node to load <tt>.coffee.md</tt>
|
||||
Literate CoffeeScript files. In the browser,
|
||||
<tt>text/literate-coffeescript</tt> script tags.
|
||||
</li>
|
||||
<li>
|
||||
The old <tt>coffee --lint</tt> command has been removed. It was useful
|
||||
while originally working on the compiler, but has been surpassed by
|
||||
JSHint. You may now use <tt>-l</tt> to pass literate files in over
|
||||
<b>stdio</b>.
|
||||
</li>
|
||||
<li>
|
||||
Bugfixes for Windows path separators, <tt>catch</tt> without naming
|
||||
the error, and executable-class-bodies-with-
|
||||
prototypal-property-attachment.
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">
|
||||
<a href="https://github.com/jashkenas/coffee-script/compare/1.6.1...1.6.2">1.6.2</a>
|
||||
<span class="timestamp"> – <small>March 18, 2013</small></span>
|
||||
</b>
|
||||
<ul>
|
||||
<li>
|
||||
Source maps have been used to provide automatic line-mapping when
|
||||
running CoffeeScript directly via the <tt>coffee</tt> command, and
|
||||
for automatic line-mapping when running CoffeeScript directly in the
|
||||
browser. Also, to provide better error messages for semantic errors
|
||||
thrown by the compiler —
|
||||
<a href="http://cl.ly/NdOA">with colors, even</a>.
|
||||
</li>
|
||||
<li>
|
||||
Improved support for mixed literate/vanilla-style CoffeeScript projects,
|
||||
and generating source maps for both at the same time.
|
||||
</li>
|
||||
<li>
|
||||
Fixes for <b>1.6.x</b> regressions with overriding inherited bound
|
||||
functions, and for Windows file path management.
|
||||
</li>
|
||||
<li>
|
||||
The <tt>coffee</tt> command can now correctly <tt>fork()</tt>
|
||||
both <tt>.coffee</tt> and <tt>.js</tt> files. (Requires Node.js 0.9+)
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">
|
||||
<a href="https://github.com/jashkenas/coffee-script/compare/1.5.0...1.6.1">1.6.1</a>
|
||||
@@ -1939,8 +2003,10 @@ Expressions
|
||||
else
|
||||
$(el).text window.compiledJS
|
||||
$('#error').hide()
|
||||
catch error
|
||||
$('#error').text(error.message).show()
|
||||
catch {location, message}
|
||||
if location?
|
||||
message = "Error on line #{location.first_line + 1}: #{message}"
|
||||
$('#error').text(message).show()
|
||||
|
||||
# Update permalink
|
||||
$('#repl_permalink').attr 'href', "##{sourceFragment}#{encodeURIComponent source}"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var volume, winner;
|
||||
|
||||
if (ignition === true) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var courses, dish, food, foods, i, _i, _j, _k, _len, _len1, _len2, _ref;
|
||||
|
||||
_ref = ['toast', 'cheese', 'wine'];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
/*
|
||||
CoffeeScript Compiler v1.6.1
|
||||
SkinnyMochaHalfCaffScript Compiler v1.0
|
||||
Released under the MIT License
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var fs;
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
var Animal, Horse, Snake, sam, tom,
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var Animal, Horse, Snake, sam, tom, _ref, _ref1,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Animal = (function() {
|
||||
|
||||
function Animal(name) {
|
||||
this.name = name;
|
||||
}
|
||||
@@ -18,11 +17,11 @@ Animal = (function() {
|
||||
})();
|
||||
|
||||
Snake = (function(_super) {
|
||||
|
||||
__extends(Snake, _super);
|
||||
|
||||
function Snake() {
|
||||
return Snake.__super__.constructor.apply(this, arguments);
|
||||
_ref = Snake.__super__.constructor.apply(this, arguments);
|
||||
return _ref;
|
||||
}
|
||||
|
||||
Snake.prototype.move = function() {
|
||||
@@ -35,11 +34,11 @@ Snake = (function(_super) {
|
||||
})(Animal);
|
||||
|
||||
Horse = (function(_super) {
|
||||
|
||||
__extends(Horse, _super);
|
||||
|
||||
function Horse() {
|
||||
return Horse.__super__.constructor.apply(this, arguments);
|
||||
_ref1 = Horse.__super__.constructor.apply(this, arguments);
|
||||
return _ref1;
|
||||
}
|
||||
|
||||
Horse.prototype.move = function() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var cholesterol, healthy;
|
||||
|
||||
cholesterol = 127;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var date, mood;
|
||||
|
||||
if (singing) {
|
||||
|
||||
11
documentation/js/constructor_destructuring.js
Normal file
11
documentation/js/constructor_destructuring.js
Normal file
@@ -0,0 +1,11 @@
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var Person;
|
||||
|
||||
Person = (function() {
|
||||
function Person(options) {
|
||||
this.name = options.name, this.age = options.age, this.height = options.height;
|
||||
}
|
||||
|
||||
return Person;
|
||||
|
||||
})();
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var fill;
|
||||
|
||||
fill = function(container, liquid) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var filename, _fn, _i, _len;
|
||||
|
||||
_fn = function(filename) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var hi;
|
||||
|
||||
hi = function() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var footprints, solipsism, speed;
|
||||
|
||||
if ((typeof mind !== "undefined" && mind !== null) && (typeof world === "undefined" || world === null)) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var eldest, grade;
|
||||
|
||||
grade = function(student) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var one, six, three, two;
|
||||
|
||||
six = (one = 1) + (two = 2) + (three = 3);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var globals, name;
|
||||
|
||||
globals = ((function() {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var error;
|
||||
|
||||
alert((function() {
|
||||
try {
|
||||
return nonexistent / void 0;
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
error = _error;
|
||||
return "And the error is ... " + error;
|
||||
}
|
||||
})());
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var Account;
|
||||
|
||||
Account = function(customer, cart) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var cube, square;
|
||||
|
||||
square = function(x) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var html;
|
||||
|
||||
html = "<strong>\n cup of coffeescript\n</strong>";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var OPERATOR;
|
||||
|
||||
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var author, quote, sentence;
|
||||
|
||||
author = "Wittgenstein";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var city, forecast, temp, weatherReport, _ref;
|
||||
|
||||
weatherReport = function(location) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var age, ages, child, yearsOld;
|
||||
|
||||
yearsOld = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var city, futurists, name, street, _ref, _ref1;
|
||||
|
||||
futurists = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var bitlist, kids, singers, song;
|
||||
|
||||
song = ["do", "re", "mi", "fa", "so"];
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
$('.account').attr({
|
||||
"class": 'active'
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var cubes, list, math, num, number, opposite, race, square,
|
||||
__slice = [].slice;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var theBait, theSwitch, _ref;
|
||||
|
||||
theBait = 1000;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var close, contents, open, tag, _i, _ref,
|
||||
__slice = [].slice;
|
||||
|
||||
|
||||
3
documentation/js/prototypes.js
vendored
3
documentation/js/prototypes.js
vendored
@@ -1,5 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
String.prototype.dasherize = function() {
|
||||
return this.replace(/_/g, "-");
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var countdown, num;
|
||||
|
||||
countdown = (function() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var changeNumbers, inner, outer;
|
||||
|
||||
outer = 1;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var copy, end, middle, numbers, start;
|
||||
|
||||
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var zip, _ref;
|
||||
|
||||
zip = typeof lottery.drawWinner === "function" ? (_ref = lottery.drawWinner().address) != null ? _ref.zipcode : void 0 : void 0;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var awardMedals, contenders, gold, rest, silver,
|
||||
__slice = [].slice;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var numbers, _ref;
|
||||
|
||||
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var mobyDick;
|
||||
|
||||
mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world...";
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
switch (day) {
|
||||
case "Mon":
|
||||
go(work);
|
||||
|
||||
19
documentation/js/switch_with_no_expression.js
Normal file
19
documentation/js/switch_with_no_expression.js
Normal file
@@ -0,0 +1,19 @@
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var grade, score;
|
||||
|
||||
score = 76;
|
||||
|
||||
grade = (function() {
|
||||
switch (false) {
|
||||
case !(score < 60):
|
||||
return 'F';
|
||||
case !(score < 70):
|
||||
return 'D';
|
||||
case !(score < 80):
|
||||
return 'C';
|
||||
case !(score < 90):
|
||||
return 'B';
|
||||
default:
|
||||
return 'A';
|
||||
}
|
||||
})();
|
||||
@@ -1,9 +1,11 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var error;
|
||||
|
||||
try {
|
||||
allHellBreaksLoose();
|
||||
catsAndDogsLivingTogether();
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
error = _error;
|
||||
print(error);
|
||||
} finally {
|
||||
cleanUp();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var lyrics, num;
|
||||
|
||||
if (this.studyingEconomics) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,44 +0,0 @@
|
||||
# JavaScriptLint configuration file for CoffeeScript.
|
||||
|
||||
+no_return_value # function {0} does not always return a value
|
||||
+duplicate_formal # duplicate formal argument {0}
|
||||
-equal_as_assign # test for equality (==) mistyped as assignment (=)?{0}
|
||||
+var_hides_arg # variable {0} hides argument
|
||||
+redeclared_var # redeclaration of {0} {1}
|
||||
-anon_no_return_value # anonymous function does not always return a value
|
||||
+missing_semicolon # missing semicolon
|
||||
+meaningless_block # meaningless block; curly braces have no impact
|
||||
-comma_separated_stmts # multiple statements separated by commas (use semicolons?)
|
||||
+unreachable_code # unreachable code
|
||||
+missing_break # missing break statement
|
||||
-missing_break_for_last_case # missing break statement for last case in switch
|
||||
-comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)
|
||||
-inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement
|
||||
-useless_void # use of the void type may be unnecessary (void is always undefined)
|
||||
+multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs
|
||||
+use_of_label # use of label
|
||||
-block_without_braces # block statement without curly braces
|
||||
+leading_decimal_point # leading decimal point may indicate a number or an object member
|
||||
+trailing_decimal_point # trailing decimal point may indicate a number or an object member
|
||||
+octal_number # leading zeros make an octal number
|
||||
+nested_comment # nested comment
|
||||
+misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma
|
||||
+ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement
|
||||
+empty_statement # empty statement or extra semicolon
|
||||
-missing_option_explicit # the "option explicit" control comment is missing
|
||||
+partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag
|
||||
+dup_option_explicit # duplicate "option explicit" control comment
|
||||
+useless_assign # useless assignment
|
||||
+ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity
|
||||
+ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent)
|
||||
-missing_default_case # missing default case in switch statement
|
||||
+duplicate_case_in_switch # duplicate case in switch statements
|
||||
+default_not_at_end # the default case is not at the end of the switch statement
|
||||
+legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax
|
||||
+jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax
|
||||
+useless_comparison # useless comparison; comparing identical expressions
|
||||
+with_statement # with statement hides undeclared variables; use temporary variable instead
|
||||
+trailing_comma_in_array # extra comma is not recommended in array initializers
|
||||
+assign_to_function_call # assignment to a function call
|
||||
+parseint_missing_radix # parseInt missing radix parameter
|
||||
+lambda_assign_requires_semicolon
|
||||
242
index.html
242
index.html
@@ -108,15 +108,13 @@
|
||||
compiles one-to-one into the equivalent JS, and there is
|
||||
no interpretation at runtime. You can use any existing JavaScript library
|
||||
seamlessly from CoffeeScript (and vice-versa). The compiled output is
|
||||
readable and pretty-printed, passes through
|
||||
<a href="http://www.javascriptlint.com/">JavaScript Lint</a>
|
||||
without warnings, will work in every JavaScript runtime, and tends
|
||||
readable and pretty-printed, will work in every JavaScript runtime, and tends
|
||||
to run as fast or faster than the equivalent handwritten JavaScript.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Latest Version:</b>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/1.6.1">1.6.1</a>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/1.6.3">1.6.3</a>
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -359,16 +357,6 @@ sudo bin/cake install</pre>
|
||||
directly to <b>stdout</b>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-l, --lint</code></td>
|
||||
<td>
|
||||
If the <tt>jsl</tt>
|
||||
(<a href="http://www.javascriptlint.com/">JavaScript Lint</a>)
|
||||
command is installed, use it
|
||||
to check the compilation of a CoffeeScript file. (Handy in
|
||||
conjunction with <br /> <tt>--watch</tt>)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-s, --stdio</code></td>
|
||||
<td>
|
||||
@@ -377,6 +365,14 @@ sudo bin/cake install</pre>
|
||||
<tt>cat src/cake.coffee | coffee -sc</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-l, --literate</code></td>
|
||||
<td>
|
||||
Parses the code as Literate CoffeeScript. You only need to specify
|
||||
this when passing in code directly over <b>stdio</b>, or using some sort
|
||||
of extension-less file name.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-e, --eval</code></td>
|
||||
<td>
|
||||
@@ -384,13 +380,6 @@ sudo bin/cake install</pre>
|
||||
command line. For example:<br /><tt>coffee -e "console.log num for num in [10..1]"</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-r, --require</code></td>
|
||||
<td>
|
||||
Load a library before compiling or executing your script. Can be used
|
||||
to hook in to the compiler (to add Growl notifications, for example).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-b, --bare</code></td>
|
||||
<td>
|
||||
@@ -671,8 +660,7 @@ kids = {
|
||||
log object.<span class="Storage">class</span>
|
||||
|
||||
|
||||
</pre><pre class="idle">
|
||||
<span class="Keyword">$</span>(<span class="String"><span class="String">'</span>.account<span class="String">'</span></span>).attr({
|
||||
</pre><pre class="idle"><span class="Keyword">$</span>(<span class="String"><span class="String">'</span>.account<span class="String">'</span></span>).attr({
|
||||
<span class="String"><span class="String">"</span>class<span class="String">"</span></span>: <span class="String"><span class="String">'</span>active<span class="String">'</span></span>
|
||||
});
|
||||
|
||||
@@ -1272,19 +1260,23 @@ globals = ((function() {
|
||||
<span class="String"><span class="String">"</span>And the error is ... <span class="String"><span class="String">#{</span>error<span class="String">}</span></span><span class="String">"</span></span>
|
||||
)
|
||||
|
||||
</pre><pre class="idle">
|
||||
</pre><pre class="idle"><span class="Storage">var</span> error;
|
||||
|
||||
<span class="LibraryFunction">alert</span>((<span class="Storage">function</span>() {
|
||||
<span class="Keyword">try</span> {
|
||||
<span class="Keyword">return</span> nonexistent / <span class="Storage">void</span> <span class="Number">0</span>;
|
||||
} <span class="Keyword">catch</span> (error) {
|
||||
} <span class="Keyword">catch</span> (_error) {
|
||||
error <span class="Keyword">=</span> _error;
|
||||
<span class="Keyword">return</span> <span class="String"><span class="String">"</span>And the error is ... <span class="String">"</span></span> <span class="Keyword">+</span> error;
|
||||
}
|
||||
})());
|
||||
</pre><script>window.example19 = "alert(\n try\n nonexistent / undefined\n catch error\n \"And the error is ... #{error}\"\n)\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example19);'>load</div><div class='minibutton ok' onclick='javascript:
|
||||
</pre><script>window.example19 = "alert(\n try\n nonexistent / undefined\n catch error\n \"And the error is ... #{error}\"\n)\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example19);'>load</div><div class='minibutton ok' onclick='javascript: var error;
|
||||
|
||||
alert((function() {
|
||||
try {
|
||||
return nonexistent / void 0;
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
error = _error;
|
||||
return "And the error is ... " + error;
|
||||
}
|
||||
})());
|
||||
@@ -1509,12 +1501,11 @@ tom.move()
|
||||
|
||||
|
||||
|
||||
</pre><pre class="idle"><span class="Storage">var</span> Animal, Horse, Snake, sam, tom,
|
||||
</pre><pre class="idle"><span class="Storage">var</span> Animal, Horse, Snake, sam, tom, _ref, _ref1,
|
||||
__hasProp <span class="Keyword">=</span> {}.hasOwnProperty,
|
||||
<span class="FunctionName">__extends</span> = <span class="Storage">function</span>(<span class="FunctionArgument">child, parent</span>) { <span class="Keyword">for</span> (<span class="Storage">var</span> key <span class="Keyword">in</span> parent) { <span class="Keyword">if</span> (__hasProp.<span class="LibraryFunction">call</span>(parent, key)) child[key] <span class="Keyword">=</span> parent[key]; } <span class="Storage">function</span> <span class="FunctionName">ctor</span>() { <span class="Variable">this</span>.<span class="LibraryConstant">constructor</span> <span class="Keyword">=</span> child; } <span class="LibraryClassType">ctor</span>.<span class="LibraryConstant">prototype</span> = parent.<span class="LibraryConstant">prototype</span>; <span class="LibraryClassType">child</span>.<span class="LibraryConstant">prototype</span> = <span class="Keyword">new</span> <span class="TypeName">ctor</span>(); child.__super__ <span class="Keyword">=</span> parent.<span class="LibraryConstant">prototype</span>; <span class="Keyword">return</span> child; };
|
||||
|
||||
Animal <span class="Keyword">=</span> (<span class="Storage">function</span>() {
|
||||
|
||||
<span class="Storage">function</span> <span class="FunctionName">Animal</span>(<span class="FunctionArgument">name</span>) {
|
||||
<span class="Variable">this</span>.<span class="LibraryConstant">name</span> <span class="Keyword">=</span> name;
|
||||
}
|
||||
@@ -1528,11 +1519,11 @@ Animal <span class="Keyword">=</span> (<span class="Storage">function</span>() {
|
||||
})();
|
||||
|
||||
Snake <span class="Keyword">=</span> (<span class="Storage">function</span>(_super) {
|
||||
|
||||
__extends(Snake, _super);
|
||||
|
||||
<span class="Storage">function</span> <span class="FunctionName">Snake</span>() {
|
||||
<span class="Keyword">return</span> Snake.__super__.<span class="LibraryConstant">constructor</span>.<span class="LibraryFunction">apply</span>(<span class="Variable">this</span>, arguments);
|
||||
_ref <span class="Keyword">=</span> Snake.__super__.<span class="LibraryConstant">constructor</span>.<span class="LibraryFunction">apply</span>(<span class="Variable">this</span>, arguments);
|
||||
<span class="Keyword">return</span> _ref;
|
||||
}
|
||||
|
||||
<span class="LibraryClassType">Snake</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">move</span> = <span class="Storage">function</span>() {
|
||||
@@ -1545,11 +1536,11 @@ Snake <span class="Keyword">=</span> (<span class="Storage">function</span>(_sup
|
||||
})(Animal);
|
||||
|
||||
Horse <span class="Keyword">=</span> (<span class="Storage">function</span>(_super) {
|
||||
|
||||
__extends(Horse, _super);
|
||||
|
||||
<span class="Storage">function</span> <span class="FunctionName">Horse</span>() {
|
||||
<span class="Keyword">return</span> Horse.__super__.<span class="LibraryConstant">constructor</span>.<span class="LibraryFunction">apply</span>(<span class="Variable">this</span>, arguments);
|
||||
_ref1 <span class="Keyword">=</span> Horse.__super__.<span class="LibraryConstant">constructor</span>.<span class="LibraryFunction">apply</span>(<span class="Variable">this</span>, arguments);
|
||||
<span class="Keyword">return</span> _ref1;
|
||||
}
|
||||
|
||||
<span class="LibraryClassType">Horse</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">move</span> = <span class="Storage">function</span>() {
|
||||
@@ -1568,12 +1559,11 @@ tom <span class="Keyword">=</span> <span class="Keyword">new</span> <span class=
|
||||
sam.move();
|
||||
|
||||
tom.move();
|
||||
</pre><script>window.example23 = "class Animal\n constructor: (@name) ->\n\n move: (meters) ->\n alert @name + \" moved #{meters}m.\"\n\nclass Snake extends Animal\n move: ->\n alert \"Slithering...\"\n super 5\n\nclass Horse extends Animal\n move: ->\n alert \"Galloping...\"\n super 45\n\nsam = new Snake \"Sammy the Python\"\ntom = new Horse \"Tommy the Palomino\"\n\nsam.move()\ntom.move()\n\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example23);'>load</div><div class='minibutton ok' onclick='javascript: var Animal, Horse, Snake, sam, tom,
|
||||
</pre><script>window.example23 = "class Animal\n constructor: (@name) ->\n\n move: (meters) ->\n alert @name + \" moved #{meters}m.\"\n\nclass Snake extends Animal\n move: ->\n alert \"Slithering...\"\n super 5\n\nclass Horse extends Animal\n move: ->\n alert \"Galloping...\"\n super 45\n\nsam = new Snake \"Sammy the Python\"\ntom = new Horse \"Tommy the Palomino\"\n\nsam.move()\ntom.move()\n\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example23);'>load</div><div class='minibutton ok' onclick='javascript: var Animal, Horse, Snake, sam, tom, _ref, _ref1,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Animal = (function() {
|
||||
|
||||
function Animal(name) {
|
||||
this.name = name;
|
||||
}
|
||||
@@ -1587,11 +1577,11 @@ Animal = (function() {
|
||||
})();
|
||||
|
||||
Snake = (function(_super) {
|
||||
|
||||
__extends(Snake, _super);
|
||||
|
||||
function Snake() {
|
||||
return Snake.__super__.constructor.apply(this, arguments);
|
||||
_ref = Snake.__super__.constructor.apply(this, arguments);
|
||||
return _ref;
|
||||
}
|
||||
|
||||
Snake.prototype.move = function() {
|
||||
@@ -1604,11 +1594,11 @@ Snake = (function(_super) {
|
||||
})(Animal);
|
||||
|
||||
Horse = (function(_super) {
|
||||
|
||||
__extends(Horse, _super);
|
||||
|
||||
function Horse() {
|
||||
return Horse.__super__.constructor.apply(this, arguments);
|
||||
_ref1 = Horse.__super__.constructor.apply(this, arguments);
|
||||
return _ref1;
|
||||
}
|
||||
|
||||
Horse.prototype.move = function() {
|
||||
@@ -1639,12 +1629,10 @@ tom.move();
|
||||
<div class='code'><pre class="idle"><span class="FunctionName">String::dasherize </span><span class="Keyword">=</span> <span class="Keyword">-</span><span class="Keyword">></span>
|
||||
<span class="Variable">this</span>.replace <span class="String">/_/g</span>, <span class="String"><span class="String">"</span>-<span class="String">"</span></span>
|
||||
|
||||
</pre><pre class="idle">
|
||||
<span class="LibraryClassType">String</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">dasherize</span> = <span class="Storage">function</span>() {
|
||||
</pre><pre class="idle"><span class="LibraryClassType">String</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">dasherize</span> = <span class="Storage">function</span>() {
|
||||
<span class="Keyword">return</span> <span class="Variable">this</span>.<span class="LibraryFunction">replace</span>(<span class="String"><span class="String">/</span>_<span class="String">/</span>g</span>, <span class="String"><span class="String">"</span>-<span class="String">"</span></span>);
|
||||
};
|
||||
</pre><script>window.example24 = "String::dasherize = ->\n this.replace /_/g, \"-\"\n\nalert \"one_two\".dasherize()"</script><div class='minibutton load' onclick='javascript: loadConsole(example24);'>load</div><div class='minibutton ok' onclick='javascript:
|
||||
String.prototype.dasherize = function() {
|
||||
</pre><script>window.example24 = "String::dasherize = ->\n this.replace /_/g, \"-\"\n\nalert \"one_two\".dasherize()"</script><div class='minibutton load' onclick='javascript: loadConsole(example24);'>load</div><div class='minibutton ok' onclick='javascript: String.prototype.dasherize = function() {
|
||||
return this.replace(/_/g, "-");
|
||||
};
|
||||
;alert("one_two".dasherize());'>run: "one_two".dasherize()</div><br class='clear' /></div>
|
||||
@@ -1786,6 +1774,35 @@ _ref <span class="Keyword">=</span> tag.<span class="LibraryFunction">split</spa
|
||||
tag = "<impossible>";
|
||||
|
||||
_ref = tag.split(""), open = _ref[0], contents = 3 <= _ref.length ? __slice.call(_ref, 1, _i = _ref.length - 1) : (_i = 1, []), close = _ref[_i++];
|
||||
;alert(contents.join(""));'>run: contents.join("")</div><br class='clear' /></div>
|
||||
<p>
|
||||
Destructuring assignment is also useful when combined with class constructors
|
||||
to assign properties to your instance from an options object passed to the constructor.
|
||||
</p>
|
||||
<div class='code'><pre class="idle"><span class="Storage">class</span> <span class="TypeName">Person</span>
|
||||
<span class="FunctionName">constructor</span><span class="Keyword">:</span> <span class="FunctionArgument">(options)</span> <span class="Storage">-></span>
|
||||
<span class="Keyword">{</span><span class="Variable">@name</span>, <span class="Variable">@age</span>, <span class="Variable">@height</span><span class="Keyword">} =</span> options
|
||||
|
||||
</pre><pre class="idle"><span class="Storage">var</span> Person;
|
||||
|
||||
Person <span class="Keyword">=</span> (<span class="Storage">function</span>() {
|
||||
<span class="Storage">function</span> <span class="FunctionName">Person</span>(<span class="FunctionArgument">options</span>) {
|
||||
<span class="Variable">this</span>.<span class="LibraryConstant">name</span> <span class="Keyword">=</span> options.<span class="LibraryConstant">name</span>, <span class="Variable">this</span>.age <span class="Keyword">=</span> options.age, <span class="Variable">this</span>.<span class="LibraryConstant">height</span> <span class="Keyword">=</span> options.<span class="LibraryConstant">height</span>;
|
||||
}
|
||||
|
||||
<span class="Keyword">return</span> Person;
|
||||
|
||||
})();
|
||||
</pre><script>window.example29 = "class Person\n constructor: (options) -> \n {@name, @age, @height} = options\n\nalert contents.join(\"\")"</script><div class='minibutton load' onclick='javascript: loadConsole(example29);'>load</div><div class='minibutton ok' onclick='javascript: var Person;
|
||||
|
||||
Person = (function() {
|
||||
function Person(options) {
|
||||
this.name = options.name, this.age = options.age, this.height = options.height;
|
||||
}
|
||||
|
||||
return Person;
|
||||
|
||||
})();
|
||||
;alert(contents.join(""));'>run: contents.join("")</div><br class='clear' /></div>
|
||||
|
||||
<p>
|
||||
@@ -1822,7 +1839,7 @@ _ref = tag.split(""), open = _ref[0], contents = 3 <= _ref.length ? __slice.call
|
||||
<span class="Keyword">return</span> _this.customer.purchase(_this.cart);
|
||||
});
|
||||
};
|
||||
</pre><script>window.example29 = "Account = (customer, cart) ->\n @customer = customer\n @cart = cart\n\n $('.shopping_cart').bind 'click', (event) =>\n @customer.purchase @cart"</script><div class='minibutton load' onclick='javascript: loadConsole(example29);'>load</div><br class='clear' /></div>
|
||||
</pre><script>window.example30 = "Account = (customer, cart) ->\n @customer = customer\n @cart = cart\n\n $('.shopping_cart').bind 'click', (event) =>\n @customer.purchase @cart"</script><div class='minibutton load' onclick='javascript: loadConsole(example30);'>load</div><br class='clear' /></div>
|
||||
<p>
|
||||
If we had used <tt>-></tt> in the callback above, <tt>@customer</tt> would
|
||||
have referred to the undefined "customer" property of the DOM element,
|
||||
@@ -1852,7 +1869,7 @@ _ref = tag.split(""), open = _ref[0], contents = 3 <= _ref.length ? __slice.call
|
||||
<span class="FunctionName">hi</span> = <span class="Storage">function</span>() {
|
||||
<span class="Keyword">return</span> [<span class="LibraryClassType">document</span>.<span class="LibraryConstant">title</span>, <span class="String"><span class="String">"</span>Hello JavaScript<span class="String">"</span></span>].<span class="LibraryFunction">join</span>(<span class="String"><span class="String">"</span>: <span class="String">"</span></span>);
|
||||
};
|
||||
</pre><script>window.example30 = "hi = `function() {\n return [document.title, \"Hello JavaScript\"].join(\": \");\n}`\n\nalert hi()"</script><div class='minibutton load' onclick='javascript: loadConsole(example30);'>load</div><div class='minibutton ok' onclick='javascript: var hi;
|
||||
</pre><script>window.example31 = "hi = `function() {\n return [document.title, \"Hello JavaScript\"].join(\": \");\n}`\n\nalert hi()"</script><div class='minibutton load' onclick='javascript: loadConsole(example31);'>load</div><div class='minibutton ok' onclick='javascript: var hi;
|
||||
|
||||
hi = function() {
|
||||
return [document.title, "Hello JavaScript"].join(": ");
|
||||
@@ -1884,8 +1901,7 @@ hi = function() {
|
||||
go dancing
|
||||
<span class="Keyword">when</span> <span class="String"><span class="String">"</span>Sun<span class="String">"</span></span> <span class="Keyword">then</span> go church
|
||||
<span class="Keyword">else</span> go work
|
||||
</pre><pre class="idle">
|
||||
<span class="Keyword">switch</span> (day) {
|
||||
</pre><pre class="idle"><span class="Keyword">switch</span> (day) {
|
||||
<span class="Keyword">case</span> <span class="String"><span class="String">"</span>Mon<span class="String">"</span></span>:
|
||||
<span class="LibraryFunction">go</span>(work);
|
||||
<span class="Keyword">break</span>;
|
||||
@@ -1908,7 +1924,38 @@ hi = function() {
|
||||
<span class="Keyword">default</span>:
|
||||
<span class="LibraryFunction">go</span>(work);
|
||||
}
|
||||
</pre><script>window.example31 = "switch day\n when \"Mon\" then go work\n when \"Tue\" then go relax\n when \"Thu\" then go iceFishing\n when \"Fri\", \"Sat\"\n if day is bingoDay\n go bingo\n go dancing\n when \"Sun\" then go church\n else go work"</script><div class='minibutton load' onclick='javascript: loadConsole(example31);'>load</div><br class='clear' /></div>
|
||||
</pre><script>window.example32 = "switch day\n when \"Mon\" then go work\n when \"Tue\" then go relax\n when \"Thu\" then go iceFishing\n when \"Fri\", \"Sat\"\n if day is bingoDay\n go bingo\n go dancing\n when \"Sun\" then go church\n else go work"</script><div class='minibutton load' onclick='javascript: loadConsole(example32);'>load</div><br class='clear' /></div>
|
||||
|
||||
<p>
|
||||
Switch statements can also be used without a control expression, turning them in to a cleaner alternative to if/else chains.
|
||||
</p>
|
||||
<div class='code'><pre class="idle">score <span class="Keyword">=</span> <span class="Number">76</span>
|
||||
grade <span class="Keyword">=</span> <span class="Keyword">switch</span>
|
||||
<span class="Keyword">when</span> score <span class="Keyword"><</span> <span class="Number">60</span> <span class="Keyword">then</span> <span class="String"><span class="String">'</span>F<span class="String">'</span></span>
|
||||
<span class="Keyword">when</span> score <span class="Keyword"><</span> <span class="Number">70</span> <span class="Keyword">then</span> <span class="String"><span class="String">'</span>D<span class="String">'</span></span>
|
||||
<span class="Keyword">when</span> score <span class="Keyword"><</span> <span class="Number">80</span> <span class="Keyword">then</span> <span class="String"><span class="String">'</span>C<span class="String">'</span></span>
|
||||
<span class="Keyword">when</span> score <span class="Keyword"><</span> <span class="Number">90</span> <span class="Keyword">then</span> <span class="String"><span class="String">'</span>B<span class="String">'</span></span>
|
||||
<span class="Keyword">else</span> <span class="String"><span class="String">'</span>A<span class="String">'</span></span>
|
||||
<span class="Comment"><span class="Comment">#</span> grade == 'C'</span>
|
||||
</pre><pre class="idle"><span class="Storage">var</span> grade, score;
|
||||
|
||||
score <span class="Keyword">=</span> <span class="Number">76</span>;
|
||||
|
||||
grade <span class="Keyword">=</span> (<span class="Storage">function</span>() {
|
||||
<span class="Keyword">switch</span> (<span class="BuiltInConstant">false</span>) {
|
||||
<span class="Keyword">case</span> <span class="Keyword">!</span>(score <span class="Keyword"><</span> <span class="Number">60</span>):
|
||||
<span class="Keyword">return</span> <span class="String"><span class="String">'</span>F<span class="String">'</span></span>;
|
||||
<span class="Keyword">case</span> <span class="Keyword">!</span>(score <span class="Keyword"><</span> <span class="Number">70</span>):
|
||||
<span class="Keyword">return</span> <span class="String"><span class="String">'</span>D<span class="String">'</span></span>;
|
||||
<span class="Keyword">case</span> <span class="Keyword">!</span>(score <span class="Keyword"><</span> <span class="Number">80</span>):
|
||||
<span class="Keyword">return</span> <span class="String"><span class="String">'</span>C<span class="String">'</span></span>;
|
||||
<span class="Keyword">case</span> <span class="Keyword">!</span>(score <span class="Keyword"><</span> <span class="Number">90</span>):
|
||||
<span class="Keyword">return</span> <span class="String"><span class="String">'</span>B<span class="String">'</span></span>;
|
||||
<span class="Keyword">default</span>:
|
||||
<span class="Keyword">return</span> <span class="String"><span class="String">'</span>A<span class="String">'</span></span>;
|
||||
}
|
||||
})();
|
||||
</pre><script>window.example33 = "score = 76\ngrade = switch\n when score < 60 then 'F'\n when score < 70 then 'D'\n when score < 80 then 'C'\n when score < 90 then 'B'\n else 'A'\n# grade == 'C'\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example33);'>load</div><br class='clear' /></div>
|
||||
|
||||
<p>
|
||||
<span id="try" class="bookmark"></span>
|
||||
@@ -1924,16 +1971,18 @@ hi = function() {
|
||||
<span class="Keyword">finally</span>
|
||||
cleanUp()
|
||||
|
||||
</pre><pre class="idle">
|
||||
</pre><pre class="idle"><span class="Storage">var</span> error;
|
||||
|
||||
<span class="Keyword">try</span> {
|
||||
allHellBreaksLoose();
|
||||
catsAndDogsLivingTogether();
|
||||
} <span class="Keyword">catch</span> (error) {
|
||||
} <span class="Keyword">catch</span> (_error) {
|
||||
error <span class="Keyword">=</span> _error;
|
||||
<span class="LibraryFunction">print</span>(error);
|
||||
} <span class="Keyword">finally</span> {
|
||||
cleanUp();
|
||||
}
|
||||
</pre><script>window.example32 = "try\n allHellBreaksLoose()\n catsAndDogsLivingTogether()\ncatch error\n print error\nfinally\n cleanUp()\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example32);'>load</div><br class='clear' /></div>
|
||||
</pre><script>window.example34 = "try\n allHellBreaksLoose()\n catsAndDogsLivingTogether()\ncatch error\n print error\nfinally\n cleanUp()\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example34);'>load</div><br class='clear' /></div>
|
||||
|
||||
<p>
|
||||
<span id="comparisons" class="bookmark"></span>
|
||||
@@ -1953,7 +2002,7 @@ healthy <span class="Keyword">=</span> <span class="Number">200</span> <span cla
|
||||
cholesterol <span class="Keyword">=</span> <span class="Number">127</span>;
|
||||
|
||||
healthy <span class="Keyword">=</span> (<span class="Number">200</span> <span class="Keyword">></span> cholesterol <span class="Keyword">&</span><span class="Keyword">&</span> cholesterol <span class="Keyword">></span> <span class="Number">60</span>);
|
||||
</pre><script>window.example33 = "cholesterol = 127\n\nhealthy = 200 > cholesterol > 60\n\nalert healthy"</script><div class='minibutton load' onclick='javascript: loadConsole(example33);'>load</div><div class='minibutton ok' onclick='javascript: var cholesterol, healthy;
|
||||
</pre><script>window.example35 = "cholesterol = 127\n\nhealthy = 200 > cholesterol > 60\n\nalert healthy"</script><div class='minibutton load' onclick='javascript: loadConsole(example35);'>load</div><div class='minibutton ok' onclick='javascript: var cholesterol, healthy;
|
||||
|
||||
cholesterol = 127;
|
||||
|
||||
@@ -1983,7 +2032,7 @@ author <span class="Keyword">=</span> <span class="String"><span class="String">
|
||||
quote <span class="Keyword">=</span> <span class="String"><span class="String">"</span>A picture is a fact. -- <span class="String">"</span></span> <span class="Keyword">+</span> author;
|
||||
|
||||
sentence <span class="Keyword">=</span> <span class="String"><span class="String">"</span><span class="String">"</span></span> <span class="Keyword">+</span> (<span class="Number">22</span> / <span class="Number">7</span>) <span class="Keyword">+</span> <span class="String"><span class="String">"</span> is a decent approximation of π<span class="String">"</span></span>;
|
||||
</pre><script>window.example34 = "author = \"Wittgenstein\"\nquote = \"A picture is a fact. -- #{ author }\"\n\nsentence = \"#{ 22 / 7 } is a decent approximation of π\"\n\nalert sentence"</script><div class='minibutton load' onclick='javascript: loadConsole(example34);'>load</div><div class='minibutton ok' onclick='javascript: var author, quote, sentence;
|
||||
</pre><script>window.example36 = "author = \"Wittgenstein\"\nquote = \"A picture is a fact. -- #{ author }\"\n\nsentence = \"#{ 22 / 7 } is a decent approximation of π\"\n\nalert sentence"</script><div class='minibutton load' onclick='javascript: loadConsole(example36);'>load</div><div class='minibutton ok' onclick='javascript: var author, quote, sentence;
|
||||
|
||||
author = "Wittgenstein";
|
||||
|
||||
@@ -2005,7 +2054,7 @@ sentence = "" + (22 / 7) + " is a decent approximation of π";
|
||||
</pre><pre class="idle"><span class="Storage">var</span> mobyDick;
|
||||
|
||||
mobyDick <span class="Keyword">=</span> <span class="String"><span class="String">"</span>Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world...<span class="String">"</span></span>;
|
||||
</pre><script>window.example35 = "mobyDick = \"Call me Ishmael. Some years ago --\n never mind how long precisely -- having little\n or no money in my purse, and nothing particular\n to interest me on shore, I thought I would sail\n about a little and see the watery part of the\n world...\"\n\nalert mobyDick"</script><div class='minibutton load' onclick='javascript: loadConsole(example35);'>load</div><div class='minibutton ok' onclick='javascript: var mobyDick;
|
||||
</pre><script>window.example37 = "mobyDick = \"Call me Ishmael. Some years ago --\n never mind how long precisely -- having little\n or no money in my purse, and nothing particular\n to interest me on shore, I thought I would sail\n about a little and see the watery part of the\n world...\"\n\nalert mobyDick"</script><div class='minibutton load' onclick='javascript: loadConsole(example37);'>load</div><div class='minibutton ok' onclick='javascript: var mobyDick;
|
||||
|
||||
mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world...";
|
||||
;alert(mobyDick);'>run: mobyDick</div><br class='clear' /></div>
|
||||
@@ -2024,7 +2073,7 @@ mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely --
|
||||
</pre><pre class="idle"><span class="Storage">var</span> html;
|
||||
|
||||
html <span class="Keyword">=</span> <span class="String"><span class="String">"</span><strong><span class="UserDefinedConstant">\n</span> cup of coffeescript<span class="UserDefinedConstant">\n</span></strong><span class="String">"</span></span>;
|
||||
</pre><script>window.example36 = "html = \"\"\"\n <strong>\n cup of coffeescript\n </strong>\n \"\"\"\n\nalert html"</script><div class='minibutton load' onclick='javascript: loadConsole(example36);'>load</div><div class='minibutton ok' onclick='javascript: var html;
|
||||
</pre><script>window.example38 = "html = \"\"\"\n <strong>\n cup of coffeescript\n </strong>\n \"\"\"\n\nalert html"</script><div class='minibutton load' onclick='javascript: loadConsole(example38);'>load</div><div class='minibutton ok' onclick='javascript: var html;
|
||||
|
||||
html = "<strong>\n cup of coffeescript\n</strong>";
|
||||
;alert(html);'>run: html</div><br class='clear' /></div>
|
||||
@@ -2038,25 +2087,25 @@ html = "<strong>\n cup of coffeescript\n</strong>";
|
||||
are preserved in the generated code.
|
||||
</p>
|
||||
<div class='code'><pre class="idle"><span class="Comment"><span class="Comment">###</span></span>
|
||||
<span class="Comment">CoffeeScript Compiler v1.6.1</span>
|
||||
<span class="Comment">SkinnyMochaHalfCaffScript Compiler v1.0</span>
|
||||
<span class="Comment">Released under the MIT License</span>
|
||||
<span class="Comment"><span class="Comment">###</span></span>
|
||||
|
||||
|
||||
</pre><pre class="idle"><span class="Comment"><span class="Comment">/*</span></span>
|
||||
<span class="Comment">CoffeeScript Compiler v1.6.1</span>
|
||||
<span class="Comment">SkinnyMochaHalfCaffScript Compiler v1.0</span>
|
||||
<span class="Comment">Released under the MIT License</span>
|
||||
<span class="Comment"><span class="Comment">*/</span></span>
|
||||
|
||||
|
||||
</pre><script>window.example37 = "###\nCoffeeScript Compiler v1.6.1\nReleased under the MIT License\n###\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example37);'>load</div><br class='clear' /></div>
|
||||
</pre><script>window.example39 = "###\nSkinnyMochaHalfCaffScript Compiler v1.0\nReleased under the MIT License\n###\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example39);'>load</div><br class='clear' /></div>
|
||||
|
||||
<p>
|
||||
<span id="regexes" class="bookmark"></span>
|
||||
<b class="header">Block Regular Expressions</b>
|
||||
Similar to block strings and comments, CoffeeScript supports block regexes —
|
||||
extended regular expressions that ignore internal whitespace and can contain
|
||||
comments and interpolation. Modeled after Perl's <tt>/x</tt> modifier, CoffeeSctipt's
|
||||
comments and interpolation. Modeled after Perl's <tt>/x</tt> modifier, CoffeeScript's
|
||||
block regexes are delimited by <tt>///</tt> and go a long way towards making complex
|
||||
regular expressions readable. To quote from the CoffeeScript source:
|
||||
</p>
|
||||
@@ -2074,7 +2123,7 @@ html = "<strong>\n cup of coffeescript\n</strong>";
|
||||
</pre><pre class="idle"><span class="Storage">var</span> OPERATOR;
|
||||
|
||||
OPERATOR <span class="Keyword">=</span><span class="String"> <span class="String">/</span>^(?:[-=]>|[-+*<span class="UserDefinedConstant">\/</span>%<>&|^!?=]=|>>>=?|([-+:])<span class="UserDefinedConstant">\1</span>|([&|<>])<span class="UserDefinedConstant">\2</span>=?|<span class="UserDefinedConstant">\?</span><span class="UserDefinedConstant">\.</span>|<span class="UserDefinedConstant">\.</span>{2,3})<span class="String">/</span></span>;
|
||||
</pre><script>window.example38 = "OPERATOR = /// ^ (\n ?: [-=]> # function\n | [-+*/%<>&|^!?=]= # compound assign / compare\n | >>>=? # zero-fill right shift\n | ([-+:])\\1 # doubles\n | ([&|<>])\\2=? # logic / shift\n | \\?\\. # soak access\n | \\.{2,3} # range or splat\n) ///\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example38);'>load</div><br class='clear' /></div>
|
||||
</pre><script>window.example40 = "OPERATOR = /// ^ (\n ?: [-=]> # function\n | [-+*/%<>&|^!?=]= # compound assign / compare\n | >>>=? # zero-fill right shift\n | ([-+:])\\1 # doubles\n | ([&|<>])\\2=? # logic / shift\n | \\?\\. # soak access\n | \\.{2,3} # range or splat\n) ///\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example40);'>load</div><br class='clear' /></div>
|
||||
|
||||
|
||||
<h2>
|
||||
@@ -2122,7 +2171,7 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
dir <span class="Keyword">=</span> options.output <span class="Keyword">||</span> <span class="String"><span class="String">'</span>lib<span class="String">'</span></span>;
|
||||
<span class="Keyword">return</span> fs.writeFile(<span class="String"><span class="String">"</span><span class="String">"</span></span> <span class="Keyword">+</span> dir <span class="Keyword">+</span> <span class="String"><span class="String">"</span>/parser.js<span class="String">"</span></span>, code);
|
||||
});
|
||||
</pre><script>window.example39 = "fs = require 'fs'\n\noption '-o', '--output [DIR]', 'directory for compiled code'\n\ntask 'build:parser', 'rebuild the Jison parser', (options) ->\n require 'jison'\n code = require('./lib/grammar').parser.generate()\n dir = options.output or 'lib'\n fs.writeFile \"#{dir}/parser.js\", code"</script><div class='minibutton load' onclick='javascript: loadConsole(example39);'>load</div><br class='clear' /></div>
|
||||
</pre><script>window.example41 = "fs = require 'fs'\n\noption '-o', '--output [DIR]', 'directory for compiled code'\n\ntask 'build:parser', 'rebuild the Jison parser', (options) ->\n require 'jison'\n code = require('./lib/grammar').parser.generate()\n dir = options.output or 'lib'\n fs.writeFile \"#{dir}/parser.js\", code"</script><div class='minibutton load' onclick='javascript: loadConsole(example41);'>load</div><br class='clear' /></div>
|
||||
<p>
|
||||
If you need to invoke one task before another — for example, running
|
||||
<tt>build</tt> before <tt>test</tt>, you can use the <tt>invoke</tt> function:
|
||||
@@ -2335,6 +2384,13 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
<a href="http://github.com/jashkenas/coffee-script/wiki/FAQ">The FAQ</a><br />
|
||||
Perhaps your CoffeeScript-related question has been asked before. Check the FAQ first.
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://js2coffee.org">JS2Coffee</a><br />
|
||||
Is a very well done reverse JavaScript-to-CoffeeScript compiler. It's
|
||||
not going to be perfect (infer what your JavaScript classes are, when
|
||||
you need bound functions, and so on...) — but it's a great starting
|
||||
point for converting simple scripts.
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/jashkenas/coffee-script/downloads">High-Rez Logo</a><br />
|
||||
The CoffeeScript logo is available in Illustrator, EPS and PSD formats, for use
|
||||
@@ -2362,6 +2418,64 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
Change Log
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">
|
||||
<a href="https://github.com/jashkenas/coffee-script/compare/1.6.2...1.6.3">1.6.3</a>
|
||||
<span class="timestamp"> – <small>June 2, 2013</small></span>
|
||||
</b>
|
||||
<ul>
|
||||
<li>
|
||||
The CoffeeScript REPL now remembers your history between sessions.
|
||||
Just like a proper REPL should.
|
||||
</li>
|
||||
<li>
|
||||
You can now use <tt>require</tt> in Node to load <tt>.coffee.md</tt>
|
||||
Literate CoffeeScript files. In the browser,
|
||||
<tt>text/literate-coffeescript</tt> script tags.
|
||||
</li>
|
||||
<li>
|
||||
The old <tt>coffee --lint</tt> command has been removed. It was useful
|
||||
while originally working on the compiler, but has been surpassed by
|
||||
JSHint. You may now use <tt>-l</tt> to pass literate files in over
|
||||
<b>stdio</b>.
|
||||
</li>
|
||||
<li>
|
||||
Bugfixes for Windows path separators, <tt>catch</tt> without naming
|
||||
the error, and executable-class-bodies-with-
|
||||
prototypal-property-attachment.
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">
|
||||
<a href="https://github.com/jashkenas/coffee-script/compare/1.6.1...1.6.2">1.6.2</a>
|
||||
<span class="timestamp"> – <small>March 18, 2013</small></span>
|
||||
</b>
|
||||
<ul>
|
||||
<li>
|
||||
Source maps have been used to provide automatic line-mapping when
|
||||
running CoffeeScript directly via the <tt>coffee</tt> command, and
|
||||
for automatic line-mapping when running CoffeeScript directly in the
|
||||
browser. Also, to provide better error messages for semantic errors
|
||||
thrown by the compiler —
|
||||
<a href="http://cl.ly/NdOA">with colors, even</a>.
|
||||
</li>
|
||||
<li>
|
||||
Improved support for mixed literate/vanilla-style CoffeeScript projects,
|
||||
and generating source maps for both at the same time.
|
||||
</li>
|
||||
<li>
|
||||
Fixes for <b>1.6.x</b> regressions with overriding inherited bound
|
||||
functions, and for Windows file path management.
|
||||
</li>
|
||||
<li>
|
||||
The <tt>coffee</tt> command can now correctly <tt>fork()</tt>
|
||||
both <tt>.coffee</tt> and <tt>.js</tt> files. (Requires Node.js 0.9+)
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">
|
||||
<a href="https://github.com/jashkenas/coffee-script/compare/1.5.0...1.6.1">1.6.1</a>
|
||||
@@ -3109,8 +3223,10 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
else
|
||||
$(el).text window.compiledJS
|
||||
$('#error').hide()
|
||||
catch error
|
||||
$('#error').text(error.message).show()
|
||||
catch {location, message}
|
||||
if location?
|
||||
message = "Error on line #{location.first_line + 1}: #{message}"
|
||||
$('#error').text(message).show()
|
||||
|
||||
# Update permalink
|
||||
$('#repl_permalink').attr 'href', "##{sourceFragment}#{encodeURIComponent source}"
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var CoffeeScript, runScripts,
|
||||
var CoffeeScript, compile, runScripts,
|
||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||
|
||||
CoffeeScript = require('./coffee-script');
|
||||
|
||||
CoffeeScript.require = require;
|
||||
|
||||
compile = CoffeeScript.compile;
|
||||
|
||||
CoffeeScript["eval"] = function(code, options) {
|
||||
var _ref;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
if ((_ref = options.bare) == null) {
|
||||
if (options.bare == null) {
|
||||
options.bare = true;
|
||||
}
|
||||
return eval(CoffeeScript.compile(code, options));
|
||||
return eval(compile(code, options));
|
||||
};
|
||||
|
||||
CoffeeScript.run = function(code, options) {
|
||||
@@ -23,19 +24,34 @@
|
||||
options = {};
|
||||
}
|
||||
options.bare = true;
|
||||
return Function(CoffeeScript.compile(code, options))();
|
||||
options.shiftLine = true;
|
||||
return Function(compile(code, options))();
|
||||
};
|
||||
|
||||
if (typeof window === "undefined" || window === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((typeof btoa !== "undefined" && btoa !== null) && (typeof JSON !== "undefined" && JSON !== null) && (typeof unescape !== "undefined" && unescape !== null) && (typeof encodeURIComponent !== "undefined" && encodeURIComponent !== null)) {
|
||||
compile = function(code, options) {
|
||||
var js, v3SourceMap, _ref;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
options.sourceMap = true;
|
||||
options.inline = true;
|
||||
_ref = CoffeeScript.compile(code, options), js = _ref.js, v3SourceMap = _ref.v3SourceMap;
|
||||
return "" + js + "\n//@ sourceMappingURL=data:application/json;base64," + (btoa(unescape(encodeURIComponent(v3SourceMap)))) + "\n//@ sourceURL=coffeescript";
|
||||
};
|
||||
}
|
||||
|
||||
CoffeeScript.load = function(url, callback, options) {
|
||||
var xhr;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();
|
||||
options.sourceFiles = [url];
|
||||
xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP') : new window.XMLHttpRequest();
|
||||
xhr.open('GET', url, true);
|
||||
if ('overrideMimeType' in xhr) {
|
||||
xhr.overrideMimeType('text/plain');
|
||||
@@ -58,7 +74,7 @@
|
||||
|
||||
runScripts = function() {
|
||||
var coffees, coffeetypes, execute, index, length, s, scripts;
|
||||
scripts = document.getElementsByTagName('script');
|
||||
scripts = window.document.getElementsByTagName('script');
|
||||
coffeetypes = ['text/coffeescript', 'text/literate-coffeescript'];
|
||||
coffees = (function() {
|
||||
var _i, _len, _ref, _results;
|
||||
@@ -84,6 +100,7 @@
|
||||
if (script.src) {
|
||||
return CoffeeScript.load(script.src, execute, options);
|
||||
} else {
|
||||
options.sourceFiles = ['embedded'];
|
||||
CoffeeScript.run(script.innerHTML, options);
|
||||
return execute();
|
||||
}
|
||||
@@ -93,9 +110,9 @@
|
||||
};
|
||||
|
||||
if (window.addEventListener) {
|
||||
addEventListener('DOMContentLoaded', runScripts, false);
|
||||
window.addEventListener('DOMContentLoaded', runScripts, false);
|
||||
} else {
|
||||
attachEvent('onload', runScripts);
|
||||
window.attachEvent('onload', runScripts);
|
||||
}
|
||||
|
||||
}).call(this);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var CoffeeScript, cakefileDirectory, existsSync, fatalError, fs, helpers, missingTask, oparse, options, optparse, path, printTasks, switches, tasks;
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
});
|
||||
|
||||
exports.run = function() {
|
||||
var arg, args, _i, _len, _ref, _results;
|
||||
var arg, args, e, _i, _len, _ref, _results;
|
||||
global.__originalDirname = fs.realpathSync('.');
|
||||
process.chdir(cakefileDirectory(__originalDirname));
|
||||
args = process.argv.slice(2);
|
||||
@@ -59,7 +59,8 @@
|
||||
}
|
||||
try {
|
||||
options = oparse.parse(args);
|
||||
} catch (e) {
|
||||
} catch (_error) {
|
||||
e = _error;
|
||||
return fatalError("" + e);
|
||||
}
|
||||
_ref = options["arguments"];
|
||||
|
||||
@@ -1,85 +1,60 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var Lexer, compile, ext, fs, helpers, lexer, loadFile, parser, path, sourcemap, vm, _i, _len, _ref,
|
||||
var Lexer, Module, SourceMap, child_process, compile, ext, findExtension, fork, formatSourcePosition, fs, helpers, lexer, loadFile, parser, patchStackTrace, patched, path, sourceMaps, vm, _i, _len, _ref,
|
||||
__hasProp = {}.hasOwnProperty;
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
vm = require('vm');
|
||||
|
||||
path = require('path');
|
||||
|
||||
child_process = require('child_process');
|
||||
|
||||
Lexer = require('./lexer').Lexer;
|
||||
|
||||
parser = require('./parser').parser;
|
||||
|
||||
helpers = require('./helpers');
|
||||
|
||||
vm = require('vm');
|
||||
SourceMap = require('./sourcemap');
|
||||
|
||||
sourcemap = require('./sourcemap');
|
||||
|
||||
loadFile = function(module, filename) {
|
||||
var raw, stripped;
|
||||
raw = fs.readFileSync(filename, 'utf8');
|
||||
stripped = raw.charCodeAt(0) === 0xFEFF ? raw.substring(1) : raw;
|
||||
return module._compile(compile(stripped, {
|
||||
filename: filename,
|
||||
literate: helpers.isLiterate(filename)
|
||||
}), filename);
|
||||
};
|
||||
|
||||
if (require.extensions) {
|
||||
_ref = ['.coffee', '.litcoffee', '.md', '.coffee.md'];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
ext = _ref[_i];
|
||||
require.extensions[ext] = loadFile;
|
||||
}
|
||||
}
|
||||
|
||||
exports.VERSION = '1.6.1';
|
||||
exports.VERSION = '1.6.3';
|
||||
|
||||
exports.helpers = helpers;
|
||||
|
||||
exports.compile = compile = function(code, options) {
|
||||
var answer, coffeeFile, currentColumn, currentLine, fragment, fragments, header, js, jsFile, merge, newLines, sourceMap, _j, _len1;
|
||||
var answer, currentColumn, currentLine, fragment, fragments, header, js, map, merge, newLines, _i, _len;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
merge = exports.helpers.merge;
|
||||
try {
|
||||
merge = helpers.merge;
|
||||
if (options.sourceMap) {
|
||||
map = new SourceMap;
|
||||
}
|
||||
fragments = parser.parse(lexer.tokenize(code, options)).compileToFragments(options);
|
||||
currentLine = 0;
|
||||
if (options.header) {
|
||||
currentLine += 1;
|
||||
}
|
||||
if (options.shiftLine) {
|
||||
currentLine += 1;
|
||||
}
|
||||
currentColumn = 0;
|
||||
js = "";
|
||||
for (_i = 0, _len = fragments.length; _i < _len; _i++) {
|
||||
fragment = fragments[_i];
|
||||
if (options.sourceMap) {
|
||||
coffeeFile = helpers.baseFileName(options.filename);
|
||||
jsFile = helpers.baseFileName(options.filename, true) + ".js";
|
||||
sourceMap = new sourcemap.SourceMap();
|
||||
}
|
||||
fragments = (parser.parse(lexer.tokenize(code, options))).compileToFragments(options);
|
||||
currentLine = 0;
|
||||
if (options.header) {
|
||||
currentLine += 1;
|
||||
}
|
||||
if (options.sourceMap) {
|
||||
currentLine += 1;
|
||||
}
|
||||
currentColumn = 0;
|
||||
js = "";
|
||||
for (_j = 0, _len1 = fragments.length; _j < _len1; _j++) {
|
||||
fragment = fragments[_j];
|
||||
if (sourceMap) {
|
||||
if (fragment.locationData) {
|
||||
sourceMap.addMapping([fragment.locationData.first_line, fragment.locationData.first_column], [currentLine, currentColumn], {
|
||||
noReplace: true
|
||||
});
|
||||
}
|
||||
newLines = helpers.count(fragment.code, "\n");
|
||||
currentLine += newLines;
|
||||
currentColumn = fragment.code.length - (newLines ? fragment.code.lastIndexOf("\n") : 0);
|
||||
if (fragment.locationData) {
|
||||
map.add([fragment.locationData.first_line, fragment.locationData.first_column], [currentLine, currentColumn], {
|
||||
noReplace: true
|
||||
});
|
||||
}
|
||||
js += fragment.code;
|
||||
newLines = helpers.count(fragment.code, "\n");
|
||||
currentLine += newLines;
|
||||
currentColumn = fragment.code.length - (newLines ? fragment.code.lastIndexOf("\n") : 0);
|
||||
}
|
||||
} catch (err) {
|
||||
if (options.filename) {
|
||||
err.message = "In " + options.filename + ", " + err.message;
|
||||
}
|
||||
throw err;
|
||||
js += fragment.code;
|
||||
}
|
||||
if (options.header) {
|
||||
header = "Generated by CoffeeScript " + this.VERSION;
|
||||
@@ -89,10 +64,8 @@
|
||||
answer = {
|
||||
js: js
|
||||
};
|
||||
if (sourceMap) {
|
||||
answer.sourceMap = sourceMap;
|
||||
answer.v3SourceMap = sourcemap.generateV3SourceMap(sourceMap, coffeeFile, jsFile);
|
||||
}
|
||||
answer.sourceMap = map;
|
||||
answer.v3SourceMap = map.generate(options, code);
|
||||
return answer;
|
||||
} else {
|
||||
return js;
|
||||
@@ -112,23 +85,29 @@
|
||||
};
|
||||
|
||||
exports.run = function(code, options) {
|
||||
var mainModule;
|
||||
var answer, mainModule;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
mainModule = require.main;
|
||||
if (options.sourceMap == null) {
|
||||
options.sourceMap = true;
|
||||
}
|
||||
mainModule.filename = process.argv[1] = options.filename ? fs.realpathSync(options.filename) : '.';
|
||||
mainModule.moduleCache && (mainModule.moduleCache = {});
|
||||
mainModule.paths = require('module')._nodeModulePaths(path.dirname(fs.realpathSync(options.filename)));
|
||||
mainModule.paths = require('module')._nodeModulePaths(path.dirname(fs.realpathSync(options.filename || '.')));
|
||||
if (!helpers.isCoffee(mainModule.filename) || require.extensions) {
|
||||
return mainModule._compile(compile(code, options), mainModule.filename);
|
||||
answer = compile(code, options);
|
||||
patchStackTrace();
|
||||
sourceMaps[mainModule.filename] = answer.sourceMap;
|
||||
return mainModule._compile(answer.js, mainModule.filename);
|
||||
} else {
|
||||
return mainModule._compile(code, mainModule.filename);
|
||||
}
|
||||
};
|
||||
|
||||
exports["eval"] = function(code, options) {
|
||||
var Module, Script, js, k, o, r, sandbox, v, _j, _len1, _module, _ref1, _ref2, _require;
|
||||
var Module, Script, js, k, o, r, sandbox, v, _i, _len, _module, _ref, _ref1, _require;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
@@ -142,10 +121,10 @@
|
||||
sandbox = options.sandbox;
|
||||
} else {
|
||||
sandbox = Script.createContext();
|
||||
_ref1 = options.sandbox;
|
||||
for (k in _ref1) {
|
||||
if (!__hasProp.call(_ref1, k)) continue;
|
||||
v = _ref1[k];
|
||||
_ref = options.sandbox;
|
||||
for (k in _ref) {
|
||||
if (!__hasProp.call(_ref, k)) continue;
|
||||
v = _ref[k];
|
||||
sandbox[k] = v;
|
||||
}
|
||||
}
|
||||
@@ -162,9 +141,9 @@
|
||||
return Module._load(path, _module, true);
|
||||
};
|
||||
_module.filename = sandbox.__filename;
|
||||
_ref2 = Object.getOwnPropertyNames(require);
|
||||
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
|
||||
r = _ref2[_j];
|
||||
_ref1 = Object.getOwnPropertyNames(require);
|
||||
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
||||
r = _ref1[_i];
|
||||
if (r !== 'paths') {
|
||||
_require[r] = require[r];
|
||||
}
|
||||
@@ -190,6 +169,70 @@
|
||||
}
|
||||
};
|
||||
|
||||
loadFile = function(module, filename) {
|
||||
var answer, raw, stripped;
|
||||
raw = fs.readFileSync(filename, 'utf8');
|
||||
stripped = raw.charCodeAt(0) === 0xFEFF ? raw.substring(1) : raw;
|
||||
answer = compile(stripped, {
|
||||
filename: filename,
|
||||
sourceMap: true,
|
||||
literate: helpers.isLiterate(filename)
|
||||
});
|
||||
sourceMaps[filename] = answer.sourceMap;
|
||||
return module._compile(answer.js, filename);
|
||||
};
|
||||
|
||||
if (require.extensions) {
|
||||
_ref = ['.coffee', '.litcoffee', '.coffee.md'];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
ext = _ref[_i];
|
||||
require.extensions[ext] = loadFile;
|
||||
}
|
||||
Module = require('module');
|
||||
findExtension = function(filename) {
|
||||
var curExtension, extensions;
|
||||
extensions = path.basename(filename).split('.');
|
||||
if (extensions[0] === '') {
|
||||
extensions.shift();
|
||||
}
|
||||
while (extensions.shift()) {
|
||||
curExtension = '.' + extensions.join('.');
|
||||
if (Module._extensions[curExtension]) {
|
||||
return curExtension;
|
||||
}
|
||||
}
|
||||
return '.js';
|
||||
};
|
||||
Module.prototype.load = function(filename) {
|
||||
var extension;
|
||||
this.filename = filename;
|
||||
this.paths = Module._nodeModulePaths(path.dirname(filename));
|
||||
extension = findExtension(filename);
|
||||
Module._extensions[extension](this, filename);
|
||||
return this.loaded = true;
|
||||
};
|
||||
}
|
||||
|
||||
if (child_process) {
|
||||
fork = child_process.fork;
|
||||
child_process.fork = function(path, args, options) {
|
||||
var execPath;
|
||||
if (args == null) {
|
||||
args = [];
|
||||
}
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
execPath = helpers.isCoffee(path) ? 'coffee' : null;
|
||||
if (!Array.isArray(args)) {
|
||||
args = [];
|
||||
options = args || {};
|
||||
}
|
||||
options.execPath || (options.execPath = execPath);
|
||||
return fork(path, args, options);
|
||||
};
|
||||
}
|
||||
|
||||
lexer = new Lexer;
|
||||
|
||||
parser.lexer = {
|
||||
@@ -215,4 +258,101 @@
|
||||
|
||||
parser.yy = require('./nodes');
|
||||
|
||||
parser.yy.parseError = function(message, _arg) {
|
||||
var token;
|
||||
token = _arg.token;
|
||||
message = "unexpected " + (token === 1 ? 'end of input' : token);
|
||||
return helpers.throwSyntaxError(message, parser.lexer.yylloc);
|
||||
};
|
||||
|
||||
patched = false;
|
||||
|
||||
sourceMaps = {};
|
||||
|
||||
patchStackTrace = function() {
|
||||
var mainModule;
|
||||
if (patched) {
|
||||
return;
|
||||
}
|
||||
patched = true;
|
||||
mainModule = require.main;
|
||||
return Error.prepareStackTrace = function(err, stack) {
|
||||
var frame, frames, getSourceMapping, sourceFiles, _ref1;
|
||||
sourceFiles = {};
|
||||
getSourceMapping = function(filename, line, column) {
|
||||
var answer, sourceMap;
|
||||
sourceMap = sourceMaps[filename];
|
||||
if (sourceMap) {
|
||||
answer = sourceMap.sourceLocation([line - 1, column - 1]);
|
||||
}
|
||||
if (answer) {
|
||||
return [answer[0] + 1, answer[1] + 1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
frames = (function() {
|
||||
var _j, _len1, _results;
|
||||
_results = [];
|
||||
for (_j = 0, _len1 = stack.length; _j < _len1; _j++) {
|
||||
frame = stack[_j];
|
||||
if (frame.getFunction() === exports.run) {
|
||||
break;
|
||||
}
|
||||
_results.push(" at " + (formatSourcePosition(frame, getSourceMapping)));
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
return "" + err.name + ": " + ((_ref1 = err.message) != null ? _ref1 : '') + "\n" + (frames.join('\n')) + "\n";
|
||||
};
|
||||
};
|
||||
|
||||
formatSourcePosition = function(frame, getSourceMapping) {
|
||||
var as, column, fileLocation, fileName, functionName, isConstructor, isMethodCall, line, methodName, source, tp, typeName;
|
||||
fileName = void 0;
|
||||
fileLocation = '';
|
||||
if (frame.isNative()) {
|
||||
fileLocation = "native";
|
||||
} else {
|
||||
if (frame.isEval()) {
|
||||
fileName = frame.getScriptNameOrSourceURL();
|
||||
if (!fileName) {
|
||||
fileLocation = "" + (frame.getEvalOrigin()) + ", ";
|
||||
}
|
||||
} else {
|
||||
fileName = frame.getFileName();
|
||||
}
|
||||
fileName || (fileName = "<anonymous>");
|
||||
line = frame.getLineNumber();
|
||||
column = frame.getColumnNumber();
|
||||
source = getSourceMapping(fileName, line, column);
|
||||
fileLocation = source ? "" + fileName + ":" + source[0] + ":" + source[1] + ", <js>:" + line + ":" + column : "" + fileName + ":" + line + ":" + column;
|
||||
}
|
||||
functionName = frame.getFunctionName();
|
||||
isConstructor = frame.isConstructor();
|
||||
isMethodCall = !(frame.isToplevel() || isConstructor);
|
||||
if (isMethodCall) {
|
||||
methodName = frame.getMethodName();
|
||||
typeName = frame.getTypeName();
|
||||
if (functionName) {
|
||||
tp = as = '';
|
||||
if (typeName && functionName.indexOf(typeName)) {
|
||||
tp = "" + typeName + ".";
|
||||
}
|
||||
if (methodName && functionName.indexOf("." + methodName) !== functionName.length - methodName.length - 1) {
|
||||
as = " [as " + methodName + "]";
|
||||
}
|
||||
return "" + tp + functionName + as + " (" + fileLocation + ")";
|
||||
} else {
|
||||
return "" + typeName + "." + (methodName || '<anonymous>') + " (" + fileLocation + ")";
|
||||
}
|
||||
} else if (isConstructor) {
|
||||
return "new " + (functionName || '<anonymous>') + " (" + fileLocation + ")";
|
||||
} else if (functionName) {
|
||||
return "" + functionName + " (" + fileLocation + ")";
|
||||
} else {
|
||||
return fileLocation;
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, exists, forkNode, fs, helpers, hidden, joinTimeout, lint, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, removeSource, sourceCode, sources, spawn, timeLog, unwatchDir, usage, version, wait, watch, watchDir, watchers, writeJs, _ref;
|
||||
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, exists, forkNode, fs, helpers, hidden, joinTimeout, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, removeSource, sourceCode, sources, spawn, timeLog, unwatchDir, usage, useWinPathSep, version, wait, watch, watchDir, watchers, writeJs, _ref;
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
exists = fs.exists || path.exists;
|
||||
|
||||
useWinPathSep = path.sep === '\\';
|
||||
|
||||
helpers.extend(CoffeeScript, new EventEmitter);
|
||||
|
||||
printLine = function(line) {
|
||||
@@ -34,7 +36,7 @@
|
||||
|
||||
BANNER = 'Usage: coffee [options] path/to/script.coffee -- [args]\n\nIf called without options, `coffee` will run your script.';
|
||||
|
||||
SWITCHES = [['-b', '--bare', 'compile without a top-level function wrapper'], ['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-e', '--eval', 'pass a string from the command line as input'], ['-h', '--help', 'display this help message'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-j', '--join [FILE]', 'concatenate the source CoffeeScript before compiling'], ['-l', '--lint', 'pipe the compiled JavaScript through JavaScript Lint'], ['-m', '--map', 'generate source map and save as .map files'], ['-n', '--nodes', 'print out the parse tree that the parser produces'], ['--nodejs [ARGS]', 'pass options directly to the "node" binary'], ['-o', '--output [DIR]', 'set the output directory for compiled JavaScript'], ['-p', '--print', 'print out the compiled JavaScript'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-t', '--tokens', 'print out the tokens that the lexer/rewriter produce'], ['-v', '--version', 'display the version number'], ['-w', '--watch', 'watch scripts for changes and rerun commands']];
|
||||
SWITCHES = [['-b', '--bare', 'compile without a top-level function wrapper'], ['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-e', '--eval', 'pass a string from the command line as input'], ['-h', '--help', 'display this help message'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-j', '--join [FILE]', 'concatenate the source CoffeeScript before compiling'], ['-m', '--map', 'generate source map and save as .map files'], ['-n', '--nodes', 'print out the parse tree that the parser produces'], ['--nodejs [ARGS]', 'pass options directly to the "node" binary'], ['-o', '--output [DIR]', 'set the output directory for compiled JavaScript'], ['-p', '--print', 'print out the compiled JavaScript'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-l', '--literate', 'treat stdio as literate style coffee-script'], ['-t', '--tokens', 'print out the tokens that the lexer/rewriter produce'], ['-v', '--version', 'display the version number'], ['-w', '--watch', 'watch scripts for changes and rerun commands']];
|
||||
|
||||
opts = {};
|
||||
|
||||
@@ -148,9 +150,12 @@
|
||||
};
|
||||
|
||||
compileScript = function(file, input, base) {
|
||||
var compiled, o, options, t, task;
|
||||
var compiled, err, message, o, options, t, task, useColors;
|
||||
if (base == null) {
|
||||
base = null;
|
||||
}
|
||||
o = opts;
|
||||
options = compileOptions(file);
|
||||
options = compileOptions(file, base);
|
||||
try {
|
||||
t = task = {
|
||||
file: file,
|
||||
@@ -165,6 +170,9 @@
|
||||
} else if (o.run) {
|
||||
return CoffeeScript.run(t.input, t.options);
|
||||
} else if (o.join && t.file !== o.join) {
|
||||
if (helpers.isLiterate(file)) {
|
||||
t.input = helpers.invertLiterate(t.input);
|
||||
}
|
||||
sourceCode[sources.indexOf(t.file)] = t.input;
|
||||
return compileJoin();
|
||||
} else {
|
||||
@@ -178,21 +186,23 @@
|
||||
if (o.print) {
|
||||
return printLine(t.output.trim());
|
||||
} else if (o.compile || o.map) {
|
||||
return writeJs(base, t.file, t.output, t.sourceMap);
|
||||
} else if (o.lint) {
|
||||
return lint(t.file, t.output);
|
||||
return writeJs(base, t.file, t.output, options.jsPath, t.sourceMap);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
} catch (_error) {
|
||||
err = _error;
|
||||
CoffeeScript.emit('failure', err, task);
|
||||
if (CoffeeScript.listeners('failure').length) {
|
||||
return;
|
||||
}
|
||||
useColors = process.stdout.isTTY && !process.env.NODE_DISABLE_COLORS;
|
||||
message = helpers.prettyErrorMessage(err, file || '[stdin]', input, useColors);
|
||||
if (o.watch) {
|
||||
return printLine(err.message + '\x07');
|
||||
return printLine(message + '\x07');
|
||||
} else {
|
||||
printWarn(message);
|
||||
return process.exit(1);
|
||||
}
|
||||
printWarn(err instanceof Error && err.stack || ("ERROR: " + err));
|
||||
return process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -227,7 +237,7 @@
|
||||
};
|
||||
|
||||
watch = function(source, base) {
|
||||
var compile, compileTimeout, prevStats, rewatch, watchErr, watcher;
|
||||
var compile, compileTimeout, e, prevStats, rewatch, watchErr, watcher;
|
||||
prevStats = null;
|
||||
compileTimeout = null;
|
||||
watchErr = function(e) {
|
||||
@@ -238,7 +248,8 @@
|
||||
try {
|
||||
rewatch();
|
||||
return compile();
|
||||
} catch (e) {
|
||||
} catch (_error) {
|
||||
e = _error;
|
||||
removeSource(source, base, true);
|
||||
return compileJoin();
|
||||
}
|
||||
@@ -269,7 +280,8 @@
|
||||
};
|
||||
try {
|
||||
watcher = fs.watch(source, compile);
|
||||
} catch (e) {
|
||||
} catch (_error) {
|
||||
e = _error;
|
||||
watchErr(e);
|
||||
}
|
||||
return rewatch = function() {
|
||||
@@ -281,7 +293,7 @@
|
||||
};
|
||||
|
||||
watchDir = function(source, base) {
|
||||
var readdirTimeout, watcher;
|
||||
var e, readdirTimeout, watcher;
|
||||
readdirTimeout = null;
|
||||
try {
|
||||
return watcher = fs.watch(source, function() {
|
||||
@@ -316,7 +328,8 @@
|
||||
});
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
} catch (_error) {
|
||||
e = _error;
|
||||
if (e.code !== 'ENOENT') {
|
||||
throw e;
|
||||
}
|
||||
@@ -374,19 +387,18 @@
|
||||
if (extension == null) {
|
||||
extension = ".js";
|
||||
}
|
||||
basename = helpers.baseFileName(source, true);
|
||||
basename = helpers.baseFileName(source, true, useWinPathSep);
|
||||
srcDir = path.dirname(source);
|
||||
baseDir = base === '.' ? srcDir : srcDir.substring(base.length);
|
||||
dir = opts.output ? path.join(opts.output, baseDir) : srcDir;
|
||||
return path.join(dir, basename + extension);
|
||||
};
|
||||
|
||||
writeJs = function(base, sourcePath, js, generatedSourceMap) {
|
||||
var compile, jsDir, jsPath, sourceMapPath;
|
||||
writeJs = function(base, sourcePath, js, jsPath, generatedSourceMap) {
|
||||
var compile, jsDir, sourceMapPath;
|
||||
if (generatedSourceMap == null) {
|
||||
generatedSourceMap = null;
|
||||
}
|
||||
jsPath = outputPath(sourcePath, base);
|
||||
sourceMapPath = outputPath(sourcePath, base, ".map");
|
||||
jsDir = path.dirname(jsPath);
|
||||
compile = function() {
|
||||
@@ -395,7 +407,7 @@
|
||||
js = ' ';
|
||||
}
|
||||
if (generatedSourceMap) {
|
||||
js = "//@ sourceMappingURL=" + (helpers.baseFileName(sourceMapPath)) + "\n" + js;
|
||||
js = "" + js + "\n/*\n//@ sourceMappingURL=" + (helpers.baseFileName(sourceMapPath, false, useWinPathSep)) + "\n*/\n";
|
||||
}
|
||||
fs.writeFile(jsPath, js, function(err) {
|
||||
if (err) {
|
||||
@@ -430,19 +442,6 @@
|
||||
return console.log("" + ((new Date).toLocaleTimeString()) + " - " + message);
|
||||
};
|
||||
|
||||
lint = function(file, js) {
|
||||
var conf, jsl, printIt;
|
||||
printIt = function(buffer) {
|
||||
return printLine(file + ':\t' + buffer.toString().trim());
|
||||
};
|
||||
conf = __dirname + '/../../extras/jsl.conf';
|
||||
jsl = spawn('jsl', ['-nologo', '-stdin', '-conf', conf]);
|
||||
jsl.stdout.on('data', printIt);
|
||||
jsl.stderr.on('data', printIt);
|
||||
jsl.stdin.write(js);
|
||||
return jsl.stdin.end();
|
||||
};
|
||||
|
||||
printTokens = function(tokens) {
|
||||
var strings, tag, token, value;
|
||||
strings = (function() {
|
||||
@@ -464,7 +463,7 @@
|
||||
optionParser = new optparse.OptionParser(SWITCHES, BANNER);
|
||||
o = opts = optionParser.parse(process.argv.slice(2));
|
||||
o.compile || (o.compile = !!o.output);
|
||||
o.run = !(o.compile || o.print || o.lint || o.map);
|
||||
o.run = !(o.compile || o.print || o.map);
|
||||
o.print = !!(o.print || (o["eval"] || o.stdio && o.compile));
|
||||
sources = o["arguments"];
|
||||
for (i = _i = 0, _len = sources.length; _i < _len; i = ++_i) {
|
||||
@@ -473,14 +472,35 @@
|
||||
}
|
||||
};
|
||||
|
||||
compileOptions = function(filename) {
|
||||
return {
|
||||
compileOptions = function(filename, base) {
|
||||
var answer, cwd, jsDir, jsPath;
|
||||
answer = {
|
||||
filename: filename,
|
||||
literate: helpers.isLiterate(filename),
|
||||
literate: opts.literate || helpers.isLiterate(filename),
|
||||
bare: opts.bare,
|
||||
header: opts.compile,
|
||||
sourceMap: opts.map
|
||||
};
|
||||
if (filename) {
|
||||
if (base) {
|
||||
cwd = process.cwd();
|
||||
jsPath = outputPath(filename, base);
|
||||
jsDir = path.dirname(jsPath);
|
||||
answer = helpers.merge(answer, {
|
||||
jsPath: jsPath,
|
||||
sourceRoot: path.relative(jsDir, cwd),
|
||||
sourceFiles: [path.relative(cwd, filename)],
|
||||
generatedFile: helpers.baseFileName(jsPath, false, useWinPathSep)
|
||||
});
|
||||
} else {
|
||||
answer = helpers.merge(answer, {
|
||||
sourceRoot: "",
|
||||
sourceFiles: [helpers.baseFileName(filename, false, useWinPathSep)],
|
||||
generatedFile: helpers.baseFileName(filename, true, useWinPathSep) + ".js"
|
||||
});
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
};
|
||||
|
||||
forkNode = function() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap;
|
||||
|
||||
@@ -350,6 +350,8 @@
|
||||
return [$2, $3];
|
||||
}), o('CATCH Object Block', function() {
|
||||
return [LOC(2)(new Value($2)), $3];
|
||||
}), o('CATCH Block', function() {
|
||||
return [null, $2];
|
||||
})
|
||||
],
|
||||
Throw: [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var buildLocationData, extend, flatten, _ref;
|
||||
var buildLocationData, extend, flatten, last, repeat, _ref;
|
||||
|
||||
exports.starts = function(string, literal, start) {
|
||||
return literal === string.substr(start, literal.length);
|
||||
@@ -12,6 +12,19 @@
|
||||
return literal === string.substr(string.length - len - (back || 0), len);
|
||||
};
|
||||
|
||||
exports.repeat = repeat = function(str, n) {
|
||||
var res;
|
||||
res = '';
|
||||
while (n > 0) {
|
||||
if (n & 1) {
|
||||
res += str;
|
||||
}
|
||||
n >>>= 1;
|
||||
str += str;
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
exports.compact = function(array) {
|
||||
var item, _i, _len, _results;
|
||||
_results = [];
|
||||
@@ -70,7 +83,7 @@
|
||||
return val;
|
||||
};
|
||||
|
||||
exports.last = function(array, back) {
|
||||
exports.last = last = function(array, back) {
|
||||
return array[array.length - (back || 0) - 1];
|
||||
};
|
||||
|
||||
@@ -85,6 +98,28 @@
|
||||
return false;
|
||||
};
|
||||
|
||||
exports.invertLiterate = function(code) {
|
||||
var line, lines, maybe_code;
|
||||
maybe_code = true;
|
||||
lines = (function() {
|
||||
var _i, _len, _ref1, _results;
|
||||
_ref1 = code.split('\n');
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
||||
line = _ref1[_i];
|
||||
if (maybe_code && /^([ ]{4}|[ ]{0,3}\t)/.test(line)) {
|
||||
_results.push(line);
|
||||
} else if (maybe_code = /^\s*$/.test(line)) {
|
||||
_results.push(line);
|
||||
} else {
|
||||
_results.push('# ' + line);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
return lines.join('\n');
|
||||
};
|
||||
|
||||
buildLocationData = function(first, last) {
|
||||
if (!last) {
|
||||
return first;
|
||||
@@ -121,19 +156,23 @@
|
||||
}
|
||||
};
|
||||
|
||||
exports.baseFileName = function(file, stripExt) {
|
||||
var parts;
|
||||
exports.baseFileName = function(file, stripExt, useWinPathSep) {
|
||||
var parts, pathSep;
|
||||
if (stripExt == null) {
|
||||
stripExt = false;
|
||||
}
|
||||
parts = file.split('/');
|
||||
if (useWinPathSep == null) {
|
||||
useWinPathSep = false;
|
||||
}
|
||||
pathSep = useWinPathSep ? /\\|\// : /\//;
|
||||
parts = file.split(pathSep);
|
||||
file = parts[parts.length - 1];
|
||||
if (!stripExt) {
|
||||
return file;
|
||||
}
|
||||
parts = file.split('.');
|
||||
parts.pop();
|
||||
if (parts[parts.length - 1] === 'coffee') {
|
||||
if (parts[parts.length - 1] === 'coffee' && parts.length > 1) {
|
||||
parts.pop();
|
||||
}
|
||||
return parts.join('.');
|
||||
@@ -147,4 +186,38 @@
|
||||
return /\.(litcoffee|coffee\.md)$/.test(file);
|
||||
};
|
||||
|
||||
exports.throwSyntaxError = function(message, location) {
|
||||
var error;
|
||||
if (location.last_line == null) {
|
||||
location.last_line = location.first_line;
|
||||
}
|
||||
if (location.last_column == null) {
|
||||
location.last_column = location.first_column;
|
||||
}
|
||||
error = new SyntaxError(message);
|
||||
error.location = location;
|
||||
throw error;
|
||||
};
|
||||
|
||||
exports.prettyErrorMessage = function(error, fileName, code, useColors) {
|
||||
var codeLine, colorize, end, first_column, first_line, last_column, last_line, marker, message, start, _ref1;
|
||||
if (!error.location) {
|
||||
return error.stack || ("" + error);
|
||||
}
|
||||
_ref1 = error.location, first_line = _ref1.first_line, first_column = _ref1.first_column, last_line = _ref1.last_line, last_column = _ref1.last_column;
|
||||
codeLine = code.split('\n')[first_line];
|
||||
start = first_column;
|
||||
end = first_line === last_line ? last_column + 1 : codeLine.length;
|
||||
marker = repeat(' ', start) + repeat('^', end - start);
|
||||
if (useColors) {
|
||||
colorize = function(str) {
|
||||
return "\x1B[1;31m" + str + "\x1B[0m";
|
||||
};
|
||||
codeLine = codeLine.slice(0, start) + colorize(codeLine.slice(start, end)) + codeLine.slice(end);
|
||||
marker = colorize(marker);
|
||||
}
|
||||
message = "" + fileName + ":" + (first_line + 1) + ":" + (first_column + 1) + ": error: " + error.message + "\n" + codeLine + "\n" + marker;
|
||||
return message;
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var key, val, _ref;
|
||||
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_ILLEGAL, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LINE_CONTINUER, LITERATE, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NOT_REGEX, NOT_SPACED_REGEX, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, STRICT_PROSCRIBED, TRAILING_SPACES, UNARY, WHITESPACE, compact, count, key, last, locationDataToString, starts, _ref, _ref1,
|
||||
var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_ILLEGAL, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NOT_REGEX, NOT_SPACED_REGEX, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, STRICT_PROSCRIBED, TRAILING_SPACES, UNARY, WHITESPACE, compact, count, invertLiterate, key, last, locationDataToString, repeat, starts, throwSyntaxError, _ref, _ref1,
|
||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||
|
||||
_ref = require('./rewriter'), Rewriter = _ref.Rewriter, INVERSES = _ref.INVERSES;
|
||||
|
||||
_ref1 = require('./helpers'), count = _ref1.count, starts = _ref1.starts, compact = _ref1.compact, last = _ref1.last, locationDataToString = _ref1.locationDataToString;
|
||||
_ref1 = require('./helpers'), count = _ref1.count, starts = _ref1.starts, compact = _ref1.compact, last = _ref1.last, repeat = _ref1.repeat, invertLiterate = _ref1.invertLiterate, locationDataToString = _ref1.locationDataToString, throwSyntaxError = _ref1.throwSyntaxError;
|
||||
|
||||
exports.Lexer = Lexer = (function() {
|
||||
|
||||
function Lexer() {}
|
||||
|
||||
Lexer.prototype.tokenize = function(code, opts) {
|
||||
@@ -43,7 +42,6 @@
|
||||
};
|
||||
|
||||
Lexer.prototype.clean = function(code) {
|
||||
var line, lines, match;
|
||||
if (code.charCodeAt(0) === BOM) {
|
||||
code = code.slice(1);
|
||||
}
|
||||
@@ -53,21 +51,7 @@
|
||||
this.chunkLine--;
|
||||
}
|
||||
if (this.literate) {
|
||||
lines = (function() {
|
||||
var _i, _len, _ref2, _results;
|
||||
_ref2 = code.split('\n');
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
line = _ref2[_i];
|
||||
if (match = LITERATE.exec(line)) {
|
||||
_results.push(line.slice(match[0].length));
|
||||
} else {
|
||||
_results.push('# ' + line);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
code = lines.join('\n');
|
||||
code = invertLiterate(code);
|
||||
}
|
||||
return code;
|
||||
};
|
||||
@@ -171,10 +155,10 @@
|
||||
}
|
||||
lexedLength = number.length;
|
||||
if (octalLiteral = /^0o([0-7]+)/.exec(number)) {
|
||||
number = '0x' + (parseInt(octalLiteral[1], 8)).toString(16);
|
||||
number = '0x' + parseInt(octalLiteral[1], 8).toString(16);
|
||||
}
|
||||
if (binaryLiteral = /^0b([01]+)/.exec(number)) {
|
||||
number = '0x' + (parseInt(binaryLiteral[1], 2)).toString(16);
|
||||
number = '0x' + parseInt(binaryLiteral[1], 2).toString(16);
|
||||
}
|
||||
this.token('NUMBER', number, 0, lexedLength);
|
||||
return lexedLength;
|
||||
@@ -244,7 +228,7 @@
|
||||
if (here) {
|
||||
this.token('HERECOMMENT', this.sanitizeHeredoc(here, {
|
||||
herecomment: true,
|
||||
indent: Array(this.indent + 1).join(' ')
|
||||
indent: repeat(' ', this.indent)
|
||||
}), 0, comment.length);
|
||||
}
|
||||
return comment.length;
|
||||
@@ -363,7 +347,7 @@
|
||||
return indent.length;
|
||||
}
|
||||
diff = size - this.indent + this.outdebt;
|
||||
this.token('INDENT', diff, 0, indent.length);
|
||||
this.token('INDENT', diff, indent.length - size, size);
|
||||
this.indents.push(diff);
|
||||
this.ends.push('OUTDENT');
|
||||
this.outdebt = this.indebt = 0;
|
||||
@@ -527,9 +511,6 @@
|
||||
if (indent) {
|
||||
doc = doc.replace(RegExp("\\n" + indent, "g"), '\n');
|
||||
}
|
||||
if (this.literate) {
|
||||
doc = doc.replace(/\n# \n/g, '\n\n');
|
||||
}
|
||||
if (!herecomment) {
|
||||
doc = doc.replace(/^\n/, '');
|
||||
}
|
||||
@@ -605,7 +586,7 @@
|
||||
};
|
||||
|
||||
Lexer.prototype.interpolateString = function(str, options) {
|
||||
var column, expr, heredoc, i, inner, interpolated, len, letter, lexedLength, line, locationToken, nested, offsetInChunk, pi, plusToken, popped, regex, strOffset, tag, token, tokens, value, _i, _len, _ref2, _ref3, _ref4;
|
||||
var column, expr, heredoc, i, inner, interpolated, len, letter, lexedLength, line, locationToken, nested, offsetInChunk, pi, plusToken, popped, regex, rparen, strOffset, tag, token, tokens, value, _i, _len, _ref2, _ref3, _ref4;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
@@ -695,7 +676,9 @@
|
||||
}
|
||||
}
|
||||
if (interpolated) {
|
||||
this.token(')', ')', offsetInChunk + lexedLength, 0);
|
||||
rparen = this.makeToken(')', ')', offsetInChunk + lexedLength, 0);
|
||||
rparen.stringEnd = true;
|
||||
this.tokens.push(rparen);
|
||||
}
|
||||
return tokens;
|
||||
};
|
||||
@@ -727,7 +710,7 @@
|
||||
column = this.chunkColumn;
|
||||
if (lineCount > 0) {
|
||||
lines = string.split('\n');
|
||||
column = (last(lines)).length;
|
||||
column = last(lines).length;
|
||||
} else {
|
||||
column += string.length;
|
||||
}
|
||||
@@ -745,7 +728,7 @@
|
||||
locationData = {};
|
||||
_ref2 = this.getLineAndColumnFromChunk(offsetInChunk), locationData.first_line = _ref2[0], locationData.first_column = _ref2[1];
|
||||
lastCharacter = Math.max(0, length - 1);
|
||||
_ref3 = this.getLineAndColumnFromChunk(offsetInChunk + (length - 1)), locationData.last_line = _ref3[0], locationData.last_column = _ref3[1];
|
||||
_ref3 = this.getLineAndColumnFromChunk(offsetInChunk + lastCharacter), locationData.last_line = _ref3[0], locationData.last_column = _ref3[1];
|
||||
token = [tag, value, locationData];
|
||||
return token;
|
||||
};
|
||||
@@ -792,7 +775,10 @@
|
||||
};
|
||||
|
||||
Lexer.prototype.error = function(message) {
|
||||
throw SyntaxError("" + message + " on line " + (this.chunkLine + 1));
|
||||
return throwSyntaxError(message, {
|
||||
first_line: this.chunkLine,
|
||||
first_column: this.chunkColumn
|
||||
});
|
||||
};
|
||||
|
||||
return Lexer;
|
||||
@@ -850,8 +836,6 @@
|
||||
|
||||
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)$)|^(?:\s*#(?!##[^#]).*)+/;
|
||||
|
||||
LITERATE = /^([ ]{4}|\t)/;
|
||||
|
||||
CODE = /^[-=]>/;
|
||||
|
||||
MULTI_DENT = /^(?:\n[^\n\S]*)+/;
|
||||
@@ -892,9 +876,9 @@
|
||||
|
||||
BOOL = ['TRUE', 'FALSE'];
|
||||
|
||||
NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', 'NULL', 'UNDEFINED', '++', '--', ']'];
|
||||
NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', 'NULL', 'UNDEFINED', '++', '--'];
|
||||
|
||||
NOT_SPACED_REGEX = NOT_REGEX.concat(')', '}', 'THIS', 'IDENTIFIER', 'STRING');
|
||||
NOT_SPACED_REGEX = NOT_REGEX.concat(')', '}', 'THIS', 'IDENTIFIER', 'STRING', ']');
|
||||
|
||||
CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER'];
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,10 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments;
|
||||
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments, repeat;
|
||||
|
||||
repeat = require('./helpers').repeat;
|
||||
|
||||
exports.OptionParser = OptionParser = (function() {
|
||||
|
||||
function OptionParser(rules, banner) {
|
||||
this.banner = banner;
|
||||
this.rules = buildRules(rules);
|
||||
@@ -67,7 +68,7 @@
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
rule = _ref[_i];
|
||||
spaces = 15 - rule.longFlag.length;
|
||||
spaces = spaces > 0 ? Array(spaces + 1).join(' ') : '';
|
||||
spaces = spaces > 0 ? repeat(' ', spaces) : '';
|
||||
letPart = rule.shortFlag ? rule.shortFlag + ', ' : ' ';
|
||||
lines.push(' ' + letPart + rule.longFlag + spaces + rule.description);
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,6 +1,10 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var CoffeeScript, addMultilineHandler, merge, nodeREPL, replDefaults, vm;
|
||||
var CoffeeScript, addHistory, addMultilineHandler, fs, merge, nodeREPL, path, prettyErrorMessage, replDefaults, vm, _ref;
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
path = require('path');
|
||||
|
||||
vm = require('vm');
|
||||
|
||||
@@ -8,25 +12,28 @@
|
||||
|
||||
CoffeeScript = require('./coffee-script');
|
||||
|
||||
merge = require('./helpers').merge;
|
||||
_ref = require('./helpers'), merge = _ref.merge, prettyErrorMessage = _ref.prettyErrorMessage;
|
||||
|
||||
replDefaults = {
|
||||
prompt: 'coffee> ',
|
||||
historyFile: process.env.HOME ? path.join(process.env.HOME, '.coffee_history') : void 0,
|
||||
historyMaxInputSize: 10240,
|
||||
"eval": function(input, context, filename, cb) {
|
||||
var js;
|
||||
var Assign, Block, Literal, Value, ast, err, js, _ref1;
|
||||
input = input.replace(/\uFF00/g, '\n');
|
||||
input = input.replace(/(^|[\r\n]+)(\s*)##?(?:[^#\r\n][^\r\n]*|)($|[\r\n])/, '$1$2$3');
|
||||
if (/^(\s*|\(\s*\))$/.test(input)) {
|
||||
return cb(null);
|
||||
}
|
||||
input = input.replace(/^\(([\s\S]*)\n\)$/m, '$1');
|
||||
_ref1 = require('./nodes'), Block = _ref1.Block, Assign = _ref1.Assign, Value = _ref1.Value, Literal = _ref1.Literal;
|
||||
try {
|
||||
js = CoffeeScript.compile("_=(" + input + "\n)", {
|
||||
filename: filename,
|
||||
bare: true
|
||||
ast = CoffeeScript.nodes(input);
|
||||
ast = new Block([new Assign(new Value(new Literal('_')), ast, '=')]);
|
||||
js = ast.compile({
|
||||
bare: true,
|
||||
locals: Object.keys(context)
|
||||
});
|
||||
return cb(null, vm.runInContext(js, context, filename));
|
||||
} catch (err) {
|
||||
return cb(err);
|
||||
} catch (_error) {
|
||||
err = _error;
|
||||
return cb(prettyErrorMessage(err, filename, input, true));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -85,18 +92,66 @@
|
||||
});
|
||||
};
|
||||
|
||||
addHistory = function(repl, filename, maxSize) {
|
||||
var buffer, fd, lastLine, readFd, size, stat;
|
||||
lastLine = null;
|
||||
try {
|
||||
stat = fs.statSync(filename);
|
||||
size = Math.min(maxSize, stat.size);
|
||||
readFd = fs.openSync(filename, 'r');
|
||||
buffer = new Buffer(size);
|
||||
fs.readSync(readFd, buffer, 0, size, stat.size - size);
|
||||
repl.rli.history = buffer.toString().split('\n').reverse();
|
||||
if (stat.size > maxSize) {
|
||||
repl.rli.history.pop();
|
||||
}
|
||||
if (repl.rli.history[0] === '') {
|
||||
repl.rli.history.shift();
|
||||
}
|
||||
repl.rli.historyIndex = -1;
|
||||
lastLine = repl.rli.history[0];
|
||||
} catch (_error) {}
|
||||
fd = fs.openSync(filename, 'a');
|
||||
repl.rli.addListener('line', function(code) {
|
||||
if (code && code.length && code !== '.history' && lastLine !== code) {
|
||||
fs.write(fd, "" + code + "\n");
|
||||
return lastLine = code;
|
||||
}
|
||||
});
|
||||
repl.rli.on('exit', function() {
|
||||
return fs.close(fd);
|
||||
});
|
||||
return repl.commands['.history'] = {
|
||||
help: 'Show command history',
|
||||
action: function() {
|
||||
repl.outputStream.write("" + (repl.rli.history.slice(0).reverse().join('\n')) + "\n");
|
||||
return repl.displayPrompt();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
start: function(opts) {
|
||||
var repl;
|
||||
var build, major, minor, repl, _ref1;
|
||||
if (opts == null) {
|
||||
opts = {};
|
||||
}
|
||||
_ref1 = process.versions.node.split('.').map(function(n) {
|
||||
return parseInt(n);
|
||||
}), major = _ref1[0], minor = _ref1[1], build = _ref1[2];
|
||||
if (major === 0 && minor < 8) {
|
||||
console.warn("Node 0.8.0+ required for CoffeeScript REPL");
|
||||
process.exit(1);
|
||||
}
|
||||
opts = merge(replDefaults, opts);
|
||||
repl = nodeREPL.start(opts);
|
||||
repl.on('exit', function() {
|
||||
return repl.outputStream.write('\n');
|
||||
});
|
||||
addMultilineHandler(repl);
|
||||
if (opts.historyFile) {
|
||||
addHistory(repl, opts.historyFile, opts.historyMaxInputSize);
|
||||
}
|
||||
return repl;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, generate, left, rite, _i, _len, _ref,
|
||||
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, generate, left, rite, _i, _len, _ref,
|
||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
|
||||
__slice = [].slice;
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
};
|
||||
|
||||
exports.Rewriter = (function() {
|
||||
|
||||
function Rewriter() {}
|
||||
|
||||
Rewriter.prototype.rewrite = function(tokens) {
|
||||
@@ -267,14 +266,14 @@
|
||||
}
|
||||
stack.pop();
|
||||
}
|
||||
if ((__indexOf.call(IMPLICIT_FUNC, tag) >= 0 && token.spaced || tag === '?' && i > 0 && !tokens[i - 1].spaced) && (__indexOf.call(IMPLICIT_CALL, nextTag) >= 0 || __indexOf.call(IMPLICIT_UNSPACED_CALL, nextTag) >= 0 && !((_ref = tokens[i + 1]) != null ? _ref.spaced : void 0) && !((_ref1 = tokens[i + 1]) != null ? _ref1.newLine : void 0))) {
|
||||
if ((__indexOf.call(IMPLICIT_FUNC, tag) >= 0 && token.spaced && !token.stringEnd || tag === '?' && i > 0 && !tokens[i - 1].spaced) && (__indexOf.call(IMPLICIT_CALL, nextTag) >= 0 || __indexOf.call(IMPLICIT_UNSPACED_CALL, nextTag) >= 0 && !((_ref = tokens[i + 1]) != null ? _ref.spaced : void 0) && !((_ref1 = tokens[i + 1]) != null ? _ref1.newLine : void 0))) {
|
||||
if (tag === '?') {
|
||||
tag = token[0] = 'FUNC_EXIST';
|
||||
}
|
||||
startImplicitCall(i + 1);
|
||||
return forward(2);
|
||||
}
|
||||
if (this.matchTags(i, IMPLICIT_FUNC, 'INDENT', null, ':') && !this.findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH', 'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])) {
|
||||
if (__indexOf.call(IMPLICIT_FUNC, tag) >= 0 && this.matchTags(i + 1, 'INDENT', null, ':') && !this.findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH', 'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])) {
|
||||
startImplicitCall(i + 1);
|
||||
stack.push(['INDENT', i + 2]);
|
||||
return forward(3);
|
||||
@@ -331,22 +330,25 @@
|
||||
|
||||
Rewriter.prototype.addLocationDataToGeneratedTokens = function() {
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var last_column, last_line, _ref, _ref1, _ref2;
|
||||
var column, line, nextLocation, prevLocation, _ref, _ref1;
|
||||
if (token[2]) {
|
||||
return 1;
|
||||
}
|
||||
if (!(token.generated || token.explicit)) {
|
||||
return 1;
|
||||
}
|
||||
_ref2 = (_ref = (_ref1 = tokens[i - 1]) != null ? _ref1[2] : void 0) != null ? _ref : {
|
||||
last_line: 0,
|
||||
last_column: 0
|
||||
}, last_line = _ref2.last_line, last_column = _ref2.last_column;
|
||||
if (token[0] === '{' && (nextLocation = (_ref = tokens[i + 1]) != null ? _ref[2] : void 0)) {
|
||||
line = nextLocation.first_line, column = nextLocation.first_column;
|
||||
} else if (prevLocation = (_ref1 = tokens[i - 1]) != null ? _ref1[2] : void 0) {
|
||||
line = prevLocation.last_line, column = prevLocation.last_column;
|
||||
} else {
|
||||
line = column = 0;
|
||||
}
|
||||
token[2] = {
|
||||
first_line: last_line,
|
||||
first_column: last_column,
|
||||
last_line: last_line,
|
||||
last_column: last_column
|
||||
first_line: line,
|
||||
first_column: column,
|
||||
last_line: line,
|
||||
last_column: column
|
||||
};
|
||||
return 1;
|
||||
});
|
||||
@@ -356,30 +358,35 @@
|
||||
var action, condition, indent, outdent, starter;
|
||||
starter = indent = outdent = null;
|
||||
condition = function(token, i) {
|
||||
var _ref;
|
||||
return token[1] !== ';' && (_ref = token[0], __indexOf.call(SINGLE_CLOSERS, _ref) >= 0) && !(token[0] === 'ELSE' && (starter !== 'IF' && starter !== 'THEN'));
|
||||
var _ref, _ref1;
|
||||
return token[1] !== ';' && (_ref = token[0], __indexOf.call(SINGLE_CLOSERS, _ref) >= 0) && !(token[0] === 'ELSE' && starter !== 'THEN') && !(((_ref1 = token[0]) === 'CATCH' || _ref1 === 'FINALLY') && (starter === '->' || starter === '=>'));
|
||||
};
|
||||
action = function(token, i) {
|
||||
return this.tokens.splice((this.tag(i - 1) === ',' ? i - 1 : i), 0, outdent);
|
||||
};
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var tag, _ref, _ref1;
|
||||
var j, tag, _i, _ref, _ref1;
|
||||
tag = token[0];
|
||||
if (tag === 'TERMINATOR' && this.tag(i + 1) === 'THEN') {
|
||||
tokens.splice(i, 1);
|
||||
return 0;
|
||||
}
|
||||
if (tag === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') {
|
||||
tokens.splice.apply(tokens, [i, 0].concat(__slice.call(this.indentation(token))));
|
||||
tokens.splice.apply(tokens, [i, 0].concat(__slice.call(this.indentation())));
|
||||
return 2;
|
||||
}
|
||||
if (tag === 'CATCH' && ((_ref = this.tag(i + 2)) === 'OUTDENT' || _ref === 'TERMINATOR' || _ref === 'FINALLY')) {
|
||||
tokens.splice.apply(tokens, [i + 2, 0].concat(__slice.call(this.indentation(token))));
|
||||
return 4;
|
||||
if (tag === 'CATCH') {
|
||||
for (j = _i = 1; _i <= 2; j = ++_i) {
|
||||
if (!((_ref = this.tag(i + j)) === 'OUTDENT' || _ref === 'TERMINATOR' || _ref === 'FINALLY')) {
|
||||
continue;
|
||||
}
|
||||
tokens.splice.apply(tokens, [i + j, 0].concat(__slice.call(this.indentation())));
|
||||
return 2 + j;
|
||||
}
|
||||
}
|
||||
if (__indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) {
|
||||
starter = tag;
|
||||
_ref1 = this.indentation(token, true), indent = _ref1[0], outdent = _ref1[1];
|
||||
_ref1 = this.indentation(true), indent = _ref1[0], outdent = _ref1[1];
|
||||
if (starter === 'THEN') {
|
||||
indent.fromThen = true;
|
||||
}
|
||||
@@ -398,8 +405,10 @@
|
||||
var action, condition, original;
|
||||
original = null;
|
||||
condition = function(token, i) {
|
||||
var _ref;
|
||||
return (_ref = token[0]) === 'TERMINATOR' || _ref === 'INDENT';
|
||||
var prevTag, tag;
|
||||
tag = token[0];
|
||||
prevTag = this.tokens[i - 1][0];
|
||||
return tag === 'TERMINATOR' || (tag === 'INDENT' && __indexOf.call(SINGLE_LINERS, prevTag) < 0);
|
||||
};
|
||||
action = function(token, i) {
|
||||
if (token[0] !== 'INDENT' || (token.generated && !token.fromThen)) {
|
||||
@@ -416,7 +425,7 @@
|
||||
});
|
||||
};
|
||||
|
||||
Rewriter.prototype.indentation = function(token, implicit) {
|
||||
Rewriter.prototype.indentation = function(implicit) {
|
||||
var indent, outdent;
|
||||
if (implicit == null) {
|
||||
implicit = false;
|
||||
@@ -461,12 +470,10 @@
|
||||
|
||||
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS'];
|
||||
|
||||
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'NULL', 'UNDEFINED', 'UNARY', 'SUPER', '@', '->', '=>', '[', '(', '{', '--', '++'];
|
||||
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'NULL', 'UNDEFINED', 'UNARY', 'SUPER', 'THROW', '@', '->', '=>', '[', '(', '{', '--', '++'];
|
||||
|
||||
IMPLICIT_UNSPACED_CALL = ['+', '-'];
|
||||
|
||||
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','];
|
||||
|
||||
IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR'];
|
||||
|
||||
SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN'];
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var Scope, extend, last, _ref;
|
||||
|
||||
_ref = require('./helpers'), extend = _ref.extend, last = _ref.last;
|
||||
|
||||
exports.Scope = Scope = (function() {
|
||||
|
||||
Scope.root = null;
|
||||
|
||||
function Scope(parent, expressions, method) {
|
||||
|
||||
@@ -1,237 +1,161 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var BASE64_CHARS, LineMapping, MAX_BASE64_VALUE, VLQ_CONTINUATION_BIT, VLQ_SHIFT, VLQ_VALUE_MASK, decodeBase64Char, encodeBase64Char;
|
||||
var LineMap, SourceMap;
|
||||
|
||||
LineMapping = (function() {
|
||||
|
||||
function LineMapping(generatedLine) {
|
||||
this.generatedLine = generatedLine;
|
||||
this.columnMap = {};
|
||||
this.columnMappings = [];
|
||||
LineMap = (function() {
|
||||
function LineMap(line) {
|
||||
this.line = line;
|
||||
this.columns = [];
|
||||
}
|
||||
|
||||
LineMapping.prototype.addMapping = function(generatedColumn, _arg, options) {
|
||||
LineMap.prototype.add = function(column, _arg, options) {
|
||||
var sourceColumn, sourceLine;
|
||||
sourceLine = _arg[0], sourceColumn = _arg[1];
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
if (this.columnMap[generatedColumn] && options.noReplace) {
|
||||
if (this.columns[column] && options.noReplace) {
|
||||
return;
|
||||
}
|
||||
this.columnMap[generatedColumn] = {
|
||||
generatedLine: this.generatedLine,
|
||||
generatedColumn: generatedColumn,
|
||||
return this.columns[column] = {
|
||||
line: this.line,
|
||||
column: column,
|
||||
sourceLine: sourceLine,
|
||||
sourceColumn: sourceColumn
|
||||
};
|
||||
this.columnMappings.push(this.columnMap[generatedColumn]);
|
||||
return this.columnMappings.sort(function(a, b) {
|
||||
return a.generatedColumn - b.generatedColumn;
|
||||
});
|
||||
};
|
||||
|
||||
LineMapping.prototype.getSourcePosition = function(generatedColumn) {
|
||||
var answer, columnMapping, lastColumnMapping, _i, _len, _ref;
|
||||
answer = null;
|
||||
lastColumnMapping = null;
|
||||
_ref = this.columnMappings;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
columnMapping = _ref[_i];
|
||||
if (columnMapping.generatedColumn > generatedColumn) {
|
||||
break;
|
||||
} else {
|
||||
lastColumnMapping = columnMapping;
|
||||
}
|
||||
}
|
||||
if (lastColumnMapping) {
|
||||
return answer = [lastColumnMapping.sourceLine, lastColumnMapping.sourceColumn];
|
||||
LineMap.prototype.sourceLocation = function(column) {
|
||||
var mapping;
|
||||
while (!((mapping = this.columns[column]) || (column <= 0))) {
|
||||
column--;
|
||||
}
|
||||
return mapping && [mapping.sourceLine, mapping.sourceColumn];
|
||||
};
|
||||
|
||||
return LineMapping;
|
||||
return LineMap;
|
||||
|
||||
})();
|
||||
|
||||
exports.SourceMap = (function() {
|
||||
SourceMap = (function() {
|
||||
var BASE64_CHARS, VLQ_CONTINUATION_BIT, VLQ_SHIFT, VLQ_VALUE_MASK;
|
||||
|
||||
function SourceMap() {
|
||||
this.generatedLines = [];
|
||||
this.lines = [];
|
||||
}
|
||||
|
||||
SourceMap.prototype.addMapping = function(sourceLocation, generatedLocation, options) {
|
||||
var generatedColumn, generatedLine, lineMapping;
|
||||
SourceMap.prototype.add = function(sourceLocation, generatedLocation, options) {
|
||||
var column, line, lineMap, _base;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
generatedLine = generatedLocation[0], generatedColumn = generatedLocation[1];
|
||||
lineMapping = this.generatedLines[generatedLine];
|
||||
if (!lineMapping) {
|
||||
lineMapping = this.generatedLines[generatedLine] = new LineMapping(generatedLine);
|
||||
}
|
||||
return lineMapping.addMapping(generatedColumn, sourceLocation, options);
|
||||
line = generatedLocation[0], column = generatedLocation[1];
|
||||
lineMap = ((_base = this.lines)[line] || (_base[line] = new LineMap(line)));
|
||||
return lineMap.add(column, sourceLocation, options);
|
||||
};
|
||||
|
||||
SourceMap.prototype.getSourcePosition = function(_arg) {
|
||||
var answer, generatedColumn, generatedLine, lineMapping;
|
||||
generatedLine = _arg[0], generatedColumn = _arg[1];
|
||||
answer = null;
|
||||
lineMapping = this.generatedLines[generatedLine];
|
||||
if (!lineMapping) {
|
||||
SourceMap.prototype.sourceLocation = function(_arg) {
|
||||
var column, line, lineMap;
|
||||
line = _arg[0], column = _arg[1];
|
||||
while (!((lineMap = this.lines[line]) || (line <= 0))) {
|
||||
line--;
|
||||
}
|
||||
return lineMap && lineMap.sourceLocation(column);
|
||||
};
|
||||
|
||||
} else {
|
||||
answer = lineMapping.getSourcePosition(generatedColumn);
|
||||
SourceMap.prototype.generate = function(options, code) {
|
||||
var buffer, lastColumn, lastSourceColumn, lastSourceLine, lineMap, lineNumber, mapping, needComma, v3, writingline, _i, _j, _len, _len1, _ref, _ref1;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
if (code == null) {
|
||||
code = null;
|
||||
}
|
||||
writingline = 0;
|
||||
lastColumn = 0;
|
||||
lastSourceLine = 0;
|
||||
lastSourceColumn = 0;
|
||||
needComma = false;
|
||||
buffer = "";
|
||||
_ref = this.lines;
|
||||
for (lineNumber = _i = 0, _len = _ref.length; _i < _len; lineNumber = ++_i) {
|
||||
lineMap = _ref[lineNumber];
|
||||
if (lineMap) {
|
||||
_ref1 = lineMap.columns;
|
||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||
mapping = _ref1[_j];
|
||||
if (!(mapping)) {
|
||||
continue;
|
||||
}
|
||||
while (writingline < mapping.line) {
|
||||
lastColumn = 0;
|
||||
needComma = false;
|
||||
buffer += ";";
|
||||
writingline++;
|
||||
}
|
||||
if (needComma) {
|
||||
buffer += ",";
|
||||
needComma = false;
|
||||
}
|
||||
buffer += this.encodeVlq(mapping.column - lastColumn);
|
||||
lastColumn = mapping.column;
|
||||
buffer += this.encodeVlq(0);
|
||||
buffer += this.encodeVlq(mapping.sourceLine - lastSourceLine);
|
||||
lastSourceLine = mapping.sourceLine;
|
||||
buffer += this.encodeVlq(mapping.sourceColumn - lastSourceColumn);
|
||||
lastSourceColumn = mapping.sourceColumn;
|
||||
needComma = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
v3 = {
|
||||
version: 3,
|
||||
file: options.generatedFile || '',
|
||||
sourceRoot: options.sourceRoot || '',
|
||||
sources: options.sourceFiles || [''],
|
||||
names: [],
|
||||
mappings: buffer
|
||||
};
|
||||
if (options.inline) {
|
||||
v3.sourcesContent = [code];
|
||||
}
|
||||
return JSON.stringify(v3, null, 2);
|
||||
};
|
||||
|
||||
VLQ_SHIFT = 5;
|
||||
|
||||
VLQ_CONTINUATION_BIT = 1 << VLQ_SHIFT;
|
||||
|
||||
VLQ_VALUE_MASK = VLQ_CONTINUATION_BIT - 1;
|
||||
|
||||
SourceMap.prototype.encodeVlq = function(value) {
|
||||
var answer, nextChunk, signBit, valueToEncode;
|
||||
answer = '';
|
||||
signBit = value < 0 ? 1 : 0;
|
||||
valueToEncode = (Math.abs(value) << 1) + signBit;
|
||||
while (valueToEncode || !answer) {
|
||||
nextChunk = valueToEncode & VLQ_VALUE_MASK;
|
||||
valueToEncode = valueToEncode >> VLQ_SHIFT;
|
||||
if (valueToEncode) {
|
||||
nextChunk |= VLQ_CONTINUATION_BIT;
|
||||
}
|
||||
answer += this.encodeBase64(nextChunk);
|
||||
}
|
||||
return answer;
|
||||
};
|
||||
|
||||
SourceMap.prototype.forEachMapping = function(fn) {
|
||||
var columnMapping, generatedLineNumber, lineMapping, _i, _len, _ref, _results;
|
||||
_ref = this.generatedLines;
|
||||
_results = [];
|
||||
for (generatedLineNumber = _i = 0, _len = _ref.length; _i < _len; generatedLineNumber = ++_i) {
|
||||
lineMapping = _ref[generatedLineNumber];
|
||||
if (lineMapping) {
|
||||
_results.push((function() {
|
||||
var _j, _len1, _ref1, _results1;
|
||||
_ref1 = lineMapping.columnMappings;
|
||||
_results1 = [];
|
||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||
columnMapping = _ref1[_j];
|
||||
_results1.push(fn(columnMapping));
|
||||
}
|
||||
return _results1;
|
||||
})());
|
||||
} else {
|
||||
_results.push(void 0);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
|
||||
SourceMap.prototype.encodeBase64 = function(value) {
|
||||
return BASE64_CHARS[value] || (function() {
|
||||
throw new Error("Cannot Base64 encode value: " + value);
|
||||
})();
|
||||
};
|
||||
|
||||
return SourceMap;
|
||||
|
||||
})();
|
||||
|
||||
exports.generateV3SourceMap = function(sourceMap, sourceFile, generatedFile) {
|
||||
var answer, lastGeneratedColumnWritten, lastSourceColumnWritten, lastSourceLineWritten, mappings, needComma, writingGeneratedLine;
|
||||
if (sourceFile == null) {
|
||||
sourceFile = null;
|
||||
}
|
||||
if (generatedFile == null) {
|
||||
generatedFile = null;
|
||||
}
|
||||
writingGeneratedLine = 0;
|
||||
lastGeneratedColumnWritten = 0;
|
||||
lastSourceLineWritten = 0;
|
||||
lastSourceColumnWritten = 0;
|
||||
needComma = false;
|
||||
mappings = "";
|
||||
sourceMap.forEachMapping(function(mapping) {
|
||||
while (writingGeneratedLine < mapping.generatedLine) {
|
||||
lastGeneratedColumnWritten = 0;
|
||||
needComma = false;
|
||||
mappings += ";";
|
||||
writingGeneratedLine++;
|
||||
}
|
||||
if (needComma) {
|
||||
mappings += ",";
|
||||
needComma = false;
|
||||
}
|
||||
mappings += exports.vlqEncodeValue(mapping.generatedColumn - lastGeneratedColumnWritten);
|
||||
lastGeneratedColumnWritten = mapping.generatedColumn;
|
||||
mappings += exports.vlqEncodeValue(0);
|
||||
mappings += exports.vlqEncodeValue(mapping.sourceLine - lastSourceLineWritten);
|
||||
lastSourceLineWritten = mapping.sourceLine;
|
||||
mappings += exports.vlqEncodeValue(mapping.sourceColumn - lastSourceColumnWritten);
|
||||
lastSourceColumnWritten = mapping.sourceColumn;
|
||||
return needComma = true;
|
||||
});
|
||||
answer = {
|
||||
version: 3,
|
||||
file: generatedFile,
|
||||
sourceRoot: "",
|
||||
sources: sourceFile ? [sourceFile] : [],
|
||||
names: [],
|
||||
mappings: mappings
|
||||
};
|
||||
return JSON.stringify(answer, null, 2);
|
||||
};
|
||||
|
||||
exports.loadV3SourceMap = function(sourceMap) {
|
||||
return todo();
|
||||
};
|
||||
|
||||
BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
|
||||
MAX_BASE64_VALUE = BASE64_CHARS.length - 1;
|
||||
|
||||
encodeBase64Char = function(value) {
|
||||
if (value > MAX_BASE64_VALUE) {
|
||||
throw new Error("Cannot encode value " + value + " > " + MAX_BASE64_VALUE);
|
||||
} else if (value < 0) {
|
||||
throw new Error("Cannot encode value " + value + " < 0");
|
||||
}
|
||||
return BASE64_CHARS[value];
|
||||
};
|
||||
|
||||
decodeBase64Char = function(char) {
|
||||
var value;
|
||||
value = BASE64_CHARS.indexOf(char);
|
||||
if (value === -1) {
|
||||
throw new Error("Invalid Base 64 character: " + char);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
VLQ_SHIFT = 5;
|
||||
|
||||
VLQ_CONTINUATION_BIT = 1 << VLQ_SHIFT;
|
||||
|
||||
VLQ_VALUE_MASK = VLQ_CONTINUATION_BIT - 1;
|
||||
|
||||
exports.vlqEncodeValue = function(value) {
|
||||
var answer, nextVlqChunk, signBit, valueToEncode;
|
||||
signBit = value < 0 ? 1 : 0;
|
||||
valueToEncode = (Math.abs(value) << 1) + signBit;
|
||||
answer = "";
|
||||
while (valueToEncode || !answer) {
|
||||
nextVlqChunk = valueToEncode & VLQ_VALUE_MASK;
|
||||
valueToEncode = valueToEncode >> VLQ_SHIFT;
|
||||
if (valueToEncode) {
|
||||
nextVlqChunk |= VLQ_CONTINUATION_BIT;
|
||||
}
|
||||
answer += encodeBase64Char(nextVlqChunk);
|
||||
}
|
||||
return answer;
|
||||
};
|
||||
|
||||
exports.vlqDecodeValue = function(str, offset) {
|
||||
var consumed, continuationShift, done, nextChunkValue, nextVlqChunk, position, signBit, value;
|
||||
if (offset == null) {
|
||||
offset = 0;
|
||||
}
|
||||
position = offset;
|
||||
done = false;
|
||||
value = 0;
|
||||
continuationShift = 0;
|
||||
while (!done) {
|
||||
nextVlqChunk = decodeBase64Char(str[position]);
|
||||
position += 1;
|
||||
nextChunkValue = nextVlqChunk & VLQ_VALUE_MASK;
|
||||
value += nextChunkValue << continuationShift;
|
||||
if (!(nextVlqChunk & VLQ_CONTINUATION_BIT)) {
|
||||
done = true;
|
||||
}
|
||||
continuationShift += VLQ_SHIFT;
|
||||
}
|
||||
consumed = position - offset;
|
||||
signBit = value & 1;
|
||||
value = value >> 1;
|
||||
if (signBit) {
|
||||
value = -value;
|
||||
}
|
||||
return [value, consumed];
|
||||
};
|
||||
module.exports = SourceMap;
|
||||
|
||||
}).call(this);
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
"description": "Unfancy JavaScript",
|
||||
"keywords": ["javascript", "language", "coffeescript", "compiler"],
|
||||
"author": "Jeremy Ashkenas",
|
||||
"version": "1.6.1",
|
||||
"version": "1.6.3",
|
||||
"licenses": [{
|
||||
"type": "MIT",
|
||||
"url": "https://raw.github.com/jashkenas/coffee-script/master/LICENSE"
|
||||
}],
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
"directories" : {
|
||||
"lib" : "./lib/coffee-script"
|
||||
|
||||
@@ -1,27 +1,43 @@
|
||||
# Override exported methods for non-Node.js engines.
|
||||
# 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.
|
||||
|
||||
CoffeeScript = require './coffee-script'
|
||||
CoffeeScript.require = require
|
||||
compile = CoffeeScript.compile
|
||||
|
||||
# Use standard JavaScript `eval` to eval code.
|
||||
CoffeeScript.eval = (code, options = {}) ->
|
||||
options.bare ?= on
|
||||
eval CoffeeScript.compile code, options
|
||||
eval compile code, options
|
||||
|
||||
# Running code does not provide access to this scope.
|
||||
CoffeeScript.run = (code, options = {}) ->
|
||||
options.bare = on
|
||||
Function(CoffeeScript.compile code, options)()
|
||||
options.shiftLine = on
|
||||
Function(compile code, options)()
|
||||
|
||||
# If we're not in a browser environment, we're finished with the public API.
|
||||
return unless window?
|
||||
|
||||
# Include source maps where possible. If we've got a base64 encoder, a
|
||||
# JSON serializer, and tools for escaping unicode characters, we're good to go.
|
||||
# Ported from https://developer.mozilla.org/en-US/docs/DOM/window.btoa
|
||||
if btoa? and JSON? and unescape? and encodeURIComponent?
|
||||
compile = (code, options = {}) ->
|
||||
options.sourceMap = true
|
||||
options.inline = true
|
||||
{js, v3SourceMap} = CoffeeScript.compile code, options
|
||||
"#{js}\n//@ sourceMappingURL=data:application/json;base64,#{btoa unescape encodeURIComponent v3SourceMap}\n//@ sourceURL=coffeescript"
|
||||
|
||||
# Load a remote script from the current domain via XHR.
|
||||
CoffeeScript.load = (url, callback, options = {}) ->
|
||||
options.sourceFiles = [url]
|
||||
xhr = if window.ActiveXObject
|
||||
new window.ActiveXObject('Microsoft.XMLHTTP')
|
||||
else
|
||||
new XMLHttpRequest()
|
||||
new window.XMLHttpRequest()
|
||||
xhr.open 'GET', url, true
|
||||
xhr.overrideMimeType 'text/plain' if 'overrideMimeType' of xhr
|
||||
xhr.onreadystatechange = ->
|
||||
@@ -37,7 +53,7 @@ CoffeeScript.load = (url, callback, options = {}) ->
|
||||
# all script tags with a content-type of `text/coffeescript`.
|
||||
# This happens on page load.
|
||||
runScripts = ->
|
||||
scripts = document.getElementsByTagName 'script'
|
||||
scripts = window.document.getElementsByTagName 'script'
|
||||
coffeetypes = ['text/coffeescript', 'text/literate-coffeescript']
|
||||
coffees = (s for s in scripts when s.type in coffeetypes)
|
||||
index = 0
|
||||
@@ -50,12 +66,13 @@ runScripts = ->
|
||||
if script.src
|
||||
CoffeeScript.load script.src, execute, options
|
||||
else
|
||||
options.sourceFiles = ['embedded']
|
||||
CoffeeScript.run script.innerHTML, options
|
||||
execute()
|
||||
null
|
||||
|
||||
# Listen for window load, both in browsers and in IE.
|
||||
# Listen for window load, both in decent browsers and in IE.
|
||||
if window.addEventListener
|
||||
addEventListener 'DOMContentLoaded', runScripts, no
|
||||
window.addEventListener 'DOMContentLoaded', runScripts, no
|
||||
else
|
||||
attachEvent 'onload', runScripts
|
||||
window.attachEvent 'onload', runScripts
|
||||
|
||||
@@ -1,77 +1,59 @@
|
||||
# CoffeeScript can be used both on the server, as a command-line compiler based
|
||||
# on Node.js/V8, or to run CoffeeScripts directly in the browser. This module
|
||||
# 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.
|
||||
#
|
||||
# If included on a webpage, it will automatically sniff out, compile, and
|
||||
# execute all scripts present in `text/coffeescript` tags.
|
||||
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
{Lexer} = require './lexer'
|
||||
{parser} = require './parser'
|
||||
helpers = require './helpers'
|
||||
vm = require 'vm'
|
||||
sourcemap = require './sourcemap'
|
||||
|
||||
# Load and run a CoffeeScript file for Node, stripping any `BOM`s.
|
||||
loadFile = (module, filename) ->
|
||||
raw = fs.readFileSync filename, 'utf8'
|
||||
stripped = if raw.charCodeAt(0) is 0xFEFF then raw.substring 1 else raw
|
||||
module._compile compile(stripped, {filename, literate: helpers.isLiterate filename}), filename
|
||||
|
||||
if require.extensions
|
||||
for ext in ['.coffee', '.litcoffee', '.md', '.coffee.md']
|
||||
require.extensions[ext] = loadFile
|
||||
fs = require 'fs'
|
||||
vm = require 'vm'
|
||||
path = require 'path'
|
||||
child_process = require 'child_process'
|
||||
{Lexer} = require './lexer'
|
||||
{parser} = require './parser'
|
||||
helpers = require './helpers'
|
||||
SourceMap = require './sourcemap'
|
||||
|
||||
# The current CoffeeScript version number.
|
||||
exports.VERSION = '1.6.1'
|
||||
exports.VERSION = '1.6.3'
|
||||
|
||||
# Expose helpers for testing.
|
||||
exports.helpers = helpers
|
||||
|
||||
# Compile CoffeeScript code to JavaScript, using the Coffee/Jison compiler.
|
||||
#
|
||||
# If `options.sourceMap` is specified, then `options.filename` must also be specified.
|
||||
# If `options.sourceMap` is specified, then `options.filename` must also be specified. All
|
||||
# options that can be passed to `SourceMap#generate` may also be passed here.
|
||||
#
|
||||
# This returns a javascript string, unless `options.sourceMap` is passed,
|
||||
# in which case this returns a `{js, v3SourceMap, sourceMap}
|
||||
# in which case this returns a `{js, v3SourceMap, sourceMap}`
|
||||
# object, where sourceMap is a sourcemap.coffee#SourceMap object, handy for doing programatic
|
||||
# lookups.
|
||||
exports.compile = compile = (code, options = {}) ->
|
||||
{merge} = exports.helpers
|
||||
try
|
||||
{merge} = helpers
|
||||
|
||||
if options.sourceMap
|
||||
map = new SourceMap
|
||||
|
||||
fragments = parser.parse(lexer.tokenize code, options).compileToFragments options
|
||||
|
||||
currentLine = 0
|
||||
currentLine += 1 if options.header
|
||||
currentLine += 1 if options.shiftLine
|
||||
currentColumn = 0
|
||||
js = ""
|
||||
for fragment in fragments
|
||||
# Update the sourcemap with data from each fragment
|
||||
if options.sourceMap
|
||||
coffeeFile = helpers.baseFileName options.filename
|
||||
jsFile = helpers.baseFileName(options.filename, yes) + ".js"
|
||||
sourceMap = new sourcemap.SourceMap()
|
||||
if fragment.locationData
|
||||
map.add(
|
||||
[fragment.locationData.first_line, fragment.locationData.first_column]
|
||||
[currentLine, currentColumn]
|
||||
{noReplace: true})
|
||||
newLines = helpers.count fragment.code, "\n"
|
||||
currentLine += newLines
|
||||
currentColumn = fragment.code.length - (if newLines then fragment.code.lastIndexOf "\n" else 0)
|
||||
|
||||
fragments = (parser.parse lexer.tokenize(code, options)).compileToFragments options
|
||||
|
||||
currentLine = 0
|
||||
currentLine += 1 if options.header
|
||||
currentLine += 1 if options.sourceMap
|
||||
currentColumn = 0
|
||||
js = ""
|
||||
for fragment in fragments
|
||||
# Update the sourcemap with data from each fragment
|
||||
if sourceMap
|
||||
if fragment.locationData
|
||||
sourceMap.addMapping(
|
||||
[fragment.locationData.first_line, fragment.locationData.first_column],
|
||||
[currentLine, currentColumn],
|
||||
{noReplace: true})
|
||||
newLines = helpers.count fragment.code, "\n"
|
||||
currentLine += newLines
|
||||
currentColumn = fragment.code.length - (if newLines then fragment.code.lastIndexOf "\n" else 0)
|
||||
|
||||
# Copy the code from each fragment into the final JavaScript.
|
||||
js += fragment.code
|
||||
|
||||
catch err
|
||||
err.message = "In #{options.filename}, #{err.message}" if options.filename
|
||||
throw err
|
||||
# Copy the code from each fragment into the final JavaScript.
|
||||
js += fragment.code
|
||||
|
||||
if options.header
|
||||
header = "Generated by CoffeeScript #{@VERSION}"
|
||||
@@ -79,9 +61,8 @@ exports.compile = compile = (code, options = {}) ->
|
||||
|
||||
if options.sourceMap
|
||||
answer = {js}
|
||||
if sourceMap
|
||||
answer.sourceMap = sourceMap
|
||||
answer.v3SourceMap = sourcemap.generateV3SourceMap sourceMap, coffeeFile, jsFile
|
||||
answer.sourceMap = map
|
||||
answer.v3SourceMap = map.generate(options, code)
|
||||
answer
|
||||
else
|
||||
js
|
||||
@@ -103,20 +84,25 @@ exports.nodes = (source, options) ->
|
||||
# setting `__filename`, `__dirname`, and relative `require()`.
|
||||
exports.run = (code, options = {}) ->
|
||||
mainModule = require.main
|
||||
|
||||
options.sourceMap ?= true
|
||||
# Set the filename.
|
||||
mainModule.filename = process.argv[1] =
|
||||
if options.filename then fs.realpathSync(options.filename) else '.'
|
||||
if options.filename then fs.realpathSync(options.filename) else '.'
|
||||
|
||||
# Clear the module cache.
|
||||
mainModule.moduleCache and= {}
|
||||
|
||||
# Assign paths for node_modules loading
|
||||
mainModule.paths = require('module')._nodeModulePaths path.dirname fs.realpathSync options.filename
|
||||
mainModule.paths = require('module')._nodeModulePaths path.dirname fs.realpathSync options.filename or '.'
|
||||
|
||||
# Compile.
|
||||
if not helpers.isCoffee(mainModule.filename) or require.extensions
|
||||
mainModule._compile compile(code, options), mainModule.filename
|
||||
answer = compile(code, options)
|
||||
# Attach sourceMap object to sourceMaps[options.filename] so that
|
||||
# it is accessible by Error.prepareStackTrace.
|
||||
do patchStackTrace
|
||||
sourceMaps[mainModule.filename] = answer.sourceMap
|
||||
mainModule._compile answer.js, mainModule.filename
|
||||
else
|
||||
mainModule._compile code, mainModule.filename
|
||||
|
||||
@@ -156,6 +142,55 @@ exports.eval = (code, options = {}) ->
|
||||
else
|
||||
vm.runInContext js, sandbox
|
||||
|
||||
# Load and run a CoffeeScript file for Node, stripping any `BOM`s.
|
||||
loadFile = (module, filename) ->
|
||||
raw = fs.readFileSync filename, 'utf8'
|
||||
stripped = if raw.charCodeAt(0) is 0xFEFF then raw.substring 1 else raw
|
||||
answer = compile(stripped, {filename, sourceMap: true, literate: helpers.isLiterate filename})
|
||||
sourceMaps[filename] = answer.sourceMap
|
||||
module._compile answer.js, filename
|
||||
|
||||
# If the installed version of Node supports `require.extensions`, register
|
||||
# CoffeeScript as an extension.
|
||||
if require.extensions
|
||||
for ext in ['.coffee', '.litcoffee', '.coffee.md']
|
||||
require.extensions[ext] = loadFile
|
||||
|
||||
# Patch Node's module loader to be able to handle mult-dot extensions.
|
||||
# This is a horrible thing that should not be required. Perhaps, one day,
|
||||
# when a truly benevolent dictator comes to rule over the Republik of Node,
|
||||
# it won't be.
|
||||
Module = require 'module'
|
||||
|
||||
findExtension = (filename) ->
|
||||
extensions = path.basename(filename).split '.'
|
||||
# Remove the initial dot from dotfiles.
|
||||
extensions.shift() if extensions[0] is ''
|
||||
# Start with the longest possible extension and work our way shortwards.
|
||||
while extensions.shift()
|
||||
curExtension = '.' + extensions.join '.'
|
||||
return curExtension if Module._extensions[curExtension]
|
||||
'.js'
|
||||
|
||||
Module::load = (filename) ->
|
||||
@filename = filename
|
||||
@paths = Module._nodeModulePaths path.dirname filename
|
||||
extension = findExtension filename
|
||||
Module._extensions[extension](this, filename)
|
||||
@loaded = true
|
||||
|
||||
# If we're on Node, patch `child_process.fork` so that Coffee scripts are able
|
||||
# to fork both CoffeeScript files, and JavaScript files, directly.
|
||||
if child_process
|
||||
{fork} = child_process
|
||||
child_process.fork = (path, args = [], options = {}) ->
|
||||
execPath = if helpers.isCoffee(path) then 'coffee' else null
|
||||
if not Array.isArray args
|
||||
args = []
|
||||
options = args or {}
|
||||
options.execPath or= execPath
|
||||
fork path, args, options
|
||||
|
||||
# Instantiate a Lexer for our use here.
|
||||
lexer = new Lexer
|
||||
|
||||
@@ -177,4 +212,103 @@ parser.lexer =
|
||||
upcomingInput: ->
|
||||
""
|
||||
|
||||
# Make all the AST nodes visible to the parser.
|
||||
parser.yy = require './nodes'
|
||||
|
||||
# Override Jison's default error handling function.
|
||||
parser.yy.parseError = (message, {token}) ->
|
||||
# Disregard Jison's message, it contains redundant line numer information.
|
||||
message = "unexpected #{if token is 1 then 'end of input' else token}"
|
||||
# The second argument has a `loc` property, which should have the location
|
||||
# data for this token. Unfortunately, Jison seems to send an outdated `loc`
|
||||
# (from the previous token), so we take the location information directly
|
||||
# from the lexer.
|
||||
helpers.throwSyntaxError message, parser.lexer.yylloc
|
||||
|
||||
# Based on [michaelficarra/CoffeeScriptRedux](http://goo.gl/ZTx1p)
|
||||
# NodeJS / V8 have no support for transforming positions in stack traces using
|
||||
# sourceMap, so we must monkey-patch Error to display CoffeeScript source
|
||||
# positions.
|
||||
|
||||
patched = false
|
||||
|
||||
# Map of filenames -> sourceMap object.
|
||||
sourceMaps = {}
|
||||
|
||||
patchStackTrace = ->
|
||||
return if patched
|
||||
patched = true
|
||||
mainModule = require.main
|
||||
|
||||
# (Assigning to a property of the Module object in the normal module cache is
|
||||
# unsuitable, because node deletes those objects from the cache if an
|
||||
# exception is thrown in the module body.)
|
||||
|
||||
Error.prepareStackTrace = (err, stack) ->
|
||||
sourceFiles = {}
|
||||
|
||||
getSourceMapping = (filename, line, column) ->
|
||||
sourceMap = sourceMaps[filename]
|
||||
answer = sourceMap.sourceLocation [line - 1, column - 1] if sourceMap
|
||||
if answer then [answer[0] + 1, answer[1] + 1] else null
|
||||
|
||||
frames = for frame in stack
|
||||
break if frame.getFunction() is exports.run
|
||||
" at #{formatSourcePosition frame, getSourceMapping}"
|
||||
|
||||
"#{err.name}: #{err.message ? ''}\n#{frames.join '\n'}\n"
|
||||
|
||||
# Based on http://v8.googlecode.com/svn/branches/bleeding_edge/src/messages.js
|
||||
# Modified to handle sourceMap
|
||||
formatSourcePosition = (frame, getSourceMapping) ->
|
||||
fileName = undefined
|
||||
fileLocation = ''
|
||||
|
||||
if frame.isNative()
|
||||
fileLocation = "native"
|
||||
else
|
||||
if frame.isEval()
|
||||
fileName = frame.getScriptNameOrSourceURL()
|
||||
fileLocation = "#{frame.getEvalOrigin()}, " unless fileName
|
||||
else
|
||||
fileName = frame.getFileName()
|
||||
|
||||
fileName or= "<anonymous>"
|
||||
|
||||
line = frame.getLineNumber()
|
||||
column = frame.getColumnNumber()
|
||||
|
||||
# Check for a sourceMap position
|
||||
source = getSourceMapping fileName, line, column
|
||||
fileLocation =
|
||||
if source
|
||||
"#{fileName}:#{source[0]}:#{source[1]}, <js>:#{line}:#{column}"
|
||||
else
|
||||
"#{fileName}:#{line}:#{column}"
|
||||
|
||||
|
||||
functionName = frame.getFunctionName()
|
||||
isConstructor = frame.isConstructor()
|
||||
isMethodCall = not (frame.isToplevel() or isConstructor)
|
||||
|
||||
if isMethodCall
|
||||
methodName = frame.getMethodName()
|
||||
typeName = frame.getTypeName()
|
||||
|
||||
if functionName
|
||||
tp = as = ''
|
||||
if typeName and functionName.indexOf typeName
|
||||
tp = "#{typeName}."
|
||||
if methodName and functionName.indexOf(".#{methodName}") isnt functionName.length - methodName.length - 1
|
||||
as = " [as #{methodName}]"
|
||||
|
||||
"#{tp}#{functionName}#{as} (#{fileLocation})"
|
||||
else
|
||||
"#{typeName}.#{methodName or '<anonymous>'} (#{fileLocation})"
|
||||
else if isConstructor
|
||||
"new #{functionName or '<anonymous>'} (#{fileLocation})"
|
||||
else if functionName
|
||||
"#{functionName} (#{fileLocation})"
|
||||
else
|
||||
fileLocation
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# The `coffee` utility. Handles command-line compilation of CoffeeScript
|
||||
# into various forms: saved into `.js` files or printed to stdout, piped to
|
||||
# [JavaScript Lint](http://javascriptlint.com/) or recompiled every time the source is
|
||||
# saved, printed as a token stream or as the syntax tree, or launch an
|
||||
# into various forms: saved into `.js` files or printed to stdout
|
||||
# or recompiled every time the source is saved,
|
||||
# printed as a token stream or as the syntax tree, or launch an
|
||||
# interactive REPL.
|
||||
|
||||
# External dependencies.
|
||||
@@ -14,6 +14,7 @@ CoffeeScript = require './coffee-script'
|
||||
{EventEmitter} = require 'events'
|
||||
|
||||
exists = fs.exists or path.exists
|
||||
useWinPathSep = path.sep is '\\'
|
||||
|
||||
# Allow CoffeeScript to emit Node.js events.
|
||||
helpers.extend CoffeeScript, new EventEmitter
|
||||
@@ -38,13 +39,13 @@ SWITCHES = [
|
||||
['-h', '--help', 'display this help message']
|
||||
['-i', '--interactive', 'run an interactive CoffeeScript REPL']
|
||||
['-j', '--join [FILE]', 'concatenate the source CoffeeScript before compiling']
|
||||
['-l', '--lint', 'pipe the compiled JavaScript through JavaScript Lint']
|
||||
['-m', '--map', 'generate source map and save as .map files']
|
||||
['-n', '--nodes', 'print out the parse tree that the parser produces']
|
||||
[ '--nodejs [ARGS]', 'pass options directly to the "node" binary']
|
||||
['-o', '--output [DIR]', 'set the output directory for compiled JavaScript']
|
||||
['-p', '--print', 'print out the compiled JavaScript']
|
||||
['-s', '--stdio', 'listen for and compile scripts over stdio']
|
||||
['-l', '--literate', 'treat stdio as literate style coffee-script']
|
||||
['-t', '--tokens', 'print out the tokens that the lexer/rewriter produce']
|
||||
['-v', '--version', 'display the version number']
|
||||
['-w', '--watch', 'watch scripts for changes and rerun commands']
|
||||
@@ -67,7 +68,7 @@ exports.run = ->
|
||||
return usage() if opts.help
|
||||
return version() if opts.version
|
||||
return require('./repl').start() if opts.interactive
|
||||
if opts.watch and !fs.watch
|
||||
if opts.watch and not fs.watch
|
||||
return printWarn "The --watch feature depends on Node v0.6.0+. You are running #{process.version}."
|
||||
return compileStdio() if opts.stdio
|
||||
return compileScript null, sources[0] if opts.eval
|
||||
@@ -112,9 +113,9 @@ compilePath = (source, topLevel, base) ->
|
||||
# Compile a single source script, containing the given code, according to the
|
||||
# requested options. If evaluating the script directly sets `__filename`,
|
||||
# `__dirname` and `module.filename` to be correct relative to the script's path.
|
||||
compileScript = (file, input, base) ->
|
||||
compileScript = (file, input, base=null) ->
|
||||
o = opts
|
||||
options = compileOptions file
|
||||
options = compileOptions file, base
|
||||
try
|
||||
t = task = {file, input, options}
|
||||
CoffeeScript.emit 'compile', task
|
||||
@@ -122,6 +123,7 @@ compileScript = (file, input, base) ->
|
||||
else if o.nodes then printLine CoffeeScript.nodes(t.input, t.options).toString().trim()
|
||||
else if o.run then CoffeeScript.run t.input, t.options
|
||||
else if o.join and t.file isnt o.join
|
||||
t.input = helpers.invertLiterate t.input if helpers.isLiterate file
|
||||
sourceCode[sources.indexOf(t.file)] = t.input
|
||||
compileJoin()
|
||||
else
|
||||
@@ -134,16 +136,18 @@ compileScript = (file, input, base) ->
|
||||
CoffeeScript.emit 'success', task
|
||||
if o.print
|
||||
printLine t.output.trim()
|
||||
else if o.compile || o.map
|
||||
writeJs base, t.file, t.output, t.sourceMap
|
||||
else if o.lint
|
||||
lint t.file, t.output
|
||||
else if o.compile or o.map
|
||||
writeJs base, t.file, t.output, options.jsPath, t.sourceMap
|
||||
catch err
|
||||
CoffeeScript.emit 'failure', err, task
|
||||
return if CoffeeScript.listeners('failure').length
|
||||
return printLine err.message + '\x07' if o.watch
|
||||
printWarn err instanceof Error and err.stack or "ERROR: #{err}"
|
||||
process.exit 1
|
||||
useColors = process.stdout.isTTY and not process.env.NODE_DISABLE_COLORS
|
||||
message = helpers.prettyErrorMessage err, file or '[stdin]', input, useColors
|
||||
if o.watch
|
||||
printLine message + '\x07'
|
||||
else
|
||||
printWarn message
|
||||
process.exit 1
|
||||
|
||||
# Attach the appropriate listeners to compile scripts incoming over **stdin**,
|
||||
# and write them back to **stdout**.
|
||||
@@ -167,7 +171,7 @@ compileJoin = ->
|
||||
|
||||
# Watch a source CoffeeScript file using `fs.watch`, recompiling it every
|
||||
# time the file is updated. May be used in combination with other options,
|
||||
# such as `--lint` or `--print`.
|
||||
# such as `--print`.
|
||||
watch = (source, base) ->
|
||||
|
||||
prevStats = null
|
||||
@@ -251,7 +255,7 @@ removeSource = (source, base, removeJs) ->
|
||||
|
||||
# Get the corresponding output JavaScript path for a source file.
|
||||
outputPath = (source, base, extension=".js") ->
|
||||
basename = helpers.baseFileName source, yes
|
||||
basename = helpers.baseFileName source, yes, useWinPathSep
|
||||
srcDir = path.dirname source
|
||||
baseDir = if base is '.' then srcDir else srcDir.substring base.length
|
||||
dir = if opts.output then path.join opts.output, baseDir else srcDir
|
||||
@@ -263,14 +267,13 @@ outputPath = (source, base, extension=".js") ->
|
||||
#
|
||||
# If `generatedSourceMap` is provided, this will write a `.map` file into the
|
||||
# same directory as the `.js` file.
|
||||
writeJs = (base, sourcePath, js, generatedSourceMap = null) ->
|
||||
jsPath = outputPath sourcePath, base
|
||||
writeJs = (base, sourcePath, js, jsPath, generatedSourceMap = null) ->
|
||||
sourceMapPath = outputPath sourcePath, base, ".map"
|
||||
jsDir = path.dirname jsPath
|
||||
compile = ->
|
||||
if opts.compile
|
||||
js = ' ' if js.length <= 0
|
||||
if generatedSourceMap then js = "//@ sourceMappingURL=#{helpers.baseFileName sourceMapPath}\n#{js}"
|
||||
if generatedSourceMap then js = "#{js}\n/*\n//@ sourceMappingURL=#{helpers.baseFileName sourceMapPath, no, useWinPathSep}\n*/\n"
|
||||
fs.writeFile jsPath, js, (err) ->
|
||||
if err
|
||||
printLine err.message
|
||||
@@ -290,17 +293,6 @@ wait = (milliseconds, func) -> setTimeout func, milliseconds
|
||||
timeLog = (message) ->
|
||||
console.log "#{(new Date).toLocaleTimeString()} - #{message}"
|
||||
|
||||
# Pipe compiled JS through JSLint (requires a working `jsl` command), printing
|
||||
# any errors or warnings that arise.
|
||||
lint = (file, js) ->
|
||||
printIt = (buffer) -> printLine file + ':\t' + buffer.toString().trim()
|
||||
conf = __dirname + '/../../extras/jsl.conf'
|
||||
jsl = spawn 'jsl', ['-nologo', '-stdin', '-conf', conf]
|
||||
jsl.stdout.on 'data', printIt
|
||||
jsl.stderr.on 'data', printIt
|
||||
jsl.stdin.write js
|
||||
jsl.stdin.end()
|
||||
|
||||
# Pretty-print a stream of tokens, sans location data.
|
||||
printTokens = (tokens) ->
|
||||
strings = for token in tokens
|
||||
@@ -315,21 +307,38 @@ parseOptions = ->
|
||||
optionParser = new optparse.OptionParser SWITCHES, BANNER
|
||||
o = opts = optionParser.parse process.argv[2..]
|
||||
o.compile or= !!o.output
|
||||
o.run = not (o.compile or o.print or o.lint or o.map)
|
||||
o.run = not (o.compile or o.print or o.map)
|
||||
o.print = !! (o.print or (o.eval or o.stdio and o.compile))
|
||||
sources = o.arguments
|
||||
sourceCode[i] = null for source, i in sources
|
||||
return
|
||||
|
||||
# The compile-time options to pass to the CoffeeScript compiler.
|
||||
compileOptions = (filename) ->
|
||||
{
|
||||
compileOptions = (filename, base) ->
|
||||
answer = {
|
||||
filename
|
||||
literate: helpers.isLiterate(filename)
|
||||
literate: opts.literate or helpers.isLiterate(filename)
|
||||
bare: opts.bare
|
||||
header: opts.compile
|
||||
sourceMap: opts.map
|
||||
}
|
||||
if filename
|
||||
if base
|
||||
cwd = process.cwd()
|
||||
jsPath = outputPath filename, base
|
||||
jsDir = path.dirname jsPath
|
||||
answer = helpers.merge answer, {
|
||||
jsPath
|
||||
sourceRoot: path.relative jsDir, cwd
|
||||
sourceFiles: [path.relative cwd, filename]
|
||||
generatedFile: helpers.baseFileName(jsPath, no, useWinPathSep)
|
||||
}
|
||||
else
|
||||
answer = helpers.merge answer,
|
||||
sourceRoot: ""
|
||||
sourceFiles: [helpers.baseFileName filename, no, useWinPathSep]
|
||||
generatedFile: helpers.baseFileName(filename, yes, useWinPathSep) + ".js"
|
||||
answer
|
||||
|
||||
# Start up a new Node.js instance with the arguments in `--nodejs` passed to
|
||||
# the `node` binary, preserving the other options.
|
||||
|
||||
@@ -401,6 +401,7 @@ grammar =
|
||||
Catch: [
|
||||
o 'CATCH Identifier Block', -> [$2, $3]
|
||||
o 'CATCH Object Block', -> [LOC(2)(new Value($2)), $3]
|
||||
o 'CATCH Block', -> [null, $2]
|
||||
]
|
||||
|
||||
# Throw an exception object.
|
||||
|
||||
@@ -11,6 +11,16 @@ exports.ends = (string, literal, back) ->
|
||||
len = literal.length
|
||||
literal is string.substr string.length - len - (back or 0), len
|
||||
|
||||
# Repeat a string `n` times.
|
||||
exports.repeat = repeat = (str, n) ->
|
||||
# Use clever algorithm to have O(log(n)) string concatenation operations.
|
||||
res = ''
|
||||
while n > 0
|
||||
res += str if n & 1
|
||||
n >>>= 1
|
||||
str += str
|
||||
res
|
||||
|
||||
# Trim out all falsy values from an array.
|
||||
exports.compact = (array) ->
|
||||
item for item in array when item
|
||||
@@ -53,13 +63,27 @@ exports.del = (obj, key) ->
|
||||
val
|
||||
|
||||
# Gets the last item of an array(-like) object.
|
||||
exports.last = (array, back) -> array[array.length - (back or 0) - 1]
|
||||
exports.last = last = (array, back) -> array[array.length - (back or 0) - 1]
|
||||
|
||||
# Typical Array::some
|
||||
exports.some = Array::some ? (fn) ->
|
||||
return true for e in this when fn e
|
||||
false
|
||||
|
||||
# Simple function for inverting Literate CoffeeScript code by putting the
|
||||
# documentation in comments, producing a string of CoffeeScript code that
|
||||
# can be compiled "normally".
|
||||
exports.invertLiterate = (code) ->
|
||||
maybe_code = true
|
||||
lines = for line in code.split('\n')
|
||||
if maybe_code and /^([ ]{4}|[ ]{0,3}\t)/.test line
|
||||
line
|
||||
else if maybe_code = /^\s*$/.test line
|
||||
line
|
||||
else
|
||||
'# ' + line
|
||||
lines.join '\n'
|
||||
|
||||
# Merge two jison-style location data objects together.
|
||||
# If `last` is not provided, this will simply return `first`.
|
||||
buildLocationData = (first, last) ->
|
||||
@@ -71,8 +95,9 @@ buildLocationData = (first, last) ->
|
||||
last_line: last.last_line
|
||||
last_column: last.last_column
|
||||
|
||||
# This returns a function which takes an object as a parameter, and if that object is an AST node,
|
||||
# updates that object's locationData. The object is returned either way.
|
||||
# This returns a function which takes an object as a parameter, and if that
|
||||
# object is an AST node, updates that object's locationData.
|
||||
# The object is returned either way.
|
||||
exports.addLocationDataFn = (first, last) ->
|
||||
(obj) ->
|
||||
if ((typeof obj) is 'object') and (!!obj['updateLocationDataIfMissing'])
|
||||
@@ -93,13 +118,14 @@ exports.locationDataToString = (obj) ->
|
||||
"No location data"
|
||||
|
||||
# A `.coffee.md` compatible version of `basename`, that returns the file sans-extension.
|
||||
exports.baseFileName = (file, stripExt = no) ->
|
||||
parts = file.split('/')
|
||||
exports.baseFileName = (file, stripExt = no, useWinPathSep = no) ->
|
||||
pathSep = if useWinPathSep then /\\|\// else /\//
|
||||
parts = file.split(pathSep)
|
||||
file = parts[parts.length - 1]
|
||||
return file unless stripExt
|
||||
parts = file.split('.')
|
||||
parts.pop()
|
||||
parts.pop() if parts[parts.length - 1] is 'coffee'
|
||||
parts.pop() if parts[parts.length - 1] is 'coffee' and parts.length > 1
|
||||
parts.join('.')
|
||||
|
||||
# Determine if a filename represents a CoffeeScript file.
|
||||
@@ -108,4 +134,40 @@ exports.isCoffee = (file) -> /\.((lit)?coffee|coffee\.md)$/.test file
|
||||
# Determine if a filename represents a Literate CoffeeScript file.
|
||||
exports.isLiterate = (file) -> /\.(litcoffee|coffee\.md)$/.test file
|
||||
|
||||
# Throws a SyntaxError with a source file location data attached to it in a
|
||||
# property called `location`.
|
||||
exports.throwSyntaxError = (message, location) ->
|
||||
location.last_line ?= location.first_line
|
||||
location.last_column ?= location.first_column
|
||||
error = new SyntaxError message
|
||||
error.location = location
|
||||
throw error
|
||||
|
||||
# Creates a nice error message like, following the "standard" format
|
||||
# <filename>:<line>:<col>: <message> plus the line with the error and a marker
|
||||
# showing where the error is.
|
||||
exports.prettyErrorMessage = (error, fileName, code, useColors) ->
|
||||
return error.stack or "#{error}" unless error.location
|
||||
|
||||
{first_line, first_column, last_line, last_column} = error.location
|
||||
codeLine = code.split('\n')[first_line]
|
||||
start = first_column
|
||||
# Show only the first line on multi-line errors.
|
||||
end = if first_line is last_line then last_column + 1 else codeLine.length
|
||||
marker = repeat(' ', start) + repeat('^', end - start)
|
||||
|
||||
if useColors
|
||||
colorize = (str) -> "\x1B[1;31m#{str}\x1B[0m"
|
||||
codeLine = codeLine[...start] + colorize(codeLine[start...end]) + codeLine[end..]
|
||||
marker = colorize marker
|
||||
|
||||
message = """
|
||||
#{fileName}:#{first_line + 1}:#{first_column + 1}: error: #{error.message}
|
||||
#{codeLine}
|
||||
#{marker}
|
||||
"""
|
||||
|
||||
# Uncomment to add stacktrace.
|
||||
#message += "\n#{error.stack}"
|
||||
|
||||
message
|
||||
|
||||
@@ -5,16 +5,15 @@
|
||||
#
|
||||
# [tag, value, locationData]
|
||||
#
|
||||
# The locationData is in the form:
|
||||
# `{first_line, first_column, last_line, last_column}`, which is a
|
||||
# format that can be fed directly into [Jison](http://github.com/zaach/jison).
|
||||
# These are read by Jison in the `parser.lexer` function defined in
|
||||
# coffee-script.coffee.
|
||||
# where locationData is {first_line, first_column, last_line, last_column}, which is a
|
||||
# format that can be fed directly into [Jison](http://github.com/zaach/jison). These
|
||||
# are read by jison in the `parser.lexer` function defined in coffee-script.coffee.
|
||||
|
||||
{Rewriter, INVERSES} = require './rewriter'
|
||||
|
||||
# Import the helpers we need.
|
||||
{count, starts, compact, last, locationDataToString} = require './helpers'
|
||||
{count, starts, compact, last, repeat, invertLiterate,
|
||||
locationDataToString, throwSyntaxError} = require './helpers'
|
||||
|
||||
# The Lexer Class
|
||||
# ---------------
|
||||
@@ -42,7 +41,7 @@ exports.Lexer = class Lexer
|
||||
@outdebt = 0 # The under-outdentation at the current level.
|
||||
@indents = [] # The stack of all current indentation levels.
|
||||
@ends = [] # The stack for pairing up tokens.
|
||||
@tokens = [] # Stream of parsed tokens in the form `['TYPE', value, line]`.
|
||||
@tokens = [] # Stream of parsed tokens in the form `['TYPE', value, location data]`.
|
||||
|
||||
@chunkLine =
|
||||
opts.line or 0 # The start line for the current @chunk.
|
||||
@@ -86,13 +85,7 @@ exports.Lexer = class Lexer
|
||||
if WHITESPACE.test code
|
||||
code = "\n#{code}"
|
||||
@chunkLine--
|
||||
if @literate
|
||||
lines = for line in code.split('\n')
|
||||
if match = LITERATE.exec line
|
||||
line[match[0].length..]
|
||||
else
|
||||
'# ' + line
|
||||
code = lines.join '\n'
|
||||
code = invertLiterate code if @literate
|
||||
code
|
||||
|
||||
# Tokenizers
|
||||
@@ -183,9 +176,9 @@ exports.Lexer = class Lexer
|
||||
@error "octal literal '#{number}' must be prefixed with '0o'"
|
||||
lexedLength = number.length
|
||||
if octalLiteral = /^0o([0-7]+)/.exec number
|
||||
number = '0x' + (parseInt octalLiteral[1], 8).toString 16
|
||||
number = '0x' + parseInt(octalLiteral[1], 8).toString 16
|
||||
if binaryLiteral = /^0b([01]+)/.exec number
|
||||
number = '0x' + (parseInt binaryLiteral[1], 2).toString 16
|
||||
number = '0x' + parseInt(binaryLiteral[1], 2).toString 16
|
||||
@token 'NUMBER', number, 0, lexedLength
|
||||
lexedLength
|
||||
|
||||
@@ -229,7 +222,7 @@ exports.Lexer = class Lexer
|
||||
if here
|
||||
@token 'HERECOMMENT',
|
||||
(@sanitizeHeredoc here,
|
||||
herecomment: true, indent: Array(@indent + 1).join(' ')),
|
||||
herecomment: true, indent: repeat ' ', @indent),
|
||||
0, comment.length
|
||||
comment.length
|
||||
|
||||
@@ -330,7 +323,7 @@ exports.Lexer = class Lexer
|
||||
@suppressNewlines()
|
||||
return indent.length
|
||||
diff = size - @indent + @outdebt
|
||||
@token 'INDENT', diff, 0, indent.length
|
||||
@token 'INDENT', diff, indent.length - size, size
|
||||
@indents.push diff
|
||||
@ends.push 'OUTDENT'
|
||||
@outdebt = @indebt = 0
|
||||
@@ -445,7 +438,6 @@ exports.Lexer = class Lexer
|
||||
attempt = match[1]
|
||||
indent = attempt if indent is null or 0 < attempt.length < indent.length
|
||||
doc = doc.replace /// \n #{indent} ///g, '\n' if indent
|
||||
doc = doc.replace /\n# \n/g, '\n\n' if @literate
|
||||
doc = doc.replace /^\n/, '' unless herecomment
|
||||
doc
|
||||
|
||||
@@ -597,7 +589,10 @@ exports.Lexer = class Lexer
|
||||
@tokens.push token
|
||||
else
|
||||
@error "Unexpected #{tag}"
|
||||
@token ')', ')', offsetInChunk + lexedLength, 0 if interpolated
|
||||
if interpolated
|
||||
rparen = @makeToken ')', ')', offsetInChunk + lexedLength, 0
|
||||
rparen.stringEnd = true
|
||||
@tokens.push rparen
|
||||
tokens
|
||||
|
||||
# Pairs up a closing token, ensuring that all listed pairs of tokens are
|
||||
@@ -635,7 +630,7 @@ exports.Lexer = class Lexer
|
||||
column = @chunkColumn
|
||||
if lineCount > 0
|
||||
lines = string.split '\n'
|
||||
column = (last lines).length
|
||||
column = last(lines).length
|
||||
else
|
||||
column += string.length
|
||||
|
||||
@@ -652,7 +647,7 @@ exports.Lexer = class Lexer
|
||||
# so if last_column == first_column, then we're looking at a character of length 1.
|
||||
lastCharacter = Math.max 0, length - 1
|
||||
[locationData.last_line, locationData.last_column] =
|
||||
@getLineAndColumnFromChunk offsetInChunk + (length - 1)
|
||||
@getLineAndColumnFromChunk offsetInChunk + lastCharacter
|
||||
|
||||
token = [tag, value, locationData]
|
||||
|
||||
@@ -695,11 +690,11 @@ exports.Lexer = class Lexer
|
||||
body = body.replace /// #{quote} ///g, '\\$&'
|
||||
quote + @escapeLines(body, heredoc) + quote
|
||||
|
||||
# Throws a syntax error on the current `@line`.
|
||||
# Throws a compiler error on the current position.
|
||||
error: (message) ->
|
||||
# TODO: Are there some cases we could improve the error line number by
|
||||
# passing the offset in the chunk where the error happened?
|
||||
throw SyntaxError "#{message} on line #{ @chunkLine + 1 }"
|
||||
throwSyntaxError message, first_line: @chunkLine, first_column: @chunkColumn
|
||||
|
||||
# Constants
|
||||
# ---------
|
||||
@@ -781,8 +776,6 @@ WHITESPACE = /^[^\n\S]+/
|
||||
|
||||
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)$)|^(?:\s*#(?!##[^#]).*)+/
|
||||
|
||||
LITERATE = /^([ ]{4}|\t)/
|
||||
|
||||
CODE = /^[-=]>/
|
||||
|
||||
MULTI_DENT = /^(?:\n[^\n\S]*)+/
|
||||
@@ -853,11 +846,11 @@ BOOL = ['TRUE', 'FALSE']
|
||||
# See: http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions
|
||||
#
|
||||
# Our list is shorter, due to sans-parentheses method calls.
|
||||
NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', 'NULL', 'UNDEFINED', '++', '--', ']']
|
||||
NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', 'NULL', 'UNDEFINED', '++', '--']
|
||||
|
||||
# If the previous token is not spaced, there are more preceding tokens that
|
||||
# force a division parse:
|
||||
NOT_SPACED_REGEX = NOT_REGEX.concat ')', '}', 'THIS', 'IDENTIFIER', 'STRING'
|
||||
NOT_SPACED_REGEX = NOT_REGEX.concat ')', '}', 'THIS', 'IDENTIFIER', 'STRING', ']'
|
||||
|
||||
# Tokens which could legitimately be invoked or indexed. An opening
|
||||
# parentheses or bracket following these tokens will be recorded as the start
|
||||
|
||||
270
src/nodes.coffee
270
src/nodes.coffee
@@ -9,7 +9,8 @@ Error.stackTraceLimit = Infinity
|
||||
{RESERVED, STRICT_PROSCRIBED} = require './lexer'
|
||||
|
||||
# Import the helpers we plan to use.
|
||||
{compact, flatten, extend, merge, del, starts, ends, last, some, addLocationDataFn, locationDataToString} = require './helpers'
|
||||
{compact, flatten, extend, merge, del, starts, ends, last, some,
|
||||
addLocationDataFn, locationDataToString, throwSyntaxError} = require './helpers'
|
||||
|
||||
# Functions required by parser
|
||||
exports.extend = extend
|
||||
@@ -33,8 +34,8 @@ exports.CodeFragment = class CodeFragment
|
||||
@locationData = parent?.locationData
|
||||
@type = parent?.constructor?.name or 'unknown'
|
||||
|
||||
toString: () ->
|
||||
"#{@code}#{[if @locationData then ": " + locationDataToString(@locationData)]}"
|
||||
toString: ->
|
||||
"#{@code}#{if @locationData then ": " + locationDataToString(@locationData) else ''}"
|
||||
|
||||
# Convert an array of CodeFragments into a string.
|
||||
fragmentsToText = (fragments) ->
|
||||
@@ -75,8 +76,8 @@ exports.Base = class Base
|
||||
# Statements converted into expressions via closure-wrapping share a scope
|
||||
# object with their parent closure, to preserve the expected lexical scope.
|
||||
compileClosure: (o) ->
|
||||
if @jumps()
|
||||
throw SyntaxError 'cannot use a pure statement in an expression.'
|
||||
if jumpNode = @jumps()
|
||||
jumpNode.error 'cannot use a pure statement in an expression'
|
||||
o.sharedScope = yes
|
||||
Closure.wrap(this).compileNode o
|
||||
|
||||
@@ -110,20 +111,16 @@ exports.Base = class Base
|
||||
new Return me
|
||||
|
||||
# Does this node, or any of its children, contain a node of a certain kind?
|
||||
# Recursively traverses down the *children* of the nodes, yielding to a block
|
||||
# and returning true when the block finds a match. `contains` does not cross
|
||||
# Recursively traverses down the *children* nodes and returns the first one
|
||||
# that verifies `pred`. Otherwise return undefined. `contains` does not cross
|
||||
# scope boundaries.
|
||||
contains: (pred) ->
|
||||
contains = no
|
||||
@traverseChildren no, (node) ->
|
||||
if pred node
|
||||
contains = yes
|
||||
node = undefined
|
||||
@traverseChildren no, (n) ->
|
||||
if pred n
|
||||
node = n
|
||||
return no
|
||||
contains
|
||||
|
||||
# Is this node of a certain type, or does it contain the type?
|
||||
containsType: (type) ->
|
||||
this instanceof type or @contains (node) -> node instanceof type
|
||||
node
|
||||
|
||||
# Pull out the last non-comment node of a node list.
|
||||
lastNonComment: (list) ->
|
||||
@@ -134,8 +131,7 @@ exports.Base = class Base
|
||||
# `toString` representation of the node, for inspecting the parse tree.
|
||||
# This is what `coffee --nodes` prints out.
|
||||
toString: (idt = '', name = @constructor.name) ->
|
||||
location = if @locationData then locationDataToString @locationData else "??"
|
||||
tree = '\n' + idt + location + ": " + name
|
||||
tree = '\n' + idt + name
|
||||
tree += '?' if @soak
|
||||
@eachChild (node) -> tree += node.toString idt + TAB
|
||||
tree
|
||||
@@ -150,8 +146,8 @@ exports.Base = class Base
|
||||
|
||||
traverseChildren: (crossScope, func) ->
|
||||
@eachChild (child) ->
|
||||
return false if func(child) is false
|
||||
child.traverseChildren crossScope, func
|
||||
recur = func(child)
|
||||
child.traverseChildren(crossScope, func) unless recur is no
|
||||
|
||||
invert: ->
|
||||
new Op '!', this
|
||||
@@ -177,16 +173,18 @@ exports.Base = class Base
|
||||
# Is this node used to assign a certain variable?
|
||||
assigns: NO
|
||||
|
||||
# For this node and all descendents, set the location data to `locationData` if the location
|
||||
# data is not already set.
|
||||
# For this node and all descendents, set the location data to `locationData`
|
||||
# if the location data is not already set.
|
||||
updateLocationDataIfMissing: (locationData) ->
|
||||
if not @locationData
|
||||
@locationData = {}
|
||||
extend @locationData, locationData
|
||||
@locationData or= locationData
|
||||
|
||||
@eachChild (child) ->
|
||||
child.updateLocationDataIfMissing locationData
|
||||
|
||||
# Throw a SyntaxError associated with this node's location.
|
||||
error: (message) ->
|
||||
throwSyntaxError message, @locationData
|
||||
|
||||
makeCode: (code) ->
|
||||
new CodeFragment this, code
|
||||
|
||||
@@ -290,7 +288,7 @@ exports.Block = class Block extends Base
|
||||
compiledNodes.push node.compileToFragments o, LEVEL_LIST
|
||||
if top
|
||||
if @spaced
|
||||
return [].concat @makeCode("\n"), @joinFragmentArrays(compiledNodes, '\n\n'), @makeCode("\n")
|
||||
return [].concat @joinFragmentArrays(compiledNodes, '\n\n'), @makeCode("\n")
|
||||
else
|
||||
return @joinFragmentArrays(compiledNodes, '\n')
|
||||
if compiledNodes.length
|
||||
@@ -305,9 +303,12 @@ exports.Block = class Block extends Base
|
||||
# clean up obvious double-parentheses.
|
||||
compileRoot: (o) ->
|
||||
o.indent = if o.bare then '' else TAB
|
||||
o.scope = new Scope null, this, null
|
||||
o.level = LEVEL_TOP
|
||||
@spaced = yes
|
||||
o.scope = new Scope null, this, null
|
||||
# Mark given local variables in the root scope as parameters so they don't
|
||||
# end up being declared on this block.
|
||||
o.scope.parameter name for name in o.locals or []
|
||||
prelude = []
|
||||
unless o.bare
|
||||
preludeExps = for exp, i in @expressions
|
||||
@@ -335,7 +336,7 @@ exports.Block = class Block extends Base
|
||||
if i
|
||||
rest = @expressions.splice i, 9e9
|
||||
[spaced, @spaced] = [@spaced, no]
|
||||
[fragments, @spaced] = [(@compileNode o), spaced]
|
||||
[fragments, @spaced] = [@compileNode(o), spaced]
|
||||
@expressions = rest
|
||||
post = @compileNode o
|
||||
{scope} = o
|
||||
@@ -346,11 +347,13 @@ exports.Block = class Block extends Base
|
||||
fragments.push @makeCode '\n' if i
|
||||
fragments.push @makeCode "#{@tab}var "
|
||||
if declars
|
||||
fragments.push @makeCode(scope.declaredVariables().join ', ')
|
||||
fragments.push @makeCode scope.declaredVariables().join(', ')
|
||||
if assigns
|
||||
fragments.push @makeCode ",\n#{@tab + TAB}" if declars
|
||||
fragments.push @makeCode (scope.assignedVariables().join ",\n#{@tab + TAB}")
|
||||
fragments.push @makeCode ';\n'
|
||||
fragments.push @makeCode scope.assignedVariables().join(",\n#{@tab + TAB}")
|
||||
fragments.push @makeCode ";\n#{if @spaced then '\n' else ''}"
|
||||
else if fragments.length and post.length
|
||||
fragments.push @makeCode "\n"
|
||||
fragments.concat post
|
||||
|
||||
# Wrap up the given nodes as a **Block**, unless it already happens
|
||||
@@ -436,9 +439,9 @@ exports.Return = class Return extends Base
|
||||
compileNode: (o) ->
|
||||
answer = []
|
||||
# TODO: If we call expression.compile() here twice, we'll sometimes get back different results!
|
||||
answer.push @makeCode(@tab + "return#{[" " if @expression]}")
|
||||
answer.push @makeCode @tab + "return#{if @expression then " " else ""}"
|
||||
if @expression
|
||||
answer = answer.concat @expression.compileToFragments(o, LEVEL_PAREN)
|
||||
answer = answer.concat @expression.compileToFragments o, LEVEL_PAREN
|
||||
answer.push @makeCode ";"
|
||||
return answer
|
||||
|
||||
@@ -552,7 +555,7 @@ exports.Comment = class Comment extends Base
|
||||
makeReturn: THIS
|
||||
|
||||
compileNode: (o, level) ->
|
||||
code = '/*' + multident(@comment, @tab) + "\n#{@tab}*/\n"
|
||||
code = "/*#{multident @comment, @tab}#{if '\n' in @comment then "\n#{@tab}" else ''}*/\n"
|
||||
code = o.indent + code if (level or o.level) is LEVEL_TOP
|
||||
[@makeCode code]
|
||||
|
||||
@@ -589,7 +592,7 @@ exports.Call = class Call extends Base
|
||||
else if method?.ctor
|
||||
"#{method.name}.__super__.constructor"
|
||||
else
|
||||
throw SyntaxError 'cannot call super outside of an instance method.'
|
||||
@error 'cannot call super outside of an instance method.'
|
||||
|
||||
# The appropriate `this` value for a `super` call.
|
||||
superThis : (o) ->
|
||||
@@ -646,7 +649,7 @@ exports.Call = class Call extends Base
|
||||
fragments.push @makeCode preface
|
||||
else
|
||||
if @isNew then fragments.push @makeCode 'new '
|
||||
fragments.push (@variable.compileToFragments(o, LEVEL_ACCESS))...
|
||||
fragments.push @variable.compileToFragments(o, LEVEL_ACCESS)...
|
||||
fragments.push @makeCode "("
|
||||
fragments.push compiledArgs...
|
||||
fragments.push @makeCode ")"
|
||||
@@ -738,7 +741,7 @@ exports.Index = class Index extends Base
|
||||
children: ['index']
|
||||
|
||||
compileToFragments: (o) ->
|
||||
[].concat @makeCode("["), (@index.compileToFragments o, LEVEL_PAREN), @makeCode("]")
|
||||
[].concat @makeCode("["), @index.compileToFragments(o, LEVEL_PAREN), @makeCode("]")
|
||||
|
||||
isComplex: ->
|
||||
@index.isComplex()
|
||||
@@ -883,7 +886,7 @@ exports.Obj = class Obj extends Base
|
||||
return [@makeCode(if @front then '({})' else '{}')] unless props.length
|
||||
if @generated
|
||||
for node in props when node instanceof Value
|
||||
throw new Error 'cannot have an implicit value in an implicit object'
|
||||
node.error 'cannot have an implicit value in an implicit object'
|
||||
idt = o.indent += TAB
|
||||
lastNoncom = @lastNonComment @properties
|
||||
answer = []
|
||||
@@ -895,6 +898,8 @@ exports.Obj = class Obj extends Base
|
||||
else
|
||||
',\n'
|
||||
indent = if prop instanceof Comment then '' else idt
|
||||
if prop instanceof Assign and prop.variable instanceof Value and prop.variable.hasProperties()
|
||||
prop.variable.error 'Invalid object key'
|
||||
if prop instanceof Value and prop.this
|
||||
prop = new Assign prop.properties[0].name, prop, 'object'
|
||||
if prop not instanceof Comment
|
||||
@@ -933,7 +938,7 @@ exports.Arr = class Arr extends Base
|
||||
if index
|
||||
answer.push @makeCode ", "
|
||||
answer.push fragments...
|
||||
if (fragmentsToText answer).indexOf('\n') >= 0
|
||||
if fragmentsToText(answer).indexOf('\n') >= 0
|
||||
answer.unshift @makeCode "[\n#{o.indent}"
|
||||
answer.push @makeCode "\n#{@tab}]"
|
||||
else
|
||||
@@ -965,7 +970,7 @@ exports.Class = class Class extends Base
|
||||
else
|
||||
@variable.base.value
|
||||
if decl in STRICT_PROSCRIBED
|
||||
throw SyntaxError "variable name may not be #{decl}"
|
||||
@variable.error "class variable name may not be #{decl}"
|
||||
decl and= IDENTIFIER.test(decl) and decl
|
||||
|
||||
# For all `this`-references and bound functions in the class definition,
|
||||
@@ -982,14 +987,9 @@ exports.Class = class Class extends Base
|
||||
# Ensure that all functions bound to the instance are proxied in the
|
||||
# constructor.
|
||||
addBoundFunctions: (o) ->
|
||||
if @boundFuncs.length
|
||||
o.scope.assign '_this', 'this'
|
||||
for [name, func] in @boundFuncs
|
||||
lhs = new Value (new Literal "this"), [new Access name]
|
||||
body = new Block [new Return new Literal "#{@ctor.name}.prototype.#{name.value}.apply(_this, arguments)"]
|
||||
rhs = new Code func.params, body, 'boundfunc'
|
||||
bound = new Assign lhs, rhs
|
||||
@ctor.body.unshift bound
|
||||
for bvar in @boundFuncs
|
||||
lhs = (new Value (new Literal "this"), [new Access bvar]).compile o
|
||||
@ctor.body.unshift new Literal "#{lhs} = #{utility 'bind'}(#{lhs}, this)"
|
||||
return
|
||||
|
||||
# Merge the properties from a top-level object as prototypal properties
|
||||
@@ -1003,9 +1003,9 @@ exports.Class = class Class extends Base
|
||||
func = assign.value
|
||||
if base.value is 'constructor'
|
||||
if @ctor
|
||||
throw new Error 'cannot define more than one constructor in a class'
|
||||
assign.error 'cannot define more than one constructor in a class'
|
||||
if func.bound
|
||||
throw new Error 'cannot define a constructor as a bound function'
|
||||
assign.error 'cannot define a constructor as a bound function'
|
||||
if func instanceof Code
|
||||
assign = @ctor = func
|
||||
else
|
||||
@@ -1017,9 +1017,9 @@ exports.Class = class Class extends Base
|
||||
if func.bound
|
||||
func.context = name
|
||||
else
|
||||
assign.variable = new Value(new Literal(name), [(new Access new Literal 'prototype'), new Access base ])
|
||||
assign.variable = new Value(new Literal(name), [(new Access new Literal 'prototype'), new Access base])
|
||||
if func instanceof Code and func.bound
|
||||
@boundFuncs.push [base, func]
|
||||
@boundFuncs.push base
|
||||
func.bound = no
|
||||
assign
|
||||
compact exprs
|
||||
@@ -1049,16 +1049,26 @@ exports.Class = class Class extends Base
|
||||
|
||||
# Make sure that a constructor is defined for the class, and properly
|
||||
# configured.
|
||||
ensureConstructor: (name) ->
|
||||
if not @ctor
|
||||
@ctor = new Code
|
||||
@ctor.body.push new Literal "#{name}.__super__.constructor.apply(this, arguments)" if @parent
|
||||
@ctor.body.push new Literal "#{@externalCtor}.apply(this, arguments)" if @externalCtor
|
||||
@ctor.body.makeReturn()
|
||||
@body.expressions.unshift @ctor
|
||||
@ctor.ctor = @ctor.name = name
|
||||
@ctor.klass = null
|
||||
ensureConstructor: (name, o) ->
|
||||
missing = not @ctor
|
||||
@ctor or= new Code
|
||||
@ctor.ctor = @ctor.name = name
|
||||
@ctor.klass = null
|
||||
@ctor.noReturn = yes
|
||||
if missing
|
||||
superCall = new Literal "#{name}.__super__.constructor.apply(this, arguments)" if @parent
|
||||
superCall = new Literal "#{@externalCtor}.apply(this, arguments)" if @externalCtor
|
||||
if superCall
|
||||
ref = new Literal o.scope.freeVariable 'ref'
|
||||
@ctor.body.unshift new Assign ref, superCall
|
||||
@addBoundFunctions o
|
||||
if superCall
|
||||
@ctor.body.push ref
|
||||
@ctor.body.makeReturn()
|
||||
@body.expressions.unshift @ctor
|
||||
else
|
||||
@addBoundFunctions o
|
||||
|
||||
|
||||
# Instead of generating the JavaScript string directly, we build up the
|
||||
# equivalent syntax tree and compile that, in pieces. You can see the
|
||||
@@ -1072,12 +1082,11 @@ exports.Class = class Class extends Base
|
||||
@hoistDirectivePrologue()
|
||||
@setContext name
|
||||
@walkBody name, o
|
||||
@ensureConstructor name
|
||||
@ensureConstructor name, o
|
||||
@body.spaced = yes
|
||||
@body.expressions.unshift @ctor unless @ctor instanceof Code
|
||||
@body.expressions.push lname
|
||||
@body.expressions.unshift @directives...
|
||||
@addBoundFunctions o
|
||||
|
||||
call = Closure.wrap @body
|
||||
|
||||
@@ -1102,7 +1111,7 @@ exports.Assign = class Assign extends Base
|
||||
@subpattern = options and options.subpattern
|
||||
forbidden = (name = @variable.unwrapAll().value) in STRICT_PROSCRIBED
|
||||
if forbidden and @context isnt 'object'
|
||||
throw SyntaxError "variable name may not be \"#{name}\""
|
||||
@variable.error "variable name may not be \"#{name}\""
|
||||
|
||||
children: ['variable', 'value']
|
||||
|
||||
@@ -1127,8 +1136,9 @@ exports.Assign = class Assign extends Base
|
||||
compiledName = @variable.compileToFragments o, LEVEL_LIST
|
||||
name = fragmentsToText compiledName
|
||||
unless @context
|
||||
unless (varBase = @variable.unwrapAll()).isAssignable()
|
||||
throw SyntaxError "\"#{ @variable.compile o }\" cannot be assigned."
|
||||
varBase = @variable.unwrapAll()
|
||||
unless varBase.isAssignable()
|
||||
@variable.error "\"#{@variable.compile o}\" cannot be assigned"
|
||||
unless varBase.hasProperties?()
|
||||
if @param
|
||||
o.scope.add name, 'var'
|
||||
@@ -1167,7 +1177,7 @@ exports.Assign = class Assign extends Base
|
||||
value = new Value value
|
||||
value.properties.push new (if acc then Access else Index) idx
|
||||
if obj.unwrap().value in RESERVED
|
||||
throw new SyntaxError "assignment to a reserved word: #{obj.compile o} = #{value.compile o}"
|
||||
obj.error "assignment to a reserved word: #{obj.compile o}"
|
||||
return new Assign(obj, value, null, param: @param).compileToFragments o, LEVEL_TOP
|
||||
vvar = value.compileToFragments o, LEVEL_LIST
|
||||
vvarText = fragmentsToText vvar
|
||||
@@ -1205,9 +1215,7 @@ exports.Assign = class Assign extends Base
|
||||
else
|
||||
name = obj.unwrap().value
|
||||
if obj instanceof Splat
|
||||
obj = obj.name.compileToFragments o
|
||||
throw new SyntaxError \
|
||||
"multiple splats are disallowed in an assignment: #{obj}..."
|
||||
obj.error "multiple splats are disallowed in an assignment"
|
||||
if typeof idx is 'number'
|
||||
idx = new Literal splat or idx
|
||||
acc = no
|
||||
@@ -1215,7 +1223,7 @@ exports.Assign = class Assign extends Base
|
||||
acc = isObject and IDENTIFIER.test idx.unwrap().value or 0
|
||||
val = new Value new Literal(vvarText), [new (if acc then Access else Index) idx]
|
||||
if name? and name in RESERVED
|
||||
throw new SyntaxError "assignment to a reserved word: #{obj.compile o} = #{val.compile o}"
|
||||
obj.error "assignment to a reserved word: #{obj.compile o}"
|
||||
assigns.push new Assign(obj, val, null, param: @param, subpattern: yes).compileToFragments o, LEVEL_LIST
|
||||
assigns.push vvar unless top or @subpattern
|
||||
fragments = @joinFragmentArrays assigns, ', '
|
||||
@@ -1229,9 +1237,9 @@ exports.Assign = class Assign extends Base
|
||||
# Disallow conditional assignment of undefined variables.
|
||||
if not left.properties.length and left.base instanceof Literal and
|
||||
left.base.value != "this" and not o.scope.check left.base.value
|
||||
throw new Error "the variable \"#{left.base.value}\" can't be assigned with #{@context} because it has not been defined."
|
||||
@variable.error "the variable \"#{left.base.value}\" can't be assigned with #{@context} because it has not been declared before"
|
||||
if "?" in @context then o.isExistentialEquals = true
|
||||
new Op(@context[...-1], left, new Assign(right, @value, '=') ).compileToFragments o
|
||||
new Op(@context[...-1], left, new Assign(right, @value, '=')).compileToFragments o
|
||||
|
||||
# Compile the assignment from an array splice literal, using JavaScript's
|
||||
# `Array#splice` method.
|
||||
@@ -1286,7 +1294,7 @@ exports.Code = class Code extends Base
|
||||
delete o.isExistentialEquals
|
||||
params = []
|
||||
exprs = []
|
||||
for name in @paramNames() # this step must be performed before the others
|
||||
@eachParamName (name) -> # this step must be performed before the others
|
||||
unless o.scope.check name then o.scope.parameter name
|
||||
for param in @params when param.splat
|
||||
for {name: p} in @params
|
||||
@@ -1314,8 +1322,8 @@ exports.Code = class Code extends Base
|
||||
params[i] = p.compileToFragments o
|
||||
o.scope.parameter fragmentsToText params[i]
|
||||
uniqs = []
|
||||
for name in @paramNames()
|
||||
throw SyntaxError "multiple parameters named '#{name}'" if name in uniqs
|
||||
@eachParamName (name, node) ->
|
||||
node.error "multiple parameters named '#{name}'" if name in uniqs
|
||||
uniqs.push name
|
||||
@body.makeReturn() unless wasEmpty or @noReturn
|
||||
if @bound
|
||||
@@ -1338,11 +1346,8 @@ exports.Code = class Code extends Base
|
||||
return [@makeCode(@tab), answer...] if @ctor
|
||||
if @front or (o.level >= LEVEL_ACCESS) then @wrapInBraces answer else answer
|
||||
|
||||
# A list of parameter names, excluding those generated by the compiler.
|
||||
paramNames: ->
|
||||
names = []
|
||||
names.push param.names()... for param in @params
|
||||
names
|
||||
eachParamName: (iterator) ->
|
||||
param.eachName iterator for param in @params
|
||||
|
||||
# Short-circuit `traverseChildren` method to prevent it from crossing scope boundaries
|
||||
# unless `crossScope` is `true`.
|
||||
@@ -1357,7 +1362,7 @@ exports.Code = class Code extends Base
|
||||
exports.Param = class Param extends Base
|
||||
constructor: (@name, @value, @splat) ->
|
||||
if (name = @name.unwrapAll().value) in STRICT_PROSCRIBED
|
||||
throw SyntaxError "parameter name \"#{name}\" is not allowed"
|
||||
@name.error "parameter name \"#{name}\" is not allowed"
|
||||
|
||||
children: ['name', 'value']
|
||||
|
||||
@@ -1380,41 +1385,40 @@ exports.Param = class Param extends Base
|
||||
isComplex: ->
|
||||
@name.isComplex()
|
||||
|
||||
# Finds the name or names of a `Param`; useful for detecting duplicates.
|
||||
# In a sense, a destructured parameter represents multiple JS parameters,
|
||||
# thus this method returns an `Array` of names.
|
||||
# Reserved words used as param names, as well as the Object and Array
|
||||
# literals used for destructured params, get a compiler generated name
|
||||
# during the `Code` compilation step, so this is necessarily an incomplete
|
||||
# list of a parameter's names.
|
||||
names: (name = @name)->
|
||||
# Iterates the name or names of a `Param`.
|
||||
# In a sense, a destructured parameter represents multiple JS parameters. This
|
||||
# method allows to iterate them all.
|
||||
# The `iterator` function will be called as `iterator(name, node)` where
|
||||
# `name` is the name of the parameter and `node` is the AST node corresponding
|
||||
# to that name.
|
||||
eachName: (iterator, name = @name)->
|
||||
atParam = (obj) ->
|
||||
{value} = obj.properties[0].name
|
||||
return if value.reserved then [] else [value]
|
||||
node = obj.properties[0].name
|
||||
iterator node.value, node unless node.value.reserved
|
||||
# * simple literals `foo`
|
||||
return [name.value] if name instanceof Literal
|
||||
return iterator name.value, name if name instanceof Literal
|
||||
# * at-params `@foo`
|
||||
return atParam(name) if name instanceof Value
|
||||
names = []
|
||||
return atParam name if name instanceof Value
|
||||
for obj in name.objects
|
||||
# * assignments within destructured parameters `{foo:bar}`
|
||||
if obj instanceof Assign
|
||||
names.push @names(obj.value.unwrap())...
|
||||
@eachName iterator, obj.value.unwrap()
|
||||
# * splats within destructured parameters `[xs...]`
|
||||
else if obj instanceof Splat
|
||||
names.push obj.name.unwrap().value
|
||||
node = obj.name.unwrap()
|
||||
iterator node.value, node
|
||||
else if obj instanceof Value
|
||||
# * destructured parameters within destructured parameters `[{a}]`
|
||||
if obj.isArray() or obj.isObject()
|
||||
names.push @names(obj.base)...
|
||||
@eachName iterator, obj.base
|
||||
# * at-params within destructured parameters `{@foo}`
|
||||
else if obj.this
|
||||
names.push atParam(obj)...
|
||||
atParam obj
|
||||
# * simple destructured parameters {foo}
|
||||
else names.push obj.base.value
|
||||
else iterator obj.base.value, obj.base
|
||||
else
|
||||
throw SyntaxError "illegal parameter #{obj.compile()}"
|
||||
names
|
||||
obj.error "illegal parameter #{obj.compile()}"
|
||||
return
|
||||
|
||||
#### Splat
|
||||
|
||||
@@ -1502,7 +1506,7 @@ exports.While = class While extends Base
|
||||
set = ''
|
||||
{body} = this
|
||||
if body.isEmpty()
|
||||
body = ''
|
||||
body = @makeCode ''
|
||||
else
|
||||
if @returns
|
||||
body.makeReturn rvar = o.scope.freeVariable 'results'
|
||||
@@ -1556,7 +1560,7 @@ exports.Op = class Op extends Base
|
||||
not @second
|
||||
|
||||
isComplex: ->
|
||||
not (@isUnary() and (@operator in ['+', '-'])) or @first.isComplex()
|
||||
not (@isUnary() and @operator in ['+', '-']) or @first.isComplex()
|
||||
|
||||
# Am I capable of
|
||||
# [Python-style comparison chaining](http://docs.python.org/reference/expressions.html#notin)?
|
||||
@@ -1615,9 +1619,9 @@ exports.Op = class Op extends Base
|
||||
# as the chained expression is wrapped.
|
||||
@first.front = @front unless isChain
|
||||
if @operator is 'delete' and o.scope.check(@first.unwrapAll().value)
|
||||
throw SyntaxError 'delete operand may not be argument or var'
|
||||
@error 'delete operand may not be argument or var'
|
||||
if @operator in ['--', '++'] and @first.unwrapAll().value in STRICT_PROSCRIBED
|
||||
throw SyntaxError 'prefix increment/decrement may not have eval or arguments operand'
|
||||
@error "cannot increment/decrement \"#{@first.unwrapAll().value}\""
|
||||
return @compileUnary o if @isUnary()
|
||||
return @compileChain o if isChain
|
||||
return @compileExistence o if @operator is '?'
|
||||
@@ -1637,8 +1641,9 @@ exports.Op = class Op extends Base
|
||||
(shared.compileToFragments o), @makeCode(" #{@operator} "), (@second.compileToFragments o, LEVEL_OP)
|
||||
@wrapInBraces fragments
|
||||
|
||||
# Keep reference to the left expression, unless this an existential assignment
|
||||
compileExistence: (o) ->
|
||||
if @first.isComplex()
|
||||
if !o.isExistentialEquals and @first.isComplex()
|
||||
ref = new Literal o.scope.freeVariable 'ref'
|
||||
fst = new Parens new Assign ref, @first
|
||||
else
|
||||
@@ -1659,7 +1664,7 @@ exports.Op = class Op extends Base
|
||||
plusMinus = op in ['+', '-']
|
||||
parts.push [@makeCode(' ')] if op in ['new', 'typeof', 'delete'] or
|
||||
plusMinus and @first instanceof Op and @first.operator is op
|
||||
if (plusMinus && @first instanceof Op) or (op is 'new' and @first.isStatement o)
|
||||
if (plusMinus and @first instanceof Op) or (op is 'new' and @first.isStatement o)
|
||||
@first = new Parens @first
|
||||
parts.push @first.compileToFragments o, LEVEL_OP
|
||||
parts.reverse() if @flip
|
||||
@@ -1699,7 +1704,7 @@ exports.In = class In extends Base
|
||||
[sub, ref] = @object.cache o, LEVEL_LIST
|
||||
fragments = [].concat @makeCode(utility('indexOf') + ".call("), @array.compileToFragments(o, LEVEL_LIST),
|
||||
@makeCode(", "), ref, @makeCode(") " + if @negated then '< 0' else '>= 0')
|
||||
return fragments if (fragmentsToText sub) is (fragmentsToText ref)
|
||||
return fragments if fragmentsToText(sub) is fragmentsToText(ref)
|
||||
fragments = sub.concat @makeCode(', '), fragments
|
||||
if o.level < LEVEL_LIST then fragments else @wrapInBraces fragments
|
||||
|
||||
@@ -1710,7 +1715,7 @@ exports.In = class In extends Base
|
||||
|
||||
# A classic *try/catch/finally* block.
|
||||
exports.Try = class Try extends Base
|
||||
constructor: (@attempt, @error, @recovery, @ensure) ->
|
||||
constructor: (@attempt, @errorVariable, @recovery, @ensure) ->
|
||||
|
||||
children: ['attempt', 'recovery', 'ensure']
|
||||
|
||||
@@ -1730,21 +1735,17 @@ exports.Try = class Try extends Base
|
||||
tryPart = @attempt.compileToFragments o, LEVEL_TOP
|
||||
|
||||
catchPart = if @recovery
|
||||
if @error.isObject?()
|
||||
placeholder = new Literal '_error'
|
||||
@recovery.unshift new Assign @error, placeholder
|
||||
@error = placeholder
|
||||
if @error.value in STRICT_PROSCRIBED
|
||||
throw SyntaxError "catch variable may not be \"#{@error.value}\""
|
||||
o.scope.add @error.value, 'param' unless o.scope.check @error.value
|
||||
[].concat @makeCode(" catch ("), @error.compileToFragments(o), @makeCode(") {\n"),
|
||||
placeholder = new Literal '_error'
|
||||
@recovery.unshift new Assign @errorVariable, placeholder if @errorVariable
|
||||
[].concat @makeCode(" catch ("), placeholder.compileToFragments(o), @makeCode(") {\n"),
|
||||
@recovery.compileToFragments(o, LEVEL_TOP), @makeCode("\n#{@tab}}")
|
||||
else unless @ensure or @recovery
|
||||
[@makeCode(' catch (_error) {}')]
|
||||
else
|
||||
[]
|
||||
|
||||
ensurePart = if @ensure then ([].concat @makeCode(" finally {\n"), (@ensure.compileToFragments o, LEVEL_TOP), @makeCode("\n#{@tab}}")) else []
|
||||
ensurePart = if @ensure then ([].concat @makeCode(" finally {\n"), @ensure.compileToFragments(o, LEVEL_TOP),
|
||||
@makeCode("\n#{@tab}}")) else []
|
||||
|
||||
[].concat @makeCode("#{@tab}try {\n"),
|
||||
tryPart,
|
||||
@@ -1765,7 +1766,7 @@ exports.Throw = class Throw extends Base
|
||||
makeReturn: THIS
|
||||
|
||||
compileNode: (o) ->
|
||||
[].concat @makeCode(@tab + "throw "), (@expression.compileToFragments o), @makeCode(";")
|
||||
[].concat @makeCode(@tab + "throw "), @expression.compileToFragments(o), @makeCode(";")
|
||||
|
||||
#### Existence
|
||||
|
||||
@@ -1831,11 +1832,12 @@ exports.For = class For extends While
|
||||
@own = !!source.own
|
||||
@object = !!source.object
|
||||
[@name, @index] = [@index, @name] if @object
|
||||
throw SyntaxError 'index cannot be a pattern matching expression' if @index instanceof Value
|
||||
@index.error 'index cannot be a pattern matching expression' if @index instanceof Value
|
||||
@range = @source instanceof Value and @source.base instanceof Range and not @source.properties.length
|
||||
@pattern = @name instanceof Value
|
||||
throw SyntaxError 'indexes do not apply to range loops' if @range and @index
|
||||
throw SyntaxError 'cannot pattern match over range loops' if @range and @pattern
|
||||
@index.error 'indexes do not apply to range loops' if @range and @index
|
||||
@name.error 'cannot pattern match over range loops' if @range and @pattern
|
||||
@index.error 'cannot use own with for-in' if @own and not @object
|
||||
@returns = false
|
||||
|
||||
children: ['body', 'source', 'guard', 'step']
|
||||
@@ -1962,7 +1964,7 @@ exports.Switch = class Switch extends Base
|
||||
idt1 = o.indent + TAB
|
||||
idt2 = o.indent = idt1 + TAB
|
||||
fragments = [].concat @makeCode(@tab + "switch ("),
|
||||
(if @subject then @subject.compileToFragments(o, LEVEL_PAREN) else @makeCode("false")),
|
||||
(if @subject then @subject.compileToFragments(o, LEVEL_PAREN) else @makeCode "false"),
|
||||
@makeCode(") {\n")
|
||||
for [conditions, block], i in @cases
|
||||
for cond in flatten [conditions]
|
||||
@@ -2077,21 +2079,22 @@ Closure =
|
||||
return expressions if expressions.jumps()
|
||||
func = new Code [], Block.wrap [expressions]
|
||||
args = []
|
||||
if (mentionsArgs = expressions.contains @literalArgs) or expressions.contains @literalThis
|
||||
if mentionsArgs and expressions.classBody
|
||||
throw SyntaxError "Class bodies shouldn't reference arguments"
|
||||
meth = new Literal if mentionsArgs then 'apply' else 'call'
|
||||
argumentsNode = expressions.contains @isLiteralArguments
|
||||
if argumentsNode and expressions.classBody
|
||||
argumentsNode.error "Class bodies shouldn't reference arguments"
|
||||
if argumentsNode or expressions.contains @isLiteralThis
|
||||
meth = new Literal if argumentsNode then 'apply' else 'call'
|
||||
args = [new Literal 'this']
|
||||
args.push new Literal 'arguments' if mentionsArgs
|
||||
args.push new Literal 'arguments' if argumentsNode
|
||||
func = new Value func, [new Access meth]
|
||||
func.noReturn = noReturn
|
||||
call = new Call func, args
|
||||
if statement then Block.wrap [call] else call
|
||||
|
||||
literalArgs: (node) ->
|
||||
isLiteralArguments: (node) ->
|
||||
node instanceof Literal and node.value is 'arguments' and not node.asKey
|
||||
|
||||
literalThis: (node) ->
|
||||
isLiteralThis: (node) ->
|
||||
(node instanceof Literal and node.value is 'this' and not node.asKey) or
|
||||
(node instanceof Code and node.bound) or
|
||||
(node instanceof Call and node.isSuper)
|
||||
@@ -2114,6 +2117,11 @@ UTILITIES =
|
||||
function(child, parent) { for (var key in parent) { if (#{utility 'hasProp'}.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }
|
||||
"""
|
||||
|
||||
# Create a function bound to the current value of "this".
|
||||
bind: -> '''
|
||||
function(fn, me){ return function(){ return fn.apply(me, arguments); }; }
|
||||
'''
|
||||
|
||||
# Discover if an item is in an array.
|
||||
indexOf: -> """
|
||||
[].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
{repeat} = require './helpers'
|
||||
|
||||
# A simple **OptionParser** class to parse option flags from the command-line.
|
||||
# Use it like so:
|
||||
#
|
||||
@@ -62,7 +64,7 @@ exports.OptionParser = class OptionParser
|
||||
lines.unshift "#{@banner}\n" if @banner
|
||||
for rule in @rules
|
||||
spaces = 15 - rule.longFlag.length
|
||||
spaces = if spaces > 0 then Array(spaces + 1).join(' ') else ''
|
||||
spaces = if spaces > 0 then repeat ' ', spaces else ''
|
||||
letPart = if rule.shortFlag then rule.shortFlag + ', ' else ' '
|
||||
lines.push ' ' + letPart + rule.longFlag + spaces + rule.description
|
||||
"\n#{ lines.join('\n') }\n"
|
||||
|
||||
@@ -1,31 +1,43 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
vm = require 'vm'
|
||||
nodeREPL = require 'repl'
|
||||
CoffeeScript = require './coffee-script'
|
||||
{merge} = require './helpers'
|
||||
{merge, prettyErrorMessage} = require './helpers'
|
||||
|
||||
replDefaults =
|
||||
prompt: 'coffee> ',
|
||||
historyFile: path.join process.env.HOME, '.coffee_history' if process.env.HOME
|
||||
historyMaxInputSize: 10240
|
||||
eval: (input, context, filename, cb) ->
|
||||
# XXX: multiline hack
|
||||
# XXX: multiline hack.
|
||||
input = input.replace /\uFF00/g, '\n'
|
||||
# strip single-line comments
|
||||
input = input.replace /(^|[\r\n]+)(\s*)##?(?:[^#\r\n][^\r\n]*|)($|[\r\n])/, '$1$2$3'
|
||||
# empty command
|
||||
return cb null if /^(\s*|\(\s*\))$/.test input
|
||||
# TODO: fix #1829: pass in-scope vars and avoid accidentally shadowing them by omitting those declarations
|
||||
# Node's REPL sends the input ending with a newline and then wrapped in
|
||||
# parens. Unwrap all that.
|
||||
input = input.replace /^\(([\s\S]*)\n\)$/m, '$1'
|
||||
|
||||
# Require AST nodes to do some AST manipulation.
|
||||
{Block, Assign, Value, Literal} = require './nodes'
|
||||
|
||||
try
|
||||
js = CoffeeScript.compile "_=(#{input}\n)", {filename, bare: yes}
|
||||
# Generate the AST of the clean input.
|
||||
ast = CoffeeScript.nodes input
|
||||
# Add assignment to `_` variable to force the input to be an expression.
|
||||
ast = new Block [
|
||||
new Assign (new Value new Literal '_'), ast, '='
|
||||
]
|
||||
js = ast.compile bare: yes, locals: Object.keys(context)
|
||||
cb null, vm.runInContext(js, context, filename)
|
||||
catch err
|
||||
cb err
|
||||
cb prettyErrorMessage(err, filename, input, yes)
|
||||
|
||||
addMultilineHandler = (repl) ->
|
||||
{rli, inputStream, outputStream} = repl
|
||||
|
||||
multiline =
|
||||
enabled: off
|
||||
initialPrompt: repl.prompt.replace(/^[^> ]*/, (x) -> x.replace /./g, '-')
|
||||
prompt: repl.prompt.replace(/^[^> ]*>?/, (x) -> x.replace /./g, '.')
|
||||
initialPrompt: repl.prompt.replace /^[^> ]*/, (x) -> x.replace /./g, '-'
|
||||
prompt: repl.prompt.replace /^[^> ]*>?/, (x) -> x.replace /./g, '.'
|
||||
buffer: ''
|
||||
|
||||
# Proxy node's line listener
|
||||
@@ -68,10 +80,54 @@ addMultilineHandler = (repl) ->
|
||||
rli.prompt true
|
||||
return
|
||||
|
||||
# Store and load command history from a file
|
||||
addHistory = (repl, filename, maxSize) ->
|
||||
lastLine = null
|
||||
try
|
||||
# Get file info and at most maxSize of command history
|
||||
stat = fs.statSync filename
|
||||
size = Math.min maxSize, stat.size
|
||||
# Read last `size` bytes from the file
|
||||
readFd = fs.openSync filename, 'r'
|
||||
buffer = new Buffer(size)
|
||||
fs.readSync readFd, buffer, 0, size, stat.size - size
|
||||
# Set the history on the interpreter
|
||||
repl.rli.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
|
||||
# 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]
|
||||
|
||||
fd = fs.openSync filename, 'a'
|
||||
|
||||
repl.rli.addListener 'line', (code) ->
|
||||
if code and code.length and code isnt '.history' and lastLine isnt code
|
||||
# Save the latest command in the file
|
||||
fs.write fd, "#{code}\n"
|
||||
lastLine = code
|
||||
|
||||
repl.rli.on 'exit', -> fs.close fd
|
||||
|
||||
# Add a command to show the history stack
|
||||
repl.commands['.history'] =
|
||||
help: 'Show command history'
|
||||
action: ->
|
||||
repl.outputStream.write "#{repl.rli.history[..].reverse().join '\n'}\n"
|
||||
repl.displayPrompt()
|
||||
|
||||
module.exports =
|
||||
start: (opts = {}) ->
|
||||
[major, minor, build] = process.versions.node.split('.').map (n) -> parseInt(n)
|
||||
|
||||
if major is 0 and minor < 8
|
||||
console.warn "Node 0.8.0+ required for CoffeeScript REPL"
|
||||
process.exit 1
|
||||
|
||||
opts = merge replDefaults, opts
|
||||
repl = nodeREPL.start opts
|
||||
repl.on 'exit', -> repl.outputStream.write '\n'
|
||||
addMultilineHandler repl
|
||||
addHistory repl, opts.historyFile, opts.historyMaxInputSize if opts.historyFile
|
||||
repl
|
||||
|
||||
@@ -16,6 +16,7 @@ generate = (tag, value) ->
|
||||
class exports.Rewriter
|
||||
|
||||
# Helpful snippet for debugging:
|
||||
#
|
||||
# console.log (t[0] + '/' + t[1] for t in @tokens).join ' '
|
||||
|
||||
# Rewrite the token stream in multiple passes, one logical filter at
|
||||
@@ -186,9 +187,12 @@ class exports.Rewriter
|
||||
return forward(1)
|
||||
|
||||
if tag is 'INDENT' and inImplicit()
|
||||
# An INDENT closes an implicit call unless
|
||||
# 1. We have seen a CONTROL argument on the line.
|
||||
# 2. The last token before the indent is part of the list below
|
||||
|
||||
# An `INDENT` closes an implicit call unless
|
||||
#
|
||||
# 1. We have seen a `CONTROL` argument on the line.
|
||||
# 2. The last token before the indent is part of the list below
|
||||
#
|
||||
if prevTag not in ['=>', '->', '[', '(', ',', '{', 'TRY', 'ELSE', '=']
|
||||
endImplicitCall() while inImplicitCall()
|
||||
stack.pop() if inImplicitControl()
|
||||
@@ -213,7 +217,7 @@ class exports.Rewriter
|
||||
|
||||
# Recognize standard implicit calls like
|
||||
# f a, f() b, f? c, h[0] d etc.
|
||||
if (tag in IMPLICIT_FUNC and token.spaced or
|
||||
if (tag in IMPLICIT_FUNC and token.spaced and not token.stringEnd or
|
||||
tag is '?' and i > 0 and not tokens[i - 1].spaced) and
|
||||
(nextTag in IMPLICIT_CALL or
|
||||
nextTag in IMPLICIT_UNSPACED_CALL and
|
||||
@@ -223,24 +227,31 @@ class exports.Rewriter
|
||||
return forward(2)
|
||||
|
||||
# Implicit call taking an implicit indented object as first argument.
|
||||
# f
|
||||
# a: b
|
||||
# c: d
|
||||
#
|
||||
# f
|
||||
# a: b
|
||||
# c: d
|
||||
#
|
||||
# and
|
||||
# f
|
||||
# 1
|
||||
# a: b
|
||||
# b: c
|
||||
#
|
||||
# f
|
||||
# 1
|
||||
# a: b
|
||||
# b: c
|
||||
#
|
||||
# Don't accept implicit calls of this type, when on the same line
|
||||
# as the control strucutures below as that may misinterpret constructs like:
|
||||
# if f
|
||||
# a: 1
|
||||
#
|
||||
# if f
|
||||
# a: 1
|
||||
# as
|
||||
# if f(a: 1)
|
||||
#
|
||||
# if f(a: 1)
|
||||
#
|
||||
# which is probably always unintended.
|
||||
# Furthermore don't allow this in literal arrays, as
|
||||
# that creates grammatical ambiguities.
|
||||
if @matchTags(i, IMPLICIT_FUNC, 'INDENT', null, ':') and
|
||||
if tag in IMPLICIT_FUNC and @matchTags(i + 1, 'INDENT', null, ':') and
|
||||
not @findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH',
|
||||
'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])
|
||||
startImplicitCall i + 1
|
||||
@@ -266,11 +277,13 @@ class exports.Rewriter
|
||||
|
||||
# End implicit calls when chaining method calls
|
||||
# like e.g.:
|
||||
# f ->
|
||||
# a
|
||||
# .g b, ->
|
||||
# c
|
||||
# .h a
|
||||
#
|
||||
# f ->
|
||||
# a
|
||||
# .g b, ->
|
||||
# c
|
||||
# .h a
|
||||
#
|
||||
if prevTag is 'OUTDENT' and inImplicitCall() and tag in ['.', '?.', '::', '?::']
|
||||
endImplicitCall()
|
||||
return forward(1)
|
||||
@@ -299,14 +312,16 @@ class exports.Rewriter
|
||||
# Close implicit object if comma is the last character
|
||||
# and what comes after doesn't look like it belongs.
|
||||
# This is used for trailing commas and calls, like:
|
||||
# x =
|
||||
# a: b,
|
||||
# c: d,
|
||||
# e = 2
|
||||
#
|
||||
# x =
|
||||
# a: b,
|
||||
# c: d,
|
||||
# e = 2
|
||||
#
|
||||
# and
|
||||
#
|
||||
# f a, b: c, d: e, f, g: h: i, j
|
||||
# f a, b: c, d: e, f, g: h: i, j
|
||||
#
|
||||
if tag is ',' and not @looksObjectish(i + 1) and inImplicitObject() and
|
||||
(nextTag isnt 'TERMINATOR' or not @looksObjectish(i + 2))
|
||||
# When nextTag is OUTDENT the comma is insignificant and
|
||||
@@ -325,13 +340,18 @@ class exports.Rewriter
|
||||
@scanTokens (token, i, tokens) ->
|
||||
return 1 if token[2]
|
||||
return 1 unless token.generated or token.explicit
|
||||
{last_line, last_column} = tokens[i - 1]?[2] ? last_line: 0, last_column: 0
|
||||
if token[0] is '{' and nextLocation=tokens[i + 1]?[2]
|
||||
{first_line: line, first_column: column} = nextLocation
|
||||
else if prevLocation = tokens[i - 1]?[2]
|
||||
{last_line: line, last_column: column} = prevLocation
|
||||
else
|
||||
line = column = 0
|
||||
token[2] =
|
||||
first_line: last_line
|
||||
first_column: last_column
|
||||
last_line: last_line
|
||||
last_column: last_column
|
||||
1
|
||||
first_line: line
|
||||
first_column: column
|
||||
last_line: line
|
||||
last_column: column
|
||||
return 1
|
||||
|
||||
# Because our grammar is LALR(1), it can't handle some single-line
|
||||
# expressions that lack ending delimiters. The **Rewriter** adds the implicit
|
||||
@@ -342,7 +362,8 @@ class exports.Rewriter
|
||||
|
||||
condition = (token, i) ->
|
||||
token[1] isnt ';' and token[0] in SINGLE_CLOSERS and
|
||||
not (token[0] is 'ELSE' and starter not in ['IF', 'THEN'])
|
||||
not (token[0] is 'ELSE' and starter isnt 'THEN') and
|
||||
not (token[0] in ['CATCH', 'FINALLY'] and starter in ['->', '=>'])
|
||||
|
||||
action = (token, i) ->
|
||||
@tokens.splice (if @tag(i - 1) is ',' then i - 1 else i), 0, outdent
|
||||
@@ -353,15 +374,16 @@ class exports.Rewriter
|
||||
tokens.splice i, 1
|
||||
return 0
|
||||
if tag is 'ELSE' and @tag(i - 1) isnt 'OUTDENT'
|
||||
tokens.splice i, 0, @indentation(token)...
|
||||
tokens.splice i, 0, @indentation()...
|
||||
return 2
|
||||
if tag is 'CATCH' and @tag(i + 2) in ['OUTDENT', 'TERMINATOR', 'FINALLY']
|
||||
tokens.splice i + 2, 0, @indentation(token)...
|
||||
return 4
|
||||
if tag is 'CATCH'
|
||||
for j in [1..2] when @tag(i + j) in ['OUTDENT', 'TERMINATOR', 'FINALLY']
|
||||
tokens.splice i + j, 0, @indentation()...
|
||||
return 2 + j
|
||||
if tag in SINGLE_LINERS and @tag(i + 1) isnt 'INDENT' and
|
||||
not (tag is 'ELSE' and @tag(i + 1) is 'IF')
|
||||
starter = tag
|
||||
[indent, outdent] = @indentation token, yes
|
||||
[indent, outdent] = @indentation yes
|
||||
indent.fromThen = true if starter is 'THEN'
|
||||
tokens.splice i + 1, 0, indent
|
||||
@detectEnd i + 2, condition, action
|
||||
@@ -376,7 +398,9 @@ class exports.Rewriter
|
||||
original = null
|
||||
|
||||
condition = (token, i) ->
|
||||
token[0] in ['TERMINATOR', 'INDENT']
|
||||
[tag] = token
|
||||
[prevTag] = @tokens[i - 1]
|
||||
tag is 'TERMINATOR' or (tag is 'INDENT' and prevTag not in SINGLE_LINERS)
|
||||
|
||||
action = (token, i) ->
|
||||
if token[0] isnt 'INDENT' or (token.generated and not token.fromThen)
|
||||
@@ -386,10 +410,10 @@ class exports.Rewriter
|
||||
return 1 unless token[0] is 'IF'
|
||||
original = token
|
||||
@detectEnd i + 1, condition, action
|
||||
1
|
||||
return 1
|
||||
|
||||
# Generate the indentation tokens, based on another token on the same line.
|
||||
indentation: (token, implicit = no) ->
|
||||
indentation: (implicit = no) ->
|
||||
indent = ['INDENT', 2]
|
||||
outdent = ['OUTDENT', 2]
|
||||
indent.generated = outdent.generated = yes if implicit
|
||||
@@ -437,14 +461,11 @@ IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@
|
||||
IMPLICIT_CALL = [
|
||||
'IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS'
|
||||
'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'NULL', 'UNDEFINED', 'UNARY', 'SUPER'
|
||||
'@', '->', '=>', '[', '(', '{', '--', '++'
|
||||
'THROW', '@', '->', '=>', '[', '(', '{', '--', '++'
|
||||
]
|
||||
|
||||
IMPLICIT_UNSPACED_CALL = ['+', '-']
|
||||
|
||||
# Tokens indicating that the implicit call must enclose a block of expressions.
|
||||
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ',']
|
||||
|
||||
# Tokens that always mark the end of an implicit call for single-liners.
|
||||
IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY',
|
||||
'LOOP', 'TERMINATOR']
|
||||
|
||||
@@ -1,244 +0,0 @@
|
||||
# Hold data about mappings for one line of generated source code.
|
||||
|
||||
class LineMapping
|
||||
constructor: (@generatedLine) ->
|
||||
# columnMap keeps track of which columns we've already mapped.
|
||||
@columnMap = {}
|
||||
|
||||
# columnMappings is an array of all column mappings, sorted by generated-column.
|
||||
@columnMappings = []
|
||||
|
||||
addMapping: (generatedColumn, [sourceLine, sourceColumn], options={}) ->
|
||||
if @columnMap[generatedColumn] and options.noReplace
|
||||
# We already have a mapping for this column.
|
||||
return
|
||||
|
||||
@columnMap[generatedColumn] = {
|
||||
generatedLine: @generatedLine
|
||||
generatedColumn
|
||||
sourceLine
|
||||
sourceColumn
|
||||
}
|
||||
|
||||
@columnMappings.push @columnMap[generatedColumn]
|
||||
@columnMappings.sort (a,b) -> a.generatedColumn - b.generatedColumn
|
||||
|
||||
getSourcePosition: (generatedColumn) ->
|
||||
answer = null
|
||||
lastColumnMapping = null
|
||||
for columnMapping in @columnMappings
|
||||
if columnMapping.generatedColumn > generatedColumn
|
||||
break
|
||||
else
|
||||
lastColumnMapping = columnMapping
|
||||
if lastColumnMapping
|
||||
answer = [lastColumnMapping.sourceLine, lastColumnMapping.sourceColumn]
|
||||
|
||||
#### SourceMap
|
||||
|
||||
# Maps locations in a generated source file back to locations in the original source file.
|
||||
#
|
||||
# This is intentionally agnostic towards how a source map might be represented on disk. A
|
||||
# SourceMap can be converted to a "v3" style sourcemap with `#generateV3SourceMap()`, for example
|
||||
# but the SourceMap class itself knows nothing about v3 source maps.
|
||||
|
||||
class exports.SourceMap
|
||||
constructor: () ->
|
||||
# `generatedLines` is an array of LineMappings, one per generated line.
|
||||
@generatedLines = []
|
||||
|
||||
# Adds a mapping to this SourceMap.
|
||||
#
|
||||
# `sourceLocation` and `generatedLocation` are both [line, column] arrays.
|
||||
#
|
||||
# If `options.noReplace` is true, then if there is already a mapping for
|
||||
# the specified `generatedLine` and `generatedColumn`, this will have no effect.
|
||||
addMapping: (sourceLocation, generatedLocation, options={}) ->
|
||||
[generatedLine, generatedColumn] = generatedLocation
|
||||
|
||||
lineMapping = @generatedLines[generatedLine]
|
||||
if not lineMapping
|
||||
lineMapping = @generatedLines[generatedLine] = new LineMapping(generatedLine)
|
||||
|
||||
lineMapping.addMapping generatedColumn, sourceLocation, options
|
||||
|
||||
# Returns [sourceLine, sourceColumn], or null if no mapping could be found.
|
||||
getSourcePosition: ([generatedLine, generatedColumn]) ->
|
||||
answer = null
|
||||
lineMapping = @generatedLines[generatedLine]
|
||||
if not lineMapping
|
||||
# TODO: Search backwards for the line?
|
||||
else
|
||||
answer = lineMapping.getSourcePosition generatedColumn
|
||||
|
||||
answer
|
||||
|
||||
|
||||
# `fn` will be called once for every recorded mapping, in the order in
|
||||
# which they occur in the generated source. `fn` will be passed an object
|
||||
# with four properties: sourceLine, sourceColumn, generatedLine, and
|
||||
# generatedColumn.
|
||||
forEachMapping: (fn) ->
|
||||
for lineMapping, generatedLineNumber in @generatedLines
|
||||
if lineMapping
|
||||
for columnMapping in lineMapping.columnMappings
|
||||
fn(columnMapping)
|
||||
|
||||
|
||||
#### generateV3SourceMap
|
||||
|
||||
# Builds a V3 source map from a SourceMap object.
|
||||
# Returns the generated JSON as a string.
|
||||
|
||||
exports.generateV3SourceMap = (sourceMap, sourceFile=null, generatedFile=null) ->
|
||||
writingGeneratedLine = 0
|
||||
lastGeneratedColumnWritten = 0
|
||||
lastSourceLineWritten = 0
|
||||
lastSourceColumnWritten = 0
|
||||
needComma = no
|
||||
|
||||
mappings = ""
|
||||
|
||||
sourceMap.forEachMapping (mapping) ->
|
||||
while writingGeneratedLine < mapping.generatedLine
|
||||
lastGeneratedColumnWritten = 0
|
||||
needComma = no
|
||||
mappings += ";"
|
||||
writingGeneratedLine++
|
||||
|
||||
# Write a comma if we've already written a segment on this line.
|
||||
if needComma
|
||||
mappings += ","
|
||||
needComma = no
|
||||
|
||||
# Write the next segment.
|
||||
# Segments can be 1, 4, or 5 values. If just one, then it is a generated column which
|
||||
# doesn't match anything in the source code.
|
||||
#
|
||||
# Fields are all zero-based, and relative to the previous occurence unless otherwise noted:
|
||||
# * starting-column in generated source, relative to previous occurence for the current line.
|
||||
# * index into the "sources" list
|
||||
# * starting line in the original source
|
||||
# * starting column in the original source
|
||||
# * index into the "names" list associated with this segment.
|
||||
|
||||
# Add the generated start-column
|
||||
mappings += exports.vlqEncodeValue(mapping.generatedColumn - lastGeneratedColumnWritten)
|
||||
lastGeneratedColumnWritten = mapping.generatedColumn
|
||||
|
||||
# Add the index into the sources list
|
||||
mappings += exports.vlqEncodeValue(0)
|
||||
|
||||
# Add the source start-line
|
||||
mappings += exports.vlqEncodeValue(mapping.sourceLine - lastSourceLineWritten)
|
||||
lastSourceLineWritten = mapping.sourceLine
|
||||
|
||||
# Add the source start-column
|
||||
mappings += exports.vlqEncodeValue(mapping.sourceColumn - lastSourceColumnWritten)
|
||||
lastSourceColumnWritten = mapping.sourceColumn
|
||||
|
||||
# TODO: Do we care about symbol names for CoffeeScript? Probably not.
|
||||
|
||||
needComma = yes
|
||||
|
||||
answer = {
|
||||
version: 3
|
||||
file: generatedFile
|
||||
sourceRoot: ""
|
||||
sources: if sourceFile then [sourceFile] else []
|
||||
names: []
|
||||
mappings
|
||||
}
|
||||
|
||||
return JSON.stringify answer, null, 2
|
||||
|
||||
# Load a SourceMap from a JSON string. Returns the SourceMap object.
|
||||
exports.loadV3SourceMap = (sourceMap) ->
|
||||
todo()
|
||||
|
||||
#### Base64 encoding helpers
|
||||
|
||||
BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
MAX_BASE64_VALUE = BASE64_CHARS.length - 1
|
||||
|
||||
encodeBase64Char = (value) ->
|
||||
if value > MAX_BASE64_VALUE
|
||||
throw new Error "Cannot encode value #{value} > #{MAX_BASE64_VALUE}"
|
||||
else if value < 0
|
||||
throw new Error "Cannot encode value #{value} < 0"
|
||||
BASE64_CHARS[value]
|
||||
|
||||
decodeBase64Char = (char) ->
|
||||
value = BASE64_CHARS.indexOf char
|
||||
if value == -1
|
||||
throw new Error "Invalid Base 64 character: #{char}"
|
||||
value
|
||||
|
||||
#### Base 64 VLQ encoding/decoding helpers
|
||||
|
||||
# Note that SourceMap VLQ encoding is "backwards". MIDI style VLQ encoding puts the
|
||||
# most-significant-bit (MSB) from the original value into the MSB of the VLQ encoded value
|
||||
# (see http://en.wikipedia.org/wiki/File:Uintvar_coding.svg). SourceMap VLQ does things
|
||||
# the other way around, with the least significat four bits of the original value encoded
|
||||
# into the first byte of the VLQ encoded value.
|
||||
|
||||
VLQ_SHIFT = 5
|
||||
VLQ_CONTINUATION_BIT = 1 << VLQ_SHIFT # 0010 0000
|
||||
VLQ_VALUE_MASK = VLQ_CONTINUATION_BIT - 1 # 0001 1111
|
||||
|
||||
# Encode a value as Base 64 VLQ.
|
||||
exports.vlqEncodeValue = (value) ->
|
||||
# Least significant bit represents the sign.
|
||||
signBit = if value < 0 then 1 else 0
|
||||
|
||||
# Next bits are the actual value
|
||||
valueToEncode = (Math.abs(value) << 1) + signBit
|
||||
|
||||
answer = ""
|
||||
# Make sure we encode at least one character, even if valueToEncode is 0.
|
||||
while valueToEncode || !answer
|
||||
nextVlqChunk = valueToEncode & VLQ_VALUE_MASK
|
||||
valueToEncode = valueToEncode >> VLQ_SHIFT
|
||||
|
||||
if valueToEncode
|
||||
nextVlqChunk |= VLQ_CONTINUATION_BIT
|
||||
|
||||
answer += encodeBase64Char(nextVlqChunk)
|
||||
|
||||
return answer
|
||||
|
||||
# Decode a Base 64 VLQ value.
|
||||
#
|
||||
# Returns `[value, consumed]` where `value` is the decoded value, and `consumed` is the number
|
||||
# of characters consumed from `str`.
|
||||
exports.vlqDecodeValue = (str, offset=0) ->
|
||||
position = offset
|
||||
done = false
|
||||
|
||||
value = 0
|
||||
continuationShift = 0
|
||||
|
||||
while !done
|
||||
nextVlqChunk = decodeBase64Char(str[position])
|
||||
position += 1
|
||||
|
||||
nextChunkValue = nextVlqChunk & VLQ_VALUE_MASK
|
||||
value += (nextChunkValue << continuationShift)
|
||||
|
||||
if !(nextVlqChunk & VLQ_CONTINUATION_BIT)
|
||||
# We'll be done after this character.
|
||||
done = true
|
||||
|
||||
# Bits are encoded least-significant first (opposite of MIDI VLQ). Increase the
|
||||
# continuationShift, so the next byte will end up where it should in the value.
|
||||
continuationShift += VLQ_SHIFT
|
||||
|
||||
consumed = position - offset
|
||||
|
||||
# Least significant bit represents the sign.
|
||||
signBit = value & 1
|
||||
value = value >> 1
|
||||
|
||||
if signBit then value = -value
|
||||
|
||||
return [value, consumed]
|
||||
180
src/sourcemap.litcoffee
Normal file
180
src/sourcemap.litcoffee
Normal file
@@ -0,0 +1,180 @@
|
||||
Source maps allow JavaScript runtimes to match running JavaScript back to
|
||||
the original source code that corresponds to it. This can be minified
|
||||
JavaScript, but in our case, we're concerned with mapping pretty-printed
|
||||
JavaScript back to CoffeeScript.
|
||||
|
||||
In order to produce maps, we must keep track of positions (line number, column number)
|
||||
that originated every node in the syntax tree, and be able to generate a
|
||||
[map file](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit)
|
||||
— which is a compact, VLQ-encoded representation of the JSON serialization
|
||||
of this information — to write out alongside the generated JavaScript.
|
||||
|
||||
|
||||
LineMap
|
||||
-------
|
||||
|
||||
A **LineMap** object keeps track of information about original line and column
|
||||
positions for a single line of output JavaScript code.
|
||||
**SourceMaps** are implemented in terms of **LineMaps**.
|
||||
|
||||
class LineMap
|
||||
constructor: (@line) ->
|
||||
@columns = []
|
||||
|
||||
add: (column, [sourceLine, sourceColumn], options={}) ->
|
||||
return if @columns[column] and options.noReplace
|
||||
@columns[column] = {line: @line, column, sourceLine, sourceColumn}
|
||||
|
||||
sourceLocation: (column) ->
|
||||
column-- until (mapping = @columns[column]) or (column <= 0)
|
||||
mapping and [mapping.sourceLine, mapping.sourceColumn]
|
||||
|
||||
|
||||
SourceMap
|
||||
---------
|
||||
|
||||
Maps locations in a single generated JavaScript file back to locations in
|
||||
the original CoffeeScript source file.
|
||||
|
||||
This is intentionally agnostic towards how a source map might be represented on
|
||||
disk. Once the compiler is ready to produce a "v3"-style source map, we can walk
|
||||
through the arrays of line and column buffer to produce it.
|
||||
|
||||
class SourceMap
|
||||
constructor: ->
|
||||
@lines = []
|
||||
|
||||
Adds a mapping to this SourceMap. `sourceLocation` and `generatedLocation`
|
||||
are both `[line, column]` arrays. If `options.noReplace` is true, then if there
|
||||
is already a mapping for the specified `line` and `column`, this will have no
|
||||
effect.
|
||||
|
||||
add: (sourceLocation, generatedLocation, options = {}) ->
|
||||
[line, column] = generatedLocation
|
||||
lineMap = (@lines[line] or= new LineMap(line))
|
||||
lineMap.add column, sourceLocation, options
|
||||
|
||||
Look up the original position of a given `line` and `column` in the generated
|
||||
code.
|
||||
|
||||
sourceLocation: ([line, column]) ->
|
||||
line-- until (lineMap = @lines[line]) or (line <= 0)
|
||||
lineMap and lineMap.sourceLocation column
|
||||
|
||||
|
||||
V3 SourceMap Generation
|
||||
-----------------------
|
||||
|
||||
Builds up a V3 source map, returning the generated JSON as a string.
|
||||
`options.sourceRoot` may be used to specify the sourceRoot written to the source
|
||||
map. Also, `options.sourceFiles` and `options.generatedFile` may be passed to
|
||||
set "sources" and "file", respectively.
|
||||
|
||||
generate: (options = {}, code = null) ->
|
||||
writingline = 0
|
||||
lastColumn = 0
|
||||
lastSourceLine = 0
|
||||
lastSourceColumn = 0
|
||||
needComma = no
|
||||
buffer = ""
|
||||
|
||||
for lineMap, lineNumber in @lines when lineMap
|
||||
for mapping in lineMap.columns when mapping
|
||||
while writingline < mapping.line
|
||||
lastColumn = 0
|
||||
needComma = no
|
||||
buffer += ";"
|
||||
writingline++
|
||||
|
||||
Write a comma if we've already written a segment on this line.
|
||||
|
||||
if needComma
|
||||
buffer += ","
|
||||
needComma = no
|
||||
|
||||
Write the next segment. Segments can be 1, 4, or 5 values. If just one, then it
|
||||
is a generated column which doesn't match anything in the source code.
|
||||
|
||||
The starting column in the generated source, relative to any previous recorded
|
||||
column for the current line:
|
||||
|
||||
buffer += @encodeVlq mapping.column - lastColumn
|
||||
lastColumn = mapping.column
|
||||
|
||||
The index into the list of sources:
|
||||
|
||||
buffer += @encodeVlq 0
|
||||
|
||||
The starting line in the original source, relative to the previous source line.
|
||||
|
||||
buffer += @encodeVlq mapping.sourceLine - lastSourceLine
|
||||
lastSourceLine = mapping.sourceLine
|
||||
|
||||
The starting column in the original source, relative to the previous column.
|
||||
|
||||
buffer += @encodeVlq mapping.sourceColumn - lastSourceColumn
|
||||
lastSourceColumn = mapping.sourceColumn
|
||||
needComma = yes
|
||||
|
||||
Produce the canonical JSON object format for a "v3" source map.
|
||||
|
||||
v3 =
|
||||
version: 3
|
||||
file: options.generatedFile or ''
|
||||
sourceRoot: options.sourceRoot or ''
|
||||
sources: options.sourceFiles or ['']
|
||||
names: []
|
||||
mappings: buffer
|
||||
|
||||
v3.sourcesContent = [code] if options.inline
|
||||
|
||||
JSON.stringify v3, null, 2
|
||||
|
||||
|
||||
Base64 VLQ Encoding
|
||||
-------------------
|
||||
|
||||
Note that SourceMap VLQ encoding is "backwards". MIDI-style VLQ encoding puts
|
||||
the most-significant-bit (MSB) from the original value into the MSB of the VLQ
|
||||
encoded value (see [Wikipedia](http://en.wikipedia.org/wiki/File:Uintvar_coding.svg)).
|
||||
SourceMap VLQ does things the other way around, with the least significat four
|
||||
bits of the original value encoded into the first byte of the VLQ encoded value.
|
||||
|
||||
VLQ_SHIFT = 5
|
||||
VLQ_CONTINUATION_BIT = 1 << VLQ_SHIFT # 0010 0000
|
||||
VLQ_VALUE_MASK = VLQ_CONTINUATION_BIT - 1 # 0001 1111
|
||||
|
||||
encodeVlq: (value) ->
|
||||
answer = ''
|
||||
|
||||
# Least significant bit represents the sign.
|
||||
signBit = if value < 0 then 1 else 0
|
||||
|
||||
# The next bits are the actual value.
|
||||
valueToEncode = (Math.abs(value) << 1) + signBit
|
||||
|
||||
# Make sure we encode at least one character, even if valueToEncode is 0.
|
||||
while valueToEncode or not answer
|
||||
nextChunk = valueToEncode & VLQ_VALUE_MASK
|
||||
valueToEncode = valueToEncode >> VLQ_SHIFT
|
||||
nextChunk |= VLQ_CONTINUATION_BIT if valueToEncode
|
||||
answer += @encodeBase64 nextChunk
|
||||
|
||||
answer
|
||||
|
||||
|
||||
Regular Base64 Encoding
|
||||
-----------------------
|
||||
|
||||
BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
|
||||
encodeBase64: (value) ->
|
||||
BASE64_CHARS[value] or throw new Error "Cannot Base64 encode value: #{value}"
|
||||
|
||||
|
||||
Our API for source maps is just the `SourceMap` class.
|
||||
|
||||
module.exports = SourceMap
|
||||
|
||||
|
||||
|
||||
@@ -337,6 +337,18 @@ test "#2502: parenthesizing inner object values", ->
|
||||
eq (new A).sections.default, 0
|
||||
|
||||
|
||||
test "conditional prototype property assignment", ->
|
||||
debug = false
|
||||
|
||||
class Person
|
||||
if debug
|
||||
age: -> 10
|
||||
else
|
||||
age: -> 20
|
||||
|
||||
eq (new Person).age(), 20
|
||||
|
||||
|
||||
test "mild metaprogramming", ->
|
||||
|
||||
class Base
|
||||
@@ -730,13 +742,52 @@ test "#2359: extending native objects that use other typed constructors requires
|
||||
eq 'yes!', workingArray.method()
|
||||
|
||||
|
||||
test "#2489: removing __bind", ->
|
||||
test "#2782: non-alphanumeric-named bound functions", ->
|
||||
class A
|
||||
'b:c': =>
|
||||
'd'
|
||||
|
||||
class Thing
|
||||
foo: (a, b, c) ->
|
||||
bar: (a, b, c) =>
|
||||
eq (new A)['b:c'](), 'd'
|
||||
|
||||
thing = new Thing
|
||||
|
||||
eq thing.foo.length, 3
|
||||
eq thing.bar.length, 3
|
||||
test "#2781: overriding bound functions", ->
|
||||
class A
|
||||
a: ->
|
||||
@b()
|
||||
b: =>
|
||||
1
|
||||
|
||||
class B extends A
|
||||
b: =>
|
||||
2
|
||||
|
||||
b = (new A).b
|
||||
eq b(), 1
|
||||
|
||||
b = (new B).b
|
||||
eq b(), 2
|
||||
|
||||
|
||||
test "#2791: bound function with destructured argument", ->
|
||||
class Foo
|
||||
method: ({a}) => 'Bar'
|
||||
|
||||
eq (new Foo).method({a: 'Bar'}), 'Bar'
|
||||
|
||||
|
||||
test "#2796: ditto, ditto, ditto", ->
|
||||
answer = null
|
||||
|
||||
outsideMethod = (func) ->
|
||||
func.call message: 'wrong!'
|
||||
|
||||
class Base
|
||||
constructor: ->
|
||||
@message = 'right!'
|
||||
outsideMethod @echo
|
||||
|
||||
echo: =>
|
||||
answer = @message
|
||||
|
||||
new Base
|
||||
eq answer, 'right!'
|
||||
|
||||
15
test/cluster.coffee
Normal file
15
test/cluster.coffee
Normal file
@@ -0,0 +1,15 @@
|
||||
# Cluster Module
|
||||
# ---------
|
||||
|
||||
return if testingBrowser?
|
||||
|
||||
cluster = require 'cluster'
|
||||
|
||||
if cluster.isMaster
|
||||
test "#2737 - cluster module can spawn workers from a coffeescript process", ->
|
||||
cluster.once 'exit', (worker, code) ->
|
||||
eq code, 0
|
||||
|
||||
cluster.fork()
|
||||
else
|
||||
process.exit 0
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user