Socket
Socket
Sign inDemoInstall

buble

Package Overview
Dependencies
Maintainers
2
Versions
109
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

buble - npm Package Compare versions

Comparing version 0.17.3 to 0.18.0

src/utils/removeTrailingComma.js

56

bin/handleError.js

@@ -1,46 +0,58 @@

var chalk = require( 'chalk' );
var chalk = require('chalk');
function print(msg) {
console.error(chalk.red(msg)); // eslint-disable-line no-console
}
var handlers = {
MISSING_INPUT_OPTION: function () {
console.error( chalk.red( 'You must specify an --input (-i) option' ) );
MISSING_INPUT_OPTION: () => {
print('You must specify an --input (-i) option');
},
MISSING_OUTPUT_DIR: function () {
console.error( chalk.red( 'You must specify an --output (-o) option when compiling a directory of files' ) );
MISSING_OUTPUT_DIR: () => {
print(
'You must specify an --output (-o) option when compiling a directory of files'
);
},
MISSING_OUTPUT_FILE: function () {
console.error( chalk.red( 'You must specify an --output (-o) option when creating a file with a sourcemap' ) );
MISSING_OUTPUT_FILE: () => {
print(
'You must specify an --output (-o) option when creating a file with a sourcemap'
);
},
ONE_AT_A_TIME: function ( err ) {
console.error( chalk.red( 'Bublé can only compile one file/directory at a time' ) );
ONE_AT_A_TIME: () => {
print('Bublé can only compile one file/directory at a time');
},
DUPLICATE_IMPORT_OPTIONS: function ( err ) {
console.error( chalk.red( 'use --input, or pass input path as argument – not both' ) );
DUPLICATE_IMPORT_OPTIONS: () => {
print('use --input, or pass input path as argument – not both');
},
BAD_TARGET: function ( err ) {
console.error( chalk.red( 'illegal --target option' ) );
BAD_TARGET: () => {
print('illegal --target option');
}
};
module.exports = function handleError ( err ) {
module.exports = function handleError(err) {
var handler;
if ( handler = handlers[ err && err.code ] ) {
handler( err );
if ((handler = handlers[err && err.code])) {
handler(err);
} else {
if ( err.snippet ) console.error( chalk.red( '---\n' + err.snippet ) );
console.error( chalk.red( err.message || err ) );
if (err.snippet) print('---\n' + err.snippet);
print(err.message || err);
if ( err.stack ) {
console.error( chalk.grey( err.stack ) );
if (err.stack) {
console.error(chalk.grey(err.stack)); // eslint-disable-line no-console
}
}
console.error( 'Type ' + chalk.cyan( 'buble --help' ) + ' for help, or visit https://buble.surge.sh/guide/' );
console.error( // eslint-disable-line no-console
'Type ' +
chalk.cyan('buble --help') +
' for help, or visit https://buble.surge.sh/guide/'
);
process.exit( 1 );
process.exit(1);
};

@@ -1,46 +0,47 @@

var fs = require( 'fs' );
var path = require( 'path' );
var buble = require( '../dist/buble.deps.js' );
var handleError = require( './handleError.js' );
var fs = require('fs');
var path = require('path');
var buble = require('../dist/buble.deps.js');
var handleError = require('./handleError.js');
var EOL = require('os').EOL;
function compile ( from, to, command, options ) {
function compile(from, to, command, options) {
try {
var stats = fs.statSync( from );
if ( stats.isDirectory() ) {
compileDir( from, to, command, options );
var stats = fs.statSync(from);
if (stats.isDirectory()) {
compileDir(from, to, command, options);
} else {
compileFile( from, to, command, options );
compileFile(from, to, command, options);
}
} catch ( err ) {
handleError( err );
} catch (err) {
handleError(err);
}
}
function compileDir ( from, to, command, options ) {
if ( !command.output ) handleError({ code: 'MISSING_OUTPUT_DIR' });
function compileDir(from, to, command, options) {
if (!command.output) handleError({ code: 'MISSING_OUTPUT_DIR' });
try {
fs.mkdirSync( to )
} catch ( e ) {
if ( e.code !== 'EEXIST' ) throw e
fs.mkdirSync(to);
} catch (e) {
if (e.code !== 'EEXIST') throw e;
}
fs.readdirSync( from ).forEach( function ( file ) {
compile( path.resolve( from, file ), path.resolve( to, file ), command, options );
fs.readdirSync(from).forEach(function(file) {
compile(path.resolve(from, file), path.resolve(to, file), command, options);
});
}
function compileFile ( from, to, command, options ) {
var ext = path.extname( from );
function compileFile(from, to, command, options) {
var ext = path.extname(from);
if ( ext !== '.js' && ext !== '.jsm' && ext !== '.es6' && ext !== '.jsx') return;
if (ext !== '.js' && ext !== '.jsm' && ext !== '.es6' && ext !== '.jsx')
return;
if ( to ) {
var extTo = path.extname( to );
to = to.slice( 0, -extTo.length ) + '.js';
if (to) {
var extTo = path.extname(to);
to = to.slice(0, -extTo.length) + '.js';
}
var source = fs.readFileSync( from, 'utf-8' );
var result = buble.transform( source, {
var source = fs.readFileSync(from, 'utf-8');
var result = buble.transform(source, {
target: options.target,

@@ -55,31 +56,31 @@ transforms: options.transforms,

write( result, to, command );
write(result, to, command);
}
function write ( result, to, command ) {
if ( command.sourcemap === 'inline' ) {
function write(result, to, command) {
if (command.sourcemap === 'inline') {
result.code += EOL + '//# sourceMappingURL=' + result.map.toUrl();
} else if ( command.sourcemap ) {
if ( !to ) {
} else if (command.sourcemap) {
if (!to) {
handleError({ code: 'MISSING_OUTPUT_FILE' });
}
result.code += EOL + '//# sourceMappingURL=' + path.basename( to ) + '.map';
fs.writeFileSync( to + '.map', result.map.toString() );
result.code += EOL + '//# sourceMappingURL=' + path.basename(to) + '.map';
fs.writeFileSync(to + '.map', result.map.toString());
}
if ( to ) {
fs.writeFileSync( to, result.code );
if (to) {
fs.writeFileSync(to, result.code);
} else {
console.log( result.code ); // eslint-disable-line no-console
console.log(result.code); // eslint-disable-line no-console
}
}
module.exports = function ( command ) {
if ( command._.length > 1 ) {
module.exports = function(command) {
if (command._.length > 1) {
handleError({ code: 'ONE_AT_A_TIME' });
}
if ( command._.length === 1 ) {
if ( command.input ) {
if (command._.length === 1) {
if (command.input) {
handleError({ code: 'DUPLICATE_IMPORT_OPTIONS' });

@@ -95,54 +96,54 @@ }

jsx: command.jsx,
objectAssign: command.objectAssign === true ? "Object.assign" : command.objectAssign,
namedFunctionExpressions: command["named-function-expr"] !== false
objectAssign:
command.objectAssign === true ? 'Object.assign' : command.objectAssign,
namedFunctionExpressions: command['named-function-expr'] !== false
};
if ( command.target ) {
if ( !/^(?:(\w+):([\d\.]+),)*(\w+):([\d\.]+)$/.test( command.target ) ) {
if (command.target) {
if (!/^(?:(\w+):([\d\.]+),)*(\w+):([\d\.]+)$/.test(command.target)) {
handleError({ code: 'BAD_TARGET' });
}
command.target.split( ',' )
.map( function ( target ) {
return target.split( ':' );
command.target
.split(',')
.map(function(target) {
return target.split(':');
})
.forEach( function ( pair ) {
options.target[ pair[0] ] = pair[1];
.forEach(function(pair) {
options.target[pair[0]] = pair[1];
});
}
if ( command.yes ) {
command.yes.split( ',' ).forEach( function ( transform ) {
options.transforms[ transform ] = true;
if (command.yes) {
command.yes.split(',').forEach(function(transform) {
options.transforms[transform] = true;
});
}
if ( command.no ) {
command.no.split( ',' ).forEach( function ( transform ) {
options.transforms[ transform ] = false;
if (command.no) {
command.no.split(',').forEach(function(transform) {
options.transforms[transform] = false;
});
}
if ( command.input ) {
compile( command.input, command.output, command, options );
}
else {
if (command.input) {
compile(command.input, command.output, command, options);
} else {
process.stdin.resume();
process.stdin.setEncoding( 'utf8' );
process.stdin.setEncoding('utf8');
var source = '';
process.stdin.on( 'data', function ( chunk ) {
process.stdin.on('data', function(chunk) {
source += chunk;
});
process.stdin.on( 'end', function () {
options.source = command.input = "stdin";
process.stdin.on('end', function() {
options.source = command.input = 'stdin';
options.file = command.output;
try {
var result = buble.transform( source, options );
write( result, command.output, command );
} catch ( err ) {
handleError( err );
var result = buble.transform(source, options);
write(result, command.output, command);
} catch (err) {
handleError(err);
}

@@ -149,0 +150,0 @@ });

@@ -1,13 +0,16 @@

var fs = require( 'fs' );
var path = require( 'path' );
var fs = require('fs');
var path = require('path');
module.exports = function () {
fs.readFile( path.join( __dirname, 'help.md' ), function ( err, result ) {
module.exports = function() {
fs.readFile(path.join(__dirname, 'help.md'), (err, result) => {
var help;
if ( err ) throw err;
if (err) throw err;
help = result.toString().replace( '<%= version %>', require( '../package.json' ).version );
console.log( '\n' + help + '\n' );
help = result
.toString()
.replace('<%= version %>', require('../package.json').version);
console.log('\n' + help + '\n'); // eslint-disable-line no-console
});
};
# buble changelog
## 0.18.0
* Allow anonymous functions and classes as default exports ([#37](https://github.com/Rich-Harris/buble/issues/37))
* Handle non-breaking spaces in JSX ([#46](https://github.com/Rich-Harris/buble/issues/46))
* Allow anonymous classes to be assigned to properties ([#33](https://github.com/Rich-Harris/buble/issues/33))
* Add `trailingFunctionCommas` transformation ([#50](https://github.com/Rich-Harris/buble/issues/50))
## 0.17.3

@@ -4,0 +11,0 @@

{
"name": "buble",
"version": "0.17.3",
"version": "0.18.0",
"description": "The blazing fast, batteries-included ES2015 compiler",

@@ -5,0 +5,0 @@ "main": "dist/buble.umd.js",

@@ -17,3 +17,3 @@ var fs = require( 'fs' );

} else {
throw new Error( 'Unsupported version (' + nodeVersion + '). Please raise an issue at https://gitlab.com/Rich-Harris/buble/issues' );
throw new Error( 'Unsupported version (' + nodeVersion + '). Please raise an issue at https://github.com/Rich-Harris/buble/issues' );
}

@@ -20,0 +20,0 @@ }

@@ -8,25 +8,32 @@ import * as acorn from 'acorn';

const { parse } = [
acornObjectSpread,
acornJsx
].reduce( ( final, plugin ) => plugin( final ), acorn );
const { parse } = [acornObjectSpread, acornJsx].reduce(
(final, plugin) => plugin(final),
acorn
);
const dangerousTransforms = [
'dangerousTaggedTemplateString',
'dangerousForOf'
];
const dangerousTransforms = ['dangerousTaggedTemplateString', 'dangerousForOf'];
export function target ( target ) {
const targets = Object.keys( target );
let bitmask = targets.length ?
0b1111111111111111111111111111111 :
0b1000000000000000000000000000000;
export function target(target) {
const targets = Object.keys(target);
let bitmask = targets.length
? 0b11111111111111111111111111111111
: 0b01000000000000000000000000000000;
Object.keys( target ).forEach( environment => {
const versions = matrix[ environment ];
if ( !versions ) throw new Error( `Unknown environment '${environment}'. Please raise an issue at https://gitlab.com/Rich-Harris/buble/issues` );
Object.keys(target).forEach(environment => {
const versions = matrix[environment];
if (!versions)
throw new Error(
`Unknown environment '${environment}'. Please raise an issue at https://github.com/Rich-Harris/buble/issues`
);
const targetVersion = target[ environment ];
if ( !( targetVersion in versions ) ) throw new Error( `Support data exists for the following versions of ${environment}: ${Object.keys( versions ).join( ', ')}. Please raise an issue at https://gitlab.com/Rich-Harris/buble/issues` );
const support = versions[ targetVersion ];
const targetVersion = target[environment];
if (!(targetVersion in versions))
throw new Error(
`Support data exists for the following versions of ${environment}: ${Object.keys(
versions
).join(
', '
)}. Please raise an issue at https://github.com/Rich-Harris/buble/issues`
);
const support = versions[targetVersion];

@@ -36,9 +43,9 @@ bitmask &= support;

let transforms = Object.create( null );
features.forEach( ( name, i ) => {
transforms[ name ] = !( bitmask & 1 << i );
let transforms = Object.create(null);
features.forEach((name, i) => {
transforms[name] = !(bitmask & (1 << i));
});
dangerousTransforms.forEach( name => {
transforms[ name ] = false;
dangerousTransforms.forEach(name => {
transforms[name] = false;
});

@@ -49,3 +56,3 @@

export function transform ( source, options = {} ) {
export function transform(source, options = {}) {
let ast;

@@ -55,3 +62,3 @@ let jsx = null;

try {
ast = parse( source, {
ast = parse(source, {
ecmaVersion: 8,

@@ -61,5 +68,5 @@ preserveParens: true,

onComment: (block, text) => {
if ( !jsx ) {
let match = /@jsx\s+([^\s]+)/.exec( text );
if ( match ) jsx = match[1];
if (!jsx) {
let match = /@jsx\s+([^\s]+)/.exec(text);
if (match) jsx = match[1];
}

@@ -73,4 +80,4 @@ },

options.jsx = jsx || options.jsx;
} catch ( err ) {
err.snippet = getSnippet( source, err.loc );
} catch (err) {
err.snippet = getSnippet(source, err.loc);
err.toString = () => `${err.name}: ${err.message}\n${err.snippet}`;

@@ -80,17 +87,19 @@ throw err;

let transforms = target( options.target || {} );
Object.keys( options.transforms || {} ).forEach( name => {
if ( name === 'modules' ) {
if ( !( 'moduleImport' in options.transforms ) ) transforms.moduleImport = options.transforms.modules;
if ( !( 'moduleExport' in options.transforms ) ) transforms.moduleExport = options.transforms.modules;
let transforms = target(options.target || {});
Object.keys(options.transforms || {}).forEach(name => {
if (name === 'modules') {
if (!('moduleImport' in options.transforms))
transforms.moduleImport = options.transforms.modules;
if (!('moduleExport' in options.transforms))
transforms.moduleExport = options.transforms.modules;
return;
}
if ( !( name in transforms ) ) throw new Error( `Unknown transform '${name}'` );
transforms[ name ] = options.transforms[ name ];
if (!(name in transforms)) throw new Error(`Unknown transform '${name}'`);
transforms[name] = options.transforms[name];
});
return new Program( source, ast, transforms, options ).export( options );
return new Program(source, ast, transforms, options).export(options);
}
export { version as VERSION } from '../package.json';

@@ -6,6 +6,6 @@ import './wrap.js'; // TODO necessary for ordering. sort it out

function isUseStrict ( node ) {
if ( !node ) return false;
if ( node.type !== 'ExpressionStatement' ) return false;
if ( node.expression.type !== 'Literal' ) return false;
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';

@@ -15,13 +15,13 @@ }

export default class BlockStatement extends Node {
createScope () {
this.parentIsFunction = /Function/.test( this.parent.type );
createScope() {
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 )
parent: this.parent.findScope(false)
});
if ( this.parentIsFunction ) {
this.parent.params.forEach( node => {
this.scope.addDeclaration( node, 'param' );
if (this.parentIsFunction) {
this.parent.params.forEach(node => {
this.scope.addDeclaration(node, 'param');
});

@@ -31,6 +31,7 @@ }

initialise ( transforms ) {
initialise(transforms) {
this.thisAlias = null;
this.argumentsAlias = null;
this.defaultParameters = [];
this.createdDeclarations = [];

@@ -41,5 +42,5 @@ // normally the scope gets created here, during initialisation,

// the body of the statement
if ( !this.scope ) this.createScope();
if (!this.scope) this.createScope();
this.body.forEach( node => node.initialise( transforms ) );
this.body.forEach(node => node.initialise(transforms));

@@ -49,5 +50,5 @@ this.scope.consolidate();

findLexicalBoundary () {
if ( this.type === 'Program' ) return this;
if ( /^Function/.test( this.parent.type ) ) return this;
findLexicalBoundary() {
if (this.type === 'Program') return this;
if (/^Function/.test(this.parent.type)) return this;

@@ -57,10 +58,11 @@ return this.parent.findLexicalBoundary();

findScope ( functionScope ) {
if ( functionScope && !this.isFunctionBlock ) return this.parent.findScope( functionScope );
findScope(functionScope) {
if (functionScope && !this.isFunctionBlock)
return this.parent.findScope(functionScope);
return this.scope;
}
getArgumentsAlias () {
if ( !this.argumentsAlias ) {
this.argumentsAlias = this.scope.createIdentifier( 'arguments' );
getArgumentsAlias() {
if (!this.argumentsAlias) {
this.argumentsAlias = this.scope.createIdentifier('arguments');
}

@@ -71,5 +73,5 @@

getArgumentsArrayAlias () {
if ( !this.argumentsArrayAlias ) {
this.argumentsArrayAlias = this.scope.createIdentifier( 'argsArray' );
getArgumentsArrayAlias() {
if (!this.argumentsArrayAlias) {
this.argumentsArrayAlias = this.scope.createIdentifier('argsArray');
}

@@ -80,5 +82,5 @@

getThisAlias () {
if ( !this.thisAlias ) {
this.thisAlias = this.scope.createIdentifier( 'this' );
getThisAlias() {
if (!this.thisAlias) {
this.thisAlias = this.scope.createIdentifier('this');
}

@@ -89,4 +91,4 @@

getIndentation () {
if ( this.indentation === undefined ) {
getIndentation() {
if (this.indentation === undefined) {
const source = this.program.magicString.original;

@@ -97,11 +99,12 @@

while ( c && source[c] !== '\n' ) c -= 1;
while (c && source[c] !== '\n') c -= 1;
this.indentation = '';
while ( true ) { // eslint-disable-line no-constant-condition
// eslint-disable-next-line no-constant-condition
while (true) {
c += 1;
const char = source[c];
if ( char !== ' ' && char !== '\t' ) break;
if (char !== ' ' && char !== '\t') break;

@@ -115,5 +118,5 @@ this.indentation += char;

let parent = this.parent;
while ( parent ) {
if ( parent.kind === 'constructor' && !parent.parent.parent.superClass ) {
this.indentation = this.indentation.replace( indentString, '' );
while (parent) {
if (parent.kind === 'constructor' && !parent.parent.parent.superClass) {
this.indentation = this.indentation.replace(indentString, '');
}

@@ -124,3 +127,3 @@

if ( useOuter ) this.indentation += indentString;
if (useOuter) this.indentation += indentString;
}

@@ -131,3 +134,3 @@

transpile ( code, transforms ) {
transpile(code, transforms) {
const indentation = this.getIndentation();

@@ -137,58 +140,76 @@

if ( this.argumentsAlias ) {
introStatementGenerators.push( ( start, prefix, suffix ) => {
const assignment = `${prefix}var ${this.argumentsAlias} = arguments${suffix}`;
code.appendLeft( start, assignment );
if (this.argumentsAlias) {
introStatementGenerators.push((start, prefix, suffix) => {
const assignment = `${prefix}var ${this.argumentsAlias} = arguments${
suffix
}`;
code.appendLeft(start, assignment);
});
}
if ( this.thisAlias ) {
introStatementGenerators.push( ( start, prefix, suffix ) => {
if (this.thisAlias) {
introStatementGenerators.push((start, prefix, suffix) => {
const assignment = `${prefix}var ${this.thisAlias} = this${suffix}`;
code.appendLeft( start, assignment );
code.appendLeft(start, assignment);
});
}
if ( this.argumentsArrayAlias ) {
introStatementGenerators.push( ( start, prefix, suffix ) => {
const i = this.scope.createIdentifier( 'i' );
const assignment = `${prefix}var ${i} = arguments.length, ${this.argumentsArrayAlias} = Array(${i});\n${indentation}while ( ${i}-- ) ${this.argumentsArrayAlias}[${i}] = arguments[${i}]${suffix}`;
code.appendLeft( start, assignment );
if (this.argumentsArrayAlias) {
introStatementGenerators.push((start, prefix, suffix) => {
const i = this.scope.createIdentifier('i');
const assignment = `${prefix}var ${i} = arguments.length, ${
this.argumentsArrayAlias
} = Array(${i});\n${indentation}while ( ${i}-- ) ${
this.argumentsArrayAlias
}[${i}] = arguments[${i}]${suffix}`;
code.appendLeft(start, assignment);
});
}
if ( /Function/.test( this.parent.type ) ) {
this.transpileParameters( code, transforms, indentation, introStatementGenerators );
if (/Function/.test(this.parent.type)) {
this.transpileParameters(
code,
transforms,
indentation,
introStatementGenerators
);
}
if ( transforms.letConst && this.isFunctionBlock ) {
this.transpileBlockScopedIdentifiers( code );
if (transforms.letConst && this.isFunctionBlock) {
this.transpileBlockScopedIdentifiers(code);
}
super.transpile( code, transforms );
super.transpile(code, transforms);
if ( this.synthetic ) {
if ( this.parent.type === 'ArrowFunctionExpression' ) {
if (this.createdDeclarations.length) {
introStatementGenerators.push((start, prefix, suffix) => {
const assignment = `${prefix}var ${this.createdDeclarations.join(', ')}${suffix}`;
code.appendLeft(start, assignment);
});
}
if (this.synthetic) {
if (this.parent.type === 'ArrowFunctionExpression') {
const expr = this.body[0];
if ( introStatementGenerators.length ) {
code.appendLeft( this.start, `{` ).prependRight( this.end, `${this.parent.getIndentation()}}` );
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, `; }` );
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, `}`);
}
else if ( introStatementGenerators.length ) {
code.prependRight( this.start, `{` ).appendLeft( this.end, `}` );
}
}
let start;
if ( isUseStrict( this.body[0] ) ) {
if (isUseStrict(this.body[0])) {
start = this.body[0].end;
} else if ( this.synthetic || this.parent.type === 'Root' ) {
} else if (this.synthetic || this.parent.type === 'Root') {
start = this.start;

@@ -201,59 +222,91 @@ } else {

let suffix = ';';
introStatementGenerators.forEach( ( fn, i ) => {
if ( i === introStatementGenerators.length - 1 ) suffix = `;\n`;
fn( start, prefix, suffix );
introStatementGenerators.forEach((fn, i) => {
if (i === introStatementGenerators.length - 1) suffix = `;\n`;
fn(start, prefix, suffix);
});
}
transpileParameters ( code, transforms, indentation, introStatementGenerators ) {
declareIdentifier(name) {
const id = this.scope.createIdentifier(name);
this.createdDeclarations.push(id);
return id;
}
transpileParameters(code, transforms, indentation, introStatementGenerators) {
const params = this.parent.params;
params.forEach( param => {
if ( param.type === 'AssignmentPattern' && param.left.type === 'Identifier' ) {
if ( transforms.defaultParameter ) {
introStatementGenerators.push( ( start, prefix, suffix ) => {
const lhs = `${prefix}if ( ${param.left.name} === void 0 ) ${param.left.name}`;
params.forEach(param => {
if (
param.type === 'AssignmentPattern' &&
param.left.type === 'Identifier'
) {
if (transforms.defaultParameter) {
introStatementGenerators.push((start, prefix, suffix) => {
const 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 );
.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((start, prefix, suffix) => {
const penultimateParam = params[params.length - 2];
else if ( param.type === 'RestElement' ) {
if ( transforms.spreadRest ) {
introStatementGenerators.push( ( start, prefix, suffix ) => {
const penultimateParam = params[ params.length - 2 ];
if ( penultimateParam ) {
code.remove( penultimateParam ? penultimateParam.end : param.start, param.end );
if (penultimateParam) {
code.remove(
penultimateParam ? penultimateParam.end : param.start,
param.end
);
} else {
let start = param.start, end = param.end; // TODO https://gitlab.com/Rich-Harris/buble/issues/8
let start = param.start,
end = param.end; // TODO https://gitlab.com/Rich-Harris/buble/issues/8
while ( /\s/.test( code.original[ start - 1 ] ) ) start -= 1;
while ( /\s/.test( code.original[ end ] ) ) end += 1;
while (/\s/.test(code.original[start - 1])) start -= 1;
while (/\s/.test(code.original[end])) end += 1;
code.remove( start, end );
code.remove(start, end);
}
const name = param.argument.name;
const len = this.scope.createIdentifier( 'len' );
const len = this.scope.createIdentifier('len');
const 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}` );
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}` );
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 ) {
const ref = this.scope.createIdentifier( 'ref' );
destructure( code, this.scope, param, ref, false, introStatementGenerators );
code.prependRight( param.start, ref );
} else if (param.type !== 'Identifier') {
if (transforms.parameterDestructuring) {
const ref = this.scope.createIdentifier('ref');
destructure(
code,
this.scope,
param,
ref,
false,
introStatementGenerators
);
code.prependRight(param.start, ref);
}

@@ -264,23 +317,28 @@ }

transpileBlockScopedIdentifiers ( code ) {
Object.keys( this.scope.blockScopedDeclarations ).forEach( name => {
const declarations = this.scope.blockScopedDeclarations[ name ];
transpileBlockScopedIdentifiers(code) {
Object.keys(this.scope.blockScopedDeclarations).forEach(name => {
const declarations = this.scope.blockScopedDeclarations[name];
for ( let declaration of declarations ) {
for (let declaration of declarations) {
let cont = false; // TODO implement proper continue...
if ( declaration.kind === 'for.let' ) {
if (declaration.kind === 'for.let') {
// special case
const forStatement = declaration.node.findNearest( 'ForStatement' );
const forStatement = declaration.node.findNearest('ForStatement');
if ( forStatement.shouldRewriteAsFunction ) {
const outerAlias = this.scope.createIdentifier( name );
const innerAlias = forStatement.reassigned[ name ] ?
this.scope.createIdentifier( name ) :
name;
if (forStatement.shouldRewriteAsFunction) {
const outerAlias = this.scope.createIdentifier(name);
const innerAlias = forStatement.reassigned[name]
? this.scope.createIdentifier(name)
: name;
declaration.name = outerAlias;
code.overwrite( declaration.node.start, declaration.node.end, outerAlias, { storeName: true });
code.overwrite(
declaration.node.start,
declaration.node.end,
outerAlias,
{ storeName: true }
);
forStatement.aliases[ name ] = {
forStatement.aliases[name] = {
outer: outerAlias,

@@ -290,9 +348,11 @@ inner: innerAlias

for ( const identifier of declaration.instances ) {
const alias = forStatement.body.contains( identifier ) ?
innerAlias :
outerAlias;
for (const identifier of declaration.instances) {
const alias = forStatement.body.contains(identifier)
? innerAlias
: outerAlias;
if ( name !== alias ) {
code.overwrite( identifier.start, identifier.end, alias, { storeName: true });
if (name !== alias) {
code.overwrite(identifier.start, identifier.end, alias, {
storeName: true
});
}

@@ -305,12 +365,19 @@ }

if ( !cont ) {
const alias = this.scope.createIdentifier( name );
if (!cont) {
const alias = this.scope.createIdentifier(name);
if ( name !== alias ) {
if (name !== alias) {
declaration.name = alias;
code.overwrite( declaration.node.start, declaration.node.end, alias, { storeName: true });
code.overwrite(
declaration.node.start,
declaration.node.end,
alias,
{ storeName: true }
);
for ( const identifier of declaration.instances ) {
for (const identifier of declaration.instances) {
identifier.rewritten = true;
code.overwrite( identifier.start, identifier.end, alias, { storeName: true });
code.overwrite(identifier.start, identifier.end, alias, {
storeName: true
});
}

@@ -317,0 +384,0 @@ }

@@ -1,4 +0,4 @@

export default function extractNames ( node ) {
export default function extractNames(node) {
const names = [];
extractors[ node.type ]( names, node );
extractors[node.type](names, node);
return names;

@@ -8,29 +8,29 @@ }

const extractors = {
Identifier ( names, node ) {
names.push( node );
Identifier(names, node) {
names.push(node);
},
ObjectPattern ( names, node ) {
for ( const prop of node.properties ) {
extractors[ prop.type ]( names, prop );
ObjectPattern(names, node) {
for (const prop of node.properties) {
extractors[prop.type](names, prop);
}
},
Property ( names, node ) {
extractors[ node.value.type ]( names, node.value );
Property(names, node) {
extractors[node.value.type](names, node.value);
},
ArrayPattern ( names, node ) {
for ( const element of node.elements ) {
if ( element ) extractors[ element.type ]( names, element );
ArrayPattern(names, node) {
for (const element of node.elements) {
if (element) extractors[element.type](names, element);
}
},
RestElement ( names, node ) {
extractors[ node.argument.type ]( names, node.argument );
RestElement(names, node) {
extractors[node.argument.type](names, node.argument);
},
AssignmentPattern ( names, node ) {
extractors[ node.left.type ]( names, node.left );
AssignmentPattern(names, node) {
extractors[node.left.type](names, node.left);
}
};
export default {
Program: [ 'body' ],
Program: ['body'],
Literal: []
};

@@ -6,14 +6,20 @@ import wrap from './wrap.js';

// circular references
function toJSON ( node ) {
function toJSON(node) {
var obj = {};
Object.keys( node ).forEach( key => {
if ( key === 'parent' || key === 'program' || key === 'keys' || key === '__wrapped' ) return;
Object.keys(node).forEach(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();
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 ];
obj[key] = node[key];
}

@@ -26,22 +32,22 @@ });

export default class Node {
constructor ( raw, parent ) {
constructor(raw, parent) {
raw.parent = parent;
raw.program = parent.program || parent;
raw.depth = parent.depth + 1;
raw.keys = keys[ raw.type ];
raw.keys = keys[raw.type];
raw.indentation = undefined;
for ( const key of keys[ raw.type ] ) {
wrap( raw[ key ], raw );
for (const key of keys[raw.type]) {
wrap(raw[key], raw);
}
raw.program.magicString.addSourcemapLocation( raw.start );
raw.program.magicString.addSourcemapLocation( raw.end );
raw.program.magicString.addSourcemapLocation(raw.start);
raw.program.magicString.addSourcemapLocation(raw.end);
}
ancestor ( level ) {
ancestor(level) {
let node = this;
while ( level-- ) {
while (level--) {
node = node.parent;
if ( !node ) return null;
if (!node) return null;
}

@@ -52,5 +58,5 @@

contains ( node ) {
while ( node ) {
if ( node === this ) return true;
contains(node) {
while (node) {
if (node === this) return true;
node = node.parent;

@@ -62,15 +68,15 @@ }

findLexicalBoundary () {
findLexicalBoundary() {
return this.parent.findLexicalBoundary();
}
findNearest ( type ) {
if ( typeof type === 'string' ) type = new RegExp( `^${type}$` );
if ( type.test( this.type ) ) return this;
return this.parent.findNearest( type );
findNearest(type) {
if (typeof type === 'string') type = new RegExp(`^${type}$`);
if (type.test(this.type)) return this;
return this.parent.findNearest(type);
}
unparenthesizedParent () {
unparenthesizedParent() {
let node = this.parent;
while ( node && node.type === 'ParenthesizedExpression' ) {
while (node && node.type === 'ParenthesizedExpression') {
node = node.parent;

@@ -81,5 +87,5 @@ }

unparenthesize () {
unparenthesize() {
let node = this;
while ( node.type === 'ParenthesizedExpression' ) {
while (node.type === 'ParenthesizedExpression') {
node = node.expression;

@@ -90,18 +96,18 @@ }

findScope ( functionScope ) {
return this.parent.findScope( functionScope );
findScope(functionScope) {
return this.parent.findScope(functionScope);
}
getIndentation () {
getIndentation() {
return this.parent.getIndentation();
}
initialise ( transforms ) {
for ( var key of this.keys ) {
const value = this[ key ];
initialise(transforms) {
for (var key of this.keys) {
const value = this[key];
if ( Array.isArray( value ) ) {
value.forEach( node => node && node.initialise( transforms ) );
} else if ( value && typeof value === 'object' ) {
value.initialise( transforms );
if (Array.isArray(value)) {
value.forEach(node => node && node.initialise(transforms));
} else if (value && typeof value === 'object') {
value.initialise(transforms);
}

@@ -111,18 +117,18 @@ }

toJSON () {
return toJSON( this );
toJSON() {
return toJSON(this);
}
toString () {
return this.program.magicString.original.slice( this.start, this.end );
toString() {
return this.program.magicString.original.slice(this.start, this.end);
}
transpile ( code, transforms ) {
for ( const key of this.keys ) {
const value = this[ key ];
transpile(code, transforms) {
for (const key of this.keys) {
const value = this[key];
if ( Array.isArray( value ) ) {
value.forEach( node => node && node.transpile( code, transforms ) );
} else if ( value && typeof value === 'object' ) {
value.transpile( code, transforms );
if (Array.isArray(value)) {
value.forEach(node => node && node.transpile(code, transforms));
} else if (value && typeof value === 'object') {
value.transpile(code, transforms);
}

@@ -129,0 +135,0 @@ }

@@ -5,3 +5,3 @@ import MagicString from 'magic-string';

export default function Program ( source, ast, transforms, options ) {
export default function Program(source, ast, transforms, options) {
this.type = 'Root';

@@ -14,3 +14,3 @@

this.source = source;
this.magicString = new MagicString( source );
this.magicString = new MagicString(source);

@@ -20,20 +20,20 @@ this.ast = ast;

wrap( this.body = ast, this );
wrap((this.body = ast), this);
this.body.__proto__ = BlockStatement.prototype;
this.indentExclusionElements = [];
this.body.initialise( transforms );
this.body.initialise(transforms);
this.indentExclusions = Object.create( null );
for ( const node of this.indentExclusionElements ) {
for ( let i = node.start; i < node.end; i += 1 ) {
this.indentExclusions[ i ] = true;
this.indentExclusions = Object.create(null);
for (const node of this.indentExclusionElements) {
for (let i = node.start; i < node.end; i += 1) {
this.indentExclusions[i] = true;
}
}
this.body.transpile( this.magicString, transforms );
this.body.transpile(this.magicString, transforms);
}
Program.prototype = {
export ( options = {} ) {
export(options = {}) {
return {

@@ -49,9 +49,9 @@ code: this.magicString.toString(),

findNearest () {
findNearest() {
return null;
},
findScope () {
findScope() {
return null;
}
};
import extractNames from './extractNames.js';
import reserved from '../utils/reserved.js';
export default function Scope ( options ) {
export default function Scope(options) {
options = options || {};

@@ -11,23 +11,24 @@

let scope = this;
while ( scope.isBlockScope ) scope = scope.parent;
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 = this.isBlockScope ? null : Object.create( null );
this.declarations = Object.create(null);
this.references = Object.create(null);
this.blockScopedDeclarations = this.isBlockScope ? null : Object.create(null);
this.aliases = this.isBlockScope ? null : Object.create(null);
}
Scope.prototype = {
addDeclaration ( node, kind ) {
for ( const identifier of extractNames( node ) ) {
addDeclaration(node, kind) {
for (const identifier of extractNames(node)) {
const name = identifier.name;
const declaration = { name, node: identifier, kind, instances: [] };
this.declarations[ name ] = declaration;
this.declarations[name] = declaration;
if ( this.isBlockScope ) {
if ( !this.functionScope.blockScopedDeclarations[ name ] ) this.functionScope.blockScopedDeclarations[ name ] = [];
this.functionScope.blockScopedDeclarations[ name ].push( declaration );
if (this.isBlockScope) {
if (!this.functionScope.blockScopedDeclarations[name])
this.functionScope.blockScopedDeclarations[name] = [];
this.functionScope.blockScopedDeclarations[name].push(declaration);
}

@@ -37,14 +38,15 @@ }

addReference ( identifier ) {
if ( this.consolidated ) {
this.consolidateReference( identifier );
addReference(identifier) {
if (this.consolidated) {
this.consolidateReference(identifier);
} else {
this.identifiers.push( identifier );
this.identifiers.push(identifier);
}
},
consolidate () {
for ( let i = 0; i < this.identifiers.length; i += 1 ) { // we might push to the array during consolidation, so don't cache length
consolidate() {
for (let i = 0; i < this.identifiers.length; i += 1) {
// we might push to the array during consolidation, so don't cache length
const identifier = this.identifiers[i];
this.consolidateReference( identifier );
this.consolidateReference(identifier);
}

@@ -55,25 +57,27 @@

consolidateReference ( identifier ) {
const declaration = this.declarations[ identifier.name ];
if ( declaration ) {
declaration.instances.push( identifier );
consolidateReference(identifier) {
const declaration = this.declarations[identifier.name];
if (declaration) {
declaration.instances.push(identifier);
} else {
this.references[ identifier.name ] = true;
if ( this.parent ) this.parent.addReference( identifier );
this.references[identifier.name] = true;
if (this.parent) this.parent.addReference(identifier);
}
},
contains ( name ) {
return this.declarations[ name ] ||
( this.parent ? this.parent.contains( name ) : false );
contains(name) {
return (
this.declarations[name] ||
(this.parent ? this.parent.contains(name) : false)
);
},
createIdentifier ( base ) {
if ( typeof base === 'number' ) base = base.toString();
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,}/, '_' );
.replace(/\s/g, '')
.replace(/\[([^\]]+)\]/g, '_$1')
.replace(/[^a-zA-Z0-9_$]/g, '_')
.replace(/_{2,}/, '_');

@@ -83,14 +87,21 @@ let name = base;

while ( this.declarations[ name ] || this.references[ name ] || this.aliases[ name ] || name in reserved ) {
while (
this.declarations[name] ||
this.references[name] ||
this.aliases[name] ||
name in reserved
) {
name = `${base}$${counter++}`;
}
this.aliases[ name ] = true;
this.aliases[name] = true;
return name;
},
findDeclaration ( name ) {
return this.declarations[ name ] ||
( this.parent && this.parent.findDeclaration( name ) );
findDeclaration(name) {
return (
this.declarations[name] ||
(this.parent && this.parent.findDeclaration(name))
);
}
};

@@ -5,10 +5,14 @@ import Node from '../Node.js';

export default class ArrayExpression extends Node {
initialise ( transforms ) {
if ( transforms.spreadRest && this.elements.length ) {
initialise(transforms) {
if (transforms.spreadRest && this.elements.length) {
const lexicalBoundary = this.findLexicalBoundary();
let i = this.elements.length;
while ( i-- ) {
while (i--) {
const element = this.elements[i];
if ( element && element.type === 'SpreadElement' && isArguments( element.argument ) ) {
if (
element &&
element.type === 'SpreadElement' &&
isArguments(element.argument)
) {
this.argumentsArrayAlias = lexicalBoundary.getArgumentsArrayAlias();

@@ -19,33 +23,44 @@ }

super.initialise( transforms );
super.initialise(transforms);
}
transpile ( code, transforms ) {
if ( transforms.spreadRest ) {
transpile(code, transforms) {
if (transforms.spreadRest) {
// erase trailing comma after last array element if not an array hole
if ( this.elements.length ) {
let 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) {
let 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 ) {
if (this.elements.length === 1) {
const element = this.elements[0];
if ( element && element.type === 'SpreadElement' ) {
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
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, ' )' );
code.overwrite(this.start, element.argument.start, '[].concat( ');
code.overwrite(element.end, this.end, ' )');
}
}
}
else {
const hasSpreadElements = spread( code, this.elements, this.start, this.argumentsArrayAlias );
} else {
const hasSpreadElements = spread(
code,
this.elements,
this.start,
this.argumentsArrayAlias
);
if ( hasSpreadElements ) {
code.overwrite( this.end - 1, this.end, ')' );
if (hasSpreadElements) {
code.overwrite(this.end - 1, this.end, ')');
}

@@ -55,4 +70,4 @@ }

super.transpile( code, transforms );
super.transpile(code, transforms);
}
}
import Node from '../Node.js';
import removeTrailingComma from '../../utils/removeTrailingComma.js';
export default class ArrowFunctionExpression extends Node {
initialise ( transforms ) {
initialise(transforms) {
this.body.createScope();
super.initialise( transforms );
super.initialise(transforms);
}
transpile ( code, transforms ) {
if ( transforms.arrow || this.needsArguments(transforms) ) {
transpile(code, transforms) {
const naked = this.params.length === 1 && this.start === this.params[0].start;
if (transforms.arrow || this.needsArguments(transforms)) {
// remove arrow
let charIndex = this.body.start;
while ( code.original[ charIndex ] !== '=' ) {
while (code.original[charIndex] !== '=') {
charIndex -= 1;
}
code.remove( charIndex, this.body.start );
code.remove(charIndex, this.body.start);
super.transpile( code, transforms );
super.transpile(code, transforms);
// wrap naked parameter
if ( this.params.length === 1 && this.start === this.params[0].start ) {
code.prependRight( this.params[0].start, '(' );
code.appendLeft( this.params[0].end, ')' );
if (naked) {
code.prependRight(this.params[0].start, '(');
code.appendLeft(this.params[0].end, ')');
}
// add function
if ( this.parent && this.parent.type === 'ExpressionStatement' ) {
if (this.parent && this.parent.type === 'ExpressionStatement') {
// standalone expression statement
code.prependRight( this.start, '!function' );
code.prependRight(this.start, '!function');
} else {
code.prependRight( this.start, 'function ' );
code.prependRight(this.start, 'function ');
}
} else {
super.transpile(code, transforms);
}
else {
super.transpile( code, transforms );
if (transforms.trailingFunctionCommas && this.params.length && !naked) {
removeTrailingComma(code, this.params[this.params.length - 1].end);
}

@@ -42,4 +47,7 @@ }

needsArguments(transforms) {
return transforms.spreadRest && this.params.filter( param => param.type === 'RestElement' ).length > 0
return (
transforms.spreadRest &&
this.params.filter(param => param.type === 'RestElement').length > 0
);
}
}

@@ -5,35 +5,37 @@ import Node from '../Node.js';

export default class AssignmentExpression extends Node {
initialise ( transforms ) {
if ( this.left.type === 'Identifier' ) {
const declaration = this.findScope( false ).findDeclaration( this.left.name );
if ( declaration && declaration.kind === 'const' ) {
throw new CompileError( `${this.left.name} is read-only`, this.left );
initialise(transforms) {
if (this.left.type === 'Identifier') {
const declaration = this.findScope(false).findDeclaration(this.left.name);
if (declaration && declaration.kind === 'const') {
throw new CompileError(`${this.left.name} is read-only`, this.left);
}
// special case – https://gitlab.com/Rich-Harris/buble/issues/11
const statement = declaration && declaration.node.ancestor( 3 );
if ( statement && statement.type === 'ForStatement' && statement.body.contains( this ) ) {
statement.reassigned[ this.left.name ] = true;
const statement = declaration && declaration.node.ancestor(3);
if (
statement &&
statement.type === 'ForStatement' &&
statement.body.contains(this)
) {
statement.reassigned[this.left.name] = true;
}
}
super.initialise( transforms );
super.initialise(transforms);
}
transpile ( code, transforms ) {
if ( this.operator === '**=' && transforms.exponentiation ) {
this.transpileExponentiation( code, transforms );
transpile(code, transforms) {
if (this.operator === '**=' && transforms.exponentiation) {
this.transpileExponentiation(code, transforms);
} else if (/Pattern/.test(this.left.type) && transforms.destructuring) {
this.transpileDestructuring(code, transforms);
}
else if ( /Pattern/.test( this.left.type ) && transforms.destructuring ) {
this.transpileDestructuring( code, transforms );
}
super.transpile( code, transforms );
super.transpile(code, transforms);
}
transpileDestructuring ( code ) {
const scope = this.findScope( true );
const assign = scope.createIdentifier( 'assign' );
const temporaries = [ assign ];
transpileDestructuring(code) {
const scope = this.findScope(true);
const assign = scope.createIdentifier('assign');
const temporaries = [assign];

@@ -47,13 +49,13 @@ const start = this.start;

let text = '';
function use ( node ) {
code.prependRight( node.start, text );
code.move( node.start, node.end, start );
function use(node) {
code.prependRight(node.start, text);
code.move(node.start, node.end, start);
text = '';
}
function write ( string ) {
function write(string) {
text += string;
}
write( `(${assign} = ` );
use( this.right );
write(`(${assign} = `);
use(this.right);

@@ -63,51 +65,49 @@ // Walk `pattern`, generating code that assigns the value in

// must take care to only output `ref` once.
function destructure ( pattern, ref, mayDuplicate ) {
if ( pattern.type === 'Identifier' || pattern.type === 'MemberExpression' ) {
write( ', ' );
use( pattern );
write( ` = ${ref}` );
}
function destructure(pattern, ref, mayDuplicate) {
if (
pattern.type === 'Identifier' ||
pattern.type === 'MemberExpression'
) {
write(', ');
use(pattern);
write(` = ${ref}`);
} else if (pattern.type === 'AssignmentPattern') {
if (pattern.left.type === 'Identifier') {
code.remove(pattern.start, pattern.right.start);
else if ( pattern.type === 'AssignmentPattern' ) {
if ( pattern.left.type === 'Identifier' ) {
code.remove( pattern.start, pattern.right.start );
const target = pattern.left.name;
let source = ref;
if ( !mayDuplicate ) {
write( `, ${target} = ${ref}` );
if (!mayDuplicate) {
write(`, ${target} = ${ref}`);
source = target;
}
write( `, ${target} = ${source} === void 0 ? ` );
use( pattern.right );
write( ` : ${source}` );
write(`, ${target} = ${source} === void 0 ? `);
use(pattern.right);
write(` : ${source}`);
} else {
code.remove( pattern.left.end, pattern.right.start );
code.remove(pattern.left.end, pattern.right.start);
const target = scope.createIdentifier( 'temp' );
const target = scope.createIdentifier('temp');
let source = ref;
temporaries.push( target );
if ( !mayDuplicate ) {
write( `, ${target} = ${ref}` );
temporaries.push(target);
if (!mayDuplicate) {
write(`, ${target} = ${ref}`);
source = target;
}
write( `, ${target} = ${source} === void 0 ? ` );
use( pattern.right );
write( ` : ${source}` );
destructure( pattern.left, target, true );
write(`, ${target} = ${source} === void 0 ? `);
use(pattern.right);
write(` : ${source}`);
destructure(pattern.left, target, true);
}
}
else if ( pattern.type === 'ArrayPattern' ) {
} else if (pattern.type === 'ArrayPattern') {
const elements = pattern.elements;
if ( elements.length === 1 ) {
code.remove( pattern.start, elements[0].start );
destructure( elements[0], `${ref}[0]`, false );
code.remove( elements[0].end, pattern.end );
}
else {
if ( !mayDuplicate ) {
const temp = scope.createIdentifier( 'array' );
temporaries.push( temp );
write( `, ${temp} = ${ref}` );
if (elements.length === 1) {
code.remove(pattern.start, elements[0].start);
destructure(elements[0], `${ref}[0]`, false);
code.remove(elements[0].end, pattern.end);
} else {
if (!mayDuplicate) {
const temp = scope.createIdentifier('array');
temporaries.push(temp);
write(`, ${temp} = ${ref}`);
ref = temp;

@@ -117,3 +117,3 @@ }

let c = pattern.start;
elements.forEach( ( element, i ) => {
elements.forEach((element, i) => {
if (!element) return;

@@ -124,7 +124,7 @@

if ( element.type === 'RestElement' ) {
code.remove( element.start, element.argument.start );
destructure( element.argument, `${ref}.slice(${i})`, false );
if (element.type === 'RestElement') {
code.remove(element.start, element.argument.start);
destructure(element.argument, `${ref}.slice(${i})`, false);
} else {
destructure( element, `${ref}[${i}]`, false );
destructure(element, `${ref}[${i}]`, false);
}

@@ -135,19 +135,19 @@ });

}
}
else if ( pattern.type === 'ObjectPattern' ) {
} else if (pattern.type === 'ObjectPattern') {
const props = pattern.properties;
if ( props.length == 1 ) {
if (props.length == 1) {
const prop = props[0];
const value = prop.computed || prop.key.type !== 'Identifier' ? `${ref}[${code.slice(prop.key.start, prop.key.end)}]` : `${ref}.${prop.key.name}`;
const value =
prop.computed || prop.key.type !== 'Identifier'
? `${ref}[${code.slice(prop.key.start, prop.key.end)}]`
: `${ref}.${prop.key.name}`;
code.remove( pattern.start, prop.value.start );
destructure( prop.value, value, false );
code.remove( prop.end, pattern.end );
}
else {
if ( !mayDuplicate ) {
const temp = scope.createIdentifier( 'obj' );
temporaries.push( temp );
write( `, ${temp} = ${ref}` );
code.remove(pattern.start, prop.value.start);
destructure(prop.value, value, false);
code.remove(prop.end, pattern.end);
} else {
if (!mayDuplicate) {
const temp = scope.createIdentifier('obj');
temporaries.push(temp);
write(`, ${temp} = ${ref}`);
ref = temp;

@@ -158,4 +158,7 @@ }

props.forEach( prop => {
const value = prop.computed || prop.key.type !== 'Identifier' ? `${ref}[${code.slice(prop.key.start, prop.key.end)}]` : `${ref}.${prop.key.name}`;
props.forEach(prop => {
const value =
prop.computed || prop.key.type !== 'Identifier'
? `${ref}[${code.slice(prop.key.start, prop.key.end)}]`
: `${ref}.${prop.key.name}`;

@@ -165,3 +168,3 @@ code.remove(c, prop.value.start);

destructure( prop.value, value, false );
destructure(prop.value, value, false);
});

@@ -171,28 +174,31 @@

}
} else {
throw new Error(
`Unexpected node type in destructuring assignment (${pattern.type})`
);
}
else {
throw new Error( `Unexpected node type in destructuring assignment (${pattern.type})` );
}
}
destructure( this.left, assign, true );
code.remove( this.left.end, this.right.start );
destructure(this.left, assign, true);
code.remove(this.left.end, this.right.start);
if ( this.unparenthesizedParent().type === 'ExpressionStatement' ) {
if (this.unparenthesizedParent().type === 'ExpressionStatement') {
// no rvalue needed for expression statement
code.prependRight( start, `${text})` );
code.prependRight(start, `${text})`);
} else {
// destructuring is part of an expression - need an rvalue
code.prependRight( start, `${text}, ${assign})` );
code.prependRight(start, `${text}, ${assign})`);
}
const statement = this.findNearest( /(?:Statement|Declaration)$/ );
code.appendLeft( statement.start, `var ${temporaries.join( ', ' )};\n${statement.getIndentation()}` );
const statement = this.findNearest(/(?:Statement|Declaration)$/);
code.appendLeft(
statement.start,
`var ${temporaries.join(', ')};\n${statement.getIndentation()}`
);
}
transpileExponentiation ( code ) {
const scope = this.findScope( false );
transpileExponentiation(code) {
const scope = this.findScope(false);
const getAlias = name => {
const declaration = scope.findDeclaration( name );
const declaration = scope.findDeclaration(name);
return declaration ? declaration.name : name;

@@ -203,4 +209,4 @@ };

let charIndex = this.left.end;
while ( code.original[ charIndex ] !== '*' ) charIndex += 1;
code.remove( charIndex, charIndex + 2 );
while (code.original[charIndex] !== '*') charIndex += 1;
code.remove(charIndex, charIndex + 2);

@@ -214,5 +220,5 @@ // how we do the next part depends on a number of factors – whether

if ( left.type === 'Identifier' ) {
base = getAlias( left.name );
} else if ( left.type === 'MemberExpression' ) {
if (left.type === 'Identifier') {
base = getAlias(left.name);
} else if (left.type === 'MemberExpression') {
let object;

@@ -223,83 +229,96 @@ let needsObjectVar = false;

const statement = this.findNearest( /(?:Statement|Declaration)$/ );
const statement = this.findNearest(/(?:Statement|Declaration)$/);
const i0 = statement.getIndentation();
if ( left.property.type === 'Identifier' ) {
property = left.computed ? getAlias( left.property.name ) : left.property.name;
if (left.property.type === 'Identifier') {
property = left.computed
? getAlias(left.property.name)
: left.property.name;
} else {
property = scope.createIdentifier( 'property' );
property = scope.createIdentifier('property');
needsPropertyVar = true;
}
if ( left.object.type === 'Identifier' ) {
object = getAlias( left.object.name );
if (left.object.type === 'Identifier') {
object = getAlias(left.object.name);
} else {
object = scope.createIdentifier( 'object' );
object = scope.createIdentifier('object');
needsObjectVar = true;
}
if ( left.start === statement.start ) {
if ( needsObjectVar && needsPropertyVar ) {
code.prependRight( statement.start, `var ${object} = ` );
code.overwrite( left.object.end, left.property.start, `;\n${i0}var ${property} = ` );
code.overwrite( left.property.end, left.end, `;\n${i0}${object}[${property}]` );
}
if (left.start === statement.start) {
if (needsObjectVar && needsPropertyVar) {
code.prependRight(statement.start, `var ${object} = `);
code.overwrite(
left.object.end,
left.property.start,
`;\n${i0}var ${property} = `
);
code.overwrite(
left.property.end,
left.end,
`;\n${i0}${object}[${property}]`
);
} else if (needsObjectVar) {
code.prependRight(statement.start, `var ${object} = `);
code.appendLeft(left.object.end, `;\n${i0}`);
code.appendLeft(left.object.end, object);
} else if (needsPropertyVar) {
code.prependRight(left.property.start, `var ${property} = `);
code.appendLeft(left.property.end, `;\n${i0}`);
code.move(left.property.start, left.property.end, this.start);
else if ( needsObjectVar ) {
code.prependRight( statement.start, `var ${object} = ` );
code.appendLeft( left.object.end, `;\n${i0}` );
code.appendLeft( left.object.end, object );
code.appendLeft(left.object.end, `[${property}]`);
code.remove(left.object.end, left.property.start);
code.remove(left.property.end, left.end);
}
else if ( needsPropertyVar ) {
code.prependRight( left.property.start, `var ${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 {
} else {
let declarators = [];
if ( needsObjectVar ) declarators.push( object );
if ( needsPropertyVar ) declarators.push( property );
if (needsObjectVar) declarators.push(object);
if (needsPropertyVar) declarators.push(property);
if ( declarators.length ) {
code.prependRight( statement.start, `var ${declarators.join( ', ' )};\n${i0}` );
if (declarators.length) {
code.prependRight(
statement.start,
`var ${declarators.join(', ')};\n${i0}`
);
}
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}]` );
}
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);
else if ( needsObjectVar ) {
code.prependRight( left.start, `( ${object} = ` );
code.appendLeft( left.object.end, `, ${object}` );
code.overwrite(left.object.end, left.property.start, `[${property}]`);
code.remove(left.property.end, left.end);
}
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, ` )`);
}
if ( needsPropertyVar ) {
code.appendLeft( this.end, ` )` );
}
}
base = object + ( left.computed || needsPropertyVar ? `[${property}]` : `.${property}` );
base =
object +
(left.computed || needsPropertyVar ? `[${property}]` : `.${property}`);
}
code.prependRight( this.right.start, `Math.pow( ${base}, ` );
code.appendLeft( this.right.end, ` )` );
code.prependRight(this.right.start, `Math.pow( ${base}, `);
code.appendLeft(this.right.end, ` )`);
}
}
import Node from '../Node.js';
export default class BinaryExpression extends Node {
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, ` )` );
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, ` )`);
}
super.transpile( code, transforms );
super.transpile(code, transforms);
}
}

@@ -6,7 +6,7 @@ import Node from '../Node.js';

export default class BreakStatement extends Node {
initialise () {
const loop = this.findNearest( loopStatement );
const switchCase = this.findNearest( 'SwitchCase' );
initialise() {
const loop = this.findNearest(loopStatement);
const switchCase = this.findNearest('SwitchCase');
if ( loop && ( !switchCase || loop.depth > switchCase.depth ) ) {
if (loop && (!switchCase || loop.depth > switchCase.depth)) {
loop.canBreak = true;

@@ -17,8 +17,12 @@ this.loop = loop;

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'` );
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'`);
}
}
}
import Node from '../Node.js';
import spread, { isArguments } from '../../utils/spread.js';
import removeTrailingComma from '../../utils/removeTrailingComma.js';
export default class CallExpression extends Node {
initialise ( transforms ) {
if ( transforms.spreadRest && this.arguments.length > 1 ) {
initialise(transforms) {
if (transforms.spreadRest && this.arguments.length > 1) {
const lexicalBoundary = this.findLexicalBoundary();
let i = this.arguments.length;
while ( i-- ) {
while (i--) {
const arg = this.arguments[i];
if ( arg.type === 'SpreadElement' && isArguments( arg.argument ) ) {
if (arg.type === 'SpreadElement' && isArguments(arg.argument)) {
this.argumentsArrayAlias = lexicalBoundary.getArgumentsArrayAlias();

@@ -18,7 +19,7 @@ }

super.initialise( transforms );
super.initialise(transforms);
}
transpile ( code, transforms ) {
if ( transforms.spreadRest && this.arguments.length ) {
transpile(code, transforms) {
if (transforms.spreadRest && this.arguments.length) {
let hasSpreadElements = false;

@@ -29,37 +30,44 @@ let context;

if ( this.arguments.length === 1 ) {
if ( firstArgument.type === 'SpreadElement' ) {
code.remove( firstArgument.start, firstArgument.argument.start );
if (this.arguments.length === 1) {
if (firstArgument.type === 'SpreadElement') {
code.remove(firstArgument.start, firstArgument.argument.start);
hasSpreadElements = true;
}
} else {
hasSpreadElements = spread( code, this.arguments, firstArgument.start, this.argumentsArrayAlias );
hasSpreadElements = spread(
code,
this.arguments,
firstArgument.start,
this.argumentsArrayAlias
);
}
if ( hasSpreadElements ) {
if (hasSpreadElements) {
// we need to handle super() and super.method() differently
// due to its instance
let _super = null;
if ( this.callee.type === 'Super' ) {
if (this.callee.type === 'Super') {
_super = this.callee;
}
else if ( this.callee.type === 'MemberExpression' && this.callee.object.type === 'Super' ) {
} else if (
this.callee.type === 'MemberExpression' &&
this.callee.object.type === 'Super'
) {
_super = this.callee.object;
}
if ( !_super && this.callee.type === 'MemberExpression' ) {
if ( this.callee.object.type === 'Identifier' ) {
if (!_super && this.callee.type === 'MemberExpression') {
if (this.callee.object.type === 'Identifier') {
context = this.callee.object.name;
} else {
context = this.findScope( true ).createIdentifier( 'ref' );
context = this.findScope(true).createIdentifier('ref');
const callExpression = this.callee.object;
const enclosure = callExpression.findNearest( /Function/ );
const block = enclosure ? enclosure.body.body
: callExpression.findNearest( /^Program$/ ).body;
const lastStatementInBlock = block[ block.length - 1 ];
const enclosure = callExpression.findNearest(/Function/);
const block = enclosure
? enclosure.body.body
: callExpression.findNearest(/^Program$/).body;
const lastStatementInBlock = block[block.length - 1];
const i0 = lastStatementInBlock.getIndentation();
code.prependRight( callExpression.start, `(${context} = ` );
code.appendLeft( callExpression.end, `)` );
code.appendLeft( lastStatementInBlock.end, `\n${i0}var ${context};` );
code.prependRight(callExpression.start, `(${context} = `);
code.appendLeft(callExpression.end, `)`);
code.appendLeft(lastStatementInBlock.end, `\n${i0}var ${context};`);
}

@@ -70,26 +78,27 @@ } else {

code.appendLeft( this.callee.end, '.apply' );
code.appendLeft(this.callee.end, '.apply');
if ( _super ) {
if (_super) {
_super.noCall = true; // bit hacky...
if ( this.arguments.length > 1 ) {
if ( firstArgument.type !== 'SpreadElement' ) {
code.prependRight( firstArgument.start, `[ ` );
if (this.arguments.length > 1) {
if (firstArgument.type !== 'SpreadElement') {
code.prependRight(firstArgument.start, `[ `);
}
code.appendLeft( this.arguments[ this.arguments.length - 1 ].end, ' )' );
code.appendLeft(
this.arguments[this.arguments.length - 1].end,
' )'
);
}
}
else if ( this.arguments.length === 1 ) {
code.prependRight( firstArgument.start, `${context}, ` );
} else if (this.arguments.length === 1) {
code.prependRight(firstArgument.start, `${context}, `);
} else {
if ( firstArgument.type === 'SpreadElement' ) {
code.appendLeft( firstArgument.start, `${context}, ` );
if (firstArgument.type === 'SpreadElement') {
code.appendLeft(firstArgument.start, `${context}, `);
} else {
code.appendLeft( firstArgument.start, `${context}, [ ` );
code.appendLeft(firstArgument.start, `${context}, [ `);
}
code.appendLeft( this.arguments[ this.arguments.length - 1 ].end, ' )' );
code.appendLeft(this.arguments[this.arguments.length - 1].end, ' )');
}

@@ -99,4 +108,8 @@ }

super.transpile( code, transforms );
if (transforms.trailingFunctionCommas && this.arguments.length) {
removeTrailingComma(code, this.arguments[this.arguments.length - 1].end);
}
super.transpile(code, transforms);
}
}

@@ -7,12 +7,16 @@ import Node from '../Node.js';

export default class ClassBody extends Node {
transpile ( code, transforms, inFunctionExpression, superName ) {
if ( transforms.classes ) {
transpile(code, transforms, inFunctionExpression, superName) {
if (transforms.classes) {
const name = this.parent.name;
const indentStr = code.getIndentString();
const i0 = this.getIndentation() + ( inFunctionExpression ? indentStr : '' );
const i0 =
this.getIndentation() + (inFunctionExpression ? indentStr : '');
const i1 = i0 + indentStr;
const constructorIndex = findIndex( this.body, node => node.kind === 'constructor' );
const constructor = this.body[ constructorIndex ];
const constructorIndex = findIndex(
this.body,
node => node.kind === 'constructor'
);
const constructor = this.body[constructorIndex];

@@ -22,35 +26,51 @@ let introBlock = '';

if ( this.body.length ) {
code.remove( this.start, this.body[0].start );
code.remove( this.body[ this.body.length - 1 ].end, this.end );
if (this.body.length) {
code.remove(this.start, this.body[0].start);
code.remove(this.body[this.body.length - 1].end, this.end);
} else {
code.remove( this.start, this.end );
code.remove(this.start, this.end);
}
if ( constructor ) {
if (constructor) {
constructor.value.body.isConstructorBody = true;
const previousMethod = this.body[ constructorIndex - 1 ];
const nextMethod = this.body[ constructorIndex + 1 ];
const previousMethod = this.body[constructorIndex - 1];
const nextMethod = this.body[constructorIndex + 1];
// ensure constructor is first
if ( constructorIndex > 0 ) {
code.remove( previousMethod.end, constructor.start );
code.move( constructor.start, nextMethod ? nextMethod.start : this.end - 1, this.body[0].start );
if (constructorIndex > 0) {
code.remove(previousMethod.end, constructor.start);
code.move(
constructor.start,
nextMethod ? nextMethod.start : this.end - 1,
this.body[0].start
);
}
if ( !inFunctionExpression ) code.appendLeft( constructor.end, ';' );
if (!inFunctionExpression) code.appendLeft(constructor.end, ';');
}
let namedFunctions = this.program.options.namedFunctionExpressions !== false;
let namedConstructor = namedFunctions || this.parent.superClass || this.parent.type !== 'ClassDeclaration';
if ( this.parent.superClass ) {
let inheritanceBlock = `if ( ${superName} ) ${name}.__proto__ = ${superName};\n${i0}${name}.prototype = Object.create( ${superName} && ${superName}.prototype );\n${i0}${name}.prototype.constructor = ${name};`;
let namedFunctions =
this.program.options.namedFunctionExpressions !== false;
let namedConstructor =
namedFunctions ||
this.parent.superClass ||
this.parent.type !== 'ClassDeclaration';
if (this.parent.superClass) {
let inheritanceBlock = `if ( ${superName} ) ${name}.__proto__ = ${
superName
};\n${i0}${name}.prototype = Object.create( ${superName} && ${
superName
}.prototype );\n${i0}${name}.prototype.constructor = ${name};`;
if ( constructor ) {
if (constructor) {
introBlock += `\n\n${i0}` + inheritanceBlock;
} else {
const fn = `function ${name} () {` + ( superName ?
`\n${i1}${superName}.apply(this, arguments);\n${i0}}` :
`}` ) + ( inFunctionExpression ? '' : ';' ) + ( this.body.length ? `\n\n${i0}` : '' );
const fn =
`function ${name} () {` +
(superName
? `\n${i1}${superName}.apply(this, arguments);\n${i0}}`
: `}`) +
(inFunctionExpression ? '' : ';') +
(this.body.length ? `\n\n${i0}` : '');

@@ -60,6 +80,6 @@ inheritanceBlock = fn + inheritanceBlock;

}
} else if ( !constructor ) {
} else if (!constructor) {
let fn = 'function ' + (namedConstructor ? name + ' ' : '') + '() {}';
if ( this.parent.type === 'ClassDeclaration' ) fn += ';';
if ( this.body.length ) fn += `\n\n${i0}`;
if (this.parent.type === 'ClassDeclaration') fn += ';';
if (this.body.length) fn += `\n\n${i0}`;

@@ -69,3 +89,3 @@ introBlock += fn;

const scope = this.findScope( false );
const scope = this.findScope(false);

@@ -77,12 +97,16 @@ let prototypeGettersAndSetters = [];

this.body.forEach( ( method, i ) => {
if ( method.kind === 'constructor' ) {
this.body.forEach((method, i) => {
if (method.kind === 'constructor') {
let constructorName = namedConstructor ? ' ' + name : '';
code.overwrite( method.key.start, method.key.end, `function${constructorName}` );
code.overwrite(
method.key.start,
method.key.end,
`function${constructorName}`
);
return;
}
if ( method.static ) {
const len = code.original[ method.start + 6 ] == ' ' ? 7 : 6;
code.remove( method.start, method.start + len );
if (method.static) {
const len = code.original[method.start + 6] == ' ' ? 7 : 6;
code.remove(method.start, method.start + len);
}

@@ -94,4 +118,7 @@

let methodName = method.key.name;
if ( reserved[ methodName ] || method.value.body.scope.references[methodName] ) {
methodName = scope.createIdentifier( methodName );
if (
reserved[methodName] ||
method.value.body.scope.references[methodName]
) {
methodName = scope.createIdentifier(methodName);
}

@@ -102,3 +129,3 @@

let fake_computed = false;
if ( ! method.computed && method.key.type === 'Literal' ) {
if (!method.computed && method.key.type === 'Literal') {
fake_computed = true;

@@ -108,17 +135,23 @@ method.computed = true;

if ( isAccessor ) {
if ( method.computed ) {
throw new Error( 'Computed accessor properties are not currently supported' );
if (isAccessor) {
if (method.computed) {
throw new Error(
'Computed accessor properties are not currently supported'
);
}
code.remove( method.start, method.key.start );
code.remove(method.start, method.key.start);
if ( method.static ) {
if ( !~staticGettersAndSetters.indexOf( method.key.name ) ) staticGettersAndSetters.push( method.key.name );
if ( !staticAccessors ) staticAccessors = scope.createIdentifier( 'staticAccessors' );
if (method.static) {
if (!~staticGettersAndSetters.indexOf(method.key.name))
staticGettersAndSetters.push(method.key.name);
if (!staticAccessors)
staticAccessors = scope.createIdentifier('staticAccessors');
lhs = `${staticAccessors}`;
} else {
if ( !~prototypeGettersAndSetters.indexOf( method.key.name ) ) prototypeGettersAndSetters.push( method.key.name );
if ( !prototypeAccessors ) prototypeAccessors = scope.createIdentifier( 'prototypeAccessors' );
if (!~prototypeGettersAndSetters.indexOf(method.key.name))
prototypeGettersAndSetters.push(method.key.name);
if (!prototypeAccessors)
prototypeAccessors = scope.createIdentifier('prototypeAccessors');

@@ -128,21 +161,20 @@ lhs = `${prototypeAccessors}`;

} else {
lhs = method.static ?
`${name}` :
`${name}.prototype`;
lhs = method.static ? `${name}` : `${name}.prototype`;
}
if ( !method.computed ) lhs += '.';
if (!method.computed) lhs += '.';
const insertNewlines = ( constructorIndex > 0 && i === constructorIndex + 1 ) ||
( i === 0 && constructorIndex === this.body.length - 1 );
const insertNewlines =
(constructorIndex > 0 && i === constructorIndex + 1) ||
(i === 0 && constructorIndex === this.body.length - 1);
if ( insertNewlines ) lhs = `\n\n${i0}${lhs}`;
if (insertNewlines) lhs = `\n\n${i0}${lhs}`;
let c = method.key.end;
if ( method.computed ) {
if ( fake_computed ) {
code.prependRight( method.key.start, '[' );
code.appendLeft( method.key.end, ']' );
if (method.computed) {
if (fake_computed) {
code.prependRight(method.key.start, '[');
code.appendLeft(method.key.end, ']');
} else {
while ( code.original[c] !== ']' ) c += 1;
while (code.original[c] !== ']') c += 1;
c += 1;

@@ -152,45 +184,64 @@ }

const funcName = method.computed || isAccessor || !namedFunctions ? '' : `${methodName} `;
const rhs = ( isAccessor ? `.${method.kind}` : '' ) + ` = function` + ( method.value.generator ? '* ' : ' ' ) + funcName;
code.remove( c, method.value.start );
code.prependRight( method.value.start, rhs );
code.appendLeft( method.end, ';' );
const funcName =
method.computed || isAccessor || !namedFunctions
? ''
: `${methodName} `;
const rhs =
(isAccessor ? `.${method.kind}` : '') +
` = function` +
(method.value.generator ? '* ' : ' ') +
funcName;
code.remove(c, method.value.start);
code.prependRight(method.value.start, rhs);
code.appendLeft(method.end, ';');
if ( method.value.generator ) code.remove( method.start, method.key.start );
if (method.value.generator) code.remove(method.start, method.key.start);
code.prependRight( method.start, lhs );
code.prependRight(method.start, lhs);
});
if ( prototypeGettersAndSetters.length || staticGettersAndSetters.length ) {
if (prototypeGettersAndSetters.length || staticGettersAndSetters.length) {
let intro = [];
let outro = [];
if ( prototypeGettersAndSetters.length ) {
intro.push( `var ${prototypeAccessors} = { ${prototypeGettersAndSetters.map( name => `${name}: { configurable: true }` ).join( ',' )} };` );
outro.push( `Object.defineProperties( ${name}.prototype, ${prototypeAccessors} );` );
if (prototypeGettersAndSetters.length) {
intro.push(
`var ${prototypeAccessors} = { ${prototypeGettersAndSetters
.map(name => `${name}: { configurable: true }`)
.join(',')} };`
);
outro.push(
`Object.defineProperties( ${name}.prototype, ${
prototypeAccessors
} );`
);
}
if ( staticGettersAndSetters.length ) {
intro.push( `var ${staticAccessors} = { ${staticGettersAndSetters.map( name => `${name}: { configurable: true }` ).join( ',' )} };` );
outro.push( `Object.defineProperties( ${name}, ${staticAccessors} );` );
if (staticGettersAndSetters.length) {
intro.push(
`var ${staticAccessors} = { ${staticGettersAndSetters
.map(name => `${name}: { configurable: true }`)
.join(',')} };`
);
outro.push(`Object.defineProperties( ${name}, ${staticAccessors} );`);
}
if ( constructor ) introBlock += `\n\n${i0}`;
introBlock += intro.join( `\n${i0}` );
if ( !constructor ) introBlock += `\n\n${i0}`;
if (constructor) introBlock += `\n\n${i0}`;
introBlock += intro.join(`\n${i0}`);
if (!constructor) introBlock += `\n\n${i0}`;
outroBlock += `\n\n${i0}` + outro.join( `\n${i0}` );
outroBlock += `\n\n${i0}` + outro.join(`\n${i0}`);
}
if ( constructor ) {
code.appendLeft( constructor.end, introBlock );
if (constructor) {
code.appendLeft(constructor.end, introBlock);
} else {
code.prependRight( this.start, introBlock );
code.prependRight(this.start, introBlock);
}
code.appendLeft( this.end, outroBlock );
code.appendLeft(this.end, outroBlock);
}
super.transpile( code, transforms );
super.transpile(code, transforms);
}
}

@@ -5,14 +5,19 @@ import Node from '../Node.js';

export default class ClassDeclaration extends Node {
initialise ( transforms ) {
this.name = this.id.name;
this.findScope( true ).addDeclaration( this.id, 'class' );
initialise(transforms) {
if (this.id) {
this.name = this.id.name;
this.findScope(true).addDeclaration(this.id, 'class');
} else {
this.name = this.findScope(true).createIdentifier("defaultExport");
}
super.initialise( transforms );
super.initialise(transforms);
}
transpile ( code, transforms ) {
if ( transforms.classes ) {
if ( !this.superClass ) deindent( this.body, code );
transpile(code, transforms) {
if (transforms.classes) {
if (!this.superClass) deindent(this.body, code);
const superName = this.superClass && ( this.superClass.name || 'superclass' );
const superName =
this.superClass && (this.superClass.name || 'superclass');

@@ -24,41 +29,53 @@ const i0 = this.getIndentation();

// after the declaration, because `export default var Foo = ...` is illegal
const syntheticDefaultExport = this.parent.type === 'ExportDefaultDeclaration' ?
`\n\n${i0}export default ${this.id.name};` :
'';
const isExportDefaultDeclaration = this.parent.type === 'ExportDefaultDeclaration';
if ( syntheticDefaultExport ) code.remove( this.parent.start, this.start );
if (isExportDefaultDeclaration) {
code.remove(this.parent.start, this.start);
}
code.overwrite( this.start, this.id.start, 'var ' );
let c = this.start
if (this.id) {
code.overwrite(c, this.id.start, 'var ');
c = this.id.end
} else {
code.prependLeft(c, `var ${this.name}`);
}
if ( this.superClass ) {
if ( this.superClass.end === this.body.start ) {
code.remove( this.id.end, this.superClass.start );
code.appendLeft( this.id.end, ` = (function (${superName}) {\n${i1}` );
if (this.superClass) {
if (this.superClass.end === this.body.start) {
code.remove(c, this.superClass.start);
code.appendLeft(c, ` = (function (${superName}) {\n${i1}`);
} else {
code.overwrite( this.id.end, this.superClass.start, ' = ' );
code.overwrite( this.superClass.end, this.body.start, `(function (${superName}) {\n${i1}` );
code.overwrite(c, this.superClass.start, ' = ');
code.overwrite(
this.superClass.end,
this.body.start,
`(function (${superName}) {\n${i1}`
);
}
} else {
if ( this.id.end === this.body.start ) {
code.appendLeft( this.id.end, ' = ' );
if (c === this.body.start) {
code.appendLeft(c, ' = ');
} else {
code.overwrite( this.id.end, this.body.start, ' = ' );
code.overwrite(c, this.body.start, ' = ');
}
}
this.body.transpile( code, transforms, !!this.superClass, superName );
this.body.transpile(code, transforms, !!this.superClass, superName);
if ( this.superClass ) {
code.appendLeft( this.end, `\n\n${i1}return ${this.name};\n${i0}}(` );
code.move( this.superClass.start, this.superClass.end, this.end );
code.prependRight( this.end, `));${syntheticDefaultExport}` );
} else if ( syntheticDefaultExport ) {
code.prependRight( this.end, syntheticDefaultExport );
const syntheticDefaultExport =
isExportDefaultDeclaration
? `\n\n${i0}export default ${this.name};`
: '';
if (this.superClass) {
code.appendLeft(this.end, `\n\n${i1}return ${this.name};\n${i0}}(`);
code.move(this.superClass.start, this.superClass.end, this.end);
code.prependRight(this.end, `));${syntheticDefaultExport}`);
} else if (syntheticDefaultExport) {
code.prependRight(this.end, syntheticDefaultExport);
}
} else {
this.body.transpile(code, transforms, false, null);
}
else {
this.body.transpile( code, transforms, false, null );
}
}
}
import Node from '../Node.js';
export default class ClassExpression extends Node {
initialise ( transforms ) {
this.name = this.id ? this.id.name :
this.parent.type === 'VariableDeclarator' ? this.parent.id.name :
this.parent.type === 'AssignmentExpression' ? this.parent.left.name :
this.findScope( true ).createIdentifier( 'anonymous' );
initialise(transforms) {
this.name = ( this.id
? this.id.name
: this.parent.type === 'VariableDeclarator'
? this.parent.id.name
: this.parent.type !== 'AssignmentExpression'
? null
: this.parent.left.type === 'Identifier'
? this.parent.left.name
: this.parent.left.type === 'MemberExpression'
? this.parent.left.property.name
: null ) || this.findScope(true).createIdentifier('anonymous');
super.initialise( transforms );
super.initialise(transforms);
}
transpile ( code, transforms ) {
if ( transforms.classes ) {
const superName = this.superClass && ( this.superClass.name || 'superclass' );
transpile(code, transforms) {
if (transforms.classes) {
const superName =
this.superClass && (this.superClass.name || 'superclass');

@@ -20,27 +28,25 @@ const i0 = this.getIndentation();

if ( this.superClass ) {
code.remove( this.start, this.superClass.start );
code.remove( this.superClass.end, this.body.start );
code.appendLeft( this.start, `(function (${superName}) {\n${i1}` );
if (this.superClass) {
code.remove(this.start, this.superClass.start);
code.remove(this.superClass.end, this.body.start);
code.appendLeft(this.start, `(function (${superName}) {\n${i1}`);
} else {
code.overwrite( this.start, this.body.start, `(function () {\n${i1}` );
code.overwrite(this.start, this.body.start, `(function () {\n${i1}`);
}
this.body.transpile( code, transforms, true, superName );
this.body.transpile(code, transforms, true, superName);
const outro = `\n\n${i1}return ${this.name};\n${i0}}(`;
if ( this.superClass ) {
code.appendLeft( this.end, outro );
code.move( this.superClass.start, this.superClass.end, this.end );
code.prependRight( this.end, '))' );
if (this.superClass) {
code.appendLeft(this.end, outro);
code.move(this.superClass.start, this.superClass.end, this.end);
code.prependRight(this.end, '))');
} else {
code.appendLeft( this.end, `\n\n${i1}return ${this.name};\n${i0}}())` );
code.appendLeft(this.end, `\n\n${i1}return ${this.name};\n${i0}}())`);
}
} else {
this.body.transpile(code, transforms, false);
}
else {
this.body.transpile( code, transforms, false );
}
}
}

@@ -6,9 +6,13 @@ import Node from '../Node.js';

export default class ContinueStatement extends Node {
transpile ( code ) {
const loop = this.findNearest( loopStatement );
if ( 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 + 8, 'return' );
transpile(code) {
const loop = this.findNearest(loopStatement);
if (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 + 8, 'return');
}
}
}

@@ -5,6 +5,7 @@ import Node from '../Node.js';

export default class ExportDefaultDeclaration extends Node {
initialise ( transforms ) {
if ( transforms.moduleExport ) throw new CompileError( 'export is not supported', this );
super.initialise( transforms );
initialise(transforms) {
if (transforms.moduleExport)
throw new CompileError('export is not supported', this);
super.initialise(transforms);
}
}

@@ -5,6 +5,7 @@ import Node from '../Node.js';

export default class ExportNamedDeclaration extends Node {
initialise ( transforms ) {
if ( transforms.moduleExport ) throw new CompileError( 'export is not supported', this );
super.initialise( transforms );
initialise(transforms) {
if (transforms.moduleExport)
throw new CompileError('export is not supported', this);
super.initialise(transforms);
}
}

@@ -5,19 +5,31 @@ import LoopStatement from './shared/LoopStatement.js';

export default class ForInStatement extends LoopStatement {
findScope ( functionScope ) {
return functionScope || !this.createdScope ? this.parent.findScope( functionScope ) : this.body.scope;
findScope(functionScope) {
return functionScope || !this.createdScope
? this.parent.findScope(functionScope)
: this.body.scope;
}
transpile ( code, transforms ) {
if ( this.shouldRewriteAsFunction ) {
transpile(code, transforms) {
if (this.shouldRewriteAsFunction) {
// which variables are declared in the init statement?
const names = this.left.type === 'VariableDeclaration' ?
[].concat.apply( [], this.left.declarations.map( declarator => extractNames( declarator.id ) ) ) :
[];
const names =
this.left.type === 'VariableDeclaration'
? [].concat.apply(
[],
this.left.declarations.map(declarator =>
extractNames(declarator.id)
)
)
: [];
this.args = names.map( name => name in this.aliases ? this.aliases[ name ].outer : name );
this.params = names.map( name => name in this.aliases ? this.aliases[ name ].inner : name );
this.args = names.map(
name => (name in this.aliases ? this.aliases[name].outer : name)
);
this.params = names.map(
name => (name in this.aliases ? this.aliases[name].inner : name)
);
}
super.transpile( code, transforms );
super.transpile(code, transforms);
}
}

@@ -6,19 +6,26 @@ import LoopStatement from './shared/LoopStatement.js';

export default class ForOfStatement extends LoopStatement {
initialise ( transforms ) {
if ( transforms.forOf && !transforms.dangerousForOf ) throw new CompileError( 'for...of statements are not supported. Use `transforms: { forOf: false }` to skip transformation and disable this error, or `transforms: { dangerousForOf: true }` if you know what you\'re doing', this );
super.initialise( transforms );
initialise(transforms) {
if (transforms.forOf && !transforms.dangerousForOf)
throw new CompileError(
"for...of statements are not supported. Use `transforms: { forOf: false }` to skip transformation and disable this error, or `transforms: { dangerousForOf: true }` if you know what you're doing",
this
);
super.initialise(transforms);
}
transpile ( code, transforms ) {
super.transpile( code, transforms );
if ( !transforms.dangerousForOf ) return;
transpile(code, transforms) {
super.transpile(code, transforms);
if (!transforms.dangerousForOf) return;
// edge case (#80)
if ( !this.body.body[0] ) {
if ( this.left.type === 'VariableDeclaration' && this.left.kind === 'var' ) {
code.remove( this.start, this.left.start );
code.appendLeft( this.left.end, ';' );
code.remove( this.left.end, this.end );
if (!this.body.body[0]) {
if (
this.left.type === 'VariableDeclaration' &&
this.left.kind === 'var'
) {
code.remove(this.start, this.left.start);
code.appendLeft(this.left.end, ';');
code.remove(this.left.end, this.end);
} else {
code.remove( this.start, this.end );
code.remove(this.start, this.end);
}

@@ -29,12 +36,12 @@

const scope = this.findScope( true );
const scope = this.findScope(true);
const i0 = this.getIndentation();
const i1 = i0 + code.getIndentString();
const key = scope.createIdentifier( 'i' );
const list = scope.createIdentifier( 'list' );
const key = scope.createIdentifier('i');
const list = scope.createIdentifier('list');
if ( this.body.synthetic ) {
code.prependRight( this.left.start, `{\n${i1}` );
code.appendLeft( this.body.body[0].end, `\n${i0}}` );
if (this.body.synthetic) {
code.prependRight(this.left.start, `{\n${i1}`);
code.appendLeft(this.body.body[0].end, `\n${i0}}`);
}

@@ -44,31 +51,31 @@

code.remove( this.left.end, this.right.start );
code.move( this.left.start, this.left.end, bodyStart );
code.remove(this.left.end, this.right.start);
code.move(this.left.start, this.left.end, bodyStart);
code.prependRight(this.right.start, `var ${key} = 0, ${list} = `);
code.appendLeft(this.right.end, `; ${key} < ${list}.length; ${key} += 1`);
code.prependRight( this.right.start, `var ${key} = 0, ${list} = ` );
code.appendLeft( this.right.end, `; ${key} < ${list}.length; ${key} += 1` );
// destructuring. TODO non declaration destructuring
const declarator = this.left.type === 'VariableDeclaration' && this.left.declarations[0];
if ( declarator && declarator.id.type !== 'Identifier' ) {
const declarator =
this.left.type === 'VariableDeclaration' && this.left.declarations[0];
if (declarator && declarator.id.type !== 'Identifier') {
let statementGenerators = [];
const ref = scope.createIdentifier( 'ref' );
destructure( code, scope, declarator.id, ref, false, statementGenerators );
const ref = scope.createIdentifier('ref');
destructure(code, scope, declarator.id, ref, false, statementGenerators);
let suffix = `;\n${i1}`;
statementGenerators.forEach( ( fn, i ) => {
if ( i === statementGenerators.length - 1 ) {
statementGenerators.forEach((fn, i) => {
if (i === statementGenerators.length - 1) {
suffix = `;\n\n${i1}`;
}
fn( bodyStart, '', suffix );
fn(bodyStart, '', suffix);
});
code.appendLeft( this.left.start + this.left.kind.length + 1, ref );
code.appendLeft( this.left.end, ` = ${list}[${key}];\n${i1}` );
code.appendLeft(this.left.start + this.left.kind.length + 1, ref);
code.appendLeft(this.left.end, ` = ${list}[${key}];\n${i1}`);
} else {
code.appendLeft( this.left.end, ` = ${list}[${key}];\n\n${i1}` );
code.appendLeft(this.left.end, ` = ${list}[${key}];\n\n${i1}`);
}
}
}

@@ -5,29 +5,45 @@ import LoopStatement from './shared/LoopStatement.js';

export default class ForStatement extends LoopStatement {
findScope ( functionScope ) {
return functionScope || !this.createdScope ? this.parent.findScope( functionScope ) : this.body.scope;
findScope(functionScope) {
return functionScope || !this.createdScope
? this.parent.findScope(functionScope)
: this.body.scope;
}
transpile ( code, transforms ) {
transpile(code, transforms) {
const i1 = this.getIndentation() + code.getIndentString();
if ( this.shouldRewriteAsFunction ) {
if (this.shouldRewriteAsFunction) {
// which variables are declared in the init statement?
const names = this.init.type === 'VariableDeclaration' ?
[].concat.apply( [], this.init.declarations.map( declarator => extractNames( declarator.id ) ) ) :
[];
const names =
this.init.type === 'VariableDeclaration'
? [].concat.apply(
[],
this.init.declarations.map(declarator =>
extractNames(declarator.id)
)
)
: [];
const aliases = this.aliases;
this.args = names.map( name => name in this.aliases ? this.aliases[ name ].outer : name );
this.params = names.map( name => name in this.aliases ? this.aliases[ name ].inner : name );
this.args = names.map(
name => (name in this.aliases ? this.aliases[name].outer : name)
);
this.params = names.map(
name => (name in this.aliases ? this.aliases[name].inner : name)
);
const updates = Object.keys( this.reassigned )
.map( name => `${aliases[ name ].outer} = ${aliases[ name ].inner};` );
const updates = Object.keys(this.reassigned).map(
name => `${aliases[name].outer} = ${aliases[name].inner};`
);
if ( updates.length ) {
if ( this.body.synthetic ) {
code.appendLeft( this.body.body[0].end, `; ${updates.join(` `)}` );
if (updates.length) {
if (this.body.synthetic) {
code.appendLeft(this.body.body[0].end, `; ${updates.join(` `)}`);
} else {
const lastStatement = this.body.body[ this.body.body.length - 1 ];
code.appendLeft( lastStatement.end, `\n\n${i1}${updates.join(`\n${i1}`)}` );
const lastStatement = this.body.body[this.body.body.length - 1];
code.appendLeft(
lastStatement.end,
`\n\n${i1}${updates.join(`\n${i1}`)}`
);
}

@@ -37,4 +53,4 @@ }

super.transpile( code, transforms );
super.transpile(code, transforms);
}
}
import Node from '../Node.js';
import CompileError from '../../utils/CompileError.js';
import removeTrailingComma from '../../utils/removeTrailingComma.js';
export default class FunctionDeclaration extends Node {
initialise ( transforms ) {
if ( this.generator && transforms.generator ) {
throw new CompileError( 'Generators are not supported', this );
initialise(transforms) {
if (this.generator && transforms.generator) {
throw new CompileError('Generators are not supported', this);
}

@@ -12,5 +13,14 @@

this.findScope( true ).addDeclaration( this.id, 'function' );
super.initialise( transforms );
if (this.id) {
this.findScope(true).addDeclaration(this.id, 'function');
}
super.initialise(transforms);
}
transpile(code, transforms) {
super.transpile(code, transforms);
if (transforms.trailingFunctionCommas && this.params.length) {
removeTrailingComma(code, this.params[this.params.length - 1].end);
}
}
}
import Node from '../Node.js';
import CompileError from '../../utils/CompileError.js';
import removeTrailingComma from '../../utils/removeTrailingComma.js';
export default class FunctionExpression extends Node {
initialise ( transforms ) {
if ( this.generator && transforms.generator ) {
throw new CompileError( 'Generators are not supported', this );
initialise(transforms) {
if (this.generator && transforms.generator) {
throw new CompileError('Generators are not supported', this);
}

@@ -12,8 +13,8 @@

if ( this.id ) {
if (this.id) {
// function expression IDs belong to the child scope...
this.body.scope.addDeclaration( this.id, 'function' );
this.body.scope.addDeclaration(this.id, 'function');
}
super.initialise( transforms );
super.initialise(transforms);

@@ -23,18 +24,20 @@ const parent = this.parent;

if ( transforms.conciseMethodProperty
&& parent.type === 'Property'
&& parent.kind === 'init'
&& parent.method
&& parent.key.type === 'Identifier' ) {
if (
transforms.conciseMethodProperty &&
parent.type === 'Property' &&
parent.kind === 'init' &&
parent.method &&
parent.key.type === 'Identifier'
) {
// object literal concise method
methodName = parent.key.name;
}
else if ( transforms.classes
&& parent.type === 'MethodDefinition'
&& parent.kind === 'method'
&& parent.key.type === 'Identifier' ) {
} else if (
transforms.classes &&
parent.type === 'MethodDefinition' &&
parent.kind === 'method' &&
parent.key.type === 'Identifier'
) {
// method definition in a class
methodName = parent.key.name;
}
else if ( this.id && this.id.type === 'Identifier' ) {
} else if (this.id && this.id.type === 'Identifier') {
// naked function expression

@@ -44,5 +47,5 @@ methodName = this.id.alias || this.id.name;

if ( methodName ) {
for ( const param of this.params ) {
if ( param.type === 'Identifier' && methodName === param.name ) {
if (methodName) {
for (const param of this.params) {
if (param.type === 'Identifier' && methodName === param.name) {
// workaround for Safari 9/WebKit bug:

@@ -53,8 +56,8 @@ // https://gitlab.com/Rich-Harris/buble/issues/154

const scope = this.body.scope;
const declaration = scope.declarations[ methodName ];
const declaration = scope.declarations[methodName];
const alias = scope.createIdentifier( methodName );
const alias = scope.createIdentifier(methodName);
param.alias = alias;
for ( const identifier of declaration.instances ) {
for (const identifier of declaration.instances) {
identifier.alias = alias;

@@ -68,2 +71,9 @@ }

}
transpile(code, transforms) {
super.transpile(code, transforms);
if (transforms.trailingFunctionCommas && this.params.length) {
removeTrailingComma(code, this.params[this.params.length - 1].end);
}
}
}

@@ -6,26 +6,33 @@ import Node from '../Node.js';

export default class Identifier extends Node {
findScope ( functionScope ) {
if ( this.parent.params && ~this.parent.params.indexOf( this ) ) {
findScope(functionScope) {
if (this.parent.params && ~this.parent.params.indexOf(this)) {
return this.parent.body.scope;
}
if ( this.parent.type === 'FunctionExpression' && this === this.parent.id ) {
if (this.parent.type === 'FunctionExpression' && this === this.parent.id) {
return this.parent.body.scope;
}
return this.parent.findScope( functionScope );
return this.parent.findScope(functionScope);
}
initialise ( transforms ) {
if ( transforms.arrow && isReference( this, this.parent ) ) {
if ( this.name === 'arguments' && !this.findScope( false ).contains( this.name ) ) {
initialise(transforms) {
if (transforms.arrow && isReference(this, this.parent)) {
if (
this.name === 'arguments' &&
!this.findScope(false).contains(this.name)
) {
const lexicalBoundary = this.findLexicalBoundary();
const arrowFunction = this.findNearest( 'ArrowFunctionExpression' );
const loop = this.findNearest( loopStatement );
const arrowFunction = this.findNearest('ArrowFunctionExpression');
const loop = this.findNearest(loopStatement);
if ( arrowFunction && arrowFunction.depth > lexicalBoundary.depth ) {
if (arrowFunction && arrowFunction.depth > lexicalBoundary.depth) {
this.alias = lexicalBoundary.getArgumentsAlias();
}
if ( loop && loop.body.contains( this ) && loop.depth > lexicalBoundary.depth ) {
if (
loop &&
loop.body.contains(this) &&
loop.depth > lexicalBoundary.depth
) {
this.alias = lexicalBoundary.getArgumentsAlias();

@@ -35,11 +42,14 @@ }

this.findScope( false ).addReference( this );
this.findScope(false).addReference(this);
}
}
transpile ( code ) {
if ( this.alias ) {
code.overwrite( this.start, this.end, this.alias, { storeName: true, contentOnly: true });
transpile(code) {
if (this.alias) {
code.overwrite(this.start, this.end, this.alias, {
storeName: true,
contentOnly: true
});
}
}
}
import Node from '../Node.js';
export default class IfStatement extends Node {
initialise ( transforms ) {
super.initialise( transforms );
initialise(transforms) {
super.initialise(transforms);
}
transpile ( code, transforms ) {
if ( this.consequent.type !== 'BlockStatement'
|| this.consequent.type === 'BlockStatement' && this.consequent.synthetic ) {
code.appendLeft( this.consequent.start, '{ ' );
code.prependRight( this.consequent.end, ' }' );
transpile(code, transforms) {
if (
this.consequent.type !== 'BlockStatement' ||
(this.consequent.type === 'BlockStatement' && this.consequent.synthetic)
) {
code.appendLeft(this.consequent.start, '{ ');
code.prependRight(this.consequent.end, ' }');
}
if ( this.alternate && this.alternate.type !== 'IfStatement' && (
this.alternate.type !== 'BlockStatement'
|| this.alternate.type === 'BlockStatement' && this.alternate.synthetic ) ) {
code.appendLeft( this.alternate.start, '{ ' );
code.prependRight( this.alternate.end, ' }' );
if (
this.alternate &&
this.alternate.type !== 'IfStatement' &&
(this.alternate.type !== 'BlockStatement' ||
(this.alternate.type === 'BlockStatement' && this.alternate.synthetic))
) {
code.appendLeft(this.alternate.start, '{ ');
code.prependRight(this.alternate.end, ' }');
}
super.transpile( code, transforms );
super.transpile(code, transforms);
}
}

@@ -5,6 +5,7 @@ import Node from '../Node.js';

export default class ImportDeclaration extends Node {
initialise ( transforms ) {
if ( transforms.moduleImport ) throw new CompileError( 'import is not supported', this );
super.initialise( transforms );
initialise(transforms) {
if (transforms.moduleImport)
throw new CompileError('import is not supported', this);
super.initialise(transforms);
}
}
import Node from '../Node.js';
export default class ImportDefaultSpecifier extends Node {
initialise ( transforms ) {
this.findScope( true ).addDeclaration( this.local, 'import' );
super.initialise( transforms );
initialise(transforms) {
this.findScope(true).addDeclaration(this.local, 'import');
super.initialise(transforms);
}
}
import Node from '../Node.js';
export default class ImportSpecifier extends Node {
initialise ( transforms ) {
this.findScope( true ).addDeclaration( this.local, 'import' );
super.initialise( transforms );
initialise(transforms) {
this.findScope(true).addDeclaration(this.local, 'import');
super.initialise(transforms);
}
}

@@ -5,9 +5,9 @@ import Node from '../Node.js';

const formatKey = key => hasDashes(key) ? `'${key}'` : key;
const formatKey = key => (hasDashes(key) ? `'${key}'` : key);
const formatVal = val => val ? '' : 'true';
const formatVal = val => (val ? '' : 'true');
export default class JSXAttribute extends Node {
transpile ( code, transforms ) {
const { start, name } = this.name;
transpile(code, transforms) {
const { start, name } = this.name;

@@ -17,6 +17,6 @@ // Overwrite equals sign if value is present.

code.overwrite( start, end, `${formatKey(name)}: ${formatVal(this.value)}` );
code.overwrite(start, end, `${formatKey(name)}: ${formatVal(this.value)}`);
super.transpile( code, transforms );
super.transpile(code, transforms);
}
}
import Node from '../Node.js';
function containsNewLine ( node ) {
return node.type === 'Literal' && !/\S/.test( node.value ) && /\n/.test( node.value );
function containsNewLine(node) {
return (
node.type === 'Literal' && !/\S/.test(node.value) && /\n/.test(node.value)
);
}
export default class JSXClosingElement extends Node {
transpile ( code ) {
transpile(code) {
let spaceBeforeParen = true;
const lastChild = this.parent.children[ this.parent.children.length - 1 ];
const lastChild = this.parent.children[this.parent.children.length - 1];

@@ -16,8 +18,11 @@ // omit space before closing paren if

// b) there are no children but there are attributes
if ( ( lastChild && containsNewLine( lastChild ) ) || ( this.parent.openingElement.attributes.length ) ) {
if (
(lastChild && containsNewLine(lastChild)) ||
this.parent.openingElement.attributes.length
) {
spaceBeforeParen = false;
}
code.overwrite( this.start, this.end, spaceBeforeParen ? ' )' : ')' );
code.overwrite(this.start, this.end, spaceBeforeParen ? ' )' : ')');
}
}
import Node from '../Node.js';
function normalise ( str, removeTrailingWhitespace ) {
if ( removeTrailingWhitespace && /\n/.test( str ) ) {
str = str.replace( /\s+$/, '' );
function normalise(str, removeTrailingWhitespace) {
if (removeTrailingWhitespace && /\n/.test(str)) {
str = str.replace(/\s+$/, '');
}
str = str
.replace( /^\n\r?\s+/, '' ) // remove leading newline + space
.replace( /\s*\n\r?\s*/gm, ' ' ); // replace newlines with spaces
.replace(/^\n\r?\s+/, '') // remove leading newline + space
.replace(/\s*\n\r?\s*/gm, ' '); // replace newlines with spaces
// TODO prefer single quotes?
return JSON.stringify( str );
return JSON.stringify(str);
}
export default class JSXElement extends Node {
transpile ( code, transforms ) {
super.transpile( code, transforms );
transpile(code, transforms) {
super.transpile(code, transforms);
const children = this.children.filter( child => {
if ( child.type !== 'Literal' ) return true;
const children = this.children.filter(child => {
if (child.type !== 'Literal') return true;
// remove whitespace-only literals, unless on a single line
return /\S/.test( child.value ) || !/\n/.test( child.value );
return /\S/.test(child.raw) || !/\n/.test(child.raw);
});
if ( children.length ) {
if (children.length) {
let c = this.openingElement.end;
let i;
for ( i = 0; i < children.length; i += 1 ) {
for (i = 0; i < children.length; i += 1) {
const child = children[i];
if ( child.type === 'JSXExpressionContainer' && child.expression.type === 'JSXEmptyExpression' ) {
if (
child.type === 'JSXExpressionContainer' &&
child.expression.type === 'JSXEmptyExpression'
) {
// empty block is a no op
} else {
const tail = code.original[ c ] === '\n' && child.type !== 'Literal' ? '' : ' ';
code.appendLeft( c, `,${tail}` );
const tail =
code.original[c] === '\n' && child.type !== 'Literal' ? '' : ' ';
code.appendLeft(c, `,${tail}`);
}
if ( child.type === 'Literal' ) {
const str = normalise( child.value, i === children.length - 1 );
code.overwrite( child.start, child.end, str );
if (child.type === 'Literal') {
const str = normalise(child.raw, i === children.length - 1);
code.overwrite(child.start, child.end, str);
}

@@ -45,0 +49,0 @@

import Node from '../Node.js';
export default class JSXExpressionContainer extends Node {
transpile ( code, transforms ) {
code.remove( this.start, this.expression.start );
code.remove( this.expression.end, this.end );
transpile(code, transforms) {
code.remove(this.start, this.expression.start);
code.remove(this.expression.end, this.end);
super.transpile( code, transforms );
super.transpile(code, transforms);
}
}

@@ -5,9 +5,11 @@ import Node from '../Node.js';

export default class JSXOpeningElement extends Node {
transpile ( code, transforms ) {
super.transpile( code, transforms );
transpile(code, transforms) {
super.transpile(code, transforms);
code.overwrite( this.start, this.name.start, `${this.program.jsx}( ` );
code.overwrite(this.start, this.name.start, `${this.program.jsx}( `);
const html = this.name.type === 'JSXIdentifier' && this.name.name[0] === this.name.name[0].toLowerCase();
if ( html ) code.prependRight( this.name.start, `'` );
const html =
this.name.type === 'JSXIdentifier' &&
this.name.name[0] === this.name.name[0].toLowerCase();
if (html) code.prependRight(this.name.start, `'`);

@@ -17,8 +19,8 @@ const len = this.attributes.length;

if ( len ) {
if (len) {
let i;
let hasSpread = false;
for ( i = 0; i < len; i += 1 ) {
if ( this.attributes[i].type === 'JSXSpreadAttribute' ) {
for (i = 0; i < len; i += 1) {
if (this.attributes[i].type === 'JSXSpreadAttribute') {
hasSpread = true;

@@ -31,22 +33,20 @@ break;

for ( i = 0; i < len; i += 1 ) {
for (i = 0; i < len; i += 1) {
const attr = this.attributes[i];
if ( i > 0 ) {
if ( attr.start === c )
code.prependRight( c, ', ' );
else
code.overwrite( c, attr.start, ', ' );
if (i > 0) {
if (attr.start === c) code.prependRight(c, ', ');
else code.overwrite(c, attr.start, ', ');
}
if ( hasSpread && attr.type !== 'JSXSpreadAttribute' ) {
const lastAttr = this.attributes[ i - 1 ];
const nextAttr = this.attributes[ i + 1 ];
if (hasSpread && attr.type !== 'JSXSpreadAttribute') {
const lastAttr = this.attributes[i - 1];
const nextAttr = this.attributes[i + 1];
if ( !lastAttr || lastAttr.type === 'JSXSpreadAttribute' ) {
code.prependRight( attr.start, '{ ' );
if (!lastAttr || lastAttr.type === 'JSXSpreadAttribute') {
code.prependRight(attr.start, '{ ');
}
if ( !nextAttr || nextAttr.type === 'JSXSpreadAttribute' ) {
code.appendLeft( attr.end, ' }' );
if (!nextAttr || nextAttr.type === 'JSXSpreadAttribute') {
code.appendLeft(attr.end, ' }');
}

@@ -60,10 +60,15 @@ }

let before;
if ( hasSpread ) {
if ( len === 1 ) {
if (hasSpread) {
if (len === 1) {
before = html ? `',` : ',';
} else {
if (!this.program.options.objectAssign) {
throw new CompileError( 'Mixed JSX attributes ending in spread requires specified objectAssign option with \'Object.assign\' or polyfill helper.', this );
throw new CompileError(
"Mixed JSX attributes ending in spread requires specified objectAssign option with 'Object.assign' or polyfill helper.",
this
);
}
before = html ? `', ${this.program.options.objectAssign}({},` : `, ${this.program.options.objectAssign}({},`;
before = html
? `', ${this.program.options.objectAssign}({},`
: `, ${this.program.options.objectAssign}({},`;
after = ')';

@@ -76,18 +81,18 @@ }

code.prependRight( this.name.end, before );
code.prependRight(this.name.end, before);
if ( after ) {
code.appendLeft( this.attributes[ len - 1 ].end, after );
if (after) {
code.appendLeft(this.attributes[len - 1].end, after);
}
} else {
code.appendLeft( this.name.end, html ? `', null` : `, null` );
code.appendLeft(this.name.end, html ? `', null` : `, null`);
c = this.name.end;
}
if ( this.selfClosing ) {
code.overwrite( c, this.end, this.attributes.length ? `)` : ` )` );
if (this.selfClosing) {
code.overwrite(c, this.end, this.attributes.length ? `)` : ` )`);
} else {
code.remove( c, this.end );
code.remove(c, this.end);
}
}
}
import Node from '../Node.js';
export default class JSXSpreadAttribute extends Node {
transpile ( code, transforms ) {
code.remove( this.start, this.argument.start );
code.remove( this.argument.end, this.end );
transpile(code, transforms) {
code.remove(this.start, this.argument.start);
code.remove(this.argument.end, this.end);
super.transpile( code, transforms );
super.transpile(code, transforms);
}
}

@@ -6,13 +6,13 @@ import Node from '../Node.js';

export default class Literal extends Node {
initialise () {
if ( typeof this.value === 'string' ) {
this.program.indentExclusionElements.push( this );
initialise() {
if (typeof this.value === 'string') {
this.program.indentExclusionElements.push(this);
}
}
transpile ( code, transforms ) {
if ( transforms.numericLiteral ) {
const leading = this.raw.slice( 0, 2 );
if ( leading === '0b' || leading === '0o' ) {
code.overwrite( this.start, this.end, String( this.value ), {
transpile(code, transforms) {
if (transforms.numericLiteral) {
const leading = this.raw.slice(0, 2);
if (leading === '0b' || leading === '0o') {
code.overwrite(this.start, this.end, String(this.value), {
storeName: true,

@@ -24,10 +24,19 @@ contentOnly: true

if ( this.regex ) {
if (this.regex) {
const { pattern, flags } = this.regex;
if ( transforms.stickyRegExp && /y/.test( flags ) ) throw new CompileError( 'Regular expression sticky flag is not supported', this );
if ( transforms.unicodeRegExp && /u/.test( flags ) ) {
code.overwrite( this.start, this.end, `/${rewritePattern( pattern, flags )}/${flags.replace( 'u', '' )}`, {
contentOnly: true
});
if (transforms.stickyRegExp && /y/.test(flags))
throw new CompileError(
'Regular expression sticky flag is not supported',
this
);
if (transforms.unicodeRegExp && /u/.test(flags)) {
code.overwrite(
this.start,
this.end,
`/${rewritePattern(pattern, flags)}/${flags.replace('u', '')}`,
{
contentOnly: true
}
);
}

@@ -34,0 +43,0 @@ }

@@ -5,10 +5,10 @@ import Node from '../Node.js';

export default class MemberExpression extends Node {
transpile ( code, transforms ) {
if ( transforms.reservedProperties && reserved[ this.property.name ] ) {
code.overwrite( this.object.end, this.property.start, `['` );
code.appendLeft( this.property.end, `']` );
transpile(code, transforms) {
if (transforms.reservedProperties && reserved[this.property.name]) {
code.overwrite(this.object.end, this.property.start, `['`);
code.appendLeft(this.property.end, `']`);
}
super.transpile( code, transforms );
super.transpile(code, transforms);
}
}

@@ -5,10 +5,10 @@ import Node from '../Node.js';

export default class NewExpression extends Node {
initialise ( transforms ) {
if ( transforms.spreadRest && this.arguments.length ) {
initialise(transforms) {
if (transforms.spreadRest && this.arguments.length) {
const lexicalBoundary = this.findLexicalBoundary();
let i = this.arguments.length;
while ( i-- ) {
while (i--) {
const arg = this.arguments[i];
if ( arg.type === 'SpreadElement' && isArguments( arg.argument ) ) {
if (arg.type === 'SpreadElement' && isArguments(arg.argument)) {
this.argumentsArrayAlias = lexicalBoundary.getArgumentsArrayAlias();

@@ -20,20 +20,33 @@ break;

super.initialise( transforms );
super.initialise(transforms);
}
transpile ( code, transforms ) {
if ( transforms.spreadRest && this.arguments.length ) {
transpile(code, transforms) {
if (transforms.spreadRest && this.arguments.length) {
const firstArgument = this.arguments[0];
const isNew = true;
let hasSpreadElements = spread( code, this.arguments, firstArgument.start, this.argumentsArrayAlias, isNew );
let hasSpreadElements = spread(
code,
this.arguments,
firstArgument.start,
this.argumentsArrayAlias,
isNew
);
if ( hasSpreadElements ) {
code.prependRight( this.start + 'new'.length, ' (Function.prototype.bind.apply(' );
code.overwrite( this.callee.end, firstArgument.start, ', [ null ].concat( ' );
code.appendLeft( this.end, ' ))' );
if (hasSpreadElements) {
code.prependRight(
this.start + 'new'.length,
' (Function.prototype.bind.apply('
);
code.overwrite(
this.callee.end,
firstArgument.start,
', [ null ].concat( '
);
code.appendLeft(this.end, ' ))');
}
}
super.transpile( code, transforms );
super.transpile(code, transforms);
}
}

@@ -5,4 +5,4 @@ import Node from '../Node.js';

export default class ObjectExpression extends Node {
transpile ( code, transforms ) {
super.transpile( code, transforms );
transpile(code, transforms) {
super.transpile(code, transforms);

@@ -16,11 +16,11 @@ let firstPropertyStart = this.start + 1;

for ( let i = 0; i < this.properties.length; ++i ) {
const prop = this.properties[ i ];
if ( prop.type === 'SpreadElement' ) {
for (let i = 0; i < this.properties.length; ++i) {
const prop = this.properties[i];
if (prop.type === 'SpreadElement') {
spreadPropertyCount += 1;
if ( firstSpreadProperty === null ) firstSpreadProperty = i;
} else if ( prop.computed ) {
if (firstSpreadProperty === null) firstSpreadProperty = i;
} else if (prop.computed) {
computedPropertyCount += 1;
if ( firstComputedProperty === null ) firstComputedProperty = i;
} else if ( prop.type === 'Property' ) {
if (firstComputedProperty === null) firstComputedProperty = i;
} else if (prop.type === 'Property') {
regularPropertyCount += 1;

@@ -30,22 +30,33 @@ }

if ( spreadPropertyCount ) {
if ( !this.program.options.objectAssign ) {
throw new CompileError( 'Object spread operator requires specified objectAssign option with \'Object.assign\' or polyfill helper.', this );
if (spreadPropertyCount) {
if (!this.program.options.objectAssign) {
throw new CompileError(
"Object spread operator requires specified objectAssign option with 'Object.assign' or polyfill helper.",
this
);
}
// enclose run of non-spread properties in curlies
let i = this.properties.length;
if ( regularPropertyCount && !computedPropertyCount ) {
while ( i-- ) {
if (regularPropertyCount && !computedPropertyCount) {
while (i--) {
const prop = this.properties[i];
if ( prop.type === 'Property' && !prop.computed ) {
const lastProp = this.properties[ i - 1 ];
const nextProp = this.properties[ i + 1 ];
if (prop.type === 'Property' && !prop.computed) {
const lastProp = this.properties[i - 1];
const nextProp = this.properties[i + 1];
if ( !lastProp || lastProp.type !== 'Property' || lastProp.computed ) {
code.prependRight( prop.start, '{' );
if (
!lastProp ||
lastProp.type !== 'Property' ||
lastProp.computed
) {
code.prependRight(prop.start, '{');
}
if ( !nextProp || nextProp.type !== 'Property' || nextProp.computed ) {
code.appendLeft( prop.end, '}' );
if (
!nextProp ||
nextProp.type !== 'Property' ||
nextProp.computed
) {
code.appendLeft(prop.end, '}');
}

@@ -58,16 +69,28 @@ }

firstPropertyStart = this.properties[0].start;
if ( !computedPropertyCount ) {
code.overwrite( this.start, firstPropertyStart, `${this.program.options.objectAssign}({}, ` );
code.overwrite( this.properties[ this.properties.length - 1 ].end, this.end, ')' );
} else if ( this.properties[0].type === "SpreadElement" ) {
code.overwrite( this.start, firstPropertyStart, `${this.program.options.objectAssign}({}, ` );
code.remove( this.end - 1, this.end );
code.appendRight( this.end, ')' );
if (!computedPropertyCount) {
code.overwrite(
this.start,
firstPropertyStart,
`${this.program.options.objectAssign}({}, `
);
code.overwrite(
this.properties[this.properties.length - 1].end,
this.end,
')'
);
} else if (this.properties[0].type === 'SpreadElement') {
code.overwrite(
this.start,
firstPropertyStart,
`${this.program.options.objectAssign}({}, `
);
code.remove(this.end - 1, this.end);
code.appendRight(this.end, ')');
} else {
code.prependLeft( this.start, `${this.program.options.objectAssign}(` );
code.appendRight( this.end, ')' );
code.prependLeft(this.start, `${this.program.options.objectAssign}(`);
code.appendRight(this.end, ')');
}
}
if ( computedPropertyCount && transforms.computedProperty ) {
if (computedPropertyCount && transforms.computedProperty) {
const i0 = this.getIndentation();

@@ -78,9 +101,20 @@

if ( this.parent.type === 'VariableDeclarator' && this.parent.parent.declarations.length === 1 && this.parent.id.type === 'Identifier' ) {
if (
this.parent.type === 'VariableDeclarator' &&
this.parent.parent.declarations.length === 1 &&
this.parent.id.type === 'Identifier'
) {
isSimpleAssignment = true;
name = this.parent.id.alias || this.parent.id.name; // TODO is this right?
} else if ( this.parent.type === 'AssignmentExpression' && this.parent.parent.type === 'ExpressionStatement' && this.parent.left.type === 'Identifier' ) {
} else if (
this.parent.type === 'AssignmentExpression' &&
this.parent.parent.type === 'ExpressionStatement' &&
this.parent.left.type === 'Identifier'
) {
isSimpleAssignment = true;
name = this.parent.left.alias || this.parent.left.name; // TODO is this right?
} else if ( this.parent.type === 'AssignmentPattern' && this.parent.left.type === 'Identifier' ) {
} else if (
this.parent.type === 'AssignmentPattern' &&
this.parent.left.type === 'Identifier'
) {
isSimpleAssignment = true;

@@ -90,7 +124,7 @@ name = this.parent.left.alias || this.parent.left.name; // TODO is this right?

if ( spreadPropertyCount ) isSimpleAssignment = false;
if (spreadPropertyCount) isSimpleAssignment = false;
// handle block scoping
const declaration = this.findScope( false ).findDeclaration( name );
if ( declaration ) name = declaration.name;
const declaration = this.findScope(false).findDeclaration(name);
if (declaration) name = declaration.name;

@@ -100,9 +134,12 @@ const start = firstPropertyStart;

if ( isSimpleAssignment ) {
if (isSimpleAssignment) {
// ???
} else {
if ( firstSpreadProperty === null || firstComputedProperty < firstSpreadProperty ) {
name = this.findScope( true ).createIdentifier( 'obj' );
if (
firstSpreadProperty === null ||
firstComputedProperty < firstSpreadProperty
) {
name = this.findLexicalBoundary().declareIdentifier('obj');
code.prependRight( this.start, `( ${name} = ` );
code.prependRight(this.start, `( ${name} = `);
} else name = null; // We don't actually need this variable

@@ -116,23 +153,27 @@ }

for ( let i = 0; i < len; i += 1 ) {
for (let i = 0; i < len; i += 1) {
const prop = this.properties[i];
let moveStart = i > 0 ? this.properties[ i - 1 ].end : start;
let moveStart = i > 0 ? this.properties[i - 1].end : start;
if ( prop.type === "Property" && ( prop.computed || ( lastComputedProp && !spreadPropertyCount ) ) ) {
if ( i === 0 ) moveStart = this.start + 1; // Trim leading whitespace
if (
prop.type === 'Property' &&
(prop.computed || (lastComputedProp && !spreadPropertyCount))
) {
if (i === 0) moveStart = this.start + 1; // Trim leading whitespace
lastComputedProp = prop;
if ( !name ) {
name = this.findScope( true ).createIdentifier( 'obj' );
if (!name) {
name = this.findLexicalBoundary().declareIdentifier('obj');
const propId = name + ( prop.computed ? "" : "." );
code.appendRight( prop.start, `( ${name} = {}, ${propId}` );
const propId = name + (prop.computed ? '' : '.');
code.appendRight(prop.start, `( ${name} = {}, ${propId}`);
} else {
const propId =
(isSimpleAssignment ? `;\n${i0}${name}` : `, ${name}`) +
(prop.computed ? '' : '.');
const propId = ( isSimpleAssignment ? `;\n${i0}${name}` : `, ${name}` ) + ( prop.computed ? "" : "." );
if ( moveStart < prop.start ) {
code.overwrite( moveStart, prop.start, propId );
if (moveStart < prop.start) {
code.overwrite(moveStart, prop.start, propId);
} else {
code.prependRight( prop.start, propId );
code.prependRight(prop.start, propId);
}

@@ -142,26 +183,27 @@ }

let c = prop.key.end;
if ( prop.computed ) {
while ( code.original[c] !== ']' ) c += 1;
if (prop.computed) {
while (code.original[c] !== ']') c += 1;
c += 1;
}
if ( prop.shorthand ) {
code.overwrite( prop.start, prop.key.end, code.slice( prop.start, prop.key.end ).replace( /:/, ' =' ) );
if (prop.shorthand) {
code.overwrite(
prop.start,
prop.key.end,
code.slice(prop.start, prop.key.end).replace(/:/, ' =')
);
} else {
if ( prop.value.start > c ) code.remove( c, prop.value.start );
code.appendLeft( c, ' = ' );
if (prop.value.start > c) code.remove(c, prop.value.start);
code.appendLeft(c, ' = ');
}
if ( prop.method && transforms.conciseMethodProperty ) {
code.prependRight( prop.value.start, 'function ' );
if (prop.method && transforms.conciseMethodProperty) {
code.prependRight(prop.value.start, 'function ');
}
} else if ( prop.type === "SpreadElement" ) {
if ( name && i > 0 ) {
if ( !lastComputedProp ) {
lastComputedProp = this.properties[ i - 1 ];
} else if (prop.type === 'SpreadElement') {
if (name && i > 0) {
if (!lastComputedProp) {
lastComputedProp = this.properties[i - 1];
}
code.appendLeft( lastComputedProp.end, `, ${name} )` );
code.appendLeft(lastComputedProp.end, `, ${name} )`);
const statement = this.findNearest( /(?:Statement|Declaration)$/ );
code.appendLeft( statement.end, `\n${i0}var ${name};` );
lastComputedProp = null;

@@ -171,16 +213,18 @@ name = null;

} else {
if ( !isFirst && spreadPropertyCount ) {
if (!isFirst && spreadPropertyCount) {
// We are in an Object.assign context, so we need to wrap regular properties
code.prependRight( prop.start, '{' );
code.appendLeft( prop.end, '}' );
code.prependRight(prop.start, '{');
code.appendLeft(prop.end, '}');
}
sawNonComputedProperty = true;
}
if (isFirst && ( prop.type === "SpreadElement" || prop.computed ) ) {
let beginEnd = sawNonComputedProperty ? this.properties[this.properties.length - 1].end : this.end - 1;
if (isFirst && (prop.type === 'SpreadElement' || prop.computed)) {
let beginEnd = sawNonComputedProperty
? this.properties[this.properties.length - 1].end
: this.end - 1;
// Trim trailing comma because it can easily become a leading comma which is illegal
if ( code.original[beginEnd] == ',' ) ++beginEnd;
const closing = code.slice( beginEnd, end );
code.prependLeft( moveStart, closing );
code.remove( beginEnd, end );
if (code.original[beginEnd] == ',') ++beginEnd;
const closing = code.slice(beginEnd, end);
code.prependLeft(moveStart, closing);
code.remove(beginEnd, end);
isFirst = false;

@@ -191,18 +235,15 @@ }

let c = prop.end;
if ( i < len - 1 && ! sawNonComputedProperty ) {
while ( code.original[c] !== ',' ) c += 1;
} else if ( i == len - 1 ) c = this.end;
code.remove( prop.end, c );
if (i < len - 1 && !sawNonComputedProperty) {
while (code.original[c] !== ',') c += 1;
} else if (i == len - 1) c = this.end;
code.remove(prop.end, c);
}
// special case
if ( computedPropertyCount === len ) {
code.remove( this.properties[ len - 1 ].end, this.end - 1 );
if (computedPropertyCount === len) {
code.remove(this.properties[len - 1].end, this.end - 1);
}
if ( !isSimpleAssignment && name ) {
code.appendLeft( lastComputedProp.end, `, ${name} )` );
const statement = this.findNearest( /(?:Statement|Declaration)$/ );
code.appendLeft( statement.end, `\n${i0}var ${name};` );
if (!isSimpleAssignment && name) {
code.appendLeft(lastComputedProp.end, `, ${name} )`);
}

@@ -209,0 +250,0 @@ }

@@ -5,18 +5,27 @@ import Node from '../Node.js';

export default class Property extends Node {
transpile ( code, transforms ) {
super.transpile( code, transforms );
transpile(code, transforms) {
super.transpile(code, transforms);
if ( transforms.conciseMethodProperty && !this.computed && this.parent.type !== 'ObjectPattern' ) {
if ( this.shorthand ) {
code.prependRight( this.start, `${this.key.name}: ` );
} else if ( this.method ) {
if (
transforms.conciseMethodProperty &&
!this.computed &&
this.parent.type !== 'ObjectPattern'
) {
if (this.shorthand) {
code.prependRight(this.start, `${this.key.name}: `);
} else if (this.method) {
let name = '';
if ( this.program.options.namedFunctionExpressions !== false ) {
if ( this.key.type === 'Literal' && typeof this.key.value === 'number' ) {
name = "";
} else if ( this.key.type === 'Identifier' ) {
if ( reserved[ this.key.name ] ||
! /^[a-z_$][a-z0-9_$]*$/i.test( this.key.name ) ||
this.value.body.scope.references[this.key.name] ) {
name = this.findScope( true ).createIdentifier( this.key.name );
if (this.program.options.namedFunctionExpressions !== false) {
if (
this.key.type === 'Literal' &&
typeof this.key.value === 'number'
) {
name = '';
} else if (this.key.type === 'Identifier') {
if (
reserved[this.key.name] ||
!/^[a-z_$][a-z0-9_$]*$/i.test(this.key.name) ||
this.value.body.scope.references[this.key.name]
) {
name = this.findScope(true).createIdentifier(this.key.name);
} else {

@@ -26,3 +35,3 @@ name = this.key.name;

} else {
name = this.findScope( true ).createIdentifier( this.key.value );
name = this.findScope(true).createIdentifier(this.key.value);
}

@@ -32,12 +41,15 @@ name = ' ' + name;

if ( this.value.generator ) code.remove( this.start, this.key.start );
code.appendLeft( this.key.end, `: function${this.value.generator ? '*' : ''}${name}` );
if (this.value.generator) code.remove(this.start, this.key.start);
code.appendLeft(
this.key.end,
`: function${this.value.generator ? '*' : ''}${name}`
);
}
}
if ( transforms.reservedProperties && reserved[ this.key.name ] ) {
code.prependRight( this.key.start, `'` );
code.appendLeft( this.key.end, `'` );
if (transforms.reservedProperties && reserved[this.key.name]) {
code.prependRight(this.key.start, `'`);
code.appendLeft(this.key.end, `'`);
}
}
}

@@ -5,7 +5,10 @@ import Node from '../Node.js';

export default class ReturnStatement extends Node {
initialise ( transforms ) {
this.loop = this.findNearest( loopStatement );
this.nearestFunction = this.findNearest( /Function/ );
initialise(transforms) {
this.loop = this.findNearest(loopStatement);
this.nearestFunction = this.findNearest(/Function/);
if ( this.loop && ( !this.nearestFunction || this.loop.depth > this.nearestFunction.depth ) ) {
if (
this.loop &&
(!this.nearestFunction || this.loop.depth > this.nearestFunction.depth)
) {
this.loop.canReturn = true;

@@ -15,16 +18,17 @@ this.shouldWrap = true;

if ( this.argument ) this.argument.initialise( transforms );
if (this.argument) this.argument.initialise(transforms);
}
transpile ( code, transforms ) {
const shouldWrap = this.shouldWrap && this.loop && this.loop.shouldRewriteAsFunction;
transpile(code, transforms) {
const shouldWrap =
this.shouldWrap && this.loop && this.loop.shouldRewriteAsFunction;
if ( this.argument ) {
if ( shouldWrap ) code.prependRight( this.argument.start, `{ v: ` );
this.argument.transpile( code, transforms );
if ( shouldWrap ) code.appendLeft( this.argument.end, ` }` );
} else if ( shouldWrap ) {
code.appendLeft( this.start + 6, ' {}' );
if (this.argument) {
if (shouldWrap) code.prependRight(this.argument.start, `{ v: `);
this.argument.transpile(code, transforms);
if (shouldWrap) code.appendLeft(this.argument.end, ` }`);
} else if (shouldWrap) {
code.appendLeft(this.start + 6, ' {}');
}
}
}
import Node from '../../Node.js';
export default class LoopStatement extends Node {
findScope ( functionScope ) {
return functionScope || !this.createdScope ? this.parent.findScope( functionScope ) : this.body.scope;
findScope(functionScope) {
return functionScope || !this.createdScope
? this.parent.findScope(functionScope)
: this.body.scope;
}
initialise ( transforms ) {
initialise(transforms) {
this.body.createScope();

@@ -13,23 +15,26 @@ this.createdScope = true;

// this is populated as and when reassignments occur
this.reassigned = Object.create( null );
this.aliases = Object.create( null );
this.reassigned = Object.create(null);
this.aliases = Object.create(null);
super.initialise( transforms );
super.initialise(transforms);
if ( transforms.letConst ) {
if (transforms.letConst) {
// see if any block-scoped declarations are referenced
// inside function expressions
const names = Object.keys( this.body.scope.declarations );
const names = Object.keys(this.body.scope.declarations);
let i = names.length;
while ( i-- ) {
while (i--) {
const name = names[i];
const declaration = this.body.scope.declarations[ name ];
const declaration = this.body.scope.declarations[name];
let j = declaration.instances.length;
while ( j-- ) {
while (j--) {
const instance = declaration.instances[j];
const nearestFunctionExpression = instance.findNearest( /Function/ );
const nearestFunctionExpression = instance.findNearest(/Function/);
if ( nearestFunctionExpression && nearestFunctionExpression.depth > this.depth ) {
if (
nearestFunctionExpression &&
nearestFunctionExpression.depth > this.depth
) {
this.shouldRewriteAsFunction = true;

@@ -40,3 +45,3 @@ break;

if ( this.shouldRewriteAsFunction ) break;
if (this.shouldRewriteAsFunction) break;
}

@@ -46,49 +51,58 @@ }

transpile ( code, transforms ) {
const needsBlock = this.type != 'ForOfStatement' && (
this.body.type !== 'BlockStatement'
|| this.body.type === 'BlockStatement' && this.body.synthetic );
transpile(code, transforms) {
const needsBlock =
this.type != 'ForOfStatement' &&
(this.body.type !== 'BlockStatement' ||
(this.body.type === 'BlockStatement' && this.body.synthetic));
if ( this.shouldRewriteAsFunction ) {
if (this.shouldRewriteAsFunction) {
const i0 = this.getIndentation();
const i1 = i0 + code.getIndentString();
const argString = this.args ? ` ${this.args.join( ', ' )} ` : '';
const paramString = this.params ? ` ${this.params.join( ', ' )} ` : '';
const argString = this.args ? ` ${this.args.join(', ')} ` : '';
const paramString = this.params ? ` ${this.params.join(', ')} ` : '';
const functionScope = this.findScope( true );
const loop = functionScope.createIdentifier( 'loop' );
const functionScope = this.findScope(true);
const loop = functionScope.createIdentifier('loop');
const before = `var ${loop} = function (${paramString}) ` + ( this.body.synthetic ? `{\n${i0}${code.getIndentString()}` : '' );
const after = ( this.body.synthetic ? `\n${i0}}` : '' ) + `;\n\n${i0}`;
const before =
`var ${loop} = function (${paramString}) ` +
(this.body.synthetic ? `{\n${i0}${code.getIndentString()}` : '');
const after = (this.body.synthetic ? `\n${i0}}` : '') + `;\n\n${i0}`;
code.prependRight( this.body.start, before );
code.appendLeft( this.body.end, after );
code.move( this.start, this.body.start, this.body.end );
code.prependRight(this.body.start, before);
code.appendLeft(this.body.end, after);
code.move(this.start, this.body.start, this.body.end);
if ( this.canBreak || this.canReturn ) {
const returned = functionScope.createIdentifier( 'returned' );
if (this.canBreak || this.canReturn) {
const returned = functionScope.createIdentifier('returned');
let insert = `{\n${i1}var ${returned} = ${loop}(${argString});\n`;
if ( this.canBreak ) insert += `\n${i1}if ( ${returned} === 'break' ) break;`;
if ( this.canReturn ) insert += `\n${i1}if ( ${returned} ) return ${returned}.v;`;
if (this.canBreak)
insert += `\n${i1}if ( ${returned} === 'break' ) break;`;
if (this.canReturn)
insert += `\n${i1}if ( ${returned} ) return ${returned}.v;`;
insert += `\n${i0}}`;
code.prependRight( this.body.end, insert );
code.prependRight(this.body.end, insert);
} else {
const callExpression = `${loop}(${argString});`;
if ( this.type === 'DoWhileStatement' ) {
code.overwrite( this.start, this.body.start, `do {\n${i1}${callExpression}\n${i0}}` );
if (this.type === 'DoWhileStatement') {
code.overwrite(
this.start,
this.body.start,
`do {\n${i1}${callExpression}\n${i0}}`
);
} else {
code.prependRight( this.body.end, callExpression );
code.prependRight(this.body.end, callExpression);
}
}
} else if ( needsBlock ) {
code.appendLeft( this.body.start, '{ ' );
code.prependRight( this.body.end, ' }' );
} else if (needsBlock) {
code.appendLeft(this.body.start, '{ ');
code.prependRight(this.body.end, ' }');
}
super.transpile( code, transforms );
super.transpile(code, transforms);
}
}

@@ -5,6 +5,7 @@ import Node from '../../Node.js';

export default class ModuleDeclaration extends Node {
initialise ( transforms ) {
if ( transforms.moduleImport ) throw new CompileError( 'Modules are not supported', this );
super.initialise( transforms );
initialise(transforms) {
if (transforms.moduleImport)
throw new CompileError('Modules are not supported', this);
super.initialise(transforms);
}
}
import Node from '../Node.js';
export default class SpreadElement extends Node {
transpile ( code, transforms ) {
if (this.parent.type == "ObjectExpression") {
code.remove( this.start, this.argument.start );
code.remove( this.argument.end, this.end );
transpile(code, transforms) {
if (this.parent.type == 'ObjectExpression') {
code.remove(this.start, this.argument.start);
code.remove(this.argument.end, this.end);
}
super.transpile( code, transforms );
super.transpile(code, transforms);
}
}

@@ -6,16 +6,23 @@ import Node from '../Node.js';

export default class Super extends Node {
initialise ( transforms ) {
if ( transforms.classes ) {
this.method = this.findNearest( 'MethodDefinition' );
if ( !this.method ) throw new CompileError( this, 'use of super outside class method' );
initialise(transforms) {
if (transforms.classes) {
this.method = this.findNearest('MethodDefinition');
if (!this.method)
throw new CompileError(this, 'use of super outside class method');
const parentClass = this.findNearest( 'ClassBody' ).parent;
this.superClassName = parentClass.superClass && (parentClass.superClass.name || 'superclass');
const parentClass = this.findNearest('ClassBody').parent;
this.superClassName =
parentClass.superClass && (parentClass.superClass.name || 'superclass');
if ( !this.superClassName ) throw new CompileError( 'super used in base class', this );
if (!this.superClassName)
throw new CompileError('super used in base class', this);
this.isCalled = this.parent.type === 'CallExpression' && this === this.parent.callee;
this.isCalled =
this.parent.type === 'CallExpression' && this === this.parent.callee;
if ( this.method.kind !== 'constructor' && this.isCalled ) {
throw new CompileError( 'super() not allowed outside class constructor', this );
if (this.method.kind !== 'constructor' && this.isCalled) {
throw new CompileError(
'super() not allowed outside class constructor',
this
);
}

@@ -25,17 +32,24 @@

if ( !this.isCalled && !this.isMember ) {
throw new CompileError( 'Unexpected use of `super` (expected `super(...)` or `super.*`)', this );
if (!this.isCalled && !this.isMember) {
throw new CompileError(
'Unexpected use of `super` (expected `super(...)` or `super.*`)',
this
);
}
}
if ( transforms.arrow ) {
if (transforms.arrow) {
const lexicalBoundary = this.findLexicalBoundary();
const arrowFunction = this.findNearest( 'ArrowFunctionExpression' );
const loop = this.findNearest( loopStatement );
const arrowFunction = this.findNearest('ArrowFunctionExpression');
const loop = this.findNearest(loopStatement);
if ( arrowFunction && arrowFunction.depth > lexicalBoundary.depth ) {
if (arrowFunction && arrowFunction.depth > lexicalBoundary.depth) {
this.thisAlias = lexicalBoundary.getThisAlias();
}
if ( loop && loop.body.contains( this ) && loop.depth > lexicalBoundary.depth ) {
if (
loop &&
loop.body.contains(this) &&
loop.depth > lexicalBoundary.depth
) {
this.thisAlias = lexicalBoundary.getThisAlias();

@@ -46,15 +60,20 @@ }

transpile ( code, transforms ) {
if ( transforms.classes ) {
const expression = ( this.isCalled || this.method.static ) ?
this.superClassName :
`${this.superClassName}.prototype`;
transpile(code, transforms) {
if (transforms.classes) {
const expression =
this.isCalled || this.method.static
? this.superClassName
: `${this.superClassName}.prototype`;
code.overwrite( this.start, this.end, expression, { storeName: true, contentOnly: true });
code.overwrite(this.start, this.end, expression, {
storeName: true,
contentOnly: true
});
const callExpression = this.isCalled ? this.parent : this.parent.parent;
if ( callExpression && callExpression.type === 'CallExpression' ) {
if ( !this.noCall ) { // special case – `super( ...args )`
code.appendLeft( callExpression.callee.end, '.call' );
if (callExpression && callExpression.type === 'CallExpression') {
if (!this.noCall) {
// special case – `super( ...args )`
code.appendLeft(callExpression.callee.end, '.call');
}

@@ -64,6 +83,6 @@

if ( callExpression.arguments.length ) {
code.appendLeft( callExpression.arguments[0].start, `${thisAlias}, ` );
if (callExpression.arguments.length) {
code.appendLeft(callExpression.arguments[0].start, `${thisAlias}, `);
} else {
code.appendLeft( callExpression.end - 1, `${thisAlias}` );
code.appendLeft(callExpression.end - 1, `${thisAlias}`);
}

@@ -70,0 +89,0 @@ }

@@ -5,24 +5,38 @@ import Node from '../Node.js';

export default class TaggedTemplateExpression extends Node {
initialise ( transforms ) {
if ( transforms.templateString && !transforms.dangerousTaggedTemplateString ) {
throw new CompileError( 'Tagged template strings are not supported. Use `transforms: { templateString: false }` to skip transformation and disable this error, or `transforms: { dangerousTaggedTemplateString: true }` if you know what you\'re doing', this );
initialise(transforms) {
if (
transforms.templateString &&
!transforms.dangerousTaggedTemplateString
) {
throw new CompileError(
"Tagged template strings are not supported. Use `transforms: { templateString: false }` to skip transformation and disable this error, or `transforms: { dangerousTaggedTemplateString: true }` if you know what you're doing",
this
);
}
super.initialise( transforms );
super.initialise(transforms);
}
transpile ( code, transforms ) {
if ( transforms.templateString && transforms.dangerousTaggedTemplateString ) {
const ordered = this.quasi.expressions.concat( this.quasi.quasis ).sort( ( a, b ) => a.start - b.start );
transpile(code, transforms) {
if (transforms.templateString && transforms.dangerousTaggedTemplateString) {
const ordered = this.quasi.expressions
.concat(this.quasi.quasis)
.sort((a, b) => a.start - b.start);
// insert strings at start
const templateStrings = this.quasi.quasis.map( quasi => JSON.stringify( quasi.value.cooked ) );
code.overwrite( this.tag.end, ordered[0].start, `([${templateStrings.join(', ')}]` );
const templateStrings = this.quasi.quasis.map(quasi =>
JSON.stringify(quasi.value.cooked)
);
code.overwrite(
this.tag.end,
ordered[0].start,
`([${templateStrings.join(', ')}]`
);
let lastIndex = ordered[0].start;
ordered.forEach( node => {
if ( node.type === 'TemplateElement' ) {
code.remove( lastIndex, node.end );
ordered.forEach(node => {
if (node.type === 'TemplateElement') {
code.remove(lastIndex, node.end);
} else {
code.overwrite( lastIndex, node.start, ', ' );
code.overwrite(lastIndex, node.start, ', ');
}

@@ -33,7 +47,7 @@

code.overwrite( lastIndex, this.end, ')' );
code.overwrite(lastIndex, this.end, ')');
}
super.transpile( code, transforms );
super.transpile(code, transforms);
}
}
import Node from '../Node.js';
export default class TemplateElement extends Node {
initialise () {
this.program.indentExclusionElements.push( this );
initialise() {
this.program.indentExclusionElements.push(this);
}
}
import Node from '../Node.js';
export default class TemplateLiteral extends Node {
transpile ( code, transforms ) {
super.transpile( code, transforms );
transpile(code, transforms) {
super.transpile(code, transforms);
if ( transforms.templateString && this.parent.type !== 'TaggedTemplateExpression' ) {
let ordered = this.expressions.concat( this.quasis )
.sort( ( a, b ) => a.start - b.start || a.end - b.end )
.filter( ( node, i ) => {
if (
transforms.templateString &&
this.parent.type !== 'TaggedTemplateExpression'
) {
let ordered = this.expressions
.concat(this.quasis)
.sort((a, b) => a.start - b.start || a.end - b.end)
.filter((node, i) => {
// include all expressions
if ( node.type !== 'TemplateElement' ) return true;
if (node.type !== 'TemplateElement') return true;
// include all non-empty strings
if ( node.value.raw ) return true;
if (node.value.raw) return true;

@@ -25,5 +29,9 @@ // exclude all empty strings not at the head

// be numeric, and `1 + 2 + '3' === '33'`)
if ( ordered.length >= 3 ) {
const [ first, , third ] = ordered;
if ( first.type === 'TemplateElement' && first.value.raw === '' && third.type === 'TemplateElement' ) {
if (ordered.length >= 3) {
const [first, , third] = ordered;
if (
first.type === 'TemplateElement' &&
first.value.raw === '' &&
third.type === 'TemplateElement'
) {
ordered.shift();

@@ -33,29 +41,33 @@ }

const parenthesise = ( this.quasis.length !== 1 || this.expressions.length !== 0 ) &&
this.parent.type !== 'TemplateLiteral' &&
this.parent.type !== 'AssignmentExpression' &&
this.parent.type !== 'AssignmentPattern' &&
this.parent.type !== 'VariableDeclarator' &&
( this.parent.type !== 'BinaryExpression' || this.parent.operator !== '+' );
const parenthesise =
(this.quasis.length !== 1 || this.expressions.length !== 0) &&
this.parent.type !== 'TemplateLiteral' &&
this.parent.type !== 'AssignmentExpression' &&
this.parent.type !== 'AssignmentPattern' &&
this.parent.type !== 'VariableDeclarator' &&
(this.parent.type !== 'BinaryExpression' ||
this.parent.operator !== '+');
if ( parenthesise ) code.appendRight( this.start, '(' );
if (parenthesise) code.appendRight(this.start, '(');
let lastIndex = this.start;
ordered.forEach( ( node, i ) => {
let prefix = i === 0 ?
parenthesise ? '(' : '' :
' + ';
ordered.forEach((node, i) => {
let prefix = i === 0 ? (parenthesise ? '(' : '') : ' + ';
if ( node.type === 'TemplateElement' ) {
code.overwrite( lastIndex, node.end, prefix + JSON.stringify( node.value.cooked ) );
if (node.type === 'TemplateElement') {
code.overwrite(
lastIndex,
node.end,
prefix + JSON.stringify(node.value.cooked)
);
} else {
const parenthesise = node.type !== 'Identifier'; // TODO other cases where it's safe
if ( parenthesise ) prefix += '(';
if (parenthesise) prefix += '(';
code.remove( lastIndex, node.start );
code.remove(lastIndex, node.start);
if ( prefix ) code.prependRight( node.start, prefix );
if ( parenthesise ) code.appendLeft( node.end, ')' );
if (prefix) code.prependRight(node.start, prefix);
if (parenthesise) code.appendLeft(node.end, ')');
}

@@ -66,6 +78,6 @@

if ( parenthesise ) code.appendLeft( lastIndex, ')' );
code.remove( lastIndex, this.end );
if (parenthesise) code.appendLeft(lastIndex, ')');
code.remove(lastIndex, this.end);
}
}
}

@@ -5,11 +5,15 @@ import Node from '../Node.js';

export default class ThisExpression extends Node {
initialise ( transforms ) {
if ( transforms.arrow ) {
initialise(transforms) {
if (transforms.arrow) {
const lexicalBoundary = this.findLexicalBoundary();
const arrowFunction = this.findNearest( 'ArrowFunctionExpression' );
const loop = this.findNearest( loopStatement );
const arrowFunction = this.findNearest('ArrowFunctionExpression');
const loop = this.findNearest(loopStatement);
if ( ( arrowFunction && arrowFunction.depth > lexicalBoundary.depth )
|| ( loop && loop.body.contains( this ) && loop.depth > lexicalBoundary.depth )
|| ( loop && loop.right && loop.right.contains( this ) ) ) {
if (
(arrowFunction && arrowFunction.depth > lexicalBoundary.depth) ||
(loop &&
loop.body.contains(this) &&
loop.depth > lexicalBoundary.depth) ||
(loop && loop.right && loop.right.contains(this))
) {
this.alias = lexicalBoundary.getThisAlias();

@@ -20,5 +24,5 @@ }

transpile ( code ) {
if ( this.alias ) {
code.overwrite( this.start, this.end, this.alias, {
transpile(code) {
if (this.alias) {
code.overwrite(this.start, this.end, this.alias, {
storeName: true,

@@ -25,0 +29,0 @@ contentOnly: true

@@ -5,18 +5,24 @@ import Node from '../Node.js';

export default class UpdateExpression extends Node {
initialise ( transforms ) {
if ( this.argument.type === 'Identifier' ) {
const declaration = this.findScope( false ).findDeclaration( this.argument.name );
if ( declaration && declaration.kind === 'const' ) {
throw new CompileError( `${this.argument.name} is read-only`, this );
initialise(transforms) {
if (this.argument.type === 'Identifier') {
const declaration = this.findScope(false).findDeclaration(
this.argument.name
);
if (declaration && declaration.kind === 'const') {
throw new CompileError(`${this.argument.name} is read-only`, this);
}
// special case – https://gitlab.com/Rich-Harris/buble/issues/150
const statement = declaration && declaration.node.ancestor( 3 );
if ( statement && statement.type === 'ForStatement' && statement.body.contains( this ) ) {
statement.reassigned[ this.argument.name ] = true;
const statement = declaration && declaration.node.ancestor(3);
if (
statement &&
statement.type === 'ForStatement' &&
statement.body.contains(this)
) {
statement.reassigned[this.argument.name] = true;
}
}
super.initialise( transforms );
super.initialise(transforms);
}
}

@@ -6,64 +6,79 @@ import Node from '../Node.js';

export default class VariableDeclaration extends Node {
initialise ( transforms ) {
this.scope = this.findScope( this.kind === 'var' );
this.declarations.forEach( declarator => declarator.initialise( transforms ) );
initialise(transforms) {
this.scope = this.findScope(this.kind === 'var');
this.declarations.forEach(declarator => declarator.initialise(transforms));
}
transpile ( code, transforms ) {
transpile(code, transforms) {
const i0 = this.getIndentation();
let kind = this.kind;
if ( transforms.letConst && kind !== 'var' ) {
if (transforms.letConst && kind !== 'var') {
kind = 'var';
code.overwrite( this.start, this.start + this.kind.length, kind, { storeName: true });
code.overwrite(this.start, this.start + this.kind.length, kind, {
storeName: true
});
}
if ( transforms.destructuring && this.parent.type !== 'ForOfStatement' ) {
if (transforms.destructuring && this.parent.type !== 'ForOfStatement') {
let c = this.start;
let lastDeclaratorIsPattern;
this.declarations.forEach( ( declarator, i ) => {
declarator.transpile( code, transforms );
this.declarations.forEach((declarator, i) => {
declarator.transpile(code, transforms);
if ( declarator.id.type === 'Identifier' ) {
if ( i > 0 && this.declarations[ i - 1 ].id.type !== 'Identifier' ) {
code.overwrite( c, declarator.id.start, `var ` );
if (declarator.id.type === 'Identifier') {
if (i > 0 && this.declarations[i - 1].id.type !== 'Identifier') {
code.overwrite(c, declarator.id.start, `var `);
}
} else {
const inline = loopStatement.test( this.parent.type );
const inline = loopStatement.test(this.parent.type);
if ( i === 0 ) {
code.remove( c, declarator.id.start );
if (i === 0) {
code.remove(c, declarator.id.start);
} else {
code.overwrite( c, declarator.id.start, `;\n${i0}` );
code.overwrite(c, declarator.id.start, `;\n${i0}`);
}
const simple = declarator.init.type === 'Identifier' && !declarator.init.rewritten;
const simple =
declarator.init.type === 'Identifier' && !declarator.init.rewritten;
const name = simple ? declarator.init.name : declarator.findScope( true ).createIdentifier( 'ref' );
const name = simple
? declarator.init.name
: declarator.findScope(true).createIdentifier('ref');
let c = declarator.start;
c = declarator.start;
let statementGenerators = [];
if ( simple ) {
code.remove( declarator.id.end, declarator.end );
if (simple) {
code.remove(declarator.id.end, declarator.end);
} else {
statementGenerators.push( ( start, prefix, suffix ) => {
code.prependRight( declarator.id.end, `var ${name}` );
code.appendLeft( declarator.init.end, `${suffix}` );
code.move( declarator.id.end, declarator.end, start );
statementGenerators.push((start, prefix, suffix) => {
code.prependRight(declarator.id.end, `var ${name}`);
code.appendLeft(declarator.init.end, `${suffix}`);
code.move(declarator.id.end, declarator.end, start);
});
}
destructure( code, declarator.findScope( false ), declarator.id, name, inline, statementGenerators );
destructure(
code,
declarator.findScope(false),
declarator.id,
name,
inline,
statementGenerators
);
let prefix = inline ? 'var ' : '';
let suffix = inline ? `, ` : `;\n${i0}`;
statementGenerators.forEach( ( fn, j ) => {
if ( i === this.declarations.length - 1 && j === statementGenerators.length - 1 ) {
statementGenerators.forEach((fn, j) => {
if (
i === this.declarations.length - 1 &&
j === statementGenerators.length - 1
) {
suffix = inline ? '' : ';';
}
fn( declarator.start, j === 0 ? prefix : '', suffix );
fn(declarator.start, j === 0 ? prefix : '', suffix);
});

@@ -76,10 +91,8 @@ }

if ( lastDeclaratorIsPattern && this.end > c ) {
code.overwrite( c, this.end, '', { contentOnly: true });
if (lastDeclaratorIsPattern && this.end > c) {
code.overwrite(c, this.end, '', { contentOnly: true });
}
}
else {
this.declarations.forEach( declarator => {
declarator.transpile( code, transforms );
} else {
this.declarations.forEach(declarator => {
declarator.transpile(code, transforms);
});

@@ -86,0 +99,0 @@ }

import Node from '../Node.js';
export default class VariableDeclarator extends Node {
initialise ( transforms ) {
initialise(transforms) {
let kind = this.parent.kind;
if ( kind === 'let' && this.parent.parent.type === 'ForStatement' ) {
if (kind === 'let' && this.parent.parent.type === 'ForStatement') {
kind = 'for.let'; // special case...
}
this.parent.scope.addDeclaration( this.id, kind );
super.initialise( transforms );
this.parent.scope.addDeclaration(this.id, kind);
super.initialise(transforms);
}
transpile ( code, transforms ) {
if ( !this.init && transforms.letConst && this.parent.kind !== 'var' ) {
let inLoop = this.findNearest( /Function|^For(In|Of)?Statement|^(?:Do)?WhileStatement/ );
if ( inLoop && ! /Function/.test( inLoop.type ) && ! this.isLeftDeclaratorOfLoop() ) {
code.appendLeft( this.id.end, ' = (void 0)' );
transpile(code, transforms) {
if (!this.init && transforms.letConst && this.parent.kind !== 'var') {
let inLoop = this.findNearest(
/Function|^For(In|Of)?Statement|^(?:Do)?WhileStatement/
);
if (
inLoop &&
!/Function/.test(inLoop.type) &&
!this.isLeftDeclaratorOfLoop()
) {
code.appendLeft(this.id.end, ' = (void 0)');
}
}
if ( this.id ) this.id.transpile( code, transforms );
if ( this.init ) this.init.transpile( code, transforms );
if (this.id) this.id.transpile(code, transforms);
if (this.init) this.init.transpile(code, transforms);
}
isLeftDeclaratorOfLoop () {
return this.parent
&& this.parent.type === 'VariableDeclaration'
&& this.parent.parent
&& (this.parent.parent.type === 'ForInStatement'
|| this.parent.parent.type === 'ForOfStatement')
&& this.parent.parent.left
&& this.parent.parent.left.declarations[0] === this;
isLeftDeclaratorOfLoop() {
return (
this.parent &&
this.parent.type === 'VariableDeclaration' &&
this.parent.parent &&
(this.parent.parent.type === 'ForInStatement' ||
this.parent.parent.type === 'ForOfStatement') &&
this.parent.parent.left &&
this.parent.parent.left.declarations[0] === this
);
}
}

@@ -16,8 +16,8 @@ import types from './types/index.js';

export default function wrap ( raw, parent ) {
if ( !raw ) return;
export default function wrap(raw, parent) {
if (!raw) return;
if ( 'length' in raw ) {
if ('length' in raw) {
let i = raw.length;
while ( i-- ) wrap( raw[i], parent );
while (i--) wrap(raw[i], parent);
return;

@@ -28,21 +28,23 @@ }

// the same node. We don't want to wrap an object twice
if ( raw.__wrapped ) return;
if (raw.__wrapped) return;
raw.__wrapped = true;
if ( !keys[ raw.type ] ) {
keys[ raw.type ] = Object.keys( raw ).filter( key => typeof raw[ key ] === 'object' );
if (!keys[raw.type]) {
keys[raw.type] = Object.keys(raw).filter(
key => typeof raw[key] === 'object'
);
}
// special case – body-less if/for/while statements. TODO others?
const bodyType = statementsWithBlocks[ raw.type ];
if ( bodyType && raw[ bodyType ].type !== 'BlockStatement' ) {
const expression = raw[ bodyType ];
const bodyType = statementsWithBlocks[raw.type];
if (bodyType && raw[bodyType].type !== 'BlockStatement') {
const expression = raw[bodyType];
// create a synthetic block statement, otherwise all hell
// breaks loose when it comes to block scoping
raw[ bodyType ] = {
raw[bodyType] = {
start: expression.start,
end: expression.end,
type: 'BlockStatement',
body: [ expression ],
body: [expression],
synthetic: true

@@ -52,6 +54,7 @@ };

new Node( raw, parent );
new Node(raw, parent);
const type = ( raw.type === 'BlockStatement' ? BlockStatement : types[ raw.type ] ) || Node;
const type =
(raw.type === 'BlockStatement' ? BlockStatement : types[raw.type]) || Node;
raw.__proto__ = type.prototype;
}
export const matrix = {
chrome: {
48: 0b1001111011111100111110101111101,
49: 0b1001111111111100111111111111111,
50: 0b1011111111111100111111111111111,
51: 0b1011111111111100111111111111111,
52: 0b1111111111111100111111111111111
48: 0b01001111011111100111110101111101,
49: 0b01001111111111100111111111111111,
50: 0b01011111111111100111111111111111,
51: 0b01011111111111100111111111111111,
52: 0b01111111111111100111111111111111
},
firefox: {
43: 0b1000111111101100000110111011101,
44: 0b1000111111101100000110111011101,
45: 0b1000111111101100000110111011101,
46: 0b1010111111111100000110111011101,
47: 0b1010111111111100111111111011111,
48: 0b1010111111111100111111111011111
43: 0b01000111111101100000110111011101,
44: 0b01000111111101100000110111011101,
45: 0b01000111111101100000110111011101,
46: 0b01010111111111100000110111011101,
47: 0b01010111111111100111111111011111,
48: 0b01010111111111100111111111011111
},
safari: {
8: 0b1000000000000000000000000000000,
9: 0b1001111001101100000011101011110
8: 0b01000000000000000000000000000000,
9: 0b01001111001101100000011101011110
},
ie: {
8: 0b0000000000000000000000000000000,
9: 0b1000000000000000000000000000000,
10: 0b1000000000000000000000000000000,
11: 0b1000000000000000111000001100000
8: 0b00000000000000000000000000000000,
9: 0b01000000000000000000000000000000,
10: 0b01000000000000000000000000000000,
11: 0b01000000000000000111000001100000
},
edge: {
12: 0b1011110110111100011010001011101,
13: 0b1011111110111100011111001011111
12: 0b01011110110111100011010001011101,
13: 0b01011111110111100011110001011111
},
node: {
'0.10': 0b1000000000101000000000001000000,
'0.12': 0b1000001000101000000010001000100,
4: 0b1001111000111100111111001111111,
5: 0b1001111000111100111111001111111,
6: 0b1011111111111100111111111111111
'0.10': 0b01000000000101000000000001000000,
'0.12': 0b01000001000101000000010001000100,
4: 0b01001111000111100111111001111111,
5: 0b01001111000111100111111001111111,
6: 0b01011111111111100111111111111111
}

@@ -76,3 +76,5 @@ };

// https://featuretests.io
'reservedProperties'
'reservedProperties',
'trailingFunctionCommas'
];

@@ -1,4 +0,4 @@

export function findIndex ( array, fn ) {
for ( let i = 0; i < array.length; i += 1 ) {
if ( fn( array[i], i ) ) return i;
export function findIndex(array, fn) {
for (let i = 0; i < array.length; i += 1) {
if (fn(array[i], i)) return i;
}

@@ -9,4 +9,4 @@

export function find ( array, fn ) {
return array[ findIndex( array, fn ) ];
export function find(array, fn) {
return array[findIndex(array, fn)];
}

@@ -5,22 +5,27 @@ import locate from './locate.js';

export default class CompileError extends Error {
constructor ( message, node ) {
super( message );
constructor(message, node) {
super(message);
this.name = 'CompileError';
if ( !node ) { return; }
if (!node) {
return;
}
const source = node.program.magicString.original;
const loc = locate( source, node.start );
const 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.stack = new Error().stack.replace(
new RegExp(`.+new ${this.name}.+\\n`, 'm'),
''
);
this.loc = loc;
this.snippet = getSnippet( source, loc, node.end - node.start );
this.snippet = getSnippet(source, loc, node.end - node.start);
}
toString () {
toString() {
return `${this.name}: ${this.message}\n${this.snippet}`;
}
}

@@ -5,3 +5,3 @@ // TODO this function is slightly flawed – it works on the original string,

// be in future...
export default function deindent ( node, code ) {
export default function deindent(node, code) {
const start = node.start;

@@ -14,17 +14,19 @@ const end = node.end;

if ( !node.program.indentExclusions[ indentStart ]
&& code.original.slice( indentStart, start ) === indentStr ) {
code.remove( indentStart, start );
if (
!node.program.indentExclusions[indentStart] &&
code.original.slice(indentStart, start) === indentStr
) {
code.remove(indentStart, start);
}
const pattern = new RegExp( indentStr + '\\S', 'g' );
const slice = code.original.slice( start, end );
const pattern = new RegExp(indentStr + '\\S', 'g');
const slice = code.original.slice(start, end);
let match;
while ( match = pattern.exec( slice ) ) {
while ((match = pattern.exec(slice))) {
const removeStart = start + match.index;
if ( !node.program.indentExclusions[ removeStart ] ) {
code.remove( removeStart, removeStart + indentStrLen );
if (!node.program.indentExclusions[removeStart]) {
code.remove(removeStart, removeStart + indentStrLen);
}
}
}

@@ -0,1 +1,2 @@

import CompileError from '../utils/CompileError.js';
import { findIndex } from './array.js';

@@ -10,41 +11,88 @@

export default function destructure ( code, scope, node, ref, inline, statementGenerators ) {
handlers[ node.type ]( code, scope, node, ref, inline, statementGenerators );
export default function destructure(
code,
scope,
node,
ref,
inline,
statementGenerators
) {
handlers[node.type](code, scope, node, ref, inline, statementGenerators);
}
function destructureIdentifier ( code, scope, node, ref, inline, statementGenerators ) {
statementGenerators.push( ( 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 destructureIdentifier(
code,
scope,
node,
ref,
inline,
statementGenerators
) {
statementGenerators.push((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, scope, node, ref, inline, statementGenerators ) {
function destructureAssignmentPattern(
code,
scope,
node,
ref,
inline,
statementGenerators
) {
const isIdentifier = node.left.type === 'Identifier';
const name = isIdentifier ? node.left.name : ref;
if ( !inline ) {
statementGenerators.push( ( 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 (!inline) {
statementGenerators.push((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, scope, node.left, ref, inline, statementGenerators );
if (!isIdentifier) {
destructure(code, scope, node.left, ref, inline, statementGenerators);
}
}
function destructureArrayPattern ( code, scope, node, ref, inline, statementGenerators ) {
function destructureArrayPattern(
code,
scope,
node,
ref,
inline,
statementGenerators
) {
let c = node.start;
node.elements.forEach( ( element, i ) => {
if ( !element ) return;
node.elements.forEach((element, i) => {
if (!element) return;
if ( element.type === 'RestElement' ) {
handleProperty( code, scope, c, element.argument, `${ref}.slice(${i})`, inline, statementGenerators );
if (element.type === 'RestElement') {
handleProperty(
code,
scope,
c,
element.argument,
`${ref}.slice(${i})`,
inline,
statementGenerators
);
} else {
handleProperty( code, scope, c, element, `${ref}[${i}]`, inline, statementGenerators );
handleProperty(
code,
scope,
c,
element,
`${ref}[${i}]`,
inline,
statementGenerators
);
}

@@ -54,41 +102,74 @@ c = element.end;

code.remove( c, node.end );
code.remove(c, node.end);
}
function destructureObjectPattern ( code, scope, node, ref, inline, statementGenerators ) {
function destructureObjectPattern(
code,
scope,
node,
ref,
inline,
statementGenerators
) {
let c = node.start;
const nonRestKeys = [];
node.properties.forEach( prop => {
node.properties.forEach(prop => {
let value;
let content
if (prop.type === "Property") {
const isComputedKey = prop.computed || prop.key.type !== 'Identifier'
const key = isComputedKey ? code.slice(prop.key.start, prop.key.end) : prop.key.name
let content;
if (prop.type === 'Property') {
const isComputedKey = prop.computed || prop.key.type !== 'Identifier';
const key = isComputedKey
? code.slice(prop.key.start, prop.key.end)
: prop.key.name;
value = isComputedKey ? `${ref}[${key}]` : `${ref}.${key}`;
content = prop.value;
nonRestKeys.push(isComputedKey ? key : '"' + key + '"')
} else if (prop.type === "RestElement") {
content = prop.argument
value = scope.createIdentifier( 'rest' );
const n = scope.createIdentifier( 'n' );
statementGenerators.push( ( start, prefix, suffix ) => {
code.overwrite(prop.start, c = prop.argument.start, `${prefix}var ${value} = {}; for (var ${n} in ${ref}) if([${nonRestKeys.join(", ")}].indexOf(${n}) === -1) ${value}[${n}] = ${ref}[${n}]${suffix}`)
code.move(prop.start, c, start)
} );
nonRestKeys.push(isComputedKey ? key : '"' + key + '"');
} else if (prop.type === 'RestElement') {
content = prop.argument;
value = scope.createIdentifier('rest');
const n = scope.createIdentifier('n');
statementGenerators.push((start, prefix, suffix) => {
code.overwrite(
prop.start,
(c = prop.argument.start),
`${prefix}var ${value} = {}; for (var ${n} in ${ref}) if([${nonRestKeys.join(
', '
)}].indexOf(${n}) === -1) ${value}[${n}] = ${ref}[${n}]${suffix}`
);
code.move(prop.start, c, start);
});
} else {
throw new CompileError( this, `Unexpected node of type ${prop.type} in object pattern`)
throw new CompileError(
this,
`Unexpected node of type ${prop.type} in object pattern`
);
}
handleProperty( code, scope, c, content, value, inline, statementGenerators );
handleProperty(code, scope, c, content, value, inline, statementGenerators);
c = prop.end;
});
code.remove( c, node.end );
code.remove(c, node.end);
}
function handleProperty ( code, scope, c, node, value, inline, statementGenerators ) {
switch ( node.type ) {
function handleProperty(
code,
scope,
c,
node,
value,
inline,
statementGenerators
) {
switch (node.type) {
case 'Identifier': {
code.remove( c, node.start );
destructureIdentifier( code, scope, node, value, inline, statementGenerators );
code.remove(c, node.start);
destructureIdentifier(
code,
scope,
node,
value,
inline,
statementGenerators
);
break;

@@ -102,28 +183,42 @@ }

if ( isIdentifier ) {
if (isIdentifier) {
name = node.left.name;
const declaration = scope.findDeclaration( name );
if ( declaration ) name = declaration.name;
const declaration = scope.findDeclaration(name);
if (declaration) name = declaration.name;
} else {
name = scope.createIdentifier( value );
name = scope.createIdentifier(value);
}
statementGenerators.push( ( start, prefix, suffix ) => {
if ( inline ) {
code.prependRight( node.right.start, `${name} = ${value} === undefined ? ` );
code.appendLeft( node.right.end, ` : ${value}` );
statementGenerators.push((start, prefix, suffix) => {
if (inline) {
code.prependRight(
node.right.start,
`${name} = ${value} === undefined ? `
);
code.appendLeft(node.right.end, ` : ${value}`);
} else {
code.prependRight( node.right.start, `${prefix}var ${name} = ${value}; if ( ${name} === void 0 ) ${name} = ` );
code.appendLeft( node.right.end, suffix );
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 );
code.move(node.right.start, node.right.end, start);
});
if ( isIdentifier ) {
code.remove( c, node.right.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, scope, c, node.left, name, inline, statementGenerators );
code.remove(c, node.left.start);
code.remove(node.left.end, node.right.start);
handleProperty(
code,
scope,
c,
node.left,
name,
inline,
statementGenerators
);
}

@@ -135,21 +230,32 @@

case 'ObjectPattern': {
code.remove( c, c = node.start );
code.remove(c, (c = node.start));
let ref = value;
if ( node.properties.length > 1 ) {
ref = scope.createIdentifier( value );
if (node.properties.length > 1) {
ref = scope.createIdentifier(value);
statementGenerators.push( ( start, prefix, suffix ) => {
statementGenerators.push((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, `${prefix}var ${ref} = ` );
code.overwrite( node.start, c = node.start + 1, value );
code.appendLeft( c, suffix );
code.prependRight(node.start, `${prefix}var ${ref} = `);
code.overwrite(node.start, (c = node.start + 1), value);
code.appendLeft(c, suffix);
code.overwrite( node.start, c = node.start + 1, `${prefix}var ${ref} = ${value}${suffix}` );
code.move( node.start, c, start );
code.overwrite(
node.start,
(c = node.start + 1),
`${prefix}var ${ref} = ${value}${suffix}`
);
code.move(node.start, c, start);
});
}
destructureObjectPattern( code, scope, node, ref, inline, statementGenerators );
destructureObjectPattern(
code,
scope,
node,
ref,
inline,
statementGenerators
);

@@ -160,22 +266,40 @@ break;

case 'ArrayPattern': {
code.remove( c, c = node.start );
code.remove(c, (c = node.start));
if ( node.elements.filter( Boolean ).length > 1 ) {
const ref = scope.createIdentifier( value );
if (node.elements.filter(Boolean).length > 1) {
const ref = scope.createIdentifier(value);
statementGenerators.push( ( start, prefix, suffix ) => {
code.prependRight( node.start, `${prefix}var ${ref} = ` );
code.overwrite( node.start, c = node.start + 1, value, { contentOnly: true });
code.appendLeft( c, suffix );
statementGenerators.push((start, prefix, suffix) => {
code.prependRight(node.start, `${prefix}var ${ref} = `);
code.overwrite(node.start, (c = node.start + 1), value, {
contentOnly: true
});
code.appendLeft(c, suffix);
code.move( node.start, c, start );
code.move(node.start, c, start);
});
node.elements.forEach( ( element, i ) => {
if ( !element ) return;
node.elements.forEach((element, i) => {
if (!element) return;
if ( element.type === 'RestElement' ) {
handleProperty( code, scope, c, element.argument, `${ref}.slice(${i})`, inline, statementGenerators );
if (element.type === 'RestElement') {
handleProperty(
code,
scope,
c,
element.argument,
`${ref}.slice(${i})`,
inline,
statementGenerators
);
} else {
handleProperty( code, scope, c, element, `${ref}[${i}]`, inline, statementGenerators );
handleProperty(
code,
scope,
c,
element,
`${ref}[${i}]`,
inline,
statementGenerators
);
}

@@ -185,8 +309,24 @@ c = element.end;

} else {
const index = findIndex( node.elements, Boolean );
const element = node.elements[ index ];
if ( element.type === 'RestElement' ) {
handleProperty( code, scope, c, element.argument, `${value}.slice(${index})`, inline, statementGenerators );
const index = findIndex(node.elements, Boolean);
const element = node.elements[index];
if (element.type === 'RestElement') {
handleProperty(
code,
scope,
c,
element.argument,
`${value}.slice(${index})`,
inline,
statementGenerators
);
} else {
handleProperty( code, scope, c, element, `${value}[${index}]`, inline, statementGenerators );
handleProperty(
code,
scope,
c,
element,
`${value}[${index}]`,
inline,
statementGenerators
);
}

@@ -196,3 +336,3 @@ c = element.end;

code.remove( c, node.end );
code.remove(c, node.end);
break;

@@ -202,5 +342,5 @@ }

default: {
throw new Error( `Unexpected node type in destructuring (${node.type})` );
throw new Error(`Unexpected node type in destructuring (${node.type})`);
}
}
}

@@ -1,30 +0,30 @@

function pad ( num, len ) {
let result = String( num );
return result + repeat( ' ', len - result.length );
function pad(num, len) {
let result = String(num);
return result + repeat(' ', len - result.length);
}
function repeat ( str, times ) {
function repeat(str, times) {
let result = '';
while ( times-- ) result += str;
while (times--) result += str;
return result;
}
export default function getSnippet ( source, loc, length = 1 ) {
const first = Math.max( loc.line - 5, 0 );
export default function getSnippet(source, loc, length = 1) {
const first = Math.max(loc.line - 5, 0);
const last = loc.line;
const numDigits = String( last ).length;
const numDigits = String(last).length;
const lines = source.split( '\n' ).slice( first, last );
const lines = source.split('\n').slice(first, last);
const lastLine = lines[ lines.length - 1 ];
const offset = lastLine.slice( 0, loc.column ).replace( /\t/g, ' ' ).length;
const lastLine = lines[lines.length - 1];
const offset = lastLine.slice(0, loc.column).replace(/\t/g, ' ').length;
let snippet = lines
.map( ( line, i ) => `${pad( i + first + 1, numDigits )} : ${line.replace( /\t/g, ' ')}` )
.join( '\n' );
.map((line, i) => `${pad(i + first + 1, numDigits)} : ${line.replace(/\t/g, ' ')}`)
.join('\n');
snippet += '\n' + repeat( ' ', numDigits + 3 + offset ) + repeat( '^', length );
snippet += '\n' + repeat(' ', numDigits + 3 + offset) + repeat('^', length);
return snippet;
}

@@ -1,26 +0,29 @@

export default function isReference ( node, parent ) {
if ( node.type === 'MemberExpression' ) {
return !node.computed && isReference( node.object, node );
export default function isReference(node, parent) {
if (node.type === 'MemberExpression') {
return !node.computed && isReference(node.object, node);
}
if ( node.type === 'Identifier' ) {
if (node.type === 'Identifier') {
// the only time we could have an identifier node without a parent is
// if it's the entire body of a function without a block statement –
// i.e. an arrow function expression like `a => a`
if ( !parent ) return true;
if (!parent) return true;
if ( /(Function|Class)Expression/.test( parent.type ) ) return false;
if (/(Function|Class)Expression/.test(parent.type)) return false;
if ( parent.type === 'VariableDeclarator' ) return node === parent.init;
if (parent.type === 'VariableDeclarator') return node === parent.init;
// TODO is this right?
if ( parent.type === 'MemberExpression' || parent.type === 'MethodDefinition' ) {
if (
parent.type === 'MemberExpression' ||
parent.type === 'MethodDefinition'
) {
return parent.computed || node === parent.object;
}
if ( parent.type === 'ArrayPattern' ) return false;
if (parent.type === 'ArrayPattern') return false;
// disregard the `bar` in `{ bar: foo }`, but keep it in `{ [bar]: foo }`
if ( parent.type === 'Property' ) {
if ( parent.parent.type === 'ObjectPattern' ) return false;
if (parent.type === 'Property') {
if (parent.parent.type === 'ObjectPattern') return false;
return parent.computed || node === parent.value;

@@ -30,6 +33,7 @@ }

// disregard the `bar` in `class Foo { bar () {...} }`
if ( parent.type === 'MethodDefinition' ) return false;
if (parent.type === 'MethodDefinition') return false;
// disregard the `bar` in `export { foo as bar }`
if ( parent.type === 'ExportSpecifier' && node !== parent.local ) return false;
if (parent.type === 'ExportSpecifier' && node !== parent.local)
return false;

@@ -36,0 +40,0 @@ return true;

@@ -1,3 +0,3 @@

export default function locate ( source, index ) {
var lines = source.split( '\n' );
export default function locate(source, index) {
var lines = source.split('\n');
var len = lines.length;

@@ -8,7 +8,7 @@

for ( i = 0; i < len; i += 1 ) {
for (i = 0; i < len; i += 1) {
var line = lines[i];
var lineEnd = lineStart + line.length + 1; // +1 for newline
var lineEnd = lineStart + line.length + 1; // +1 for newline
if ( lineEnd > index ) {
if (lineEnd > index) {
return { line: i + 1, column: index - lineStart, char: i };

@@ -20,3 +20,3 @@ }

throw new Error( 'Could not determine location of character' );
throw new Error('Could not determine location of character');
}

@@ -1,5 +0,6 @@

let 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( word => reserved[ word ] = true );
let 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(word => (reserved[word] = true));
export default reserved;

@@ -1,14 +0,24 @@

export function isArguments ( node ) {
export function isArguments(node) {
return node.type === 'Identifier' && node.name === 'arguments';
}
export default function spread ( code, elements, start, argumentsArrayAlias, isNew ) {
export default function spread(
code,
elements,
start,
argumentsArrayAlias,
isNew
) {
let i = elements.length;
let firstSpreadIndex = -1;
while ( i-- ) {
while (i--) {
const element = elements[i];
if ( element && element.type === 'SpreadElement' ) {
if ( isArguments( element.argument ) ) {
code.overwrite( element.argument.start, element.argument.end, argumentsArrayAlias );
if (element && element.type === 'SpreadElement') {
if (isArguments(element.argument)) {
code.overwrite(
element.argument.start,
element.argument.end,
argumentsArrayAlias
);
}

@@ -20,12 +30,12 @@

if ( firstSpreadIndex === -1 ) return false; // false indicates no spread elements
if (firstSpreadIndex === -1) return false; // false indicates no spread elements
if (isNew) {
for ( i = 0; i < elements.length; i += 1 ) {
for (i = 0; i < elements.length; i += 1) {
let element = elements[i];
if ( element.type === 'SpreadElement' ) {
code.remove( element.start, element.argument.start );
if (element.type === 'SpreadElement') {
code.remove(element.start, element.argument.start);
} else {
code.prependRight( element.start, '[' );
code.prependRight( element.end, ']' );
code.prependRight(element.start, '[');
code.prependRight(element.end, ']');
}

@@ -37,21 +47,21 @@ }

let element = elements[ firstSpreadIndex ];
const previousElement = elements[ firstSpreadIndex - 1 ];
let element = elements[firstSpreadIndex];
const previousElement = elements[firstSpreadIndex - 1];
if ( !previousElement ) {
code.remove( start, element.start );
code.overwrite( element.end, elements[1].start, '.concat( ' );
if (!previousElement) {
code.remove(start, element.start);
code.overwrite(element.end, elements[1].start, '.concat( ');
} else {
code.overwrite( previousElement.end, element.start, ' ].concat( ' );
code.overwrite(previousElement.end, element.start, ' ].concat( ');
}
for ( i = firstSpreadIndex; i < elements.length; i += 1 ) {
for (i = firstSpreadIndex; i < elements.length; i += 1) {
element = elements[i];
if ( element ) {
if ( element.type === 'SpreadElement' ) {
code.remove( element.start, element.argument.start );
if (element) {
if (element.type === 'SpreadElement') {
code.remove(element.start, element.argument.start);
} else {
code.appendLeft( element.start, '[' );
code.appendLeft( element.end, ']' );
code.appendLeft(element.start, '[');
code.appendLeft(element.end, ']');
}

@@ -58,0 +68,0 @@ }

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc