mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
Merge branch 'master' into ast
# Conflicts: # lib/coffeescript/grammar.js # lib/coffeescript/nodes.js # lib/coffeescript/parser.js # package-lock.json # src/nodes.coffee # test/error_messages.coffee
This commit is contained in:
commit
0b5bac666f
24 changed files with 1576 additions and 1441 deletions
3
Cakefile
3
Cakefile
|
@ -486,6 +486,9 @@ task 'test:integrations', 'test the module integrated with other libraries and e
|
|||
webpack = require 'webpack'
|
||||
webpack {
|
||||
entry: './'
|
||||
optimization:
|
||||
# Webpack’s minification causes the CoffeeScript module to fail some tests.
|
||||
minimize: off
|
||||
output:
|
||||
path: tmpdir
|
||||
filename: 'coffeescript.js'
|
||||
|
|
|
@ -376,7 +376,7 @@ undeclared variable <code>__</code>.</p>
|
|||
vm.runInContext js, context, filename
|
||||
<span class="hljs-function">
|
||||
<span class="hljs-title">addMultilineHandler</span> = <span class="hljs-params">(repl)</span> -></span>
|
||||
{rli, inputStream, outputStream} = repl</pre></div></div>
|
||||
{inputStream, outputStream} = repl</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
@ -412,15 +412,15 @@ undeclared variable <code>__</code>.</p>
|
|||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> nodeLineListener = rli.listeners(<span class="hljs-string">'line'</span>)[<span class="hljs-number">0</span>]
|
||||
rli.removeListener <span class="hljs-string">'line'</span>, nodeLineListener
|
||||
rli.<span class="hljs-literal">on</span> <span class="hljs-string">'line'</span>, <span class="hljs-function"><span class="hljs-params">(cmd)</span> -></span>
|
||||
<div class="content"><div class='highlight'><pre> nodeLineListener = repl.listeners(<span class="hljs-string">'line'</span>)[<span class="hljs-number">0</span>]
|
||||
repl.removeListener <span class="hljs-string">'line'</span>, nodeLineListener
|
||||
repl.<span class="hljs-literal">on</span> <span class="hljs-string">'line'</span>, <span class="hljs-function"><span class="hljs-params">(cmd)</span> -></span>
|
||||
<span class="hljs-keyword">if</span> multiline.enabled
|
||||
multiline.buffer += <span class="hljs-string">"<span class="hljs-subst">#{cmd}</span>\n"</span>
|
||||
rli.setPrompt multiline.prompt
|
||||
rli.prompt <span class="hljs-literal">true</span>
|
||||
repl.setPrompt multiline.prompt
|
||||
repl.prompt <span class="hljs-literal">true</span>
|
||||
<span class="hljs-keyword">else</span>
|
||||
rli.setPrompt origPrompt
|
||||
repl.setPrompt origPrompt
|
||||
nodeLineListener cmd
|
||||
<span class="hljs-keyword">return</span></pre></div></div>
|
||||
|
||||
|
@ -456,8 +456,8 @@ undeclared variable <code>__</code>.</p>
|
|||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">unless</span> multiline.buffer.match <span class="hljs-regexp">/\n/</span>
|
||||
multiline.enabled = <span class="hljs-keyword">not</span> multiline.enabled
|
||||
rli.setPrompt origPrompt
|
||||
rli.prompt <span class="hljs-literal">true</span>
|
||||
repl.setPrompt origPrompt
|
||||
repl.prompt <span class="hljs-literal">true</span>
|
||||
<span class="hljs-keyword">return</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
@ -473,7 +473,7 @@ undeclared variable <code>__</code>.</p>
|
|||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> rli.line? <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> rli.line.match <span class="hljs-regexp">/^\s*$/</span></pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> repl.line? <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> repl.line.match <span class="hljs-regexp">/^\s*$/</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
@ -489,10 +489,10 @@ undeclared variable <code>__</code>.</p>
|
|||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> multiline.enabled = <span class="hljs-keyword">not</span> multiline.enabled
|
||||
rli.line = <span class="hljs-string">''</span>
|
||||
rli.cursor = <span class="hljs-number">0</span>
|
||||
rli.output.cursorTo <span class="hljs-number">0</span>
|
||||
rli.output.clearLine <span class="hljs-number">1</span></pre></div></div>
|
||||
repl.line = <span class="hljs-string">''</span>
|
||||
repl.cursor = <span class="hljs-number">0</span>
|
||||
repl.output.cursorTo <span class="hljs-number">0</span>
|
||||
repl.output.clearLine <span class="hljs-number">1</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
@ -508,12 +508,12 @@ undeclared variable <code>__</code>.</p>
|
|||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> multiline.buffer = multiline.buffer.replace <span class="hljs-regexp">/\n/g</span>, <span class="hljs-string">'\uFF00'</span>
|
||||
rli.emit <span class="hljs-string">'line'</span>, multiline.buffer
|
||||
repl.emit <span class="hljs-string">'line'</span>, multiline.buffer
|
||||
multiline.buffer = <span class="hljs-string">''</span>
|
||||
<span class="hljs-keyword">else</span>
|
||||
multiline.enabled = <span class="hljs-keyword">not</span> multiline.enabled
|
||||
rli.setPrompt multiline.initialPrompt
|
||||
rli.prompt <span class="hljs-literal">true</span>
|
||||
repl.setPrompt multiline.initialPrompt
|
||||
repl.prompt <span class="hljs-literal">true</span>
|
||||
<span class="hljs-keyword">return</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
@ -580,7 +580,7 @@ undeclared variable <code>__</code>.</p>
|
|||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> repl.rli.history = buffer.toString().split(<span class="hljs-string">'\n'</span>).reverse()</pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> repl.history = buffer.toString().split(<span class="hljs-string">'\n'</span>).reverse()</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
@ -595,7 +595,7 @@ undeclared variable <code>__</code>.</p>
|
|||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> repl.rli.history.pop() <span class="hljs-keyword">if</span> stat.size > maxSize</pre></div></div>
|
||||
<div class="content"><div class='highlight'><pre> repl.history.pop() <span class="hljs-keyword">if</span> stat.size > maxSize</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
@ -610,13 +610,13 @@ undeclared variable <code>__</code>.</p>
|
|||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> repl.rli.history.shift() <span class="hljs-keyword">if</span> repl.rli.history[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">''</span>
|
||||
repl.rli.historyIndex = <span class="hljs-number">-1</span>
|
||||
lastLine = repl.rli.history[<span class="hljs-number">0</span>]
|
||||
<div class="content"><div class='highlight'><pre> repl.history.shift() <span class="hljs-keyword">if</span> repl.history[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">''</span>
|
||||
repl.historyIndex = <span class="hljs-number">-1</span>
|
||||
lastLine = repl.history[<span class="hljs-number">0</span>]
|
||||
|
||||
fd = fs.openSync filename, <span class="hljs-string">'a'</span>
|
||||
|
||||
repl.rli.addListener <span class="hljs-string">'line'</span>, <span class="hljs-function"><span class="hljs-params">(code)</span> -></span>
|
||||
repl.addListener <span class="hljs-string">'line'</span>, <span class="hljs-function"><span class="hljs-params">(code)</span> -></span>
|
||||
<span class="hljs-keyword">if</span> code <span class="hljs-keyword">and</span> code.length <span class="hljs-keyword">and</span> code <span class="hljs-keyword">isnt</span> <span class="hljs-string">'.history'</span> <span class="hljs-keyword">and</span> code <span class="hljs-keyword">isnt</span> <span class="hljs-string">'.exit'</span> <span class="hljs-keyword">and</span> lastLine <span class="hljs-keyword">isnt</span> code</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
@ -667,7 +667,7 @@ undeclared variable <code>__</code>.</p>
|
|||
<div class="content"><div class='highlight'><pre> repl.commands[getCommandId(repl, <span class="hljs-string">'history'</span>)] =
|
||||
help: <span class="hljs-string">'Show command history'</span>
|
||||
action: <span class="hljs-function">-></span>
|
||||
repl.outputStream.write <span class="hljs-string">"<span class="hljs-subst">#{repl.rli.history[..].reverse().join <span class="hljs-string">'\n'</span>}</span>\n"</span>
|
||||
repl.outputStream.write <span class="hljs-string">"<span class="hljs-subst">#{repl.history[..].reverse().join <span class="hljs-string">'\n'</span>}</span>\n"</span>
|
||||
repl.displayPrompt()
|
||||
<span class="hljs-function">
|
||||
<span class="hljs-title">getCommandId</span> = <span class="hljs-params">(repl, commandName)</span> -></span></pre></div></div>
|
||||
|
@ -742,7 +742,7 @@ the REPL, the only applicable option is <code>transpile</code>.</p>
|
|||
opts = merge replDefaults, opts
|
||||
repl = nodeREPL.start opts
|
||||
runInContext opts.prelude, repl.context, <span class="hljs-string">'prelude'</span> <span class="hljs-keyword">if</span> opts.prelude
|
||||
repl.<span class="hljs-literal">on</span> <span class="hljs-string">'exit'</span>, <span class="hljs-function">-></span> repl.outputStream.write <span class="hljs-string">'\n'</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> repl.rli.closed
|
||||
repl.<span class="hljs-literal">on</span> <span class="hljs-string">'exit'</span>, <span class="hljs-function">-></span> repl.outputStream.write <span class="hljs-string">'\n'</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> repl.closed
|
||||
addMultilineHandler repl
|
||||
addHistory repl, opts.historyFile, opts.historyMaxInputSize <span class="hljs-keyword">if</span> opts.historyFile</pre></div></div>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// on Node.js/V8, or to run CoffeeScript directly in the browser. This module
|
||||
// contains the main entry functions for tokenizing, parsing, and compiling
|
||||
// source CoffeeScript into JavaScript.
|
||||
var FILE_EXTENSIONS, Lexer, SourceMap, base64encode, checkShebangLine, compile, formatSourcePosition, getSourceMap, helpers, lexer, packageJson, parser, sourceMaps, sources, withPrettyErrors,
|
||||
var FILE_EXTENSIONS, Lexer, SourceMap, base64encode, checkShebangLine, compile, formatSourcePosition, getSourceMap, helpers, lexer, packageJson, parser, registerCompiled, sourceMaps, sources, withPrettyErrors,
|
||||
indexOf = [].indexOf;
|
||||
|
||||
({Lexer} = require('./lexer'));
|
||||
|
@ -74,6 +74,24 @@
|
|||
// Also save source maps if generated, in form of `(source)`: [`(source map)`].
|
||||
sourceMaps = {};
|
||||
|
||||
// This is exported to enable an external module to implement caching of
|
||||
// compilation results. When the compiled js source is loaded from cache, the
|
||||
// original coffee code should be added with this method in order to enable the
|
||||
// Error.prepareStackTrace below to correctly adjust the stack trace for the
|
||||
// corresponding file (the source map will be generated on demand).
|
||||
exports.registerCompiled = registerCompiled = function(filename, source, sourcemap) {
|
||||
if (sources[filename] == null) {
|
||||
sources[filename] = [];
|
||||
}
|
||||
sources[filename].push(source);
|
||||
if (sourcemap != null) {
|
||||
if (sourceMaps[filename] == null) {
|
||||
sourceMaps[filename] = [];
|
||||
}
|
||||
return sourceMaps[filename].push(sourcemap);
|
||||
}
|
||||
};
|
||||
|
||||
// Compile CoffeeScript code to JavaScript, using the Coffee/Jison compiler.
|
||||
|
||||
// If `options.sourceMap` is specified, then `options.filename` must also be
|
||||
|
@ -94,10 +112,6 @@
|
|||
generateSourceMap = options.sourceMap || options.inlineMap || (options.filename == null);
|
||||
filename = options.filename || '<anonymous>';
|
||||
checkShebangLine(filename, code);
|
||||
if (sources[filename] == null) {
|
||||
sources[filename] = [];
|
||||
}
|
||||
sources[filename].push(code);
|
||||
if (generateSourceMap) {
|
||||
map = new SourceMap();
|
||||
}
|
||||
|
@ -177,10 +191,6 @@
|
|||
}
|
||||
if (generateSourceMap) {
|
||||
v3SourceMap = map.generate(options, code);
|
||||
if (sourceMaps[filename] == null) {
|
||||
sourceMaps[filename] = [];
|
||||
}
|
||||
sourceMaps[filename].push(map);
|
||||
}
|
||||
if (options.transpile) {
|
||||
if (typeof options.transpile !== 'object') {
|
||||
|
@ -211,6 +221,7 @@
|
|||
sourceURL = `//# sourceURL=${(ref1 = options.filename) != null ? ref1 : 'coffeescript'}`;
|
||||
js = `${js}\n${sourceMapDataURI}\n${sourceURL}`;
|
||||
}
|
||||
registerCompiled(filename, code, map);
|
||||
if (options.sourceMap) {
|
||||
return {
|
||||
js,
|
||||
|
|
|
@ -412,6 +412,11 @@
|
|||
false,
|
||||
$1);
|
||||
}),
|
||||
o('DYNAMIC_IMPORT Arguments',
|
||||
function() {
|
||||
return new DynamicImportCall(LOC(1)(new DynamicImport()),
|
||||
$2);
|
||||
}),
|
||||
o('SimpleObjAssignable Arguments',
|
||||
function() {
|
||||
return new Call(new Value($1),
|
||||
|
@ -1077,6 +1082,11 @@
|
|||
$3,
|
||||
$2,
|
||||
$1);
|
||||
}),
|
||||
o('DYNAMIC_IMPORT Arguments',
|
||||
function() {
|
||||
return new DynamicImportCall(LOC(1)(new DynamicImport()),
|
||||
$2);
|
||||
})
|
||||
],
|
||||
// An optional existence check on a function.
|
||||
|
@ -2321,7 +2331,7 @@
|
|||
// And not:
|
||||
|
||||
// (2 + 3) * 4
|
||||
operators = [['right', 'DO_IIFE'], ['left', '.', '?.', '::', '?::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY', 'DO'], ['right', 'AWAIT'], ['right', '**'], ['right', 'UNARY_MATH'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', '&'], ['left', '^'], ['left', '|'], ['left', '&&'], ['left', '||'], ['left', 'BIN?'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', 'YIELD'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'FORFROM', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT'], ['left', 'POST_IF']];
|
||||
operators = [['right', 'DO_IIFE'], ['left', '.', '?.', '::', '?::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY', 'DO'], ['right', 'AWAIT'], ['right', '**'], ['right', 'UNARY_MATH'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', '&'], ['left', '^'], ['left', '|'], ['left', '&&'], ['left', '||'], ['left', 'BIN?'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', 'YIELD'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'FORFROM', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT', 'DYNAMIC_IMPORT'], ['left', 'POST_IF']];
|
||||
|
||||
// Wrapping Up
|
||||
// -----------
|
||||
|
|
|
@ -152,9 +152,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
CoffeeScript._compileFile = function(filename, options = {}) {
|
||||
var answer, err, raw, stripped;
|
||||
raw = fs.readFileSync(filename, 'utf8');
|
||||
CoffeeScript._compileRawFileContent = function(raw, filename, options = {}) {
|
||||
var answer, err, stripped;
|
||||
// Strip the Unicode byte order mark, if this file begins with one.
|
||||
stripped = raw.charCodeAt(0) === 0xFEFF ? raw.substring(1) : raw;
|
||||
options = Object.assign({}, options, {
|
||||
|
@ -175,6 +174,12 @@
|
|||
return answer;
|
||||
};
|
||||
|
||||
CoffeeScript._compileFile = function(filename, options = {}) {
|
||||
var raw;
|
||||
raw = fs.readFileSync(filename, 'utf8');
|
||||
return CoffeeScript._compileRawFileContent(raw, filename, options);
|
||||
};
|
||||
|
||||
module.exports = CoffeeScript;
|
||||
|
||||
}).call(this);
|
||||
|
|
|
@ -997,6 +997,9 @@
|
|||
return value.length;
|
||||
}
|
||||
}
|
||||
if (value === '(' && (prev != null ? prev[0] : void 0) === 'IMPORT') {
|
||||
prev[0] = 'DYNAMIC_IMPORT';
|
||||
}
|
||||
if (value === '{' && this.seenImport) {
|
||||
this.importSpecifierList = true;
|
||||
} else if (this.importSpecifierList && value === '}') {
|
||||
|
@ -1714,7 +1717,7 @@
|
|||
// Tokens which could legitimately be invoked or indexed. An opening
|
||||
// parentheses or bracket following these tokens will be recorded as the start
|
||||
// of a function invocation or indexing operation.
|
||||
CALLABLE = ['IDENTIFIER', 'PROPERTY', ')', ']', '?', '@', 'THIS', 'SUPER'];
|
||||
CALLABLE = ['IDENTIFIER', 'PROPERTY', ')', ']', '?', '@', 'THIS', 'SUPER', 'DYNAMIC_IMPORT'];
|
||||
|
||||
INDEXABLE = CALLABLE.concat(['NUMBER', 'INFINITY', 'NAN', 'STRING', 'STRING_END', 'REGEX', 'REGEX_END', 'BOOL', 'NULL', 'UNDEFINED', '}', '::']);
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// nodes are created as the result of actions in the [grammar](grammar.html),
|
||||
// but some are created by other nodes as a method of code generation. To convert
|
||||
// the syntax tree into a string of JavaScript code, call `compile()` on the root.
|
||||
var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, CSXAttribute, CSXAttributes, CSXElement, CSXExpressionContainer, CSXIdentifier, CSXTag, Call, Catch, Class, Code, CodeFragment, ComputedPropertyName, DefaultLiteral, Elision, ExecutableClassBody, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, FuncDirectiveReturn, FuncGlyph, HEREGEX_OMIT, HereComment, HoistTarget, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, Interpolation, JS_FORBIDDEN, LEADING_BLANK_LINE, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, LineComment, Literal, MetaProperty, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, ObjectProperty, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, Root, SIMPLENUM, SIMPLE_STRING_OMIT, STRING_OMIT, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, Super, SuperCall, Switch, SwitchCase, SwitchWhen, TAB, THIS, TRAILING_BLANK_LINE, TaggedTemplateCall, TemplateElement, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addDataToNode, attachCommentsToNode, compact, del, ends, extend, flatten, fragmentsToText, greater, hasLineComments, indentInitial, isAstLocGreater, isFunction, isLiteralArguments, isLiteralThis, isLocationDataEndGreater, isLocationDataStartGreater, isNumber, isPlainObject, isUnassignable, jisonLocationDataToAstLocationData, lesser, locationDataToString, makeDelimitedLiteral, merge, mergeAstLocationData, mergeLocationData, moveComments, multident, replaceUnicodeCodePointEscapes, shouldCacheOrIsAssignable, some, starts, throwSyntaxError, unfoldSoak, unshiftAfterComments, utility,
|
||||
var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, CSXAttribute, CSXAttributes, CSXElement, CSXExpressionContainer, CSXIdentifier, CSXTag, Call, Catch, Class, Code, CodeFragment, ComputedPropertyName, DefaultLiteral, DynamicImport, DynamicImportCall, Elision, ExecutableClassBody, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, FuncDirectiveReturn, FuncGlyph, HEREGEX_OMIT, HereComment, HoistTarget, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, Interpolation, JS_FORBIDDEN, LEADING_BLANK_LINE, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, LineComment, Literal, MetaProperty, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, ObjectProperty, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, Root, SIMPLENUM, SIMPLE_STRING_OMIT, STRING_OMIT, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, Super, SuperCall, Switch, SwitchCase, SwitchWhen, TAB, THIS, TRAILING_BLANK_LINE, TaggedTemplateCall, TemplateElement, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addDataToNode, attachCommentsToNode, compact, del, ends, extend, flatten, fragmentsToText, greater, hasLineComments, indentInitial, isAstLocGreater, isFunction, isLiteralArguments, isLiteralThis, isLocationDataEndGreater, isLocationDataStartGreater, isNumber, isPlainObject, isUnassignable, jisonLocationDataToAstLocationData, lesser, locationDataToString, makeDelimitedLiteral, merge, mergeAstLocationData, mergeLocationData, moveComments, multident, replaceUnicodeCodePointEscapes, shouldCacheOrIsAssignable, some, starts, throwSyntaxError, unfoldSoak, unshiftAfterComments, utility,
|
||||
indexOf = [].indexOf,
|
||||
splice = [].splice,
|
||||
slice1 = [].slice;
|
||||
|
@ -282,7 +282,7 @@
|
|||
|
||||
// Occasionally it may be useful to make an expression behave as if it was 'hoisted', whereby the
|
||||
// result of the expression is available before its location in the source, but the expression's
|
||||
// variable scope corresponds the source position. This is used extensively to deal with executable
|
||||
// variable scope corresponds to the source position. This is used extensively to deal with executable
|
||||
// class bodies in classes.
|
||||
|
||||
// Calling this method mutates the node, proxying the `compileNode` and `compileToFragments`
|
||||
|
@ -3468,10 +3468,10 @@
|
|||
return [this.makeCode('[]')];
|
||||
}
|
||||
o.indent += TAB;
|
||||
fragmentIsElision = function(fragment) {
|
||||
return fragmentsToText(fragment).trim() === ',';
|
||||
fragmentIsElision = function([fragment]) {
|
||||
return fragment.type === 'Elision' && fragment.code.trim() === ',';
|
||||
};
|
||||
// Detect if `Elisions` at the beginning of the array are processed (e.g. [, , , a]).
|
||||
// Detect if `Elision`s at the beginning of the array are processed (e.g. [, , , a]).
|
||||
passedElision = false;
|
||||
answer = [];
|
||||
ref1 = this.objects;
|
||||
|
@ -3528,7 +3528,7 @@
|
|||
fragment = answer[fragmentIndex];
|
||||
if (fragment.isHereComment) {
|
||||
fragment.code = `${multident(fragment.code, o.indent, false)}\n${o.indent}`;
|
||||
} else if (fragment.code === ', ' && !(fragment != null ? fragment.isElision : void 0)) {
|
||||
} else if (fragment.code === ', ' && !(fragment != null ? fragment.isElision : void 0) && fragment.type !== 'StringLiteral') {
|
||||
fragment.code = `,\n${o.indent}`;
|
||||
}
|
||||
}
|
||||
|
@ -4013,7 +4013,7 @@
|
|||
return this.body.traverseChildren(false, (node) => {
|
||||
if (node instanceof ThisLiteral) {
|
||||
return node.value = this.name;
|
||||
} else if (node instanceof Code && node.bound && node.isStatic) {
|
||||
} else if (node instanceof Code && node.bound && (node.isStatic || !node.name)) {
|
||||
return node.context = this.name;
|
||||
}
|
||||
});
|
||||
|
@ -4403,6 +4403,23 @@
|
|||
|
||||
};
|
||||
|
||||
exports.DynamicImport = DynamicImport = class DynamicImport extends Base {
|
||||
compileNode() {
|
||||
return [this.makeCode('import')];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
exports.DynamicImportCall = DynamicImportCall = class DynamicImportCall extends Call {
|
||||
compileNode(o) {
|
||||
if (this.args.length !== 1) {
|
||||
this.error('import() requires exactly one argument');
|
||||
}
|
||||
return super.compileNode(o);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//### Assign
|
||||
|
||||
// The **Assign** is used to assign a local variable to value, or to set the
|
||||
|
@ -5223,7 +5240,7 @@
|
|||
// (e.g. `ref`), shift those into the parent scope since we can’t put a
|
||||
// `var` line inside a function parameter list.
|
||||
scopeVariablesCount = o.scope.variables.length;
|
||||
signature.push(...param.compileToFragments(o));
|
||||
signature.push(...param.compileToFragments(o, LEVEL_PAREN));
|
||||
if (scopeVariablesCount !== o.scope.variables.length) {
|
||||
generatedVariables = o.scope.variables.splice(scopeVariablesCount);
|
||||
o.scope.parent.variables.push(...generatedVariables);
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -113,8 +113,8 @@
|
|||
};
|
||||
|
||||
addMultilineHandler = function(repl) {
|
||||
var inputStream, multiline, nodeLineListener, origPrompt, outputStream, ref, rli;
|
||||
({rli, inputStream, outputStream} = repl);
|
||||
var inputStream, multiline, nodeLineListener, origPrompt, outputStream, ref;
|
||||
({inputStream, outputStream} = repl);
|
||||
// Node 0.11.12 changed API, prompt is now _prompt.
|
||||
origPrompt = (ref = repl._prompt) != null ? ref : repl.prompt;
|
||||
multiline = {
|
||||
|
@ -128,15 +128,15 @@
|
|||
buffer: ''
|
||||
};
|
||||
// Proxy node's line listener
|
||||
nodeLineListener = rli.listeners('line')[0];
|
||||
rli.removeListener('line', nodeLineListener);
|
||||
rli.on('line', function(cmd) {
|
||||
nodeLineListener = repl.listeners('line')[0];
|
||||
repl.removeListener('line', nodeLineListener);
|
||||
repl.on('line', function(cmd) {
|
||||
if (multiline.enabled) {
|
||||
multiline.buffer += `${cmd}\n`;
|
||||
rli.setPrompt(multiline.prompt);
|
||||
rli.prompt(true);
|
||||
repl.setPrompt(multiline.prompt);
|
||||
repl.prompt(true);
|
||||
} else {
|
||||
rli.setPrompt(origPrompt);
|
||||
repl.setPrompt(origPrompt);
|
||||
nodeLineListener(cmd);
|
||||
}
|
||||
});
|
||||
|
@ -149,28 +149,28 @@
|
|||
// allow arbitrarily switching between modes any time before multiple lines are entered
|
||||
if (!multiline.buffer.match(/\n/)) {
|
||||
multiline.enabled = !multiline.enabled;
|
||||
rli.setPrompt(origPrompt);
|
||||
rli.prompt(true);
|
||||
repl.setPrompt(origPrompt);
|
||||
repl.prompt(true);
|
||||
return;
|
||||
}
|
||||
// no-op unless the current line is empty
|
||||
if ((rli.line != null) && !rli.line.match(/^\s*$/)) {
|
||||
if ((repl.line != null) && !repl.line.match(/^\s*$/)) {
|
||||
return;
|
||||
}
|
||||
// eval, print, loop
|
||||
multiline.enabled = !multiline.enabled;
|
||||
rli.line = '';
|
||||
rli.cursor = 0;
|
||||
rli.output.cursorTo(0);
|
||||
rli.output.clearLine(1);
|
||||
repl.line = '';
|
||||
repl.cursor = 0;
|
||||
repl.output.cursorTo(0);
|
||||
repl.output.clearLine(1);
|
||||
// XXX: multiline hack
|
||||
multiline.buffer = multiline.buffer.replace(/\n/g, '\uFF00');
|
||||
rli.emit('line', multiline.buffer);
|
||||
repl.emit('line', multiline.buffer);
|
||||
multiline.buffer = '';
|
||||
} else {
|
||||
multiline.enabled = !multiline.enabled;
|
||||
rli.setPrompt(multiline.initialPrompt);
|
||||
rli.prompt(true);
|
||||
repl.setPrompt(multiline.initialPrompt);
|
||||
repl.prompt(true);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -189,20 +189,20 @@
|
|||
fs.readSync(readFd, buffer, 0, size, stat.size - size);
|
||||
fs.closeSync(readFd);
|
||||
// Set the history on the interpreter
|
||||
repl.rli.history = buffer.toString().split('\n').reverse();
|
||||
repl.history = buffer.toString().split('\n').reverse();
|
||||
if (stat.size > maxSize) {
|
||||
// If the history file was truncated we should pop off a potential partial line
|
||||
repl.rli.history.pop();
|
||||
repl.history.pop();
|
||||
}
|
||||
if (repl.rli.history[0] === '') {
|
||||
if (repl.history[0] === '') {
|
||||
// Shift off the final blank newline
|
||||
repl.rli.history.shift();
|
||||
repl.history.shift();
|
||||
}
|
||||
repl.rli.historyIndex = -1;
|
||||
lastLine = repl.rli.history[0];
|
||||
repl.historyIndex = -1;
|
||||
lastLine = repl.history[0];
|
||||
} catch (error) {}
|
||||
fd = fs.openSync(filename, 'a');
|
||||
repl.rli.addListener('line', function(code) {
|
||||
repl.addListener('line', function(code) {
|
||||
if (code && code.length && code !== '.history' && code !== '.exit' && lastLine !== code) {
|
||||
// Save the latest command in the file
|
||||
fs.writeSync(fd, `${code}\n`);
|
||||
|
@ -220,7 +220,7 @@
|
|||
return repl.commands[getCommandId(repl, 'history')] = {
|
||||
help: 'Show command history',
|
||||
action: function() {
|
||||
repl.outputStream.write(`${repl.rli.history.slice(0).reverse().join('\n')}\n`);
|
||||
repl.outputStream.write(`${repl.history.slice(0).reverse().join('\n')}\n`);
|
||||
return repl.displayPrompt();
|
||||
}
|
||||
};
|
||||
|
@ -283,7 +283,7 @@
|
|||
runInContext(opts.prelude, repl.context, 'prelude');
|
||||
}
|
||||
repl.on('exit', function() {
|
||||
if (!repl.rli.closed) {
|
||||
if (!repl.closed) {
|
||||
return repl.outputStream.write('\n');
|
||||
}
|
||||
});
|
||||
|
|
2207
package-lock.json
generated
2207
package-lock.json
generated
File diff suppressed because it is too large
Load diff
14
package.json
14
package.json
|
@ -39,16 +39,16 @@
|
|||
"url": "git://github.com/jashkenas/coffeescript.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.0.0",
|
||||
"@babel/preset-env": "^7.0.0",
|
||||
"babel-preset-minify": "^0.4.3",
|
||||
"codemirror": "^5.39.2",
|
||||
"@babel/core": "^7.4.0",
|
||||
"@babel/preset-env": "^7.4.2",
|
||||
"babel-preset-minify": "^0.5.0",
|
||||
"codemirror": "^5.45.0",
|
||||
"docco": "~0.8.0",
|
||||
"highlight.js": "~9.12.0",
|
||||
"jison": ">=0.4.18",
|
||||
"highlight.js": "~9.15.6",
|
||||
"jison": "^0.4.18",
|
||||
"markdown-it": "~8.4.2",
|
||||
"underscore": "~1.9.1",
|
||||
"webpack": "~4.17.2"
|
||||
"webpack": "~4.29.6"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,20 @@ sources = {}
|
|||
# Also save source maps if generated, in form of `(source)`: [`(source map)`].
|
||||
sourceMaps = {}
|
||||
|
||||
# This is exported to enable an external module to implement caching of
|
||||
# compilation results. When the compiled js source is loaded from cache, the
|
||||
# original coffee code should be added with this method in order to enable the
|
||||
# Error.prepareStackTrace below to correctly adjust the stack trace for the
|
||||
# corresponding file (the source map will be generated on demand).
|
||||
exports.registerCompiled = registerCompiled = (filename, source, sourcemap) ->
|
||||
|
||||
sources[filename] ?= []
|
||||
sources[filename].push source
|
||||
|
||||
if sourcemap?
|
||||
sourceMaps[filename] ?= []
|
||||
sourceMaps[filename].push sourcemap
|
||||
|
||||
# Compile CoffeeScript code to JavaScript, using the Coffee/Jison compiler.
|
||||
#
|
||||
# If `options.sourceMap` is specified, then `options.filename` must also be
|
||||
|
@ -75,8 +89,6 @@ exports.compile = compile = withPrettyErrors (code, options = {}) ->
|
|||
|
||||
checkShebangLine filename, code
|
||||
|
||||
sources[filename] ?= []
|
||||
sources[filename].push code
|
||||
map = new SourceMap if generateSourceMap
|
||||
|
||||
tokens = lexer.tokenize code, options
|
||||
|
@ -141,8 +153,6 @@ exports.compile = compile = withPrettyErrors (code, options = {}) ->
|
|||
|
||||
if generateSourceMap
|
||||
v3SourceMap = map.generate options, code
|
||||
sourceMaps[filename] ?= []
|
||||
sourceMaps[filename].push map
|
||||
|
||||
if options.transpile
|
||||
if typeof options.transpile isnt 'object'
|
||||
|
@ -173,6 +183,8 @@ exports.compile = compile = withPrettyErrors (code, options = {}) ->
|
|||
sourceURL = "//# sourceURL=#{options.filename ? 'coffeescript'}"
|
||||
js = "#{js}\n#{sourceMapDataURI}\n#{sourceURL}"
|
||||
|
||||
registerCompiled filename, code, map
|
||||
|
||||
if options.sourceMap
|
||||
{
|
||||
js
|
||||
|
|
|
@ -269,6 +269,7 @@ grammar =
|
|||
o 'Super'
|
||||
o 'This'
|
||||
o 'SUPER Arguments', -> new SuperCall LOC(1)(new Super), $2, no, $1
|
||||
o 'DYNAMIC_IMPORT Arguments', -> new DynamicImportCall LOC(1)(new DynamicImport), $2
|
||||
o 'SimpleObjAssignable Arguments', -> new Call (new Value $1), $2
|
||||
o 'ObjSpreadExpr Arguments', -> new Call $1, $2
|
||||
]
|
||||
|
@ -522,6 +523,7 @@ grammar =
|
|||
o 'Value OptFuncExist String', -> new TaggedTemplateCall $1, $3, $2
|
||||
o 'Value OptFuncExist Arguments', -> new Call $1, $3, $2
|
||||
o 'SUPER OptFuncExist Arguments', -> new SuperCall LOC(1)(new Super), $3, $2, $1
|
||||
o 'DYNAMIC_IMPORT Arguments', -> new DynamicImportCall LOC(1)(new DynamicImport), $2
|
||||
]
|
||||
|
||||
# An optional existence check on a function.
|
||||
|
@ -932,7 +934,7 @@ operators = [
|
|||
['right', 'YIELD']
|
||||
['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS']
|
||||
['right', 'FORIN', 'FOROF', 'FORFROM', 'BY', 'WHEN']
|
||||
['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT']
|
||||
['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT', 'DYNAMIC_IMPORT']
|
||||
['left', 'POST_IF']
|
||||
]
|
||||
|
||||
|
|
|
@ -110,8 +110,8 @@ if require.extensions
|
|||
Use CoffeeScript.register() or require the coffeescript/register module to require #{ext} files.
|
||||
"""
|
||||
|
||||
CoffeeScript._compileFile = (filename, options = {}) ->
|
||||
raw = fs.readFileSync filename, 'utf8'
|
||||
CoffeeScript._compileRawFileContent = (raw, filename, options = {}) ->
|
||||
|
||||
# Strip the Unicode byte order mark, if this file begins with one.
|
||||
stripped = if raw.charCodeAt(0) is 0xFEFF then raw.substring 1 else raw
|
||||
|
||||
|
@ -131,4 +131,9 @@ CoffeeScript._compileFile = (filename, options = {}) ->
|
|||
|
||||
answer
|
||||
|
||||
CoffeeScript._compileFile = (filename, options = {}) ->
|
||||
raw = fs.readFileSync filename, 'utf8'
|
||||
|
||||
CoffeeScript._compileRawFileContent raw, filename, options
|
||||
|
||||
module.exports = CoffeeScript
|
||||
|
|
|
@ -689,6 +689,9 @@ exports.Lexer = class Lexer
|
|||
@error message, origin[2] if message
|
||||
return value.length if skipToken
|
||||
|
||||
if value is '(' and prev?[0] is 'IMPORT'
|
||||
prev[0] = 'DYNAMIC_IMPORT'
|
||||
|
||||
if value is '{' and @seenImport
|
||||
@importSpecifierList = yes
|
||||
else if @importSpecifierList and value is '}'
|
||||
|
@ -1313,7 +1316,7 @@ BOOL = ['TRUE', 'FALSE']
|
|||
# Tokens which could legitimately be invoked or indexed. An opening
|
||||
# parentheses or bracket following these tokens will be recorded as the start
|
||||
# of a function invocation or indexing operation.
|
||||
CALLABLE = ['IDENTIFIER', 'PROPERTY', ')', ']', '?', '@', 'THIS', 'SUPER']
|
||||
CALLABLE = ['IDENTIFIER', 'PROPERTY', ')', ']', '?', '@', 'THIS', 'SUPER', 'DYNAMIC_IMPORT']
|
||||
INDEXABLE = CALLABLE.concat [
|
||||
'NUMBER', 'INFINITY', 'NAN', 'STRING', 'STRING_END', 'REGEX', 'REGEX_END'
|
||||
'BOOL', 'NULL', 'UNDEFINED', '}', '::'
|
||||
|
|
|
@ -208,7 +208,7 @@ exports.Base = class Base
|
|||
|
||||
# Occasionally it may be useful to make an expression behave as if it was 'hoisted', whereby the
|
||||
# result of the expression is available before its location in the source, but the expression's
|
||||
# variable scope corresponds the source position. This is used extensively to deal with executable
|
||||
# variable scope corresponds to the source position. This is used extensively to deal with executable
|
||||
# class bodies in classes.
|
||||
#
|
||||
# Calling this method mutates the node, proxying the `compileNode` and `compileToFragments`
|
||||
|
@ -2337,8 +2337,9 @@ exports.Arr = class Arr extends Base
|
|||
compileNode: (o) ->
|
||||
return [@makeCode '[]'] unless @objects.length
|
||||
o.indent += TAB
|
||||
fragmentIsElision = (fragment) -> fragmentsToText(fragment).trim() is ','
|
||||
# Detect if `Elisions` at the beginning of the array are processed (e.g. [, , , a]).
|
||||
fragmentIsElision = ([ fragment ]) ->
|
||||
fragment.type is 'Elision' and fragment.code.trim() is ','
|
||||
# Detect if `Elision`s at the beginning of the array are processed (e.g. [, , , a]).
|
||||
passedElision = no
|
||||
|
||||
answer = []
|
||||
|
@ -2376,7 +2377,7 @@ exports.Arr = class Arr extends Base
|
|||
for fragment, fragmentIndex in answer
|
||||
if fragment.isHereComment
|
||||
fragment.code = "#{multident(fragment.code, o.indent, no)}\n#{o.indent}"
|
||||
else if fragment.code is ', ' and not fragment?.isElision
|
||||
else if fragment.code is ', ' and not fragment?.isElision and fragment.type isnt 'StringLiteral'
|
||||
fragment.code = ",\n#{o.indent}"
|
||||
answer.unshift @makeCode "[\n#{o.indent}"
|
||||
answer.push @makeCode "\n#{@tab}]"
|
||||
|
@ -2701,7 +2702,7 @@ exports.ExecutableClassBody = class ExecutableClassBody extends Base
|
|||
@body.traverseChildren false, (node) =>
|
||||
if node instanceof ThisLiteral
|
||||
node.value = @name
|
||||
else if node instanceof Code and node.bound and node.isStatic
|
||||
else if node instanceof Code and node.bound and (node.isStatic or not node.name)
|
||||
node.context = @name
|
||||
|
||||
# Make class/prototype assignments for invalid ES properties
|
||||
|
@ -2940,6 +2941,16 @@ exports.ExportSpecifier = class ExportSpecifier extends ModuleSpecifier
|
|||
local: originalAst
|
||||
exported: @alias?.ast(o) ? originalAst
|
||||
|
||||
exports.DynamicImport = class DynamicImport extends Base
|
||||
compileNode: ->
|
||||
[@makeCode 'import']
|
||||
|
||||
exports.DynamicImportCall = class DynamicImportCall extends Call
|
||||
compileNode: (o) ->
|
||||
unless @args.length is 1
|
||||
@error 'import() requires exactly one argument'
|
||||
super o
|
||||
|
||||
#### Assign
|
||||
|
||||
# The **Assign** is used to assign a local variable to value, or to set the
|
||||
|
@ -3528,7 +3539,7 @@ exports.Code = class Code extends Base
|
|||
# (e.g. `ref`), shift those into the parent scope since we can’t put a
|
||||
# `var` line inside a function parameter list.
|
||||
scopeVariablesCount = o.scope.variables.length
|
||||
signature.push param.compileToFragments(o)...
|
||||
signature.push param.compileToFragments(o, LEVEL_PAREN)...
|
||||
if scopeVariablesCount isnt o.scope.variables.length
|
||||
generatedVariables = o.scope.variables.splice scopeVariablesCount
|
||||
o.scope.parent.variables.push generatedVariables...
|
||||
|
@ -5107,7 +5118,7 @@ isLocationDataEndGreater = (a, b) ->
|
|||
# encompasses the location data of both nodes. So the new `first_line` value
|
||||
# will be the earlier of the two nodes’ `first_line` values, the new
|
||||
# `last_column` the later of the two nodes’ `last_column` values, etc.
|
||||
#
|
||||
#
|
||||
# If you only want to extend the first node’s location data with the start or
|
||||
# end location data of the second node, pass the `justLeading` or `justEnding`
|
||||
# options. So e.g. if `first`’s range is [4, 5] and `second`’s range is [1, 10],
|
||||
|
@ -5164,7 +5175,7 @@ exports.mergeLocationData = mergeLocationData = (locationDataA, locationDataB, {
|
|||
# location data object that encompasses the location data of both nodes. So the
|
||||
# new `start` value will be the earlier of the two nodes’ `start` values, the
|
||||
# new `end` value will be the later of the two nodes’ `end` values, etc.
|
||||
#
|
||||
#
|
||||
# If you only want to extend the first node’s location data with the start or
|
||||
# end location data of the second node, pass the `justLeading` or `justEnding`
|
||||
# options. So e.g. if `first`’s range is [4, 5] and `second`’s range is [1, 10],
|
||||
|
|
|
@ -75,7 +75,7 @@ runInContext = (js, context, filename) ->
|
|||
vm.runInContext js, context, filename
|
||||
|
||||
addMultilineHandler = (repl) ->
|
||||
{rli, inputStream, outputStream} = repl
|
||||
{inputStream, outputStream} = repl
|
||||
# Node 0.11.12 changed API, prompt is now _prompt.
|
||||
origPrompt = repl._prompt ? repl.prompt
|
||||
|
||||
|
@ -86,15 +86,15 @@ addMultilineHandler = (repl) ->
|
|||
buffer: ''
|
||||
|
||||
# Proxy node's line listener
|
||||
nodeLineListener = rli.listeners('line')[0]
|
||||
rli.removeListener 'line', nodeLineListener
|
||||
rli.on 'line', (cmd) ->
|
||||
nodeLineListener = repl.listeners('line')[0]
|
||||
repl.removeListener 'line', nodeLineListener
|
||||
repl.on 'line', (cmd) ->
|
||||
if multiline.enabled
|
||||
multiline.buffer += "#{cmd}\n"
|
||||
rli.setPrompt multiline.prompt
|
||||
rli.prompt true
|
||||
repl.setPrompt multiline.prompt
|
||||
repl.prompt true
|
||||
else
|
||||
rli.setPrompt origPrompt
|
||||
repl.setPrompt origPrompt
|
||||
nodeLineListener cmd
|
||||
return
|
||||
|
||||
|
@ -105,25 +105,25 @@ addMultilineHandler = (repl) ->
|
|||
# allow arbitrarily switching between modes any time before multiple lines are entered
|
||||
unless multiline.buffer.match /\n/
|
||||
multiline.enabled = not multiline.enabled
|
||||
rli.setPrompt origPrompt
|
||||
rli.prompt true
|
||||
repl.setPrompt origPrompt
|
||||
repl.prompt true
|
||||
return
|
||||
# no-op unless the current line is empty
|
||||
return if rli.line? and not rli.line.match /^\s*$/
|
||||
return if repl.line? and not repl.line.match /^\s*$/
|
||||
# eval, print, loop
|
||||
multiline.enabled = not multiline.enabled
|
||||
rli.line = ''
|
||||
rli.cursor = 0
|
||||
rli.output.cursorTo 0
|
||||
rli.output.clearLine 1
|
||||
repl.line = ''
|
||||
repl.cursor = 0
|
||||
repl.output.cursorTo 0
|
||||
repl.output.clearLine 1
|
||||
# XXX: multiline hack
|
||||
multiline.buffer = multiline.buffer.replace /\n/g, '\uFF00'
|
||||
rli.emit 'line', multiline.buffer
|
||||
repl.emit 'line', multiline.buffer
|
||||
multiline.buffer = ''
|
||||
else
|
||||
multiline.enabled = not multiline.enabled
|
||||
rli.setPrompt multiline.initialPrompt
|
||||
rli.prompt true
|
||||
repl.setPrompt multiline.initialPrompt
|
||||
repl.prompt true
|
||||
return
|
||||
|
||||
# Store and load command history from a file
|
||||
|
@ -139,17 +139,17 @@ addHistory = (repl, filename, maxSize) ->
|
|||
fs.readSync readFd, buffer, 0, size, stat.size - size
|
||||
fs.closeSync readFd
|
||||
# Set the history on the interpreter
|
||||
repl.rli.history = buffer.toString().split('\n').reverse()
|
||||
repl.history = buffer.toString().split('\n').reverse()
|
||||
# If the history file was truncated we should pop off a potential partial line
|
||||
repl.rli.history.pop() if stat.size > maxSize
|
||||
repl.history.pop() if stat.size > maxSize
|
||||
# Shift off the final blank newline
|
||||
repl.rli.history.shift() if repl.rli.history[0] is ''
|
||||
repl.rli.historyIndex = -1
|
||||
lastLine = repl.rli.history[0]
|
||||
repl.history.shift() if repl.history[0] is ''
|
||||
repl.historyIndex = -1
|
||||
lastLine = repl.history[0]
|
||||
|
||||
fd = fs.openSync filename, 'a'
|
||||
|
||||
repl.rli.addListener 'line', (code) ->
|
||||
repl.addListener 'line', (code) ->
|
||||
if code and code.length and code isnt '.history' and code isnt '.exit' and lastLine isnt code
|
||||
# Save the latest command in the file
|
||||
fs.writeSync fd, "#{code}\n"
|
||||
|
@ -163,7 +163,7 @@ addHistory = (repl, filename, maxSize) ->
|
|||
repl.commands[getCommandId(repl, 'history')] =
|
||||
help: 'Show command history'
|
||||
action: ->
|
||||
repl.outputStream.write "#{repl.rli.history[..].reverse().join '\n'}\n"
|
||||
repl.outputStream.write "#{repl.history[..].reverse().join '\n'}\n"
|
||||
repl.displayPrompt()
|
||||
|
||||
getCommandId = (repl, commandName) ->
|
||||
|
@ -212,7 +212,7 @@ module.exports =
|
|||
opts = merge replDefaults, opts
|
||||
repl = nodeREPL.start opts
|
||||
runInContext opts.prelude, repl.context, 'prelude' if opts.prelude
|
||||
repl.on 'exit', -> repl.outputStream.write '\n' if not repl.rli.closed
|
||||
repl.on 'exit', -> repl.outputStream.write '\n' if not repl.closed
|
||||
addMultilineHandler repl
|
||||
addHistory repl, opts.historyFile, opts.historyMaxInputSize if opts.historyFile
|
||||
# Adapt help inherited from the node REPL
|
||||
|
|
|
@ -115,6 +115,12 @@ test "array elisions nested destructuring", ->
|
|||
deepEqual d, {x:2}
|
||||
arrayEq w, [1,2,4]
|
||||
|
||||
test "#5112: array elisions not detected inside strings", ->
|
||||
arr = [
|
||||
str: ", #{3}"
|
||||
]
|
||||
eq arr[0].str, ', 3'
|
||||
|
||||
# Splats in Array Literals
|
||||
|
||||
test "array splat expansions with assignments", ->
|
||||
|
|
|
@ -1917,3 +1917,16 @@ test "#4609: Support new.target", ->
|
|||
|
||||
new Foo()
|
||||
eq newTarget, yes
|
||||
|
||||
test "#5085: Bug: @ reference to class not maintained in do block", ->
|
||||
thisFoo = 'initial foo'
|
||||
thisBar = 'initial bar'
|
||||
fn = (o) -> o.bar()
|
||||
|
||||
class A
|
||||
@foo = 'foo assigned in class'
|
||||
do => thisFoo = @foo
|
||||
fn bar: => thisBar = @foo
|
||||
|
||||
eq thisFoo, 'foo assigned in class'
|
||||
eq thisBar, 'foo assigned in class'
|
||||
|
|
|
@ -1946,3 +1946,29 @@ test "`new.target` cannot be assigned", ->
|
|||
new.target = b
|
||||
^
|
||||
'''
|
||||
|
||||
test "#4834: dynamic import requires exactly one argument", ->
|
||||
assertErrorFormat '''
|
||||
import()
|
||||
''', '''
|
||||
[stdin]:1:1: error: import() requires exactly one argument
|
||||
import()
|
||||
^^^^^^^^
|
||||
'''
|
||||
|
||||
assertErrorFormat '''
|
||||
import('x', {})
|
||||
''', '''
|
||||
[stdin]:1:1: error: import() requires exactly one argument
|
||||
import('x', {})
|
||||
^^^^^^^^^^^^^^^
|
||||
'''
|
||||
|
||||
test "#4834: dynamic import requires explicit call parentheses", ->
|
||||
assertErrorFormat '''
|
||||
promise = import 'foo'
|
||||
''', '''
|
||||
[stdin]:1:23: error: unexpected end of input
|
||||
promise = import 'foo'
|
||||
^
|
||||
'''
|
||||
|
|
|
@ -493,3 +493,7 @@ test "#4657: destructured array parameters", ->
|
|||
result = f [1, 2, 3, 4]
|
||||
arrayEq result.a, [1, 2, 3]
|
||||
eq result.b, 4
|
||||
|
||||
test "#5128: default parameters of function in binary operation", ->
|
||||
foo = yes or (a, b = {}) -> null
|
||||
eq foo, yes
|
||||
|
|
|
@ -920,3 +920,24 @@ test "#4874: backslash `export`", ->
|
|||
min
|
||||
} from 'underscore';
|
||||
"""
|
||||
|
||||
test "#4834: dynamic import", ->
|
||||
eqJS """
|
||||
import('module').then ->
|
||||
""",
|
||||
"""
|
||||
import('module').then(function() {});
|
||||
"""
|
||||
|
||||
eqJS """
|
||||
foo = ->
|
||||
bar = await import('bar')
|
||||
""",
|
||||
"""
|
||||
var foo;
|
||||
|
||||
foo = async function() {
|
||||
var bar;
|
||||
return bar = (await import('bar'));
|
||||
};
|
||||
"""
|
||||
|
|
|
@ -418,3 +418,13 @@ test "#4673: complex destructured object spread variables", ->
|
|||
g = ({@y...}) ->
|
||||
eq @y.b, 1
|
||||
g b: 1
|
||||
|
||||
test "#4834: dynamic import can technically be object spread", ->
|
||||
eqJS """
|
||||
x = {...import('module')}
|
||||
""",
|
||||
"""
|
||||
var x;
|
||||
|
||||
x = {...import('module')};
|
||||
"""
|
||||
|
|
|
@ -45,7 +45,7 @@ ctrlV = { ctrl: true, name: 'v'}
|
|||
|
||||
|
||||
testRepl 'reads history file', (input, output, repl) ->
|
||||
input.emitLine repl.rli.history[0]
|
||||
input.emitLine repl.history[0]
|
||||
eq '3', output.lastWrite()
|
||||
|
||||
testRepl "starts with coffee prompt", (input, output) ->
|
||||
|
|
Loading…
Reference in a new issue