1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00
This commit is contained in:
Jeremy Ashkenas 2013-04-06 09:31:30 +08:00
commit 170f311101
15 changed files with 162 additions and 37 deletions

View file

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

View file

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

View file

@ -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"
});
}
}

View file

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

View file

@ -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'));

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -112,6 +112,8 @@
'soaks'
'strings'
]
# allow utf-8 chars in comments
# 智に働けば角が立つ、情に掉させば流される。
</script>
</body>