Comparing version 0.4.5 to 0.4.6
# buble changelog | ||
## 0.4.6 | ||
* Report locations of parse/compile errors ([#4](https://gitlab.com/Rich-Harris/buble/issues/4)) | ||
## 0.4.5 | ||
@@ -4,0 +8,0 @@ |
import { parse } from 'acorn'; | ||
import MagicString from 'magic-string'; | ||
import { walk } from 'estree-walker'; | ||
import 'estree-walker'; | ||
@@ -46,12 +46,2 @@ var statementsWithBlocks = { | ||
Node.prototype.findChildren = function findChildren ( type ) { | ||
var children = []; | ||
walk( this, { | ||
enter: function ( node ) { | ||
if ( node.type === type ) children.push( node ); | ||
} | ||
}); | ||
return children; | ||
}; | ||
Node.prototype.findLexicalBoundary = function findLexicalBoundary () { | ||
@@ -62,3 +52,3 @@ return this.parent.findLexicalBoundary(); | ||
Node.prototype.findNearest = function findNearest ( type ) { | ||
if ( typeof type === 'string' ) type = new RegExp( "^" + type + "$" ); | ||
if ( typeof type === 'string' ) type = new RegExp( ("^" + type + "$") ); | ||
if ( type.test( this.type ) ) return this; | ||
@@ -84,3 +74,3 @@ return this.parent.findNearest( type ); | ||
if ( Array.isArray( value ) ) { | ||
value.forEach( function ( node ) { return node.initialise(); } ); | ||
value.forEach( function ( node ) { return node && node.initialise(); } ); | ||
} else if ( value && typeof value === 'object' ) { | ||
@@ -103,3 +93,3 @@ value.initialise(); | ||
if ( Array.isArray( value ) ) { | ||
value.forEach( function ( node ) { return node.transpile( code ); } ); | ||
value.forEach( function ( node ) { return node && node.transpile( code ); } ); | ||
} else if ( value && typeof value === 'object' ) { | ||
@@ -111,2 +101,78 @@ value.transpile( code ); | ||
function locate ( source, index ) { | ||
var lines = source.split( '\n' ); | ||
var len = lines.length; | ||
var lineStart = 0; | ||
var i; | ||
for ( i = 0; i < len; i += 1 ) { | ||
var line = lines[i]; | ||
var lineEnd = lineStart + line.length + 1; // +1 for newline | ||
if ( lineEnd > index ) { | ||
return { line: i + 1, column: index - lineStart, char: i }; | ||
} | ||
lineStart = lineEnd; | ||
} | ||
throw new Error( 'Could not determine location of character' ); | ||
} | ||
function pad ( num, len ) { | ||
var result = String( num ); | ||
return result + repeat( ' ', len - result.length ); | ||
} | ||
function repeat ( str, times ) { | ||
var result = ''; | ||
while ( times-- ) result += str; | ||
return result; | ||
} | ||
function getSnippet ( source, loc, length ) { | ||
if ( length === void 0 ) length = 1; | ||
var first = Math.max( loc.line - 5, 0 ); | ||
var last = loc.line; | ||
var numDigits = String( last ).length; | ||
var lines = source.split( '\n' ).slice( first, last ); | ||
var lastLine = lines[ lines.length - 1 ]; | ||
var offset = lastLine.slice( 0, loc.column ).replace( /\t/g, ' ' ).length; | ||
var snippet = lines | ||
.map( function ( line, i ) { return ("" + (pad( i + first + 1, numDigits )) + " : " + (line.replace( /\t/g, ' '))); } ) | ||
.join( '\n' ); | ||
snippet += '\n' + repeat( ' ', numDigits + 3 + offset ) + repeat( '^', length ); | ||
return snippet; | ||
} | ||
var CompileError = (function (Error) { | ||
function CompileError ( node, message ) { | ||
Error.call(this); | ||
var source = node.program.magicString.original; | ||
var loc = locate( source, node.start ); | ||
this.name = 'CompileError'; | ||
this.message = message + " (" + (loc.line) + ":" + (loc.column) + ")"; | ||
this.stack = new Error().stack.replace( new RegExp( (".+new " + (this.name) + ".+\\n"), 'm' ), '' ); | ||
this.loc = loc; | ||
this.snippet = getSnippet( source, loc, node.end - node.start ); | ||
} | ||
CompileError.prototype = Object.create( Error && Error.prototype ); | ||
CompileError.prototype.constructor = CompileError; | ||
return CompileError; | ||
}(Error)); | ||
var AssignmentExpression = (function (Node) { | ||
@@ -124,4 +190,3 @@ function AssignmentExpression () { | ||
if ( declaration && declaration.kind === 'const' ) { | ||
// TODO location etc | ||
throw new Error( "" + (this.left.name) + " is read-only" ); | ||
throw new CompileError( this.left, ("" + (this.left.name) + " is read-only") ); | ||
} | ||
@@ -210,5 +275,5 @@ } | ||
if ( nextMethod ) { | ||
code.insert( nextMethod.start, "\n\n" + indentation + "" ); | ||
code.insert( nextMethod.start, ("\n\n" + indentation) ); | ||
} else { | ||
code.insert( constructor.end, "\n\n" + indentation + "" ); | ||
code.insert( constructor.end, ("\n\n" + indentation) ); | ||
} | ||
@@ -218,4 +283,4 @@ } | ||
var fn = "function " + name + " () {" + ( superName ? | ||
"\n" + indentation + "" + indentStr + "" + superName + ".apply(this, arguments);\n" + indentation + "}" : | ||
"}" ) + ( inFunctionExpression ? '' : ';' ) + ( this.body.length ? "\n\n" + indentation + "" : '' ); | ||
("\n" + indentation + "" + indentStr + "" + superName + ".apply(this, arguments);\n" + indentation + "}") : | ||
("}") ) + ( inFunctionExpression ? '' : ';' ) + ( this.body.length ? ("\n\n" + indentation) : '' ); | ||
code.insert( this.start, fn ); | ||
@@ -228,5 +293,5 @@ } | ||
if ( constructor ) { | ||
code.insert( constructor.end, "\n\n" + indentation + "" + inheritanceBlock ); | ||
code.insert( constructor.end, "\n\n" + indentation + inheritanceBlock ); | ||
} else { | ||
code.insert( this.start, inheritanceBlock + "\n\n" + indentation + "" ); | ||
code.insert( this.start, inheritanceBlock + "\n\n" + indentation ); | ||
} | ||
@@ -237,3 +302,3 @@ } | ||
if ( method.kind === 'constructor' ) { | ||
code.overwrite( method.key.start, method.key.end, "function " + name + "" ); | ||
code.overwrite( method.key.start, method.key.end, ("function " + name) ); | ||
return; | ||
@@ -245,6 +310,6 @@ } | ||
var lhs = method.static ? | ||
"" + name + "." + (method.key.name) + "" : | ||
"" + name + ".prototype." + (method.key.name) + ""; | ||
("" + name + "." + (method.key.name)) : | ||
("" + name + ".prototype." + (method.key.name)); | ||
code.insert( method.start, "" + lhs + " = function " ); | ||
code.insert( method.start, ("" + lhs + " = function ") ); | ||
code.insert( method.end, ';' ); | ||
@@ -276,9 +341,2 @@ | ||
var isExcluded = {}; | ||
node.findChildren( 'TemplateLiteral' ).forEach( function ( node ) { | ||
for ( var i = node.start; i < node.end; i += 1 ) { | ||
isExcluded[i] = true; | ||
} | ||
}); | ||
if ( code.original.slice( start - indentStr.length, start ) === indentStr ) { | ||
@@ -291,3 +349,3 @@ code.remove( start - indentStr.length, start ); | ||
while ( match = pattern.exec( slice ) ) { | ||
if ( !isExcluded[ match.index ] ) code.remove( start + match.index, start + match.index + indentStr.length ); | ||
if ( !node.program.indentExclusions[ match.index ] ) code.remove( start + match.index, start + match.index + indentStr.length ); | ||
} | ||
@@ -318,8 +376,8 @@ } | ||
var intro = this.superClass ? | ||
"var " + (this.name) + " = (function (" + superName + ") {\n" + indentation + "" + indentStr + "" : | ||
"var " + (this.name) + " = "; | ||
("var " + (this.name) + " = (function (" + superName + ") {\n" + indentation + "" + indentStr) : | ||
("var " + (this.name) + " = "); | ||
var outro = this.superClass ? | ||
"\n\n" + indentation + "" + indentStr + "return " + (this.name) + ";\n" + indentation + "}(" + superName + "));" : | ||
""; | ||
("\n\n" + indentation + "" + indentStr + "return " + (this.name) + ";\n" + indentation + "}(" + superName + "));") : | ||
(""); | ||
@@ -359,7 +417,7 @@ code.remove( this.start, this.body.start ); | ||
code.overwrite( this.start, this.body.start, "(function (" + (superName || '') + ") {\n" + indentation + "" + indentStr + "" ); | ||
code.overwrite( this.start, this.body.start, ("(function (" + (superName || '') + ") {\n" + indentation + "" + indentStr) ); | ||
this.body.transpile( code, true ); | ||
code.insert( this.end, "\n\n" + indentation + "" + indentStr + "return " + (this.name) + ";\n" + indentation + "}(" + (superName || '') + "))" ); | ||
code.insert( this.end, ("\n\n" + indentation + "" + indentStr + "return " + (this.name) + ";\n" + indentation + "}(" + (superName || '') + "))") ); | ||
}; | ||
@@ -382,5 +440,5 @@ | ||
if ( this.declaration.type === 'ClassDeclaration' ) { | ||
code.insert( this.end, "\n\n" + (this.getIndentation()) + "" ); | ||
code.insert( this.end, ("\n\n" + (this.getIndentation())) ); | ||
code.move( this.start, this.declaration.start, this.end ); | ||
code.insert( this.end, "" + (this.declaration.id.name) + ";" ); | ||
code.insert( this.end, ("" + (this.declaration.id.name) + ";") ); | ||
} | ||
@@ -476,4 +534,4 @@ }; | ||
var before = "var forLoop = function ( " + (names$1.join( ', ' )) + " ) " + ( this.body.synthetic ? "{\n" + indentation + "" + (code.getIndentString()) + "" : '' ); | ||
var after = ( this.body.synthetic ? "\n" + indentation + "}" : '' ) + ";\n\n" + indentation + ""; | ||
var before = "var forLoop = function ( " + (names$1.join( ', ' )) + " ) " + ( this.body.synthetic ? ("{\n" + indentation + "" + (code.getIndentString())) : '' ); | ||
var after = ( this.body.synthetic ? ("\n" + indentation + "}") : '' ) + ";\n\n" + indentation; | ||
@@ -484,3 +542,3 @@ code.insert( this.start, before ); | ||
code.insert( this.end, "forLoop( " + (names$1.join( ', ' )) + " );" ); | ||
code.insert( this.end, ("forLoop( " + (names$1.join( ', ' )) + " );") ); | ||
} | ||
@@ -658,7 +716,2 @@ | ||
function unsupported ( node, description ) { | ||
// TODO show offending snippet | ||
throw new Error( "" + description + ". See TK for more information" ); | ||
} | ||
var Property = (function (Node) { | ||
@@ -674,3 +727,3 @@ function Property () { | ||
if ( this.computed ) { | ||
unsupported( this, 'Computed properties are not supported' ); | ||
throw new CompileError( this.key, 'Computed properties are not supported' ); | ||
} | ||
@@ -684,5 +737,5 @@ | ||
if ( this.shorthand ) { | ||
code.insert( this.start, "" + (this.key.name) + ": " ); | ||
code.insert( this.start, ("" + (this.key.name) + ": ") ); | ||
} else if ( this.method ) { | ||
code.insert( this.key.end, ": function" ); | ||
code.insert( this.key.end, (": function") ); | ||
} | ||
@@ -707,14 +760,13 @@ } | ||
this.method = this.findNearest( 'MethodDefinition' ); | ||
this.superClassName = this.findNearest( 'ClassBody' ).parent.superClass.name; | ||
if ( !this.method ) throw new CompileError( this, 'use of super outside class method' ); | ||
if ( !this.method ) { | ||
throw new Error( 'super outside method' ); // TODO location etc | ||
} | ||
var parentClass = this.findNearest( 'ClassBody' ).parent; | ||
this.superClassName = parentClass.superClass && parentClass.superClass.name; | ||
this.isCalled = this.parent.type === 'CallExpression'; | ||
if ( !this.superClassName ) throw new CompileError( this, 'super used in base class' ); | ||
if ( this.method.kind === 'constructor' ) { | ||
if ( !this.isCalled ) throw new Error( 'super cannot be referred to in constructor outside a call expression' ); // TODO this is cryptic | ||
} else { | ||
if ( this.isCalled ) throw new Error( 'super() not allowed outside class constructor' ); | ||
this.isCalled = this.parent.type === 'CallExpression' && this === this.parent.callee; | ||
if ( this.method.kind !== 'constructor' && this.isCalled ) { | ||
throw new CompileError( this, 'super() not allowed outside class constructor' ); | ||
} | ||
@@ -725,3 +777,3 @@ | ||
if ( !this.isCalled && !this.isMember ) { | ||
throw new Error( 'Unexpected use of `super` (expected `super(...)` or `super.*`)' ); | ||
throw new CompileError( this, 'Unexpected use of `super` (expected `super(...)` or `super.*`)' ); | ||
} | ||
@@ -731,3 +783,3 @@ }; | ||
Super.prototype.transpile = function transpile ( code ) { | ||
var expression = this.isCalled ? this.superClassName : "" + (this.superClassName) + ".prototype"; | ||
var expression = this.isCalled ? this.superClassName : ("" + (this.superClassName) + ".prototype"); | ||
code.overwrite( this.start, this.end, expression, true ); | ||
@@ -741,5 +793,5 @@ | ||
if ( callExpression.arguments.length ) { | ||
code.insert( callExpression.arguments[0].start, "this, " ); | ||
code.insert( callExpression.arguments[0].start, ("this, ") ); | ||
} else { | ||
code.insert( callExpression.end - 1, "this" ); | ||
code.insert( callExpression.end - 1, ("this") ); | ||
} | ||
@@ -761,3 +813,3 @@ } | ||
TaggedTemplateExpression.prototype.initialise = function initialise () { | ||
unsupported( this, 'Tagged template expressions are not supported' ); | ||
throw new CompileError( this.tag, 'Tagged template expressions are not supported' ); | ||
}; | ||
@@ -768,2 +820,17 @@ | ||
var TemplateElement = (function (Node) { | ||
function TemplateElement () { | ||
Node.apply(this, arguments); | ||
} | ||
TemplateElement.prototype = Object.create( Node && Node.prototype ); | ||
TemplateElement.prototype.constructor = TemplateElement; | ||
TemplateElement.prototype.initialise = function initialise () { | ||
this.program.templateElements.push( this ); | ||
}; | ||
return TemplateElement; | ||
}(Node)); | ||
var TemplateLiteral = (function (Node) { | ||
@@ -795,3 +862,3 @@ function TemplateLiteral () { | ||
var stringified = JSON.stringify( node.value.cooked ); | ||
var replacement = ( closeParenthesis ? ')' : '' ) + ( ( node.tail && !node.value.cooked.length && i !== 0 ) ? '' : "" + (i ? ' + ' : '') + "" + stringified + "" ); | ||
var replacement = ( closeParenthesis ? ')' : '' ) + ( ( node.tail && !node.value.cooked.length && i !== 0 ) ? '' : ("" + (i ? ' + ' : '') + "" + stringified) ); | ||
code.overwrite( lastIndex, node.end, replacement ); | ||
@@ -859,4 +926,3 @@ | ||
if ( declaration && declaration.kind === 'const' ) { | ||
// TODO location etc | ||
throw new Error( "" + (this.argument.name) + " is read-only" ); | ||
throw new CompileError( this, ("" + (this.argument.name) + " is read-only") ); | ||
} | ||
@@ -911,4 +977,4 @@ } | ||
this.id[ this.isObjectPattern ? 'properties' : 'elements' ].forEach( function ( node ) { | ||
if ( /Pattern/.test( this$1.isObjectPattern ? node.value.type : node.type ) ) { | ||
unsupported( this$1, 'Compound destructuring is not supported' ); | ||
if ( node && /Pattern/.test( this$1.isObjectPattern ? node.value.type : node.type ) ) { | ||
throw new CompileError( node.value, 'Compound destructuring is not supported' ); | ||
} | ||
@@ -923,2 +989,4 @@ }); | ||
VariableDeclarator.prototype.transpile = function transpile ( code ) { | ||
var this$1 = this; | ||
if ( this.id.type !== 'Identifier' ) { | ||
@@ -929,5 +997,5 @@ var simple = this.init.type === 'Identifier'; | ||
if ( !simple ) { | ||
code.insert( this.start, "" + name + " = " ); | ||
code.insert( this.start, ("" + name + " = ") ); | ||
code.move( this.init.start, this.init.end, this.start ); | ||
code.insert( this.start, ", " ); | ||
code.insert( this.start, (", ") ); | ||
} else { | ||
@@ -941,11 +1009,17 @@ code.remove( this.init.start, this.init.end ); | ||
props.forEach( this.isObjectPattern ? | ||
function ( property ) { | ||
code.overwrite( property.start, property.end, "" + (property.value.name) + " = " + name + "." + (property.key.name) + "" ); | ||
} : | ||
function ( property, i ) { | ||
code.overwrite( property.start, property.end, "" + (property.name) + " = " + name + "[" + i + "]" ); | ||
}); | ||
var lastIndex = this.start; | ||
var first = true; | ||
code.remove( props[ props.length - 1 ].end, this.init.start ); | ||
props.forEach( function ( property, i ) { | ||
if ( property ) { | ||
var lhs = this$1.isObjectPattern ? property.value.name : property.name; | ||
var rhs = this$1.isObjectPattern ? ("" + name + "." + (property.key.name)) : ("" + name + "[" + i + "]"); | ||
code.overwrite( lastIndex, property.end, ("" + (first ? '' : ', ') + "" + lhs + " = " + rhs) ); | ||
lastIndex = property.end; | ||
first = false; | ||
} | ||
}); | ||
code.remove( lastIndex, this.init.start ); | ||
} | ||
@@ -976,2 +1050,3 @@ | ||
TaggedTemplateExpression: TaggedTemplateExpression, | ||
TemplateElement: TemplateElement, | ||
TemplateLiteral: TemplateLiteral, | ||
@@ -1025,4 +1100,3 @@ ThisExpression: ThisExpression, | ||
if ( this$1.declarations[ name ] ) { | ||
// TODO add location for debugging... | ||
throw new Error( "" + name + " is already declared" ); | ||
throw new CompileError( node, ("" + name + " is already declared") ); | ||
} | ||
@@ -1060,3 +1134,3 @@ | ||
while ( this.declarations[ name ] || this.references[ name ] || this.aliases[ name ] || name in reserved ) { | ||
name = "" + base + "$" + (counter++) + ""; | ||
name = "" + base + "$" + (counter++); | ||
} | ||
@@ -1157,3 +1231,3 @@ | ||
if ( this.thisAlias ) { | ||
if ( addedStuff ) code.insert( start, "\n" + indentation + "" ); | ||
if ( addedStuff ) code.insert( start, ("\n" + indentation) ); | ||
var assignment$1 = "var " + (this.thisAlias) + " = this;"; | ||
@@ -1169,9 +1243,9 @@ code.insert( start, assignment$1 ); | ||
params.filter( function ( param ) { return param.type === 'AssignmentPattern'; } ).forEach( function ( param ) { | ||
if ( addedStuff ) code.insert( start, "\n" + indentation + "" ); | ||
if ( addedStuff ) code.insert( start, ("\n" + indentation) ); | ||
var lhs = "if ( " + (param.left.name) + " === void 0 ) " + (param.left.name) + ""; | ||
var lhs = "if ( " + (param.left.name) + " === void 0 ) " + (param.left.name); | ||
code | ||
.insert( start, "" + lhs + "" ) | ||
.insert( start, ("" + lhs) ) | ||
.move( param.left.end, param.right.end, start ) | ||
.insert( start, ";" ); | ||
.insert( start, (";") ); | ||
@@ -1191,3 +1265,3 @@ addedStuff = true; | ||
if ( addedStuff ) code.insert( start, "\n" + indentation + "" ); | ||
if ( addedStuff ) code.insert( start, ("\n" + indentation) ); | ||
@@ -1201,3 +1275,3 @@ var key = prop.key.name; | ||
var value = prop.value.name; | ||
code.insert( start, "var " + value + " = " + ref + "." + key + ";" ); | ||
code.insert( start, ("var " + value + " = " + ref + "." + key + ";") ); | ||
} else if ( prop.value.type === 'AssignmentPattern' ) { | ||
@@ -1209,9 +1283,9 @@ code.remove( prop.value.start, prop.value.right.start ); | ||
code | ||
.insert( start, "var " + ref + "_" + key + " = ref." + key + ", " + value$1 + " = ref_" + key + " === void 0 ? " ) | ||
.insert( start, ("var " + ref + "_" + key + " = ref." + key + ", " + value$1 + " = ref_" + key + " === void 0 ? ") ) | ||
.move( prop.value.right.start, prop.value.right.end, start ) | ||
.insert( start, " : ref_" + key + ";" ); | ||
.insert( start, (" : ref_" + key + ";") ); | ||
} | ||
else { | ||
throw new Error( "" + (prop.type) + " not currently supported" ); // TODO... | ||
throw new CompileError( prop, ("Compound destructuring is not supported") ); | ||
} | ||
@@ -1236,3 +1310,3 @@ | ||
if ( addedStuff ) code.insert( start, "\n" + indentation + "" ); | ||
if ( addedStuff ) code.insert( start, ("\n" + indentation) ); | ||
@@ -1243,3 +1317,3 @@ if ( element.type === 'Identifier' ) { | ||
code.insert( start, "var " + (element.name) + " = " + ref + "[" + i + "];" ); | ||
code.insert( start, ("var " + (element.name) + " = " + ref + "[" + i + "];") ); | ||
} else if ( element.type === 'AssignmentPattern' ) { | ||
@@ -1251,9 +1325,9 @@ code.remove( element.start, element.right.start ); | ||
code | ||
.insert( start, "var " + ref + "_" + i + " = ref[" + i + "], " + name + " = ref_" + i + " === void 0 ? " ) | ||
.insert( start, ("var " + ref + "_" + i + " = ref[" + i + "], " + name + " = ref_" + i + " === void 0 ? ") ) | ||
.move( element.right.start, element.right.end, start ) | ||
.insert( start, " : ref_" + i + ";" ); | ||
.insert( start, (" : ref_" + i + ";") ); | ||
} | ||
else { | ||
throw new Error( "" + (element.type) + " not currently supported" ); // TODO... | ||
throw new CompileError( element, ("Compound destructuring is not supported") ); | ||
} | ||
@@ -1280,3 +1354,3 @@ | ||
if ( addedStuff ) code.insert( start, "\n" + indentation + "" ); | ||
if ( addedStuff ) code.insert( start, ("\n" + indentation) ); | ||
@@ -1288,5 +1362,5 @@ var name = lastParam.argument.name; | ||
if ( count ) { | ||
code.insert( start, "var " + name + " = [], " + len + " = arguments.length - " + count + ";\n" + indentation + "while ( " + len + "-- > 0 ) " + name + "[ " + len + " ] = arguments[ " + len + " + " + count + " ];" ); | ||
code.insert( start, ("var " + name + " = [], " + len + " = arguments.length - " + count + ";\n" + indentation + "while ( " + len + "-- > 0 ) " + name + "[ " + len + " ] = arguments[ " + len + " + " + count + " ];") ); | ||
} else { | ||
code.insert( start, "var " + name + " = [], " + len + " = arguments.length;\n" + indentation + "while ( " + len + "-- ) " + name + "[ " + len + " ] = arguments[ " + len + " ];" ); | ||
code.insert( start, ("var " + name + " = [], " + len + " = arguments.length;\n" + indentation + "while ( " + len + "-- ) " + name + "[ " + len + " ] = arguments[ " + len + " ];") ); | ||
} | ||
@@ -1299,3 +1373,3 @@ | ||
if ( addedStuff ) { | ||
code.insert( start, "\n\n" + indentation + "" ); | ||
code.insert( start, ("\n\n" + indentation) ); | ||
} | ||
@@ -1307,3 +1381,3 @@ | ||
for ( var i = 0; i < declarations.length; i += 1 ) { | ||
var forLoop = function ( i ) { | ||
var declaration = declarations[i]; | ||
@@ -1317,3 +1391,5 @@ var alias = this$1.scope.createIdentifier( name ); | ||
} | ||
} | ||
}; | ||
for ( var i = 0; i < declarations.length; i += 1 ) forLoop( i ); | ||
}); | ||
@@ -1329,2 +1405,4 @@ } | ||
function Program ( source, ast ) { | ||
var this$1 = this; | ||
this.type = 'Root'; | ||
@@ -1340,3 +1418,12 @@ | ||
this.templateElements = []; | ||
this.body.initialise(); | ||
this.indentExclusions = {}; | ||
this.templateElements.forEach( function ( node ) { | ||
for ( var i = node.start; i < node.end; i += 1 ) { | ||
this$1.indentExclusions[ node.start + i ] = true; | ||
} | ||
}); | ||
this.body.transpile( this.magicString ); | ||
@@ -1369,11 +1456,16 @@ } | ||
function transform ( source, options ) { | ||
var ast = parse( source, { | ||
ecmaVersion: 6, | ||
preserveParens: true, | ||
sourceType: 'module' | ||
}); | ||
var ast; | ||
var program = new Program( source, ast ); | ||
try { | ||
ast = parse( source, { | ||
ecmaVersion: 6, | ||
preserveParens: true, | ||
sourceType: 'module' | ||
}); | ||
} catch ( err ) { | ||
err.snippet = getSnippet( source, err.loc ); | ||
throw err; | ||
} | ||
return program.export( options ); | ||
return new Program( source, ast ).export( options ); | ||
} | ||
@@ -1380,0 +1472,0 @@ |
@@ -50,12 +50,2 @@ (function (global, factory) { | ||
Node.prototype.findChildren = function findChildren ( type ) { | ||
var children = []; | ||
estreeWalker.walk( this, { | ||
enter: function ( node ) { | ||
if ( node.type === type ) children.push( node ); | ||
} | ||
}); | ||
return children; | ||
}; | ||
Node.prototype.findLexicalBoundary = function findLexicalBoundary () { | ||
@@ -66,3 +56,3 @@ return this.parent.findLexicalBoundary(); | ||
Node.prototype.findNearest = function findNearest ( type ) { | ||
if ( typeof type === 'string' ) type = new RegExp( "^" + type + "$" ); | ||
if ( typeof type === 'string' ) type = new RegExp( ("^" + type + "$") ); | ||
if ( type.test( this.type ) ) return this; | ||
@@ -88,3 +78,3 @@ return this.parent.findNearest( type ); | ||
if ( Array.isArray( value ) ) { | ||
value.forEach( function ( node ) { return node.initialise(); } ); | ||
value.forEach( function ( node ) { return node && node.initialise(); } ); | ||
} else if ( value && typeof value === 'object' ) { | ||
@@ -107,3 +97,3 @@ value.initialise(); | ||
if ( Array.isArray( value ) ) { | ||
value.forEach( function ( node ) { return node.transpile( code ); } ); | ||
value.forEach( function ( node ) { return node && node.transpile( code ); } ); | ||
} else if ( value && typeof value === 'object' ) { | ||
@@ -115,2 +105,78 @@ value.transpile( code ); | ||
function locate ( source, index ) { | ||
var lines = source.split( '\n' ); | ||
var len = lines.length; | ||
var lineStart = 0; | ||
var i; | ||
for ( i = 0; i < len; i += 1 ) { | ||
var line = lines[i]; | ||
var lineEnd = lineStart + line.length + 1; // +1 for newline | ||
if ( lineEnd > index ) { | ||
return { line: i + 1, column: index - lineStart, char: i }; | ||
} | ||
lineStart = lineEnd; | ||
} | ||
throw new Error( 'Could not determine location of character' ); | ||
} | ||
function pad ( num, len ) { | ||
var result = String( num ); | ||
return result + repeat( ' ', len - result.length ); | ||
} | ||
function repeat ( str, times ) { | ||
var result = ''; | ||
while ( times-- ) result += str; | ||
return result; | ||
} | ||
function getSnippet ( source, loc, length ) { | ||
if ( length === void 0 ) length = 1; | ||
var first = Math.max( loc.line - 5, 0 ); | ||
var last = loc.line; | ||
var numDigits = String( last ).length; | ||
var lines = source.split( '\n' ).slice( first, last ); | ||
var lastLine = lines[ lines.length - 1 ]; | ||
var offset = lastLine.slice( 0, loc.column ).replace( /\t/g, ' ' ).length; | ||
var snippet = lines | ||
.map( function ( line, i ) { return ("" + (pad( i + first + 1, numDigits )) + " : " + (line.replace( /\t/g, ' '))); } ) | ||
.join( '\n' ); | ||
snippet += '\n' + repeat( ' ', numDigits + 3 + offset ) + repeat( '^', length ); | ||
return snippet; | ||
} | ||
var CompileError = (function (Error) { | ||
function CompileError ( node, message ) { | ||
Error.call(this); | ||
var source = node.program.magicString.original; | ||
var loc = locate( source, node.start ); | ||
this.name = 'CompileError'; | ||
this.message = message + " (" + (loc.line) + ":" + (loc.column) + ")"; | ||
this.stack = new Error().stack.replace( new RegExp( (".+new " + (this.name) + ".+\\n"), 'm' ), '' ); | ||
this.loc = loc; | ||
this.snippet = getSnippet( source, loc, node.end - node.start ); | ||
} | ||
CompileError.prototype = Object.create( Error && Error.prototype ); | ||
CompileError.prototype.constructor = CompileError; | ||
return CompileError; | ||
}(Error)); | ||
var AssignmentExpression = (function (Node) { | ||
@@ -128,4 +194,3 @@ function AssignmentExpression () { | ||
if ( declaration && declaration.kind === 'const' ) { | ||
// TODO location etc | ||
throw new Error( "" + (this.left.name) + " is read-only" ); | ||
throw new CompileError( this.left, ("" + (this.left.name) + " is read-only") ); | ||
} | ||
@@ -214,5 +279,5 @@ } | ||
if ( nextMethod ) { | ||
code.insert( nextMethod.start, "\n\n" + indentation + "" ); | ||
code.insert( nextMethod.start, ("\n\n" + indentation) ); | ||
} else { | ||
code.insert( constructor.end, "\n\n" + indentation + "" ); | ||
code.insert( constructor.end, ("\n\n" + indentation) ); | ||
} | ||
@@ -222,4 +287,4 @@ } | ||
var fn = "function " + name + " () {" + ( superName ? | ||
"\n" + indentation + "" + indentStr + "" + superName + ".apply(this, arguments);\n" + indentation + "}" : | ||
"}" ) + ( inFunctionExpression ? '' : ';' ) + ( this.body.length ? "\n\n" + indentation + "" : '' ); | ||
("\n" + indentation + "" + indentStr + "" + superName + ".apply(this, arguments);\n" + indentation + "}") : | ||
("}") ) + ( inFunctionExpression ? '' : ';' ) + ( this.body.length ? ("\n\n" + indentation) : '' ); | ||
code.insert( this.start, fn ); | ||
@@ -232,5 +297,5 @@ } | ||
if ( constructor ) { | ||
code.insert( constructor.end, "\n\n" + indentation + "" + inheritanceBlock ); | ||
code.insert( constructor.end, "\n\n" + indentation + inheritanceBlock ); | ||
} else { | ||
code.insert( this.start, inheritanceBlock + "\n\n" + indentation + "" ); | ||
code.insert( this.start, inheritanceBlock + "\n\n" + indentation ); | ||
} | ||
@@ -241,3 +306,3 @@ } | ||
if ( method.kind === 'constructor' ) { | ||
code.overwrite( method.key.start, method.key.end, "function " + name + "" ); | ||
code.overwrite( method.key.start, method.key.end, ("function " + name) ); | ||
return; | ||
@@ -249,6 +314,6 @@ } | ||
var lhs = method.static ? | ||
"" + name + "." + (method.key.name) + "" : | ||
"" + name + ".prototype." + (method.key.name) + ""; | ||
("" + name + "." + (method.key.name)) : | ||
("" + name + ".prototype." + (method.key.name)); | ||
code.insert( method.start, "" + lhs + " = function " ); | ||
code.insert( method.start, ("" + lhs + " = function ") ); | ||
code.insert( method.end, ';' ); | ||
@@ -280,9 +345,2 @@ | ||
var isExcluded = {}; | ||
node.findChildren( 'TemplateLiteral' ).forEach( function ( node ) { | ||
for ( var i = node.start; i < node.end; i += 1 ) { | ||
isExcluded[i] = true; | ||
} | ||
}); | ||
if ( code.original.slice( start - indentStr.length, start ) === indentStr ) { | ||
@@ -295,3 +353,3 @@ code.remove( start - indentStr.length, start ); | ||
while ( match = pattern.exec( slice ) ) { | ||
if ( !isExcluded[ match.index ] ) code.remove( start + match.index, start + match.index + indentStr.length ); | ||
if ( !node.program.indentExclusions[ match.index ] ) code.remove( start + match.index, start + match.index + indentStr.length ); | ||
} | ||
@@ -322,8 +380,8 @@ } | ||
var intro = this.superClass ? | ||
"var " + (this.name) + " = (function (" + superName + ") {\n" + indentation + "" + indentStr + "" : | ||
"var " + (this.name) + " = "; | ||
("var " + (this.name) + " = (function (" + superName + ") {\n" + indentation + "" + indentStr) : | ||
("var " + (this.name) + " = "); | ||
var outro = this.superClass ? | ||
"\n\n" + indentation + "" + indentStr + "return " + (this.name) + ";\n" + indentation + "}(" + superName + "));" : | ||
""; | ||
("\n\n" + indentation + "" + indentStr + "return " + (this.name) + ";\n" + indentation + "}(" + superName + "));") : | ||
(""); | ||
@@ -363,7 +421,7 @@ code.remove( this.start, this.body.start ); | ||
code.overwrite( this.start, this.body.start, "(function (" + (superName || '') + ") {\n" + indentation + "" + indentStr + "" ); | ||
code.overwrite( this.start, this.body.start, ("(function (" + (superName || '') + ") {\n" + indentation + "" + indentStr) ); | ||
this.body.transpile( code, true ); | ||
code.insert( this.end, "\n\n" + indentation + "" + indentStr + "return " + (this.name) + ";\n" + indentation + "}(" + (superName || '') + "))" ); | ||
code.insert( this.end, ("\n\n" + indentation + "" + indentStr + "return " + (this.name) + ";\n" + indentation + "}(" + (superName || '') + "))") ); | ||
}; | ||
@@ -386,5 +444,5 @@ | ||
if ( this.declaration.type === 'ClassDeclaration' ) { | ||
code.insert( this.end, "\n\n" + (this.getIndentation()) + "" ); | ||
code.insert( this.end, ("\n\n" + (this.getIndentation())) ); | ||
code.move( this.start, this.declaration.start, this.end ); | ||
code.insert( this.end, "" + (this.declaration.id.name) + ";" ); | ||
code.insert( this.end, ("" + (this.declaration.id.name) + ";") ); | ||
} | ||
@@ -480,4 +538,4 @@ }; | ||
var before = "var forLoop = function ( " + (names$1.join( ', ' )) + " ) " + ( this.body.synthetic ? "{\n" + indentation + "" + (code.getIndentString()) + "" : '' ); | ||
var after = ( this.body.synthetic ? "\n" + indentation + "}" : '' ) + ";\n\n" + indentation + ""; | ||
var before = "var forLoop = function ( " + (names$1.join( ', ' )) + " ) " + ( this.body.synthetic ? ("{\n" + indentation + "" + (code.getIndentString())) : '' ); | ||
var after = ( this.body.synthetic ? ("\n" + indentation + "}") : '' ) + ";\n\n" + indentation; | ||
@@ -488,3 +546,3 @@ code.insert( this.start, before ); | ||
code.insert( this.end, "forLoop( " + (names$1.join( ', ' )) + " );" ); | ||
code.insert( this.end, ("forLoop( " + (names$1.join( ', ' )) + " );") ); | ||
} | ||
@@ -662,7 +720,2 @@ | ||
function unsupported ( node, description ) { | ||
// TODO show offending snippet | ||
throw new Error( "" + description + ". See TK for more information" ); | ||
} | ||
var Property = (function (Node) { | ||
@@ -678,3 +731,3 @@ function Property () { | ||
if ( this.computed ) { | ||
unsupported( this, 'Computed properties are not supported' ); | ||
throw new CompileError( this.key, 'Computed properties are not supported' ); | ||
} | ||
@@ -688,5 +741,5 @@ | ||
if ( this.shorthand ) { | ||
code.insert( this.start, "" + (this.key.name) + ": " ); | ||
code.insert( this.start, ("" + (this.key.name) + ": ") ); | ||
} else if ( this.method ) { | ||
code.insert( this.key.end, ": function" ); | ||
code.insert( this.key.end, (": function") ); | ||
} | ||
@@ -711,14 +764,13 @@ } | ||
this.method = this.findNearest( 'MethodDefinition' ); | ||
this.superClassName = this.findNearest( 'ClassBody' ).parent.superClass.name; | ||
if ( !this.method ) throw new CompileError( this, 'use of super outside class method' ); | ||
if ( !this.method ) { | ||
throw new Error( 'super outside method' ); // TODO location etc | ||
} | ||
var parentClass = this.findNearest( 'ClassBody' ).parent; | ||
this.superClassName = parentClass.superClass && parentClass.superClass.name; | ||
this.isCalled = this.parent.type === 'CallExpression'; | ||
if ( !this.superClassName ) throw new CompileError( this, 'super used in base class' ); | ||
if ( this.method.kind === 'constructor' ) { | ||
if ( !this.isCalled ) throw new Error( 'super cannot be referred to in constructor outside a call expression' ); // TODO this is cryptic | ||
} else { | ||
if ( this.isCalled ) throw new Error( 'super() not allowed outside class constructor' ); | ||
this.isCalled = this.parent.type === 'CallExpression' && this === this.parent.callee; | ||
if ( this.method.kind !== 'constructor' && this.isCalled ) { | ||
throw new CompileError( this, 'super() not allowed outside class constructor' ); | ||
} | ||
@@ -729,3 +781,3 @@ | ||
if ( !this.isCalled && !this.isMember ) { | ||
throw new Error( 'Unexpected use of `super` (expected `super(...)` or `super.*`)' ); | ||
throw new CompileError( this, 'Unexpected use of `super` (expected `super(...)` or `super.*`)' ); | ||
} | ||
@@ -735,3 +787,3 @@ }; | ||
Super.prototype.transpile = function transpile ( code ) { | ||
var expression = this.isCalled ? this.superClassName : "" + (this.superClassName) + ".prototype"; | ||
var expression = this.isCalled ? this.superClassName : ("" + (this.superClassName) + ".prototype"); | ||
code.overwrite( this.start, this.end, expression, true ); | ||
@@ -745,5 +797,5 @@ | ||
if ( callExpression.arguments.length ) { | ||
code.insert( callExpression.arguments[0].start, "this, " ); | ||
code.insert( callExpression.arguments[0].start, ("this, ") ); | ||
} else { | ||
code.insert( callExpression.end - 1, "this" ); | ||
code.insert( callExpression.end - 1, ("this") ); | ||
} | ||
@@ -765,3 +817,3 @@ } | ||
TaggedTemplateExpression.prototype.initialise = function initialise () { | ||
unsupported( this, 'Tagged template expressions are not supported' ); | ||
throw new CompileError( this.tag, 'Tagged template expressions are not supported' ); | ||
}; | ||
@@ -772,2 +824,17 @@ | ||
var TemplateElement = (function (Node) { | ||
function TemplateElement () { | ||
Node.apply(this, arguments); | ||
} | ||
TemplateElement.prototype = Object.create( Node && Node.prototype ); | ||
TemplateElement.prototype.constructor = TemplateElement; | ||
TemplateElement.prototype.initialise = function initialise () { | ||
this.program.templateElements.push( this ); | ||
}; | ||
return TemplateElement; | ||
}(Node)); | ||
var TemplateLiteral = (function (Node) { | ||
@@ -799,3 +866,3 @@ function TemplateLiteral () { | ||
var stringified = JSON.stringify( node.value.cooked ); | ||
var replacement = ( closeParenthesis ? ')' : '' ) + ( ( node.tail && !node.value.cooked.length && i !== 0 ) ? '' : "" + (i ? ' + ' : '') + "" + stringified + "" ); | ||
var replacement = ( closeParenthesis ? ')' : '' ) + ( ( node.tail && !node.value.cooked.length && i !== 0 ) ? '' : ("" + (i ? ' + ' : '') + "" + stringified) ); | ||
code.overwrite( lastIndex, node.end, replacement ); | ||
@@ -863,4 +930,3 @@ | ||
if ( declaration && declaration.kind === 'const' ) { | ||
// TODO location etc | ||
throw new Error( "" + (this.argument.name) + " is read-only" ); | ||
throw new CompileError( this, ("" + (this.argument.name) + " is read-only") ); | ||
} | ||
@@ -915,4 +981,4 @@ } | ||
this.id[ this.isObjectPattern ? 'properties' : 'elements' ].forEach( function ( node ) { | ||
if ( /Pattern/.test( this$1.isObjectPattern ? node.value.type : node.type ) ) { | ||
unsupported( this$1, 'Compound destructuring is not supported' ); | ||
if ( node && /Pattern/.test( this$1.isObjectPattern ? node.value.type : node.type ) ) { | ||
throw new CompileError( node.value, 'Compound destructuring is not supported' ); | ||
} | ||
@@ -927,2 +993,4 @@ }); | ||
VariableDeclarator.prototype.transpile = function transpile ( code ) { | ||
var this$1 = this; | ||
if ( this.id.type !== 'Identifier' ) { | ||
@@ -933,5 +1001,5 @@ var simple = this.init.type === 'Identifier'; | ||
if ( !simple ) { | ||
code.insert( this.start, "" + name + " = " ); | ||
code.insert( this.start, ("" + name + " = ") ); | ||
code.move( this.init.start, this.init.end, this.start ); | ||
code.insert( this.start, ", " ); | ||
code.insert( this.start, (", ") ); | ||
} else { | ||
@@ -945,11 +1013,17 @@ code.remove( this.init.start, this.init.end ); | ||
props.forEach( this.isObjectPattern ? | ||
function ( property ) { | ||
code.overwrite( property.start, property.end, "" + (property.value.name) + " = " + name + "." + (property.key.name) + "" ); | ||
} : | ||
function ( property, i ) { | ||
code.overwrite( property.start, property.end, "" + (property.name) + " = " + name + "[" + i + "]" ); | ||
}); | ||
var lastIndex = this.start; | ||
var first = true; | ||
code.remove( props[ props.length - 1 ].end, this.init.start ); | ||
props.forEach( function ( property, i ) { | ||
if ( property ) { | ||
var lhs = this$1.isObjectPattern ? property.value.name : property.name; | ||
var rhs = this$1.isObjectPattern ? ("" + name + "." + (property.key.name)) : ("" + name + "[" + i + "]"); | ||
code.overwrite( lastIndex, property.end, ("" + (first ? '' : ', ') + "" + lhs + " = " + rhs) ); | ||
lastIndex = property.end; | ||
first = false; | ||
} | ||
}); | ||
code.remove( lastIndex, this.init.start ); | ||
} | ||
@@ -980,2 +1054,3 @@ | ||
TaggedTemplateExpression: TaggedTemplateExpression, | ||
TemplateElement: TemplateElement, | ||
TemplateLiteral: TemplateLiteral, | ||
@@ -1029,4 +1104,3 @@ ThisExpression: ThisExpression, | ||
if ( this$1.declarations[ name ] ) { | ||
// TODO add location for debugging... | ||
throw new Error( "" + name + " is already declared" ); | ||
throw new CompileError( node, ("" + name + " is already declared") ); | ||
} | ||
@@ -1064,3 +1138,3 @@ | ||
while ( this.declarations[ name ] || this.references[ name ] || this.aliases[ name ] || name in reserved ) { | ||
name = "" + base + "$" + (counter++) + ""; | ||
name = "" + base + "$" + (counter++); | ||
} | ||
@@ -1161,3 +1235,3 @@ | ||
if ( this.thisAlias ) { | ||
if ( addedStuff ) code.insert( start, "\n" + indentation + "" ); | ||
if ( addedStuff ) code.insert( start, ("\n" + indentation) ); | ||
var assignment$1 = "var " + (this.thisAlias) + " = this;"; | ||
@@ -1173,9 +1247,9 @@ code.insert( start, assignment$1 ); | ||
params.filter( function ( param ) { return param.type === 'AssignmentPattern'; } ).forEach( function ( param ) { | ||
if ( addedStuff ) code.insert( start, "\n" + indentation + "" ); | ||
if ( addedStuff ) code.insert( start, ("\n" + indentation) ); | ||
var lhs = "if ( " + (param.left.name) + " === void 0 ) " + (param.left.name) + ""; | ||
var lhs = "if ( " + (param.left.name) + " === void 0 ) " + (param.left.name); | ||
code | ||
.insert( start, "" + lhs + "" ) | ||
.insert( start, ("" + lhs) ) | ||
.move( param.left.end, param.right.end, start ) | ||
.insert( start, ";" ); | ||
.insert( start, (";") ); | ||
@@ -1195,3 +1269,3 @@ addedStuff = true; | ||
if ( addedStuff ) code.insert( start, "\n" + indentation + "" ); | ||
if ( addedStuff ) code.insert( start, ("\n" + indentation) ); | ||
@@ -1205,3 +1279,3 @@ var key = prop.key.name; | ||
var value = prop.value.name; | ||
code.insert( start, "var " + value + " = " + ref + "." + key + ";" ); | ||
code.insert( start, ("var " + value + " = " + ref + "." + key + ";") ); | ||
} else if ( prop.value.type === 'AssignmentPattern' ) { | ||
@@ -1213,9 +1287,9 @@ code.remove( prop.value.start, prop.value.right.start ); | ||
code | ||
.insert( start, "var " + ref + "_" + key + " = ref." + key + ", " + value$1 + " = ref_" + key + " === void 0 ? " ) | ||
.insert( start, ("var " + ref + "_" + key + " = ref." + key + ", " + value$1 + " = ref_" + key + " === void 0 ? ") ) | ||
.move( prop.value.right.start, prop.value.right.end, start ) | ||
.insert( start, " : ref_" + key + ";" ); | ||
.insert( start, (" : ref_" + key + ";") ); | ||
} | ||
else { | ||
throw new Error( "" + (prop.type) + " not currently supported" ); // TODO... | ||
throw new CompileError( prop, ("Compound destructuring is not supported") ); | ||
} | ||
@@ -1240,3 +1314,3 @@ | ||
if ( addedStuff ) code.insert( start, "\n" + indentation + "" ); | ||
if ( addedStuff ) code.insert( start, ("\n" + indentation) ); | ||
@@ -1247,3 +1321,3 @@ if ( element.type === 'Identifier' ) { | ||
code.insert( start, "var " + (element.name) + " = " + ref + "[" + i + "];" ); | ||
code.insert( start, ("var " + (element.name) + " = " + ref + "[" + i + "];") ); | ||
} else if ( element.type === 'AssignmentPattern' ) { | ||
@@ -1255,9 +1329,9 @@ code.remove( element.start, element.right.start ); | ||
code | ||
.insert( start, "var " + ref + "_" + i + " = ref[" + i + "], " + name + " = ref_" + i + " === void 0 ? " ) | ||
.insert( start, ("var " + ref + "_" + i + " = ref[" + i + "], " + name + " = ref_" + i + " === void 0 ? ") ) | ||
.move( element.right.start, element.right.end, start ) | ||
.insert( start, " : ref_" + i + ";" ); | ||
.insert( start, (" : ref_" + i + ";") ); | ||
} | ||
else { | ||
throw new Error( "" + (element.type) + " not currently supported" ); // TODO... | ||
throw new CompileError( element, ("Compound destructuring is not supported") ); | ||
} | ||
@@ -1284,3 +1358,3 @@ | ||
if ( addedStuff ) code.insert( start, "\n" + indentation + "" ); | ||
if ( addedStuff ) code.insert( start, ("\n" + indentation) ); | ||
@@ -1292,5 +1366,5 @@ var name = lastParam.argument.name; | ||
if ( count ) { | ||
code.insert( start, "var " + name + " = [], " + len + " = arguments.length - " + count + ";\n" + indentation + "while ( " + len + "-- > 0 ) " + name + "[ " + len + " ] = arguments[ " + len + " + " + count + " ];" ); | ||
code.insert( start, ("var " + name + " = [], " + len + " = arguments.length - " + count + ";\n" + indentation + "while ( " + len + "-- > 0 ) " + name + "[ " + len + " ] = arguments[ " + len + " + " + count + " ];") ); | ||
} else { | ||
code.insert( start, "var " + name + " = [], " + len + " = arguments.length;\n" + indentation + "while ( " + len + "-- ) " + name + "[ " + len + " ] = arguments[ " + len + " ];" ); | ||
code.insert( start, ("var " + name + " = [], " + len + " = arguments.length;\n" + indentation + "while ( " + len + "-- ) " + name + "[ " + len + " ] = arguments[ " + len + " ];") ); | ||
} | ||
@@ -1303,3 +1377,3 @@ | ||
if ( addedStuff ) { | ||
code.insert( start, "\n\n" + indentation + "" ); | ||
code.insert( start, ("\n\n" + indentation) ); | ||
} | ||
@@ -1311,3 +1385,3 @@ | ||
for ( var i = 0; i < declarations.length; i += 1 ) { | ||
var forLoop = function ( i ) { | ||
var declaration = declarations[i]; | ||
@@ -1321,3 +1395,5 @@ var alias = this$1.scope.createIdentifier( name ); | ||
} | ||
} | ||
}; | ||
for ( var i = 0; i < declarations.length; i += 1 ) forLoop( i ); | ||
}); | ||
@@ -1333,2 +1409,4 @@ } | ||
function Program ( source, ast ) { | ||
var this$1 = this; | ||
this.type = 'Root'; | ||
@@ -1344,3 +1422,12 @@ | ||
this.templateElements = []; | ||
this.body.initialise(); | ||
this.indentExclusions = {}; | ||
this.templateElements.forEach( function ( node ) { | ||
for ( var i = node.start; i < node.end; i += 1 ) { | ||
this$1.indentExclusions[ node.start + i ] = true; | ||
} | ||
}); | ||
this.body.transpile( this.magicString ); | ||
@@ -1373,11 +1460,16 @@ } | ||
function transform ( source, options ) { | ||
var ast = acorn.parse( source, { | ||
ecmaVersion: 6, | ||
preserveParens: true, | ||
sourceType: 'module' | ||
}); | ||
var ast; | ||
var program = new Program( source, ast ); | ||
try { | ||
ast = acorn.parse( source, { | ||
ecmaVersion: 6, | ||
preserveParens: true, | ||
sourceType: 'module' | ||
}); | ||
} catch ( err ) { | ||
err.snippet = getSnippet( source, err.loc ); | ||
throw err; | ||
} | ||
return program.export( options ); | ||
return new Program( source, ast ).export( options ); | ||
} | ||
@@ -1384,0 +1476,0 @@ |
{ | ||
"name": "buble", | ||
"version": "0.4.5", | ||
"version": "0.4.6", | ||
"description": "The blazing fast, batteries-included ES2015 compiler", | ||
@@ -5,0 +5,0 @@ "main": "dist/buble.umd.js", |
import { parse } from 'acorn'; | ||
import Program from './program/Program.js'; | ||
import getSnippet from './utils/getSnippet.js'; | ||
export function transform ( source, options ) { | ||
var ast = parse( source, { | ||
ecmaVersion: 6, | ||
preserveParens: true, | ||
sourceType: 'module' | ||
}); | ||
let ast; | ||
var program = new Program( source, ast ); | ||
try { | ||
ast = parse( source, { | ||
ecmaVersion: 6, | ||
preserveParens: true, | ||
sourceType: 'module' | ||
}); | ||
} catch ( err ) { | ||
err.snippet = getSnippet( source, err.loc ); | ||
throw err; | ||
} | ||
return program.export( options ); | ||
return new Program( source, ast ).export( options ); | ||
} |
import wrap from './wrap.js'; | ||
import Node from './Node.js'; | ||
import Scope from './Scope.js'; | ||
import CompileError from '../utils/CompileError.js'; | ||
@@ -131,3 +132,3 @@ export default class BlockStatement extends Node { | ||
else { | ||
throw new Error( `${prop.type} not currently supported` ); // TODO... | ||
throw new CompileError( prop, `Compound destructuring is not supported` ); | ||
} | ||
@@ -171,3 +172,3 @@ | ||
else { | ||
throw new Error( `${element.type} not currently supported` ); // TODO... | ||
throw new CompileError( element, `Compound destructuring is not supported` ); | ||
} | ||
@@ -174,0 +175,0 @@ |
@@ -44,12 +44,2 @@ import { walk } from 'estree-walker'; | ||
findChildren ( type ) { | ||
let children = []; | ||
walk( this, { | ||
enter ( node ) { | ||
if ( node.type === type ) children.push( node ); | ||
} | ||
}); | ||
return children; | ||
} | ||
findLexicalBoundary () { | ||
@@ -79,3 +69,3 @@ return this.parent.findLexicalBoundary(); | ||
if ( Array.isArray( value ) ) { | ||
value.forEach( node => node.initialise() ); | ||
value.forEach( node => node && node.initialise() ); | ||
} else if ( value && typeof value === 'object' ) { | ||
@@ -96,3 +86,3 @@ value.initialise(); | ||
if ( Array.isArray( value ) ) { | ||
value.forEach( node => node.transpile( code ) ); | ||
value.forEach( node => node && node.transpile( code ) ); | ||
} else if ( value && typeof value === 'object' ) { | ||
@@ -99,0 +89,0 @@ value.transpile( code ); |
@@ -15,3 +15,12 @@ import MagicString from 'magic-string'; | ||
this.templateElements = []; | ||
this.body.initialise(); | ||
this.indentExclusions = {}; | ||
this.templateElements.forEach( node => { | ||
for ( let i = node.start; i < node.end; i += 1 ) { | ||
this.indentExclusions[ node.start + i ] = true; | ||
} | ||
}); | ||
this.body.transpile( this.magicString ); | ||
@@ -18,0 +27,0 @@ } |
@@ -1,3 +0,3 @@ | ||
//import Declaration from '../Declaration.js'; | ||
import extractNames from './extractNames.js'; | ||
import CompileError from '../utils/CompileError.js'; | ||
@@ -28,4 +28,3 @@ let reserved = Object.create( null ); | ||
if ( this.declarations[ name ] ) { | ||
// TODO add location for debugging... | ||
throw new Error( `${name} is already declared` ); | ||
throw new CompileError( node, `${name} is already declared` ); | ||
} | ||
@@ -32,0 +31,0 @@ |
import Node from '../Node.js'; | ||
import CompileError from '../../utils/CompileError.js'; | ||
@@ -8,4 +9,3 @@ export default class AssignmentExpression extends Node { | ||
if ( declaration && declaration.kind === 'const' ) { | ||
// TODO location etc | ||
throw new Error( `${this.left.name} is read-only` ); | ||
throw new CompileError( this.left, `${this.left.name} is read-only` ); | ||
} | ||
@@ -12,0 +12,0 @@ } |
@@ -17,2 +17,3 @@ import AssignmentExpression from './AssignmentExpression.js'; | ||
import TaggedTemplateExpression from './TaggedTemplateExpression.js'; | ||
import TemplateElement from './TemplateElement.js'; | ||
import TemplateLiteral from './TemplateLiteral.js'; | ||
@@ -41,2 +42,3 @@ import ThisExpression from './ThisExpression.js'; | ||
TaggedTemplateExpression, | ||
TemplateElement, | ||
TemplateLiteral, | ||
@@ -43,0 +45,0 @@ ThisExpression, |
import Node from '../Node.js'; | ||
import unsupported from '../../utils/unsupported.js'; | ||
import CompileError from '../../utils/CompileError.js'; | ||
@@ -7,3 +7,3 @@ export default class Property extends Node { | ||
if ( this.computed ) { | ||
unsupported( this, 'Computed properties are not supported' ); | ||
throw new CompileError( this.key, 'Computed properties are not supported' ); | ||
} | ||
@@ -10,0 +10,0 @@ |
import Node from '../Node.js'; | ||
import CompileError from '../../utils/CompileError.js'; | ||
@@ -6,14 +7,13 @@ export default class Super extends Node { | ||
this.method = this.findNearest( 'MethodDefinition' ); | ||
this.superClassName = this.findNearest( 'ClassBody' ).parent.superClass.name; | ||
if ( !this.method ) throw new CompileError( this, 'use of super outside class method' ); | ||
if ( !this.method ) { | ||
throw new Error( 'super outside method' ); // TODO location etc | ||
} | ||
const parentClass = this.findNearest( 'ClassBody' ).parent; | ||
this.superClassName = parentClass.superClass && parentClass.superClass.name; | ||
this.isCalled = this.parent.type === 'CallExpression'; | ||
if ( !this.superClassName ) throw new CompileError( this, 'super used in base class' ); | ||
if ( this.method.kind === 'constructor' ) { | ||
if ( !this.isCalled ) throw new Error( 'super cannot be referred to in constructor outside a call expression' ); // TODO this is cryptic | ||
} else { | ||
if ( this.isCalled ) throw new Error( 'super() not allowed outside class constructor' ); | ||
this.isCalled = this.parent.type === 'CallExpression' && this === this.parent.callee; | ||
if ( this.method.kind !== 'constructor' && this.isCalled ) { | ||
throw new CompileError( this, 'super() not allowed outside class constructor' ); | ||
} | ||
@@ -24,3 +24,3 @@ | ||
if ( !this.isCalled && !this.isMember ) { | ||
throw new Error( 'Unexpected use of `super` (expected `super(...)` or `super.*`)' ); | ||
throw new CompileError( this, 'Unexpected use of `super` (expected `super(...)` or `super.*`)' ); | ||
} | ||
@@ -27,0 +27,0 @@ } |
import Node from '../Node.js'; | ||
import unsupported from '../../utils/unsupported.js'; | ||
import CompileError from '../../utils/CompileError.js'; | ||
export default class TaggedTemplateExpression extends Node { | ||
initialise () { | ||
unsupported( this, 'Tagged template expressions are not supported' ); | ||
throw new CompileError( this.tag, 'Tagged template expressions are not supported' ); | ||
} | ||
} |
import Node from '../Node.js'; | ||
import CompileError from '../../utils/CompileError.js'; | ||
@@ -8,4 +9,3 @@ export default class UpdateExpression extends Node { | ||
if ( declaration && declaration.kind === 'const' ) { | ||
// TODO location etc | ||
throw new Error( `${this.argument.name} is read-only` ); | ||
throw new CompileError( this, `${this.argument.name} is read-only` ); | ||
} | ||
@@ -12,0 +12,0 @@ } |
import Node from '../Node.js'; | ||
import unsupported from '../../utils/unsupported.js'; | ||
import CompileError from '../../utils/CompileError.js'; | ||
@@ -11,4 +11,4 @@ export default class VariableDeclarator extends Node { | ||
this.id[ this.isObjectPattern ? 'properties' : 'elements' ].forEach( node => { | ||
if ( /Pattern/.test( this.isObjectPattern ? node.value.type : node.type ) ) { | ||
unsupported( this, 'Compound destructuring is not supported' ); | ||
if ( node && /Pattern/.test( this.isObjectPattern ? node.value.type : node.type ) ) { | ||
throw new CompileError( node.value, 'Compound destructuring is not supported' ); | ||
} | ||
@@ -39,11 +39,17 @@ }); | ||
props.forEach( this.isObjectPattern ? | ||
property => { | ||
code.overwrite( property.start, property.end, `${property.value.name} = ${name}.${property.key.name}` ); | ||
} : | ||
( property, i ) => { | ||
code.overwrite( property.start, property.end, `${property.name} = ${name}[${i}]` ); | ||
}); | ||
let lastIndex = this.start; | ||
let first = true; | ||
code.remove( props[ props.length - 1 ].end, this.init.start ); | ||
props.forEach( ( property, i ) => { | ||
if ( property ) { | ||
const lhs = this.isObjectPattern ? property.value.name : property.name; | ||
const rhs = this.isObjectPattern ? `${name}.${property.key.name}` : `${name}[${i}]`; | ||
code.overwrite( lastIndex, property.end, `${first ? '' : ', '}${lhs} = ${rhs}` ); | ||
lastIndex = property.end; | ||
first = false; | ||
} | ||
}); | ||
code.remove( lastIndex, this.init.start ); | ||
} | ||
@@ -50,0 +56,0 @@ |
@@ -12,9 +12,2 @@ // TODO this function is slightly flawed – it works on the original string, | ||
let isExcluded = {}; | ||
node.findChildren( 'TemplateLiteral' ).forEach( node => { | ||
for ( let i = node.start; i < node.end; i += 1 ) { | ||
isExcluded[i] = true; | ||
} | ||
}); | ||
if ( code.original.slice( start - indentStr.length, start ) === indentStr ) { | ||
@@ -27,4 +20,4 @@ code.remove( start - indentStr.length, start ); | ||
while ( match = pattern.exec( slice ) ) { | ||
if ( !isExcluded[ match.index ] ) code.remove( start + match.index, start + match.index + indentStr.length ); | ||
if ( !node.program.indentExclusions[ match.index ] ) code.remove( start + match.index, start + match.index + indentStr.length ); | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
295685
43
3168