mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
Merge branch 'master' of https://github.com/jashkenas/coffee-script
This commit is contained in:
commit
170f311101
15 changed files with 162 additions and 37 deletions
|
@ -25,6 +25,7 @@
|
|||
options = {};
|
||||
}
|
||||
options.bare = true;
|
||||
options.shiftLine = true;
|
||||
return Function(compile(code, options))();
|
||||
};
|
||||
|
||||
|
@ -32,7 +33,7 @@
|
|||
return;
|
||||
}
|
||||
|
||||
if ((typeof btoa !== "undefined" && btoa !== null) && (typeof JSON !== "undefined" && JSON !== null)) {
|
||||
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) {
|
||||
|
@ -41,7 +42,7 @@
|
|||
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(v3SourceMap)) + "\n//@ sourceURL=coffeescript";
|
||||
return "" + js + "\n//@ sourceMappingURL=data:application/json;base64," + (btoa(unescape(encodeURIComponent(v3SourceMap)))) + "\n//@ sourceURL=coffeescript";
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -51,7 +52,7 @@
|
|||
options = {};
|
||||
}
|
||||
options.sourceFiles = [url];
|
||||
xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();
|
||||
xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP') : new window.XMLHttpRequest();
|
||||
xhr.open('GET', url, true);
|
||||
if ('overrideMimeType' in xhr) {
|
||||
xhr.overrideMimeType('text/plain');
|
||||
|
@ -74,7 +75,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;
|
||||
|
@ -110,9 +111,9 @@
|
|||
};
|
||||
|
||||
if (window.addEventListener) {
|
||||
addEventListener('DOMContentLoaded', runScripts, false);
|
||||
window.addEventListener('DOMContentLoaded', runScripts, false);
|
||||
} else {
|
||||
attachEvent('onload', runScripts);
|
||||
window.attachEvent('onload', runScripts);
|
||||
}
|
||||
|
||||
}).call(this);
|
||||
|
|
|
@ -34,7 +34,10 @@
|
|||
}
|
||||
fragments = (parser.parse(lexer.tokenize(code, options))).compileToFragments(options);
|
||||
currentLine = 0;
|
||||
if (options.header || options.inline) {
|
||||
if (options.header) {
|
||||
currentLine += 1;
|
||||
}
|
||||
if (options.shiftLine) {
|
||||
currentLine += 1;
|
||||
}
|
||||
currentColumn = 0;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Generated by CoffeeScript 1.6.2
|
||||
(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, lint, 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) {
|
||||
|
@ -387,7 +389,7 @@
|
|||
if (extension == null) {
|
||||
extension = ".js";
|
||||
}
|
||||
basename = helpers.baseFileName(source, true, path.sep);
|
||||
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;
|
||||
|
@ -407,7 +409,7 @@
|
|||
js = ' ';
|
||||
}
|
||||
if (generatedSourceMap) {
|
||||
js = "" + js + "\n/*\n//@ sourceMappingURL=" + (helpers.baseFileName(sourceMapPath, false, path.sep)) + "\n*/\n";
|
||||
js = "" + js + "\n/*\n//@ sourceMappingURL=" + (helpers.baseFileName(sourceMapPath, false, useWinPathSep)) + "\n*/\n";
|
||||
}
|
||||
fs.writeFile(jsPath, js, function(err) {
|
||||
if (err) {
|
||||
|
@ -503,13 +505,13 @@
|
|||
jsPath: jsPath,
|
||||
sourceRoot: path.relative(jsDir, cwd),
|
||||
sourceFiles: [path.relative(cwd, filename)],
|
||||
generatedFile: helpers.baseFileName(jsPath, false, path.sep)
|
||||
generatedFile: helpers.baseFileName(jsPath, false, useWinPathSep)
|
||||
});
|
||||
} else {
|
||||
answer = helpers.merge(answer, {
|
||||
sourceRoot: "",
|
||||
sourceFiles: [helpers.baseFileName(filename, false, path.sep)],
|
||||
generatedFile: helpers.baseFileName(filename, true, path.sep) + ".js"
|
||||
sourceFiles: [helpers.baseFileName(filename, false, useWinPathSep)],
|
||||
generatedFile: helpers.baseFileName(filename, true, useWinPathSep) + ".js"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,14 +156,15 @@
|
|||
}
|
||||
};
|
||||
|
||||
exports.baseFileName = function(file, stripExt, pathSep) {
|
||||
var parts;
|
||||
exports.baseFileName = function(file, stripExt, useWinPathSep) {
|
||||
var parts, pathSep;
|
||||
if (stripExt == null) {
|
||||
stripExt = false;
|
||||
}
|
||||
if (pathSep == null) {
|
||||
pathSep = '/';
|
||||
if (useWinPathSep == null) {
|
||||
useWinPathSep = false;
|
||||
}
|
||||
pathSep = useWinPathSep ? /\\|\// : /\//;
|
||||
parts = file.split(pathSep);
|
||||
file = parts[parts.length - 1];
|
||||
if (!stripExt) {
|
||||
|
|
|
@ -2126,7 +2126,7 @@
|
|||
set = '';
|
||||
body = this.body;
|
||||
if (body.isEmpty()) {
|
||||
body = '';
|
||||
body = this.makeCode('');
|
||||
} else {
|
||||
if (this.returns) {
|
||||
body.makeReturn(rvar = o.scope.freeVariable('results'));
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
// Generated by CoffeeScript 1.6.2
|
||||
(function() {
|
||||
var CoffeeScript, addMultilineHandler, merge, nodeREPL, prettyErrorMessage, replDefaults, vm, _ref;
|
||||
var CoffeeScript, addHistory, addMultilineHandler, fs, merge, nodeREPL, path, prettyErrorMessage, replDefaults, vm, _ref;
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
path = require('path');
|
||||
|
||||
vm = require('vm');
|
||||
|
||||
|
@ -12,6 +16,8 @@
|
|||
|
||||
replDefaults = {
|
||||
prompt: 'coffee> ',
|
||||
historyFile: path.join(process.env.HOME, '.coffee_history'),
|
||||
historyMaxInputSize: 10240,
|
||||
"eval": function(input, context, filename, cb) {
|
||||
var Assign, Block, Literal, Value, ast, err, js, _ref1;
|
||||
input = input.replace(/\uFF00/g, '\n');
|
||||
|
@ -86,6 +92,52 @@
|
|||
});
|
||||
};
|
||||
|
||||
addHistory = function(repl, filename, maxSize) {
|
||||
var buffer, fd, readFd, size, stat;
|
||||
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 (size === maxSize) {
|
||||
repl.rli.history.pop();
|
||||
}
|
||||
if (repl.rli.history[0] === '') {
|
||||
repl.rli.history.shift();
|
||||
}
|
||||
repl.rli.historyIndex = -1;
|
||||
} catch (_error) {}
|
||||
fd = fs.openSync(filename, 'a');
|
||||
repl.rli.addListener('line', function(code) {
|
||||
if (code && code.length && code !== '.history') {
|
||||
return fs.write(fd, "" + code + "\n");
|
||||
}
|
||||
});
|
||||
process.on('exit', function() {
|
||||
return fs.closeSync(fd);
|
||||
});
|
||||
return repl.commands['.history'] = {
|
||||
help: 'Show command history',
|
||||
action: function() {
|
||||
var history, k;
|
||||
history = ((function() {
|
||||
var _i, _len, _ref1, _results;
|
||||
_ref1 = Object.keys(repl.rli.history);
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
||||
k = _ref1[_i];
|
||||
_results.push(repl.rli.history[k]);
|
||||
}
|
||||
return _results;
|
||||
})()).reverse();
|
||||
repl.outputStream.write("" + (history.join('\n')) + "\n");
|
||||
return repl.displayPrompt();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
start: function(opts) {
|
||||
var build, major, minor, repl, _ref1;
|
||||
|
@ -105,6 +157,9 @@
|
|||
return repl.outputStream.write('\n');
|
||||
});
|
||||
addMultilineHandler(repl);
|
||||
if (opts.historyFile) {
|
||||
addHistory(repl, opts.historyFile, opts.historyMaxInputSize);
|
||||
}
|
||||
return repl;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -15,19 +15,21 @@ CoffeeScript.eval = (code, options = {}) ->
|
|||
# Running code does not provide access to this scope.
|
||||
CoffeeScript.run = (code, options = {}) ->
|
||||
options.bare = on
|
||||
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, and a
|
||||
# JSON serializer, we're good to go.
|
||||
if btoa? and JSON?
|
||||
# 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 v3SourceMap}\n//@ sourceURL=coffeescript"
|
||||
"#{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 = {}) ->
|
||||
|
@ -35,7 +37,7 @@ CoffeeScript.load = (url, callback, options = {}) ->
|
|||
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 = ->
|
||||
|
@ -51,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
|
||||
|
@ -71,6 +73,6 @@ runScripts = ->
|
|||
|
||||
# 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
|
||||
|
|
|
@ -36,7 +36,8 @@ exports.compile = compile = (code, options = {}) ->
|
|||
fragments = (parser.parse lexer.tokenize(code, options)).compileToFragments options
|
||||
|
||||
currentLine = 0
|
||||
currentLine += 1 if options.header or options.inline
|
||||
currentLine += 1 if options.header
|
||||
currentLine += 1 if options.shiftLine
|
||||
currentColumn = 0
|
||||
js = ""
|
||||
for fragment in fragments
|
||||
|
|
|
@ -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
|
||||
|
@ -256,7 +257,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, path.sep
|
||||
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
|
||||
|
@ -274,7 +275,7 @@ writeJs = (base, sourcePath, js, jsPath, generatedSourceMap = null) ->
|
|||
compile = ->
|
||||
if opts.compile
|
||||
js = ' ' if js.length <= 0
|
||||
if generatedSourceMap then js = "#{js}\n/*\n//@ sourceMappingURL=#{helpers.baseFileName sourceMapPath, no, path.sep}\n*/\n"
|
||||
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
|
||||
|
@ -343,13 +344,13 @@ compileOptions = (filename, base) ->
|
|||
jsPath
|
||||
sourceRoot: path.relative jsDir, cwd
|
||||
sourceFiles: [path.relative cwd, filename]
|
||||
generatedFile: helpers.baseFileName(jsPath, no, path.sep)
|
||||
generatedFile: helpers.baseFileName(jsPath, no, useWinPathSep)
|
||||
}
|
||||
else
|
||||
answer = helpers.merge answer,
|
||||
sourceRoot: ""
|
||||
sourceFiles: [helpers.baseFileName filename, no, path.sep]
|
||||
generatedFile: helpers.baseFileName(filename, yes, path.sep) + ".js"
|
||||
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
|
||||
|
|
|
@ -118,7 +118,8 @@ exports.locationDataToString = (obj) ->
|
|||
"No location data"
|
||||
|
||||
# A `.coffee.md` compatible version of `basename`, that returns the file sans-extension.
|
||||
exports.baseFileName = (file, stripExt = no, pathSep = '/') ->
|
||||
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
|
||||
|
|
|
@ -1504,7 +1504,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'
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
vm = require 'vm'
|
||||
nodeREPL = require 'repl'
|
||||
CoffeeScript = require './coffee-script'
|
||||
|
@ -5,6 +7,8 @@ CoffeeScript = require './coffee-script'
|
|||
|
||||
replDefaults =
|
||||
prompt: 'coffee> ',
|
||||
historyFile: path.join(process.env.HOME, '.coffee_history')
|
||||
historyMaxInputSize: 10240
|
||||
eval: (input, context, filename, cb) ->
|
||||
# XXX: multiline hack.
|
||||
input = input.replace /\uFF00/g, '\n'
|
||||
|
@ -76,6 +80,42 @@ addMultilineHandler = (repl) ->
|
|||
rli.prompt true
|
||||
return
|
||||
|
||||
# Store and load command history from a file
|
||||
addHistory = (repl, filename, maxSize) ->
|
||||
try
|
||||
# Get file info and at most 10KB 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 size is maxSize
|
||||
# Shift off the final blank newline
|
||||
repl.rli.history.shift() if repl.rli.history[0] is ''
|
||||
repl.rli.historyIndex = -1
|
||||
|
||||
fd = fs.openSync filename, 'a'
|
||||
|
||||
repl.rli.addListener 'line', (code) ->
|
||||
if code and code.length and code isnt '.history'
|
||||
# Save the latest command in the file
|
||||
fs.write fd, "#{code}\n"
|
||||
|
||||
process.on 'exit', ->
|
||||
fs.closeSync fd
|
||||
|
||||
# Add a command to show the history stack
|
||||
repl.commands['.history'] =
|
||||
help: 'Show command history'
|
||||
action: ->
|
||||
history = (repl.rli.history[k] for k in Object.keys(repl.rli.history)).reverse()
|
||||
repl.outputStream.write "#{history.join '\n'}\n"
|
||||
repl.displayPrompt()
|
||||
|
||||
module.exports =
|
||||
start: (opts = {}) ->
|
||||
[major, minor, build] = process.versions.node.split('.').map (n) -> parseInt(n)
|
||||
|
@ -88,4 +128,5 @@ module.exports =
|
|||
repl = nodeREPL.start opts
|
||||
repl.on 'exit', -> repl.outputStream.write '\n'
|
||||
addMultilineHandler repl
|
||||
addHistory repl, opts.historyFile, opts.historyMaxInputSize if opts.historyFile
|
||||
repl
|
||||
|
|
|
@ -76,3 +76,6 @@ test "#1055: invalid keys in real (but not work-product) objects", ->
|
|||
|
||||
test "#1066: interpolated strings are not implicit functions", ->
|
||||
cantCompile '"int#{er}polated" arg'
|
||||
|
||||
test "#2846: while with empty body", ->
|
||||
CoffeeScript.compile 'while 1 then', {sourceMap: true}
|
|
@ -1,5 +1,7 @@
|
|||
return if global.testingBrowser
|
||||
|
||||
fs = require 'fs'
|
||||
|
||||
# REPL
|
||||
# ----
|
||||
Stream = require 'stream'
|
||||
|
@ -25,16 +27,23 @@ class MockOutputStream extends Stream
|
|||
lastWrite: (fromEnd = -1) ->
|
||||
@written[@written.length - 1 + fromEnd].replace /\n$/, ''
|
||||
|
||||
# Create a dummy history file
|
||||
historyFile = '.coffee_history_test'
|
||||
fs.writeFileSync historyFile, '1 + 2\n'
|
||||
|
||||
testRepl = (desc, fn) ->
|
||||
input = new MockInputStream
|
||||
output = new MockOutputStream
|
||||
Repl.start {input, output}
|
||||
test desc, -> fn input, output
|
||||
repl = Repl.start {input, output, historyFile}
|
||||
test desc, -> fn input, output, repl
|
||||
|
||||
ctrlV = { ctrl: true, name: 'v'}
|
||||
|
||||
|
||||
testRepl 'reads history file', (input, output, repl) ->
|
||||
input.emitLine repl.rli.history[0]
|
||||
eq '3', output.lastWrite()
|
||||
|
||||
testRepl "starts with coffee prompt", (input, output) ->
|
||||
eq 'coffee> ', output.lastWrite(0)
|
||||
|
||||
|
@ -97,3 +106,6 @@ testRepl "keeps running after runtime error", (input, output) ->
|
|||
eq 0, output.lastWrite().indexOf 'ReferenceError: b is not defined'
|
||||
input.emitLine 'a'
|
||||
eq 'undefined', output.lastWrite()
|
||||
|
||||
process.on 'exit', ->
|
||||
fs.unlinkSync historyFile
|
||||
|
|
|
@ -112,6 +112,8 @@
|
|||
'soaks'
|
||||
'strings'
|
||||
]
|
||||
# allow utf-8 chars in comments
|
||||
# 智に働けば角が立つ、情に掉させば流される。
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
|
Loading…
Reference in a new issue