buble
Version:
The blazing fast, batteries-included ES2015 compiler
1,816 lines (1,530 loc) • 142 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var acorn = require('acorn');
var acornJsx = _interopDefault(require('acorn-jsx'));
var acornDynamicImport = _interopDefault(require('acorn-dynamic-import'));
var MagicString = _interopDefault(require('magic-string'));
var rewritePattern = _interopDefault(require('regexpu-core'));
// used for debugging, without the noise created by
// circular references
function toJSON(node) {
var obj = {};
Object.keys(node).forEach(function (key) {
if (
key === 'parent' ||
key === 'program' ||
key === 'keys' ||
key === '__wrapped'
)
{ return; }
if (Array.isArray(node[key])) {
obj[key] = node[key].map(toJSON);
} else if (node[key] && node[key].toJSON) {
obj[key] = node[key].toJSON();
} else {
obj[key] = node[key];
}
});
return obj;
}
var Node = function Node () {};
Node.prototype.ancestor = function ancestor (level) {
var node = this;
while (level--) {
node = node.parent;
if (!node) { return null; }
}
return node;
};
Node.prototype.contains = function contains (node) {
while (node) {
if (node === this) { return true; }
node = node.parent;
}
return false;
};
Node.prototype.findLexicalBoundary = function findLexicalBoundary () {
return this.parent.findLexicalBoundary();
};
Node.prototype.findNearest = function findNearest (type) {
if (typeof type === 'string') { type = new RegExp(("^" + type + "$")); }
if (type.test(this.type)) { return this; }
return this.parent.findNearest(type);
};
Node.prototype.unparenthesizedParent = function unparenthesizedParent () {
var node = this.parent;
while (node && node.type === 'ParenthesizedExpression') {
node = node.parent;
}
return node;
};
Node.prototype.unparenthesize = function unparenthesize () {
var node = this;
while (node.type === 'ParenthesizedExpression') {
node = node.expression;
}
return node;
};
Node.prototype.findScope = function findScope (functionScope) {
return this.parent.findScope(functionScope);
};
Node.prototype.getIndentation = function getIndentation () {
return this.parent.getIndentation();
};
Node.prototype.initialise = function initialise (transforms) {
for (var i = 0, list = this.keys; i < list.length; i += 1) {
var key = list[i];
var value = this[key];
if (Array.isArray(value)) {
value.forEach(function (node) { return node && node.initialise(transforms); });
} else if (value && typeof value === 'object') {
value.initialise(transforms);
}
}
};
Node.prototype.toJSON = function toJSON$1 () {
return toJSON(this);
};
Node.prototype.toString = function toString () {
return this.program.magicString.original.slice(this.start, this.end);
};
Node.prototype.transpile = function transpile (code, transforms) {
for (var i = 0, list = this.keys; i < list.length; i += 1) {
var key = list[i];
var value = this[key];
if (Array.isArray(value)) {
value.forEach(function (node) { return node && node.transpile(code, transforms); });
} else if (value && typeof value === 'object') {
value.transpile(code, transforms);
}
}
};
function extractNames(node) {
var names = [];
extractors[node.type](names, node);
return names;
}
var extractors = {
Identifier: function Identifier(names, node) {
names.push(node);
},
ObjectPattern: function ObjectPattern(names, node) {
for (var i = 0, list = node.properties; i < list.length; i += 1) {
var prop = list[i];
extractors[prop.type](names, prop);
}
},
Property: function Property(names, node) {
extractors[node.value.type](names, node.value);
},
ArrayPattern: function ArrayPattern(names, node) {
for (var i = 0, list = node.elements; i < list.length; i += 1) {
var element = list[i];
if (element) { extractors[element.type](names, element); }
}
},
RestElement: function RestElement(names, node) {
extractors[node.argument.type](names, node.argument);
},
AssignmentPattern: function AssignmentPattern(names, node) {
extractors[node.left.type](names, node.left);
}
};
var reserved = Object.create(null);
'do if in for let new try var case else enum eval null this true void with await break catch class const false super throw while yield delete export import public return static switch typeof default extends finally package private continue debugger function arguments interface protected implements instanceof'
.split(' ')
.forEach(function (word) { return (reserved[word] = true); });
function Scope(options) {
options = options || {};
this.parent = options.parent;
this.isBlockScope = !!options.block;
this.createDeclarationCallback = options.declare;
var scope = this;
while (scope.isBlockScope) { scope = scope.parent; }
this.functionScope = scope;
this.identifiers = [];
this.declarations = Object.create(null);
this.references = Object.create(null);
this.blockScopedDeclarations = this.isBlockScope ? null : Object.create(null);
this.aliases = Object.create(null);
}
Scope.prototype = {
addDeclaration: function addDeclaration(node, kind) {
for (var i = 0, list = extractNames(node); i < list.length; i += 1) {
var identifier = list[i];
var name = identifier.name;
var declaration = { name: name, node: identifier, kind: kind, instances: [] };
this.declarations[name] = declaration;
if (this.isBlockScope) {
if (!this.functionScope.blockScopedDeclarations[name])
{ this.functionScope.blockScopedDeclarations[name] = []; }
this.functionScope.blockScopedDeclarations[name].push(declaration);
}
}
},
addReference: function addReference(identifier) {
if (this.consolidated) {
this.consolidateReference(identifier);
} else {
this.identifiers.push(identifier);
}
},
consolidate: function consolidate() {
for (var i = 0; i < this.identifiers.length; i += 1) {
// we might push to the array during consolidation, so don't cache length
var identifier = this.identifiers[i];
this.consolidateReference(identifier);
}
this.consolidated = true; // TODO understand why this is necessary... seems bad
},
consolidateReference: function consolidateReference(identifier) {
var declaration = this.declarations[identifier.name];
if (declaration) {
declaration.instances.push(identifier);
} else {
this.references[identifier.name] = true;
if (this.parent) { this.parent.addReference(identifier); }
}
},
contains: function contains(name) {
return (
this.declarations[name] ||
(this.parent ? this.parent.contains(name) : false)
);
},
createIdentifier: function createIdentifier(base) {
if (typeof base === 'number') { base = base.toString(); }
base = base
.replace(/\s/g, '')
.replace(/\[([^\]]+)\]/g, '_$1')
.replace(/[^a-zA-Z0-9_$]/g, '_')
.replace(/_{2,}/, '_');
var name = base;
var counter = 1;
while (
this.declarations[name] ||
this.references[name] ||
this.aliases[name] ||
name in reserved
) {
name = base + "$" + (counter++);
}
this.aliases[name] = true;
return name;
},
createDeclaration: function createDeclaration(base) {
var id = this.createIdentifier(base);
this.createDeclarationCallback(id);
return id;
},
findDeclaration: function findDeclaration(name) {
return (
this.declarations[name] ||
(this.parent && this.parent.findDeclaration(name))
);
},
// Sometimes, block scope declarations change name during transpilation
resolveName: function resolveName(name) {
var declaration = this.findDeclaration(name);
return declaration ? declaration.name : name;
}
};
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 = /*@__PURE__*/(function (Error) {
function CompileError(message, node) {
Error.call(this, message);
this.name = 'CompileError';
if (!node) {
return;
}
var source = node.program.magicString.original;
var loc = locate(source, node.start);
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);
}
if ( Error ) CompileError.__proto__ = Error;
CompileError.prototype = Object.create( Error && Error.prototype );
CompileError.prototype.constructor = CompileError;
CompileError.prototype.toString = function toString () {
return ((this.name) + ": " + (this.message) + "\n" + (this.snippet));
};
CompileError.missingTransform = function missingTransform (feature, transformKey, node, dangerousKey) {
if ( dangerousKey === void 0 ) dangerousKey = null;
var maybeDangerous = dangerousKey ? (", or `transforms: { " + dangerousKey + ": true }` if you know what you're doing") : '';
throw new CompileError(("Transforming " + feature + " is not " + (dangerousKey ? "fully supported" : "implemented") + ". Use `transforms: { " + transformKey + ": false }` to skip transformation and disable this error" + maybeDangerous + "."), node);
};
return CompileError;
}(Error));
function findIndex(array, fn) {
for (var i = 0; i < array.length; i += 1) {
if (fn(array[i], i)) { return i; }
}
return -1;
}
var handlers = {
Identifier: destructureIdentifier,
AssignmentPattern: destructureAssignmentPattern,
ArrayPattern: destructureArrayPattern,
ObjectPattern: destructureObjectPattern
};
function destructure(
code,
createIdentifier,
resolveName,
node,
ref,
inline,
statementGenerators
) {
handlers[node.type](code, createIdentifier, resolveName, node, ref, inline, statementGenerators);
}
function destructureIdentifier(
code,
createIdentifier,
resolveName,
node,
ref,
inline,
statementGenerators
) {
statementGenerators.push(function (start, prefix, suffix) {
code.overwrite(node.start, node.end, (inline ? prefix : (prefix + "var ")) + resolveName(node) + " = " + ref + suffix);
code.move(node.start, node.end, start);
});
}
function destructureMemberExpression(
code,
createIdentifier,
resolveName,
node,
ref,
inline,
statementGenerators
) {
statementGenerators.push(function (start, prefix, suffix) {
code.prependRight(node.start, inline ? prefix : (prefix + "var "));
code.appendLeft(node.end, (" = " + ref + suffix));
code.move(node.start, node.end, start);
});
}
function destructureAssignmentPattern(
code,
createIdentifier,
resolveName,
node,
ref,
inline,
statementGenerators
) {
var isIdentifier = node.left.type === 'Identifier';
var name = isIdentifier ? node.left.name : ref;
if (!inline) {
statementGenerators.push(function (start, prefix, suffix) {
code.prependRight(
node.left.end,
(prefix + "if ( " + name + " === void 0 ) " + name)
);
code.move(node.left.end, node.right.end, start);
code.appendLeft(node.right.end, suffix);
});
}
if (!isIdentifier) {
destructure(code, createIdentifier, resolveName, node.left, ref, inline, statementGenerators);
}
}
function destructureArrayPattern(
code,
createIdentifier,
resolveName,
node,
ref,
inline,
statementGenerators
) {
var c = node.start;
node.elements.forEach(function (element, i) {
if (!element) { return; }
if (element.type === 'RestElement') {
handleProperty(
code,
createIdentifier,
resolveName,
c,
element.argument,
(ref + ".slice(" + i + ")"),
inline,
statementGenerators
);
} else {
handleProperty(
code,
createIdentifier,
resolveName,
c,
element,
(ref + "[" + i + "]"),
inline,
statementGenerators
);
}
c = element.end;
});
code.remove(c, node.end);
}
function destructureObjectPattern(
code,
createIdentifier,
resolveName,
node,
ref,
inline,
statementGenerators
) {
var this$1 = this;
var c = node.start;
var nonRestKeys = [];
node.properties.forEach(function (prop) {
var value;
var content;
if (prop.type === 'Property') {
content = prop.value;
if (!prop.computed && prop.key.type === 'Identifier') {
value = ref + "." + (prop.key.name);
nonRestKeys.push(("\"" + (prop.key.name) + "\""));
} else if (!prop.computed && prop.key.type === 'Literal') {
value = ref + "[" + (prop.key.raw) + "]";
nonRestKeys.push(JSON.stringify(String(prop.key.value)));
} else {
var expr = code.slice(prop.key.start, prop.key.end);
value = ref + "[" + expr + "]";
nonRestKeys.push(("String(" + expr + ")"));
}
} else if (prop.type === 'RestElement') {
content = prop.argument;
value = createIdentifier('rest');
statementGenerators.push(function (start, prefix, suffix) {
var helper = prop.program.getObjectWithoutPropertiesHelper(code);
code.overwrite(
prop.start,
(c = prop.argument.start),
(inline ? prefix : (prefix + "var ")) + value + " = " + helper + "( " + ref + ", [" + (nonRestKeys.join(', ')) + "] )" + suffix
);
code.move(prop.start, c, start);
});
} else {
throw new CompileError(
this$1,
("Unexpected node of type " + (prop.type) + " in object pattern")
);
}
handleProperty(code, createIdentifier, resolveName, c, content, value, inline, statementGenerators);
c = prop.end;
});
code.remove(c, node.end);
}
function handleProperty(
code,
createIdentifier,
resolveName,
c,
node,
value,
inline,
statementGenerators
) {
switch (node.type) {
case 'Identifier': {
code.remove(c, node.start);
destructureIdentifier(
code,
createIdentifier,
resolveName,
node,
value,
inline,
statementGenerators
);
break;
}
case 'MemberExpression':
code.remove(c, node.start);
destructureMemberExpression(
code,
createIdentifier,
resolveName,
node,
value,
true,
statementGenerators
);
break;
case 'AssignmentPattern': {
var name;
var isIdentifier = node.left.type === 'Identifier';
if (isIdentifier) {
name = resolveName(node.left);
} else {
name = createIdentifier(value);
}
statementGenerators.push(function (start, prefix, suffix) {
if (inline) {
code.prependRight(
node.right.start,
(name + " = " + value + ", " + name + " = " + name + " === void 0 ? ")
);
code.appendLeft(node.right.end, (" : " + name + suffix));
} else {
code.prependRight(
node.right.start,
(prefix + "var " + name + " = " + value + "; if ( " + name + " === void 0 ) " + name + " = ")
);
code.appendLeft(node.right.end, suffix);
}
code.move(node.right.start, node.right.end, start);
});
if (isIdentifier) {
code.remove(c, node.right.start);
} else {
code.remove(c, node.left.start);
code.remove(node.left.end, node.right.start);
handleProperty(
code,
createIdentifier,
resolveName,
c,
node.left,
name,
inline,
statementGenerators
);
}
break;
}
case 'ObjectPattern': {
code.remove(c, (c = node.start));
var ref = value;
if (node.properties.length > 1) {
ref = createIdentifier(value);
statementGenerators.push(function (start, prefix, suffix) {
// this feels a tiny bit hacky, but we can't do a
// straightforward appendLeft and keep correct order...
code.prependRight(node.start, (inline ? '' : (prefix + "var ")) + ref + " = ");
code.overwrite(node.start, (c = node.start + 1), value);
code.appendLeft(c, suffix);
code.overwrite(
node.start,
(c = node.start + 1),
(inline ? '' : (prefix + "var ")) + ref + " = " + value + suffix
);
code.move(node.start, c, start);
});
}
destructureObjectPattern(
code,
createIdentifier,
resolveName,
node,
ref,
inline,
statementGenerators
);
break;
}
case 'ArrayPattern': {
code.remove(c, (c = node.start));
if (node.elements.filter(Boolean).length > 1) {
var ref$1 = createIdentifier(value);
statementGenerators.push(function (start, prefix, suffix) {
code.prependRight(node.start, (inline ? '' : (prefix + "var ")) + ref$1 + " = ");
code.overwrite(node.start, (c = node.start + 1), value, {
contentOnly: true
});
code.appendLeft(c, suffix);
code.move(node.start, c, start);
});
node.elements.forEach(function (element, i) {
if (!element) { return; }
if (element.type === 'RestElement') {
handleProperty(
code,
createIdentifier,
resolveName,
c,
element.argument,
(ref$1 + ".slice(" + i + ")"),
inline,
statementGenerators
);
} else {
handleProperty(
code,
createIdentifier,
resolveName,
c,
element,
(ref$1 + "[" + i + "]"),
inline,
statementGenerators
);
}
c = element.end;
});
} else {
var index = findIndex(node.elements, Boolean);
var element = node.elements[index];
if (element.type === 'RestElement') {
handleProperty(
code,
createIdentifier,
resolveName,
c,
element.argument,
(value + ".slice(" + index + ")"),
inline,
statementGenerators
);
} else {
handleProperty(
code,
createIdentifier,
resolveName,
c,
element,
(value + "[" + index + "]"),
inline,
statementGenerators
);
}
c = element.end;
}
code.remove(c, node.end);
break;
}
default: {
throw new Error(("Unexpected node type in destructuring (" + (node.type) + ")"));
}
}
}
function isUseStrict(node) {
if (!node) { return false; }
if (node.type !== 'ExpressionStatement') { return false; }
if (node.expression.type !== 'Literal') { return false; }
return node.expression.value === 'use strict';
}
var BlockStatement = /*@__PURE__*/(function (Node) {
function BlockStatement () {
Node.apply(this, arguments);
}
if ( Node ) BlockStatement.__proto__ = Node;
BlockStatement.prototype = Object.create( Node && Node.prototype );
BlockStatement.prototype.constructor = BlockStatement;
BlockStatement.prototype.createScope = function createScope () {
var this$1 = this;
this.parentIsFunction = /Function/.test(this.parent.type);
this.isFunctionBlock = this.parentIsFunction || this.parent.type === 'Root';
this.scope = new Scope({
block: !this.isFunctionBlock,
parent: this.parent.findScope(false),
declare: function (id) { return this$1.createdDeclarations.push(id); }
});
if (this.parentIsFunction) {
this.parent.params.forEach(function (node) {
this$1.scope.addDeclaration(node, 'param');
});
}
};
BlockStatement.prototype.initialise = function initialise (transforms) {
this.thisAlias = null;
this.argumentsAlias = null;
this.defaultParameters = [];
this.createdDeclarations = [];
// normally the scope gets created here, during initialisation,
// but in some cases (e.g. `for` statements), we need to create
// the scope early, as it pertains to both the init block and
// the body of the statement
if (!this.scope) { this.createScope(); }
this.body.forEach(function (node) { return node.initialise(transforms); });
this.scope.consolidate();
};
BlockStatement.prototype.findLexicalBoundary = function findLexicalBoundary () {
if (this.type === 'Program') { return this; }
if (/^Function/.test(this.parent.type)) { return this; }
return this.parent.findLexicalBoundary();
};
BlockStatement.prototype.findScope = function findScope (functionScope) {
if (functionScope && !this.isFunctionBlock)
{ return this.parent.findScope(functionScope); }
return this.scope;
};
BlockStatement.prototype.getArgumentsAlias = function getArgumentsAlias () {
if (!this.argumentsAlias) {
this.argumentsAlias = this.scope.createIdentifier('arguments');
}
return this.argumentsAlias;
};
BlockStatement.prototype.getArgumentsArrayAlias = function getArgumentsArrayAlias () {
if (!this.argumentsArrayAlias) {
this.argumentsArrayAlias = this.scope.createIdentifier('argsArray');
}
return this.argumentsArrayAlias;
};
BlockStatement.prototype.getThisAlias = function getThisAlias () {
if (!this.thisAlias) {
this.thisAlias = this.scope.createIdentifier('this');
}
return this.thisAlias;
};
BlockStatement.prototype.getIndentation = function getIndentation () {
if (this.indentation === undefined) {
var source = this.program.magicString.original;
var useOuter = this.synthetic || !this.body.length;
var c = useOuter ? this.start : this.body[0].start;
while (c && source[c] !== '\n') { c -= 1; }
this.indentation = '';
// eslint-disable-next-line no-constant-condition
while (true) {
c += 1;
var char = source[c];
if (char !== ' ' && char !== '\t') { break; }
this.indentation += char;
}
var indentString = this.program.magicString.getIndentString();
// account for dedented class constructors
var parent = this.parent;
while (parent) {
if (parent.kind === 'constructor' && !parent.parent.parent.superClass) {
this.indentation = this.indentation.replace(indentString, '');
}
parent = parent.parent;
}
if (useOuter) { this.indentation += indentString; }
}
return this.indentation;
};
BlockStatement.prototype.transpile = function transpile (code, transforms) {
var this$1 = this;
var indentation = this.getIndentation();
var introStatementGenerators = [];
if (this.argumentsAlias) {
introStatementGenerators.push(function (start, prefix, suffix) {
var assignment = prefix + "var " + (this$1.argumentsAlias) + " = arguments" + suffix;
code.appendLeft(start, assignment);
});
}
if (this.thisAlias) {
introStatementGenerators.push(function (start, prefix, suffix) {
var assignment = prefix + "var " + (this$1.thisAlias) + " = this" + suffix;
code.appendLeft(start, assignment);
});
}
if (this.argumentsArrayAlias) {
introStatementGenerators.push(function (start, prefix, suffix) {
var i = this$1.scope.createIdentifier('i');
var assignment = prefix + "var " + i + " = arguments.length, " + (this$1.argumentsArrayAlias) + " = Array(" + i + ");\n" + indentation + "while ( " + i + "-- ) " + (this$1.argumentsArrayAlias) + "[" + i + "] = arguments[" + i + "]" + suffix;
code.appendLeft(start, assignment);
});
}
if (/Function/.test(this.parent.type)) {
this.transpileParameters(
this.parent.params,
code,
transforms,
indentation,
introStatementGenerators
);
} else if ('CatchClause' === this.parent.type) {
this.transpileParameters(
[this.parent.param],
code,
transforms,
indentation,
introStatementGenerators
);
}
if (transforms.letConst && this.isFunctionBlock) {
this.transpileBlockScopedIdentifiers(code);
}
Node.prototype.transpile.call(this, code, transforms);
if (this.createdDeclarations.length) {
introStatementGenerators.push(function (start, prefix, suffix) {
var assignment = prefix + "var " + (this$1.createdDeclarations.join(', ')) + suffix;
code.appendLeft(start, assignment);
});
}
if (this.synthetic) {
if (this.parent.type === 'ArrowFunctionExpression') {
var expr = this.body[0];
if (introStatementGenerators.length) {
code
.appendLeft(this.start, "{")
.prependRight(this.end, ((this.parent.getIndentation()) + "}"));
code.prependRight(expr.start, ("\n" + indentation + "return "));
code.appendLeft(expr.end, ";\n");
} else if (transforms.arrow) {
code.prependRight(expr.start, "{ return ");
code.appendLeft(expr.end, "; }");
}
} else if (introStatementGenerators.length) {
code.prependRight(this.start, "{").appendLeft(this.end, "}");
}
}
var start;
if (isUseStrict(this.body[0])) {
start = this.body[0].end;
} else if (this.synthetic || this.parent.type === 'Root') {
start = this.start;
} else {
start = this.start + 1;
}
var prefix = "\n" + indentation;
var suffix = ';';
introStatementGenerators.forEach(function (fn, i) {
if (i === introStatementGenerators.length - 1) { suffix = ";\n"; }
fn(start, prefix, suffix);
});
};
BlockStatement.prototype.transpileParameters = function transpileParameters (params, code, transforms, indentation, introStatementGenerators) {
var this$1 = this;
params.forEach(function (param) {
if (
param.type === 'AssignmentPattern' &&
param.left.type === 'Identifier'
) {
if (transforms.defaultParameter) {
introStatementGenerators.push(function (start, prefix, suffix) {
var lhs = prefix + "if ( " + (param.left.name) + " === void 0 ) " + (param.left.name);
code
.prependRight(param.left.end, lhs)
.move(param.left.end, param.right.end, start)
.appendLeft(param.right.end, suffix);
});
}
} else if (param.type === 'RestElement') {
if (transforms.spreadRest) {
introStatementGenerators.push(function (start, prefix, suffix) {
var penultimateParam = params[params.length - 2];
if (penultimateParam) {
code.remove(
penultimateParam ? penultimateParam.end : param.start,
param.end
);
} else {
var start$1 = param.start,
end = param.end; // TODO https://gitlab.com/Rich-Harris/buble/issues/8
while (/\s/.test(code.original[start$1 - 1])) { start$1 -= 1; }
while (/\s/.test(code.original[end])) { end += 1; }
code.remove(start$1, end);
}
var name = param.argument.name;
var len = this$1.scope.createIdentifier('len');
var count = params.length - 1;
if (count) {
code.prependRight(
start,
(prefix + "var " + name + " = [], " + len + " = arguments.length - " + count + ";\n" + indentation + "while ( " + len + "-- > 0 ) " + name + "[ " + len + " ] = arguments[ " + len + " + " + count + " ]" + suffix)
);
} else {
code.prependRight(
start,
(prefix + "var " + name + " = [], " + len + " = arguments.length;\n" + indentation + "while ( " + len + "-- ) " + name + "[ " + len + " ] = arguments[ " + len + " ]" + suffix)
);
}
});
}
} else if (param.type !== 'Identifier') {
if (transforms.parameterDestructuring) {
var ref = this$1.scope.createIdentifier('ref');
destructure(
code,
function (id) { return this$1.scope.createIdentifier(id); },
function (ref) {
var name = ref.name;
return this$1.scope.resolveName(name);
},
param,
ref,
false,
introStatementGenerators
);
code.prependRight(param.start, ref);
}
}
});
};
BlockStatement.prototype.transpileBlockScopedIdentifiers = function transpileBlockScopedIdentifiers (code) {
var this$1 = this;
Object.keys(this.scope.blockScopedDeclarations).forEach(function (name) {
var declarations = this$1.scope.blockScopedDeclarations[name];
for (var i$2 = 0, list$2 = declarations; i$2 < list$2.length; i$2 += 1) {
var declaration = list$2[i$2];
var cont = false; // TODO implement proper continue...
if (declaration.kind === 'for.let') {
// special case
var forStatement = declaration.node.findNearest('ForStatement');
if (forStatement.shouldRewriteAsFunction) {
var outerAlias = this$1.scope.createIdentifier(name);
var innerAlias = forStatement.reassigned[name]
? this$1.scope.createIdentifier(name)
: name;
declaration.name = outerAlias;
code.overwrite(
declaration.node.start,
declaration.node.end,
outerAlias,
{ storeName: true }
);
forStatement.aliases[name] = {
outer: outerAlias,
inner: innerAlias
};
for (var i = 0, list = declaration.instances; i < list.length; i += 1) {
var identifier = list[i];
var alias = forStatement.body.contains(identifier)
? innerAlias
: outerAlias;
if (name !== alias) {
code.overwrite(identifier.start, identifier.end, alias, {
storeName: true
});
}
}
cont = true;
}
}
if (!cont) {
var alias$1 = this$1.scope.createIdentifier(name);
if (name !== alias$1) {
var declarationParent = declaration.node.parent;
declaration.name = alias$1;
code.overwrite(
declaration.node.start,
declaration.node.end,
alias$1,
{ storeName: true }
);
if (declarationParent.type === 'Property' && declarationParent.shorthand) {
declarationParent.shorthand = false;
code.prependLeft(declaration.node.start, (name + ": "));
}
for (var i$1 = 0, list$1 = declaration.instances; i$1 < list$1.length; i$1 += 1) {
var identifier$1 = list$1[i$1];
identifier$1.rewritten = true;
var identifierParent = identifier$1.parent;
code.overwrite(identifier$1.start, identifier$1.end, alias$1, {
storeName: true
});
if (identifierParent.type === 'Property' && identifierParent.shorthand) {
identifierParent.shorthand = false;
code.prependLeft(identifier$1.start, (name + ": "));
}
}
}
}
}
});
};
return BlockStatement;
}(Node));
function isArguments(node) {
return node.type === 'Identifier' && node.name === 'arguments';
}
function inlineSpreads(
code,
node,
elements
) {
var i = elements.length;
while (i--) {
var element = elements[i];
if (!element || element.type !== 'SpreadElement') {
continue;
}
var argument = element.argument;
if (argument.type !== 'ArrayExpression') {
continue;
}
var subelements = argument.elements;
if (subelements.some(function (subelement) { return subelement === null; })) {
// Not even going to try inlining spread arrays with holes.
// It's a lot of work (got to be VERY careful in comma counting for
// ArrayExpression, and turn blanks into undefined for
// CallExpression and NewExpression), and probably literally no one
// would ever benefit from it.
continue;
}
// We can inline it: drop the `...[` and `]` and sort out any commas.
var isLast = i === elements.length - 1;
if (subelements.length === 0) {
code.remove(
isLast && i !== 0
? elements[i - 1].end // Take the previous comma too
: element.start,
isLast
? node.end - 1 // Must remove trailing comma; element.end wouldn’t
: elements[i + 1].start);
} else {
// Strip the `...[` and the `]` with a possible trailing comma before it,
// leaving just the possible trailing comma after it.
code.remove(element.start, subelements[0].start);
code.remove(
// Strip a possible trailing comma after the last element
subelements[subelements.length - 1].end,
// And also a possible trailing comma after the spread
isLast
? node.end - 1
: element.end
);
}
elements.splice.apply(elements, [ i, 1 ].concat( subelements ));
i += subelements.length;
}
}
// Returns false if it’s safe to simply append a method call to the node,
// e.g. `a` → `a.concat()`.
//
// Returns true if it may not be and so parentheses should be employed,
// e.g. `a ? b : c` → `a ? b : c.concat()` would be wrong.
//
// This test may be overcautious; if desired it can be refined over time.
function needsParentheses(node) {
switch (node.type) {
// Currently whitelisted are all relevant ES5 node types ('Literal' and
// 'ObjectExpression' are skipped as irrelevant for array/call spread.)
case 'ArrayExpression':
case 'CallExpression':
case 'Identifier':
case 'ParenthesizedExpression':
case 'ThisExpression':
return false;
default:
return true;
}
}
function spread(
code,
elements,
start,
argumentsArrayAlias,
isNew
) {
var i = elements.length;
var firstSpreadIndex = -1;
while (i--) {
var element$1 = elements[i];
if (element$1 && element$1.type === 'SpreadElement') {
if (isArguments(element$1.argument)) {
code.overwrite(
element$1.argument.start,
element$1.argument.end,
argumentsArrayAlias
);
}
firstSpreadIndex = i;
}
}
if (firstSpreadIndex === -1) { return false; } // false indicates no spread elements
if (isNew) {
for (i = 0; i < elements.length; i += 1) {
var element$2 = elements[i];
if (element$2.type === 'SpreadElement') {
code.remove(element$2.start, element$2.argument.start);
} else {
code.prependRight(element$2.start, '[');
code.prependRight(element$2.end, ']');
}
}
return true; // true indicates some spread elements
}
var element = elements[firstSpreadIndex];
var previousElement = elements[firstSpreadIndex - 1];
if (!previousElement) {
// We may need to parenthesize it to handle ternaries like [...a ? b : c].
var addClosingParen;
if (start !== element.start) {
if ((addClosingParen = needsParentheses(element.argument))) {
code.overwrite(start, element.start, '( ');
} else {
code.remove(start, element.start);
}
} else if (element.parent.type === 'CallExpression') {
// CallExpression inserts `( ` itself, we add the ).
// (Yeah, CallExpression did the needsParentheses call already,
// but we don’t have its result handy, so do it again. It’s cheap.)
addClosingParen = needsParentheses(element.argument);
} else {
// Should be unreachable, but doing this is more robust.
throw new CompileError(
'Unsupported spread construct, please raise an issue at https://github.com/bublejs/buble/issues',
element
);
}
code.overwrite(element.end, elements[1].start,
addClosingParen ? ' ).concat( ' : '.concat( ');
} else {
code.overwrite(previousElement.end, element.start, ' ].concat( ');
}
for (i = firstSpreadIndex; i < elements.length; i += 1) {
element = elements[i];
if (element) {
if (element.type === 'SpreadElement') {
code.remove(element.start, element.argument.start);
} else {
code.appendLeft(element.start, '[');
code.appendLeft(element.end, ']');
}
}
}
return true; // true indicates some spread elements
}
var ArrayExpression = /*@__PURE__*/(function (Node) {
function ArrayExpression () {
Node.apply(this, arguments);
}
if ( Node ) ArrayExpression.__proto__ = Node;
ArrayExpression.prototype = Object.create( Node && Node.prototype );
ArrayExpression.prototype.constructor = ArrayExpression;
ArrayExpression.prototype.initialise = function initialise (transforms) {
if (transforms.spreadRest && this.elements.length) {
var lexicalBoundary = this.findLexicalBoundary();
var i = this.elements.length;
while (i--) {
var element = this.elements[i];
if (
element &&
element.type === 'SpreadElement' &&
isArguments(element.argument)
) {
this.argumentsArrayAlias = lexicalBoundary.getArgumentsArrayAlias();
}
}
}
Node.prototype.initialise.call(this, transforms);
};
ArrayExpression.prototype.transpile = function transpile (code, transforms) {
Node.prototype.transpile.call(this, code, transforms);
if (transforms.spreadRest) {
inlineSpreads(code, this, this.elements);
// erase trailing comma after last array element if not an array hole
if (this.elements.length) {
var lastElement = this.elements[this.elements.length - 1];
if (
lastElement &&
/\s*,/.test(code.original.slice(lastElement.end, this.end))
) {
code.overwrite(lastElement.end, this.end - 1, ' ');
}
}
if (this.elements.length === 1) {
var element = this.elements[0];
if (element && element.type === 'SpreadElement') {
// special case – [ ...arguments ]
if (isArguments(element.argument)) {
code.overwrite(
this.start,
this.end,
("[].concat( " + (this.argumentsArrayAlias) + " )")
); // TODO if this is the only use of argsArray, don't bother concating
} else {
code.overwrite(this.start, element.argument.start, '[].concat( ');
code.overwrite(element.end, this.end, ' )');
}
}
} else {
var hasSpreadElements = spread(
code,
this.elements,
this.start,
this.argumentsArrayAlias
);
if (hasSpreadElements) {
code.overwrite(this.end - 1, this.end, ')');
}
}
}
};
return ArrayExpression;
}(Node));
function removeTrailingComma(code, c) {
while (code.original[c] !== ')') {
if (code.original[c] === ',') {
code.remove(c, c + 1);
return;
}
if (code.original[c] === '/') {
if (code.original[c + 1] === '/') {
c = code.original.indexOf('\n', c);
} else {
c = code.original.indexOf('*/', c) + 1;
}
}
c += 1;
}
}
var ArrowFunctionExpression = /*@__PURE__*/(function (Node) {
function ArrowFunctionExpression () {
Node.apply(this, arguments);
}
if ( Node ) ArrowFunctionExpression.__proto__ = Node;
ArrowFunctionExpression.prototype = Object.create( Node && Node.prototype );
ArrowFunctionExpression.prototype.constructor = ArrowFunctionExpression;
ArrowFunctionExpression.prototype.initialise = function initialise (transforms) {
if (this.async && transforms.asyncAwait) {
CompileError.missingTransform("async arrow functions", "asyncAwait", this);
}
this.body.createScope();
Node.prototype.initialise.call(this, transforms);
};
ArrowFunctionExpression.prototype.transpile = function transpile (code, transforms) {
var openParensPos = this.start;
for (var end = (this.body || this.params[0]).start - 1; code.original[openParensPos] !== '(' && openParensPos < end;) {
++openParensPos;
}
if (code.original[openParensPos] !== '(') { openParensPos = -1; }
var naked = openParensPos === -1;
if (transforms.arrow || this.needsArguments(transforms)) {
// remove arrow
var charIndex = this.body.start;
while (code.original[charIndex] !== '=') {
charIndex -= 1;
}
code.remove(charIndex, this.body.start);
Node.prototype.transpile.call(this, code, transforms);
// wrap naked parameter
if (naked) {
code.prependRight(this.params[0].start, '(');
code.appendLeft(this.params[0].end, ')');
}
// standalone expression statement
var standalone = this.parent && this.parent.type === 'ExpressionStatement';
var start, text = standalone ? '!' : '';
if (this.async) { text += 'async '; }
text += 'function';
if (!standalone) { text += ' '; }
if (naked) {
start = this.params[0].start;
} else {
start = openParensPos;
}
// add function
if (start > this.start) {
code.overwrite(this.start, start, text);
} else {
code.prependRight(this.start, text);
}
} else {
Node.prototype.transpile.call(this, code, transforms);
}
if (transforms.trailingFunctionCommas && this.params.length && !naked) {
removeTrailingComma(code, this.params[this.params.length - 1].end);
}
};
// Returns whether any transforms that will happen use `arguments`
ArrowFunctionExpression.prototype.needsArguments = function needsArguments (transforms) {
return (
transforms.spreadRest &&
this.params.filter(function (param) { return param.type === 'RestElement'; }).length > 0
);
};
return ArrowFunctionExpression;
}(Node));
function checkConst(identifier, scope) {
var declaration = scope.findDeclaration(identifier.name);
if (declaration && declaration.kind === 'const') {
throw new CompileError(((identifier.name) + " is read-only"), identifier);
}
}
var AssignmentExpression = /*@__PURE__*/(function (Node) {
function AssignmentExpression () {
Node.apply(this, arguments);
}
if ( Node ) AssignmentExpression.__proto__ = Node;
AssignmentExpression.prototype = Object.create( Node && Node.prototype );
AssignmentExpression.prototype.constructor = AssignmentExpression;
AssignmentExpression.prototype.initialise = function initialise (transforms) {
if (this.left.type === 'Identifier') {
var declaration = this.findScope(false).findDeclaration(this.left.name);
// special case – https://gitlab.com/Rich-Harris/buble/issues/11
var statement = declaration && declaration.node.ancestor(3);
if (
statement &&
statement.type === 'ForStatement' &&
statement.body.contains(this)
) {
statement.reassigned[this.left.name] = true;
}
}
Node.prototype.initialise.call(this, transforms);
};
AssignmentExpression.prototype.transpile = function transpile (code, transforms) {
if (this.left.type === 'Identifier') {
// Do this check after everything has been initialized to find
// shadowing declarations after this expression
checkConst(this.left, this.findScope(false));
}
if (this.operator === '**=' && transforms.exponentiation) {
this.transpileExponentiation(code, transforms);
} else if (/Pattern/.test(this.left.type) && transforms.destructuring) {
this.transpileDestructuring(code);
}
Node.prototype.transpile.call(this, code, transforms);
};
AssignmentExpression.prototype.transpileDestructuring = function transpileDestructuring (code) {
var this$1 = this;
var writeScope = this.findScope(true);
var lookupScope = this.findScope(false);
var assign = writeScope.createDeclaration('assign');
code.appendRight(this.left.end, ("(" + assign));
code.appendLeft(this.right.end, ', ');
var statementGenerators = [];
destructure(
code,
function (id) { return writeScope.createDeclaration(id); },
function (node) {
var name = lookupScope.resolveName(node.name);
checkConst(node, lookupScope);
return name;
},
this.left,
assign,
true,
statementGenerators
);
var suffix = ', ';
statementGenerators.forEach(function (fn, j) {
if (j === statementGenerators.length - 1) {
suffix = '';
}
fn(this$1.end, '', suffix);
});
if (this.unparenthesizedParent().type === 'ExpressionStatement') {
// no rvalue needed for expression statement
code.prependRight(this.end, ")");
} else {
// destructuring is part of an expression - need an rvalue
code.appendRight(this.end, (", " + assign + ")"));
}
};
AssignmentExpression.prototype.transpileExponentiation = function transpileExponentiation (code) {
var scope = this.findScope(false);
// first, the easy part – `**=` -> `=`
var charIndex = this.left.end;
while (code.original[charIndex] !== '*') { charIndex += 1; }
code.remove(charIndex, charIndex + 2);
// how we do the next part depends on a number of factors – whether
// this is a top-level statement, and whether we're updating a
// simple or complex reference
var base;
var left = this.left.unparenthesize();
if (left.type === 'Identifier') {
base = scope.resolveName(left.name);
} else if (left.type === 'MemberExpression') {
var object;
var needsObjectVar = false;
var property;
var needsPropertyVar = false;
var statement = this.findNearest(/(?:Statement|Declaration)$/);
var i0 = statement.getIndentation();
if (left.property.type === 'Identifier') {
property = left.computed
? scope.resolveName(left.property.name)
: left.property.name;
} else {
property = scope.createDeclaration('property');
needsPropertyVar = true;
}
if (left.object.type === 'Identifier') {
object = scope.resolveName(left.object.name);
} else {
object = scope.createDeclaration('object');
needsObjectVar = true;
}
if (left.start === statement.start) {
if (needsObjectVar && needsPropertyVar) {
code.prependRight(statement.start, (object + " = "));
code.overwrite(
left.object.end,
left.property.start,
(";\n" + i0 + property + " = ")
);
code.overwrite(
left.property.end,
left.end,
(";\n" + i0 + object + "[" + property + "]")
);
} else if (needsObjectVar) {
code.prependRight(statement.start, (object + " = "));
code.appendLeft(left.object.end, (";\n" + i0));
code.appendLeft(left.object.end, object);
} else if (needsPropertyVar) {
code.prependRight(left.property.start, (property + " = "));
code.appendLeft(left.property.end, (";\n" + i0));
code.move(left.property.start, left.property.end, this.start);
code.appendLeft(left.object.end, ("[" + property + "]"));
code.remove(left.object.end, left.property.start);
code.remove(left.property.end, left.end);
}
} else {
if (needsObjectVar && needsPropertyVar) {
code.prependRight(left.start, ("( " + object + " = "));
code.overwrite(
left.object.end,
left.property.start,
(", " + property + " = ")
);
code.overwrite(
left.property.end,
left.end,
(", " + object + "[" + property + "]")
);
} else if (needsObjectVar) {
code.prependRight(left.start, ("( " + object + " = "));
code.appendLeft(left.object.end, (", " + object));
} else if (needsPropertyVar) {
code.prependRight(left.property.start, ("( " + property + " = "));
code.appendLeft(left.property.end, ", ");
code.move(left.property.start, left.property.end, left.start);
code.overwrite(left.object.end, left.property.start, ("[" + property + "]"));
code.remove(left.property.end, left.end);
}
if (needsPropertyVar) {
code.appendLeft(this.end, " )");
}
}
base =
object +
(left.computed || needsPropertyVar ? ("[" + property + "]") : ("." + property));
}
code.prependRight(this.right.start, ("Math.pow( " + base + ", "));
code.appendLeft(this.right.end, " )");
};
return AssignmentExpression;
}(Node));
var AwaitExpression = /*@__PURE__*/(function (Node) {
function AwaitExpression () {
Node.apply(this, arguments);
}
if ( Node ) AwaitExpression.__proto__ = Node;
AwaitExpression.prototype = Object.create( Node && Node.prototype );
AwaitExpression.prototype.constructor = AwaitExpression;
AwaitExpression.prototype.initialise = function initialise (transforms) {
if (transforms.asyncAwait) {
CompileError.missingTransform("await", "asyncAwait", this);
}
Node.prototype.initialise.call(this, transforms);
};
return AwaitExpression;
}(Node));
var BinaryExpression = /*@__PURE__*/(function (Node) {
function BinaryExpression () {
Node.apply(this, arguments);
}
if ( Node ) BinaryExpression.__proto__ = Node;
BinaryExpression.prototype = Object.create( Node && Node.prototype );
BinaryExpression.prototype.constructor = BinaryExpression;
BinaryExpression.prototype.transpile = function transpile (code, transforms) {
if (this.operator === '**' && transforms.exponentiation) {
code.prependRight(this.start, "Math.pow( ");
code.overwrite(this.left.end, this.right.start, ", ");
code.appendLeft(this.end, " )");
}
Node.prototype.transpile.call(this, code, transforms);
};
return BinaryExpression;
}(Node));
var loopStatement = /(?:For(?:In|Of)?|While)Statement/;
var BreakStatement = /*@__PURE__*/(function (Node) {
function BreakStatement () {
Node.apply(this, arguments);
}
if ( Node ) BreakStatement.__proto__ = Node;
BreakStatement.prototype = Object.create( Node && Node.prototype );
BreakStatement.prototype.constructor = BreakStatement;
BreakStatement.prototype.initialise = function initialise () {
var loop = this.findNearest(loopStatement);
var switchCase = this.findNearest('SwitchCase');
if (loop && (!switchCase || loop.depth > switchCase.depth)) {
loop.canBreak = true;
this.loop = loop;
}
};
BreakStatement.prototype.transpile = function transpile (code) {
if (this.loop && this.loop.shouldRewriteAsFunction) {
if (this.label)
{ throw new CompileError(
'Labels are not currently supported in a loop with locally-scoped variables',
this
); }
code.overwrite(this.start, this.start + 5, "return 'break'");
}
};
return BreakStatement;
}(Node));
var CallExpression = /*@__PURE__*/(function (Node) {
function CallExpression () {
Node.apply(this, arguments);
}
if ( Node ) CallExpression.__proto__ = Node;
CallExpression.prototype = Object.create( Node && Node.prototype );
CallExpression.prototype.constructor = CallExpression;
CallExpression.prototype.initialise = function initialise (transforms) {
if (transforms.spreadRest && this.arguments.length > 1) {
var lexicalBoundary = this.findLexicalBoundary();
var i = this.arguments.length;
while (i--) {
var arg = this.arguments[i];
if (arg.type === 'SpreadElement' && isArguments(arg.argument)) {
this.argumentsArrayAlias = lexicalBoundary.getArgumentsArrayAlias();
}
}
}
Node.prototype.initialise.call(this, transforms);
};
CallExpression.prototype.transpile = function transpile (code, transforms) {
if (transforms.spreadRest && this.arguments.length) {
inlineSpreads(code, this, this.arguments);
// this.arguments.length may have changed, must retest.
}
if (transforms.sprea